diff --git a/.changeset/htmljs-parser-5-18.md b/.changeset/htmljs-parser-5-18.md new file mode 100644 index 00000000..34a7e6df --- /dev/null +++ b/.changeset/htmljs-parser-5-18.md @@ -0,0 +1,6 @@ +--- +"@marko/language-tools": patch +"@marko/language-server": patch +--- + +Require htmljs-parser 5.18.0, which ends a type at a trailing `void`, reads a TypeScript `!` after an operand as a non-null assertion, reads `delete` as an operator, and reads types in scriptlets, so templates using them are no longer misparsed. diff --git a/.changeset/postfix-bang-type-void-highlighting.md b/.changeset/postfix-bang-type-void-highlighting.md new file mode 100644 index 00000000..9b39e582 --- /dev/null +++ b/.changeset/postfix-bang-type-void-highlighting.md @@ -0,0 +1,5 @@ +--- +"marko-vscode": patch +--- + +Highlight attribute values the way the parser now reads them: a `!` directly after an operand (`x!`, `f()!`, `x!!`, `"s"!`) is a non-null assertion that ends the value, `void` in a tag variable's type no longer runs on into the next attribute, and `delete x` stays one value. diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 0baee187..62cd6c59 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -47,7 +47,7 @@ "@marko/compiler": "^5.42.8", "@marko/language-tools": "^2.7.0", "axe-core": "^4.12.1", - "htmljs-parser": "^5.17.1", + "htmljs-parser": "^5.18.0", "jsdom": "^29.1.1", "marko": "^5.39.43", "prettier": "^3.8.4", diff --git a/packages/language-tools/package.json b/packages/language-tools/package.json index a6132ac5..2e8f2040 100644 --- a/packages/language-tools/package.json +++ b/packages/language-tools/package.json @@ -39,7 +39,7 @@ "dependencies": { "@luxass/strip-json-comments": "^1.4.0", "@marko/compiler": "^5.42.8", - "htmljs-parser": "^5.17.1", + "htmljs-parser": "^5.18.0", "relative-import-path": "^1.0.1" }, "devDependencies": { diff --git a/packages/vscode/syntaxes/marko.tmLanguage.json b/packages/vscode/syntaxes/marko.tmLanguage.json index c2c5df0c..549f697d 100644 --- a/packages/vscode/syntaxes/marko.tmLanguage.json +++ b/packages/vscode/syntaxes/marko.tmLanguage.json @@ -110,7 +110,7 @@ "name": "meta.marko-spread-attribute", "contentName": "source.ts", "begin": "(\\.\\.\\.)", - "end": "(?=[,;\\]]|/>|(?<=[^=>])(?:(?|>(?!=))|(?+=-]=|[=>]>|[^.]\\.|[^-]-|[^+]\\+|[a-zA-Z0-9%).<\\]}]\\s/|[^.$\\w]await|[^.$\\w]async|[^.$\\w]class|[^.$\\w]function|[^.$\\w]keyof|[^.$\\w]new|[^.$\\w]readonly|[^.$\\w]infer|[^.$\\w]typeof|[^.$\\w]void)\\s+(?![\\n{(+!~*%&^|?:]|[<>/=-]=|[=>]>|\\.[^.]|-[^-]|/[^>]|(?:in|instanceof|satisfies|as|extends)\\s+[^:=/,;>]))", + "end": "(?=[,;\\]]|/>|(?<=[^=>])(?:(?|>(?!=))|(?+=-]=|[=>]>|[^.]\\.|[^-]-|[^+]\\+|[a-zA-Z0-9%).<\\]}]\\s/|[^.$\\w]await|[^.$\\w]async|[^.$\\w]class|[^.$\\w]function|[^.$\\w]keyof|[^.$\\w]new|[^.$\\w]readonly|[^.$\\w]infer|[^.$\\w]typeof|[^.$\\w]void|[^.$\\w]delete)\\s+(?![\\n{(+!~*%&^|?:]|[<>/=-]=|[=>]>|\\.[^.]|-[^-]|/[^>]|(?:in|instanceof|satisfies|as|extends)\\s+[^:=/,;>]))", "patterns": [{ "include": "#javascript-expression" }], "beginCaptures": { "1": { "name": "keyword.operator.spread.marko" } } }, @@ -128,7 +128,7 @@ "name": "meta.embedded.ts", "contentName": "source.ts", "begin": "\\s*(:?=)\\s*", - "end": "(?=[,;\\]]|/>|(?<=[^=>])(?:(?|>(?!=))|(?+=-]=|[=>]>|[^.]\\.|[^-]-|[^+]\\+|[a-zA-Z0-9%).<\\]}]\\s/|[^.$\\w]await|[^.$\\w]async|[^.$\\w]class|[^.$\\w]function|[^.$\\w]keyof|[^.$\\w]new|[^.$\\w]readonly|[^.$\\w]infer|[^.$\\w]typeof|[^.$\\w]void)\\s+(?![\\n{(+!~*%&^|?:]|[<>/=-]=|[=>]>|\\.[^.]|-[^-]|/[^>]|(?:in|instanceof|satisfies|as|extends)\\s+[^:=/,;>]))", + "end": "(?=[,;\\]]|/>|(?<=[^=>])(?:(?|>(?!=))|(?+=-]=|[=>]>|[^.]\\.|[^-]-|[^+]\\+|[a-zA-Z0-9%).<\\]}]\\s/|[^.$\\w]await|[^.$\\w]async|[^.$\\w]class|[^.$\\w]function|[^.$\\w]keyof|[^.$\\w]new|[^.$\\w]readonly|[^.$\\w]infer|[^.$\\w]typeof|[^.$\\w]void|[^.$\\w]delete)\\s+(?![\\n{(+!~*%&^|?:]|[<>/=-]=|[=>]>|\\.[^.]|-[^-]|/[^>]|(?:in|instanceof|satisfies|as|extends)\\s+[^:=/,;>]))", "patterns": [{ "include": "#javascript-expression" }], "beginCaptures": { "1": { "patterns": [{ "include": "source.ts" }] } } }, @@ -643,7 +643,7 @@ { "comment": "We must match the some expressions ourselves since otherwise the js grammar can overstep.", "contentName": "source.ts", - "match": "(?:\\s*\\b(?:as|await|extends|in|instanceof|satisfies|keyof|new|typeof|void))+\\s+(?![:=/,;>])[a-zA-Z0-9_$@#]*", + "match": "(?:\\s*\\b(?:as|await|delete|extends|in|instanceof|satisfies|keyof|new|typeof|void))+\\s+(?![:=/,;>])[a-zA-Z0-9_$@#]*", "captures": { "0": { "patterns": [{ "include": "source.ts" }] } } }, { @@ -763,9 +763,16 @@ { "comment": "Match type", "begin": "\\s*(:)(?!=)", - "end": "(?=[,;\\](]|/>|(?<=[^=>])(?:(?|>(?!=))|(?+=-]=|[=>]>|[^.]\\.|[^-]-|[^+]\\+|[a-zA-Z0-9%).<\\]}]\\s/|[^.$\\w]await|[^.$\\w]async|[^.$\\w]class|[^.$\\w]function|[^.$\\w]keyof|[^.$\\w]new|[^.$\\w]readonly|[^.$\\w]infer|[^.$\\w]typeof|[^.$\\w]void)\\s+(?![\\n{+!~*%&^|?:]|[<>/=-]=|[=>]>|\\.[^.]|-[^-]|/[^>]|(?:in|instanceof|satisfies|as|extends)\\s+[^:=/,;>]))", + "end": "(?=[,;\\](]|/>|(?<=[^=>])(?:(?|>(?!=))|(?+=-]=|[=>]>|[^.]\\.|[^-]-|[^+]\\+|[a-zA-Z0-9%).<\\]}]\\s/|[^.$\\w]await|[^.$\\w]async|[^.$\\w]class|[^.$\\w]function|[^.$\\w]keyof|[^.$\\w]new|[^.$\\w]readonly|[^.$\\w]infer|[^.$\\w]typeof)\\s+(?![\\n{+!~*%&^|?:]|[<>/=-]=|[=>]>|\\.[^.]|-[^-]|/[^>]|(?:in|instanceof|satisfies|as|extends)\\s+[^:=/,;>]))", "patterns": [ { "include": "source.ts#type" }, + { + "comment": "In a type `void` is the void type, so unlike the operator it takes no operand", + "match": "\\s*\\b(void)\\b", + "captures": { + "1": { "name": "support.type.primitive.ts" } + } + }, { "include": "#javascript-expression" } ], "beginCaptures": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 26a97327..33447c2a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -91,8 +91,8 @@ importers: specifier: ^4.12.1 version: 4.12.1 htmljs-parser: - specifier: ^5.17.1 - version: 5.17.1 + specifier: ^5.18.0 + version: 5.18.0 jsdom: specifier: ^29.1.1 version: 29.1.1(patch_hash=63260bcabe348afac2b14cafcd725106f132adbad0fab0328f16e5a9c6a1a1e4) @@ -140,8 +140,8 @@ importers: specifier: ^5.42.8 version: 5.42.8 htmljs-parser: - specifier: ^5.17.1 - version: 5.17.1 + specifier: ^5.18.0 + version: 5.18.0 relative-import-path: specifier: ^1.0.1 version: 1.0.1 @@ -1715,8 +1715,8 @@ packages: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - htmljs-parser@5.17.1: - resolution: {integrity: sha512-ww3wkVhxedYGoqZIFbA5tQfgyDvdqv2rIOkMsdu4fez2XOAcOgR+3ZLKbpFwhfaOWYAmSpj8JFrjOqRcjAg+Sg==} + htmljs-parser@5.18.0: + resolution: {integrity: sha512-ANKBAi2UyiQ7K/In2a3jZLt/WLAIKl8GFE3k5KIYEaroUdOBtt/gnclkJcSMI+kPChWdGOw3YHnbequVNy39Tg==} htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} @@ -3441,7 +3441,7 @@ snapshots: dependencies: '@luxass/strip-json-comments': 2.0.2 complain: 1.6.1 - htmljs-parser: 5.17.1 + htmljs-parser: 5.18.0 jsesc: 3.1.0 kleur: 4.1.5 lasso-package-root: 1.0.1 @@ -4603,7 +4603,7 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' - htmljs-parser@5.17.1: {} + htmljs-parser@5.18.0: {} htmlparser2@10.1.0: dependencies: @@ -5237,7 +5237,7 @@ snapshots: prettier-plugin-marko@4.1.3: dependencies: - htmljs-parser: 5.17.1 + htmljs-parser: 5.18.0 prettier-plugin-packagejson@3.0.2(prettier@3.8.4): dependencies: