diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d93f54..6c02a5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,319 @@ +## 1.5.4 (2025-09-18) + +### Bug fixes + +Support `this` parameters in function types. + +## 1.5.3 (2025-09-09) + +### Bug fixes + +Fix missing highlight tag for `defer` contextual keyword. + +## 1.5.2 (2025-09-04) + +### Bug fixes + +Allow `const` casts with old angle-bracket cast syntax. + +Add support for `import defer` syntax. + +## 1.5.1 (2025-04-18) + +### Bug fixes + +Properly highlight `satisfies` as a keyword. + +## 1.5.0 (2025-04-17) + +### Bug fixes + +Support `in`/`out` modifiers on TypeScript type parameters. + +### New features + +Support the TypeScript `satisfies` operator. + +## 1.4.21 (2024-12-03) + +### Bug fixes + +Add support for `const` modifiers on TypeScript type parameters. + +Allow TypeScript syntax, where the condition is just a variable. + +Fix a bug where some TypeScript `<` tokens didn't appear in the syntax tree. + +## 1.4.20 (2024-12-02) + +### Bug fixes + +Use the `className` style tag for variable names used as constructors with `new`. + +Add support for `asserts` syntax in function return types. + +## 1.4.19 (2024-10-08) + +### Bug fixes + +Support question marks after method names in TypeScript object type notation. + +Support bracketed property names in TypeScript object types. + +Allow TypeScript interface declarations to extend multiple types. + +## 1.4.18 (2024-09-17) + +### Bug fixes + +Support `as` syntax in mapped object types. + +Make sure the parser doesn't get confused when a template interpolation is missing its expression. + +## 1.4.17 (2024-06-11) + +### Bug fixes + +Add support for `{-readonly [K in T]-?: U}` TypeScript syntax. + +## 1.4.16 (2024-05-04) + +### Bug fixes + +Don't consume `?.` tokens when followed by a digit. + +Support type arguments on non-call expressions. + +## 1.4.15 (2024-04-23) + +### Bug fixes + +Add support for `new.target` syntax. + +## 1.4.14 (2024-03-30) + +### Bug fixes + +Recognize the `d` and `v` RegExp flags. Support destructured parameters in function types + +Allow destructured parameters in function signature types. + +## 1.4.13 (2024-01-16) + +### Bug fixes + +Fix inverted relative precedence of `&`, `|`, and `^` bitwise operators. + +Add an explicit dependency on @lezer/common ^1.2.0. + +## 1.4.12 (2024-01-04) + +### Bug fixes + +Mark strings, comments, and interpolations as isolating for bidirectional text. + +## 1.4.11 (2023-12-18) + +### Bug fixes + +In TSX mode, parse `` or `` as type parameters, not JSX tags. + +## 1.4.10 (2023-12-06) + +### Bug fixes + +Support `|` and `&` as prefixes in TypeScript types. + +## 1.4.9 (2023-10-30) + +### Bug fixes + +Allow `default` to be used in `import`/`export` binding sets. + +## 1.4.8 (2023-10-05) + +### Bug fixes + +Properly highlight `using` as a keyword. + +## 1.4.7 (2023-08-23) + +### Bug fixes + +Properly parse hashbang comments. + +## 1.4.6 (2023-08-22) + +### Bug fixes + +Make sure that, in TypeScript, type argument lists are prefered over comparison operators when both produce valid parses. + +## 1.4.5 (2023-07-25) + +### Bug fixes + +Allow the index in a TypeScript indexed type to be any kind of type. + +## 1.4.4 (2023-07-03) + +### Bug fixes + +Add support for `using` syntax. + +Make the package work with new TS resolution styles. + +## 1.4.3 (2023-04-24) + +### Bug fixes + +Properly parse `this: Type` within parameter lists for TypeScript. + +## 1.4.2 (2023-03-29) + +### Bug fixes + +Properly parse `declare` in front of class properties and methods in TypeScript. + +## 1.4.1 (2023-01-09) + +### Bug fixes + +Fix a bug where something like `yield [1]` (or `await`) was parsed as a member expression. + +Add support for `yield*` syntax. + +Escapes in strings are now parsed as their own tokens (and styled with the `escape` tag). + +## 1.4.0 (2022-12-19) + +### New features + +The new `"SingleClassItem"` top-level rule can be used to parse only a class item (method, property, or static block). + +## 1.3.2 (2022-12-14) + +### Bug fixes + +Typescript allows `override` on all class elements, not just methods. + +Allow expressions in class extends clauses in TypeScript. + +## 1.3.1 (2022-11-29) + +### Bug fixes + +Actually emit a tree node for the `@` characters in decorators. + +## 1.3.0 (2022-11-28) + +### New features + +Add support for decorator syntax. + +## 1.2.0 (2022-11-24) + +### New features + +The grammar now supports `top: "SingleExpression"` to parse an expression rather than a script. + +## 1.1.1 (2022-11-19) + +### Bug fixes + +Fix parsing of computed properties in class declarations. + +## 1.1.0 (2022-11-17) + +### Bug fixes + +Fix parsing of 'null' as type in TypeScript. + +Allow computed properties in object destructuring patterns. + +Add TypeScript 4.9's `satisfies` operator. + +Support `accessor` syntax on class properties. + +### New features + +Add support for optional call syntax. + +Distinguish lower-case JSX element names syntactically, give them a `standard(tagName)` highlight tag. + +## 1.0.2 (2022-07-21) + +### Bug fixes + +Properly assign a highlighting tag to the `super` keyword. + +## 1.0.1 (2022-06-27) + +### Bug fixes + +Fix parsing of TypeScript conditional types. + +Support type parameters in TypeScript function type syntax. + +## 1.0.0 (2022-06-06) + +### New features + +First stable version. + +## 0.16.0 (2022-04-20) + +### Breaking changes + +Move to 0.16 serialized parser format. + +### Bug fixes + +Allow commas as separators in TypeScript object type syntax. + +### New features + +Add `CatchClause` and `FinallyClause` nodes wrapping parts of `TryStatement`. + +The parser now includes syntax highlighting information in its node types. + +## 0.15.3 (2022-01-26) + +### Bug fixes + +Support missing values in array pattern syntax. + +Support quoted module export names. + +### New features + +Template string interpolations now get their own nodes in the syntax tree. + +## 0.15.2 (2021-12-08) + +### Bug fixes + +Fix a typo in the `TaggedTemplateExpression` node name. Support n suffixes after non-decimal integers + +Add support for non-decimal bignum literals (). + +Add support for static class initialization blocks. + +## 0.15.1 (2021-11-12) + +### Bug fixes + +Add support for TypeScript `import {type X} from y` syntax. + +Indexed TypeScript types can now take type parameters. + +Add support for private field syntax. + +Rename PropertyNameDefinition node to PropertyDefinition for consistency with other names. + +### New features + +Recognize TypeScript 4.3's `override` keyword. + ## 0.15.0 (2021-08-11) ### Breaking changes diff --git a/LICENSE b/LICENSE index 30a86e3..c21df7e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (C) 2018 by Marijn Haverbeke and others +Copyright (C) 2018 by Marijn Haverbeke and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index e80270f..6ebba94 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,16 @@ -# lezer-javascript +**This repository has moved to https://code.haverbeke.berlin/lezer/javascript** + +# @lezer/javascript This is a JavaScript grammar for the [lezer](https://lezer.codemirror.net/) parser system. -It parses ES2020, and supports a `"ts"` +It parses modern JavaScript, and supports a `"ts"` [dialect](https://lezer.codemirror.net/docs/guide/#dialects) to parse TypeScript, and a `"jsx"` dialect to parse JSX. +The `top` option can be set to `"SingleExpression"` or +`"SingleClassItem"` to parse an expression or class item instead of a +full program. + The code is licensed under an MIT license. diff --git a/dist/index.d.cts b/dist/index.d.cts new file mode 100644 index 0000000..b1518ec --- /dev/null +++ b/dist/index.d.cts @@ -0,0 +1,3 @@ +import {LRParser} from "@lezer/lr" + +export const parser: LRParser diff --git a/package.json b/package.json index 4adfe6e..1a12121 100644 --- a/package.json +++ b/package.json @@ -1,29 +1,31 @@ { "name": "@lezer/javascript", - "version": "0.15.0", + "version": "1.5.4", "description": "lezer-based JavaScript grammar", "main": "dist/index.cjs", "type": "module", "exports": { - "import": "./dist/index.es.js", + "import": "./dist/index.js", "require": "./dist/index.cjs" }, - "module": "dist/index.es.js", + "module": "dist/index.js", "types": "dist/index.d.ts", - "author": "Marijn Haverbeke ", + "author": "Marijn Haverbeke ", "license": "MIT", "devDependencies": { - "@lezer/generator": "^0.15.0", - "mocha": "^9.0.1", + "@lezer/generator": "^1.7.0", + "mocha": "^10.2.0", "rollup": "^2.52.2", "@rollup/plugin-node-resolve": "^9.0.0" }, "dependencies": { - "@lezer/lr": "^0.15.0" + "@lezer/lr": "^1.3.0", + "@lezer/common": "^1.2.0", + "@lezer/highlight": "^1.1.3" }, "repository": { "type": "git", - "url": "https://github.com/lezer-parser/javascript.git" + "url": "git+https://code.haverbeke.berlin/lezer/javascript.git" }, "scripts": { "build": "lezer-generator src/javascript.grammar -o src/parser && rollup -c", diff --git a/rollup.config.js b/rollup.config.js index 75a876c..35012b4 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -7,7 +7,7 @@ export default { file: "./dist/index.cjs" }, { format: "es", - file: "./dist/index.es.js" + file: "./dist/index.js" }], external(id) { return !/^[\.\/]/.test(id) }, plugins: [ diff --git a/src/highlight.js b/src/highlight.js new file mode 100644 index 0000000..385f4c4 --- /dev/null +++ b/src/highlight.js @@ -0,0 +1,62 @@ +import {styleTags, tags as t} from "@lezer/highlight" + +export const jsHighlight = styleTags({ + "get set async static": t.modifier, + "for while do if else switch try catch finally return throw break continue default case defer": t.controlKeyword, + "in of await yield void typeof delete instanceof as satisfies": t.operatorKeyword, + "let var const using function class extends": t.definitionKeyword, + "import export from": t.moduleKeyword, + "with debugger new": t.keyword, + TemplateString: t.special(t.string), + super: t.atom, + BooleanLiteral: t.bool, + this: t.self, + null: t.null, + Star: t.modifier, + VariableName: t.variableName, + "CallExpression/VariableName TaggedTemplateExpression/VariableName": t.function(t.variableName), + VariableDefinition: t.definition(t.variableName), + Label: t.labelName, + PropertyName: t.propertyName, + PrivatePropertyName: t.special(t.propertyName), + "CallExpression/MemberExpression/PropertyName": t.function(t.propertyName), + "FunctionDeclaration/VariableDefinition": t.function(t.definition(t.variableName)), + "ClassDeclaration/VariableDefinition": t.definition(t.className), + "NewExpression/VariableName": t.className, + PropertyDefinition: t.definition(t.propertyName), + PrivatePropertyDefinition: t.definition(t.special(t.propertyName)), + UpdateOp: t.updateOperator, + "LineComment Hashbang": t.lineComment, + BlockComment: t.blockComment, + Number: t.number, + String: t.string, + Escape: t.escape, + ArithOp: t.arithmeticOperator, + LogicOp: t.logicOperator, + BitOp: t.bitwiseOperator, + CompareOp: t.compareOperator, + RegExp: t.regexp, + Equals: t.definitionOperator, + Arrow: t.function(t.punctuation), + ": Spread": t.punctuation, + "( )": t.paren, + "[ ]": t.squareBracket, + "{ }": t.brace, + "InterpolationStart InterpolationEnd": t.special(t.brace), + ".": t.derefOperator, + ", ;": t.separator, + "@": t.meta, + + TypeName: t.typeName, + TypeDefinition: t.definition(t.typeName), + "type enum interface implements namespace module declare": t.definitionKeyword, + "abstract global Privacy readonly override": t.modifier, + "is keyof unique infer asserts": t.operatorKeyword, + + JSXAttributeValue: t.attributeValue, + JSXText: t.content, + "JSXStartTag JSXStartCloseTag JSXSelfCloseEndTag JSXEndTag": t.angleBracket, + "JSXIdentifier JSXNameSpacedName": t.tagName, + "JSXAttribute/JSXIdentifier JSXAttribute/JSXNameSpacedName": t.attributeName, + "JSXBuiltin/JSXIdentifier": t.standard(t.tagName) +}) diff --git a/src/javascript.grammar b/src/javascript.grammar index e998e6e..c148f11 100644 --- a/src/javascript.grammar +++ b/src/javascript.grammar @@ -4,14 +4,17 @@ typeargs, typeMember, typePrefix, + intersectionPrefixed @left, intersection @left, + unionPrefixed @left, union @left, - typeTernary @right, + typeExtends @right, else @right, member, readonly, newArgs, call, + instantiate, taggedTemplate, prefix, postfix, @@ -22,10 +25,11 @@ shift @left, loop, rel @left, + satisfies, equal @left, - bitOr @left, - bitXor @left, bitAnd @left, + bitXor @left, + bitOr @left, and @left, or @left, ternary @right, @@ -35,7 +39,11 @@ predicate } -@top Script { statement+ } +@top Script { Hashbang? statement* } + +@top SingleExpression { expression } + +@top SingleClassItem { classItem } statement[@isGroup=Statement] { ExportDeclaration | @@ -46,7 +54,11 @@ statement[@isGroup=Statement] { DoStatement { kw<"do"> statement kw<"while"> ParenthesizedExpression semi } | IfStatement { kw<"if"> ParenthesizedExpression statement (!else kw<"else"> statement)? } | SwitchStatement { kw<"switch"> ParenthesizedExpression SwitchBody { "{" switchItem* "}" } } | - TryStatement { kw<"try"> Block (kw<"catch"> ("(" pattern ")")? Block)? (kw<"finally"> Block)? } | + TryStatement { + kw<"try"> Block + CatchClause { kw<"catch"> ("(" pattern ")")? Block }? + FinallyClause { kw<"finally"> Block }? + } | ReturnStatement { kw<"return"> (noSemi expression)? semi } | ThrowStatement { kw<"throw"> expression semi } | BreakStatement { kw<"break"> (noSemi Label)? semi } | @@ -60,7 +72,7 @@ statement[@isGroup=Statement] { } ExportDeclaration { - kw<"export"> Star (ckw<"as"> VariableName)? ckw<"from"> String semi | + kw<"export"> Star (ckw<"as"> (VariableName | String))? ckw<"from"> String semi | kw<"export"> kw<"default"> (FunctionDeclaration | ClassDeclaration | expression semi) | kw<"export"> tskw<"type">? declaration | kw<"export"> tskw<"type">? ExportGroup (ckw<"from"> String)? semi | @@ -68,17 +80,17 @@ ExportDeclaration { } ExportGroup { - "{" commaSep VariableName { word })?> "}" + "{" commaSep<(VariableName | String | kw<"default">) (ckw<"as"> (VariableName { word } | String))?> "}" } ImportDeclaration { - kw<"import"> tskw<"type">? (Star ckw<"as"> VariableDefinition | commaSep) + kw<"import"> ckw<"defer">? tskw<"type">? (Star ckw<"as"> VariableDefinition | commaSep) ckw<"from"> String semi | - kw<"import"> String semi + kw<"import"> ckw<"defer">? String semi } ImportGroup { - "{" commaSep VariableDefinition> "}" + "{" commaSep? (VariableDefinition | (VariableName | String | kw<"default">) ckw<"as"> VariableDefinition)> "}" } ForSpec { @@ -89,7 +101,7 @@ ForSpec { forXSpec { "(" - ((kw<"let"> | kw<"var"> | kw<"const">) pattern | VariableName | MemberExpression | ArrayPattern | ObjectPattern) + (variableDeclarationKeyword pattern | VariableName | MemberExpression | ArrayPattern | ObjectPattern) !loop op expression ")" } @@ -109,19 +121,19 @@ declaration { } FunctionDeclaration { - async? !statement kw<"function"> Star? VariableDefinition? functionSignature Block + async? !statement kw<"function"> Star? VariableDefinition? functionSignature (Block | semi) } ClassDeclaration { - !statement tskw<"abstract">? kw<"class"> VariableDefinition TypeParamList? - (kw<"extends"> expression | TSExtends type)? + !statement Decorator* tskw<"abstract">? kw<"class"> VariableDefinition TypeParamList? + (kw<"extends"> ((VariableName | MemberExpression) !typeargs TypeArgList | expression))? (tskw<"implements"> commaSep1)? ClassBody } -ClassBody { - "{" (MethodDeclaration | PropertyDeclaration | ";")* "}" -} +classItem { MethodDeclaration | PropertyDeclaration | StaticBlock | ";" } + +ClassBody { "{" classItem* "}" } privacy { @extend[@name=Privacy,@dialect=ts] @@ -131,29 +143,46 @@ privacyArg { @extend[@name=Privacy,@dialect=ts] } +propModifier { + Decorator | + tsPkwMod<"declare"> | + privacy | + pkwMod<"static"> | + tsPkwMod<"abstract"> | + tsPkwMod<"override"> +} + +classPropName { propName | PrivatePropertyDefinition } + MethodDeclaration[group=ClassItem] { - privacy? - (pkwMod<"static"> | tsPkwMod<"abstract">)? + propModifier* pkwMod<"async">? (pkwMod<"get"> | pkwMod<"set"> | Star)? - PropertyNameDefinition + classPropName functionSignature - Block + (Block | semi) +} + +StaticBlock[group=ClassItem] { + pkwMod<"static"> Block } PropertyDeclaration[group=ClassItem] { - privacy? - (pkwMod<"static"> | tsPkwMod<"abstract">)? - pkwMod<"readonly">? - PropertyNameDefinition + propModifier* + (tsPkwMod<"readonly"> | pkwMod<"accessor">)? + classPropName (Optional | LogicOp<"!">)? TypeAnnotation? ("=" expressionNoComma)? semi } +variableDeclarationKeyword { + kw<"let"> | kw<"var"> | kw<"const"> | ckw<"await">? ckw<"using"> +} + VariableDeclaration { - (kw<"let"> | kw<"var"> | kw<"const">) commaSep1 semi + variableDeclarationKeyword commaSep1 semi } TypeAliasDeclaration { @@ -161,7 +190,7 @@ TypeAliasDeclaration { } InterfaceDeclaration { - tskw<"interface"> TypeDefinition TypeParamList? (TSExtends type)? ObjectType + tskw<"interface"> TypeDefinition TypeParamList? (kw<"extends"> commaSep1)? ObjectType } EnumDeclaration { @@ -169,7 +198,7 @@ EnumDeclaration { } NamespaceDeclaration { - (tskw<"namespace"> | tskw<"module">) VariableDefinition ("." PropertyNameDefinition)* Block + (tskw<"namespace"> | tskw<"module">) VariableDefinition ("." PropertyDefinition)* Block } AmbientDeclaration { @@ -182,15 +211,12 @@ AmbientDeclaration { GlobalDeclaration { tskw<"global"> Block } | ClassDeclaration { tskw<"abstract">? kw<"class"> VariableDefinition TypeParamList? - (kw<"extends"> expression | TSExtends type)? + (kw<"extends"> expression)? (tskw<"implements"> commaSep1)? ClassBody { "{" ( - MethodDeclaration { - privacy? (pkwMod<"static"> | tsPkwMod<"abstract">)? pkwMod<"async">? (pkwMod<"get"> | pkwMod<"set"> | Star)? - PropertyNameDefinition TypeParamList? ParamList (TypeAnnotation | TypePredicate) semi - } | - PropertyDeclaration | - IndexSignature + MethodDeclaration | + PropertyDeclaration | + IndexSignature semi )* "}" } } | AmbientFunctionDeclaration { @@ -199,9 +225,18 @@ AmbientDeclaration { ) } +decoratorExpression { + VariableName | + MemberExpression { decoratorExpression !member ("." | questionDot) (PropertyName | PrivatePropertyName) } | + CallExpression { decoratorExpression !call TypeArgList? questionDot? ArgList } | + ParenthesizedExpression +} + +Decorator { "@" decoratorExpression } + pattern { VariableDefinition | ArrayPattern | ObjectPattern } -ArrayPattern { "[" commaSep<"..."? patternAssign> ~destructure "]" } +ArrayPattern { "[" commaSep<("..."? patternAssign)?> ~destructure "]" } ObjectPattern { "{" commaSep ~destructure "}" } @@ -211,14 +246,19 @@ patternAssign { TypeAnnotation { ":" type } -TypePredicate { ":" (VariableName | kw<"this">) !predicate tskw<"is"> type } +TypePredicate { + ":" ( + tskw<"asserts"> (VariableName | kw<"this">) !predicate (tskw<"is"> type)? | + (VariableName | kw<"this">) !predicate tskw<"is"> type + ) +} patternAssignTyped { pattern Optional? TypeAnnotation? ("=" expressionNoComma)? } ParamList { - "(" commaSep<"..." patternAssignTyped | privacyArg? tskw<"readonly">? patternAssignTyped> ")" + "(" commaSep<"..." patternAssignTyped | Decorator* privacyArg? tskw<"readonly">? patternAssignTyped | kw<"this"> TypeAnnotation> ")" } Block { @@ -251,8 +291,11 @@ expressionNoComma { RegExp | ArrayExpression | ObjectExpression { "{" commaSep ~destructure "}" } | - NewExpression { kw<"new"> expressionNoComma (!newArgs TypeArgList? ArgList)? } | + NewTarget { kw<"new"> "." PropertyName } | + NewExpression { kw<"new"> expressionNoComma (!newArgs ArgList)? } | UnaryExpression | + YieldExpression | + AwaitExpression | ParenthesizedExpression | ClassExpression | FunctionExpression | @@ -262,12 +305,13 @@ expressionNoComma { ConditionalExpression { expressionNoComma !ternary questionOp expressionNoComma LogicOp<":"> expressionNoComma } | AssignmentExpression | PostfixExpression { expressionNoComma !postfix (incdec | LogicOp<"!">) } | - CallExpression { expressionNoComma !call TypeArgList? ArgList } | - TaggedTemplatExpression { expressionNoComma !taggedTemplate TemplateString } | + CallExpression { expressionNoComma !call questionDot? ArgList } | + InstantiationExpression { (VariableName | MemberExpression) !instantiate TypeArgList } | + TaggedTemplateExpression { expressionNoComma !taggedTemplate TemplateString } | DynamicImport { kw<"import"> "(" expressionNoComma ")" } | ImportMeta { kw<"import"> "." PropertyName } | JSXElement | - PrefixCast { tsAngleOpen type ~tsAngle ">" expressionNoComma } | + PrefixCast { tsAngleOpen (type | kw<"const">) ~tsAngle ">" expressionNoComma } | ArrowFunction[@dynamicPrecedence=1] { TypeParamList { tsAngleOpen commaSep ">" } ParamList TypeAnnotation? "=>" (Block | expressionNoComma) } @@ -279,7 +323,7 @@ ArrayExpression { "[" commaSep1<"..."? expressionNoComma | ""> ~destructure "]" } -propName { PropertyNameDefinition | "[" expression "]" | Number | String } +propName { PropertyDefinition | "[" expression "]" ~destructure | Number ~destructure | String ~destructure } Property { pkwMod<"async">? (pkwMod<"get"> | pkwMod<"set"> | Star)? propName functionSignature Block | @@ -289,11 +333,12 @@ Property { PatternProperty { "..." patternAssign | - (PropertyName | Number | String) ~destructure (":" pattern)? ("=" expressionNoComma)? + ((PropertyName | Number | String) ~destructure (":" pattern)? | + ("[" expression "]" ~destructure ":" pattern)) ("=" expressionNoComma)? } ClassExpression { - kw<"class"> VariableDefinition? (kw<"extends"> expression | TSExtends type)? ClassBody + kw<"class"> VariableDefinition? (kw<"extends"> expression)? ClassBody } functionSignature { TypeParamList? ParamList (TypeAnnotation | TypePredicate)? } @@ -302,19 +347,30 @@ FunctionExpression { async? kw<"function"> Star? VariableDefinition? functionSignature Block } +YieldExpression[@dynamicPrecedence=1] { + !prefix ckw<"yield"> Star? expressionNoComma +} + +AwaitExpression[@dynamicPrecedence=1] { + !prefix ckw<"await"> expressionNoComma +} + UnaryExpression { - !prefix (ckw<"await"> | ckw<"yield"> | kw<"void"> | kw<"typeof"> | kw<"delete"> | - LogicOp<"!"> | BitOp<"~"> | incdec | incdecPrefix | ArithOp<"+" | "-">) + !prefix (kw<"void"> | kw<"typeof"> | kw<"delete"> | + LogicOp<"!"> | BitOp<"~"> | incdec | incdecPrefix | plusMin) expressionNoComma } BinaryExpression { expressionNoComma !exp ArithOp<"**"> expressionNoComma | expressionNoComma !times (divide | ArithOp<"%"> | ArithOp<"*">) expressionNoComma | - expressionNoComma !plus ArithOp<"+" | "-"> expressionNoComma | + expressionNoComma !plus plusMin expressionNoComma | expressionNoComma !shift BitOp<">>" ">"? | "<<"> expressionNoComma | - expressionNoComma !rel (LessThan | CompareOp<"<=" | ">" "="?> | kw<"in"> | kw<"instanceof">) expressionNoComma | + expressionNoComma !rel (LessThan | CompareOp<"<=" | ">" "="?> | kw<"instanceof">) expressionNoComma | + expressionNoComma !satisfies tskw<"satisfies"> type | + (expressionNoComma | PrivatePropertyName) !rel ~tsIn kw<"in"> expressionNoComma | expressionNoComma !rel ckw<"as"> (kw<"const"> | type) | + expressionNoComma !rel tskw<"satisfies"> type | expressionNoComma !equal CompareOp<"==" "="? | "!=" "="?> expressionNoComma | expressionNoComma !bitOr BitOp { "|" } expressionNoComma | expressionNoComma !bitXor BitOp<"^"> expressionNoComma | @@ -330,7 +386,7 @@ AssignmentExpression { } MemberExpression { - expressionNoComma !member (("." | "?.") PropertyName | "[" expression "]") + expressionNoComma !member (("." | questionDot) (PropertyName | PrivatePropertyName) | questionDot? "[" expression "]") } ArgList { @@ -341,7 +397,7 @@ ArrowFunction { async? (ParamList { VariableDefinition } | ParamList TypeAnnotation?) "=>" (Block | expressionNoComma) } -TypeArgList { +TypeArgList[@dynamicPrecedence=1] { @extend[@dialect=ts,@name="<"] commaSep ">" } @@ -349,89 +405,111 @@ TypeParamList { "<" commaSep ">" } -typeParam { TypeDefinition ~tsAngle (TSExtends type)? ("=" type)? } +typeParam { (kw<"in"> | tskw<"out"> | kw<"const">)? TypeDefinition ~tsAngle (kw<"extends"> type)? ("=" type)? } -typeofMemberExpression[@name=MemberExpression] { - VariableName !member (("." | "?.") PropertyName | "[" expression "]") +typeofExpression { + MemberExpression { typeofExpression !member (("." | questionDot) PropertyName | "[" expression "]") } | + InstantiationExpression { typeofExpression !instantiate TypeArgList } | + VariableName } type[@isGroup=Type] { ThisType { kw<"this"> } | LiteralType { - ArithOp<"+" | "-">? Number | + plusMin? Number | boolean | String } | TemplateType | + NullType { kw<"null"> } | VoidType { kw<"void"> } | - TypeofType { kw<"typeof"> (VariableName | typeofMemberExpression) } | + TypeofType { kw<"typeof"> typeofExpression } | KeyofType { !typePrefix tskw<"keyof"> type } | UniqueType { !typePrefix tskw<"unique"> type } | ImportType { kw<"import"> "(" String ")" } | InferredType { tskw<"infer"> TypeName } | ParenthesizedType { "(" type ")" } | - FunctionSignature { ParamTypeList "=>" type } | + FunctionSignature { TypeParamList? ParamTypeList "=>" type } | NewSignature { kw<"new"> ParamTypeList "=>" type } | - IndexedType { type !typeMember ("." PropertyName | "[" (String | Number) "]")+ } | - TupleType { "[" commaSep<(Label ":")? type | "..." type> "]" } | - ArrayType { type "[" "]" | type "[" "]" } | + IndexedType | + TupleType { "[" commaSep<(Label ":")? type | "..." type> ~destructure "]" } | + ArrayType { type noSemiType "[" "]" } | ReadonlyType { tskw<"readonly"> !readonly type } | ObjectType | - UnionType { type !union LogicOp { "|" } type } | - IntersectionType { type !intersection LogicOp { "&" } type } | - ConditionalType { type !typeTernary questionOp ~arrow type LogicOp<":"> type } | - ParameterizedType { TypeName !typeargs TypeArgList } | + UnionType { + type (!union unionOp type)+ | + unionOp type (!unionPrefixed unionOp type)* + } | + IntersectionType { + type (!intersection intersectionOp type)+ | + intersectionOp type (!intersectionPrefixed intersectionOp type)* + } | + ConditionalType { type !typeExtends kw<"extends"> type questionOp ~arrow type LogicOp<":"> type } | + ParameterizedType { (TypeName | IndexedType) !typeargs TypeArgList } | TypeName } +IndexedType { + type !typeMember ("." TypeName | noSemiType "[" type "]")+ +} + ObjectType { "{" ( - MethodType | - PropertyType | - IndexSignature | - CallSignature { ParamTypeList (TypeAnnotation | TypePredicate) semi } | - NewSignature[@dynamicPrecedence=1] { @extend[@name=new] ParamTypeList TypeAnnotation semi } | - ";" - )* "}" + (MethodType | + PropertyType | + IndexSignature | + CallSignature { ParamTypeList (TypeAnnotation | TypePredicate) } | + NewSignature[@dynamicPrecedence=1] { @extend[@name=new] ParamTypeList TypeAnnotation }) + ("," | semi) + )* ~destructure "}" } IndexSignature { - pkwMod<"readonly">? "[" PropertyNameDefinition (TypeAnnotation | kw<"in"> type) "]" TypeAnnotation semi + (plusMin? tsPkwMod<"readonly">)? + "[" PropertyDefinition { identifier } (TypeAnnotation | ~tsIn kw<"in"> type (ckw<"as"> type)?) "]" + (plusMin? Optional)? + TypeAnnotation } MethodType { pkwMod<"async">? (pkwMod<"get"> | pkwMod<"set"> | Star)? - PropertyNameDefinition + propName + (plusMin? Optional)? functionSignature - semi } PropertyType { - (ArithOp<"+" | "-">? pkwMod<"readonly">)? - PropertyNameDefinition - (ArithOp<"+" | "-">? Optional)? + (plusMin? tsPkwMod<"readonly">)? + propName + (plusMin? Optional)? TypeAnnotation - semi -} +} ParamTypeList[@name=ParamList] { - "(" commaSep<"..."? VariableDefinition ~arrow Optional? ~arrow TypeAnnotation?> ")" + "(" commaSep<"..."? pattern ~arrow Optional? ~arrow TypeAnnotation? | kw<"this"> TypeAnnotation> ")" } @skip {} { - TemplateString { - templateStart (templateContent | templateExpr)* templateEnd + TemplateString[isolate] { + templateStart (templateEscape | templateContent | templateExpr)* templateEnd } - TemplateType { + TemplateType[isolate] { templateStart (templateContent | templateType)* templateEnd } + + String[isolate] { + '"' (stringContentDouble | Escape)* ('"' | "\n") | + "'" (stringContentSingle | Escape)* ("'" | "\n") + } + + BlockComment[isolate] { "/*" (blockCommentContent | blockCommentNewline)* blockCommentEnd } } -templateExpr { templateDollarBrace expression templateClosingBrace } +templateExpr[@name=Interpolation,isolate] { InterpolationStart expression? InterpolationEnd } -templateType { templateDollarBrace type templateClosingBrace } +templateType[@name=Interpolation,isolate] { InterpolationStart type? InterpolationEnd } @skip {} { JSXElement { @@ -450,17 +528,18 @@ JSXCloseTag { JSXStartCloseTag jsxElementName? JSXEndTag } jsxElementName { JSXIdentifier | + JSXBuiltin { JSXLowerIdentifier } | JSXNamespacedName | JSXMemberExpression } -JSXMemberExpression { (JSXMemberExpression | JSXIdentifier) "." JSXIdentifier } +JSXMemberExpression { (JSXMemberExpression | JSXIdentifier | JSXLowerIdentifier) "." (JSXIdentifier | JSXLowerIdentifier) } -JSXNamespacedName { (JSXIdentifier | JSXNamespacedName) ":" JSXIdentifier } +JSXNamespacedName { (JSXIdentifier | JSXNamespacedName | JSXLowerIdentifier) ":" (JSXIdentifier | JSXLowerIdentifier) } jsxAttribute { JSXSpreadAttribute { "{" "..." expression "}" } | - JSXAttribute { (JSXIdentifier | JSXNamespacedName) ("=" jsxAttributeValue)? } + JSXAttribute { (JSXIdentifier | JSXNamespacedName | JSXLowerIdentifier) ("=" jsxAttributeValue)? } } jsxAttributeValue { @@ -513,81 +592,105 @@ TypeName { identifier ~arrow } Label { identifier } -PropertyName { word } +PropertyName { word ~propName } -PropertyNameDefinition { word } +PropertyDefinition { word ~propName } + +PrivatePropertyName { privateIdentifier } + +PrivatePropertyDefinition { privateIdentifier } Optional { "?" } questionOp[@name=LogicOp] { "?" } +unionOp[@name=LogicOp] { "|" } + +plusMin { ArithOp<"+" | "-"> } + +intersectionOp[@name=LogicOp] { "&" } + @skip { spaces | newline | LineComment | BlockComment } @context trackNewline from "./tokens.js" -@external extend { identifier } tsExtends from "./tokens" { TSExtends[@name=extends] } - @external tokens noSemicolon from "./tokens" { noSemi } -@external tokens incdecToken from "./tokens" { +@external tokens noSemicolonType from "./tokens" { noSemiType } + +@external tokens operatorToken from "./tokens" { incdec[@name=ArithOp], incdecPrefix[@name=ArithOp] + questionDot[@name="?."] } -@external tokens template from "./tokens" { - templateContent, - templateDollarBrace, - templateEnd +@external tokens jsx from "./tokens" { JSXStartTag } + +@local tokens { + InterpolationStart[closedBy=InterpolationEnd] { "${" } + templateEnd { "`" } + templateEscape[@name=Escape] { Escape } + @else templateContent +} + +@local tokens { + blockCommentEnd { "*/" } + blockCommentNewline { "\n" } + @else blockCommentContent } @tokens { spaces[@export] { $[\u0009 \u000b\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff]+ } newline[@export] { $[\r\n\u2028\u2029] } - LineComment { "//" ![\n]* } - - // FIXME split into multiple tokens - BlockComment { "/*" blockCommentRest } + LineComment[isolate] { "//" ![\n]* } - blockCommentRest { ![*] blockCommentRest | "*" blockCommentAfterStar } - - blockCommentAfterStar { "/" | "*" blockCommentAfterStar | ![/*] blockCommentRest } + Hashbang { "#!" ![\n]* } divide[@name=ArithOp] { "/" } - @precedence { BlockComment, LineComment, divide } + @precedence { "/*", LineComment, divide } - @precedence { BlockComment, LineComment, RegExp } + @precedence { "/*", LineComment, RegExp } - identifierChar { std.asciiLetter | $[_$\u{a1}-\u{10ffff}] } + identifierChar { @asciiLetter | $[_$\u{a1}-\u{10ffff}] } - word { identifierChar (identifierChar | std.digit)* } + word { identifierChar (identifierChar | @digit)* } identifier { word } + privateIdentifier { "#" word } + @precedence { spaces, newline, identifier } - @precedence { spaces, newline, JSXIdentifier } + @precedence { spaces, newline, JSXIdentifier, JSXLowerIdentifier } @precedence { spaces, newline, word } + hex { @digit | $[a-fA-F] } + Number { - (std.digit ("_" | std.digit)* ("." ("_" | std.digit)*)? | "." std.digit ("_" | std.digit)*) - (("e" | "E") ("+" | "-")? ("_" | std.digit)+)? | - std.digit ("_" | std.digit)* "n" | - "0x" (std.digit | $[a-fA-F] | "_")+ | - "0b" $[01_]+ | - "0o" $[0-7_]+ + (@digit ("_" | @digit)* ("." ("_" | @digit)*)? | "." @digit ("_" | @digit)*) + (("e" | "E") ("+" | "-")? ("_" | @digit)+)? | + @digit ("_" | @digit)* "n" | + "0x" (hex | "_")+ "n"? | + "0b" $[01_]+ "n"? | + "0o" $[0-7_]+ "n"? } - String { - '"' (![\\\n"] | "\\" _)* '"'? | - "'" (![\\\n'] | "\\" _)* "'"? + @precedence { Number "." } + + Escape { + "\\" ("x" hex hex | "u" ("{" hex+ "}" | hex hex hex hex) | ![xu]) } + stringContentSingle { ![\\\n']+ } + + stringContentDouble { ![\\\n"]+ } + templateStart { "`" } - templateClosingBrace { "}" } + InterpolationEnd[openedBy=InterpolationStart] { "}" } ArithOp { expr } LogicOp { expr } @@ -595,7 +698,9 @@ questionOp[@name=LogicOp] { "?" } CompareOp { expr } UpdateOp { expr } - RegExp { "/" (![/\\\n[] | "\\" ![\n] | "[" (![\n\\\]] | "\\" ![\n])* "]")+ ("/" $[gimsuy]*)? } + @precedence { "*", ArithOp } + + RegExp[isolate] { "/" (![/\\\n[] | "\\" ![\n] | "[" (![\n\\\]] | "\\" ![\n])* "]")+ ("/" $[dgimsuvy]*)? } LessThan[@name=CompareOp] { "<" } @@ -603,16 +708,15 @@ questionOp[@name=LogicOp] { "?" } "..."[@name=Spread] "=>"[@name=Arrow] - "(" ")" "[" "]" "{" "}" + "(" ")" "[" "]" "{" "}" "<" ">" - "?." "." "," ";" ":" + "." "," ";" ":" "@" - JSXIdentifier { identifierChar (identifierChar | std.digit | "-")* } + JSXIdentifier { $[A-Z_$\u{a1}-\u{10ffff}] (identifierChar | @digit | "-")* } + JSXLowerIdentifier[@name=JSXIdentifier] { $[a-z] (identifierChar | @digit | "-")* } JSXAttributeValue { '"' !["]* '"' | "'" ![']* "'" } - JSXStartTag[@dialect=jsx] { "<" } - JSXStartCloseTag { "" } @@ -621,11 +725,11 @@ questionOp[@name=LogicOp] { "?" } JSXText { ![<{]+ } - tsAngleOpen[@dialect=ts] { "<" } - - @precedence { JSXStartTag, tsAngleOpen } + tsAngleOpen[@dialect=ts,@name="<"] { "<" } } @external tokens insertSemicolon from "./tokens" { insertSemi } +@external propSource jsHighlight from "./highlight" + @detectDelim diff --git a/src/tokens.js b/src/tokens.js index 2445cce..299102e 100644 --- a/src/tokens.js +++ b/src/tokens.js @@ -2,15 +2,15 @@ expressed by lezer's built-in tokenizer. */ import {ExternalTokenizer, ContextTracker} from "@lezer/lr" -import {insertSemi, noSemi, incdec, incdecPrefix, templateContent, templateDollarBrace, templateEnd, +import {insertSemi, noSemi, noSemiType, incdec, incdecPrefix, questionDot, spaces, newline, BlockComment, LineComment, - TSExtends, Dialect_ts} from "./parser.terms.js" + JSXStartTag, Dialect_jsx} from "./parser.terms.js" const space = [9, 10, 11, 12, 13, 32, 133, 160, 5760, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232, 8233, 8239, 8287, 12288] -const braceR = 125, braceL = 123, semicolon = 59, slash = 47, star = 42, - plus = 43, minus = 45, dollar = 36, backtick = 96, backslash = 92 +const braceR = 125, semicolon = 59, slash = 47, star = 42, plus = 43, minus = 45, lt = 60, comma = 44, + question = 63, dot = 46, bracketL = 91 export const trackNewline = new ContextTracker({ start: false, @@ -22,7 +22,7 @@ export const trackNewline = new ContextTracker({ export const insertSemicolon = new ExternalTokenizer((input, stack) => { let {next} = input - if ((next == braceR || next == -1 || stack.context) && stack.canShift(insertSemi)) + if (next == braceR || next == -1 || stack.context) input.acceptToken(insertSemi) }, {contextual: true, fallback: true}) @@ -30,11 +30,15 @@ export const noSemicolon = new ExternalTokenizer((input, stack) => { let {next} = input, after if (space.indexOf(next) > -1) return if (next == slash && ((after = input.peek(1)) == slash || after == star)) return - if (next != braceR && next != semicolon && next != -1 && !stack.context && stack.canShift(noSemi)) + if (next != braceR && next != semicolon && next != -1 && !stack.context) input.acceptToken(noSemi) }, {contextual: true}) -export const incdecToken = new ExternalTokenizer((input, stack) => { +export const noSemicolonType = new ExternalTokenizer((input, stack) => { + if (input.next == bracketL && !stack.context) input.acceptToken(noSemiType) +}, {contextual: true}) + +export const operatorToken = new ExternalTokenizer((input, stack) => { let {next} = input if (next == plus || next == minus) { input.advance() @@ -43,36 +47,41 @@ export const incdecToken = new ExternalTokenizer((input, stack) => { let mayPostfix = !stack.context && stack.canShift(incdec) input.acceptToken(mayPostfix ? incdec : incdecPrefix) } + } else if (next == question && input.peek(1) == dot) { + input.advance(); input.advance() + if (input.next < 48 || input.next > 57) // No digit after + input.acceptToken(questionDot) } }, {contextual: true}) -export const template = new ExternalTokenizer(input => { - for (let afterDollar = false, i = 0;; i++) { - let {next} = input - if (next < 0) { - if (i) input.acceptToken(templateContent) - break - } else if (next == backtick) { - if (i) input.acceptToken(templateContent) - else input.acceptToken(templateEnd, 1) - break - } else if (next == braceL && afterDollar) { - if (i == 1) input.acceptToken(templateDollarBrace, 1) - else input.acceptToken(templateContent, -1) - break - } else if (next == 10 /* "\n" */ && i) { - // Break up template strings on lines, to avoid huge tokens - input.advance() - input.acceptToken(templateContent) - break - } else if (next == backslash) { +function identifierChar(ch, start) { + return ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122 || ch == 95 || ch >= 192 || + !start && ch >= 48 && ch <= 57 +} + +export const jsx = new ExternalTokenizer((input, stack) => { + if (input.next != lt || !stack.dialectEnabled(Dialect_jsx)) return + input.advance() + if (input.next == slash) return + // Scan for an identifier followed by a comma or 'extends', don't + // treat this as a start tag if present. + let back = 0 + while (space.indexOf(input.next) > -1) { input.advance(); back++ } + if (identifierChar(input.next, true)) { + input.advance() + back++ + while (identifierChar(input.next, false)) { input.advance(); back++ } + while (space.indexOf(input.next) > -1) { input.advance(); back++ } + if (input.next == comma) return + for (let i = 0;; i++) { + if (i == 7) { + if (!identifierChar(input.next, true)) return + break + } + if (input.next != "extends".charCodeAt(i)) break input.advance() + back++ } - afterDollar = next == dollar - input.advance() } + input.acceptToken(JSXStartTag, -back) }) - -export function tsExtends(value, stack) { - return value == "extends" && stack.dialectEnabled(Dialect_ts) ? TSExtends : -1 -} diff --git a/test/decorator.txt b/test/decorator.txt new file mode 100644 index 0000000..56679f7 --- /dev/null +++ b/test/decorator.txt @@ -0,0 +1,64 @@ +# Decorators on classes and class fields + +@d1 class Foo { + @d2 bar() {} + @d3 get baz() { return 1 } + @d4 quux = 1 +} + +==> + +Script(ClassDeclaration( + Decorator(VariableName), + class,VariableDefinition,ClassBody( + MethodDeclaration(Decorator(VariableName),PropertyDefinition,ParamList,Block), + MethodDeclaration(Decorator(VariableName),get,PropertyDefinition,ParamList,Block( + ReturnStatement(return,Number))), + PropertyDeclaration(Decorator(VariableName),PropertyDefinition,Equals,Number)))) + +# Multiple decorators + +@d1 @d2 class Y {} + +==> + +Script(ClassDeclaration(Decorator(VariableName),Decorator(VariableName),class,VariableDefinition,ClassBody)) + +# Member decorators + +@one.two class X {} + +==> + +Script(ClassDeclaration(Decorator(MemberExpression(VariableName,PropertyName)),class,VariableDefinition,ClassBody)) + +# Call decorators + +@d(2) @a.b() class Z {} + +==> + +Script(ClassDeclaration( + Decorator(CallExpression(VariableName,ArgList(Number))), + Decorator(CallExpression(MemberExpression(VariableName,PropertyName),ArgList)), + class,VariableDefinition,ClassBody)) + +# Parenthesized decorators + +@(a instanceof Array ? x : y)(2) class P {} + +==> + +Script(ClassDeclaration( + Decorator(CallExpression(ParenthesizedExpression( + ConditionalExpression(BinaryExpression(VariableName,instanceof,VariableName),LogicOp,VariableName,LogicOp,VariableName)), + ArgList(Number))), + class,VariableDefinition,ClassBody)) + +# Parameter decorators + +function foo(@d bar) {} + +==> + +Script(FunctionDeclaration(function,VariableDefinition,ParamList(Decorator(VariableName),VariableDefinition),Block)) diff --git a/test/expression.txt b/test/expression.txt index 438b2d9..2666aa7 100644 --- a/test/expression.txt +++ b/test/expression.txt @@ -18,11 +18,11 @@ line'; ==> -Script(ExpressionStatement(String), - ExpressionStatement(String), - ExpressionStatement(String), - ExpressionStatement(String), - ExpressionStatement(String)) +Script(ExpressionStatement(String(Escape,Escape)), + ExpressionStatement(String(Escape,Escape)), + ExpressionStatement(String(Escape)), + ExpressionStatement(String(Escape)), + ExpressionStatement(String(Escape))) # Numbers @@ -156,8 +156,8 @@ Script( ==> Script(ExpressionStatement(ParenthesizedExpression(ObjectExpression( - Property(PropertyNameDefinition,ArrowFunction(ParamList,Arrow,Number)), - Property(PropertyNameDefinition,String))))) + Property(PropertyDefinition,ArrowFunction(ParamList,Arrow,Number)), + Property(PropertyDefinition,String))))) # Long potential arrow function @@ -293,12 +293,16 @@ Script( # Yield expressions yield db.users.where('[endpoint+email]'); +yield* a; +yield [22]; ==> Script( - ExpressionStatement(UnaryExpression(yield, - CallExpression(MemberExpression(MemberExpression(VariableName,PropertyName),PropertyName),ArgList(String))))) + ExpressionStatement(YieldExpression(yield, + CallExpression(MemberExpression(MemberExpression(VariableName,PropertyName),PropertyName),ArgList(String)))), + ExpressionStatement(YieldExpression(yield,Star,VariableName)), + ExpressionStatement(YieldExpression(yield,ArrayExpression(Number)))) # Template strings @@ -316,7 +320,7 @@ Script( `$`; `$$$$${ async }`; -`\\`; +`\\\``; `one${`two${`three`}`}`; @@ -327,13 +331,17 @@ f`hi${there}`; Script( ExpressionStatement(TemplateString), ExpressionStatement(TemplateString), - ExpressionStatement(TemplateString(BinaryExpression(Number,ArithOp,Number),SequenceExpression(Number,Number))), + ExpressionStatement(TemplateString( + Interpolation(InterpolationStart,BinaryExpression(Number,ArithOp,Number),InterpolationEnd), + Interpolation(InterpolationStart,SequenceExpression(Number,Number),InterpolationEnd))), ExpressionStatement(TemplateString), ExpressionStatement(TemplateString), - ExpressionStatement(TemplateString(VariableName)), - ExpressionStatement(TemplateString), - ExpressionStatement(TemplateString(TemplateString(TemplateString))), - ExpressionStatement(TaggedTemplatExpression(VariableName,TemplateString(VariableName)))) + ExpressionStatement(TemplateString(Interpolation(InterpolationStart,VariableName,InterpolationEnd))), + ExpressionStatement(TemplateString(Escape,Escape)), + ExpressionStatement(TemplateString(Interpolation(InterpolationStart,TemplateString( + Interpolation(InterpolationStart,TemplateString,InterpolationEnd)),InterpolationEnd))), + ExpressionStatement(TaggedTemplateExpression(VariableName,TemplateString( + Interpolation(InterpolationStart,VariableName,InterpolationEnd))))) # Atoms @@ -368,11 +376,11 @@ foo({}, Script(ExpressionStatement(CallExpression(VariableName,ArgList( ObjectExpression, - ObjectExpression(Property(PropertyNameDefinition,String)), - ObjectExpression(Property(PropertyNameDefinition,String),Property(String,VariableName),Property(Number,Number)), - ObjectExpression(Property(PropertyNameDefinition),Property(VariableName,ParamList,Block)), - ObjectExpression(Property(PropertyNameDefinition),Property(PropertyNameDefinition)), - ObjectExpression(Property(PropertyNameDefinition)))))) + ObjectExpression(Property(PropertyDefinition,String)), + ObjectExpression(Property(PropertyDefinition,String),Property(String,VariableName),Property(Number,Number)), + ObjectExpression(Property(PropertyDefinition),Property(VariableName,ParamList,Block)), + ObjectExpression(Property(PropertyDefinition),Property(PropertyDefinition)), + ObjectExpression(Property(PropertyDefinition)))))) # Method definitions @@ -395,14 +403,14 @@ Script(ExpressionStatement(CallExpression(VariableName,ArgList( ==> Script(ExpressionStatement(ParenthesizedExpression(ObjectExpression( - Property(PropertyNameDefinition,BooleanLiteral), - Property(PropertyNameDefinition,ParamList(VariableDefinition,VariableDefinition), + Property(PropertyDefinition,BooleanLiteral), + Property(PropertyDefinition,ParamList(VariableDefinition,VariableDefinition), Block(ReturnStatement(return,BinaryExpression(VariableName,ArithOp,VariableName)))), - Property(get,PropertyNameDefinition,ParamList,Block(ReturnStatement(return,VariableName))), - Property(set,PropertyNameDefinition,ParamList(VariableDefinition), + Property(get,PropertyDefinition,ParamList,Block(ReturnStatement(return,VariableName))), + Property(set,PropertyDefinition,ParamList(VariableDefinition), Block(ExpressionStatement(AssignmentExpression(VariableName,Equals,VariableName)))), - Property(Star,PropertyNameDefinition,ParamList,Block(ExpressionStatement(UnaryExpression(yield,VariableName)))), - Property(PropertyNameDefinition,ParamList,Block(ReturnStatement(return,Number))))))) + Property(Star,PropertyDefinition,ParamList,Block(ExpressionStatement(YieldExpression(yield,VariableName)))), + Property(PropertyDefinition,ParamList,Block(ReturnStatement(return,Number))))))) # Keyword property names @@ -418,12 +426,12 @@ Script(ExpressionStatement(ParenthesizedExpression(ObjectExpression( ==> Script(ExpressionStatement(ParenthesizedExpression(ObjectExpression( - Property(PropertyNameDefinition,ParamList,Block), - Property(PropertyNameDefinition,ParamList,Block), - Property(PropertyNameDefinition,FunctionExpression(function,ParamList,Block)), - Property(PropertyNameDefinition,ParamList,Block), - Property(PropertyNameDefinition,BooleanLiteral), - Property(PropertyNameDefinition,BooleanLiteral))))) + Property(PropertyDefinition,ParamList,Block), + Property(PropertyDefinition,ParamList,Block), + Property(PropertyDefinition,FunctionExpression(function,ParamList,Block)), + Property(PropertyDefinition,ParamList,Block), + Property(PropertyDefinition,BooleanLiteral), + Property(PropertyDefinition,BooleanLiteral))))) # Generator functions @@ -441,7 +449,7 @@ Script(ExpressionStatement(ArrayExpression( FunctionExpression(function,Star,ParamList,Block), FunctionExpression(function,Star,VariableDefinition,ParamList(VariableDefinition,VariableDefinition),Block( ExpressionStatement(VariableName), - ExpressionStatement(UnaryExpression(yield,VariableName))))))) + ExpressionStatement(YieldExpression(yield,VariableName))))))) # Member expressions @@ -516,8 +524,8 @@ await asyncPromise; ==> Script( - ExpressionStatement(UnaryExpression(await,CallExpression(VariableName,ArgList))), - ExpressionStatement(UnaryExpression(await,VariableName))) + ExpressionStatement(AwaitExpression(await,CallExpression(VariableName,ArgList))), + ExpressionStatement(AwaitExpression(await,VariableName))) # Numeric operators @@ -642,7 +650,7 @@ c = {d: (3, 4 + 5)}; Script( ExpressionStatement(SequenceExpression(AssignmentExpression(VariableName,Equals,Number),AssignmentExpression(VariableName,Equals,Number))), ExpressionStatement(AssignmentExpression(VariableName,Equals,ObjectExpression( - Property(PropertyNameDefinition,ParenthesizedExpression(SequenceExpression(Number,BinaryExpression(Number,ArithOp,Number)))))))) + Property(PropertyDefinition,ParenthesizedExpression(SequenceExpression(Number,BinaryExpression(Number,ArithOp,Number)))))))) # Punctuation @@ -668,3 +676,11 @@ Script(ExpressionStatement(ConditionalExpression(Number,LogicOp,Number,⚠))) ==> Script(ExpressionStatement(TemplateString(⚠))) + +# Ternary with leading-dot number + +a?.2:.3 + +==> + +Script(ExpressionStatement(ConditionalExpression(VariableName,LogicOp,Number,LogicOp,Number))) diff --git a/test/jsx.txt b/test/jsx.txt index 47e5eaf..837d939 100644 --- a/test/jsx.txt +++ b/test/jsx.txt @@ -4,7 +4,7 @@ ==> -Script(ExpressionStatement(JSXElement(JSXSelfClosingTag(JSXStartTag,JSXIdentifier,JSXSelfCloseEndTag)))) +Script(ExpressionStatement(JSXElement(JSXSelfClosingTag(JSXStartTag,JSXBuiltin(JSXIdentifier),JSXSelfCloseEndTag)))) # Regular element {"dialect": "jsx"} @@ -53,7 +53,7 @@ Script(ExpressionStatement(JSXElement( ==> Script(ExpressionStatement(JSXElement( - JSXOpenTag(JSXStartTag, JSXIdentifier, JSXEndTag), + JSXOpenTag(JSXStartTag, JSXBuiltin(JSXIdentifier), JSXEndTag), JSXElement( JSXOpenTag(JSXStartTag, JSXMemberExpression(JSXIdentifier, JSXIdentifier), JSXEndTag), JSXText, @@ -61,11 +61,11 @@ Script(ExpressionStatement(JSXElement( JSXEscape(VariableName), JSXText, JSXEscape(Spread, VariableName), - JSXCloseTag(JSXStartCloseTag, JSXIdentifier, JSXEndTag)))) + JSXCloseTag(JSXStartCloseTag, JSXBuiltin(JSXIdentifier), JSXEndTag)))) # Attributes {"dialect": "jsx"} - + ==> diff --git a/test/statement.txt b/test/statement.txt index c8fd5b0..4bf28d8 100644 --- a/test/statement.txt +++ b/test/statement.txt @@ -34,7 +34,7 @@ async (a) => { return foo; }; Script( FunctionDeclaration(async,function,VariableDefinition,ParamList,Block), - ClassDeclaration(class,VariableDefinition,ClassBody(MethodDeclaration(async,PropertyNameDefinition,ParamList,Block))), + ClassDeclaration(class,VariableDefinition,ClassBody(MethodDeclaration(async,PropertyDefinition,ParamList,Block))), ExpressionStatement(ArrowFunction(async,ParamList(VariableDefinition),Arrow,Block(ReturnStatement(return,VariableName))))) # If statements @@ -97,10 +97,10 @@ try { 1; } catch (x) { 2; } finally { 3; } ==> Script( - TryStatement(try,Block(ThrowStatement(throw,NewExpression(new,VariableName))),catch,Block), + TryStatement(try,Block(ThrowStatement(throw,NewExpression(new,VariableName))),CatchClause(catch,Block)), TryStatement(try,Block(ExpressionStatement(Number)), - catch,VariableDefinition,Block(ExpressionStatement(Number)), - finally,Block(ExpressionStatement(Number)))) + CatchClause(catch,VariableDefinition,Block(ExpressionStatement(Number))), + FinallyClause(finally,Block(ExpressionStatement(Number))))) # Switch @@ -176,18 +176,59 @@ class Foo { class Foo extends require('another-class') { constructor() { super(); } bar() { super.a(); } + prop; + etc = 20; + static { f() } } ==> Script( ClassDeclaration(class,VariableDefinition,ClassBody( - MethodDeclaration(static,PropertyNameDefinition,ParamList(VariableDefinition),Block(ReturnStatement(return,VariableName))), - MethodDeclaration(PropertyNameDefinition,ParamList(VariableDefinition),Block(ReturnStatement(return,VariableName))), - MethodDeclaration(PropertyNameDefinition,ParamList,Block))), + MethodDeclaration(static,PropertyDefinition,ParamList(VariableDefinition),Block(ReturnStatement(return,VariableName))), + MethodDeclaration(PropertyDefinition,ParamList(VariableDefinition),Block(ReturnStatement(return,VariableName))), + MethodDeclaration(PropertyDefinition,ParamList,Block))), ClassDeclaration(class,VariableDefinition,extends,CallExpression(VariableName,ArgList(String)),ClassBody( - MethodDeclaration(PropertyNameDefinition,ParamList,Block(ExpressionStatement(CallExpression(super,ArgList)))), - MethodDeclaration(PropertyNameDefinition,ParamList,Block(ExpressionStatement(CallExpression(MemberExpression(super,PropertyName),ArgList))))))) + MethodDeclaration(PropertyDefinition,ParamList,Block(ExpressionStatement(CallExpression(super,ArgList)))), + MethodDeclaration(PropertyDefinition,ParamList,Block(ExpressionStatement(CallExpression(MemberExpression(super,PropertyName),ArgList)))), + PropertyDeclaration(PropertyDefinition), + PropertyDeclaration(PropertyDefinition,Equals,Number), + StaticBlock(static, Block(ExpressionStatement(CallExpression(VariableName,ArgList))))))) + +# Private properties + +class Foo { + #bar() { this.#a() + this?.#prop == #prop in this; } + #prop; + #etc = 20; +} + +==> + +Script(ClassDeclaration(class,VariableDefinition,ClassBody( + MethodDeclaration(PrivatePropertyDefinition,ParamList,Block( + ExpressionStatement(BinaryExpression( + BinaryExpression( + CallExpression(MemberExpression(this,PrivatePropertyName),ArgList), + ArithOp, + MemberExpression(this,PrivatePropertyName)), + CompareOp, + BinaryExpression(PrivatePropertyName, in, this))))), + PropertyDeclaration(PrivatePropertyDefinition), + PropertyDeclaration(PrivatePropertyDefinition,Equals,Number)))) + +# Computed properties + +class Foo { + [x] = 44; + [Symbol.iterator]() {} +} + +==> + +Script(ClassDeclaration(class,VariableDefinition,ClassBody( + PropertyDeclaration(VariableName,Equals,Number), + MethodDeclaration(MemberExpression(VariableName,PropertyName),ParamList,Block)))) # Imports @@ -197,6 +238,8 @@ import { member } from "module-name"; import { member1, member2 as alias2 } from "module-name"; import defaultMember, { member1, member2 as alias2, } from "module-name"; import "module-name"; +import defer x from "y"; +import defer from "y"; ==> @@ -206,7 +249,9 @@ Script( ImportDeclaration(import,ImportGroup(VariableDefinition),from,String), ImportDeclaration(import,ImportGroup(VariableDefinition,VariableName,as,VariableDefinition),from,String), ImportDeclaration(import,VariableDefinition,ImportGroup(VariableDefinition,VariableName,as,VariableDefinition),from,String), - ImportDeclaration(import,String)) + ImportDeclaration(import,String), + ImportDeclaration(import,defer,VariableDefinition,from,String), + ImportDeclaration(import,VariableDefinition,from,String)) # Exports @@ -271,7 +316,7 @@ Script( # Recover from invalid char -const {foo#bar} = {}; +const {foobar} = {}; ==> @@ -293,3 +338,67 @@ function g() {} Script( FunctionDeclaration(function,VariableDefinition,ParamList,Block(ExpressionStatement(CallExpression(VariableName,ArgList(...))))), FunctionDeclaration(function,VariableDefinition,ParamList,Block)) + +# Destructuring + +({x} = y); +[u, v] = w; +let [a,, b = 0] = c; +let {x, y: z = 1} = d; +let {[f]: m} = e; + +==> + +Script( + ExpressionStatement(ParenthesizedExpression(AssignmentExpression( + ObjectPattern(PatternProperty(PropertyName)),Equals,VariableName))), + ExpressionStatement(AssignmentExpression(ArrayPattern(VariableDefinition,VariableDefinition),Equals,VariableName)), + VariableDeclaration(let,ArrayPattern(VariableDefinition,VariableDefinition,Equals,Number),Equals,VariableName), + VariableDeclaration(let,ObjectPattern( + PatternProperty(PropertyName), + PatternProperty(PropertyName,VariableDefinition,Equals,Number) + ),Equals,VariableName), + VariableDeclaration(let,ObjectPattern(PatternProperty(VariableName,VariableDefinition)),Equals,VariableName)) + +# Generators + +function* foo() { yield 1 } + +class B { + *method() {} +} + +({*x() {}}) + +==> + +Script( + FunctionDeclaration(function,Star,VariableDefinition,ParamList,Block( + ExpressionStatement(YieldExpression(yield,Number)))), + ClassDeclaration(class,VariableDefinition,ClassBody( + MethodDeclaration(Star,PropertyDefinition,ParamList,Block))), + ExpressionStatement(ParenthesizedExpression(ObjectExpression(Property(Star,PropertyDefinition,ParamList,Block))))) + +# Hashbang + +#!/bin/env node +foo() + +==> + +Script(Hashbang,ExpressionStatement(CallExpression(VariableName,ArgList))) + +# new.target + +function MyObj() { + if (!new.target) { + throw new Error('Must construct MyObj with new'); + } +} + +==> + +Script( + FunctionDeclaration(function,VariableDefinition,ParamList,Block( + IfStatement(if,ParenthesizedExpression(UnaryExpression(LogicOp,NewTarget(new,PropertyName))), Block( + ThrowStatement(throw,NewExpression(new,VariableName,ArgList(String)))))))) diff --git a/test/test-javascript.js b/test/test-javascript.js index bf7fcc1..21ba880 100644 --- a/test/test-javascript.js +++ b/test/test-javascript.js @@ -1,9 +1,9 @@ -import {parser} from "../dist/index.es.js" +import {parser} from "../dist/index.js" import {fileTests} from "@lezer/generator/dist/test" import * as fs from "fs" import * as path from "path" -import { fileURLToPath } from 'url'; +import {fileURLToPath} from "url" let caseDir = path.dirname(fileURLToPath(import.meta.url)) for (let file of fs.readdirSync(caseDir)) { diff --git a/test/typescript.txt b/test/typescript.txt index a3cb464..3a740a7 100644 --- a/test/typescript.txt +++ b/test/typescript.txt @@ -1,3 +1,16 @@ +# Undefined and Null Type {"dialect": "ts"} + +let x: undefined +let y: null + +==> + +Script( + VariableDeclaration(let,VariableDefinition,TypeAnnotation( + TypeName)), + VariableDeclaration(let,VariableDefinition,TypeAnnotation( + NullType(null)))) + # Type declaration {"dialect": "ts"} function foo(a: number, b: "literal" | Map): RegExp[] {} @@ -13,11 +26,17 @@ Script(FunctionDeclaration(function, VariableDefinition, ParamList( function isFoo(foo: any): foo is Foo { return true } +function assertFoo(foo: any): asserts foo is "string" { return true } + ==> -Script(FunctionDeclaration(function, VariableDefinition, ParamList( - VariableDefinition, TypeAnnotation(TypeName) -), TypePredicate(VariableName, is, TypeName), Block(ReturnStatement(return, BooleanLiteral)))) +Script( + FunctionDeclaration(function, VariableDefinition, ParamList( + VariableDefinition, TypeAnnotation(TypeName) + ), TypePredicate(VariableName, is, TypeName), Block(ReturnStatement(return, BooleanLiteral))), + FunctionDeclaration(function,VariableDefinition,ParamList( + VariableDefinition,TypeAnnotation(TypeName) + ),TypePredicate(asserts,VariableName,is,LiteralType(String)),Block(ReturnStatement(return,BooleanLiteral)))) # Type alias {"dialect": "ts"} @@ -48,11 +67,11 @@ interface Foo { ==> Script(InterfaceDeclaration(interface, TypeDefinition, ObjectType( - PropertyType(readonly, PropertyNameDefinition, TypeAnnotation(TypeName)), - MethodType(PropertyNameDefinition, ParamList(VariableDefinition, TypeAnnotation(TypeName)), TypeAnnotation(VoidType(void))), + PropertyType(readonly, PropertyDefinition, TypeAnnotation(TypeName)), + MethodType(PropertyDefinition, ParamList(VariableDefinition, TypeAnnotation(TypeName)), TypeAnnotation(VoidType(void))), CallSignature(ParamList(VariableDefinition, TypeAnnotation(TypeName)), TypeAnnotation(TypeName)), NewSignature(new,ParamList, TypeAnnotation(TypeName)), - IndexSignature(readonly, PropertyNameDefinition, TypeAnnotation(TypeName), TypeAnnotation(TypeName))))) + IndexSignature(readonly, PropertyDefinition, TypeAnnotation(TypeName), TypeAnnotation(TypeName))))) # Call type args {"dialect": "ts"} @@ -63,9 +82,9 @@ x < 10 > 5 Script( ExpressionStatement(BinaryExpression( - CallExpression(VariableName, TypeArgList(TypeName, TypeName), ArgList), + CallExpression(InstantiationExpression(VariableName, TypeArgList(TypeName, TypeName)), ArgList), ArithOp, - NewExpression(new, VariableName, TypeArgList(LiteralType(Number)), ArgList))), + NewExpression(new, InstantiationExpression(VariableName, TypeArgList(LiteralType(Number))), ArgList))), ExpressionStatement(BinaryExpression(BinaryExpression(VariableName, CompareOp, Number), CompareOp, Number))) # Advanced types {"dialect": "ts"} @@ -78,13 +97,29 @@ let f: (x: number) => boolean Script( VariableDeclaration(let, VariableDefinition, TypeAnnotation( - UnionType(UnionType(TypeofType(typeof, MemberExpression(VariableName, PropertyName)), LogicOp, - IntersectionType(KeyofType(keyof, TypeName), LogicOp, IndexedType(TypeName, String))), + UnionType(TypeofType(typeof, MemberExpression(VariableName, PropertyName)), LogicOp, + IntersectionType(KeyofType(keyof, TypeName), LogicOp, IndexedType(TypeName, LiteralType(String))), LogicOp, ParameterizedType(TypeName, TypeArgList(TypeName))))), VariableDeclaration(let, VariableDefinition, TypeAnnotation(TupleType(TypeName, TypeName))), VariableDeclaration(let, VariableDefinition, TypeAnnotation(FunctionSignature( ParamList(VariableDefinition, TypeAnnotation(TypeName)), Arrow, TypeName)))) +# Prefix union/intersection + +let x: + | A + | B + | C +let y: & RegExp & (& Date) + +==> + +Script( + VariableDeclaration(let,VariableDefinition,TypeAnnotation( + UnionType(LogicOp,TypeName,LogicOp,TypeName,LogicOp,TypeName))), + VariableDeclaration(let,VariableDefinition,TypeAnnotation( + IntersectionType(LogicOp,TypeName,LogicOp,ParenthesizedType(IntersectionType(LogicOp,TypeName)))))) + # Prefix cast {"dialect": "ts"} foo @@ -100,9 +135,9 @@ Script(ExpressionStatement(PrefixCast(TypeName, VariableName))) ==> Script(ExpressionStatement(JSXElement( - JSXOpenTag(JSXStartTag, JSXIdentifier, JSXEndTag), + JSXOpenTag(JSXStartTag, JSXBuiltin(JSXIdentifier), JSXEndTag), JSXText, - JSXCloseTag(JSXStartCloseTag, JSXIdentifier, JSXEndTag)))) + JSXCloseTag(JSXStartCloseTag, JSXBuiltin(JSXIdentifier), JSXEndTag)))) # Class definition {"dialect": "ts"} @@ -117,16 +152,16 @@ class Foo extends Bar implements Stuff { Script(ClassDeclaration( class, VariableDefinition, TypeParamList(TypeDefinition), - extends ParameterizedType(TypeName, TypeArgList(TypeName)), + extends, VariableName, TypeArgList(TypeName), implements TypeName, ClassBody( - PropertyDeclaration(PropertyNameDefinition, TypeAnnotation(TypeName)), - PropertyDeclaration(Privacy, readonly, PropertyNameDefinition, TypeAnnotation(TypeName), Equals, String), - MethodDeclaration(PropertyNameDefinition, ParamList( + PropertyDeclaration(PropertyDefinition, TypeAnnotation(TypeName)), + PropertyDeclaration(Privacy, readonly, PropertyDefinition, TypeAnnotation(TypeName), Equals, String), + MethodDeclaration(PropertyDefinition, ParamList( readonly, VariableDefinition, TypeAnnotation(TypeName), Privacy, VariableDefinition, TypeAnnotation(TypeName), VariableDefinition, TypeAnnotation(TypeName)), Block), - MethodDeclaration(Privacy, static, PropertyNameDefinition, ParamList, TypeAnnotation(VoidType(void)), Block)))) + MethodDeclaration(Privacy, static, PropertyDefinition, ParamList, TypeAnnotation(VoidType(void)), Block)))) # Arrow with type params {"dialect": "ts"} @@ -148,4 +183,219 @@ type Tmpl = `${string} ${5}` | `one ${Two}` ==> Script(TypeAliasDeclaration(type, TypeDefinition, TypeParamList(TypeDefinition), Equals, - UnionType(TemplateType(TypeName, LiteralType(Number)), LogicOp, TemplateType(TypeName)))) + UnionType(TemplateType(Interpolation(InterpolationStart,TypeName,InterpolationEnd), Interpolation(InterpolationStart,LiteralType(Number),InterpolationEnd)), LogicOp, TemplateType(Interpolation(InterpolationStart,TypeName,InterpolationEnd))))) + +# Extending complex types {"dialect": "ts"} + +class Foo extends A.B {} + +==> + +Script(ClassDeclaration(class, VariableDefinition, + extends, MemberExpression(VariableName, PropertyName), TypeArgList(TypeName), + ClassBody)) + +# Object type {"dialect": "ts"} + +type A = {a: number, b: number} +type B = {a: number; b: number;} + +==> + +Script( + TypeAliasDeclaration(type,TypeDefinition,Equals,ObjectType( + PropertyType(PropertyDefinition,TypeAnnotation(TypeName)), + PropertyType(PropertyDefinition,TypeAnnotation(TypeName)))), + TypeAliasDeclaration(type,TypeDefinition,Equals,ObjectType( + PropertyType(PropertyDefinition,TypeAnnotation(TypeName)), + PropertyType(PropertyDefinition,TypeAnnotation(TypeName))))) + +# Conditional Type {"dialect": "ts"} + +type X = T extends E ? number : A + +==> + +Script( + TypeAliasDeclaration(type,TypeDefinition,TypeParamList(TypeDefinition),Equals, + ConditionalType(TypeName,extends,TypeName,LogicOp,TypeName,LogicOp,TypeName))) + +# Generic Function Type {"dialect": "ts"} + +let f: () => T + +==> + +Script( + VariableDeclaration(let,VariableDefinition,TypeAnnotation( + FunctionSignature(TypeParamList(TypeDefinition),ParamList,Arrow,TypeName)))) + +# Satisfies operator {"dialect": "ts"} + +let x = 1 satisfies number + +==> + +Script(VariableDeclaration(let,VariableDefinition,Equals,BinaryExpression(Number,satisfies,TypeName))) + +# Override modifier on properties {"dialect": "ts"} + +class A { + override accessor a; + static override b = 1; + override c = 2; +} + +==> + +Script(ClassDeclaration(class,VariableDefinition,ClassBody( + PropertyDeclaration(override,accessor,PropertyDefinition), + PropertyDeclaration(static,override,PropertyDefinition,Equals,Number), + PropertyDeclaration(override,PropertyDefinition,Equals,Number)))) + +# Class extending expression {"dialect": "ts"} + +class X extends class {} {} + +==> + +Script(ClassDeclaration(class,VariableDefinition,extends,ClassExpression(class,ClassBody),ClassBody)) + +# Declare syntax {"dialect": "ts"} + +declare namespace myLib { + function makeGreeting(s: string): string; + let numberOfGreetings: number; +} + +declare function greet(setting: GreetingSettings): void; + +declare class Greeter { + constructor(greeting: string); + greeting: string; + showGreeting(): void; +} + +class X { + declare foo(); + declare bar: number; +} + +==> + +Script( + AmbientDeclaration(declare,NamespaceDeclaration(namespace,VariableDefinition,Block( + FunctionDeclaration(function,VariableDefinition,ParamList(VariableDefinition,TypeAnnotation(TypeName)), + TypeAnnotation(TypeName)), + VariableDeclaration(let,VariableDefinition,TypeAnnotation(TypeName))))), + AmbientDeclaration(declare,AmbientFunctionDeclaration(function,VariableDefinition, + ParamList(VariableDefinition,TypeAnnotation(TypeName)),TypeAnnotation(VoidType(void)))), + AmbientDeclaration(declare,ClassDeclaration(class,VariableDefinition,ClassBody( + MethodDeclaration(PropertyDefinition,ParamList(VariableDefinition,TypeAnnotation(TypeName))), + PropertyDeclaration(PropertyDefinition,TypeAnnotation(TypeName)), + MethodDeclaration(PropertyDefinition,ParamList,TypeAnnotation(VoidType(void)))))), + ClassDeclaration(class,VariableDefinition,ClassBody( + MethodDeclaration(declare,PropertyDefinition,ParamList), + PropertyDeclaration(declare,PropertyDefinition,TypeAnnotation(TypeName))))) + +# Declare this in a Function {"dialect": "ts"} + +function foo(this: User) {} + +==> + +Script(FunctionDeclaration(function,VariableDefinition,ParamList(this,TypeAnnotation(TypeName)),Block)) + +# Prefers type parameters to comparison operators {"dialect": "ts jsx"} + +let a = useState(1) +return 2 + +==> + +Script( + VariableDeclaration(let,VariableDefinition,Equals, + CallExpression(InstantiationExpression(VariableName,TypeArgList(TypeName)),ArgList(Number))), + ReturnStatement(return,Number)) + +# Type parameters vs JSX {"dialect": "jsx ts"} + +let a = (f) => null +let b = () => 1 + +==> + +Script( + VariableDeclaration(let,VariableDefinition,Equals,ArrowFunction( + TypeParamList(TypeDefinition,extends,TypeName),ParamList(VariableDefinition),Arrow,null)), + VariableDeclaration(let,VariableDefinition,Equals,ArrowFunction( + TypeParamList(TypeDefinition),ParamList,Arrow,Number))) + +# Destructured parameters in function signature {"dialect": "ts"} + +type F = ([a, b]: [number, number]) => void + +==> + +Script(TypeAliasDeclaration(type,TypeDefinition,Equals,FunctionSignature( + ParamList(ArrayPattern(VariableDefinition,VariableDefinition),TypeAnnotation(TupleType(TypeName,TypeName))), + Arrow, + VoidType(void)))) + +# Instantiated expression {"dialect": "ts"} + +let x = a; + +type Foo = Bar>>; + +==> + +Script( + VariableDeclaration(let,VariableDefinition,Equals,InstantiationExpression(VariableName,TypeArgList(TypeName))), + TypeAliasDeclaration(type,TypeDefinition,Equals,ParameterizedType(TypeName,TypeArgList( + TypeofType(typeof,InstantiationExpression(VariableName,TypeArgList( + ParameterizedType(TypeName,TypeArgList(TypeName))))))))) + +# Not instantiated {"dialect": "ts"} + +let x = ac + +==> + +Script(VariableDeclaration(let,VariableDefinition,Equals,BinaryExpression( + BinaryExpression(VariableName,CompareOp,VariableName),CompareOp,VariableName))) + +# Allows computed properties in types {"dialect": "ts"} + +interface X { + [Symbol.iterator](): Iterator + [1]: string +} + +==> + +Script(InterfaceDeclaration(interface,TypeDefinition,ObjectType( + MethodType(MemberExpression(VariableName,PropertyName),ParamList, + TypeAnnotation(ParameterizedType(TypeName,TypeArgList(TypeName)))), + PropertyType(Number,TypeAnnotation(TypeName))))) + +# Binary type operators {"dialect": "ts"} + +log(foo as number, {} satisfies AbstractObjectFactory) + +==> + +Script(ExpressionStatement(CallExpression(VariableName,ArgList( + BinaryExpression(VariableName,as,TypeName), + BinaryExpression(ObjectExpression,satisfies,ParameterizedType(TypeName,TypeArgList(TypeName))))))) + +# Allows this parameters in function types {"dialect": "ts"} + +let x: (this: X, expression: string) => Promise + +==> + +Script(VariableDeclaration(let,VariableDefinition,TypeAnnotation(FunctionSignature( + ParamList(this,TypeAnnotation(TypeName),VariableDefinition,TypeAnnotation(TypeName)), + Arrow, + ParameterizedType(TypeName,TypeArgList(ArrayType(TypeName)))))))