From 9fcf918e61cdb78f7a2e55af64362ad469a92aee Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Thu, 2 Oct 2025 13:00:31 +0200 Subject: [PATCH 01/18] add dependency on Ohm wasm packages --- packages/liquid-html-parser/package.json | 1 + packages/liquid-html-parser/src/grammar.ts | 2 +- yarn.lock | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/liquid-html-parser/package.json b/packages/liquid-html-parser/package.json index 6e523db09..1fd84c2cc 100644 --- a/packages/liquid-html-parser/package.json +++ b/packages/liquid-html-parser/package.json @@ -32,6 +32,7 @@ "type-check": "tsc --noEmit" }, "dependencies": { + "@ohm-js/wasm": "^0.6.2", "line-column": "^1.0.2", "ohm-js": "^17.0.0" }, diff --git a/packages/liquid-html-parser/src/grammar.ts b/packages/liquid-html-parser/src/grammar.ts index 2d91f00fd..e43266c6d 100644 --- a/packages/liquid-html-parser/src/grammar.ts +++ b/packages/liquid-html-parser/src/grammar.ts @@ -1,4 +1,4 @@ -import { grammars, Grammar } from 'ohm-js'; +import { grammars, Grammar } from '@ohm-js/wasm/compat'; export const liquidHtmlGrammars = grammars(require('../grammar/liquid-html.ohm.js')); diff --git a/yarn.lock b/yarn.lock index 826ef7afc..9f8939171 100644 --- a/yarn.lock +++ b/yarn.lock @@ -909,6 +909,13 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@ohm-js/wasm@^0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@ohm-js/wasm/-/wasm-0.6.2.tgz#a1c33a859cb62e2f87541f42a8a729b7a0b9aaa3" + integrity sha512-kWmF4oSa7r0t91xd36pzXPyGi0FQDmBHoTeY/VA2AMStvs+2iyQ1qnN01RjhbIfiza2v0YLXjDfmainCEHuPeA== + dependencies: + "@wasmgroundup/emit" "^1.0.2" + "@playwright/browser-chromium@^1.47.2": version "1.48.0" resolved "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.48.0.tgz#780ca1ebe1aa34dbffa117267c5a84077ed784d0" @@ -1758,6 +1765,11 @@ resolved "https://registry.npmjs.org/@vscode/web-custom-data/-/web-custom-data-0.4.6.tgz" integrity sha512-4zen0CzChZ0cvVqttxe9B+G56M3A0pMoaG6Y9784EN2zvr5n61m6JebfYhJ5rzINbTqePEqmwG+7tsdr5g9BJA== +"@wasmgroundup/emit@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@wasmgroundup/emit/-/emit-1.0.2.tgz#8d428e98468562b745aa584ac259334765c7826b" + integrity sha512-9FupNg9RUOQIBe2zNp0DY78Rb03xeElaL9NQB4haz+JDOF+0Bq4tNSuB/vwG4DFTKSffBKFCa85YdVZaf5vQPw== + "@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.12.1": version "1.14.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6" From 4aa462803d9f3b2b10304ebd1a6b0acb44708c1d Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Tue, 7 Oct 2025 10:33:56 +0200 Subject: [PATCH 02/18] package.json: Change moduleResolution to node16 --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 7cc798d6d..2be1d643e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,7 +26,7 @@ /* Modules */ "module": "commonjs", /* Specify what module code is generated. */ "rootDir": ".", /* Specify the root folder within your source files. */ - "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + "moduleResolution": "node16", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ "paths": { "@shopify/theme-check-common": [ From 0a041435fedad20cd689477ebf8c7f4d2c60df8e Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Mon, 22 Sep 2025 10:24:49 +0200 Subject: [PATCH 03/18] pld: refactor to use AstBuilder --- packages/liquid-html-parser/package.json | 1 + .../liquid-html-parser/src/stage-1-cst.ts | 73 +++++++------------ yarn.lock | 5 ++ 3 files changed, 32 insertions(+), 47 deletions(-) diff --git a/packages/liquid-html-parser/package.json b/packages/liquid-html-parser/package.json index 1fd84c2cc..da913545c 100644 --- a/packages/liquid-html-parser/package.json +++ b/packages/liquid-html-parser/package.json @@ -37,6 +37,7 @@ "ohm-js": "^17.0.0" }, "devDependencies": { + "@ohm-js/miniohm-js": "^0.3.6", "@types/line-column": "^1.0.0" } } diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index f28bd0891..012fb871b 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -32,7 +32,8 @@ import { Parser } from 'prettier'; import { Grammar, Node } from 'ohm-js'; -import { toAST } from 'ohm-js/extras'; +import { AstBuilder } from '@ohm-js/wasm'; + import { LiquidDocGrammar, LiquidGrammars, @@ -602,10 +603,7 @@ function toCST( empty: () => null, nonemptyOrderedListOf: 0, nonemptyOrderedListOfBoth(nonemptyListOfA: Node, _sep: Node, nonemptyListOfB: Node) { - const self = this as any; - return nonemptyListOfA - .toAST(self.args.mapping) - .concat(nonemptyListOfB.toAST(self.args.mapping)); + return this.toAst(nonemptyListOfA).concat(this.toAst(nonemptyListOfB)); }, }; @@ -734,7 +732,7 @@ function toCST( const markupNode = nodes[6]; const nameNode = nodes[3]; if (NamedTags.hasOwnProperty(nameNode.sourceString)) { - return markupNode.toAST((this as any).args.mapping); + return this.toAst(markupNode); } return markupNode.sourceString.trim(); }, @@ -830,7 +828,7 @@ function toCST( const markupNode = nodes[6]; const nameNode = nodes[3]; if (NamedTags.hasOwnProperty(nameNode.sourceString)) { - return markupNode.toAST((this as any).args.mapping); + return this.toAst(markupNode); } return markupNode.sourceString.trim(); }, @@ -906,12 +904,10 @@ function toCST( variableLookup, _7, ) { - const self = this as any; - // variableLookup.sourceString can be '' when there are no incomplete params - return namedArguments - .toAST(self.args.mapping) - .concat(variableLookup.sourceString === '' ? [] : variableLookup.toAST(self.args.mapping)); + return this.toAst(namedArguments).concat( + variableLookup.sourceString === '' ? [] : this.toAst(variableLookup), + ); }, snippetExpression: 0, renderVariableExpression: { @@ -969,30 +965,24 @@ function toCST( if (nodes[7].sourceString === '') { return []; } else { - return nodes[7].toAST((this as any).args.mapping); + return this.toAst(nodes[7]); } }, }, filterArguments: 0, arguments: 0, complexArguments: function (completeParams, _space1, _comma, _space2, incompleteParam) { - const self = this as any; - - return completeParams - .toAST(self.args.mapping) - .concat( - incompleteParam.sourceString === '' ? [] : incompleteParam.toAST(self.args.mapping), - ); + return this.toAst(completeParams).concat( + incompleteParam.sourceString === '' ? [] : this.toAst(incompleteParam), + ); }, simpleArgument: 0, tagArguments: 0, contentForTagArgument: 0, completionModeContentForTagArgument: function (namedArguments, _separator, variableLookup) { - const self = this as any; - - return namedArguments - .toAST(self.args.mapping) - .concat(variableLookup.sourceString === '' ? [] : variableLookup.toAST(self.args.mapping)); + return this.toAst(namedArguments).concat( + variableLookup.sourceString === '' ? [] : this.toAst(variableLookup), + ); }, positionalArgument: 0, namedArgument: { @@ -1014,12 +1004,8 @@ function toCST( }, liquidBooleanExpression(initialCondition: Node, subsequentConditions: Node) { - const initialConditionAst = initialCondition.toAST( - (this as any).args.mapping, - ) as ConcreteLiquidCondition; - const subsequentConditionAsts = subsequentConditions.toAST( - (this as any).args.mapping, - ) as ConcreteLiquidCondition[]; + const initialConditionAst = this.toAst(initialCondition) as ConcreteLiquidCondition; + const subsequentConditionAsts = this.toAst(subsequentConditions) as ConcreteLiquidCondition[]; // liquidBooleanExpression can capture too much. If there are no comparisons (e.g. `==`, `>`, etc.) // and we only have a single condition (i.e. no `and` or `or` operators), we can return the expression directly. @@ -1145,7 +1131,7 @@ function toCST( const markupNode = nodes[2]; const nameNode = nodes[0]; if (NamedTags.hasOwnProperty(nameNode.sourceString)) { - return markupNode.toAST((this as any).args.mapping); + return this.toAst(markupNode); } return markupNode.sourceString.trim(); }, @@ -1173,7 +1159,7 @@ function toCST( const markupNode = nodes[2]; const nameNode = nodes[0]; if (NamedTags.hasOwnProperty(nameNode.sourceString)) { - return markupNode.toAST((this as any).args.mapping); + return this.toAst(markupNode); } return markupNode.sourceString.trim(); }, @@ -1260,11 +1246,10 @@ function toCST( const LiquidHTMLMappings: Mapping = { Node(frontmatter: Node, nodes: Node) { - const self = this as any; const frontmatterNode = - frontmatter.sourceString.length === 0 ? [] : [frontmatter.toAST(self.args.mapping)]; + frontmatter.sourceString.length === 0 ? [] : [this.toAst(frontmatter)]; - return frontmatterNode.concat(nodes.toAST(self.args.mapping)); + return frontmatterNode.concat(this.toAst(nodes)); }, yamlFrontmatter: { @@ -1295,8 +1280,7 @@ function toCST( type: ConcreteNodeTypes.HtmlRawTag, name: (tokens: Node[]) => tokens[0].children[1].sourceString, attrList(tokens: Node[]) { - const mappings = (this as any).args.mapping; - return tokens[0].children[2].toAST(mappings); + return this.toAst(tokens[0].children[2]); }, body: (tokens: Node[]) => source.slice(tokens[0].source.endIdx, tokens[2].source.startIdx), children: (tokens: Node[]) => { @@ -1359,8 +1343,7 @@ function toCST( trailingTagNamePart: 0, trailingTagNameTextNode: textNode, tagName(leadingPart: Node, trailingParts: Node) { - const mappings = (this as any).args.mapping; - return [leadingPart.toAST(mappings)].concat(trailingParts.toAST(mappings)); + return [this.toAst(leadingPart)].concat(this.toAst(trailingParts)); }, AttrUnquoted: { @@ -1422,8 +1405,7 @@ function toCST( }), {}, ); - - return toAST(res, selectedMappings) as T; + return new AstBuilder(selectedMappings).toAst(res) as T; } /** @@ -1457,12 +1439,9 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) const LiquidDocMappings: Mapping = { Node(implicitDescription: Node, body: Node) { - const self = this as any; const implicitDescriptionNode = - implicitDescription.sourceString.length === 0 - ? [] - : [implicitDescription.toAST(self.args.mapping)]; - return implicitDescriptionNode.concat(body.toAST(self.args.mapping)); + implicitDescription.sourceString.length === 0 ? [] : [this.toAst(implicitDescription)]; + return implicitDescriptionNode.concat(this.toAst(body)); }, ImplicitDescription: { type: ConcreteNodeTypes.LiquidDocDescriptionNode, diff --git a/yarn.lock b/yarn.lock index 9f8939171..aa7bb93dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -909,6 +909,11 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@ohm-js/miniohm-js@^0.3.6": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@ohm-js/miniohm-js/-/miniohm-js-0.3.6.tgz#d6bafe987db7e1963e703ab9040ae3af474883f4" + integrity sha512-GWsbhyRdKxxhM2MG8z40/dgQe0w3rZCOdzHXJVfTpUxN1k0gFy+dNyJWtVr9XCZfXQ+p0EV/0HkN48pmQo0xVg== + "@ohm-js/wasm@^0.6.2": version "0.6.2" resolved "https://registry.yarnpkg.com/@ohm-js/wasm/-/wasm-0.6.2.tgz#a1c33a859cb62e2f87541f42a8a729b7a0b9aaa3" From 22537b1e44e468b8c9e08806d49a470b55544a9f Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Mon, 22 Sep 2025 19:45:47 +0200 Subject: [PATCH 04/18] pld: fix some issues due to different Cst format --- packages/liquid-html-parser/package.json | 1 + packages/liquid-html-parser/src/stage-1-cst.ts | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/liquid-html-parser/package.json b/packages/liquid-html-parser/package.json index da913545c..044a4d1d3 100644 --- a/packages/liquid-html-parser/package.json +++ b/packages/liquid-html-parser/package.json @@ -38,6 +38,7 @@ }, "devDependencies": { "@ohm-js/miniohm-js": "^0.3.6", + "@ohm-js/wasm": "^0.3.3", "@types/line-column": "^1.0.0" } } diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 012fb871b..e132132ca 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -945,7 +945,7 @@ function toCST( expression: 0, filters: 1, rawSource: (tokens: Node[]) => - source.slice(locStart(tokens), tokens[tokens.length - 2].source.endIdx).trimEnd(), + source.slice(locStart(tokens), tokens[tokens.length - 1].source.endIdx).trimEnd(), locStart, // The last node of this rule is a positive lookahead, we don't // want its endIdx, we want the endIdx of the previous one. @@ -960,13 +960,13 @@ function toCST( locEnd, source, args(nodes: Node[]) { - // Traditinally, this would get transformed into null or array. But - // it's better if we have an empty array instead of null here. - if (nodes[7].sourceString === '') { + if (nodes[4].sourceString === '') { + // Traditionally, this would get transformed into null or array. But + // it's better if we have an empty array instead of null here. return []; - } else { - return this.toAst(nodes[7]); } + const argumentsNode = nodes[4].children[3]; + return this.toAst(argumentsNode); }, }, filterArguments: 0, From f7de78f959a8a31243208c63c278fc90160d5ba9 Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Tue, 23 Sep 2025 19:38:33 +0200 Subject: [PATCH 05/18] pld: fix some issues due to diff't arity of iter nodes --- packages/liquid-html-parser/package.json | 2 +- packages/liquid-html-parser/src/stage-1-cst.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/liquid-html-parser/package.json b/packages/liquid-html-parser/package.json index 044a4d1d3..e40ba5220 100644 --- a/packages/liquid-html-parser/package.json +++ b/packages/liquid-html-parser/package.json @@ -37,7 +37,7 @@ "ohm-js": "^17.0.0" }, "devDependencies": { - "@ohm-js/miniohm-js": "^0.3.6", + "@ohm-js/miniohm-js": "^0.3.7", "@ohm-js/wasm": "^0.3.3", "@types/line-column": "^1.0.0" } diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index e132132ca..5e42c5b02 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -867,7 +867,7 @@ function toCST( liquidTagCycleMarkup: { type: ConcreteNodeTypes.CycleMarkup, groupName: 0, - args: 3, + args: 2, locStart, locEnd, source, @@ -997,7 +997,7 @@ function toCST( contentForNamedArgument: { type: ConcreteNodeTypes.NamedArgument, name: (node) => node[0].sourceString + node[1].sourceString, - value: 6, + value: 5, locStart, locEnd, source, @@ -1228,8 +1228,8 @@ function toCST( source, blockStartLocStart: (tokens: Node[]) => offset + tokens[0].source.startIdx, blockStartLocEnd: (tokens: Node[]) => offset + tokens[0].source.endIdx, - blockEndLocStart: (tokens: Node[]) => offset + tokens[4].source.startIdx, - blockEndLocEnd: (tokens: Node[]) => offset + tokens[4].source.endIdx, + blockEndLocStart: (tokens: Node[]) => offset + tokens[3].source.startIdx, + blockEndLocEnd: (tokens: Node[]) => offset + tokens[3].source.endIdx, }, liquidInlineComment: { From 970c3279b08e61d7fb7f7ea487d7aa86705fcdcd Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Wed, 24 Sep 2025 12:02:16 +0200 Subject: [PATCH 06/18] pld: fix more issues --- packages/liquid-html-parser/package.json | 2 -- packages/liquid-html-parser/src/stage-1-cst.ts | 4 ++-- yarn.lock | 5 ----- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/liquid-html-parser/package.json b/packages/liquid-html-parser/package.json index e40ba5220..1fd84c2cc 100644 --- a/packages/liquid-html-parser/package.json +++ b/packages/liquid-html-parser/package.json @@ -37,8 +37,6 @@ "ohm-js": "^17.0.0" }, "devDependencies": { - "@ohm-js/miniohm-js": "^0.3.7", - "@ohm-js/wasm": "^0.3.3", "@types/line-column": "^1.0.0" } } diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 5e42c5b02..46f104acf 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -583,7 +583,7 @@ function toCST( const textNode = { type: ConcreteNodeTypes.TextNode, value: function () { - return (this as any).sourceString; + return this.currNode.sourceString; }, locStart, locEnd, @@ -1430,7 +1430,7 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) const textNode = () => ({ type: ConcreteNodeTypes.TextNode, value: function () { - return (this as any).sourceString; + return this.currNode.sourceString; }, locStart, locEnd, diff --git a/yarn.lock b/yarn.lock index aa7bb93dc..9f8939171 100644 --- a/yarn.lock +++ b/yarn.lock @@ -909,11 +909,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@ohm-js/miniohm-js@^0.3.6": - version "0.3.6" - resolved "https://registry.yarnpkg.com/@ohm-js/miniohm-js/-/miniohm-js-0.3.6.tgz#d6bafe987db7e1963e703ab9040ae3af474883f4" - integrity sha512-GWsbhyRdKxxhM2MG8z40/dgQe0w3rZCOdzHXJVfTpUxN1k0gFy+dNyJWtVr9XCZfXQ+p0EV/0HkN48pmQo0xVg== - "@ohm-js/wasm@^0.6.2": version "0.6.2" resolved "https://registry.yarnpkg.com/@ohm-js/wasm/-/wasm-0.6.2.tgz#a1c33a859cb62e2f87541f42a8a729b7a0b9aaa3" From f24ea44405be3890452c2c8b6e2af1d348a391a5 Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Thu, 25 Sep 2025 16:59:40 +0200 Subject: [PATCH 07/18] pld: get rid of locEndSecondToLast (lookahead no longer binds) --- packages/liquid-html-parser/src/stage-1-cst.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 46f104acf..2aa739871 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -578,7 +578,6 @@ function toCST( // for the offset of the {% liquid %} markup const locStart = (tokens: Node[]) => offset + tokens[0].source.startIdx; const locEnd = (tokens: Node[]) => offset + tokens[tokens.length - 1].source.endIdx; - const locEndSecondToLast = (tokens: Node[]) => offset + tokens[tokens.length - 2].source.endIdx; const textNode = { type: ConcreteNodeTypes.TextNode, @@ -947,9 +946,7 @@ function toCST( rawSource: (tokens: Node[]) => source.slice(locStart(tokens), tokens[tokens.length - 1].source.endIdx).trimEnd(), locStart, - // The last node of this rule is a positive lookahead, we don't - // want its endIdx, we want the endIdx of the previous one. - locEnd: locEndSecondToLast, + locEnd, source, }, @@ -1138,7 +1135,7 @@ function toCST( whitespaceStart: null, whitespaceEnd: null, locStart, - locEnd: locEndSecondToLast, + locEnd, source, }, @@ -1148,7 +1145,7 @@ function toCST( whitespaceStart: null, whitespaceEnd: null, locStart, - locEnd: locEndSecondToLast, + locEnd, source, }, @@ -1166,7 +1163,7 @@ function toCST( whitespaceStart: null, whitespaceEnd: null, locStart, - locEnd: locEndSecondToLast, + locEnd, source, }, @@ -1189,7 +1186,7 @@ function toCST( delimiterWhitespaceStart: null, delimiterWhitespaceEnd: null, locStart, - locEnd: locEndSecondToLast, + locEnd, source, blockStartLocStart: (tokens: Node[]) => offset + tokens[0].source.startIdx, blockStartLocEnd: (tokens: Node[]) => offset + tokens[2].source.endIdx, @@ -1239,7 +1236,7 @@ function toCST( whitespaceStart: null, whitespaceEnd: null, locStart, - locEnd: locEndSecondToLast, + locEnd, source, }, }; From df1a06ac315272e52aad2e4a5515ac27b2e6e8fa Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Fri, 26 Sep 2025 16:02:29 +0200 Subject: [PATCH 08/18] pld: more fixes due to arity changes --- packages/liquid-html-parser/src/stage-1-cst.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 2aa739871..2f44b4f77 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -750,8 +750,8 @@ function toCST( type: ConcreteNodeTypes.ForMarkup, variableName: 0, collection: 4, - reversed: 6, - args: 8, + reversed: (children: Node[]) => children[5].children[1]?.sourceString ?? null, + args: 7, locStart, locEnd, source, @@ -1459,7 +1459,7 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) source, paramType: 2, paramName: 4, - paramDescription: 8, + paramDescription: 7, }, descriptionNode: { type: ConcreteNodeTypes.LiquidDocDescriptionNode, From 6db5d74d92829cad7f27be1d884ab929bf383059 Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Fri, 26 Sep 2025 16:09:20 +0200 Subject: [PATCH 09/18] fix: access of `this` --- packages/liquid-html-parser/src/stage-1-cst.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 2f44b4f77..0f7607b3e 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -1469,8 +1469,8 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) source, content: 2, isImplicit: false, - isInline: function (this: Node) { - return !this.children[1].sourceString.includes('\n'); + isInline: function (children) { + return !children[1].sourceString.includes('\n'); }, }, descriptionContent: textNode(), @@ -1500,8 +1500,8 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) locEnd, source, content: 2, - isInline: function (this: Node) { - return !this.children[1].sourceString.includes('\n'); + isInline: function (children) { + return !children[1].sourceString.includes('\n'); }, }, promptNode: { From 90343708cef6e4830d4d6cec0e1a8c538f0a281c Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Fri, 26 Sep 2025 16:54:25 +0200 Subject: [PATCH 10/18] pld: fix up one more arity issue --- packages/liquid-html-parser/src/stage-1-cst.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 0f7607b3e..a8b6e735c 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -1303,7 +1303,7 @@ function toCST( HtmlVoidElement: { type: ConcreteNodeTypes.HtmlVoidElement, name: 1, - attrList: 3, + attrList: 2, locStart, locEnd, source, From 6d476b97a22de7273f1c929729b00cdd51775234 Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Mon, 29 Sep 2025 11:22:28 +0200 Subject: [PATCH 11/18] pld: make sure MatchResults are properly used() --- packages/liquid-html-parser/src/stage-1-cst.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index a8b6e735c..016434e0b 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -591,7 +591,9 @@ function toCST( const res = grammar.match(matchingSource, 'Node'); if (res.failed()) { - throw new LiquidHTMLCSTParsingError(res); + res.use(r => { + throw new LiquidHTMLCSTParsingError(r); + }); } const HelperMappings: Mapping = { @@ -1402,7 +1404,7 @@ function toCST( }), {}, ); - return new AstBuilder(selectedMappings).toAst(res) as T; + return res.use(r => new AstBuilder(selectedMappings).toAst(r) as T); } /** @@ -1418,7 +1420,9 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) const res = LiquidDocGrammar.match(matchingSource, 'Node'); if (res.failed()) { - throw new LiquidHTMLCSTParsingError(res); + res.use(r => { + throw new LiquidHTMLCSTParsingError(r); + }); } /** @@ -1517,5 +1521,5 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) fallbackNode: textNode(), }; - return toAST(res, LiquidDocMappings); + return res.use(r => new AstBuilder(LiquidDocMappings).toAst(r)); } From 5dd086fc3be6b5cec3b2b9147490d7156eefec88 Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Wed, 8 Oct 2025 16:22:13 +0200 Subject: [PATCH 12/18] upgrade to latest version of @ohm-js/wasm --- packages/liquid-html-parser/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/liquid-html-parser/package.json b/packages/liquid-html-parser/package.json index 1fd84c2cc..c5e4ed8e0 100644 --- a/packages/liquid-html-parser/package.json +++ b/packages/liquid-html-parser/package.json @@ -32,7 +32,7 @@ "type-check": "tsc --noEmit" }, "dependencies": { - "@ohm-js/wasm": "^0.6.2", + "@ohm-js/wasm": "^0.6.5", "line-column": "^1.0.2", "ohm-js": "^17.0.0" }, diff --git a/yarn.lock b/yarn.lock index 9f8939171..813fb0040 100644 --- a/yarn.lock +++ b/yarn.lock @@ -909,10 +909,10 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@ohm-js/wasm@^0.6.2": - version "0.6.2" - resolved "https://registry.yarnpkg.com/@ohm-js/wasm/-/wasm-0.6.2.tgz#a1c33a859cb62e2f87541f42a8a729b7a0b9aaa3" - integrity sha512-kWmF4oSa7r0t91xd36pzXPyGi0FQDmBHoTeY/VA2AMStvs+2iyQ1qnN01RjhbIfiza2v0YLXjDfmainCEHuPeA== +"@ohm-js/wasm@^0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@ohm-js/wasm/-/wasm-0.6.5.tgz#9b924ca390f31cc6114e281fbc61a2667022ed6e" + integrity sha512-9V9UGFti7sMnUN5jjbGYW2Mqq8qsMYZnGRL3u4xvv18TQkQpAF9RTY5oovFEHPn1XweYjPmBKCvoPxbfZ5k5Ug== dependencies: "@wasmgroundup/emit" "^1.0.2" From 51fae52637df15a6be4d6fd90a735665020e9a9c Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Wed, 8 Oct 2025 16:23:40 +0200 Subject: [PATCH 13/18] update imports --- packages/liquid-html-parser/src/errors.ts | 2 +- packages/liquid-html-parser/src/stage-1-cst.ts | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/liquid-html-parser/src/errors.ts b/packages/liquid-html-parser/src/errors.ts index 254604455..5b4d67d2e 100644 --- a/packages/liquid-html-parser/src/errors.ts +++ b/packages/liquid-html-parser/src/errors.ts @@ -1,5 +1,5 @@ import lineColumn from 'line-column'; -import { MatchResult } from 'ohm-js'; +import { MatchResult } from '@ohm-js/wasm'; import { NodeTypes, Position } from './types'; interface LineColPosition { diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 016434e0b..887f52d0f 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -31,8 +31,8 @@ */ import { Parser } from 'prettier'; -import { Grammar, Node } from 'ohm-js'; -import { AstBuilder } from '@ohm-js/wasm'; +import { AstBuilder, CstNode as Node, AstMapping as Mapping } from '@ohm-js/wasm'; +import { Grammar } from '@ohm-js/wasm/compat'; import { LiquidDocGrammar, @@ -509,10 +509,6 @@ export type LiquidDocConcreteNode = | ConcreteLiquidDocDescriptionNode | ConcreteLiquidDocPromptNode; -interface Mapping { - [k: string]: number | TemplateMapping | TopLevelFunctionMapping; -} - interface TemplateMapping { type: ConcreteNodeTypes; locStart: (node: Node[]) => number; From 4cca53e8455a3922cac8387a7a4948e39cfa6522 Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Wed, 8 Oct 2025 16:29:51 +0200 Subject: [PATCH 14/18] fix types --- .../liquid-html-parser/src/stage-1-cst.ts | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 887f52d0f..9c8ccadfa 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -577,8 +577,8 @@ function toCST( const textNode = { type: ConcreteNodeTypes.TextNode, - value: function () { - return this.currNode.sourceString; + value: function (this: AstBuilder) { + return this.currNode!.sourceString; }, locStart, locEnd, @@ -587,12 +587,12 @@ function toCST( const res = grammar.match(matchingSource, 'Node'); if (res.failed()) { - res.use(r => { + res.use((r) => { throw new LiquidHTMLCSTParsingError(r); }); } - const HelperMappings: Mapping = { + const HelperMappings: Mapping = { Node: 0, TextNode: textNode, orderedListOf: 0, @@ -604,7 +604,7 @@ function toCST( }, }; - const LiquidMappings: Mapping = { + const LiquidMappings: Mapping = { liquidNode: 0, liquidRawTag: 0, liquidRawTagImpl: { @@ -1117,7 +1117,7 @@ function toCST( tagMarkup: (n: Node) => n.sourceString.trim(), }; - const LiquidStatement: Mapping = { + const LiquidStatement: Mapping = { LiquidStatement: 0, liquidTagOpenRule: { type: ConcreteNodeTypes.LiquidTagOpen, @@ -1239,9 +1239,9 @@ function toCST( }, }; - const LiquidHTMLMappings: Mapping = { + const LiquidHTMLMappings: Mapping = { Node(frontmatter: Node, nodes: Node) { - const frontmatterNode = + const frontmatterNode: T[] = frontmatter.sourceString.length === 0 ? [] : [this.toAst(frontmatter)]; return frontmatterNode.concat(this.toAst(nodes)); @@ -1400,7 +1400,7 @@ function toCST( }), {}, ); - return res.use(r => new AstBuilder(selectedMappings).toAst(r) as T); + return res.use((r) => new AstBuilder(selectedMappings).toAst(r) as T); } /** @@ -1416,7 +1416,7 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) const res = LiquidDocGrammar.match(matchingSource, 'Node'); if (res.failed()) { - res.use(r => { + res.use((r) => { throw new LiquidHTMLCSTParsingError(r); }); } @@ -1426,15 +1426,15 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) */ const textNode = () => ({ type: ConcreteNodeTypes.TextNode, - value: function () { - return this.currNode.sourceString; + value: function (this: AstBuilder): string { + return this.currNode!.sourceString; }, locStart, locEnd, source, }); - const LiquidDocMappings: Mapping = { + const LiquidDocMappings: Mapping = { Node(implicitDescription: Node, body: Node) { const implicitDescriptionNode = implicitDescription.sourceString.length === 0 ? [] : [this.toAst(implicitDescription)]; @@ -1517,5 +1517,5 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) fallbackNode: textNode(), }; - return res.use(r => new AstBuilder(LiquidDocMappings).toAst(r)); + return res.use((r) => new AstBuilder(LiquidDocMappings).toAst(r)); } From d96801f72760bc887e2262dda4f9ca4b1b5a6eb3 Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Wed, 8 Oct 2025 16:30:01 +0200 Subject: [PATCH 15/18] FIXME: ts-ignore last type error --- packages/liquid-html-parser/src/stage-1-cst.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 9c8ccadfa..07690ec58 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -998,6 +998,7 @@ function toCST( source, }, + // @ts-ignore liquidBooleanExpression(initialCondition: Node, subsequentConditions: Node) { const initialConditionAst = this.toAst(initialCondition) as ConcreteLiquidCondition; const subsequentConditionAsts = this.toAst(subsequentConditions) as ConcreteLiquidCondition[]; From 27dce6d54abd7975c6747ffd326c216d9daf71ae Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Wed, 8 Oct 2025 16:34:38 +0200 Subject: [PATCH 16/18] fix up build issues due to pure-ESM package --- packages/codemirror-language-client/tsconfig.json | 2 +- packages/lang-jsonc/tsconfig.json | 2 +- tsconfig.json | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/codemirror-language-client/tsconfig.json b/packages/codemirror-language-client/tsconfig.json index 48524f58b..d064ecbf8 100644 --- a/packages/codemirror-language-client/tsconfig.json +++ b/packages/codemirror-language-client/tsconfig.json @@ -6,6 +6,7 @@ "outDir": "./dist/esm", "tsBuildInfoFile": "./dist/esm/tsconfig.tsbuildInfo", "module": "es6", + "moduleResolution": "node", "rootDir": "src", "resolveJsonModule": false, "lib": [ @@ -15,4 +16,3 @@ ] } } - diff --git a/packages/lang-jsonc/tsconfig.json b/packages/lang-jsonc/tsconfig.json index 48524f58b..d064ecbf8 100644 --- a/packages/lang-jsonc/tsconfig.json +++ b/packages/lang-jsonc/tsconfig.json @@ -6,6 +6,7 @@ "outDir": "./dist/esm", "tsBuildInfoFile": "./dist/esm/tsconfig.tsbuildInfo", "module": "es6", + "moduleResolution": "node", "rootDir": "src", "resolveJsonModule": false, "lib": [ @@ -15,4 +16,3 @@ ] } } - diff --git a/tsconfig.json b/tsconfig.json index 2be1d643e..c17ef1956 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,9 +9,9 @@ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2019", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ "lib": [ - "es2019" + "es2020" ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ @@ -24,9 +24,9 @@ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "node20", /* Specify what module code is generated. */ "rootDir": ".", /* Specify the root folder within your source files. */ - "moduleResolution": "node16", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "moduleResolution": "", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ "paths": { "@shopify/theme-check-common": [ From a99d8b8a476f1819ac046a473511117cf490b33f Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Wed, 8 Oct 2025 20:13:51 +0200 Subject: [PATCH 17/18] Use' using' to ensure MatchResults are properly disposed --- packages/liquid-html-parser/src/grammar.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/liquid-html-parser/src/grammar.spec.ts b/packages/liquid-html-parser/src/grammar.spec.ts index 01e08a8d0..0cb27eafb 100644 --- a/packages/liquid-html-parser/src/grammar.spec.ts +++ b/packages/liquid-html-parser/src/grammar.spec.ts @@ -101,7 +101,7 @@ describe('Unit: liquidHtmlGrammar', () => { expectMatchSucceeded('<6h>').to.be.false; function expectMatchSucceeded(text: string) { - const match = grammar.LiquidHTML.match(text, 'Node'); + using match = grammar.LiquidHTML.match(text, 'Node'); return expect(match.succeeded(), text); } }); @@ -129,7 +129,7 @@ describe('Unit: liquidHtmlGrammar', () => { `).to.be.true; function expectMatchSucceeded(text: string) { - const match = grammar.LiquidStatement.match(text.trimStart(), 'Node'); + using match = grammar.LiquidStatement.match(text.trimStart(), 'Node'); return expect(match.succeeded(), text); } }); @@ -156,7 +156,7 @@ describe('Unit: liquidHtmlGrammar', () => { }); function expectMatchSucceeded(text: string) { - const match = placeholderGrammars.LiquidHTML.match(text.trimStart(), 'Node'); + using match = placeholderGrammars.LiquidHTML.match(text.trimStart(), 'Node'); return expect(match.succeeded(), text); } }); From b9def04b142fc103240c626bb6579f714fd2f255 Mon Sep 17 00:00:00 2001 From: Patrick Dubroy Date: Thu, 9 Oct 2025 11:31:40 +0200 Subject: [PATCH 18/18] use `when` for proper handling of Opt nodes --- packages/liquid-html-parser/package.json | 2 +- .../liquid-html-parser/src/stage-1-cst.ts | 46 +++++++++---------- yarn.lock | 8 ++-- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/packages/liquid-html-parser/package.json b/packages/liquid-html-parser/package.json index c5e4ed8e0..ac329fdfc 100644 --- a/packages/liquid-html-parser/package.json +++ b/packages/liquid-html-parser/package.json @@ -32,7 +32,7 @@ "type-check": "tsc --noEmit" }, "dependencies": { - "@ohm-js/wasm": "^0.6.5", + "@ohm-js/wasm": "^0.6.8", "line-column": "^1.0.2", "ohm-js": "^17.0.0" }, diff --git a/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index 07690ec58..1c65cd0e6 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -891,19 +891,12 @@ function toCST( source, }, renderArguments: 1, - completionModeRenderArguments: function ( - _0, - namedArguments, - _2, - _3, - _4, - _5, - variableLookup, - _7, - ) { - // variableLookup.sourceString can be '' when there are no incomplete params + completionModeRenderArguments: function (_0, namedArguments, _2, _3, opt) { return this.toAst(namedArguments).concat( - variableLookup.sourceString === '' ? [] : this.toAst(variableLookup), + opt.when({ + Some: (_sep, variableLookup, _space) => this.toAst(variableLookup), + None: () => [], + }), ); }, snippetExpression: 0, @@ -954,29 +947,34 @@ function toCST( locStart, locEnd, source, - args(nodes: Node[]) { - if (nodes[4].sourceString === '') { - // Traditionally, this would get transformed into null or array. But - // it's better if we have an empty array instead of null here. - return []; - } - const argumentsNode = nodes[4].children[3]; - return this.toAst(argumentsNode); + args([_sp1, _bar, _sp2, ident, opt]: Node[]) { + // Traditionally, this would get transformed into null or array. But + // it's better if we have an empty array instead of null here. + return opt.when({ + Some: (_sp1, _colon, _sp2, args, _opt) => this.toAst(args), + None: () => [], + }); }, }, filterArguments: 0, arguments: 0, - complexArguments: function (completeParams, _space1, _comma, _space2, incompleteParam) { + complexArguments: function (completeParams, opt) { return this.toAst(completeParams).concat( - incompleteParam.sourceString === '' ? [] : this.toAst(incompleteParam), + opt.when({ + Some: (_space1, _comma, _space2, incompleteParam) => this.toAst(incompleteParam), + None: () => [], + }), ); }, simpleArgument: 0, tagArguments: 0, contentForTagArgument: 0, - completionModeContentForTagArgument: function (namedArguments, _separator, variableLookup) { + completionModeContentForTagArgument: function (namedArguments, opt) { return this.toAst(namedArguments).concat( - variableLookup.sourceString === '' ? [] : this.toAst(variableLookup), + opt.when({ + Some: (_sep, variableLookup) => this.toAst(variableLookup), + None: () => [], + }), ); }, positionalArgument: 0, diff --git a/yarn.lock b/yarn.lock index 813fb0040..5d78c08ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -909,10 +909,10 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@ohm-js/wasm@^0.6.5": - version "0.6.5" - resolved "https://registry.yarnpkg.com/@ohm-js/wasm/-/wasm-0.6.5.tgz#9b924ca390f31cc6114e281fbc61a2667022ed6e" - integrity sha512-9V9UGFti7sMnUN5jjbGYW2Mqq8qsMYZnGRL3u4xvv18TQkQpAF9RTY5oovFEHPn1XweYjPmBKCvoPxbfZ5k5Ug== +"@ohm-js/wasm@^0.6.8": + version "0.6.8" + resolved "https://registry.yarnpkg.com/@ohm-js/wasm/-/wasm-0.6.8.tgz#9436eccee089dcfc4dd79bb493905abd4e7f96df" + integrity sha512-Z8zXCT8A9lTcMgTvLKjx2ZxDL67esf+9P0ymXWoCIBgIEtTswoluW4g/edjXE4WnjhTTQDbPc+bP7IXLgYfefg== dependencies: "@wasmgroundup/emit" "^1.0.2"