From 4857148e7a66e26c76915a3cf2e374cbd7a520c1 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 18 Nov 2022 01:37:35 -0500 Subject: [PATCH] Add support for `@shopify/prettier-plugin-liquid` --- package-lock.json | 53 ++++++++++++++++++++++++++++++++++++ package.json | 1 + src/index.js | 63 +++++++++++++++++++++++++++++++++++++++++++ tests/plugins.test.js | 17 ++++++++++++ 4 files changed, 134 insertions(+) diff --git a/package-lock.json b/package-lock.json index 5032679..d1c184c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "devDependencies": { "@prettier/plugin-php": "^0.19.2", "@prettier/plugin-pug": "^2.3.0", + "@shopify/prettier-plugin-liquid": "^0.4.0", "@shufo/prettier-plugin-blade": "^1.8.0", "@tailwindcss/line-clamp": "^0.3.0", "@trivago/prettier-plugin-sort-imports": "^3.3.0", @@ -1778,6 +1779,20 @@ "prettier": "^2.3.0" } }, + "node_modules/@shopify/prettier-plugin-liquid": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@shopify/prettier-plugin-liquid/-/prettier-plugin-liquid-0.4.0.tgz", + "integrity": "sha512-pJDTud9alhtCF0ZNDKpREmjvrWSVL60ZJsd1BE1kZ+QWBuuj6MYiVth9edYsupFp3Xa29VqrZ0QaEzgIouOeSg==", + "dev": true, + "dependencies": { + "html-styles": "^1.0.0", + "line-column": "^1.0.2", + "ohm-js": "^16.3.0" + }, + "peerDependencies": { + "prettier": "^2.0.0" + } + }, "node_modules/@shufo/prettier-plugin-blade": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@shufo/prettier-plugin-blade/-/prettier-plugin-blade-1.8.0.tgz", @@ -5490,6 +5505,12 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/html-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/html-styles/-/html-styles-1.0.0.tgz", + "integrity": "sha512-cDl5dcj73oI4Hy0DSUNh54CAwslNLJRCCoO+RNkVo+sBrjA/0+7E/xzvj3zH/GxbbBLGJhE0hBe1eg+0FINC6w==", + "dev": true + }, "node_modules/http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -9538,6 +9559,15 @@ "node": ">=0.10.0" } }, + "node_modules/ohm-js": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/ohm-js/-/ohm-js-16.4.0.tgz", + "integrity": "sha512-u1QI5h2w29I4838+/m32rzqfNNH1Qej9L6O1MTZZMx7bVOu09orc/TO0HRVeYh5jStieZ3INszM7oqbCdx2x7A==", + "dev": true, + "engines": { + "node": ">=0.12.1" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -13880,6 +13910,17 @@ "pug-lexer": "^5.0.0" } }, + "@shopify/prettier-plugin-liquid": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@shopify/prettier-plugin-liquid/-/prettier-plugin-liquid-0.4.0.tgz", + "integrity": "sha512-pJDTud9alhtCF0ZNDKpREmjvrWSVL60ZJsd1BE1kZ+QWBuuj6MYiVth9edYsupFp3Xa29VqrZ0QaEzgIouOeSg==", + "dev": true, + "requires": { + "html-styles": "^1.0.0", + "line-column": "^1.0.2", + "ohm-js": "^16.3.0" + } + }, "@shufo/prettier-plugin-blade": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@shufo/prettier-plugin-blade/-/prettier-plugin-blade-1.8.0.tgz", @@ -16716,6 +16757,12 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "html-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/html-styles/-/html-styles-1.0.0.tgz", + "integrity": "sha512-cDl5dcj73oI4Hy0DSUNh54CAwslNLJRCCoO+RNkVo+sBrjA/0+7E/xzvj3zH/GxbbBLGJhE0hBe1eg+0FINC6w==", + "dev": true + }, "http-proxy-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", @@ -19688,6 +19735,12 @@ } } }, + "ohm-js": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/ohm-js/-/ohm-js-16.4.0.tgz", + "integrity": "sha512-u1QI5h2w29I4838+/m32rzqfNNH1Qej9L6O1MTZZMx7bVOu09orc/TO0HRVeYh5jStieZ3INszM7oqbCdx2x7A==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", diff --git a/package.json b/package.json index 59bdf40..bf33a7b 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "devDependencies": { "@prettier/plugin-php": "^0.19.2", "@prettier/plugin-pug": "^2.3.0", + "@shopify/prettier-plugin-liquid": "^0.4.0", "@shufo/prettier-plugin-blade": "^1.8.0", "@tailwindcss/line-clamp": "^0.3.0", "@trivago/prettier-plugin-sort-imports": "^3.3.0", diff --git a/src/index.js b/src/index.js index 7ffd975..81e0b49 100644 --- a/src/index.js +++ b/src/index.js @@ -345,6 +345,63 @@ function transformGlimmer(ast, { env }) { }) } +function transformLiquid(ast, { env }) { + visit(ast, { + HtmlElement(node) { + node.source = '' + console.log({node}) + }, + + AttrSingleQuoted(node, _parent, _key, _index, meta) { + if (node.name !== "class") { + return; + } + + meta.sortTextNodes = true; + meta.sourceNode = node; + }, + + AttrDoubleQuoted(node, _parent, _key, _index, meta) { + if (node.name !== "class") { + return; + } + + meta.sortTextNodes = true; + + // With Liquid Script it uses the "source" of certain nodes as the "source of truth" + // We must modify that node's source to get the desired output + // Even if we modify the AST it will be ignored + meta.sourceNode = node; + }, + + TextNode(node, _parent, _key, _index, meta) { + if (!meta.sortTextNodes) { + return; + } + + node.value = sortClasses(node.value, { env }); + + // This feels hacky but it's necessary + node.source = node.source.slice(0, node.position.start) + node.value + node.source.slice(node.position.end); + meta.sourceNode.source = node.source; + }, + + String(node, _parent, _key, _index, meta) { + if (!meta.sortTextNodes) { + return; + } + + node.value = sortClasses(node.value, { env }); + + // This feels hacky but it's necessary + // String position includes the quotes even if the value doesn't + // Hence the +1 and -1 when slicing + node.source = node.source.slice(0, node.position.start+1) + node.value + node.source.slice(node.position.end-1); + meta.sourceNode.source = node.source; + }, + }); +} + function sortStringLiteral(node, { env }) { let result = sortClasses(node.value, { env }) let didChange = result !== node.value @@ -500,6 +557,9 @@ export const parsers = { ...base.parsers.php ? { php: createParser('php', transformPHP) } : {}, ...base.parsers.melody ? { melody: createParser('melody', transformMelody) } : {}, ...base.parsers.pug ? { pug: createParser('pug', transformPug) } : {}, + ...(base.parsers['liquid-html'] + ? { 'liquid-html': createParser("liquid-html", transformLiquid) } + : {}), // ...base.parsers.blade ? { blade: createParser('blade', transformBlade) } : {}, } @@ -733,6 +793,7 @@ function getBasePlugins() { let php = loadIfExists('@prettier/plugin-php') let melody = loadIfExists('prettier-plugin-twig-melody') let pug = loadIfExists('@prettier/plugin-pug') + let liquid = loadIfExists('@shopify/prettier-plugin-liquid') // let blade = loadIfExists('@shufo/prettier-plugin-blade') return { @@ -759,6 +820,7 @@ function getBasePlugins() { ...(php?.parsers ?? {}), ...(melody?.parsers ?? {}), ...(pug?.parsers ?? {}), + ...(liquid?.parsers ?? {}), // ...(blade?.parsers ?? {}), }, printers: { @@ -782,6 +844,7 @@ function getCompatibleParser(parserFormat, options) { 'prettier-plugin-organize-imports', '@prettier/plugin-php', '@prettier/plugin-pug', + '@shopify/prettier-plugin-liquid', '@shufo/prettier-plugin-blade', 'prettier-plugin-css-order', 'prettier-plugin-import-sort', diff --git a/tests/plugins.test.js b/tests/plugins.test.js index 48dcc56..576b26b 100644 --- a/tests/plugins.test.js +++ b/tests/plugins.test.js @@ -208,6 +208,23 @@ let tests = [ ], } }, + { + plugins: [ + '@shopify/prettier-plugin-liquid', + ], + tests: { + 'liquid-html': [ + [ + `Example`, + `Example`, + ], + [ + `{% if state == true %}\n Example\n{% endif %}`, + `{% if state == true -%}\n Example\n{%- endif %}`, + ], + ], + } + }, ] for (const group of tests) {