diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 33b3a004..a0ee9282 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,6 @@ { "recommendations": [ - "prettier.prettier-vscode", + "esbenp.prettier-vscode", "editorconfig.editorconfig", "dbaeumer.vscode-eslint", "streetsidesoftware.code-spell-checker" diff --git a/.vscode/settings.json b/.vscode/settings.json index 87a16267..61cd6013 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,7 @@ "editor.codeActionsOnSave": ["source.fixAll.eslint"] }, "[javascript][typescript][markdown][json][jsonc][json5][yaml]": { - "editor.defaultFormatter": "prettier.prettier-vscode", + "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true }, "editor.codeActionsOnSave": { diff --git a/package.json b/package.json index c72f5849..aa57aee4 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "release": "release-it" }, "devDependencies": { - "@angular/compiler": "21.1.0", + "@angular/compiler": "21.2.0-next.0", "@babel/code-frame": "8.0.0-beta.4", "@babel/parser": "8.0.0-beta.4", "@babel/types": "8.0.0-beta.4", @@ -54,7 +54,7 @@ "vitest": "4.0.17" }, "peerDependencies": { - "@angular/compiler": ">=21.0.7 || >= 21.1.0-0" + "@angular/compiler": ">=21.0.7 || >= 21.2.0-0" }, "engines": { "node": ">= 20" diff --git a/src/ast-transform/node-transformer.ts b/src/ast-transform/node-transformer.ts index 134aa235..a9f3206c 100644 --- a/src/ast-transform/node-transformer.ts +++ b/src/ast-transform/node-transformer.ts @@ -1,15 +1,11 @@ -import { - type AST, - EmptyExpr, - ParenthesizedExpression, -} from '@angular/compiler'; +import { type AST, ParenthesizedExpression } from '@angular/compiler'; import { type IncompleteNode, type RawLocationInformation, Source, } from '../source.ts'; -import type { NGEmptyExpression, NGNode } from './node-types.ts'; +import type { NGNode } from './node-types.ts'; import { transformVisitors } from './visitors.ts'; export class NodeTransformer extends Source { @@ -62,10 +58,6 @@ export class NodeTransformer extends Source { transform() { const { node } = this; - if (node instanceof EmptyExpr) { - return this.create({ type: 'NGEmptyExpression' }) as T; - } - const properties = node.visit(transformVisitors, this); return this.create(properties, this.node) as T; } diff --git a/src/ast-transform/transforms/index.ts b/src/ast-transform/transforms/index.ts index bc7d4b9f..541f7c9d 100644 --- a/src/ast-transform/transforms/index.ts +++ b/src/ast-transform/transforms/index.ts @@ -1,9 +1,11 @@ export * from './transform-array-expression.ts'; +export * from './transform-arrow-function-expression.ts'; export * from './transform-ast-with-source.ts'; export * from './transform-binary-expression.ts'; export * from './transform-call-expression.ts'; export * from './transform-chained-expression.ts'; export * from './transform-conditional-expression.ts'; +export * from './transform-empty-expression.ts'; export * from './transform-interpolation.ts'; export * from './transform-literal.ts'; export * from './transform-member-expression.ts'; diff --git a/src/ast-transform/transforms/transform-arrow-function-expression.ts b/src/ast-transform/transforms/transform-arrow-function-expression.ts new file mode 100644 index 00000000..10cf33eb --- /dev/null +++ b/src/ast-transform/transforms/transform-arrow-function-expression.ts @@ -0,0 +1,26 @@ +import { type ArrowFunction, type AstVisitor } from '@angular/compiler'; +import type * as babel from '@babel/types'; + +import { type NodeTransformer } from '../node-transformer.ts'; + +const commonProperties = { + id: null, + generator: false, + async: false, + expression: true, +} as const; + +export const visitArrowFunction: AstVisitor['visitArrowFunction'] = ( + node: ArrowFunction, + transformer: NodeTransformer, +): babel.ArrowFunctionExpression & { id: null } => ({ + type: 'ArrowFunctionExpression', + params: node.parameters.map((parameter) => + transformer.createNode( + { type: 'Identifier', name: parameter.name }, + parameter.sourceSpan, + ), + ), + body: transformer.transformChild(node.body), + ...commonProperties, +}); diff --git a/src/ast-transform/transforms/transform-empty-expression.ts b/src/ast-transform/transforms/transform-empty-expression.ts new file mode 100644 index 00000000..f2c2f8b6 --- /dev/null +++ b/src/ast-transform/transforms/transform-empty-expression.ts @@ -0,0 +1,6 @@ +import type { NGEmptyExpression } from '../../types.ts'; + +export const visitEmptyExpr = (): Omit< + NGEmptyExpression, + 'start' | 'end' | 'range' +> => ({ type: 'NGEmptyExpression' }); diff --git a/tests/helpers.ts b/tests/helpers.ts index 983daced..46a22eac 100644 --- a/tests/helpers.ts +++ b/tests/helpers.ts @@ -46,6 +46,13 @@ export function massageAst(ast: any, parser: 'babel' | 'angular'): any { delete ast.extra.trailingComma; } + if ( + ast.type === 'ArrowFunctionExpression' && + !Object.hasOwn(ast, 'expression') + ) { + ast.expression = ast.body.type !== 'BlockStatement'; + } + delete ast.loc; } diff --git a/tests/transform.test.ts b/tests/transform.test.ts index 856d2ca2..4c8d2e0c 100644 --- a/tests/transform.test.ts +++ b/tests/transform.test.ts @@ -42,6 +42,11 @@ const testCases: TestCase[] = [ expectedEstreeType: 'BinaryExpression', text: ' ( ( ( ( a ) ) in ( ( b ) ) ) ) ', }, + { + expectedAngularType: 'Binary', + expectedEstreeType: 'BinaryExpression', + text: ' ( ( ( ( a ) ) instanceof ( ( b ) ) ) ) ', + }, { expectedAngularType: 'Binary', expectedEstreeType: 'LogicalExpression', @@ -495,6 +500,16 @@ const testCases: TestCase[] = [ expectedEstreeType: 'ObjectExpression', text: ' ( ( {foo: tag ` a ${ b } ` } ) ) ', }, + { + expectedAngularType: 'ArrowFunction', + expectedEstreeType: 'ArrowFunctionExpression', + text: ' ( ( () => ( ( 1 ) ) ) ) ', + }, + { + expectedAngularType: 'ArrowFunction', + expectedEstreeType: 'ArrowFunctionExpression', + text: ' ( ( (a, b ) => ( ( 1 ) ) ) ) ', + }, ]; const IS_CI = Boolean(process.env.CI); diff --git a/yarn.lock b/yarn.lock index 768b3b54..e734d005 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,12 +5,12 @@ __metadata: version: 8 cacheKey: 10 -"@angular/compiler@npm:21.1.0": - version: 21.1.0 - resolution: "@angular/compiler@npm:21.1.0" +"@angular/compiler@npm:21.2.0-next.0": + version: 21.2.0-next.0 + resolution: "@angular/compiler@npm:21.2.0-next.0" dependencies: tslib: "npm:^2.3.0" - checksum: 10/1f409c20eb36079719e004f9e683a41d9d9fd975d814132faa28f941a0d491ba392c7cca92061f8dbe540bd922cac905f76ccab48a87c82c764b3b7cdb6b28dd + checksum: 10/61e5c75eff50de8ffcb3098fbbab7dbe3da885db5939d99965ab54cab1649771dc35dd57de0c7af0031a410f273afaac436ee66c63c639eb455175d38311b74a languageName: node linkType: hard @@ -1671,7 +1671,7 @@ __metadata: version: 0.0.0-use.local resolution: "angular-estree-parser@workspace:." dependencies: - "@angular/compiler": "npm:21.1.0" + "@angular/compiler": "npm:21.2.0-next.0" "@babel/code-frame": "npm:8.0.0-beta.4" "@babel/parser": "npm:8.0.0-beta.4" "@babel/types": "npm:8.0.0-beta.4" @@ -1692,7 +1692,7 @@ __metadata: typescript-eslint: "npm:8.53.0" vitest: "npm:4.0.17" peerDependencies: - "@angular/compiler": ">=21.0.7 || >= 21.1.0-0" + "@angular/compiler": ">=21.0.7 || >= 21.2.0-0" languageName: unknown linkType: soft