From eae9a65111f40cbc82748bf9379baa72521b88d7 Mon Sep 17 00:00:00 2001 From: fisker <lionkay@gmail.com> Date: Wed, 16 Apr 2025 23:47:54 +0800 Subject: [PATCH 1/2] feat: support Angular selectorless syntax --- .../.vscode/extensions.json | 8 ++ .../angular-html-parser/.vscode/settings.json | 12 +++ packages/angular-html-parser/src/index.ts | 7 ++ .../angular-html-parser/test/index_spec.ts | 86 ++++++++++++++++++- 4 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 packages/angular-html-parser/.vscode/extensions.json create mode 100644 packages/angular-html-parser/.vscode/settings.json diff --git a/packages/angular-html-parser/.vscode/extensions.json b/packages/angular-html-parser/.vscode/extensions.json new file mode 100644 index 0000000000000..d85e4793e8b2a --- /dev/null +++ b/packages/angular-html-parser/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "esbenp.prettier-vscode", + "editorconfig.editorconfig", + // "dbaeumer.vscode-eslint", + "streetsidesoftware.code-spell-checker", + ], +} diff --git a/packages/angular-html-parser/.vscode/settings.json b/packages/angular-html-parser/.vscode/settings.json new file mode 100644 index 0000000000000..a215cd10444c4 --- /dev/null +++ b/packages/angular-html-parser/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "[javascript][typescript][json][jsonc][markdown][yaml]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true, + }, + // "[javascript][typescript]": { + // "editor.codeActionsOnSave": { + // "source.fixAll.eslint": "explicit", + // }, + // }, + "prettier.requireConfig": true, +} diff --git a/packages/angular-html-parser/src/index.ts b/packages/angular-html-parser/src/index.ts index ceef960444598..815fbd599d34f 100644 --- a/packages/angular-html-parser/src/index.ts +++ b/packages/angular-html-parser/src/index.ts @@ -49,6 +49,11 @@ export interface ParseOptions { * tokenize angular let declaration syntax */ tokenizeAngularLetDeclaration?: boolean; + + /** + * enable angular selectorless syntax + */ + enableAngularSelectorlessSyntax?: boolean; } export function parse( @@ -62,6 +67,7 @@ export function parse( getTagContentType, tokenizeAngularBlocks = false, tokenizeAngularLetDeclaration = false, + enableAngularSelectorlessSyntax = false, } = options; return getParser().parse( input, @@ -73,6 +79,7 @@ export function parse( allowHtmComponentClosingTags, tokenizeBlocks: tokenizeAngularBlocks, tokenizeLet: tokenizeAngularLetDeclaration, + selectorlessEnabled: enableAngularSelectorlessSyntax, }, isTagNameCaseSensitive, getTagContentType, diff --git a/packages/angular-html-parser/test/index_spec.ts b/packages/angular-html-parser/test/index_spec.ts index e6088bfb79893..81e87afcb6628 100644 --- a/packages/angular-html-parser/test/index_spec.ts +++ b/packages/angular-html-parser/test/index_spec.ts @@ -68,7 +68,7 @@ describe("AST format", () => { ]); }); - it("should have `type` property when tokenizeBlocks is enabled", () => { + it("should support 'tokenizeAngularBlocks'", () => { const input = `@if (user.isHuman) { <p>Hello human</p> }`; const ast = parse(input, { tokenizeAngularBlocks: true }); expect(ast.rootNodes).toEqual([ @@ -95,4 +95,88 @@ describe("AST format", () => { }), ]); }); + + it("should support 'tokenizeAngularLetDeclaration'", () => { + const input = `@let foo = 'bar';`; + const ast = parse(input, { tokenizeAngularLetDeclaration: true }); + expect(ast.rootNodes).toEqual([ + expect.objectContaining({ + name: "foo", + type: "letDeclaration", + value: "'bar'", + }), + ]); + }); + + // https://github.com/angular/angular/pull/60724 + it("should support 'enableAngularSelectorlessSyntax'", () => { + { + const ast = parse("<div @Dir></div>", { + enableAngularSelectorlessSyntax: true, + }); + expect(ast.rootNodes).toEqual([ + expect.objectContaining({ + name: "div", + type: "element", + directives: [ + expect.objectContaining({ + name: "Dir", + type: "directive", + }), + ], + }), + ]); + } + + { + const ast = parse("<MyComp>Hello</MyComp>", { + enableAngularSelectorlessSyntax: true, + }); + + expect(ast.rootNodes).toEqual([ + expect.objectContaining({ + fullName: "MyComp", + componentName: "MyComp", + type: "component", + }), + ]); + } + + { + const ast = parse("<MyComp/>", { enableAngularSelectorlessSyntax: true }); + expect(ast.rootNodes).toEqual([ + expect.objectContaining({ + fullName: "MyComp", + componentName: "MyComp", + type: "component", + }), + ]); + } + + { + const ast = parse("<MyComp:button>Hello</MyComp:button>", { + enableAngularSelectorlessSyntax: true, + }); + expect(ast.rootNodes).toEqual([ + expect.objectContaining({ + fullName: "MyComp:button", + componentName: "MyComp", + type: "component", + }), + ]); + } + + { + const ast = parse("<MyComp:svg:title>Hello</MyComp:svg:title>", { + enableAngularSelectorlessSyntax: true, + }); + expect(ast.rootNodes).toEqual([ + expect.objectContaining({ + fullName: "MyComp:svg:title", + componentName: "MyComp", + type: "component", + }), + ]); + } + }); }); From e9db4f12931a526ed7e5b3014b12a50bf4027a4a Mon Sep 17 00:00:00 2001 From: fisker <lionkay@gmail.com> Date: Wed, 16 Apr 2025 23:54:48 +0800 Subject: [PATCH 2/2] style: fix EOL --- packages/angular-html-parser/.vscode/extensions.json | 4 ++-- packages/angular-html-parser/.vscode/settings.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/angular-html-parser/.vscode/extensions.json b/packages/angular-html-parser/.vscode/extensions.json index d85e4793e8b2a..77e870d1b231a 100644 --- a/packages/angular-html-parser/.vscode/extensions.json +++ b/packages/angular-html-parser/.vscode/extensions.json @@ -3,6 +3,6 @@ "esbenp.prettier-vscode", "editorconfig.editorconfig", // "dbaeumer.vscode-eslint", - "streetsidesoftware.code-spell-checker", - ], + "streetsidesoftware.code-spell-checker" + ] } diff --git a/packages/angular-html-parser/.vscode/settings.json b/packages/angular-html-parser/.vscode/settings.json index a215cd10444c4..707104dc663e6 100644 --- a/packages/angular-html-parser/.vscode/settings.json +++ b/packages/angular-html-parser/.vscode/settings.json @@ -1,12 +1,12 @@ { "[javascript][typescript][json][jsonc][markdown][yaml]": { "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true, + "editor.formatOnSave": true }, // "[javascript][typescript]": { // "editor.codeActionsOnSave": { // "source.fixAll.eslint": "explicit", // }, // }, - "prettier.requireConfig": true, + "prettier.requireConfig": true }