├── .gitignore ├── .liquidrc ├── .npmignore ├── .npmrc ├── .vscode └── settings.json ├── LICENSE ├── ThirdPartyNotices.txt ├── docs ├── .eleventy.js ├── .eleventyignore ├── .npmrc ├── .prettierignore ├── netlify.toml ├── package.json ├── pnpm-lock.yaml ├── postcss.config.cjs ├── readme.md ├── src │ ├── app │ │ ├── completions │ │ │ ├── html.ts │ │ │ ├── liquid.ts │ │ │ └── rules.ts │ │ ├── components │ │ │ ├── accordion.ts │ │ │ ├── demo.ts │ │ │ ├── drawer.ts │ │ │ ├── dropdown.ts │ │ │ ├── parser.ts │ │ │ ├── playground.ts │ │ │ ├── scrollspy.ts │ │ │ └── sticky.ts │ │ ├── index.ts │ │ ├── samples │ │ │ ├── global.ts │ │ │ ├── liquid.ts │ │ │ ├── markup.ts │ │ │ ├── script.ts │ │ │ └── styles.ts │ │ └── utilities │ │ │ └── common.ts │ ├── assets │ │ ├── img │ │ │ └── social-banner.png │ │ └── svg │ │ │ ├── anchor.svg │ │ │ ├── bell.svg │ │ │ ├── check.svg │ │ │ ├── checked.svg │ │ │ ├── chevron-down.svg │ │ │ ├── chevron-left.svg │ │ │ ├── chevron-right.svg │ │ │ ├── copy.svg │ │ │ ├── corner-left.svg │ │ │ ├── edit.svg │ │ │ ├── esthetic.svg │ │ │ ├── file.svg │ │ │ ├── full.svg │ │ │ ├── gears.svg │ │ │ ├── github-2.svg │ │ │ ├── github-issue.svg │ │ │ ├── github.svg │ │ │ ├── home.svg │ │ │ ├── info.svg │ │ │ ├── link.svg │ │ │ ├── logo.svg │ │ │ ├── menu.svg │ │ │ ├── minus-square.svg │ │ │ ├── moloko.svg │ │ │ ├── npm.svg │ │ │ ├── plus-square.svg │ │ │ ├── process.svg │ │ │ ├── settings.svg │ │ │ ├── sparser.svg │ │ │ ├── split.svg │ │ │ ├── table.svg │ │ │ ├── typescript.svg │ │ │ ├── unchecked.svg │ │ │ └── æsthetic.svg │ ├── data │ │ ├── i18n.json │ │ ├── main.json │ │ ├── navbar.json │ │ ├── parse.json │ │ └── rules.json │ ├── docs │ │ ├── integrate │ │ │ ├── browser.md │ │ │ ├── linters.md │ │ │ └── text-editor.md │ │ ├── introduction │ │ │ ├── installation.md │ │ │ ├── language-support.md │ │ │ ├── motivation.md │ │ │ └── what-is-esthetic.md │ │ ├── misc │ │ │ ├── acknowledgements.md │ │ │ ├── benchmarks.md │ │ │ ├── documentation.md │ │ │ ├── limitations.md │ │ │ └── terminologies.md │ │ ├── parser │ │ │ ├── algorithm.md │ │ │ ├── error-handling.md │ │ │ ├── lexers.md │ │ │ ├── parse-table.md │ │ │ ├── terminology.md │ │ │ └── tokens.md │ │ └── usage │ │ │ ├── cli.md │ │ │ ├── config-file.md │ │ │ ├── events.md │ │ │ ├── format.md │ │ │ ├── grammar.md │ │ │ ├── hooks.md │ │ │ ├── ignoring-code.md │ │ │ ├── inline-control.md │ │ │ ├── language.md │ │ │ ├── method-chains.md │ │ │ ├── parse.md │ │ │ ├── rules.md │ │ │ ├── settings.md │ │ │ └── utilities.md │ ├── rules │ │ ├── global │ │ │ ├── correct.md │ │ │ ├── crlf.md │ │ │ ├── endNewline.md │ │ │ ├── indentChar.md │ │ │ ├── indentLevel.md │ │ │ ├── indentSize.md │ │ │ ├── language.md │ │ │ ├── preserveLine.md │ │ │ ├── preset.md │ │ │ ├── wrap.md │ │ │ └── wrapFraction.md │ │ ├── json │ │ │ ├── allowComments.md │ │ │ ├── arrayFormat.md │ │ │ ├── bracePadding.md │ │ │ ├── objectIndent.md │ │ │ └── objectSort.md │ │ ├── liquid │ │ │ ├── commentIndent.md │ │ │ ├── commentNewline.md │ │ │ ├── dedentTagList.md │ │ │ ├── delimiterPlacement.md │ │ │ ├── delimiterTrims.md │ │ │ ├── forceArgument.md │ │ │ ├── forceFilter.md │ │ │ ├── forceIndent.md │ │ │ ├── ignoreTagList.md │ │ │ ├── indentAttribute.md │ │ │ ├── lineBreakSeparator.md │ │ │ ├── normalizeSpacing.md │ │ │ ├── paddedTagList.md │ │ │ ├── preserveComment.md │ │ │ ├── preserveInternal.md │ │ │ └── quoteConvert.md │ │ ├── markup │ │ │ ├── attributeCasing.md │ │ │ ├── attributeSort.md │ │ │ ├── commentDelimiters.md │ │ │ ├── commentIndent.md │ │ │ ├── commentNewline.md │ │ │ ├── correct.md │ │ │ ├── delimiterTerminus.md │ │ │ ├── forceAttribute.md │ │ │ ├── forceIndent.md │ │ │ ├── ignoreCSS.md │ │ │ ├── ignoreJS.md │ │ │ ├── ignoreJSON.md │ │ │ ├── lineBreakValue.md │ │ │ ├── preserveAttribute.md │ │ │ ├── preserveComment.md │ │ │ ├── preserveText.md │ │ │ ├── quoteConvert.md │ │ │ ├── selfCloseSVG.md │ │ │ ├── selfCloseSpace.md │ │ │ └── stripAttributeLines.md │ │ ├── strap.md │ │ └── style │ │ │ ├── atRuleSpace.md │ │ │ ├── classPadding.md │ │ │ ├── commentIndent.md │ │ │ ├── commentNewline.md │ │ │ ├── noLeadZero.md │ │ │ ├── preserveComment.md │ │ │ ├── quoteConvert.md │ │ │ ├── shorthandMargin.md │ │ │ ├── shorthandPadding.md │ │ │ ├── sortProperties.md │ │ │ └── sortSelectors.md │ ├── samples │ │ ├── common.ts │ │ └── normalizeSpacing.ts │ ├── sass │ │ ├── styles │ │ │ ├── accordion.scss │ │ │ ├── breadcrumb.scss │ │ │ ├── code.scss │ │ │ ├── demo.scss │ │ │ ├── drawer.scss │ │ │ ├── footer.scss │ │ │ ├── landing.scss │ │ │ ├── navbar.scss │ │ │ ├── overwrites.scss │ │ │ ├── parser.scss │ │ │ ├── playground.scss │ │ │ ├── sidebar.scss │ │ │ ├── svg.scss │ │ │ └── tabs.scss │ │ ├── stylesheet.scss │ │ └── variables.scss │ └── views │ │ ├── include │ │ ├── anchors.liquid │ │ ├── breadcrumbs.liquid │ │ ├── footer.liquid │ │ ├── landing.liquid │ │ ├── navbar.liquid │ │ ├── navigators.liquid │ │ ├── parser.liquid │ │ ├── playground.liquid │ │ ├── rules.liquid │ │ ├── sidebar.liquid │ │ └── tokens.liquid │ │ ├── index.md │ │ ├── layouts │ │ └── base.liquid │ │ ├── playground.md │ │ └── rules.md ├── tsconfig.json └── tsup.config.ts ├── index.d.ts ├── package.json ├── pnpm-lock.yaml ├── readme.md ├── schema.config.json ├── schema.package.json ├── src ├── cli.ts ├── cli │ ├── log.ts │ ├── run.ts │ └── tui.ts ├── comments │ ├── block.ts │ ├── control.ts │ ├── index.ts │ └── line.ts ├── config.ts ├── esthetic.ts ├── format │ ├── index.ts │ ├── markup.ts │ ├── script.ts │ └── style.ts ├── index.ts ├── lexers │ ├── index.ts │ ├── markup.ts │ ├── script.ts │ └── style.ts ├── lexical │ ├── chars.ts │ ├── codes.ts │ ├── enum.ts │ ├── errors.ts │ ├── lexing.ts │ ├── liquid.ts │ └── regex.ts ├── parse │ ├── classes.ts │ ├── detection.ts │ ├── errors.ts │ ├── external.ts │ ├── grammar.ts │ ├── parser.ts │ └── sorting.ts ├── rules │ ├── define.ts │ ├── definitions.ts │ ├── language.ts │ ├── presets.ts │ ├── presets │ │ ├── default.ts │ │ ├── prettier.ts │ │ ├── recommended.ts │ │ ├── strict.ts │ │ └── warrington.ts │ └── validate.ts └── utils │ ├── helpers.ts │ └── native.ts ├── tests ├── LICENSE ├── bench │ ├── changes │ │ ├── compare.mjs │ │ └── samples │ │ │ └── doctype.txt │ ├── methods │ │ ├── loops.mjs │ │ └── null-prototype.mjs │ ├── package.json │ ├── readme.md │ └── tools │ │ ├── html.mjs │ │ ├── javascript.mjs │ │ └── samples │ │ ├── html.txt │ │ └── javascript.txt ├── cases │ ├── attributes │ │ ├── casing.test.mjs │ │ ├── forcing.test.mjs │ │ ├── indentation.test.mjs │ │ ├── nested-delimiters.test.mjs │ │ ├── quotations.test.mjs │ │ ├── snapshots │ │ │ ├── casing.test.mjs.md │ │ │ ├── casing.test.mjs.snap │ │ │ ├── indentation.test.mjs.md │ │ │ ├── indentation.test.mjs.snap │ │ │ ├── liquid-chains.test.mjs.md │ │ │ ├── liquid-chains.test.mjs.snap │ │ │ ├── nested-delimiters.test.mjs.md │ │ │ ├── nested-delimiters.test.mjs.snap │ │ │ ├── quotations.test.mjs.md │ │ │ └── quotations.test.mjs.snap │ │ ├── sorting.test.mjs │ │ └── todo │ │ │ ├── html-structures.test.mjs │ │ │ ├── liquid-chains.test.mjs │ │ │ └── liquid-structures.test.mjs │ ├── css │ │ ├── liquid-css.test.mjs │ │ ├── nested.test.mjs │ │ ├── sorting.test.mjs │ │ └── structures.test.mjs │ ├── html │ │ ├── comments.test.mjs │ │ ├── ignore-next.test.mjs │ │ ├── ignore-region.test.mjs │ │ ├── ignore-script.test.mjs │ │ ├── ignore-style.test.mjs │ │ ├── script-tag.test.mjs │ │ ├── snapshots │ │ │ ├── ignore-next.test.mjs.md │ │ │ ├── ignore-next.test.mjs.snap │ │ │ ├── ignore-region.test.mjs.md │ │ │ └── ignore-region.test.mjs.snap │ │ ├── style-tag.test.mjs │ │ └── svg-structures.test.mjs │ ├── json │ │ ├── liquid-occurances.test.mjs │ │ ├── liquid-strings.test.mjs │ │ ├── sorting.test.mjs │ │ └── todo │ │ │ └── strip-comments.test.mjs │ └── liquid │ │ ├── captures.test.mjs │ │ ├── case-tag.test.mjs │ │ ├── comment-block.test.mjs │ │ ├── delimiter-placement.test.mjs │ │ ├── delimiter-trims.test.mjs │ │ ├── force-arguments.test.mjs │ │ ├── force-filters.test.mjs │ │ ├── force-wrap.test.mjs │ │ ├── ignore-next.test.mjs │ │ ├── ignore-region.test.mjs │ │ ├── indentation.test.mjs │ │ ├── line-comments.test.mjs │ │ ├── linebreak-separators.test.mjs │ │ ├── liquid-tag.test.mjs │ │ ├── normalize-spacing.test.mjs │ │ ├── schema-tag.test.mjs │ │ ├── snapshots │ │ ├── comment-block.test.mjs.md │ │ ├── comment-block.test.mjs.snap │ │ ├── comments.test.mjs.md │ │ ├── comments.test.mjs.snap │ │ ├── delimiter-placement.test.mjs.md │ │ ├── delimiter-placement.test.mjs.snap │ │ ├── ignore-next.test.mjs.md │ │ ├── ignore-next.test.mjs.snap │ │ ├── ignore-region.test.mjs.md │ │ ├── ignore-region.test.mjs.snap │ │ ├── line-comments.test.mjs.md │ │ └── line-comments.test.mjs.snap │ │ ├── style-tag.test.mjs │ │ └── todo │ │ ├── capture-tag.mjs │ │ ├── javascript-tag.test.mjs │ │ └── line-breaks.test.mjs ├── cli │ ├── file.css │ ├── file.html │ ├── file.liquid │ └── file.xml ├── dev.liquid ├── dev.test.mjs ├── dev.txt ├── e2e │ ├── cjs │ │ ├── package.json │ │ ├── samples │ │ │ └── file-1.liquid │ │ └── Æ.json │ ├── e2e.test.mjs │ ├── esm │ │ ├── package.json │ │ └── samples │ │ │ └── file-1.liquid │ └── iife │ │ ├── package.json │ │ └── src │ │ ├── css │ │ └── file.css │ │ ├── html │ │ ├── file-1.html │ │ └── file-2.html │ │ ├── liquid │ │ └── file.liquid │ │ └── xml │ │ └── file.xml ├── package.json ├── readme.md ├── rules │ ├── globals.test.mjs │ ├── markup.test.mjs │ ├── samples │ │ ├── global │ │ │ ├── comment-indent.txt │ │ │ ├── crlf.txt │ │ │ ├── end-newline.txt │ │ │ ├── indent-char.txt │ │ │ ├── indent-size.txt │ │ │ ├── preserve-comment.txt │ │ │ ├── preserve-line.txt │ │ │ └── wrap.txt │ │ ├── markup │ │ │ ├── attribute-casing.txt │ │ │ ├── attribute-sort-list.txt │ │ │ ├── attribute-sort.txt │ │ │ ├── attribute-values.txt │ │ │ ├── comment-newline.txt │ │ │ ├── correct.txt │ │ │ ├── delimiter-trims.txt │ │ │ ├── force-attribute-wrap.txt │ │ │ ├── force-attribute.txt │ │ │ ├── force-indent.txt │ │ │ ├── force-lead-attribute.txt │ │ │ ├── normalize-spacing.txt │ │ │ ├── preserve-attributes.txt │ │ │ ├── quote-convert.txt │ │ │ └── self-close-space.txt │ │ ├── script │ │ │ ├── array-format.txt │ │ │ ├── brace-allman.txt │ │ │ ├── brace-newline.txt │ │ │ ├── brace-padding.txt │ │ │ ├── brace-style.txt │ │ │ ├── case-space.txt │ │ │ ├── correct.txt │ │ │ ├── else-newline.txt │ │ │ ├── end-comma.txt │ │ │ ├── function-name-space.txt │ │ │ ├── function-space.txt │ │ │ ├── inline-return.txt │ │ │ ├── method-chain.txt │ │ │ ├── never-flatten.txt │ │ │ ├── no-case-indent.txt │ │ │ ├── no-semicolon.txt │ │ │ ├── object-indent.txt │ │ │ ├── object-sort.txt │ │ │ ├── quote-convert.txt │ │ │ ├── ternary-line.txt │ │ │ ├── variable-list.txt │ │ │ └── vertical.txt │ │ └── style │ │ │ ├── class-padding.txt │ │ │ ├── compress-css.txt │ │ │ ├── correct.txt │ │ │ ├── force-value.txt │ │ │ ├── no-lead-zero.txt │ │ │ ├── quote-convert.txt │ │ │ ├── sort-properties.txt │ │ │ └── sort-selectors.txt │ ├── script.test.mjs │ ├── snapshots │ │ ├── globals.test.mjs.md │ │ ├── globals.test.mjs.snap │ │ ├── markup.test.mjs.md │ │ ├── markup.test.mjs.snap │ │ ├── style.test.mjs.md │ │ └── style.test.mjs.snap │ └── style.test.mjs └── units │ ├── chars.test.mjs │ ├── detect.test.mjs │ ├── errors.test.mjs │ ├── events.test.mjs │ ├── grammar.test.mjs │ ├── hooks.test.mjs │ ├── options.test.mjs │ ├── preset.test.mjs │ ├── rules.test.mjs │ └── stats.test.mjs ├── tsconfig.json ├── tsup.config.ts └── types ├── events.d.ts ├── hooks.d.ts ├── index.d.ts ├── misc ├── defintions.d.ts ├── grammar.d.ts ├── settings.d.ts └── specifics.d.ts ├── next.d.ts ├── parse ├── parser.d.ts └── tokens.d.ts ├── rules ├── global.d.ts ├── javascript.d.ts ├── json.d.ts ├── liquid.d.ts ├── markup.d.ts ├── script.d.ts └── style.d.ts └── shared.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | package/ 3 | node_modules/ 4 | tests/testa/node_modules 5 | tests/samples/ 6 | tests/cases/todo 7 | dist/ 8 | bin/ 9 | 10 | versions/ 11 | .pnpm-debug.log 12 | 13 | docs/old 14 | docs/public 15 | packages/samples 16 | 17 | # Local Netlify folder 18 | .netlify 19 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # DIRECTORIES 2 | 3 | .vscode 4 | src 5 | tests 6 | docs 7 | versions 8 | 9 | # BUILD FILES 10 | 11 | tsconfig.json 12 | tsup.config.ts 13 | 14 | # MARKDOWN FILES 15 | 16 | readme.md 17 | changelog.md 18 | 19 | # DOT FILES 20 | 21 | .npmignore 22 | .npmrc 23 | .gitignore 24 | .liquidrc 25 | .pnpm-lock.yaml 26 | .pnpm-debug.log -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # NO LINK 2 | link-workspace-packages = false 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 | Present: ΝΙΚΟΛΑΣ ΣΑΒΒΙΔΗΣ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/.eleventyignore: -------------------------------------------------------------------------------- 1 | src/rules/strap.md 2 | -------------------------------------------------------------------------------- /docs/.npmrc: -------------------------------------------------------------------------------- 1 | link-workspace-packages = false 2 | shared-workspace-lockfile = false 3 | -------------------------------------------------------------------------------- /docs/.prettierignore: -------------------------------------------------------------------------------- 1 | .scss 2 | -------------------------------------------------------------------------------- /docs/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "pnpm run build" 3 | 4 | 5 | # REQUEST HEADERS 6 | # --------------------------- 7 | [[headers]] 8 | for = "/*" 9 | [headers.values] 10 | Access-Control-Allow-Origin = "*" 11 | -------------------------------------------------------------------------------- /docs/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | const purge = require('@fullhuman/postcss-purgecss'); 2 | const autoprefixer = require('autoprefixer'); 3 | const cssnano = require('cssnano'); 4 | 5 | module.exports = { 6 | plugins: [ 7 | autoprefixer(), 8 | cssnano({ 9 | preset: 'default' 10 | }), 11 | purge( 12 | { 13 | variables: true, 14 | content: [ 15 | 'public/**/*.html', 16 | 'public/**/*.js' 17 | ] 18 | } 19 | ) 20 | ] 21 | }; 22 | -------------------------------------------------------------------------------- /docs/src/app/completions/liquid.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable n/no-callback-literal */ 2 | import { Completions } from 'papyrus'; 3 | 4 | export default [ 5 | 6 | /* -------------------------------------------- */ 7 | /* TAG NAMES */ 8 | /* -------------------------------------------- */ 9 | 10 | { 11 | match: /(\w*)$/, 12 | index: 1, 13 | cache: false, 14 | context: (before) => /{%-?\s*$/.test(before), 15 | replace: (result: string) => `${result}`, 16 | search: (term, callback) => callback([ 17 | 'form', 18 | 'paginate', 19 | 'capture', 20 | 'case', 21 | 'comment', 22 | 'for', 23 | 'if', 24 | 'raw', 25 | 'tablerow', 26 | 'unless', 27 | 'schema', 28 | 'style', 29 | 'script', 30 | 'stylesheet', 31 | 'javascript' 32 | ].filter(tag => tag.indexOf(term) > -1)) 33 | }, 34 | { 35 | match: /(\w*)$/, 36 | index: 1, 37 | cache: false, 38 | context: (before) => /{%-?\s*end$/.test(before), 39 | replace: (result: string) => `${result}`, 40 | search: (term, callback) => callback([ 41 | 'form', 42 | 'paginate', 43 | 'capture', 44 | 'case', 45 | 'comment', 46 | 'for', 47 | 'if', 48 | 'raw', 49 | 'tablerow', 50 | 'unless', 51 | 'schema', 52 | 'style', 53 | 'script', 54 | 'stylesheet', 55 | 'javascript' 56 | ].filter(tag => tag.indexOf(term) > -1)) 57 | } 58 | 59 | ]; 60 | -------------------------------------------------------------------------------- /docs/src/app/components/accordion.ts: -------------------------------------------------------------------------------- 1 | import { Controller } from '@hotwired/stimulus'; 2 | import relapse, { Scope } from 'relapse'; 3 | import spx from 'spx'; 4 | 5 | /* -------------------------------------------- */ 6 | /* CLASS */ 7 | /* -------------------------------------------- */ 8 | 9 | export class Accordion extends Controller { 10 | 11 | accordion: Scope; 12 | multipleValue: boolean; 13 | persistValue: boolean; 14 | 15 | static values = { 16 | multiple: { 17 | type: Boolean, 18 | default: false 19 | }, 20 | persist: { 21 | type: Boolean, 22 | default: true 23 | } 24 | }; 25 | 26 | /** 27 | * Stimulus Initialize 28 | */ 29 | initialize (): void { 30 | 31 | this.accordion = relapse(this.element, { 32 | multiple: this.multipleValue, 33 | persist: this.persistValue 34 | }); 35 | 36 | } 37 | 38 | /** 39 | * Stimulus Disconnect 40 | */ 41 | disconnect () { 42 | 43 | this.accordion.destroy(); 44 | 45 | } 46 | 47 | /** 48 | * Programmatic Visit 49 | * 50 | * Executes a programmatic visit 51 | */ 52 | goto ({ target }: { target: HTMLButtonElement }) { 53 | 54 | spx.visit('/' + target.dataset.href); 55 | 56 | } 57 | 58 | /** 59 | * Open Fold 60 | * 61 | * Event target should be the the fold index to open 62 | */ 63 | open ({ target: { dataset: { index } } }) { 64 | 65 | return this.accordion.folds[parseInt(index)].open(); 66 | 67 | } 68 | 69 | /** 70 | * Close Fold 71 | * 72 | * Event target should be the the fold index to close 73 | */ 74 | close ({ target: { dataset: { index } } }) { 75 | 76 | return this.accordion.folds[parseInt(index)].close(); 77 | 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /docs/src/app/components/playground.ts: -------------------------------------------------------------------------------- 1 | import type Moloko from 'moloko'; 2 | import { Controller } from '@hotwired/stimulus'; 3 | 4 | export class Playground extends Controller { 5 | 6 | static loaded: boolean = false; 7 | static moloko: typeof Moloko; 8 | 9 | /** 10 | * Stimulus: Targets 11 | */ 12 | static targets = [ 13 | 'mount', 14 | 'splash' 15 | ]; 16 | 17 | /** 18 | * Stimulus: Values 19 | */ 20 | static values = { 21 | module: String, 22 | loaded: Boolean 23 | }; 24 | 25 | get moloko () { 26 | 27 | return Playground.moloko; 28 | } 29 | 30 | get hash () { 31 | return localStorage.getItem('moloko'); 32 | } 33 | 34 | svg: Element; 35 | timer: NodeJS.Timer; 36 | 37 | async connect () { 38 | 39 | if (this.hash) window.location.hash = this.hash; 40 | 41 | if (Playground.loaded) return this.mount(); 42 | 43 | this.splashTarget.classList.remove('d-none'); 44 | 45 | this.loading(); 46 | await this.module(); 47 | 48 | } 49 | 50 | disconnect (): void { 51 | 52 | localStorage.setItem('moloko', this.moloko.hash()); 53 | 54 | } 55 | 56 | async module () { 57 | 58 | const moloko = await import(this.moduleValue); 59 | 60 | Playground.moloko = moloko.default; 61 | Playground.loaded = true; 62 | 63 | } 64 | 65 | mount () { 66 | 67 | Playground.moloko.mount(this.mountTarget, { 68 | offset: 52, 69 | resolve: { 70 | path: 'assets/moloko' 71 | } 72 | }); 73 | 74 | } 75 | 76 | loading () { 77 | 78 | if (!Playground.loaded) { 79 | 80 | this.timer = setInterval(() => { 81 | 82 | this.loading(); 83 | 84 | }, 500); 85 | 86 | } else { 87 | 88 | this.splashTarget.classList.add('d-none'); 89 | 90 | clearInterval(this.timer); 91 | this.mount(); 92 | 93 | } 94 | 95 | } 96 | 97 | /** 98 | * Import URL to the moloko module 99 | */ 100 | mountTarget: HTMLElement; 101 | splashTarget: HTMLElement; 102 | moduleValue: string; 103 | estheticValue: string; 104 | loadedValue: boolean; 105 | 106 | } 107 | -------------------------------------------------------------------------------- /docs/src/app/index.ts: -------------------------------------------------------------------------------- 1 | import { Application } from '@hotwired/stimulus'; 2 | import { Accordion } from './components/accordion'; 3 | import { Drawer } from './components/drawer'; 4 | import { Sticky } from './components/sticky'; 5 | import { Demo } from './components/demo'; 6 | import { Dropdown } from './components/dropdown'; 7 | import { ScrollSpy } from './components/scrollspy'; 8 | import { Playground } from './components/playground'; 9 | import { Parser } from './components/parser'; 10 | import spx from 'spx'; 11 | 12 | spx.connect({ 13 | targets: [ 'body' ], 14 | progress: false 15 | })(function () { 16 | 17 | const stimulus = Application.start(); 18 | 19 | stimulus.register('drawer', Drawer); 20 | stimulus.register('accordion', Accordion); 21 | stimulus.register('dropdown', Dropdown); 22 | stimulus.register('sticky', Sticky); 23 | stimulus.register('demo', Demo); 24 | stimulus.register('scrollspy', ScrollSpy); 25 | stimulus.register('playground', Playground); 26 | stimulus.register('parser', Parser); 27 | 28 | }); 29 | 30 | spx.on('fetch', ({ key }) => { 31 | 32 | if (key === '/playground') { 33 | 34 | import(window.location.host + '/assets/moloko.js'); 35 | 36 | } 37 | 38 | }); 39 | -------------------------------------------------------------------------------- /docs/src/app/samples/global.ts: -------------------------------------------------------------------------------- 1 | export const global = { 2 | 3 | indentChar: { 4 | field: 'string', 5 | default: ' ', 6 | input: ` 7 |
8 | 13 |
14 | ` 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /docs/src/app/samples/liquid.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/app/samples/liquid.ts -------------------------------------------------------------------------------- /docs/src/app/samples/markup.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/app/samples/markup.ts -------------------------------------------------------------------------------- /docs/src/app/samples/script.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/app/samples/script.ts -------------------------------------------------------------------------------- /docs/src/app/samples/styles.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/app/samples/styles.ts -------------------------------------------------------------------------------- /docs/src/app/utilities/common.ts: -------------------------------------------------------------------------------- 1 | import qvp from 'qvp'; 2 | import { LinesAndColumns } from 'lines-and-columns'; 3 | import JSONFallback from 'json-parse-better-errors'; 4 | 5 | /** 6 | * Check if an element is out of the viewport 7 | */ 8 | export function isOutOfViewport (element: HTMLElement) { 9 | 10 | // Get element's bounding 11 | const bounding = element.getBoundingClientRect(); 12 | 13 | const top = bounding.top < 0; 14 | const left = bounding.left < 0; 15 | const bottom = bounding.bottom > (window.innerHeight || document.documentElement.clientHeight); 16 | const right = bounding.right > (window.innerWidth || document.documentElement.clientWidth); 17 | 18 | return top || left || bottom || right; 19 | 20 | }; 21 | 22 | /** 23 | * Whether or not we are within a screen viewport 24 | */ 25 | export function isScreen (screens: string) { 26 | 27 | return screens.split('|').some(qvp.active); 28 | 29 | } 30 | 31 | export function parseJSON (input: string) { 32 | 33 | try { 34 | 35 | try { 36 | return JSON.parse(input); 37 | 38 | } catch (error) { 39 | JSONFallback(input); 40 | throw error; 41 | 42 | } 43 | } catch (error) { 44 | 45 | const indexMatch = error.message.match(/in JSON at position (\d+) while parsing/); 46 | 47 | if (indexMatch && indexMatch.length > 0) { 48 | 49 | const lines = new LinesAndColumns(input); 50 | const index = Number(indexMatch[1]); 51 | const location = lines.locationForIndex(index); 52 | 53 | error.message = error.message.replace(/parsing/, 'parsing:\n\n').replace(/'/g, ''); 54 | 55 | error.stack = [ 56 | `LineNo: ${location.line}`, 57 | `Column: ${location.column}`, 58 | `Offset: ${indexMatch[1]}` 59 | ].join('\n'); 60 | } 61 | 62 | throw error; 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /docs/src/assets/img/social-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/assets/img/social-banner.png -------------------------------------------------------------------------------- /docs/src/assets/svg/anchor.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/bell.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/check.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/checked.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/chevron-down.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/chevron-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/assets/svg/chevron-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/assets/svg/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/corner-left.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/assets/svg/file.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/full.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/github-2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/assets/svg/github-issue.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/github.svg: -------------------------------------------------------------------------------- 1 | github 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/home.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/info.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/link.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/menu.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/minus-square.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/npm.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/assets/svg/plus-square.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/settings.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/split.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/table.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/assets/svg/typescript.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/src/assets/svg/unchecked.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/src/data/i18n.json: -------------------------------------------------------------------------------- 1 | { 2 | "docs": { 3 | "en": "Docs" 4 | }, 5 | "rules": { 6 | "en": "Rules" 7 | }, 8 | "playground": { 9 | "en": "Playground" 10 | }, 11 | "before": { 12 | "en": "Before" 13 | }, 14 | "after": { 15 | "en": "After" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /docs/src/data/navbar.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "Docs", 4 | "url": "/introduction/what-is-esthetic/", 5 | "group": [ 6 | "introduction", 7 | "usage", 8 | "parse", 9 | "integrate", 10 | "misc" 11 | ] 12 | }, 13 | { 14 | "title": "Rules", 15 | "url": "/rules/", 16 | "group": [ 17 | "global", 18 | "liquid", 19 | "html", 20 | "xml", 21 | "css", 22 | "json", 23 | "script" 24 | ] 25 | }, 26 | { 27 | "title": "Playground", 28 | "url": "/playground/", 29 | "group": ["format", "parser", "grammar", "language"] 30 | } 31 | ] 32 | -------------------------------------------------------------------------------- /docs/src/docs/integrate/browser.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Integrate - Browser' 3 | layout: base 4 | permalink: '/integrate/browser/index.html' 5 | --- 6 | 7 | # TODO 8 | -------------------------------------------------------------------------------- /docs/src/docs/integrate/linters.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Integrate - Linters' 3 | layout: base 4 | permalink: '/integrate/linters/index.html' 5 | --- 6 | 7 | # TODO 8 | -------------------------------------------------------------------------------- /docs/src/docs/integrate/text-editor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Integrate - Text Editor' 3 | layout: base 4 | permalink: '/integrate/text-editor/index.html' 5 | --- 6 | 7 | # Text Editor 8 | 9 | Æsthetic is not yet available within text editors, but support is on the he roadmap. Though an official Æsthetic text editor extension/plugin is planned, Æsthetic is leverages within the [VSCode Liquid](#) extension. 10 | -------------------------------------------------------------------------------- /docs/src/docs/misc/benchmarks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Benchmarks' 3 | layout: base 4 | permalink: '/misc/benchmarks/index.html' 5 | --- 6 | -------------------------------------------------------------------------------- /docs/src/docs/misc/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Documentation' 3 | layout: base 4 | permalink: '/misc/documentation/index.html' 5 | --- 6 | 7 | # Documentation 8 | 9 | The Æsthetic documentation uses several different Open Source modules under the hood. Some considerable time went into producing documentation and developers are free to use the internal tools in their own projects. Below is brief breakdown and of third-parties leveraged and their appropriation. 10 | 11 | > Take a peek at the [source code](#) in the Æsthetic Github repository. 12 | 13 | ### 11ty 14 | 15 | Æsthetic docs are developed using the [11ty](#) static site generator. Æsthetic compiles markdown files and uses certain structures to determine how output should be written. The [.eleventy.js](#) file is where you will find all bundling logic. 16 | 17 | ### SPX + Stimulus 18 | 19 | Under the hood, the Æsthetic docs are using [SPX](#) which is an OTW (over the wire) module that intercepts navigation and maintains a snapshot cache engine in DOM state. SPX is used together with [Stimulus](#) to perform per-page interactivity and handling. 20 | 21 | **SPX** 22 | 23 | - [Repository](#) 24 | - [Documentation](#) 25 | 26 | **Stimulus** 27 | 28 | - [Repository](#) 29 | - [Documentation](#) 30 | 31 | ### Papyrus 32 | 33 | The Æsthetic rule examples are made possible with [Papyrus](#) which was developed for usage in the documentation. Papyrus provides editable (lightweight) embedded text regions with [PrismJS](#) grammars. 34 | 35 | - [Repository](#) 36 | - [Documentation](#) 37 | 38 | ### Moloko 39 | 40 | The Æsthetic playground is made possible with [Moloko](#) which provides a wrapped around the [Monaco Editor](#). Moloko leverages [Mithril](#) to virtually render Monaco and exposes some custom DX capabilities for specific usage in Æsthetic. 41 | 42 | **Moloko** 43 | 44 | - [Repository](#) 45 | - [Documentation](#) 46 | 47 | **Monaco** 48 | 49 | - [Repository](#) 50 | - [Documentation](#) 51 | -------------------------------------------------------------------------------- /docs/src/docs/misc/limitations.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Limitations' 3 | layout: base 4 | permalink: '/misc/limitations/index.html' 5 | --- 6 | 7 | # Limitations 8 | 9 | Æsthetic is comparatively _recluse_ in terms of PnP (plug and play) integrations/extensibility. Depending on your stack and development preferences you may wish to use Æsthetic together with additional tools like [eslint](https://eslint.org/), [stylelint](https://stylelint.io/) or even [Prettier](https://prettier.io/). There are a few notable caveats you should be aware before running Æsthetic, most of which are trivial. 10 | 11 | ## Æsthetic and Prettier 12 | 13 | It is not uncommon for developers to use Prettier in their projects but you should avoid executing Æsthetic alongside Prettier in code editor environments. You can easily prevent issues from arising by excluding the files Æsthetic handles by adding them to a `.prettierignore` file. 14 | 15 | ## Linters 16 | 17 | Æsthetic can be used together with tools like ESLint and StyleLint without the need to install additional plugins but the caveats come when you introduce Liquid into the code. Æsthetic can format Liquid contained in JavaScript, TypeScript, JSX and TSX but tools like ESLint are currently unable to process content of that nature and as such without official linting support for Liquid by these tools it is best to only run Æsthetic with linters on code that does not contain Liquid. 18 | 19 | ## Shopify Themes 20 | 21 | Developers working with straps like [Dawn](https://github.com/Shopify/dawn) should take some consideration before running Æsthetic on the distributed code contained within the project. Dawn is chaotic, novice and it employs some terrible approaches. Using Æsthetic blindly on the project may lead to problematic scenarios and readability issues. 22 | -------------------------------------------------------------------------------- /docs/src/docs/misc/terminologies.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Terminologies' 3 | layout: base 4 | permalink: '/misc/terminologies/index.html' 5 | --- 6 | 7 | # Rule Terminologies 8 | 9 | ### Forcing 10 | 11 | Æsthetic refers to placing content onto newlines as "forcing" or "force". 12 | 13 | ### Preserve or Ignore 14 | 15 | Æsthetic has 2 different forms of code exclusion. Preserved code and Ignored code are similar in the sense that content is skipped during beautification cycles but with preserved syntax indentation is respected whereas with ignored code indentation persisted as per the input. 16 | 17 | ### Fractional Wrapping 18 | 19 | Æsthetic implements a basic fractional based calculation approach for rules which need reference to the wrap limit. 20 | 21 | ### Allman Indentation 22 | 23 | ### Padding and Spacing 24 | 25 | ### Delimiters 26 | 27 | Delimiters are 28 | 29 | ### Leads 30 | 31 | ### External 32 | 33 | # Parse Terminologies 34 | 35 | ### Lexer 36 | 37 | ### Open and Close 38 | 39 | ### Start and End 40 | 41 | ### 42 | -------------------------------------------------------------------------------- /docs/src/docs/parser/lexers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Lexers' 3 | layout: base 4 | permalink: '/parser/lexers/index.html' 5 | order: 4 6 | anchors: 7 | - 'Markup' 8 | - 'Style' 9 | - 'Script' 10 | --- 11 | 12 | # Lexers 13 | 14 | TODO 15 | 16 | ## Markup 17 | 18 | TODO 19 | 20 | # Style 21 | 22 | TODO 23 | 24 | # Script 25 | 26 | TODO 27 | -------------------------------------------------------------------------------- /docs/src/docs/parser/parse-table.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Parse Table' 3 | layout: base 4 | permalink: '/parser/parse-table/index.html' 5 | anchors: 6 | - 'Algorithm' 7 | - 'Parse Table' 8 | - 'Terminology' 9 | --- 10 | 11 | # Data Structure 12 | 13 | The Sparser approach produces output in the form of parallel arrays instead of an AST format. The idea is that an AST can be created from a parse table provided one of the categories of data is structure and placement information, but a parse table cannot be created from an AST without running another parsing operation. The parse table approach also allows for sorting and analysis by selectively targeting various areas and data types without consideration for the output as a whole. 14 | -------------------------------------------------------------------------------- /docs/src/docs/parser/terminology.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Terminology' 3 | layout: base 4 | permalink: '/parser/terminology/index.html' 5 | --- 6 | 7 | # TODO 8 | -------------------------------------------------------------------------------- /docs/src/docs/parser/tokens.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Tokens' 3 | layout: base 4 | permalink: '/parser/tokens/index.html' 5 | anchors: 6 | - 'Tokens' 7 | - 'Parse Table' 8 | - 'Terminology' 9 | --- 10 | 11 | # Tokens 12 | 13 | The sparser algorithm uses a simple and elegant approach for token identification of character types. These character types are used in the beautification cycle to produce the formatted result and provide context to structural formation of the input. 14 | 15 | # Liquid 16 | 17 | TODO 18 | 19 | # Markup 20 | 21 | TODO 22 | 23 | # Style 24 | 25 | TODO 26 | 27 | # Script 28 | 29 | TODO 30 | -------------------------------------------------------------------------------- /docs/src/docs/usage/events.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Events' 3 | layout: base 4 | permalink: '/usage/events/index.html' 5 | anchors: 6 | - Events 7 | - Format 8 | - Rules 9 | - Parse 10 | - Error 11 | --- 12 | 13 | # Events 14 | 15 | Æsthetic provides a very modest event listening API. 16 | 17 | # Format 18 | 19 | 20 | ```js 21 | import esthetic from 'esthetic' 22 | 23 | 24 | esthetic.on('format', function({ output, stats, rules }) { 25 | 26 | console.log(this.data) 27 | 28 | console.log(output) 29 | 30 | console.log(stats) 31 | 32 | console.log(rules) 33 | 34 | }); 35 | 36 | ``` 37 | 38 | # Rules 39 | 40 | 41 | ```js 42 | import esthetic from 'esthetic' 43 | 44 | 45 | esthetic.on('rules', function(changed, rules) { 46 | 47 | console.log(changed) 48 | 49 | console.log(rules) 50 | 51 | }); 52 | 53 | ``` 54 | 55 | # Parse 56 | 57 | 58 | ```js 59 | import esthetic from 'esthetic' 60 | 61 | 62 | esthetic.on('parse', function({ data, stats, rules }) { 63 | 64 | console.log(data) 65 | 66 | console.log(stats) 67 | 68 | console.log(rules) 69 | 70 | }); 71 | 72 | 73 | ``` 74 | 75 | # Error 76 | 77 | 78 | ```js 79 | import esthetic from 'esthetic' 80 | 81 | 82 | esthetic.on('error', function(error) { 83 | 84 | console.log(error) 85 | 86 | 87 | }); 88 | 89 | 90 | ``` 91 | -------------------------------------------------------------------------------- /docs/src/docs/usage/grammar.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Grammar' 3 | layout: base 4 | permalink: '/usage/grammar/index.html' 5 | --- 6 | 7 | # TODO 8 | -------------------------------------------------------------------------------- /docs/src/docs/usage/hooks.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Hooks' 3 | layout: base 4 | permalink: '/usage/hooks/index.html' 5 | --- 6 | 7 | # TODO 8 | -------------------------------------------------------------------------------- /docs/src/docs/usage/ignoring-code.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Ignoring Code' 3 | layout: base 4 | permalink: '/usage/ignoring-code/index.html' 5 | prev: 6 | label: 'Format' 7 | uri: '/usage/format' 8 | next: 9 | label: 'Parse' 10 | uri: '/usage/parse' 11 | --- 12 | 13 | # Ignoring Code 14 | 15 | Excluding regions of code, entire documents and token specific occurrences can be achieved a few different ways in Æsthetic. Code exclusion and preservation is handled differently depending on the method leveraged and language. 16 | 17 | # Comments 18 | 19 | Æsthetic supports inline ignore comments and developers. 20 | 21 | ##### esthetic-ignore 22 | 23 | The `esthetic-ignore` comment can be used to exclude formatting on the entire document. 24 | 25 | ```liquid 26 | 27 | // esthetic-ignore 28 | 29 | /* esthetic-ignore */ 30 | 31 | 32 | 33 | {% # esthetic-ignore %} 34 | 35 | {% comment %} esthetic-ignore {% endcomment %} 36 | 37 | ``` 38 | 39 | ##### esthetic-ignore-next 40 | 41 | ```html 42 | 43 | 44 | {% # esthetic-ignore-next %} {% comment %} esthetic-ignore-next {% endcomment %} 45 | ``` 46 | 47 | ##### esthetic-ignore-start → esthetic-ignore-end 48 | 49 | ```liquid 50 | 51 | // esthetic-ignore-start 52 | // esthetic-ignore-end 53 | 54 | /* esthetic-ignore-start */ 55 | /* esthetic-ignore-end */ 56 | 57 | 58 | 59 | 60 | {% # esthetic-ignore-start %} 61 | {% # esthetic-ignore-end %} 62 | 63 | {% comment %} esthetic-ignore-start {% endcomment %} 64 | {% comment %} esthetic-ignore-end {% endcomment %} 65 | 66 | ``` 67 | 68 | # Rules 69 | -------------------------------------------------------------------------------- /docs/src/docs/usage/inline-control.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Inline Control' 3 | layout: base 4 | permalink: '/usage/inline-control/index.html' 5 | prev: 6 | label: 'Format' 7 | uri: '/usage/format' 8 | next: 9 | label: 'Parse' 10 | uri: '/usage/parse' 11 | --- 12 | 13 | # Inline Control 14 | 15 | Æsthetic provides inline control options for developers using comments. 16 | 17 | ### Ignore File 18 | 19 | 20 | ```html 21 | 22 | 23 |
24 | 27 |
28 | ``` 29 | 30 | ### Ignore Next 31 | 32 | 33 | ```html 34 | 35 | 36 |
37 | This token will not be formatted 38 |
39 | 40 | 43 | ``` 44 | 45 | ### Ignore Region 46 | 47 | 48 | ```html 49 | 50 | 51 |
52 | This token will not be formatted 53 |
54 | 55 | 56 | 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/src/docs/usage/language.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Formatting' 3 | layout: base 4 | permalink: '/usage/language/index.html' 5 | --- 6 | 7 | # TODO 8 | -------------------------------------------------------------------------------- /docs/src/docs/usage/method-chains.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Usage - Method Chains' 3 | layout: base 4 | permalink: '/usage/method-chaining/index.html' 5 | --- 6 | 7 | # Method Chains 8 | 9 | --- 10 | 11 | ## Rules 12 | 13 | ## Settings 14 | 15 | The `settings` method supports chaining. 16 | 17 | 18 | ```js 19 | import esthetic from 'esthetic'; 20 | 21 | // We will disable stat reporting and then define some formatting rules 22 | // Below we deconstruct the format method, but this can also be chained 23 | // 24 | const { format } = esthetic 25 | .settings({ reportStats: false }) 26 | .grammar({ html: { voids: ['singleton'] }}) 27 | .rules({ markup: { forceIndent: true } }) 28 | 29 | try { 30 | 31 | const input = `

Hello World!

`; 32 | const output = format(, { language: 'html' }); 33 | 34 | console.log(output); 35 | 36 | } catch(e) { 37 | console.error(e); 38 | } 39 | 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/src/docs/usage/parse.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Parse' 3 | layout: base 4 | permalink: '/usage/parse/index.html' 5 | prev: 6 | label: 'Inline Control' 7 | uri: '/usage/inline-control' 8 | next: 9 | label: 'Settings' 10 | uri: '/usage/settings' 11 | anchors: 12 | - Parse 13 | - Basic Usage 14 | --- 15 | 16 | # Parse 17 | 18 | The `parse` method can returns a uniform parse table data structure. Unlike many parsers that typically generate an [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree), Æsthetic follows a distinct path. Its implementation of Sparser results in a uniform table-like structure. 19 | 20 | ### Basic Usage 21 | 22 | 23 | ```js 24 | import esthetic from "esthetic"; 25 | 26 | const input = `
{% if x %}Hello World{% endif %}
`; 27 | 28 | try { 29 | 30 | const data = esthetic.parse(sample) 31 | console.log(data) 32 | 33 | } catch(e) { 34 | 35 | console.error(e) 36 | 37 | } 38 | 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/src/docs/usage/utilities.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Utilities' 3 | layout: base 4 | permalink: '/usage/utilities/index.html' 5 | anchors: 6 | - Utilities 7 | --- 8 | 9 | # TODO 10 | -------------------------------------------------------------------------------- /docs/src/rules/global/correct.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Global Rules - Correct' 3 | layout: base 4 | permalink: '/rules/global/correct/index.html' 5 | describe: 6 | - Correct 7 | - Rule Options 8 | options: 9 | - false 10 | - true 11 | --- 12 | 13 | # Correct 14 | 15 | TODO 16 | -------------------------------------------------------------------------------- /docs/src/rules/global/crlf.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Global Rules - CRLF' 3 | layout: base 4 | permalink: '/rules/global/crlf/index.html' 5 | --- 6 | 7 | ::: grid col-12 col-sm-9 p-100 8 | 9 | # CRLF 10 | 11 | If line termination should be Windows **CRLF** (CR = Carriage Return and LF = Line Feed) format. By default, Unix **LF** format is used. Setting this value to `true` will use CRLF. 12 | 13 | ::: 14 | 15 | --- 16 | 17 | ::: rule 👍 18 | 19 | #### false 20 | 21 | ::: 22 | 23 | ```json:rules 24 | { 25 | "esthetic": { 26 | "language": "html", 27 | "crlf": false 28 | }, 29 | "papyrus": { 30 | "showCRLF": true 31 | } 32 | } 33 | ``` 34 | 35 | This rule is **disabled** by default and line feed termination is used. 36 | 37 | 38 | ```liquid 39 | 44 | ``` 45 | 46 | --- 47 | 48 | ::: rule 👎 49 | 50 | #### true 51 | 52 | ::: 53 | 54 | When the rule is **enabled** carriage return and line feed termination is used. 55 | 56 | ```json:rules 57 | { 58 | "esthetic": { 59 | "language": "html", 60 | "crlf": true 61 | }, 62 | "papyrus": { 63 | "showCRLF": true 64 | } 65 | } 66 | ``` 67 | 68 | 69 | ```liquid 70 | 75 | ``` 76 | -------------------------------------------------------------------------------- /docs/src/rules/global/indentLevel.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Global Rules - Indent Level' 3 | layout: base 4 | permalink: '/rules/global/indentLevel/index.html' 5 | describe: 6 | - Indent Level 7 | --- 8 | 9 | ::: grid col-12 col-sm-9 p-100 10 | 11 | # Indent Level 12 | 13 | The `indentLevel` rule is typically used internally and will control the padding indentation to be applied. 14 | 15 | ::: 16 | 17 | --- 18 | 19 | 45 | 46 | ::: rule 💡 47 | 48 | #### `0` 49 | 50 | ::: 51 | 52 | The default `indentLevel` is set to `0` 53 | 54 | ```json:rules 55 | { 56 | "language": "html", 57 | "indentLevel": 0 58 | } 59 | ``` 60 | 61 | 62 | ```html 63 |
64 | 70 |
71 | ``` 72 | 73 | --- 74 | 75 | ::: rule 💡 76 | 77 | #### `2` 78 | 79 | ::: 80 | 81 | Below we are using an `indentLevel` value of `2` 82 | 83 | ```json:rules 84 | { 85 | "language": "html", 86 | "indentLevel": 2 87 | } 88 | ``` 89 | 90 | 91 | ```html 92 | 93 |
94 | 100 |
101 | ``` 102 | 103 | --- 104 | 105 | ::: rule 💡 106 | 107 | #### `5` 108 | 109 | ::: 110 | 111 | Below we are using an `indentLevel` value of `5` 112 | 113 | ```json:rules 114 | { 115 | "language": "html", 116 | "indentLevel": 5 117 | } 118 | ``` 119 | 120 | 121 | ```html 122 | 123 |
124 | 130 |
131 | ``` 132 | -------------------------------------------------------------------------------- /docs/src/rules/global/indentSize.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Global Rules - Indent Size' 3 | layout: base 4 | permalink: '/rules/global/indentSize/index.html' 5 | describe: 6 | - Indent Size 7 | - Rule Options 8 | --- 9 | 10 | ::: grid col-8 p-100 11 | 12 | # Indent Size 13 | 14 | The number of `indentChar` values to comprise a single indentation. By default this is set to `2` meaning a single indentation will be 2 whitespace characters. 15 | 16 | #### How to use Tabs? 17 | 18 | If you're heathen who prefers Tabs, then you will need to set the `indentChar` to `\t` and infer the size limit here. 19 | 20 | ::: 21 | 22 | --- 23 | 24 | 50 | 51 | ::: rule 💡 52 | 53 | #### `0` 54 | 55 | ::: 56 | 57 | Below is we have set the `indentSize` to `4` - Notice how the indentation increases by `2` after formatting. 58 | 59 | ```json:rules 60 | { 61 | "language": "html", 62 | "indentSize": 4 63 | } 64 | ``` 65 | 66 | 67 | ```html 68 |
69 | 75 |
76 | ``` 77 | -------------------------------------------------------------------------------- /docs/src/rules/global/preserveLine.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Global Rules - Indent Character' 3 | layout: base 4 | permalink: '/rules/global/preserveLine/index.html' 5 | --- 6 | 7 | ::: grid col-8 p-100 8 | 9 | # Preserve Line 10 | 11 | The maximum number of consecutive empty lines to retain (ie: preserve). By default, `3` newlines are preserved. 12 | 13 | > This is a global option and it will be used for markup, json, styles and scripts languages. 14 | 15 | ::: 16 | 17 | --- 18 | 19 | 45 | 46 | ::: rule 💡 47 | 48 | #### `0` 49 | 50 | ::: 51 | 52 | Below is we instructed to Æsthetic to preserve `0` empty lines. Notice how before formatting the code has several empty newlines but after formatting all lines are stripped. 53 | 54 | ```json:rules 55 | { 56 | "esthetic": { 57 | "language": "html", 58 | "preserveLine": 0 59 | }, 60 | "papyrus": { 61 | "showLF": true 62 | } 63 | } 64 | ``` 65 | 66 | 67 | ```html 68 | 79 | 80 | 81 |
82 | 83 | Lines 84 | 85 | 86 | 87 | 88 |
89 | ``` 90 | -------------------------------------------------------------------------------- /docs/src/rules/global/wrap.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Global Rules - Wrap' 3 | layout: base 4 | permalink: '/rules/global/wrap/index.html' 5 | prev: 6 | label: 'Preset' 7 | uri: '/rules/global/preset/' 8 | next: 9 | label: 'Wrap Fraction' 10 | uri: '/rules/global/wrapFraction/' 11 | describe: 12 | - Wrap 13 | - Example 14 | --- 15 | 16 | :::: grid row pr-5 17 | 18 | ::: grid col-6 p-100 pl-5 19 | 20 | # Wrap 21 | 22 | Character width limit before applying word wrap. A value of `0` will disable wrapping and is the default setting. 23 | 24 | > When this rule is undefined in a `.liquidrc` file the Text Editors settings will be used, in vscode that is `*.endWithNewline` where `*` is a language name. 25 | 26 | ::: 27 | 28 | ::: grid col-12 p-100 pl-5 29 | 30 | # Example 31 | 32 | Adjust the range to input to see how Æsthetic handles word wrap. 33 | 34 | ```json:rules 35 | { 36 | "papyrus": { 37 | "editor": false 38 | }, 39 | "example": { 40 | "rule": "wrap", 41 | "min": 20, 42 | "max": 100, 43 | "value": 80, 44 | "step": 1 45 | }, 46 | "esthetic": { 47 | "language": "html", 48 | "wrap": 80, 49 | "endNewline": false, 50 | "markup": { 51 | "forceIndent": true, 52 | "preserveText": false 53 | } 54 | } 55 | } 56 | ``` 57 | 58 | 59 | ```html 60 |
61 |

Hello World

62 |
63 | 64 |

Hello World

65 | 66 |
67 |

68 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 69 |

70 |

71 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat 72 |

73 |
74 | ``` 75 | 76 | ::: 77 | 78 | :::: 79 | -------------------------------------------------------------------------------- /docs/src/rules/global/wrapFraction.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Global Rules - Wrap Fraction' 3 | layout: base 4 | permalink: '/rules/global/wrapFraction/index.html' 5 | describe: 6 | - Wrap Fraction 7 | - Rule Options 8 | --- 9 | 10 | :::: grid row pr-5 11 | 12 | ::: grid col-6 p-100 pl-5 13 | 14 | # Wrap 15 | 16 | The `wrapFraction` rule is secondary character limit used to applying forcing on token structures. Fractional wrapping applied forcing when at `¾` (or 75%) of the global [wrap](/rules/global/wrap) limit and is referenced by different rules. 17 | 18 | ::: 19 | 20 | ::: grid col-12 p-100 pl-5 21 | 22 | # Example 23 | 24 | Adjust the range to input to see how Æsthetic handles word wrap. 25 | 26 | ```json:rules 27 | { 28 | "papyrus": { 29 | "editor": false 30 | }, 31 | "example": { 32 | "rule": "wrapFraction", 33 | "min": 20, 34 | "max": 100, 35 | "value": 80, 36 | "step": 1 37 | }, 38 | "esthetic": { 39 | "language": "liquid", 40 | "wrap": 100, 41 | "wrapFraction":80, 42 | "endNewline": false, 43 | "liquid": { 44 | "forceFilter": 0, 45 | "forceArgument": 0, 46 | "delimiterPlacement": "force-multiline" 47 | }, 48 | "markup": { 49 | "forceIndent": true, 50 | "preserveText": false 51 | } 52 | } 53 | } 54 | ``` 55 | 56 | 57 | ```liquid 58 |
59 | {% unless product.metafields.data == nil and product == nil %} 60 | 61 | {% form 'x', id: 'xxx', attr_1: 'foo', attr_2: 'bar' %} 62 | 63 | {{ settings.logo 64 | | replace: ',' , 'foo' 65 | | font_family: 'bold', '300', 'exec' }} 66 | 67 | {% render 'snippet', param_1: true, param_2: 1000 %} 68 | {% endform %} 69 | 70 | 71 | {% endunless %} 72 |
73 | ``` 74 | 75 | ::: 76 | 77 | :::: 78 | -------------------------------------------------------------------------------- /docs/src/rules/json/allowComments.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/rules/json/allowComments.md -------------------------------------------------------------------------------- /docs/src/rules/json/arrayFormat.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/rules/json/arrayFormat.md -------------------------------------------------------------------------------- /docs/src/rules/json/bracePadding.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/rules/json/bracePadding.md -------------------------------------------------------------------------------- /docs/src/rules/json/objectIndent.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/rules/json/objectIndent.md -------------------------------------------------------------------------------- /docs/src/rules/json/objectSort.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/rules/json/objectSort.md -------------------------------------------------------------------------------- /docs/src/rules/liquid/commentIndent.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Liquid - Comment Indent' 3 | layout: base 4 | permalink: '/rules/liquid/commentIndent/index.html' 5 | prev: 6 | label: 'Wrap Fraction' 7 | uri: '/rules/global/wrapFraction/' 8 | next: 9 | label: 'Comment Newline' 10 | uri: '/rules/liquid/commentNewline/' 11 | describe: 12 | - Comment Indent 13 | - Rule Override 14 | - Rule Options 15 | options: 16 | - false 17 | - true 18 | --- 19 | 20 | ::: grid col-8 p-100 21 | 22 | # Comment Indent 23 | 24 | The `commentIndent` rule applies single level indentation to the containing content of Liquid **block** type comments. This is a Liquid specific formatting rule which defaults to using `false` when no option is defined. The **Recommended** setting to use is `true`. 25 | 26 | > Liquid line type comments `{% # example %}` are currently not supported by this rule. Only block type Liquid tokens will be handled. 27 | 28 | # Rule Override 29 | 30 | When the [`preserveComment`](/rules/liquid/preserveComment) (liquid) rule is enabled (i.e: `true`) it will take precedence and override `commentIndent` rule. 31 | 32 | - [preserveComment](/rules/liquid/preserveComment) 33 | 34 | ::: 35 | 36 | --- 37 | 38 | ::: rule 🙌 39 | 40 | #### true 41 | 42 | ::: 43 | 44 | Below is an example of how this rule works if it's enabled (`true`). Notice how after formatting when this rule is enabled that the inner contents of the Liquid comment tag regions are indented. 45 | 46 | ```json:rules 47 | { 48 | "language": "liquid", 49 | "liquid": { 50 | "commentIndent": true 51 | } 52 | } 53 | ``` 54 | 55 | 56 | ```liquid 57 | {% comment %} 58 | Example 59 | The contents of this comment will have indentation applied 60 | {% endcomment %} 61 | ``` 62 | 63 | --- 64 | 65 | ::: rule 👎 66 | 67 | #### false 68 | 69 | ::: 70 | 71 | The `commentIndent` rule is **disabled** by default, so Liquid comments do not apply indentation. Liquid block comment contents will have indentation removed in the sample when formatting. 72 | 73 | 74 | 75 | ```json:rules 76 | { 77 | "language": "liquid", 78 | "liquid": { 79 | "commentIndent": false 80 | } 81 | } 82 | ``` 83 | 84 | 85 | ```liquid 86 | {% comment %} 87 | Example 88 | The contents of this comment will have indentation stripped. 89 | {% endcomment %} 90 | ``` 91 | -------------------------------------------------------------------------------- /docs/src/rules/liquid/commentNewline.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Liquid - Comment Newline' 3 | layout: base 4 | permalink: '/rules/liquid/commentNewline/index.html' 5 | describe: 6 | - Comment Newline 7 | - Rule Options 8 | options: 9 | - false 10 | - true 11 | --- 12 | 13 | ::: grid col-8 p-100 14 | 15 | # Comment Newline 16 | 17 | Inserts a new line above comment tags. When enabled the rule will add a newline even if `preserveLine` is set to `0`. The rule will not inject new lines when the previous expression is determined to already contain a new line. The `commentNewline` rule is disabled (`false`) by default. Newline insertion will not be applied to comments blocks in the sample. 18 | 19 | > Liquid line type comments are currently not supported by this rule. Only block type Liquid tokens will be handled. 20 | 21 | ::: 22 | 23 | --- 24 | 25 | ::: rule 👍 26 | 27 | #### false 28 | 29 | ::: 30 | 31 | If the rule is `undefined` or set to `false` (which is the default). In the sample, there will be no change applied. 32 | 33 | ```json:rules 34 | { 35 | "language": "liquid", 36 | "liquid": { 37 | "commentNewline": false 38 | } 39 | } 40 | ``` 41 | 42 | 43 | ```liquid 44 |
45 | {% comment %} 46 | No newline will be inserted above this comment 47 | {% endcomment %} 48 | 51 | {% comment %} 52 | No newline will be inserted above this comment 53 | {% endcomment %} 54 |
55 | ``` 56 | 57 | --- 58 | 59 | ::: rule 🙌 60 | 61 | #### true 62 | 63 | ::: 64 | 65 | When the `commentNewline` rule is enabled (`true`) then a newline will inserted above the `{% comment %}` tag. In the sample, the comment which immediately follows the `
  • ` tag will have a newline inserted above. When a newline exists above a comment tag then no insertion is applied. 66 | 67 | ```json:rules 68 | { 69 | "language": "liquid", 70 | "liquid": { 71 | "commentNewline": true 72 | } 73 | } 74 | ``` 75 | 76 | 77 | ```liquid 78 |
      79 |
    • Hello
    • 80 | {% comment %} 81 | A newline will be inserted above this comment 82 | {% endcomment %} 83 |
    • World
    • 84 | {% comment %} 85 | Same as above, a newline will be inserted 86 | {% endcomment %} 87 |
    88 | ``` 89 | -------------------------------------------------------------------------------- /docs/src/rules/liquid/dedentTagList.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Liquid - Dedent Tag List' 3 | layout: base 4 | permalink: '/rules/liquid/dedentTagList/index.html' 5 | describe: 6 | - Dedent Tag List 7 | - Rule Options 8 | examples: 9 | - case 10 | - schema 11 | --- 12 | 13 | ::: grid col-8 p-100 14 | 15 | # Dedent Tag List 16 | 17 | Omit applied indentation within Liquid tag blocks. By default, Æsthetic will indent content encapsulated within Liquid tags blocks. Tag blocks are Liquid tokens which require ender type be passed. This is a Liquid specific formatting rule which defaults to using `[]` when no option has been specified. You should avoid applying de-dentation to common used Liquid tags. The **recommended** entry to provide the rule is the `case` tag name. 18 | 19 | > The rules behavior will differ depending on the tag structure. Passing in singleton type tag names such as `"assign"` or `"render"` will have no effect on output. 20 | 21 | ::: 22 | 23 | --- 24 | 25 | ::: rule 💡 26 | 27 | #### case 28 | 29 | ::: 30 | 31 | The below sample will result in the `{% when %}` tokens of the expression to dedent. The tokens will align themselves to starting levels of the `{% case %}` and its `{% endcase %}` tag placements. 32 | 33 | ```json:rules 34 | { 35 | "language": "liquid", 36 | "liquid": { 37 | "dedentTagList": [ 38 | "case" 39 | ] 40 | } 41 | } 42 | ``` 43 | 44 | 45 | ```liquid 46 | {% case 'dedent-example' -%} 47 | {% when foo %} 48 | {{ object.prop }} 49 | {% when bar %} 50 | {{ object.prop | filter: 'xxx' }} 51 | {% when baz %} 52 | Hello World! 53 | {% else %} 54 | Lorem Ipsum 55 | {% endcase %} 56 | ``` 57 | 58 | --- 59 | 60 | ::: rule 💡 61 | 62 | #### schema 63 | 64 | ::: 65 | 66 | ```json:rules 67 | { 68 | "language": "liquid", 69 | "liquid": { 70 | "dedentTagList": [ 71 | "schema" 72 | ] 73 | } 74 | } 75 | ``` 76 | 77 | 78 | ```liquid 79 | {% schema %} 80 | { 81 | "name": "Section", 82 | "tag": "main", 83 | "class": "some-class", 84 | "settings": [ 85 | { 86 | "type": "header", 87 | "content": "Example", 88 | "info": "The braces {} will dedent" 89 | } 90 | ] 91 | } 92 | {% endschema %} 93 | ``` 94 | 95 | --- 96 | -------------------------------------------------------------------------------- /docs/src/rules/liquid/forceIndent.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/rules/liquid/forceIndent.md -------------------------------------------------------------------------------- /docs/src/rules/liquid/ignoreTagList.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Liquid - Ignore Tag List' 3 | layout: base 4 | permalink: '/rules/liquid/ignoreTagList/index.html' 5 | describe: 6 | - Ignore Tag List 7 | - Example Options 8 | - Rule Options 9 | - Examples 10 | --- 11 | 12 | ::: grid col-9 p-100 13 | 14 | # Ignore Tag List 15 | 16 | A list of Liquid tags that should excluded from formatting. Only tags which contain a start and end types are valid. This is a Liquid specific formatting rule which defaults to using `0` when no option has been specified. 17 | 18 | ::: 19 | 20 | 29 | 30 | --- 31 | 32 | # Example 33 | 34 | ```json:rules 35 | { 36 | "language": "liquid", 37 | "wrap": 0, 38 | "preserveLine": 2, 39 | "liquid": { 40 | "ignoreTagList": [ 41 | "for", 42 | "unless" 43 | ] 44 | } 45 | } 46 | ``` 47 | 48 | Below we are ignoring `{% for %}` and `{% unless %}` tag regions. Æsthetic will be skipped formatting these tag blocks. Ignored regions are excluded in a strict manner, so indentation levels are completely void of change and will persist. Only the surrounding tokens will have beautification applied. 49 | 50 | 51 | ```liquid 52 |
    53 | {% if x == true %} 54 | 55 | {% for i in array %} 56 | {% # This region will not be formatted %} 57 | {% for x in i.ignored %} 58 | {{ i.xxx }} {% # Nested tags are also ignored %} 59 | {% endfor %} 60 | {% # Notice how no indentation is applied %} 61 | {% endfor %} 62 | 63 | {% if xx == true %} 64 |
      65 |
    • 66 | This tag will format but below will not 67 |
    • 68 | {% unless bar %} 69 | 70 |
    • 71 | {% # This region will not be formatted %} 72 |
    • 73 | 74 | {% endunless %} 75 |
    • 76 | This tag will format but above will not 77 |
    • 78 |
    79 | {% endif %} 80 | {% endif %} 81 |
    82 | ``` 83 | -------------------------------------------------------------------------------- /docs/src/rules/liquid/paddedTagList.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Liquid - Padded Tag List' 3 | layout: base 4 | permalink: '/rules/liquid/paddedTagList/index.html' 5 | describe: 6 | - Ignore Tag List 7 | - Example Options 8 | - Rule Options 9 | - Examples 10 | --- 11 | 12 | ::: grid col-12 col-sm-9 p-100 13 | 14 | # Padded Tag List 15 | 16 | A list of Liquid tags that should have newlines inserted above and below inner contents. Padding will only apply to Liquid start/end type tags or singleton types which can be used together to perform chained control flows. Passing isolated singleton (or _void_) liquid tags such as `assign` or Liquid object output types will have no effect. 17 | 18 | ::: 19 | 20 | 29 | 30 | --- 31 | 32 | # Example 33 | 34 | ```json:rules 35 | { 36 | "language": "liquid", 37 | "wrap": 0, 38 | "preserveLine": 2, 39 | "liquid": { 40 | "ignoreTagList": [ 41 | 42 | ] 43 | } 44 | } 45 | ``` 46 | 47 | Below we are ignoring `{% for %}` and `{% unless %}` tag regions. Æsthetic will be skipped formatting these tag blocks. Ignored regions are excluded in a strict manner, so indentation levels are completely void of change and will persist. Only the surrounding tokens will have beautification applied. 48 | 49 | 50 | ```liquid 51 |
    52 | {% if x == true %} 53 | 54 | {% for i in array %} 55 | {% # This region will not be formatted %} 56 | {% for x in i.ignored %} 57 | {{ i.xxx }} {% # Nested tags are also ignored %} 58 | {% endfor %} 59 | {% # Notice how no indentation is applied %} 60 | {% endfor %} 61 | 62 | {% if xx == true %} 63 |
      64 |
    • 65 | This tag will format but below will not 66 |
    • 67 | {% unless bar %} 68 | 69 |
    • 70 | {% # This region will not be formatted %} 71 |
    • 72 | 73 | {% endunless %} 74 |
    • 75 | This tag will format but above will not 76 |
    • 77 |
    78 | {% endif %} 79 | {% endif %} 80 |
    81 | ``` 82 | -------------------------------------------------------------------------------- /docs/src/rules/liquid/preserveInternal.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Liquid - Preserve Internal' 3 | layout: base 4 | permalink: '/rules/liquid/preserveInternal/index.html' 5 | anchors: 6 | - '' 7 | --- 8 | 9 | # RULE_NAME 10 | 11 | Lorem Ipsum 12 | 13 | ::: note 14 | Lorem Ipsum 15 | ::: 16 | 17 | ##### RELATED_RULES 18 | 19 | Lorem Ipsum 20 | 21 | --- 22 | 23 | # Rule Options 24 | 25 | This is a LANGUAGE_NAME specific formatting rule which defaults to using `preserve` when no option has been specified. 26 | 27 | 36 | 37 | ::: rule 👍 38 | 39 | #### RULE_OPTION 40 | 41 | ::: 42 | 43 | Lorem Ipsum 44 | 45 | 46 | 47 | ```json:rules 48 | { 49 | "language": "liquid", 50 | "liquid": { 51 | "preserveInternal": false 52 | } 53 | } 54 | ``` 55 | 56 | 57 | ```liquid 58 | 59 | {% # All argument comma separators will be placed at the end %} 60 | {% render 'snippet', 61 | param_1: true, 62 | param_2: 1000 63 | , param_3: 'string' 64 | , param_4: nil %} 65 | 66 | {% if condition == assertion %} 67 | 68 | {% # Filter argument using a comma separator will be placed at the end %} 69 | {{ object.prop 70 | | param_1: true, 71 | | param_2: 1000 72 | | param_3: 73 | arg_1: 'value' 74 | , arg_2: 2000 75 | , arg_3: false 76 | , arg_4: nil 77 | | param_4: 'xxxx' }} 78 | 79 | {% endif %} 80 | 81 | ``` 82 | 83 | --- 84 | -------------------------------------------------------------------------------- /docs/src/rules/markup/commentIndent.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Markup - Comment Indent' 3 | layout: base 4 | permalink: '/rules/markup/commentIndent/index.html' 5 | describe: 6 | - Comment Indent 7 | - Rule Options 8 | options: 9 | - false 10 | - true 11 | --- 12 | 13 | ::: grid col-12 col-sm-9 p-100 14 | 15 | # Comment Indent 16 | 17 | Applies single indentation to containing content of HTML and XML comments which span multiple lines. This is a markup specific formatting rule which will be applied to HTML or XML comments. It will **default** to using `false` when no option has been specified and the **recommended** option to use is `true`. 18 | 19 | > This rule only effects markup comments containing newlines. Inline markup comments which start and end on the same line will skipped. 20 | 21 | ::: 22 | 23 | --- 24 | 25 | ::: rule 👎 26 | 27 | #### false 28 | 29 | ::: 30 | 31 | The `commentIndent` rule is **disabled** by default, so Liquid comments do not apply indentation. Liquid block comment contents will have indentation removed in the sample when formatting. 32 | 33 | 34 | 35 | ```json:rules 36 | { 37 | "language": "html", 38 | "markup": { 39 | "commentIndent": false 40 | } 41 | } 42 | ``` 43 | 44 | 45 | ```html 46 | 50 |
    51 | 55 | 60 |
    61 | ``` 62 | 63 | --- 64 | 65 | ::: rule 🙌 66 | 67 | #### true 68 | 69 | ::: 70 | 71 | Below is an example of how this rule works if it's enabled (`true`). Notice how after formatting when this rule is enabled that the inner contents of the Liquid comment tag regions are indented. 72 | 73 | ```json:rules 74 | { 75 | "language": "html", 76 | "markup": { 77 | "commentIndent": true 78 | } 79 | } 80 | ``` 81 | 82 | 83 | ```html 84 | 88 |
    89 | 93 | 98 |
    99 | ``` 100 | -------------------------------------------------------------------------------- /docs/src/rules/markup/commentNewline.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Markup - Comment Newline' 3 | layout: base 4 | permalink: '/rules/markup/commentNewline/index.html' 5 | describe: 6 | - Comment Newline 7 | - Rule Options 8 | options: 9 | - false 10 | - true 11 | --- 12 | 13 | ::: grid col-12 col-sm-9 p-100 14 | 15 | # Comment Newline 16 | 17 | Inserts a new line above comment tags. When enabled the rule will add a newline even if `preserveLine` is set to `0`. The rule will not inject new lines when the previous expression is determined to already contain a new line. 18 | 19 | 28 | 29 | ::: 30 | 31 | --- 32 | 33 | ::: rule 👎 34 | 35 | #### false 36 | 37 | ::: 38 | 39 | The `commentNewline` rule is **disabled** by default. HTML comments will not insert a newline above comments. Notice how the HTML type comment tag immediately following the `
  • ` nodes will only adhere to the `preserveLine` global rule. 40 | 41 | ```json:rules 42 | { 43 | "language": "html", 44 | "markup": { 45 | "commentNewline": false 46 | } 47 | } 48 | ``` 49 | 50 | ```html 51 |
      52 |
    • Hello
    • 53 | 56 |
    • World
    • 57 | 58 | 62 |
    • How are you?
    • 63 |
    64 | ``` 65 | 66 | --- 67 | 68 | ::: rule 🙌 69 | 70 | #### true 71 | 72 | ::: 73 | 74 | When the markup `commentNewline` rule is enabled (i.e: `true) then newlines will be inserted above the comments. The first comment in the example below will have a newline inserted. The second comment will remain intact as a newline already exists. 75 | 76 | ```json:rules 77 | { 78 | "language": "html", 79 | "markup": { 80 | "commentNewline": true 81 | } 82 | } 83 | ``` 84 | 85 | ```html 86 |
      87 |
    • Hello
    • 88 | 91 |
    • World
    • 92 | 93 | 97 |
    • How are you?
    • 98 |
    99 | ``` 100 | -------------------------------------------------------------------------------- /docs/src/rules/markup/correct.md: -------------------------------------------------------------------------------- 1 |  ⚙️   **Default** `false` 2 | 3 |  💁🏽‍♀️   Recommended setting is `false` 4 | 5 | #### Correct 6 | 7 | Automatically correct some sloppiness in markup languages and allows Prettify to reason with intended structures. The option acts as a very mild form of linting, wherein invalid or language specification preferred code will attempt to be corrected in the least obtrusive manner possible and with respect to language standards. Enabling this rule is not going to produce miracles and for the most part will have little effect overall but can help in some situations. 8 | 9 | > This rule is still experimental and will be both improved and refined in future versions. 10 | 11 | # 12 | 13 | --- 14 | 15 | 16 | #### Applied Corrections 17 | 18 | Below is a list of current applied corrections supported when the rule is enabled, (ie: `true`). The comments in the example below will inform upon corrections that the rule will apply to code where necessary. 19 | 20 | ```css 21 | 22 | /* Semicolon will be added when missing */ 23 | .class { 24 | font-weight: 200 25 | } 26 | 27 | 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /docs/src/rules/markup/forceIndent.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Markup - Force Indent' 3 | layout: base 4 | permalink: '/rules/markup/forceIndent/index.html' 5 | describe: 6 | - Force Indent 7 | - Rule Options 8 | options: 9 | - false 10 | - true 11 | --- 12 | 13 | ::: grid col-8 p-100 14 | 15 | # Force Indent 16 | 17 | Will force indentation upon all content and tags without regard for the text nodes. To some degree this rule emulates a result similar to that you'd expect in the Prettier uniform. 18 | 19 | > Inline preservation is respected in cases where a Liquid output object token is encapsulated between text nodes. In such scenarios the text content will only force indent the start and end portions. 20 | 21 | ::: 22 | 23 | --- 24 | 25 | ::: rule 👍 26 | 27 | #### true 28 | 29 | ::: 30 | 31 | Below is an example of how this rule works if it's enabled, ie: `true`. Notice how the text type nodes encapsulated within `
  • ` tags are expressed inline. 32 | 33 | ```json:rules 34 | { 35 | "language": "html", 36 | "markup": { 37 | "forceIndent": true 38 | } 39 | } 40 | ``` 41 | 42 | ```html 43 | 44 | 48 | ``` 49 | 50 | --- 51 | 52 | ::: rule 👍 53 | 54 | #### false 55 | 56 | ::: 57 | 58 | Using the above sample with the rule enabled (ie: `true`), when applying beautification the text type node are no longer inlined, but instead have applied new line breaks and been force indented. 59 | 60 | ```json:rules 61 | { 62 | "language": "html", 63 | "markup": { 64 | "forceIndent": false 65 | } 66 | } 67 | ``` 68 | 69 | ```html 70 | 71 | 75 | ``` 76 | -------------------------------------------------------------------------------- /docs/src/rules/markup/ignoreJSON.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Markup - Ignore JSON' 3 | layout: base 4 | permalink: '/rules/markup/ignoreJSON/index.html' 5 | describe: 6 | - Ignore JSON 7 | - Rule Options 8 | options: 9 | - false 10 | - true 11 | --- 12 | 13 | ::: grid col-8 p-100 14 | 15 | # Ignore JSON 16 | 17 | Whether or not to format regions of code that are identified to be JSON. Such tags are typically identified using attribute annotations like ` 54 | 55 | 56 | ``` 57 | 58 | --- 59 | 60 | ::: rule 🧐 61 | 62 | #### false 63 | 64 | ::: 65 | 66 | After formatting the above sample notice how the `` region has been completely skipped from formatting. Ignored regions are excluded in a strict manner, so indentation levels are completely void of change and will persist. Only the surrounding tokens will have beautification applied. 67 | 68 | ```json:rules 69 | { 70 | "language": "html", 71 | "markup": { 72 | "ignoreJSON": false 73 | } 74 | } 75 | ``` 76 | 77 | 78 | ```html 79 | 80 | 81 | 82 | Example 83 | 84 | 85 | 91 | 92 | 93 | ``` 94 | -------------------------------------------------------------------------------- /docs/src/rules/markup/lineBreakValue.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Markup - Line Break Value' 3 | layout: base 4 | permalink: '/rules/markup/lineBreakValue/index.html' 5 | anchors: 6 | - Line Break Value 7 | options: 8 | - 'preserve' 9 | - 'align' 10 | - 'indent' 11 | - 'force-preserve' 12 | - 'force-align' 13 | - 'force-indent' 14 | --- 15 | 16 | ::: grid col-8 p-100 17 | 18 | # Line Break Value 19 | 20 | TODO 21 | -------------------------------------------------------------------------------- /docs/src/rules/markup/selfCloseSVG.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Markup - Self Close SVG' 3 | layout: base 4 | permalink: '/rules/markup/selfCloseSVG/index.html' 5 | describe: 6 | - Self Close SVG 7 | - Rule Options 8 | options: 9 | - true 10 | - false 11 | --- 12 | -------------------------------------------------------------------------------- /docs/src/rules/markup/selfCloseSpace.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Markup - Self Close Space' 3 | layout: base 4 | permalink: '/rules/markup/selfCloseSpace/index.html' 5 | describe: 6 | - Self Close Space 7 | - Rule Options 8 | options: 9 | - true 10 | - false 11 | --- 12 | 13 | ::: grid col-8 p-100 14 | 15 | # Self Close Space 16 | 17 | Whether markup self-closing (void) tags should apply a single space to ending portion of the delimiter which results in the tag output to produce `' />'` instead of `'/>'`. 18 | 19 | ::: 20 | 21 | --- 22 | 23 | --- 24 | 25 | ::: rule 🙌 26 | 27 | #### true 28 | 29 | ::: 30 | 31 | When the markup `selfCloseSpace` rule is enabled (i.e: `true`) then forward slash closing delimiters will insert a single space character. 32 | 33 | ```json:rules 34 | { 35 | "language": "html", 36 | "markup": { 37 | "selfCloseSpace": true 38 | } 39 | } 40 | ``` 41 | 42 | 43 | ```html 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | ``` 56 | 57 | --- 58 | 59 | ::: rule 👎 60 | 61 | #### false 62 | 63 | ::: 64 | 65 | When the markup `selfCloseSpace` rule is disabled (i.e: `false`) then forward slash closing delimiters will strip leading spaces. 66 | 67 | ```json:rules 68 | { 69 | "language": "html", 70 | "markup": { 71 | "selfCloseSpace": false 72 | } 73 | } 74 | ``` 75 | 76 | 77 | ```html 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | ``` 90 | -------------------------------------------------------------------------------- /docs/src/rules/strap.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'LANGUAGE - RULE_NAME' 3 | layout: base 4 | permalink: '/rules/[LANGUAGE]/[RULE_NAME]/index.html' 5 | anchors: 6 | - '' 7 | --- 8 | 9 | # RULE_NAME 10 | 11 | Lorem Ipsum 12 | 13 | ::: note 14 | Lorem Ipsum 15 | ::: 16 | 17 | ##### RELATED_RULES 18 | 19 | Lorem Ipsum 20 | 21 | --- 22 | 23 | # Rule Options 24 | 25 | This is a LANGUAGE_NAME specific formatting rule which defaults to using `preserve` when no option has been specified. 26 | 27 | 40 | 41 | ::: rule 👍 42 | 43 | #### RULE_OPTION 44 | 45 | ::: 46 | 47 | Lorem Ipsum 48 | 49 | 50 | 51 | ```json:rules 52 | { 53 | "language": "", 54 | } 55 | ``` 56 | 57 | 58 | ```liquid 59 | 60 | ``` 61 | 62 | --- 63 | -------------------------------------------------------------------------------- /docs/src/rules/style/atRuleSpace.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Style - At Rule Space' 3 | layout: base 4 | permalink: '/rules/style/atRuleSpace/index.html' 5 | describe: 6 | - Delimiter Trims 7 | - Rule Options 8 | options: 9 | - preserve 10 | - tags 11 | - outputs 12 | - never 13 | - always 14 | - multiline 15 | --- 16 | 17 | ::: grid col-12 col-sm-9 p-100 18 | 19 | # At Rule Space 20 | 21 | Insert or strip whitespace of `@` at rules prefixed CSS rules and their starting parenthesis. 22 | ::: 23 | 24 | 33 | 34 | --- 35 | 36 | ::: rule 👍 37 | 38 | #### true 39 | 40 | ::: 41 | 42 | The `atRuleSpace` style rule is enabled (i.e: `true`) by default. The rule will ensure the `@` at rules will use a single whitespace occurrences before the starting parenthesis. 43 | 44 | ```json:rules 45 | { 46 | "language": "css", 47 | "style": { 48 | "atRuleSpace": true 49 | } 50 | } 51 | ``` 52 | 53 | 54 | ```css 55 | 56 | @media(min-width: 1200px) { 57 | .some-selector { 58 | font-size: 1.5rem; 59 | background-color: whitesmoke; 60 | } 61 | } 62 | 63 | @media(prefers-reduced-motion: reduce) { 64 | .foo { 65 | color: black; 66 | width: 200px; 67 | height: 200px; 68 | } 69 | } 70 | 71 | ``` 72 | 73 | --- 74 | 75 | ::: rule 🤡 76 | 77 | #### false 78 | 79 | ::: 80 | 81 | The `atRuleSpace` style rule is disabled (i.e: `false`) then `@` rule occurrences will have white stripped between the rule name and the starting parenthesis. 82 | 83 | ```json:rules 84 | { 85 | "language": "css", 86 | "style": { 87 | "atRuleSpace": false 88 | } 89 | } 90 | ``` 91 | 92 | 93 | ```css 94 | 95 | @media(min-width: 1200px) { 96 | .some-selector { 97 | font-size: 1.5rem; 98 | background-color: whitesmoke; 99 | } 100 | } 101 | 102 | @media(prefers-reduced-motion: reduce) { 103 | .foo { 104 | color: black; 105 | width: 200px; 106 | height: 200px; 107 | } 108 | } 109 | 110 | ``` 111 | -------------------------------------------------------------------------------- /docs/src/rules/style/classPadding.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Style - Class Padding' 3 | layout: base 4 | permalink: '/rules/style/classPadding/index.html' 5 | anchors: 6 | - '' 7 | --- 8 | 9 | ::: grid col-12 col-sm-9 p-100 10 | 11 | # Class Padding 12 | 13 | The `classPadding` rule will insert a newline **before** and **after** the starting and ending structure of class selectors properties. 14 | 15 | --- 16 | 17 | ::: 18 | 19 | 28 | 29 | ::: rule 🙌 30 | 31 | #### false 32 | 33 | ::: 34 | 35 | Lorem Ipsum 36 | 37 | 38 | 39 | ```json:rules 40 | { 41 | "language": "css", 42 | "style": { 43 | "classPadding": false 44 | } 45 | } 46 | ``` 47 | 48 | 49 | ```css 50 | .class-a { 51 | width: 100px; 52 | } 53 | .class-b { 54 | width: 100px; 55 | } 56 | .class-c { 57 | width: 100px; 58 | } 59 | .class-d { 60 | width: 100px; 61 | } 62 | ``` 63 | 64 | --- 65 | 66 | ::: rule 👍 67 | 68 | #### true 69 | 70 | ::: 71 | 72 | ```json:rules 73 | { 74 | "language": "css", 75 | "style": { 76 | "classPadding": true 77 | } 78 | } 79 | ``` 80 | 81 | 82 | ```css 83 | .class-a { 84 | width: 100px; 85 | } 86 | .class-b { 87 | width: 100px; 88 | } 89 | .class-c { 90 | width: 100px; 91 | } 92 | .class-d { 93 | width: 100px; 94 | } 95 | ``` 96 | -------------------------------------------------------------------------------- /docs/src/rules/style/noLeadZero.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Style - No Lead Zero' 3 | layout: base 4 | permalink: '/rules/style/noLeadZero/index.html' 5 | anchors: 6 | - '' 7 | --- 8 | 9 | # No Lead Zero 10 | 11 | The `noLeadZero` rule will eliminate leading zeros from numbers expressed within values. 12 | 13 | --- 14 | 15 | 24 | 25 | ::: rule 👍 26 | 27 | #### false 28 | 29 | ::: 30 | 31 | Lorem Ipsum 32 | 33 | 34 | 35 | ```json:rules 36 | { 37 | "language": "css", 38 | "style": { 39 | "noLeadZero": false 40 | } 41 | } 42 | ``` 43 | 44 | 45 | ```css 46 | .class-a { 47 | width: 0.5px; 48 | height: 0.05rem; 49 | left: 0.1em; 50 | right: 0.50cm; 51 | top: 0.3ch; 52 | } 53 | ``` 54 | 55 | --- 56 | 57 | ::: rule 👍 58 | 59 | #### true 60 | 61 | ::: 62 | 63 | ```json:rules 64 | { 65 | "language": "css", 66 | "style": { 67 | "noLeadZero": true 68 | } 69 | } 70 | ``` 71 | 72 | 73 | ```css 74 | .class-a { 75 | width: 0.5px; 76 | height: 0.05rem; 77 | left: 0.1em; 78 | right: 0.50cm; 79 | top: 0.3ch; 80 | } 81 | ``` 82 | -------------------------------------------------------------------------------- /docs/src/rules/style/shorthandMargin.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/rules/style/shorthandMargin.md -------------------------------------------------------------------------------- /docs/src/rules/style/shorthandPadding.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/rules/style/shorthandPadding.md -------------------------------------------------------------------------------- /docs/src/rules/style/sortProperties.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Style - Sort Properties' 3 | layout: base 4 | permalink: '/rules/style/sortProperties/index.html' 5 | anchors: 6 | - '' 7 | --- 8 | 9 | # Sort Properties 10 | 11 | The `sortProperties` rule will apply alphabetical sorting to style class selector properties.. 12 | 13 | --- 14 | 15 | 24 | 25 | ::: rule 🙌 26 | 27 | #### true 28 | 29 | ::: 30 | 31 | Lorem Ipsum 32 | 33 | 34 | 35 | ```json:rules 36 | { 37 | "language": "css", 38 | "style": { 39 | "sortProperties": true 40 | } 41 | } 42 | ``` 43 | 44 | 45 | ```css 46 | .class { 47 | z-index: 999; 48 | color: #fff; 49 | width: 200px; 50 | background-repeat: no-repeat; 51 | background-position: top; 52 | background-attachment: fixed; 53 | font-weight: 100; 54 | font-style: bold; 55 | margin-top: 100px; 56 | display: flex; 57 | position: absolute; 58 | float: right; 59 | margin-left: 100px; 60 | padding-right: 25px; 61 | transition: ease-in; 62 | visibility: visible; 63 | padding-bottom: 40px; 64 | font-weight: 100; 65 | font-style: bold; 66 | padding-left: 25px; 67 | visibility: collapse; 68 | min-inline-size: inherit; 69 | } 70 | ``` 71 | 72 | --- 73 | 74 | ::: rule 👍 75 | 76 | #### false 77 | 78 | ::: 79 | 80 | ```json:rules 81 | { 82 | "language": "css", 83 | "style": { 84 | "sortProperties": false 85 | } 86 | } 87 | ``` 88 | 89 | 90 | ```css 91 | .class { 92 | z-index: 999; 93 | color: #fff; 94 | width: 200px; 95 | background-repeat: no-repeat; 96 | background-position: top; 97 | background-attachment: fixed; 98 | font-weight: 100; 99 | font-style: bold; 100 | margin-top: 100px; 101 | display: flex; 102 | position: absolute; 103 | float: right; 104 | margin-left: 100px; 105 | padding-right: 25px; 106 | transition: ease-in; 107 | visibility: visible; 108 | padding-bottom: 40px; 109 | font-weight: 100; 110 | font-style: bold; 111 | padding-left: 25px; 112 | visibility: collapse; 113 | min-inline-size: inherit; 114 | } 115 | ``` 116 | -------------------------------------------------------------------------------- /docs/src/rules/style/sortSelectors.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Style - Sort Selectors' 3 | layout: base 4 | permalink: '/rules/style/sortSelectors/index.html' 5 | anchors: 6 | - '' 7 | --- 8 | 9 | # Sort Selectors 10 | 11 | The `sortSelectors` rule will apply alphabetical sorting to style language class name selectors. 12 | 13 | --- 14 | 15 | 24 | 25 | ::: rule 👍 26 | 27 | #### false 28 | 29 | ::: 30 | 31 | Lorem Ipsum 32 | 33 | 34 | 35 | ```json:rules 36 | { 37 | "language": "css", 38 | "style": { 39 | "sortSelectors": false 40 | } 41 | } 42 | ``` 43 | 44 | 45 | ```css 46 | .v, 47 | .z, 48 | .y, 49 | .a, 50 | .x > .a > .b, 51 | .x > .c > .d, 52 | .c > .d > .x, 53 | .r, 54 | .t > .v > .x, 55 | .w, 56 | .b, 57 | .o { 58 | background-position: right top; 59 | background-attachment: fixed; 60 | font-weight: 100; 61 | font-style: bold; 62 | margin-top: 100px; 63 | } 64 | ``` 65 | 66 | --- 67 | 68 | ::: rule 👍 69 | 70 | #### true 71 | 72 | ::: 73 | 74 | ```json:rules 75 | { 76 | "language": "css", 77 | "style": { 78 | "sortSelectors": true 79 | } 80 | } 81 | ``` 82 | 83 | 84 | ```css 85 | .v, 86 | .z, 87 | .y, 88 | .a, 89 | .x > .a > .b, 90 | .x > .c > .d, 91 | .c > .d > .x, 92 | .r, 93 | .t > .v > .x, 94 | .w, 95 | .b, 96 | .o { 97 | background-position: right top; 98 | background-attachment: fixed; 99 | font-weight: 100; 100 | font-style: bold; 101 | margin-top: 100px; 102 | } 103 | ``` 104 | -------------------------------------------------------------------------------- /docs/src/samples/common.ts: -------------------------------------------------------------------------------- 1 | import { html, liquid, json } from 'language-literals'; 2 | 3 | export default [ 4 | [ 5 | 'HTML UL > LI' 6 | , 7 | html` 8 | 13 | ` 14 | ], 15 | [ 16 | 'Liquid For Loop' 17 | , 18 | liquid` 19 | {% for item in array %} 20 | 26 | {% endfor %} 27 | ` 28 | ], 29 | [ 30 | 'JSON Object' 31 | , 32 | json` 33 | { 34 | "property": [ 35 | { 36 | "string": "Hello World", 37 | "boolean": true, 38 | "number": 1000 39 | } 40 | ], 41 | "array": [ 42 | "Foo", 43 | "Bar", 44 | "Baz" 45 | ] 46 | } 47 | ` 48 | ] 49 | ]; 50 | -------------------------------------------------------------------------------- /docs/src/samples/normalizeSpacing.ts: -------------------------------------------------------------------------------- 1 | import { liquid } from 'language-literals'; 2 | 3 | export default [ 4 | [ 5 | 'Whitespace & Newlines' 6 | , 7 | liquid` 8 | 13 | ` 14 | ], 15 | [ 16 | 'Objects & Properties' 17 | , 18 | liquid` 19 | {% for item in array %} 20 | 26 | {% endfor %} 27 | ` 28 | ], 29 | [ 30 | 'Filter Expressions' 31 | , 32 | json` 33 | { 34 | "property": [ 35 | { 36 | "string": "Hello World", 37 | "boolean": true, 38 | "number": 1000 39 | } 40 | ], 41 | "array": [ 42 | "Foo", 43 | "Bar", 44 | "Baz" 45 | ] 46 | } 47 | ` 48 | ], 49 | [ 50 | 'Tag Arguments' 51 | , 52 | json` 53 | { 54 | "property": [ 55 | { 56 | "string": "Hello World", 57 | "boolean": true, 58 | "number": 1000 59 | } 60 | ], 61 | "array": [ 62 | "Foo", 63 | "Bar", 64 | "Baz" 65 | ] 66 | } 67 | ` 68 | ] 69 | ]; 70 | -------------------------------------------------------------------------------- /docs/src/sass/styles/breadcrumb.scss: -------------------------------------------------------------------------------- 1 | .breadcrumb { 2 | @include media-breakpoint-down(sm) { 3 | margin-top: 50px !important; 4 | font-size: $font-size-sm; 5 | margin: 0 auto; 6 | } 7 | .icon-right, 8 | .icon-home { 9 | width: 15px; 10 | height: 15px; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /docs/src/sass/styles/footer.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/sass/styles/footer.scss -------------------------------------------------------------------------------- /docs/src/sass/styles/navbar.scss: -------------------------------------------------------------------------------- 1 | header { 2 | position: fixed; 3 | //background-color: $white; 4 | z-index: 300; 5 | display: flex; 6 | background-color: $body-bg; 7 | 8 | right: 0; 9 | height: 52px; 10 | font-size: 1.075rem; 11 | //letter-spacing: 00.06rem; 12 | //box-shadow: $box-shadow; 13 | 14 | //background-color: rgb(15 15 15 / 56.2%); 15 | 16 | // backdrop-filter: blur(15px); 17 | } 18 | 19 | .navbar { 20 | width: 100%; 21 | // margin-right: 33.3%; 22 | 23 | .drawer-toggle { 24 | background-image: url(icon-menu($body-color)); 25 | background-repeat: no-repeat; 26 | background-position: center; 27 | } 28 | 29 | .e { 30 | @include media-breakpoint-down(sm) { 31 | color: $pink !important; 32 | } 33 | } 34 | .icon-github { 35 | width: 20px; 36 | height: 20px; 37 | color: $white; 38 | } 39 | 40 | .icon-npm { 41 | width: 44px; 42 | height: 44px; 43 | color: $gray-400; 44 | } 45 | 46 | .off { 47 | color: $gray-300; 48 | } 49 | 50 | a { 51 | font-weight: 400; 52 | color: $pink; 53 | margin-right: 15px; 54 | 55 | &.nav-link { 56 | font-family: $font-family-other; 57 | text-transform: uppercase; 58 | font-weight: 100; 59 | font-size: 0.9rem; 60 | letter-spacing: 0.03rem; 61 | } 62 | 63 | &.mr { 64 | margin-right: 0; 65 | } 66 | 67 | .icon-logo { 68 | width: 120px; 69 | height: 17px; 70 | stroke: purple; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /docs/src/sass/styles/parser.scss: -------------------------------------------------------------------------------- 1 | .parser { 2 | .papyrus { 3 | background-color: #12161d; 4 | border-top-right-radius: 0; 5 | border-bottom-right-radius: 0; 6 | } 7 | 8 | &-table { 9 | background-color: #12161d; 10 | 11 | tr { 12 | border-bottom: $border-width solid $border-color; 13 | 14 | &:hover { 15 | background-color: rgba( 16 | var(--papyrus-line-highlight-bg), 17 | var(--papyrus-line-highlight-alpha) 18 | ); 19 | } 20 | 21 | &.stripe { 22 | background-color: #151a22; 23 | } 24 | 25 | td { 26 | font-size: $font-size-sm; 27 | 28 | &.number { 29 | width: 3em; 30 | } 31 | 32 | pre { 33 | margin: 0 !important; 34 | background-color: transparent; 35 | 36 | code { 37 | padding: 0; 38 | font-size: $font-size-sm; 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /docs/src/sass/styles/sidebar.scss: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | // background-color: #fff; 3 | 4 | @include media-breakpoint-up(md) { 5 | position: fixed; 6 | margin-top: 52px; 7 | width: 280px; 8 | height: 100vh; 9 | display: block !important; 10 | visibility: visible; 11 | opacity: 1; 12 | transform: translateX(0); 13 | background-color: $body-bg; 14 | } 15 | //left: 0; 16 | 17 | // border-color: $cyan; 18 | 19 | ul > li { 20 | list-style-type: none; 21 | 22 | a { 23 | font-size: 1rem; 24 | text-decoration: none; 25 | } 26 | } 27 | } 28 | 29 | .content { 30 | @include media-breakpoint-up(md) { 31 | padding-left: 335px !important; 32 | } 33 | } 34 | 35 | .anchors { 36 | // background-color: #fff; 37 | 38 | margin-top: 52px; 39 | width: 350px; 40 | height: 100vh; 41 | 42 | //left: 0; 43 | } 44 | -------------------------------------------------------------------------------- /docs/src/sass/styles/tabs.scss: -------------------------------------------------------------------------------- 1 | .tabs { 2 | nav > button { 3 | color: $black; 4 | font-weight: 500; 5 | font-size: 0.895rem; 6 | font-family: Roboto, sans-serif !important; 7 | text-transform: uppercase; 8 | background-color: transparent; 9 | border: 0; 10 | border-bottom: 1px solid $cyan; 11 | cursor: pointer; 12 | 13 | 14 | &:hover, 15 | &:active, 16 | &:focus { 17 | color: $black; 18 | } 19 | 20 | &:last-child { 21 | margin-right: 0; 22 | } 23 | 24 | &[aria-selected="true"] { 25 | color: $black; 26 | background-color: $cyan; 27 | } 28 | 29 | &[aria-selected="false"] { 30 | color: $white; 31 | } 32 | } 33 | 34 | .panel, 35 | .panel > ul { 36 | position: relative; 37 | 38 | > li { 39 | list-style-type: inherit; 40 | } 41 | } 42 | } 43 | 44 | [role="tabpanel"][aria-hidden="true"] { 45 | display: none; 46 | } 47 | -------------------------------------------------------------------------------- /docs/src/views/include/breadcrumbs.liquid: -------------------------------------------------------------------------------- 1 | {% assign links = page.url | split: '/' %} 2 | 3 | -------------------------------------------------------------------------------- /docs/src/views/include/footer.liquid: -------------------------------------------------------------------------------- 1 | 32 | -------------------------------------------------------------------------------- /docs/src/views/include/landing.liquid: -------------------------------------------------------------------------------- 1 |
    4 |
    5 |
    6 | 13 | 14 | 24 | 25 |
    26 |
    29 | {{ content | remove: '

    ' | remove: '

    ' }} 30 |
    31 |
    32 | 33 |
    34 | 35 | pnpm add esthetic 36 | 37 |
    38 | 39 |
    40 |
    41 | {% version %} 42 |
    43 |
    44 |
    -------------------------------------------------------------------------------- /docs/src/views/include/navbar.liquid: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/views/include/navigators.liquid: -------------------------------------------------------------------------------- 1 | {% for link in collections.all %} 2 | {% if link.url == page.url and link.data.prev and link.data.next %} 3 | 4 |
    5 | 6 | 28 | {% endif %} 29 | {% endfor %} -------------------------------------------------------------------------------- /docs/src/views/include/parser.liquid: -------------------------------------------------------------------------------- 1 |
    4 | 5 |
    6 |

    Parse Data Structure

    7 |
    8 | 9 |
    10 |
    11 |       
    12 |       
    13 |     
    14 |
    15 | 16 |
    20 | 21 |
    -------------------------------------------------------------------------------- /docs/src/views/include/playground.liquid: -------------------------------------------------------------------------------- 1 |
    2 |
    8 | 9 | 10 |
    13 |
    14 | {% svg 'moloko', 'icon icon-moloko' %} 15 |
    16 |
    17 | 18 |
    19 |
    20 | 21 |
    22 | 23 |
    24 |
    -------------------------------------------------------------------------------- /docs/src/views/include/rules.liquid: -------------------------------------------------------------------------------- 1 | {% if page.url == '/' %} 2 | {% assign is_open = 'false' %} 3 | {% assign hidden = 'false' %} 4 | {% assign active = '' %} 5 | {% else %} 6 | {% assign is_open = 'true' %} 7 | {% assign hidden = 'true' %} 8 | {% assign active = 'drawer-active' %} 9 | {% endif %} 10 | 11 |
    14 | 69 |
    -------------------------------------------------------------------------------- /docs/src/views/include/tokens.liquid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/docs/src/views/include/tokens.liquid -------------------------------------------------------------------------------- /docs/src/views/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Code Beautification' 3 | layout: base 4 | permalink: '/index.html' 5 | --- 6 | 7 | A new generation **code beautification** tool. Syntactical **formatting** leveraging the **Sparser** algorithm with support for **10** different **client side** languages. 8 | -------------------------------------------------------------------------------- /docs/src/views/playground.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Playground' 3 | layout: base 4 | permalink: '/playground/index.html' 5 | --- 6 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": [ 3 | "node_modules/**", 4 | "public" 5 | ], 6 | "include": [ 7 | "src/app/**/*.ts" 8 | ], 9 | "compilerOptions": { 10 | "incremental": false, 11 | "allowSyntheticDefaultImports": true, 12 | "esModuleInterop": true, 13 | "declaration": true, 14 | "removeComments": true, 15 | "target": "ES6", 16 | "lib": [ 17 | "es2020", 18 | "dom", 19 | "dom.iterable" 20 | ], 21 | "typeRoots": [ 22 | "node_modules/@types" 23 | ], 24 | "module": "ESNext", 25 | "moduleResolution": "node", 26 | "emitDeclarationOnly": true, 27 | "isolatedModules": true, 28 | "baseUrl": ".", 29 | "paths": { 30 | "moloko": [ 31 | "." 32 | ] 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /docs/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig( 4 | { 5 | entry: { 6 | 'bundle.min': './src/app/index.ts' 7 | }, 8 | external: [ 9 | 'moloko', 10 | 'esthetic' 11 | ], 12 | outDir: './public/assets', 13 | outExtension: () => ({ 14 | js: '.js' 15 | }), 16 | clean: false, 17 | treeshake: false, 18 | splitting: false, 19 | platform: 'browser', 20 | format: [ 21 | 'iife' 22 | ] 23 | } 24 | ); 25 | -------------------------------------------------------------------------------- /src/cli.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import mm from 'minimist'; 4 | import { run } from 'cli/run'; 5 | 6 | (async () => await run(mm(process.argv.slice(1), { 7 | alias: { 8 | watch: 'w', 9 | output: 'o', 10 | config: 'c', 11 | format: 'f', 12 | help: 'h', 13 | javascript: 'js', 14 | typescript: 'ts' 15 | }, 16 | default: { 17 | format: false, 18 | help: false, 19 | liquid: false, 20 | html: false, 21 | xml: false, 22 | css: false, 23 | scss: false, 24 | json: false, 25 | javascript: false, 26 | jsx: false, 27 | typescript: false, 28 | tsx: false, 29 | 'no-color': false 30 | }, 31 | boolean: [ 32 | 'watch', 33 | 'dry', 34 | 'no-color', 35 | 'silent', 36 | 'rules', 37 | 'help', 38 | 'liquid', 39 | 'html', 40 | 'xml', 41 | 'css', 42 | 'scss', 43 | 'json', 44 | 'javascript', 45 | 'jsx', 46 | 'typescript', 47 | 'tsx' 48 | ], 49 | string: [ 50 | 'config', 51 | 'output' 52 | ] 53 | })))(); 54 | -------------------------------------------------------------------------------- /src/comments/index.ts: -------------------------------------------------------------------------------- 1 | export * from './block'; 2 | export * from './line'; 3 | export * from './control'; 4 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import { IConfigInternal } from 'types'; 2 | import { LogLevel } from 'lexical/enum'; 3 | 4 | /** 5 | * Global Settings 6 | * 7 | * This export is responsible for handling global settings for Æsthetic. 8 | */ 9 | export const config: IConfigInternal = { 10 | // @ts-ignore 11 | version: VERSION, 12 | env: typeof process !== 'undefined' && process.versions != null ? 'node' : 'browser', 13 | lastUpdate: new Date().toDateString(), 14 | cwd: null, 15 | reportStats: true, 16 | editorConfig: false, 17 | throwErrors: true, 18 | globalThis: true, 19 | persistRules: true, 20 | logLevel: LogLevel.Standard, 21 | logColors: true, 22 | resolveConfig: 'package.json' 23 | }; 24 | -------------------------------------------------------------------------------- /src/format/index.ts: -------------------------------------------------------------------------------- 1 | import { Lexers } from 'lexical/enum'; 2 | import { markup } from './markup'; 3 | import { script } from './script'; 4 | import { style } from './style'; 5 | 6 | export function format (lexer: Lexers) { 7 | 8 | if (lexer === Lexers.Markup) return markup(); 9 | 10 | if (lexer === Lexers.Style) return style(); 11 | 12 | if (lexer === Lexers.Script) return script(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import './parse/parser'; 2 | import './parse/grammar'; 3 | import './lexers/index'; 4 | import './format/index'; 5 | 6 | export { esthetic as default } from './esthetic'; 7 | -------------------------------------------------------------------------------- /src/lexers/index.ts: -------------------------------------------------------------------------------- 1 | import { Lexers } from 'lexical/enum'; 2 | import { markup } from './markup'; 3 | import { script } from './script'; 4 | import { style } from './style'; 5 | 6 | export function lexers (lexer: Lexers) { 7 | 8 | if (lexer === Lexers.Markup) return markup(); 9 | 10 | if (lexer === Lexers.Style) return style(); 11 | 12 | if (lexer === Lexers.Script) return script(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/lexical/chars.ts: -------------------------------------------------------------------------------- 1 | 2 | /* -------------------------------------------- */ 3 | /* COMMON CHARACTERS */ 4 | /* -------------------------------------------- */ 5 | 6 | /** 7 | * `''` – Empty String 8 | */ 9 | export const NIL = ''; 10 | 11 | /** 12 | * `' '` – Mid String comprised of 2 whitespaces (Used in block comment formatting) 13 | */ 14 | export const MID = ' '; 15 | 16 | /** 17 | * `' '` – Big String comprised of 4 whitespaces (Used in block comment formatting) 18 | */ 19 | export const BIG = ' '; 20 | 21 | /** 22 | * `"` – Double quotation character 23 | */ 24 | export const DQO = '"'; 25 | 26 | /** 27 | * `,` – Comma Character 28 | */ 29 | export const COM = ','; 30 | 31 | /** 32 | * `'` – Single quotation character 33 | */ 34 | export const SQO = "'"; 35 | 36 | /** 37 | * ` ` – Single whitespace character 38 | */ 39 | export const WSP = ' '; 40 | 41 | /** 42 | * `\t` – Single tab character 43 | */ 44 | export const TAB = '\t'; 45 | 46 | /** 47 | * `\n` – Newline character 48 | */ 49 | export const NWL = '\n'; 50 | 51 | /** 52 | * `\r\n` - CRLF character sequence 53 | */ 54 | export const CNL = '\r\n'; 55 | -------------------------------------------------------------------------------- /src/lexical/lexing.ts: -------------------------------------------------------------------------------- 1 | import { is, not, isLast, isString } from 'utils/helpers'; 2 | import { NIL } from 'lexical/chars'; 3 | import { cc } from 'lexical/codes'; 4 | 5 | /** 6 | * Get Tag Name 7 | * 8 | * Returns the tag name of the provided token. Looks for HTML and Liquid tag names, 9 | * includes Liquid output objects too. Will convert tag names to lowercase. 10 | * 11 | * Optionally provide a slice offset index to slice the tag name. Helpful in situations 12 | * when we need to exclude `end` from `endtag` 13 | */ 14 | export function getTagName (tag: string, slice: number = NaN, fallback?: string) { 15 | 16 | if (isString(tag) === false) return NIL; 17 | 18 | if (not(tag, cc.LAN) && not(tag, cc.LCB)) return fallback || tag; 19 | 20 | if (is(tag, cc.LAN)) { 21 | 22 | const next = tag.search(/[\s>]/); 23 | const name = tag.slice(is(tag[1], cc.FWS) ? 2 : 1, next); 24 | 25 | // Handles XML tag name (ie: ) 26 | return is(name, cc.QWS) && isLast(name, cc.QWS) ? 'xml' : isNaN(slice) 27 | ? name 28 | : name.slice(slice); 29 | 30 | } 31 | 32 | // Returns the Liquid tag or output token name 33 | const name = is(tag[2], cc.DSH) ? tag.slice(3).trimStart() : tag.slice(2).trimStart(); 34 | const tname = name.split(/\s|-?[%}]}/).shift(); 35 | 36 | return isNaN(slice) ? tname : tname.slice(slice); 37 | 38 | }; 39 | 40 | /** 41 | * Quote Conversion 42 | * 43 | * Converts quotes while excluding escaped instances. 44 | * Returns a function and is intended to be used within a `replace`. 45 | * 46 | * @example 47 | * 48 | * string.replace(/"/g, lx.qc("'")) 49 | */ 50 | export function qc (to: string) { 51 | 52 | return (m: string, i: number, input: string) => { 53 | 54 | let o = to; 55 | let c = to; 56 | 57 | if (is(input[i - 1], cc.BWS)) o = m[0]; 58 | if (is(m[m.length - 2], cc.BWS)) c = m[m.length - 1]; 59 | 60 | return o + m.slice(1, -1) + c; 61 | 62 | }; 63 | } 64 | 65 | /** 66 | * Count Occurances 67 | * 68 | * Counts the number of occurances of a character in the provided 69 | * string and returns the number. 70 | */ 71 | export function countChars (string: string, char: string) { 72 | 73 | return string.split(char).length - 1; 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/parse/external.ts: -------------------------------------------------------------------------------- 1 | import { grammar } from 'parse/grammar'; 2 | import { isRegex } from 'utils/helpers'; 3 | 4 | /** 5 | * Determine External 6 | * 7 | * Returns a boolean when an external language tag name is 8 | * determined to require another lexer. Optionally provide 9 | * a second `ref` parameter to only check sepecific grammars. 10 | */ 11 | export function determine (tag: string, ref: 'html' | 'liquid', attrs?: any) { 12 | 13 | if (ref === 'html') { 14 | 15 | if (!(tag in grammar.html.embed)) return false; 16 | 17 | const token = grammar.html.embed[tag]; 18 | 19 | if (token.attr.size > 0) { 20 | for (const attribute of token.attr.values()) { 21 | 22 | if (!attrs) return attribute; 23 | 24 | if (attribute.attr.has(attrs[0]) && attribute.attr.get(attrs[0]).value.has(attrs[1])) { 25 | return attribute.attr.get(attrs[0]); 26 | } 27 | 28 | } 29 | } 30 | 31 | return token.attr.has(attrs[0]) ? token.attr.get(attrs[0]).attr.has(attrs[1]) 32 | ? token.attr.get(attrs[0]).attr.get(attrs[1]) 33 | : token.attr.get(attrs[0]) : token; 34 | 35 | } else if (ref === 'liquid') { 36 | 37 | if (!(tag in grammar.liquid.embed)) return false; 38 | 39 | const token = grammar.liquid.embed[tag]; 40 | 41 | if (token.args.size > 0 && attrs) { 42 | 43 | const arg = attrs.slice(attrs.indexOf(tag) + tag.length).match(/\s*(.*)(?=\s)/)[0]; 44 | 45 | for (const [ match, key ] of token.args) { 46 | if (match.has(arg)) { 47 | return key; 48 | } else { 49 | for (const test of match) { 50 | if (isRegex(test) && test.test(arg)) return key; 51 | } 52 | } 53 | } 54 | 55 | } 56 | 57 | return token; 58 | 59 | } 60 | 61 | } 62 | 63 | /** 64 | * Detect External 65 | * 66 | * Returns a boolean when an external language tag name is 67 | * determined to require another lexer. Optionally provide 68 | * a second `language` parameter to only check sepecific grammars. 69 | */ 70 | export function detect (tag: string, language?: T) { 71 | 72 | if (typeof language !== 'undefined') return tag in grammar[language].embed; 73 | 74 | return ( 75 | tag in grammar.html.embed || 76 | tag in grammar.liquid.embed 77 | ); 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/rules/presets.ts: -------------------------------------------------------------------------------- 1 | export { defaults } from './presets/default'; 2 | -------------------------------------------------------------------------------- /src/rules/presets/prettier.ts: -------------------------------------------------------------------------------- 1 | import { merge } from 'utils/helpers'; 2 | import { Rules } from 'types'; 3 | 4 | /** 5 | * Prettier Presets 6 | * 7 | * Rules which replicates the Prettier formatting style. 8 | * These also reflect the prettier-liquid plugin. 9 | */ 10 | export const prettier: Rules = merge({ 11 | preset: 'prettier', 12 | language: 'auto', 13 | preserveLine: 1, 14 | wrap: 80, 15 | wrapFraction: 60, 16 | liquid: { 17 | ignoreTagList: [ 'javascript' ], 18 | indentAttribute: true, 19 | lineBreakSeparator: 'after', 20 | dedentTagList: [ 'schema' ], 21 | quoteConvert: 'double' 22 | }, 23 | markup: { 24 | commentDelimiters: 'consistent', 25 | commentIndent: true, 26 | delimiterTerminus: 'force', 27 | forceAttribute: 1, 28 | forceIndent: true, 29 | ignoreJS: true, 30 | ignoreCSS: true, 31 | ignoreJSON: false, 32 | lineBreakValue: 'force-indent', 33 | selfCloseSpace: true, 34 | selfCloseSVG: true, 35 | stripAttributeLines: true, 36 | quoteConvert: 'double' 37 | }, 38 | json: { 39 | arrayFormat: 'indent', 40 | objectIndent: 'indent' 41 | }, 42 | style: { 43 | commentIndent: false, 44 | quoteConvert: 'double' 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /src/rules/presets/recommended.ts: -------------------------------------------------------------------------------- 1 | import { merge } from 'utils/helpers'; 2 | import { Rules } from 'types'; 3 | 4 | /** 5 | * Recommended Presets 6 | * 7 | * The `recommended` rule presets which produce the most common 8 | * and expect formatted results. 9 | */ 10 | export const recommended: Rules = merge({ 11 | preset: 'recommended', 12 | language: 'auto', 13 | preserveLine: 2, 14 | wrap: 120, 15 | wrapFraction: 90, 16 | liquid: { 17 | ignoreTagList: [ 'javascript' ], 18 | indentAttribute: true, 19 | commentNewline: true, 20 | delimiterTrims: 'tags', 21 | lineBreakSeparator: 'after', 22 | quoteConvert: 'double', 23 | delimiterPlacement: 'consistent' 24 | }, 25 | markup: { 26 | attributeCasing: 'lowercase-name', 27 | commentDelimiters: 'preserve', 28 | commentNewline: true, 29 | delimiterTerminus: 'adapt', 30 | forceAttribute: 2, 31 | forceIndent: true, 32 | ignoreCSS: false, 33 | ignoreJSON: false, 34 | lineBreakValue: 'indent', 35 | selfCloseSpace: true, 36 | selfCloseSVG: true, 37 | quoteConvert: 'double' 38 | }, 39 | json: { 40 | arrayFormat: 'indent', 41 | objectIndent: 'indent' 42 | }, 43 | style: { 44 | commentNewline: true, 45 | commentIndent: true, 46 | quoteConvert: 'double', 47 | noLeadZero: true, 48 | sortProperties: true 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /src/rules/presets/strict.ts: -------------------------------------------------------------------------------- 1 | import { merge } from 'utils/helpers'; 2 | import { Rules } from 'types'; 3 | 4 | /** 5 | * Strict Presets 6 | * 7 | * The `recommended` rule presets which produce the most common 8 | * and expect formatted results. 9 | */ 10 | export const strict: Rules = merge({ 11 | preset: 'strict', 12 | language: 'auto', 13 | preserveLine: 1, 14 | wrap: 0, 15 | wrapFraction: 80, 16 | liquid: { 17 | ignoreTagList: [], 18 | commentNewline: true, 19 | delimiterTrims: 'never', 20 | lineBreakSeparator: 'before', 21 | quoteConvert: 'double', 22 | forceArgument: 3, 23 | forceFilter: 4, 24 | delimiterPlacement: 'consistent' 25 | }, 26 | markup: { 27 | attributeSort: [ 28 | 'id', 29 | 'class', 30 | 'type', 31 | 'name', 32 | 'value', 33 | 'href', 34 | 'src' 35 | ], 36 | attributeCasing: 'lowercase-name', 37 | commentDelimiters: 'force', 38 | commentNewline: true, 39 | delimiterTerminus: 'adapt', 40 | forceAttribute: 1, 41 | forceIndent: true, 42 | ignoreCSS: false, 43 | ignoreJSON: false, 44 | ignoreJS: false, 45 | lineBreakValue: 'force-indent', 46 | selfCloseSpace: true, 47 | selfCloseSVG: true, 48 | stripAttributeLines: true, 49 | quoteConvert: 'double' 50 | }, 51 | json: { 52 | arrayFormat: 'indent', 53 | objectIndent: 'indent', 54 | objectSort: true 55 | }, 56 | style: { 57 | commentNewline: true, 58 | commentIndent: true, 59 | quoteConvert: 'double', 60 | noLeadZero: true, 61 | sortProperties: true, 62 | sortSelectors: true 63 | } 64 | }); 65 | -------------------------------------------------------------------------------- /src/rules/presets/warrington.ts: -------------------------------------------------------------------------------- 1 | import { merge } from 'utils/helpers'; 2 | import { Rules } from 'types'; 3 | 4 | /** 5 | * Warrington Presets 6 | * 7 | * The `warrington` rule presets which are geared towards 8 | * Shopify projects. 9 | */ 10 | export const warrington: Rules = merge({ 11 | preset: 'warrington', 12 | language: 'auto', 13 | preserveLine: 2, 14 | wrap: 0, 15 | liquid: { 16 | ignoreTagList: [ 'javascript' ], 17 | indentAttribute: true, 18 | lineBreakSeparator: 'after', 19 | quoteConvert: 'double' 20 | }, 21 | markup: { 22 | commentNewline: true, 23 | commentDelimiters: 'consistent', 24 | delimiterTerminus: 'adapt', 25 | forceAttribute: 1, 26 | forceIndent: true, 27 | ignoreCSS: true, 28 | ignoreJSON: false, 29 | lineBreakValue: 'indent', 30 | selfCloseSpace: true, 31 | selfCloseSVG: true, 32 | stripAttributeLines: true, 33 | quoteConvert: 'double' 34 | }, 35 | json: { 36 | arrayFormat: 'indent', 37 | objectIndent: 'indent' 38 | }, 39 | style: { 40 | commentIndent: false, 41 | quoteConvert: 'double' 42 | } 43 | }); 44 | -------------------------------------------------------------------------------- /src/utils/native.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Native object assign 3 | */ 4 | export const assign = Object.assign; 5 | 6 | /** 7 | * Native object create 8 | */ 9 | export const object = Object.create; 10 | 11 | /** 12 | * Native object keys 13 | */ 14 | export const keys = Object.keys; 15 | 16 | /** 17 | * Native object values 18 | */ 19 | export const values = Object.values; 20 | 21 | /** 22 | * Native object define property 23 | */ 24 | export const defineProperty = Object.defineProperty; 25 | 26 | /** 27 | * Native object define property 28 | */ 29 | export const defineProperties = Object.defineProperties; 30 | 31 | /** 32 | * Native Console Warn 33 | */ 34 | export const warn = console.warn; 35 | -------------------------------------------------------------------------------- /tests/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 | Present: ΝΙΚΟΛΑΣ ΣΑΒΒΙΔΗΣ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/bench/changes/compare.mjs: -------------------------------------------------------------------------------- 1 | import Benchmark from 'benchmark'; 2 | import Esthetic from 'esthetic'; 3 | import PrettyDiff from 'prettydiff'; 4 | import path from 'path'; 5 | import fs from 'fs'; 6 | 7 | const html = fs.readFileSync(path.join(process.cwd(), 'changes', '/samples/doctype.txt')).toString(); 8 | 9 | const suite = new Benchmark.Suite(); 10 | 11 | suite.add('PrettyDiff', function () { 12 | 13 | PrettyDiff.options.mode = 'beautify'; 14 | PrettyDiff.options.lexer = 'markup'; 15 | PrettyDiff.options.source = html; 16 | PrettyDiff.options.wrap = 80; 17 | 18 | return PrettyDiff(); 19 | 20 | }, { 21 | async: false 22 | }); 23 | 24 | suite.add('Æsthetic', function () { 25 | 26 | return Prettify.format(html, { 27 | language: 'html', 28 | lexer: 'markup', 29 | wrap: 80 30 | }); 31 | }, { 32 | async: true 33 | }); 34 | 35 | suite.on('cycle', function (event) { 36 | console.log(String(event.target)); 37 | }); 38 | 39 | suite.on('complete', async function () { 40 | 41 | console.log('\nSlowest is ' + this.filter('slowest').map('name')); 42 | console.log('Fastest is ' + this.filter('fastest').map('name')); 43 | 44 | console.log('\nBeautification Times:', '\n'); 45 | 46 | console.time('PrettyDiff'); 47 | 48 | PrettyDiff.options.mode = 'beautify'; 49 | PrettyDiff.options.lexer = 'markup'; 50 | PrettyDiff.options.source = html; 51 | PrettyDiff.options.wrap = 80; 52 | PrettyDiff(); 53 | 54 | console.timeEnd('PrettyDiff'); 55 | 56 | console.time('Æsthetic'); 57 | 58 | Esthetic.format(html, { 59 | language: 'html', 60 | lexer: 'markup', 61 | wrap: 80 62 | }); 63 | 64 | console.timeEnd('Æsthetic'); 65 | }); 66 | 67 | suite.run(); 68 | -------------------------------------------------------------------------------- /tests/bench/methods/loops.mjs: -------------------------------------------------------------------------------- 1 | import Benchmark from 'benchmark'; 2 | 3 | const arr = Array.of(1e5); 4 | const len = arr.length; 5 | const suite = new Benchmark.Suite(); 6 | 7 | suite.add('do {} while ()', function () { 8 | let a = 0; 9 | do { a = a + 1; } while (a < len); 10 | return a; 11 | }); 12 | 13 | suite.add('for () {}', function () { 14 | let a = 0; 15 | let x = ''; 16 | for (a; a < len; a = a + 1) { x = `${a}`; } 17 | return x; 18 | }); 19 | 20 | suite.add('while () {}', function () { 21 | let a = 0; 22 | while (a < len) { a = a + 1; } 23 | return a; 24 | }); 25 | 26 | suite.add('[].forEach()', function () { 27 | 28 | arr.forEach(x => { 29 | return x; 30 | }); 31 | 32 | }); 33 | 34 | suite.on('cycle', function (evt) { 35 | console.log(' - ' + evt.target); 36 | }); 37 | 38 | suite.on('complete', function () { 39 | 40 | console.log('\nFastest is ' + this.filter('fastest').map('name')); 41 | }); 42 | 43 | console.log(1e5 + ' Loops'); 44 | console.log(new Array(30).join('-')); 45 | 46 | suite.run(); 47 | -------------------------------------------------------------------------------- /tests/bench/methods/null-prototype.mjs: -------------------------------------------------------------------------------- 1 | import Benchmark from 'benchmark'; 2 | 3 | const arr = Array.of(1e5); 4 | const len = arr.length; 5 | 6 | const suite = new Benchmark.Suite(); 7 | 8 | suite.add('Object.create(null)', function () { 9 | 10 | let a = 0; 11 | const x = Object.create(null); 12 | 13 | do { 14 | x.foo = 100; 15 | a = a + 1; 16 | } while (a < len); 17 | 18 | return x; 19 | }); 20 | 21 | suite.add('{}', function () { 22 | 23 | let a = 0; 24 | const x = {}; 25 | 26 | do { 27 | x.foo = 100; 28 | a = a + 1; 29 | } while (a < len); 30 | 31 | return x; 32 | }); 33 | 34 | suite.on('cycle', function (evt) { 35 | console.log(' - ' + evt.target); 36 | }); 37 | 38 | suite.on('complete', function () { 39 | 40 | console.log('\nFastest is ' + this.filter('fastest').map('name')); 41 | }); 42 | 43 | console.log('Object Creations'); 44 | console.log(new Array(30).join('-')); 45 | 46 | suite.run(); 47 | -------------------------------------------------------------------------------- /tests/bench/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bench", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@shopify/prettier-plugin-liquid": "^0.4.0", 14 | "@types/benchmark": "^2.1.2", 15 | "@types/js-beautify": "^1.13.3", 16 | "benchmark": "^2.1.4", 17 | "esthetic": "link:../..", 18 | "js-beautify": "^1.14.6", 19 | "prettier": "^2.7.1", 20 | "prettydiff": "^101.2.6" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/bench/readme.md: -------------------------------------------------------------------------------- 1 | # Benchmarks 2 | 3 | This directory contains some basic benchmark comparisons for Æsthetic 4 | 5 | # Comparisons 6 | 7 | Below are some basic benchmark comparisons that compare different formatting tools. Prettier performs the lowest in every single benchmark. 8 | 9 | ### HTML 10 | 11 | Repeated runs. Fastest is JSBeautify. Prettier is the slowest. 12 | 13 | | Lines | Tool | Result | 14 | | ----- | ---------- | ---------------------------------------- | 15 | | 1k | JSBeautify | x 348 ops/sec ±0.19% (95 runs sampled) | 16 | | 1k | Æsthetic | x 111 ops/sec ±2.20% (82 runs sampled) | 17 | | 1k | PrettyDiff | x 93.11 ops/sec ±1.23% (81 runs sampled) | 18 | | 1k | Prettier | x 36.75 ops/sec ±9.77% (52 runs sampled) | 19 | 20 | Runtime parse + beautification. Æsthetic is the fastest. Prettier is the slowest. 21 | 22 | | Lines | Tool | Result | 23 | | ----- | ---------- | ---------- | 24 | | 1k | Æsthetic | x 3.41ms | 25 | | 1k | JSBeautify | x 9.48ms | 26 | | 1k | PrettyDiff | x 34.177ms | 27 | | 1k | Prettier | x 30.655ms | 28 | 29 | ### CSS 30 | 31 | TODO 32 | 33 | ### JavaScript 34 | 35 | TODO 36 | 37 | ### TypeScript 38 | 39 | TODO 40 | -------------------------------------------------------------------------------- /tests/bench/tools/html.mjs: -------------------------------------------------------------------------------- 1 | import Benchmark from 'benchmark'; 2 | import Esthetic from 'esthetic'; 3 | import Prettier from 'prettier'; 4 | import JSBeautify from 'js-beautify'; 5 | import path from 'path'; 6 | import fs from 'fs'; 7 | 8 | const html = fs.readFileSync(path.join(process.cwd(), 'tools', '/samples/html.txt')).toString(); 9 | const suite = new Benchmark.Suite(); 10 | 11 | suite.add('Prettier', function () { 12 | 13 | return Prettier.format(html, { 14 | parser: 'html' 15 | }); 16 | 17 | }, { 18 | async: true 19 | }); 20 | 21 | suite.add('JSBeautify', function () { 22 | 23 | return JSBeautify.html(html, { 24 | wrap_line_length: 80, 25 | indent_inner_html: true 26 | }); 27 | 28 | }, { 29 | async: false 30 | }); 31 | 32 | suite.add('Æsthetic', function () { 33 | 34 | return Esthetic.format(html, { 35 | language: 'html', 36 | lexer: 'markup', 37 | wrap: 80 38 | }); 39 | 40 | }, { 41 | async: false 42 | }); 43 | 44 | suite.on('cycle', function (event) { 45 | console.log(String(event.target)); 46 | }); 47 | 48 | suite.on('complete', async function () { 49 | 50 | console.log('\nFastest is ' + this.filter('fastest').map('name')); 51 | 52 | console.log('\nBeautification Times:', '\n'); 53 | 54 | console.time('Prettier'); 55 | Prettier.format(html, { parser: 'html' }); 56 | console.timeEnd('Prettier'); 57 | 58 | console.time('JSBeautify'); 59 | JSBeautify.html_beautify(html, { wrap_line_length: 80 }); 60 | console.timeEnd('JSBeautify'); 61 | 62 | console.time('Æsthetic'); 63 | Esthetic.format(html, { language: 'html', lexer: 'markup', wrap: 80 }); 64 | console.timeEnd('Æsthetic'); 65 | 66 | }); 67 | 68 | suite.run(); 69 | -------------------------------------------------------------------------------- /tests/bench/tools/javascript.mjs: -------------------------------------------------------------------------------- 1 | import Benchmark from 'benchmark'; 2 | import Prettify from '@liquify/prettify'; 3 | import Prettier from 'prettier'; 4 | import JSBeautify from 'js-beautify'; 5 | import path from 'path'; 6 | import fs from 'fs'; 7 | 8 | const js = fs.readFileSync(path.join(process.cwd(), 'tools', '/samples/javascript.txt')).toString(); 9 | 10 | const suite = new Benchmark.Suite(); 11 | 12 | suite.add('Prettier (JavaScript)', function () { 13 | 14 | return Prettier.format(js, { 15 | parser: 'babel' 16 | 17 | }); 18 | 19 | }, { 20 | async: true 21 | }); 22 | 23 | suite.add('JSBeautify (JavaScript)', function () { 24 | 25 | JSBeautify.js(js, { 26 | wrap_line_length: 80 27 | }); 28 | 29 | }, { 30 | async: false 31 | }); 32 | 33 | suite.add('Prettify (JavaScript)', function () { 34 | 35 | return Prettify.format(js, { 36 | language: 'javascript', 37 | lexer: 'script', 38 | wrap: 80 39 | }).catch(e => { 40 | console.log(e); 41 | }); 42 | 43 | }, { 44 | async: true 45 | }); 46 | 47 | suite.on('cycle', function (event) { 48 | console.log(String(event.target)); 49 | }); 50 | 51 | suite.on('complete', async function () { 52 | 53 | console.log('\nFastest is ' + this.filter('fastest').map('name')); 54 | console.log('\nBeautification Times:', '\n'); 55 | 56 | console.time('Prettier'); 57 | 58 | await Prettier.format(js, { 59 | parser: 'babel' 60 | }); 61 | 62 | console.timeEnd('Prettier'); 63 | 64 | console.time('JSBeautify'); 65 | 66 | JSBeautify.js_beautify(js, { 67 | wrap_line_length: 80 68 | }); 69 | console.timeEnd('JSBeautify'); 70 | 71 | console.time('Prettify'); 72 | await Prettify.format(js, { 73 | language: 'javascript', 74 | lexer: 'script', 75 | wrap: 80 76 | }); 77 | console.timeEnd('Prettify'); 78 | }); 79 | 80 | suite.run(); 81 | -------------------------------------------------------------------------------- /tests/cases/attributes/casing.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { forRule, liquid } from '@liquify/ava/esthetic'; 3 | import esthetic from 'esthetic'; 4 | 5 | test('Casing rule cases', t => { 6 | 7 | forRule( 8 | [ 9 | liquid` 10 | 11 | {% # Testing HTML "attributeCasing" rule. This case tests HTML attributes only. %} 12 | 13 |
    14 | 15 | `, 16 | liquid` 17 | 18 | {% # Testing HTML (markup) "attributeCasing" rule with Liquid attributes %} 19 | 20 |
    21 | 22 | ` 23 | ] 24 | )( 25 | [ 26 | { language: 'liquid', markup: { attributeCasing: 'preserve' } }, 27 | { language: 'liquid', markup: { attributeCasing: 'lowercase' } }, 28 | { language: 'liquid', markup: { attributeCasing: 'lowercase-name' } }, 29 | { language: 'liquid', markup: { attributeCasing: 'lowercase-value' } } 30 | ] 31 | )(function (source, rules, label) { 32 | 33 | const snapshot = esthetic.format(source, rules); 34 | 35 | t.snapshot(snapshot, label); 36 | 37 | }); 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /tests/cases/attributes/indentation.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { forRule, liquid } from '@liquify/ava/esthetic'; 3 | import esthetic from 'esthetic'; 4 | 5 | test('Indenting attributes contained in Liquid block tags', t => { 6 | 7 | forRule( 8 | [ 9 | liquid` 10 | 11 | {% # Indenting controls %} 12 | 13 |
    14 | 15 |
    36 | 37 | Hello World 38 | 39 |
    40 | 41 |
    ` 42 | , 43 | 44 | liquid` 45 | 46 | {% # Deeply nested indentations %} 47 | 48 |
    49 | 50 |
    86 | 87 | Hello World 88 | 89 |
    90 | 91 |
    ` 92 | ] 93 | )( 94 | [ 95 | { 96 | language: 'liquid', 97 | liquid: { 98 | indentAttributes: true 99 | }, 100 | markup: { 101 | forceAttribute: true 102 | } 103 | } 104 | 105 | ] 106 | )(function (source, rules, label) { 107 | 108 | const snapshot = esthetic.format(source, rules); 109 | 110 | // t.log(snapshot); 111 | 112 | t.snapshot(snapshot, label); 113 | 114 | }); 115 | }); 116 | -------------------------------------------------------------------------------- /tests/cases/attributes/nested-delimiters.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { forSample, liquid } from '@liquify/ava/esthetic'; 3 | import esthetic from 'esthetic'; 4 | 5 | test('Liquid delimiter handling', t => { 6 | 7 | forSample( 8 | [ 9 | liquid` 10 | 11 | {% # Testing HTML tag delimiter characters ">" and "<" within HTML attribute values. %} 12 | 13 |
    21 | 22 |
    23 | ` 24 | , 25 | 26 | liquid` 27 | 28 | {% # Testing Liquid token containing HTML tag delimiter characters ">" and "<" within attribute values %} 29 | 30 |
    b %} data-a {% endif %} 33 | {% if c < d %} data-b {% endif %} 34 | {% unless e > f and g < h %} data-c="a > b" {% elsif i > j %} data-d="a > b"{% endunless %} 35 | {% if < k and l > m %} 36 | {{ output_1 | filter: '>' | filter: '<' }} 37 | {% else %} 38 | {{ output_2 | filter: '<' | filter: '>' }} 39 | {% endif %} 40 | 41 | > 42 | 43 |
    44 | ` 45 | , 46 | 47 | liquid` 48 | 49 | {% # Testing Liquid tokens as attributes and containing HTML tag delimiter characters ">" and "<" %} 50 | 51 |
    b %} data-a {% endif %} 54 | {% if c < d %} data-b {% endif %} 55 | {% unless e > f and g < h %}data-c="a > b"{% elsif i > j %}data-d="a > b"{% endunless %} 56 | {% if < k and l > m %} 57 | {{ output_1 | filter: '>' | filter: '<' }} 58 | {% else %} 59 | {{ output_2 | filter: '<' | filter: '>' }} 60 | {% endif %} 61 | 62 | > 63 | 64 |
    65 | 66 | ` 67 | ] 68 | )( 69 | { 70 | language: 'liquid', 71 | liquid: { 72 | normalizeSpacing: true 73 | }, 74 | markup: { 75 | forceAttribute: true 76 | } 77 | } 78 | )(function (source, rules, label) { 79 | 80 | const snapshot = esthetic.format(source, rules); 81 | 82 | // console.log(snapshot); 83 | t.snapshot(snapshot, label); 84 | 85 | }); 86 | 87 | }); 88 | -------------------------------------------------------------------------------- /tests/cases/attributes/quotations.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { forRule, liquid } from '@liquify/ava/esthetic'; 3 | import esthetic from 'esthetic'; 4 | 5 | test('Quote conversion within values', t => { 6 | 7 | forRule( 8 | [ 9 | liquid` 10 | 11 | {% # single quotation "'" characters nesting in HTML attribute values. %} 12 | 13 |
    19 | 20 |
    ` 21 | , 22 | liquid` 23 | 24 | {% # double quotation '"' characters nesting in HTML attribute values %} 25 | 26 |
    32 | 33 |
    ` 34 | , 35 | liquid` 36 | 37 | {% # mixture of double and single quotations nesting in HTML attribute values %} 38 | 39 |
    45 | 46 |
    47 | 48 | ` 49 | ] 50 | )( 51 | [ 52 | { 53 | language: 'liquid', 54 | markup: { quoteConvert: 'none' } 55 | }, 56 | { 57 | language: 'liquid', 58 | markup: { quoteConvert: 'double' } 59 | }, 60 | { 61 | language: 'liquid', 62 | markup: { quoteConvert: 'single' } 63 | }, 64 | { 65 | language: 'liquid', 66 | markup: { quoteConvert: 'none' } 67 | } 68 | ] 69 | )(function (source, rules, label) { 70 | 71 | const snapshot = esthetic.format(source, rules); 72 | 73 | t.snapshot(snapshot, label); 74 | 75 | }); 76 | 77 | }); 78 | -------------------------------------------------------------------------------- /tests/cases/attributes/snapshots/casing.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/attributes/snapshots/casing.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/attributes/snapshots/indentation.test.mjs.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `tests/cases/attributes/indentation.test.mjs` 2 | 3 | The actual snapshot is saved in `indentation.test.mjs.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## Indenting attributes contained in Liquid block tags 8 | 9 | >

    Rules

    10 | > 11 | > ```js 12 | > { 13 | > "language": "liquid", 14 | > "liquid": { 15 | > "indentAttributes": true 16 | > }, 17 | > "markup": { 18 | > "forceAttribute": true 19 | > } 20 | > } 21 | > ``` 22 | 23 | `{% # Indenting controls %}␊ 24 | ␊ 25 |
    ␊ 26 | ␊ 27 | ␊ 43 | ␊ 44 | Hello World␊ 45 | ␊ 46 | ␊ 47 | ␊ 48 |
    ` 49 | 50 | >

    Rules

    51 | > 52 | > ```js 53 | > { 54 | > "language": "liquid", 55 | > "liquid": { 56 | > "indentAttributes": true 57 | > }, 58 | > "markup": { 59 | > "forceAttribute": true 60 | > } 61 | > } 62 | > ``` 63 | 64 | `{% # Deeply nested indentations %}␊ 65 | ␊ 66 |
    ␊ 67 | ␊ 68 | ␊ 89 | ␊ 90 | Hello World␊ 91 | ␊ 92 | ␊ 93 | ␊ 94 |
    ` 95 | -------------------------------------------------------------------------------- /tests/cases/attributes/snapshots/indentation.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/attributes/snapshots/indentation.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/attributes/snapshots/liquid-chains.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/attributes/snapshots/liquid-chains.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/attributes/snapshots/nested-delimiters.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/attributes/snapshots/nested-delimiters.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/attributes/snapshots/quotations.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/attributes/snapshots/quotations.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/attributes/todo/html-structures.test.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/attributes/todo/html-structures.test.mjs -------------------------------------------------------------------------------- /tests/cases/attributes/todo/liquid-structures.test.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/attributes/todo/liquid-structures.test.mjs -------------------------------------------------------------------------------- /tests/cases/css/nested.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { css, forSample } from '@liquify/ava/esthetic'; 3 | 4 | test.skip('Nested Test: Structural handling of CSS stylesheets', t => { 5 | 6 | forSample([ 7 | css` 8 | header-drawer { 9 | justify-self: start; 10 | margin-left: -1.2rem; 11 | } 12 | 13 | {%- if section.settings.sticky_header_type == 'reduce-logo-size' -%} 14 | .scrolled-past-header .header__heading-logo-wrapper { 15 | width: 75%; 16 | } 17 | {%- endif -%} 18 | 19 | {%- if section.settings.menu_type_desktop != "drawer" -%} 20 | @media screen and (min-width: 990px) { 21 | header-drawer { 22 | display: none; 23 | } 24 | } 25 | {%- endif -%} 26 | 27 | .menu-drawer-container { 28 | display: flex; 29 | } 30 | 31 | .list-menu { 32 | list-style: none; 33 | padding: 0; 34 | margin: 0; 35 | } 36 | 37 | .list-menu--inline { 38 | display: inline-flex; 39 | flex-wrap: wrap; 40 | } 41 | 42 | summary.list-menu__item { 43 | padding-right: 2.7rem; 44 | } 45 | 46 | .list-menu__item { 47 | display: flex; 48 | align-items: center; 49 | line-height: calc(1 + 0.3 / var(--font-body-scale)); 50 | } 51 | 52 | .list-menu__item--link { 53 | text-decoration: none; 54 | padding-bottom: 1rem; 55 | padding-top: 1rem; 56 | line-height: calc(1 + 0.8 / var(--font-body-scale)); 57 | } 58 | 59 | @media screen and (min-width: 750px) { 60 | .list-menu__item--link { 61 | padding-bottom: 0.5rem; 62 | padding-top: 0.5rem; 63 | } 64 | } 65 | ` 66 | 67 | ]); 68 | 69 | }); 70 | -------------------------------------------------------------------------------- /tests/cases/html/snapshots/ignore-next.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/html/snapshots/ignore-next.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/html/snapshots/ignore-region.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/html/snapshots/ignore-region.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/json/liquid-occurances.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { forAssert, json } from '@liquify/ava/esthetic'; 3 | import esthetic from 'esthetic'; 4 | 5 | test('Structure Tests - Liquid as values', t => { 6 | 7 | forAssert( 8 | [ 9 | [ 10 | json` 11 | {"prop": 12 | {{ object.prop }}} 13 | `, 14 | json` 15 | { 16 | "prop": {{ object.prop }} 17 | } 18 | ` 19 | ], 20 | [ 21 | json` 22 | {"prop": {% if foo %} {{ object.prop }} {% else %} {{ object.prop }} {% endif %} } 23 | `, 24 | json` 25 | { 26 | "prop": {% if foo %} {{ object.prop }} {% else %} {{ object.prop }} {% endif %} 27 | } 28 | ` 29 | ], 30 | [ 31 | json` 32 | // comment 33 | [ 34 | { 35 | "foo": 100 36 | }, 37 | 38 | {% for i in array %} 39 | { 40 | "prop": {{ i }} 41 | }{% unless i.last %},{% endunless %} 42 | {% endfor %} 43 | ] 44 | `, 45 | json` 46 | // comment 47 | [ 48 | { 49 | "foo": 100 50 | }, 51 | {% for i in array %} 52 | { 53 | "prop": {{ i }} 54 | }{% unless i.last %},{% endunless %} 55 | {% endfor %} 56 | ] 57 | ` 58 | ] 59 | ] 60 | )(function (source, expect) { 61 | 62 | const actual = esthetic.json(source, { 63 | preserveLine: 0, 64 | json: { 65 | objectSort: true, 66 | arrayFormat: 'indent', 67 | bracePadding: false, 68 | objectIndent: 'indent', 69 | braceAllman: true 70 | } 71 | }); 72 | 73 | t.deepEqual(actual, expect); 74 | 75 | }); 76 | 77 | }); 78 | -------------------------------------------------------------------------------- /tests/cases/json/liquid-strings.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { forAssert, json } from '@liquify/ava/esthetic'; 3 | import esthetic from 'esthetic'; 4 | 5 | test('Structure Tests - Liquid in JSON string occurances', t => { 6 | 7 | forAssert( 8 | [ 9 | [ 10 | json` 11 | {"prop": "Use {{ amount }} for where you want the remaining amount to display"} 12 | `, 13 | json` 14 | { 15 | "prop": "Use {{ amount }} for where you want the remaining amount to display" 16 | } 17 | ` 18 | ], 19 | [ 20 | json` 21 | {"prop": "Some text {% if condition %} {{ object }} {% endif %} Some more"} 22 | `, 23 | json` 24 | { 25 | "prop": "Some text {% if condition %} {{ object }} {% endif %} Some more" 26 | } 27 | ` 28 | ] 29 | ] 30 | )(function (source, expect) { 31 | 32 | const actual = esthetic.json(source, { 33 | preserveLine: 0, 34 | json: { 35 | objectSort: true, 36 | arrayFormat: 'indent', 37 | bracePadding: false, 38 | objectIndent: 'indent', 39 | braceAllman: true 40 | } 41 | }); 42 | 43 | t.deepEqual(actual, expect); 44 | 45 | }); 46 | 47 | }); 48 | -------------------------------------------------------------------------------- /tests/cases/json/todo/strip-comments.test.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/json/todo/strip-comments.test.mjs -------------------------------------------------------------------------------- /tests/cases/liquid/force-filters.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { forAssert, liquid } from '@liquify/ava/esthetic'; 3 | import esthetic from 'esthetic'; 4 | 5 | test.skip('Structure Test: Force Tag Arguments (Line Break - After)', t => { 6 | 7 | forAssert( 8 | [ 9 | [ 10 | liquid` 11 | {% render 'snippet', param_1: true, param_2: 1000, param_3: 'string', param_4: nil %} 12 | `, 13 | liquid` 14 | {% render 'snippet', 15 | param_1: true, 16 | param_2: 1000, 17 | param_3: 'string', 18 | param_4: nil %} 19 | ` 20 | ], 21 | [ 22 | liquid` 23 | {% render 'snippet' 24 | , param_1: true 25 | , param_2: 1000 26 | , param_3: 'string' 27 | , param_4: nil %} 28 | `, 29 | liquid` 30 | {% render 'snippet', 31 | param_1: true, 32 | param_2: 1000, 33 | param_3: 'string', 34 | param_4: nil %} 35 | ` 36 | ], 37 | [ 38 | liquid` 39 | {% render 'snippet', param_1: true, param_2: 1000 40 | , param_3: 'string', param_4: nil %} 41 | `, 42 | liquid` 43 | {% render 'snippet', 44 | param_1: true, 45 | param_2: 1000, 46 | param_3: 'string', 47 | param_4: nil %} 48 | ` 49 | ], 50 | [ 51 | liquid` 52 | {% render 'snippet' 53 | , 54 | param_1: true , param_2: 1000 55 | , 56 | param_3: 'string' 57 | , param_4: nil, %} 58 | `, 59 | liquid` 60 | {% render 'snippet', 61 | param_1: true, 62 | param_2: 1000, 63 | param_3: 'string', 64 | param_4: nil %} 65 | ` 66 | ] 67 | 68 | ] 69 | )(function (source, expect) { 70 | 71 | const actual = esthetic.format(source, { 72 | language: 'liquid', 73 | liquid: { 74 | forceArgument: 2 75 | } 76 | }); 77 | 78 | t.is(actual, expect); 79 | 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /tests/cases/liquid/force-wrap.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { forAssert, liquid } from '@liquify/ava/esthetic'; 3 | import esthetic from 'esthetic'; 4 | 5 | test.todo('Write Force Tests'); 6 | 7 | test.skip('Forcing Filters: Newlined filters and filter arguments', t => { 8 | 9 | forAssert( 10 | [ 11 | [ 12 | liquid` 13 | {% assign x = settings.logo 14 | | image_url: width: 500 15 | | image_tag: class: 'header__heading-logo motion-reduce' 16 | , widths: '50, 100, 150, 200, 250, 300, 400, 500' 17 | , height: logo_height 18 | , width: settings.logo_width 19 | , alt: logo_alt 20 | | replace: ',' , 'foo' 21 | | font_family: 'bold', '300', 'exec' %} 22 | 23 | ` 24 | ] 25 | ] 26 | ); 27 | }); 28 | 29 | test.skip('Forcing Conditions: Newlined control conditions', t => { 30 | 31 | forAssert( 32 | [ 33 | [ 34 | liquid` 35 | {% unless product.metafields.data.material_shell.value == nil 36 | and product.metafields.data.material_lining.value == nil 37 | and product.metafields.data.material_padding.value == nil 38 | and product.metafields.data.material_piping.value == nil 39 | and product.metafields.data.material_webbing.value == nil %} 40 | 41 | {% form 'some-form', id: 'some-long-id', attr-1: 'foo', attr-2: 'bar', attr-3: 'baz', attr-4: 'xxx' %} 42 | 43 | {% endform %} 44 | 45 | hello world 46 | {% endunless %} 47 | 48 | ` 49 | ] 50 | ] 51 | ); 52 | }); 53 | -------------------------------------------------------------------------------- /tests/cases/liquid/linebreak-separators.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import { forSample, liquid } from '@liquify/ava/esthetic'; 3 | import esthetic from 'esthetic'; 4 | 5 | test.skip('Line Break Separator (after): ', t => { 6 | 7 | forSample( 8 | [ 9 | 10 | liquid`{{- output -}}` 11 | 12 | ] 13 | )(function (source, expect) { 14 | 15 | const actual = esthetic.format(source, { 16 | language: 'liquid', 17 | liquid: { 18 | delimiterTrims: 'outputs' 19 | } 20 | }); 21 | 22 | t.is(actual, expect); 23 | 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /tests/cases/liquid/snapshots/comment-block.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/liquid/snapshots/comment-block.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/liquid/snapshots/comments.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/liquid/snapshots/comments.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/liquid/snapshots/delimiter-placement.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/liquid/snapshots/delimiter-placement.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/liquid/snapshots/ignore-next.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/liquid/snapshots/ignore-next.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/liquid/snapshots/ignore-region.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/liquid/snapshots/ignore-region.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/liquid/snapshots/line-comments.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/liquid/snapshots/line-comments.test.mjs.snap -------------------------------------------------------------------------------- /tests/cases/liquid/todo/capture-tag.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/liquid/todo/capture-tag.mjs -------------------------------------------------------------------------------- /tests/cases/liquid/todo/javascript-tag.test.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/liquid/todo/javascript-tag.test.mjs -------------------------------------------------------------------------------- /tests/cases/liquid/todo/line-breaks.test.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cases/liquid/todo/line-breaks.test.mjs -------------------------------------------------------------------------------- /tests/cli/file.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cli/file.css -------------------------------------------------------------------------------- /tests/cli/file.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cli/file.html -------------------------------------------------------------------------------- /tests/cli/file.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/cli/file.xml -------------------------------------------------------------------------------- /tests/dev.liquid: -------------------------------------------------------------------------------- 1 | 22 | 23 | 32 | -------------------------------------------------------------------------------- /tests/rules/samples/global/end-newline.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing newline ending, ie: whether or not to insert a final line. 3 | --- 4 | Lorem ipsum dolor sit amet, consectetur adipiscing elit 5 | -------------------------------------------------------------------------------- /tests/rules/samples/global/indent-char.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing different types of indentation characters. 3 | --- 4 | 5 | // INDENTATION CHARACTERS 6 | 7 | const foo = { 8 | first: { 9 | second: { 10 | third: [ 11 | 'one', 12 | 'two', 13 | 'three', 14 | 'four', 15 | 'fix', 16 | 'six', 17 | 'seven', 18 | 'eight', 19 | 'nine', 20 | '10' 21 | ] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/rules/samples/global/indent-size.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing indentation size. 3 | --- 4 | 5 |
    6 |
    7 |
    8 | {% if x %} 9 |
      10 |
    • Hello
    • 11 |
    • World
    • 12 |
    13 | {% else %} 14 |
    15 |
    16 |
    17 | {% unless x %} 18 |

    Indentation Size

    19 | {% else %} 20 |

    Testing Indentation

    21 | {% endunless %} 22 |
    23 |
    24 |
    25 | {% endif %} 26 |
    27 |
    28 |
    29 | -------------------------------------------------------------------------------- /tests/rules/samples/global/preserve-comment.txt: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 |

    Testing inline comments

    5 | 6 | 7 |

    Hello world

    8 | 9 |

    Testing indented comments

    10 | 11 |
    12 | {%- if x -%} 13 |
    14 | {%- comment -%} 15 | Donec pretium 16 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, 17 | sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 18 | {%- endcomment -%} 19 | 20 | {{- 'string' | t -}} 21 | 22 |
    23 | {% comment %} inline comment {% endcomment %} 24 |
      25 |
    • 26 | {% comment %}Lorem ipsum dolor sit amet, consectetur adipiscing elit, 27 | sed do eiusmod tempor incididunt ut labore 28 | et dolore magna aliqua.{% endcomment -%} 29 |
        30 | {% comment %} 31 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, 32 | sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.{% endcomment -%} 33 |
      • Hello World
      • 34 | 35 |
      • HTML Comments
      • 36 | 37 |
      • HTML Comments inline
      • 38 |
      39 |
    • 40 |
    41 | {%- endif -%} 42 |
    43 |
    44 | -------------------------------------------------------------------------------- /tests/rules/samples/global/preserve-line.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing newline preservation 3 | --- 4 | 5 | .class { 6 | font-size: 10px; 7 | 8 | 9 | 10 | 11 | background: black; 12 | 13 | 14 | color: pink; 15 | } 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | .another-class { 26 | 27 | 28 | 29 | text-transform: uppercase; 30 | } 31 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/attribute-casing.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing HTML (markup) `attributeCasing` rule. 3 | --- 4 | 5 |
    11 | 12 |
    13 |
    14 |
    15 | 16 |
    17 | 18 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/attribute-sort-list.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing attribute sorting list accordance. Attributes will sorted according to the names provided to `attributeSortList[]` and alphanumerically thereafter. This rule requires `attributeSort` to be `true` 3 | --- 4 | 5 |
    16 | 17 |
    18 | 19 |

    36 | 37 |

    38 | 39 |

    40 | 41 |
    42 |
    43 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/attribute-sort.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing attribute sorting. This rule sorts markup attributes alphanumerically. 3 | --- 4 | 5 |
    16 | 17 |
      18 | 19 |
    • 36 | 37 |
    • 38 |
    39 | 40 |
    41 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/attribute-values.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/markup/attribute-values.txt -------------------------------------------------------------------------------- /tests/rules/samples/markup/comment-newline.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/markup/comment-newline.txt -------------------------------------------------------------------------------- /tests/rules/samples/markup/correct.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/markup/correct.txt -------------------------------------------------------------------------------- /tests/rules/samples/markup/delimiter-trims.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing delimiter trim appliers. This is a Liquid specific beautification option. 3 | --- 4 | 5 | {{no_trims | filter: 'something'}} 6 | {{no_trims | filter: 'something'}} 7 | {{no_trims | filter: 'something'}} 8 | 9 | {{- full_trims | filter: 'something'-}} 10 | {{- full_trims | filter: 'something'-}} 11 | {{- full_trims | filter: 'something'-}} 12 | {{- full_trims | filter: 'something'-}} 13 | 14 | {{- left_trim | filter: 'something'}} 15 | {{- left_trim | filter: 'something'}} 16 | {{- left_trim | filter: 'something'}} 17 | {{- left_trim | filter: 'something'}} 18 | 19 | {{right_trim | filter: 'something' -}} 20 | {{right_trim | filter: 'something' -}} 21 | {{right_trim | filter: 'something' -}} 22 | {{right_trim | filter: 'something' -}} 23 | 24 | {{- 25 | newline_top_trim 26 | }} 27 | 28 | {{ 29 | newline_bottom_trim 30 | -}} 31 | 32 | {{- 33 | newline_full_trim 34 | -}} 35 | 36 | {{ 37 | newline_no_trim 38 | }} 39 | 40 | 41 | {% if no_trims %}Something{% endif %} 42 | {%- if full_trims -%}Something{%- endif -%} 43 | {%if right_trim -%}Something{% endif -%} 44 | {%- if left_trim -%}Something{%- endif %} 45 | 46 | {% for x in arr -%} 47 | 48 |
    49 | 50 |
      51 | 52 |
    • 53 | 54 | {{no_trims | filter: 'something'}} 55 | {{no_trims | filter: 'something'}} 56 | 57 | {{- full_trims | filter: 'something'-}} 58 | {{- full_trims | filter: 'something'-}} 59 | 60 |
    • 61 | 62 |
    63 |
    64 | 65 | {%endif-%} 66 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/force-attribute-wrap.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing wrap based attribute forcing. When word wrap limit is exceeded then attributes will be forced. This beautification rule requires `forceAttribute` to be `false` and `wrap` to be higher than `0` 3 | --- 4 | 5 |
    7 |
      8 |
    • 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 |
      Header 1Header 2
      0 %}data-elsif{% else %}data-else{% endif %}={{ value}}> 
      23 |
    • 24 |
    • 25 |
    • 26 |
    27 |
    28 | 29 |
    30 | 31 |
    33 | 34 |
    35 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/force-attribute.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing forced attribute indentation. We have provided a complex series of attributes. The **cases/attributes** tests deal with a lot of this logic. 3 | --- 4 | 5 |
    7 | 8 |
    9 | 10 |
    12 | 13 |
    14 |
    18 | 19 |
    20 | 21 |
    33 | 34 |
    35 | 36 | 37 |
    38 | 39 |
    40 | 41 |
    42 | 43 |
    44 | 45 |
    0 %}data-elsif{% else %}data-else{% endif %}={{ value}} 63 | 64 | data-{% if x %}id="foo"{% else %}name{% endif %} 65 | 66 | >
    67 | 68 |
    69 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/force-indent.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing forced content indentation. 3 | --- 4 | 5 |
      6 |
    • Content will be forced onto newlines
    • 7 |
    • Content will be forced onto newlines
    • 8 |
    • Content will be forced onto newlines
    • 9 |
    • Content will be forced onto newlines
    • 10 |
    • 11 |
        12 |
      • Content will be forced onto newlines
      • 13 |
      • Content will be forced onto newlines
      • 14 |
      • Content will be forced onto newlines
      • 15 |
      • Content will be forced onto newlines
      • 16 |
      • Content will be forced onto newlines
      • 17 |
      18 |
    • 19 |
    20 | 21 |
    Content will be forced onto newlines
    22 | 23 |

    Content will be forced onto newlines 24 |

    25 | 26 |

    Content will be forced onto newlines

    27 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/force-lead-attribute.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing wrap based attribute forcing with lead attributes of tags being output onto new lines. This rule behaves that same as `forceAttribute` but uses `wrap` limit as the trigger. 3 | --- 4 | 5 |
    7 |
      8 |
    • 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 |
      Header 1Header 2
      0 %}data-elsif{% else %}data-else{% endif %}={{ value}}> 
      23 |
    • 24 |
    • 25 |
    • 26 |
    27 |
    28 | 29 |
    30 | 31 |
    33 | 34 |
    35 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/normalize-spacing.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing normalized spacing. This rule is for Liquid tokens and will equalize and correct spacing. It equally distributes spaces applied inside of Liquid tags and outputs. 3 | --- 4 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/preserve-attributes.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing attribute preservation. The attribut structures will not be beautified and left intact during formatting. 3 | --- 4 | 5 |
    8 | 9 |

    Attributes will be untouched

    10 | 11 | 12 | No formatting is applied to attributes: 13 | 14 |
    26 | 27 |

    Attributes will be untouched

    28 | 29 |
    30 | 31 | 32 |
    33 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/quote-convert.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing quotation character conversions. All Liquid tags contained within HTML attribute values will use the opposite quotation characters. 3 | --- 4 | 5 | 6 |
    12 | 13 | {% assign x = "quote-convert" | filter: "xxxxx" %} 14 | 15 |
      16 |
    • 17 | {{ 'xxx' }} 18 |
    • 19 |
    20 | 21 |
    22 | -------------------------------------------------------------------------------- /tests/rules/samples/markup/self-close-space.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing self close spacer. This applies a single space character on void tags. This is _legacy_ beautification option and inherited from PrettyDiff. Still hold relevance for some situations. 3 | --- 4 | 5 | 6 | 7 |
    8 |
    9 |
    10 | 11 |
    12 | 13 | 14 | 15 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/rules/samples/script/array-format.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/array-format.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/brace-allman.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/brace-allman.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/brace-newline.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/brace-newline.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/brace-padding.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/brace-padding.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/brace-style.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/brace-style.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/case-space.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/case-space.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/correct.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/correct.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/else-newline.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/else-newline.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/end-comma.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/end-comma.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/function-name-space.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/function-name-space.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/function-space.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/function-space.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/inline-return.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/inline-return.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/method-chain.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/method-chain.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/never-flatten.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/never-flatten.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/no-case-indent.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/no-case-indent.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/no-semicolon.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/no-semicolon.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/object-indent.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/object-indent.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/object-sort.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/object-sort.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/quote-convert.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/quote-convert.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/ternary-line.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/ternary-line.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/variable-list.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/variable-list.txt -------------------------------------------------------------------------------- /tests/rules/samples/script/vertical.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/script/vertical.txt -------------------------------------------------------------------------------- /tests/rules/samples/style/class-padding.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing class padding beautification option. The option will place newlines between selectors 3 | --- 4 | 5 | .a {} 6 | .b {} 7 | .c {} 8 | 9 | /* Other Selectors */ 10 | 11 | .selector { background: #eee; border-radius: 20px; } 12 | label { 13 | width: 160px; 14 | float: left; 15 | text-align: right; 16 | padding: 4px; 17 | margin-bottom: 20px; 18 | } 19 | input { 20 | width: 130px; 21 | float: right; 22 | } 23 | label, input { 24 | font-size: 1em; 25 | line-height: 1.5; 26 | } 27 | input[type="checkbox"] { 28 | height: 24px; 29 | } 30 | div { clear: both; } 31 | .errors { 32 | background: yellow; 33 | border-radius: 20px; 34 | box-shadow: 1px 1px 1px black; 35 | padding: 20px; 36 | width: 300px; 37 | position: absolute; 38 | left: 390px; 39 | } 40 | -------------------------------------------------------------------------------- /tests/rules/samples/style/compress-css.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing compress css 3 | --- 4 | 5 | 6 | :is(section, article, aside, nav) :is(h1, h2, h3, h4, h5, h6) { 7 | color: #BADA55; 8 | } 9 | 10 | input { 11 | width: 130px; 12 | float: right; 13 | } 14 | 15 | section h1, section h2, section h3, section h4, section h5, section h6, 16 | article h1, article h2, article h3, article h4, article h5, article h6, 17 | aside h1, aside h2, aside h3, aside h4, aside h5, aside h6, 18 | nav h1, nav h2, nav h3, nav h4, nav h5, nav h6 { 19 | color: #BADA55; 20 | } 21 | -------------------------------------------------------------------------------- /tests/rules/samples/style/correct.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing correction option. This rule will do some very mild linting and fix sloppiness in code. The comments will list the applied corrections. 3 | --- 4 | 5 | /* Adds a semicolon to the last property (display: flex) */ 6 | 7 | .select { 8 | float: right; 9 | width: 100%; 10 | height: 100%; 11 | display: flex 12 | } 13 | -------------------------------------------------------------------------------- /tests/rules/samples/style/force-value.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/samples/style/force-value.txt -------------------------------------------------------------------------------- /tests/rules/samples/style/no-lead-zero.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing unit based beautification rule which will remove leading zeros `0` from number values. The option will preserve some units (like `%`) 3 | --- 4 | 5 | .selector { 6 | width: 0.1%; 7 | height: 0.05rem; 8 | font-size: 00.30em; 9 | padding: 0.9px; 10 | line-height: 001.10%; 11 | } 12 | -------------------------------------------------------------------------------- /tests/rules/samples/style/quote-convert.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Testing quote conversions applied to string values 3 | --- 4 | 5 | .box { 6 | background-image: url("images/my-background.png"); 7 | } 8 | 9 | .box { 10 | background-image: url("https://www.example.com/images/my-background.png"); 11 | } 12 | 13 | p:lang(en) { 14 | quotes: "\201C" "\201D" "\2018" "\2019" "\201C" "\201D" "\2018" "\2019"; 15 | } 16 | 17 | .clip-me { 18 | clip-path: path('M0.5,1 C0.5,1,0,0.7,0,0.3 A0.25,0.25,1,1,1,0.5,0.3 A0.25,0.25,1,1,1,1,0.3 C1,0.7,0.5,1,0.5,1 Z'); 19 | } 20 | 21 | .move-me { 22 | offset-path: path("M56.06,227 ..."); 23 | } 24 | 25 | 26 | @font-face { 27 | font-family: 'FeltTipPen'; 28 | src: local('Felt Tip Pen Web'), /* Full font name */ 29 | local('FeltTipPen-Regular'); /* Postscript name */ 30 | } 31 | 32 | .help::before { 33 | content: image("try.webp", "try.svg", "try.gif"); 34 | } 35 | -------------------------------------------------------------------------------- /tests/rules/samples/style/sort-properties.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Test CSS selector property sorting. Property sorting will be applied in alphabetical order. The first snapshot has sorting enabled, the second snapshot has it disabled. 3 | --- 4 | 5 | img { 6 | padding-top: 40px; 7 | padding-right: 25px; 8 | padding-bottom: 40px; 9 | padding-left: 25px; 10 | margin: 100px; 11 | font-size: 12px; 12 | } 13 | 14 | body { 15 | background-image: url("barn.jpg"); 16 | z-index: 999; 17 | color: #fff; 18 | width: 200px; 19 | background-repeat: no-repeat; 20 | background-position: right top; 21 | background-attachment: fixed; 22 | font-weight: 100; 23 | font-style: bold: 24 | margin-top: 100px; 25 | display: flex; 26 | position: absolute; 27 | float: right; 28 | margin-left: 100px; 29 | padding-right: 25px; 30 | transition: ease-in; 31 | visibility: 32 | padding-bottom: 40px; 33 | font-weight: 100; 34 | font-style: bold: 35 | padding-left: 25px; 36 | visibility: collapse; 37 | min-inline-size: inherit; 38 | } 39 | 40 | 41 | .selector { 42 | background-image: url("barn.jpg"); 43 | z-index: 999; 44 | color: #fff; 45 | width: 200px; 46 | background-repeat: no-repeat; 47 | background-position: right top; 48 | background-attachment: fixed; 49 | font-weight: 100; 50 | font-style: bold: 51 | margin-top: 100px; 52 | display: flex; 53 | position: absolute; 54 | float: right; 55 | margin-left: 100px; 56 | padding-right: 25px; 57 | transition: ease-in; 58 | visibility: 59 | padding-bottom: 40px; 60 | font-weight: 100; 61 | font-style: bold: 62 | padding-left: 25px; 63 | visibility: collapse; 64 | min-inline-size: inherit; 65 | } 66 | -------------------------------------------------------------------------------- /tests/rules/samples/style/sort-selectors.txt: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | Test CSS selector sorting. Class selector sorting will be applied in alphabetical order. The first snapshot has sorting enabled, the second snapshot has it disabled. 4 | --- 5 | 6 | .v, 7 | .z, 8 | .y, 9 | .a, 10 | .g, 11 | .u, 12 | .x > .a > .b, 13 | .x > .c > .d, 14 | .c > .d > .x, 15 | .f, 16 | .e, 17 | .n, 18 | .r, 19 | .t > .v > .x, 20 | .w, 21 | .b, 22 | .h, 23 | .j, 24 | .m, 25 | .k, 26 | .o, 27 | .ö, 28 | .ä { 29 | background-image: url("barn.jpg"); 30 | z-index: 999; 31 | color: #fff; 32 | width: 200px; 33 | background-repeat: no-repeat; 34 | background-position: right top; 35 | background-attachment: fixed; 36 | font-weight: 100; 37 | font-style: bold: 38 | margin-top: 100px; 39 | display: flex; 40 | position: absolute; 41 | float: right; 42 | margin-left: 100px; 43 | padding-right: 25px; 44 | transition: ease-in; 45 | visibility: 46 | padding-bottom: 40px; 47 | font-weight: 100; 48 | font-style: bold: 49 | padding-left: 25px; 50 | visibility: collapse; 51 | min-inline-size: inherit; 52 | } 53 | 54 | 55 | .v, 56 | .z, 57 | .y, 58 | .a, 59 | .g, 60 | .u, 61 | .x, 62 | .x, 63 | .c, 64 | .f, 65 | .e, 66 | .n, 67 | .r, 68 | .t, 69 | .w, 70 | .b, 71 | .h, 72 | .j, 73 | .m, 74 | .k, 75 | .o, 76 | .ö, 77 | .ä { 78 | background-image: url("barn.jpg"); 79 | z-index: 999; 80 | color: #fff; 81 | width: 200px; 82 | background-repeat: no-repeat; 83 | background-position: right top; 84 | background-attachment: fixed; 85 | font-weight: 100; 86 | font-style: bold: 87 | margin-top: 100px; 88 | display: flex; 89 | position: absolute; 90 | float: right; 91 | margin-left: 100px; 92 | padding-right: 25px; 93 | transition: ease-in; 94 | visibility: 95 | padding-bottom: 40px; 96 | font-weight: 100; 97 | font-style: bold: 98 | padding-left: 25px; 99 | visibility: collapse; 100 | min-inline-size: inherit; 101 | } 102 | -------------------------------------------------------------------------------- /tests/rules/script.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | test.todo('TODO: Script rules tests'); 4 | -------------------------------------------------------------------------------- /tests/rules/snapshots/globals.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/snapshots/globals.test.mjs.snap -------------------------------------------------------------------------------- /tests/rules/snapshots/markup.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/snapshots/markup.test.mjs.snap -------------------------------------------------------------------------------- /tests/rules/snapshots/style.test.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/rules/snapshots/style.test.mjs.snap -------------------------------------------------------------------------------- /tests/units/chars.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | const chars = { 4 | ATT: 64, // @ 5 | HSH: 35, // # 6 | LPR: 40, // ( 7 | RPR: 41, // ) 8 | LCB: 123, // { 9 | RCB: 125, // } 10 | LSB: 91, // [] 11 | RSB: 93, // ] 12 | LAN: 60, // < 13 | RAN: 62, // > 14 | BNG: 33, // ! 15 | DSH: 45, // - 16 | PER: 37, // % 17 | EQS: 61, // = 18 | DQO: 34, // " 19 | SQO: 39, // ' 20 | TQO: 96, // ` 21 | WSP: 32, // 22 | NWL: 10, // \n 23 | FWS: 47, // / 24 | QWS: 63, // ? 25 | ARS: 42, // * 26 | COL: 58, // : 27 | SEM: 59, // ; 28 | COM: 44, // , 29 | PLS: 43 // + 30 | }; 31 | 32 | test('Unit: Characted Codes (Enum) Maps', t => { 33 | 34 | t.is('@'.charCodeAt(0), chars.ATT); 35 | t.is('#'.charCodeAt(0), chars.HSH); 36 | t.is('('.charCodeAt(0), chars.LPR); 37 | t.is(')'.charCodeAt(0), chars.RPR); 38 | t.is('{'.charCodeAt(0), chars.LCB); 39 | t.is('}'.charCodeAt(0), chars.RCB); 40 | t.is('['.charCodeAt(0), chars.LSB); 41 | t.is(']'.charCodeAt(0), chars.RSB); 42 | t.is('<'.charCodeAt(0), chars.LAN); 43 | t.is('>'.charCodeAt(0), chars.RAN); 44 | t.is('!'.charCodeAt(0), chars.BNG); 45 | t.is('-'.charCodeAt(0), chars.DSH); 46 | t.is('%'.charCodeAt(0), chars.PER); 47 | t.is('='.charCodeAt(0), chars.EQS); 48 | t.is('"'.charCodeAt(0), chars.DQO); 49 | t.is("'".charCodeAt(0), chars.SQO); 50 | t.is('`'.charCodeAt(0), chars.TQO); 51 | t.is(' '.charCodeAt(0), chars.WSP); 52 | t.is('\n'.charCodeAt(0), chars.NWL); 53 | t.is('/'.charCodeAt(0), chars.FWS); 54 | t.is('?'.charCodeAt(0), chars.QWS); 55 | t.is('*'.charCodeAt(0), chars.ARS); 56 | t.is(':'.charCodeAt(0), chars.COL); 57 | t.is(';'.charCodeAt(0), chars.SEM); 58 | t.is(','.charCodeAt(0), chars.COM); 59 | t.is('+'.charCodeAt(0), chars.PLS); 60 | }); 61 | -------------------------------------------------------------------------------- /tests/units/detect.test.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/units/detect.test.mjs -------------------------------------------------------------------------------- /tests/units/errors.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | test.todo('TODO: Write error tests'); 4 | -------------------------------------------------------------------------------- /tests/units/events.test.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/units/events.test.mjs -------------------------------------------------------------------------------- /tests/units/grammar.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | test.todo('TODO: Write grammar tests'); 4 | -------------------------------------------------------------------------------- /tests/units/hooks.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | test.todo('TODO: Write hook tests'); 4 | -------------------------------------------------------------------------------- /tests/units/options.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | test.todo('TODO: Write options tests'); 4 | -------------------------------------------------------------------------------- /tests/units/preset.test.mjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/tests/units/preset.test.mjs -------------------------------------------------------------------------------- /tests/units/rules.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | import esthetic from 'esthetic'; 3 | 4 | test('Unit: Persisting merging of rules ', t => { 5 | 6 | const rules = esthetic.rules({ 7 | language: 'liquid', 8 | liquid: { 9 | normalizeSpacing: true 10 | } 11 | }); 12 | 13 | }); 14 | -------------------------------------------------------------------------------- /tests/units/stats.test.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava'; 2 | 3 | test.todo('TODO: Write stats tests'); 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@liquify/tsconfig", 3 | "exclude": [ 4 | "node_modules/**", 5 | "package", 6 | "test", 7 | "indexs.mjs", 8 | "indexs.js", 9 | "index.d.ts" 10 | ], 11 | "include": [ 12 | "src", 13 | "types", 14 | "tests" 15 | ], 16 | "typeAcquisition": { 17 | "enable": true, 18 | "include": ["node"], 19 | }, 20 | "compilerOptions": { 21 | "types": ["node"], 22 | "incremental": false, 23 | "allowJs": true, 24 | "declaration": true, 25 | "removeComments": false, 26 | "module": "ESNext", 27 | "emitDeclarationOnly": true, 28 | "baseUrl": ".", 29 | "paths": { 30 | "types/*": [ 31 | "./types/*" 32 | ], 33 | "config": [ 34 | "./src/config.ts" 35 | ], 36 | "./index.js": [ 37 | "./index.js" 38 | ], 39 | "cli/*": [ 40 | "./src/cli/*" 41 | ], 42 | "format": [ 43 | "src/format/index.ts" 44 | ], 45 | "lexers": [ 46 | "./src/lexers/index.ts" 47 | ], 48 | "lexical/*": [ 49 | "./src/lexical/*" 50 | ], 51 | "chars": [ 52 | "./src/lexical/chars.ts" 53 | ], 54 | "comments": [ 55 | "./src/comments/index.ts" 56 | ], 57 | "utils/*": [ 58 | "./src/utils/*" 59 | ], 60 | "parse/*": [ 61 | "src/parse/*" 62 | ], 63 | "rules/*": [ 64 | "src/rules/*" 65 | ], 66 | "@liquify/ava/esthetic": [ 67 | "./node_modules/@liquify/ava/package/esthetic.d.ts" 68 | ] 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | import * as pkg from './package.json'; 3 | import { join } from 'node:path'; 4 | import { writeFileSync, readFileSync } from 'node:fs'; 5 | 6 | const cwd = process.cwd(); 7 | const pkjson = readFileSync('./node_modules/@liquify/schema/esthetic.json').toString(); 8 | const config = readFileSync('./node_modules/@liquify/schema/esthetic/package-json.json').toString(); 9 | 10 | writeFileSync(join(cwd, 'schema.config.json'), JSON.stringify(pkjson)); 11 | writeFileSync(join(cwd, 'schema.package.json'), JSON.stringify(config)); 12 | 13 | export default defineConfig([ 14 | { 15 | entry: { 16 | esthetic: './src/index.ts' 17 | }, 18 | clean: false, 19 | treeshake: true, 20 | name: 'Æsthetic', 21 | minify: false, 22 | noExternal: [ 23 | 'mergerino' 24 | ], 25 | terserOptions: { 26 | compress: { 27 | passes: 10 28 | } 29 | }, 30 | globalName: 'esthetic', 31 | splitting: false, 32 | platform: 'neutral', 33 | minifyIdentifiers: true, 34 | minifySyntax: true, 35 | define: { 36 | VERSION: `"${pkg.version}"` 37 | }, 38 | esbuildOptions: options => { 39 | options.treeShaking = true; 40 | }, 41 | outExtension ({ format }) { 42 | 43 | if (format === 'cjs') { 44 | return { 45 | js: '.cjs' 46 | }; 47 | } else if (format === 'esm') { 48 | return { 49 | js: '.mjs' 50 | }; 51 | 52 | } else { 53 | return { 54 | js: '.js' 55 | }; 56 | } 57 | }, 58 | format: [ 59 | 'cjs', 60 | 'esm', 61 | 'iife' 62 | ] 63 | }, 64 | { 65 | entry: { 66 | cli: './src/cli.ts' 67 | }, 68 | format: [ 69 | 'cjs', 70 | 'esm' 71 | ], 72 | external: [ 73 | 'chokidar', 74 | 'fast-glob', 75 | './esthetic.cjs' 76 | ], 77 | name: 'Æsthetic', 78 | clean: false, 79 | minify: process.env.production ? 'terser' : false, 80 | define: { 81 | VERSION: `"${pkg.version}"` 82 | }, 83 | treeshake: true, 84 | cjsInterop: true, 85 | shims: true, 86 | bundle: true, 87 | splitting: false, 88 | esbuildOptions: options => { 89 | options.treeShaking = true; 90 | } 91 | } 92 | ]); 93 | -------------------------------------------------------------------------------- /types/hooks.d.ts: -------------------------------------------------------------------------------- 1 | import { ParseHook } from './parse/parser'; 2 | 3 | export declare interface Hooks { 4 | /** 5 | * Parse Hook 6 | * 7 | * Hook into the parse cycle of Æsthetic and optionally augment 8 | * records before insertion into the data structure. The hook will 9 | * be invoked for every token insertion. 10 | * 11 | * **Advanced Usage** 12 | * 13 | * Hooks are for advanced usage of Æsthetic. 14 | */ 15 | (name: 'parse', callback: ParseHook): T; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /types/misc/defintions.d.ts: -------------------------------------------------------------------------------- 1 | import { GlobalRules, JSONRules, LiquidRules, MarkupRules, ScriptRules, StyleRules } from '..'; 2 | 3 | /** 4 | * Option defintion type string Literal 5 | */ 6 | export type DefinitionTypes = 'boolean' | 'array' | 'number' | 'string' | 'choice' 7 | 8 | /** 9 | * Option defintion lexer types 10 | */ 11 | export type DefinitionLexerTypes = 'auto' | 'markup' | 'script' | 'style' 12 | 13 | /** 14 | * Definition Reference 15 | */ 16 | export interface Definition { 17 | /** 18 | * Rules description 19 | */ 20 | description: string; 21 | /** 22 | * The default setting 23 | */ 24 | default: boolean | string[] | string | number; 25 | /** 26 | * Preset default 27 | */ 28 | preset?: { 29 | [K in GlobalRules['preset']]: boolean | string[] | string | number 30 | } 31 | /** 32 | * Types 33 | * 34 | * When multiple types are accepted this will contain the references of each type. 35 | * The property should match the type name 36 | */ 37 | type: DefinitionTypes | DefinitionTypes[] | { 38 | /** 39 | * The rule value 40 | */ 41 | [K in DefinitionTypes]?: string; 42 | 43 | }; 44 | /** 45 | * An optional list of pre-selected rule values. 46 | */ 47 | values?: { 48 | /** 49 | * The rule value 50 | */ 51 | rule: string; 52 | /** 53 | * Rule value description 54 | */ 55 | description: string; 56 | }[] 57 | } 58 | 59 | /** 60 | * Option Definitions 61 | */ 62 | export interface Definitions { 63 | global: { 64 | [K in keyof GlobalRules]: Definition 65 | }; 66 | liquid: { 67 | [K in keyof LiquidRules]: Definition 68 | }; 69 | markup: { 70 | [K in keyof MarkupRules]: Definition 71 | }; 72 | style: { 73 | [K in keyof StyleRules]: Definition 74 | }; 75 | json: { 76 | [K in keyof JSONRules]: Definition 77 | }; 78 | script: { 79 | [K in keyof ScriptRules]: Definition 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /types/misc/specifics.d.ts: -------------------------------------------------------------------------------- 1 | import { Format, Rules } from '..'; 2 | import { Except } from 'type-fest'; 3 | 4 | /** 5 | * Helper Utility for excluding common rules 6 | */ 7 | type Excludes = 'language' | 'indentLevel' | T 8 | 9 | /* -------------------------------------------- */ 10 | /* EXPORTS */ 11 | /* -------------------------------------------- */ 12 | 13 | /** 14 | * Liquid Specifics 15 | * 16 | * Used by the `prettify.liquid()` method 17 | */ 18 | export type LiquidFormat = Format> 19 | 20 | /** 21 | * HTML Specifics 22 | * 23 | * Used by the `prettify.html()` method 24 | */ 25 | export type HTMLFormat = Format>> 26 | 27 | /** 28 | * XML Specifics 29 | * 30 | * Used by the `prettify.xml()` method 31 | */ 32 | export type XMLFormat = Format>> 33 | 34 | /** 35 | * CSS Specifics 36 | * 37 | * Used by the `prettify.css()` method 38 | */ 39 | export type CSSFormat = Format>> 40 | 41 | /** 42 | * SCSS Specifics 43 | * 44 | * Used by the `prettify.scss()` method 45 | */ 46 | export type SCSSFormat = Format>> 47 | 48 | /** 49 | * JSON Specifics 50 | * 51 | * Used by the `prettify.json()` method 52 | */ 53 | export type JSONFormat = Format>> 54 | 55 | /** 56 | * JavaScript Specifics 57 | * 58 | * Used by the `prettify.js()` method 59 | */ 60 | export type JavaScriptFormat = Format>> 61 | 62 | /** 63 | * TypeScript Specifics 64 | * 65 | * Used by the `prettify.ts()` method 66 | */ 67 | export type TypeScriptFormat = Format>> 68 | 69 | /** 70 | * TSX Specifics 71 | * 72 | * Used by the `prettify.tsx()` method 73 | */ 74 | export type TSXFormat = Format>> 75 | 76 | /** 77 | * JSX Specifics 78 | * 79 | * Used by the `prettify.jsx()` method 80 | */ 81 | export type JSXFormat = Format>> 82 | -------------------------------------------------------------------------------- /types/rules/javascript.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/panoply/esthetic/200472302d66a58d5975159b1d940163171db2f5/types/rules/javascript.d.ts --------------------------------------------------------------------------------