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/packages/liquid-html-parser/package.json b/packages/liquid-html-parser/package.json index 6e523db09..ac329fdfc 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.8", "line-column": "^1.0.2", "ohm-js": "^17.0.0" }, 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/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); } }); 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/packages/liquid-html-parser/src/stage-1-cst.ts b/packages/liquid-html-parser/src/stage-1-cst.ts index f28bd0891..1c65cd0e6 100644 --- a/packages/liquid-html-parser/src/stage-1-cst.ts +++ b/packages/liquid-html-parser/src/stage-1-cst.ts @@ -31,8 +31,9 @@ */ import { Parser } from 'prettier'; -import { Grammar, Node } from 'ohm-js'; -import { toAST } from 'ohm-js/extras'; +import { AstBuilder, CstNode as Node, AstMapping as Mapping } from '@ohm-js/wasm'; +import { Grammar } from '@ohm-js/wasm/compat'; + import { LiquidDocGrammar, LiquidGrammars, @@ -508,10 +509,6 @@ export type LiquidDocConcreteNode = | ConcreteLiquidDocDescriptionNode | ConcreteLiquidDocPromptNode; -interface Mapping { - [k: string]: number | TemplateMapping | TopLevelFunctionMapping; -} - interface TemplateMapping { type: ConcreteNodeTypes; locStart: (node: Node[]) => number; @@ -577,12 +574,11 @@ 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, - value: function () { - return (this as any).sourceString; + value: function (this: AstBuilder) { + return this.currNode!.sourceString; }, locStart, locEnd, @@ -591,10 +587,12 @@ 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 = { + const HelperMappings: Mapping = { Node: 0, TextNode: textNode, orderedListOf: 0, @@ -602,14 +600,11 @@ 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)); }, }; - const LiquidMappings: Mapping = { + const LiquidMappings: Mapping = { liquidNode: 0, liquidRawTag: 0, liquidRawTagImpl: { @@ -734,7 +729,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(); }, @@ -753,8 +748,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, @@ -830,7 +825,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(); }, @@ -869,7 +864,7 @@ function toCST( liquidTagCycleMarkup: { type: ConcreteNodeTypes.CycleMarkup, groupName: 0, - args: 3, + args: 2, locStart, locEnd, source, @@ -896,22 +891,13 @@ function toCST( source, }, renderArguments: 1, - completionModeRenderArguments: function ( - _0, - namedArguments, - _2, - _3, - _4, - _5, - 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)); + completionModeRenderArguments: function (_0, namedArguments, _2, _3, opt) { + return this.toAst(namedArguments).concat( + opt.when({ + Some: (_sep, variableLookup, _space) => this.toAst(variableLookup), + None: () => [], + }), + ); }, snippetExpression: 0, renderVariableExpression: { @@ -949,11 +935,9 @@ 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. - locEnd: locEndSecondToLast, + locEnd, source, }, @@ -963,36 +947,35 @@ function toCST( locStart, locEnd, source, - args(nodes: Node[]) { - // Traditinally, this would get transformed into null or array. But + 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. - if (nodes[7].sourceString === '') { - return []; - } else { - return nodes[7].toAST((this as any).args.mapping); - } + return opt.when({ + Some: (_sp1, _colon, _sp2, args, _opt) => this.toAst(args), + None: () => [], + }); }, }, 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), - ); + complexArguments: function (completeParams, opt) { + return this.toAst(completeParams).concat( + opt.when({ + Some: (_space1, _comma, _space2, incompleteParam) => this.toAst(incompleteParam), + None: () => [], + }), + ); }, 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)); + completionModeContentForTagArgument: function (namedArguments, opt) { + return this.toAst(namedArguments).concat( + opt.when({ + Some: (_sep, variableLookup) => this.toAst(variableLookup), + None: () => [], + }), + ); }, positionalArgument: 0, namedArgument: { @@ -1007,19 +990,16 @@ function toCST( contentForNamedArgument: { type: ConcreteNodeTypes.NamedArgument, name: (node) => node[0].sourceString + node[1].sourceString, - value: 6, + value: 5, locStart, locEnd, source, }, + // @ts-ignore 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. @@ -1136,7 +1116,7 @@ function toCST( tagMarkup: (n: Node) => n.sourceString.trim(), }; - const LiquidStatement: Mapping = { + const LiquidStatement: Mapping = { LiquidStatement: 0, liquidTagOpenRule: { type: ConcreteNodeTypes.LiquidTagOpen, @@ -1145,14 +1125,14 @@ 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(); }, whitespaceStart: null, whitespaceEnd: null, locStart, - locEnd: locEndSecondToLast, + locEnd, source, }, @@ -1162,7 +1142,7 @@ function toCST( whitespaceStart: null, whitespaceEnd: null, locStart, - locEnd: locEndSecondToLast, + locEnd, source, }, @@ -1173,14 +1153,14 @@ 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(); }, whitespaceStart: null, whitespaceEnd: null, locStart, - locEnd: locEndSecondToLast, + locEnd, source, }, @@ -1203,7 +1183,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, @@ -1242,8 +1222,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: { @@ -1253,18 +1233,17 @@ function toCST( whitespaceStart: null, whitespaceEnd: null, locStart, - locEnd: locEndSecondToLast, + locEnd, source, }, }; - const LiquidHTMLMappings: Mapping = { + const LiquidHTMLMappings: Mapping = { Node(frontmatter: Node, nodes: Node) { - const self = this as any; - const frontmatterNode = - frontmatter.sourceString.length === 0 ? [] : [frontmatter.toAST(self.args.mapping)]; + const frontmatterNode: T[] = + frontmatter.sourceString.length === 0 ? [] : [this.toAst(frontmatter)]; - return frontmatterNode.concat(nodes.toAST(self.args.mapping)); + return frontmatterNode.concat(this.toAst(nodes)); }, yamlFrontmatter: { @@ -1295,8 +1274,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[]) => { @@ -1322,7 +1300,7 @@ function toCST( HtmlVoidElement: { type: ConcreteNodeTypes.HtmlVoidElement, name: 1, - attrList: 3, + attrList: 2, locStart, locEnd, source, @@ -1359,8 +1337,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 +1399,7 @@ function toCST( }), {}, ); - - return toAST(res, selectedMappings) as T; + return res.use((r) => new AstBuilder(selectedMappings).toAst(r) as T); } /** @@ -1439,7 +1415,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); + }); } /** @@ -1447,22 +1425,19 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) */ const textNode = () => ({ type: ConcreteNodeTypes.TextNode, - value: function () { - return (this as any).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 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, @@ -1483,7 +1458,7 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) source, paramType: 2, paramName: 4, - paramDescription: 8, + paramDescription: 7, }, descriptionNode: { type: ConcreteNodeTypes.LiquidDocDescriptionNode, @@ -1493,8 +1468,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(), @@ -1524,8 +1499,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: { @@ -1541,5 +1516,5 @@ function toLiquidDocAST(source: string, matchingSource: string, offset: number) fallbackNode: textNode(), }; - return toAST(res, LiquidDocMappings); + return res.use((r) => new AstBuilder(LiquidDocMappings).toAst(r)); } diff --git a/tsconfig.json b/tsconfig.json index 7cc798d6d..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": "node", /* 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": [ diff --git a/yarn.lock b/yarn.lock index 826ef7afc..5d78c08ff 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.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" + "@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"