@analogjs/vite-plugin-angular 3.0.0-alpha.98 → 3.0.0-alpha.99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/lib/angular-jit-plugin.js +3 -4
- package/src/lib/angular-jit-plugin.js.map +1 -1
- package/src/lib/angular-vite-plugin.js +1 -1
- package/src/lib/angular-vite-plugin.js.map +1 -1
- package/src/lib/compiler/compile.js +2 -3
- package/src/lib/compiler/compile.js.map +1 -1
- package/src/lib/compiler/jit-metadata.d.ts +2 -0
- package/src/lib/compiler/jit-metadata.js +9 -4
- package/src/lib/compiler/jit-metadata.js.map +1 -1
- package/src/lib/compiler/jit-transform.js +59 -31
- package/src/lib/compiler/jit-transform.js.map +1 -1
- package/src/lib/compiler/metadata.js +16 -6
- package/src/lib/compiler/metadata.js.map +1 -1
- package/src/lib/utils/jit-inline-styles.d.ts +3 -2
- package/src/lib/utils/jit-inline-styles.js +9 -5
- package/src/lib/utils/jit-inline-styles.js.map +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ANGULAR_DECORATORS, FIELD_DECORATORS } from "./constants.js";
|
|
2
2
|
import { detectTypeOnlyImportNames } from "./type-elision.js";
|
|
3
|
-
import { buildCtorParameters, buildPropDecorators } from "./jit-metadata.js";
|
|
3
|
+
import { buildCtorParameters, buildPropDecorators, findConstructor } from "./jit-metadata.js";
|
|
4
4
|
import { parseSync } from "oxc-parser";
|
|
5
5
|
import MagicString from "magic-string";
|
|
6
6
|
//#region packages/vite-plugin-angular/src/lib/compiler/jit-transform.ts
|
|
@@ -23,6 +23,49 @@ function findAllClasses(node) {
|
|
|
23
23
|
return result;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
|
+
* `@Injectable` and `@Service` stay on the class — their decorator functions
|
|
27
|
+
* self-register ɵprov/ɵfac at class definition time and there is no JIT
|
|
28
|
+
* compile entry point to call instead.
|
|
29
|
+
*/
|
|
30
|
+
function isSelfRegisteringDecorator(dec) {
|
|
31
|
+
const name = dec.expression?.callee?.name;
|
|
32
|
+
return name === "Injectable" || name === "Service";
|
|
33
|
+
}
|
|
34
|
+
/** Remove a decorator along with its trailing whitespace. */
|
|
35
|
+
function removeDecorator(ms, sourceCode, dec) {
|
|
36
|
+
let trimEnd = dec.end;
|
|
37
|
+
while (trimEnd < sourceCode.length && /\s/.test(sourceCode[trimEnd])) trimEnd++;
|
|
38
|
+
ms.remove(dec.start, trimEnd);
|
|
39
|
+
}
|
|
40
|
+
var DI_PARAM_DECORATORS = new Set([
|
|
41
|
+
"Inject",
|
|
42
|
+
"Optional",
|
|
43
|
+
"Self",
|
|
44
|
+
"SkipSelf",
|
|
45
|
+
"Host",
|
|
46
|
+
"Attribute"
|
|
47
|
+
]);
|
|
48
|
+
var PROVIDER_KEYS = new Set([
|
|
49
|
+
"useClass",
|
|
50
|
+
"useExisting",
|
|
51
|
+
"useFactory",
|
|
52
|
+
"useValue"
|
|
53
|
+
]);
|
|
54
|
+
function ctorParamDecorators(classNode) {
|
|
55
|
+
const ctor = findConstructor(classNode);
|
|
56
|
+
return (ctor?.value?.params?.items || ctor?.value?.params || []).flatMap((param) => [...param.decorators || [], ...param.type === "TSParameterProperty" && param.parameter?.decorators ? param.parameter.decorators : []]);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Whether an @Injectable/@Service class needs ctorParameters. Skipped when a
|
|
60
|
+
* provider option replaces the constructor, or when a non-DI parameter
|
|
61
|
+
* decorator must keep running as written.
|
|
62
|
+
*/
|
|
63
|
+
function needsInjectableCtorParameters(node, decorators) {
|
|
64
|
+
const dec = decorators.find(isSelfRegisteringDecorator);
|
|
65
|
+
const options = dec?.expression.arguments?.[0];
|
|
66
|
+
return !!dec && node.type === "ClassDeclaration" && !options?.properties?.some((p) => PROVIDER_KEYS.has(p.key?.name)) && ctorParamDecorators(node).every((d) => DI_PARAM_DECORATORS.has(d.expression?.callee?.name));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
26
69
|
* JIT transform for Angular files.
|
|
27
70
|
*
|
|
28
71
|
* Converts Angular decorators to static metadata arrays that Angular's
|
|
@@ -52,24 +95,28 @@ function jitTransform(sourceCode, fileName) {
|
|
|
52
95
|
const resourceImports = [];
|
|
53
96
|
let needsJitImport = false;
|
|
54
97
|
for (const node of allClasses) {
|
|
55
|
-
const
|
|
98
|
+
const decorators = node.decorators || [];
|
|
99
|
+
const angularDecs = decorators.filter((dec) => {
|
|
56
100
|
const expr = dec.expression;
|
|
57
101
|
if (!expr || expr.type !== "CallExpression") return false;
|
|
58
102
|
const name = expr.callee?.name;
|
|
59
|
-
if (
|
|
103
|
+
if (isSelfRegisteringDecorator(dec)) return false;
|
|
60
104
|
return name !== void 0 && ANGULAR_DECORATORS.has(name);
|
|
61
105
|
});
|
|
62
|
-
if (angularDecs.length === 0) continue;
|
|
63
106
|
const className = node.id?.name;
|
|
64
107
|
if (!className) continue;
|
|
108
|
+
if (angularDecs.length === 0) {
|
|
109
|
+
const ctorParams = needsInjectableCtorParameters(node, decorators) && buildCtorParameters(node, sourceCode, typeOnlyImports);
|
|
110
|
+
if (ctorParams) {
|
|
111
|
+
hasAngularClass = true;
|
|
112
|
+
for (const dec of ctorParamDecorators(node)) removeDecorator(ms, sourceCode, dec);
|
|
113
|
+
ms.appendLeft(node.end, `\n${className}.ctorParameters = () => [${ctorParams}];\n`);
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
65
117
|
hasAngularClass = true;
|
|
66
118
|
const classStatements = [];
|
|
67
|
-
for (const dec of angularDecs)
|
|
68
|
-
const start = dec.start;
|
|
69
|
-
let trimEnd = dec.end;
|
|
70
|
-
while (trimEnd < sourceCode.length && /\s/.test(sourceCode[trimEnd])) trimEnd++;
|
|
71
|
-
ms.remove(start, trimEnd);
|
|
72
|
-
}
|
|
119
|
+
for (const dec of angularDecs) removeDecorator(ms, sourceCode, dec);
|
|
73
120
|
const decoratorMeta = [];
|
|
74
121
|
const decoratorEntries = angularDecs.map((dec) => {
|
|
75
122
|
const call = dec.expression;
|
|
@@ -147,27 +194,8 @@ function jitTransform(sourceCode, fileName) {
|
|
|
147
194
|
const propDecorators = buildPropDecorators(node, sourceCode);
|
|
148
195
|
if (propDecorators) classStatements.push(`${className}.propDecorators = ${propDecorators};`);
|
|
149
196
|
const members = node.body?.body || [];
|
|
150
|
-
for (const member of members)
|
|
151
|
-
|
|
152
|
-
for (const dec of memberDecs) {
|
|
153
|
-
const start = dec.start;
|
|
154
|
-
let trimEnd = dec.end;
|
|
155
|
-
while (trimEnd < sourceCode.length && /\s/.test(sourceCode[trimEnd])) trimEnd++;
|
|
156
|
-
ms.remove(start, trimEnd);
|
|
157
|
-
}
|
|
158
|
-
if (member.type === "MethodDefinition" && member.kind === "constructor") {
|
|
159
|
-
const params = member.value?.params?.items || member.value?.params || [];
|
|
160
|
-
for (const param of params) {
|
|
161
|
-
const allParamDecs = [...param.decorators || [], ...param.type === "TSParameterProperty" && param.parameter?.decorators ? param.parameter.decorators : []];
|
|
162
|
-
for (const dec of allParamDecs) {
|
|
163
|
-
const start = dec.start;
|
|
164
|
-
let trimEnd = dec.end;
|
|
165
|
-
while (trimEnd < sourceCode.length && /\s/.test(sourceCode[trimEnd])) trimEnd++;
|
|
166
|
-
ms.remove(start, trimEnd);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
197
|
+
for (const member of members) for (const dec of member.decorators || []) removeDecorator(ms, sourceCode, dec);
|
|
198
|
+
for (const dec of ctorParamDecorators(node)) removeDecorator(ms, sourceCode, dec);
|
|
171
199
|
if (classStatements.length > 0) {
|
|
172
200
|
allEmittedStatements.push(...classStatements);
|
|
173
201
|
ms.appendLeft(node.end, "\n" + classStatements.join("\n") + "\n");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jit-transform.js","names":[],"sources":["../../../../src/lib/compiler/jit-transform.ts"],"sourcesContent":["import { parseSync } from 'oxc-parser';\nimport MagicString from 'magic-string';\nimport { detectTypeOnlyImportNames } from './type-elision.js';\nimport { buildCtorParameters, buildPropDecorators } from './jit-metadata.js';\nimport { ANGULAR_DECORATORS, FIELD_DECORATORS } from './constants.js';\n\nexport interface JitTransformResult {\n code: string;\n map: any;\n}\n\n/**\n * Recursively find all ClassDeclaration nodes in an OXC AST.\n * Handles top-level, exported, and nested classes (e.g. inside function scopes).\n */\nfunction findAllClasses(node: any): any[] {\n const result: any[] = [];\n if (!node || typeof node !== 'object') return result;\n if (Array.isArray(node)) {\n for (const item of node) {\n result.push(...findAllClasses(item));\n }\n return result;\n }\n if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') {\n result.push(node);\n }\n for (const key of Object.keys(node)) {\n if (\n key === 'type' ||\n key === 'start' ||\n key === 'end' ||\n key === 'range' ||\n key === 'loc'\n )\n continue;\n result.push(...findAllClasses(node[key]));\n }\n return result;\n}\n\n/**\n * JIT transform for Angular files.\n *\n * Converts Angular decorators to static metadata arrays that Angular's\n * runtime JIT compiler reads via ReflectionCapabilities:\n *\n * - Class.decorators = [{ type: Component, args: [{...}] }]\n * - Class.ctorParameters = () => [{ type: ServiceA, decorators: [{type: Optional}] }]\n * - Class.propDecorators = { name: [{ type: Input }], ... }\n *\n * Also emits ɵfac (factory function) with constructor DI and downlevels\n * signal APIs (input, model, output, viewChild, etc.) to propDecorators.\n *\n * No template compilation — Angular's JIT compiler handles that at runtime.\n * Requires `import '@angular/compiler'` in main.ts for the browser JIT.\n *\n * Uses OXC's native Rust parser instead of TypeScript's parser for ~1.5x\n * faster parsing and source-position slicing instead of getText() calls.\n */\nexport function jitTransform(\n sourceCode: string,\n fileName: string,\n): JitTransformResult {\n const { program } = parseSync(fileName, sourceCode);\n const ms = new MagicString(sourceCode, { filename: fileName });\n const typeOnlyImports = detectTypeOnlyImportNames(sourceCode, program);\n let hasAngularClass = false;\n\n const allClasses = findAllClasses(program.body);\n\n // Accumulates every class's emitted statements so the post-loop import\n // detection (missing field-decorator imports) can scan all of them.\n // The statements themselves are inserted in-scope after each class via\n // `ms.appendLeft(node.end, ...)` rather than dumped at the end of the\n // file — a class declared inside a function/callback scope (e.g. a host\n // `@Component` defined inside a `describe(...)`/`it(...)` block in a test)\n // is not in scope at module end, so a file-end emit would reference an\n // undefined name (#2360).\n const allEmittedStatements: string[] = [];\n let importCounter = 0;\n const resourceImports: string[] = [];\n let needsJitImport = false;\n\n for (const node of allClasses) {\n const decorators: any[] = node.decorators || [];\n\n const angularDecs = decorators.filter((dec: any) => {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') return false;\n const name: string | undefined = expr.callee?.name;\n // Keep @Injectable and @Service on the class — their decorator\n // functions self-register ɵprov/ɵfac at class definition time and\n // there is no JIT compile entry point to call instead.\n if (name === 'Injectable' || name === 'Service') return false;\n return name !== undefined && ANGULAR_DECORATORS.has(name);\n });\n if (angularDecs.length === 0) continue;\n\n const className: string | undefined = node.id?.name;\n if (!className) continue;\n hasAngularClass = true;\n\n // Statements emitted for THIS class. Inserted directly after the class\n // body (see end of loop) so they run in the class's own lexical scope.\n const classStatements: string[] = [];\n\n // 1. Remove Angular decorators from source\n for (const dec of angularDecs) {\n const start: number = dec.start;\n let trimEnd: number = dec.end;\n while (trimEnd < sourceCode.length && /\\s/.test(sourceCode[trimEnd]))\n trimEnd++;\n ms.remove(start, trimEnd);\n }\n\n // 2. Emit Class.decorators = [{ type: DecName, args: [...] }]\n // For @Component: convert templateUrl/styleUrl/styleUrls to ESM imports\n const decoratorMeta: { name: string; argsText: string }[] = [];\n const decoratorEntries = angularDecs.map((dec: any) => {\n const call = dec.expression;\n const decName: string = call.callee.name;\n const args: any[] = call.arguments || [];\n\n if (\n args.length > 0 &&\n decName === 'Component' &&\n args[0].type === 'ObjectExpression'\n ) {\n // Rewrite component metadata: convert external resources to imports\n const obj = args[0];\n const rewrittenProps: string[] = [];\n\n for (const prop of obj.properties) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property') {\n rewrittenProps.push(sourceCode.slice(prop.start, prop.end));\n continue;\n }\n const key: string = prop.key?.name || prop.key?.value;\n const val = prop.value;\n\n if (\n key === 'templateUrl' &&\n (val?.type === 'StringLiteral' ||\n (val?.type === 'Literal' && typeof val.value === 'string'))\n ) {\n // templateUrl: './foo.html' → template: _tpl0 (with import)\n const varName = `_jit_tpl_${importCounter++}`;\n resourceImports.push(`import ${varName} from '${val.value}?raw';`);\n rewrittenProps.push(`template: ${varName}`);\n } else if (\n key === 'styleUrl' &&\n (val?.type === 'StringLiteral' ||\n (val?.type === 'Literal' && typeof val.value === 'string'))\n ) {\n // styleUrl: './foo.scss' → styles: [_style0]\n const varName = `_jit_style_${importCounter++}`;\n resourceImports.push(\n `import ${varName} from '${val.value}?inline';`,\n );\n rewrittenProps.push(`styles: [${varName}]`);\n } else if (key === 'styleUrls' && val?.type === 'ArrayExpression') {\n // styleUrls: ['./a.scss', './b.css'] → styles: [_style0, _style1]\n const vars: string[] = [];\n for (const el of val.elements) {\n if (\n el?.type === 'StringLiteral' ||\n (el?.type === 'Literal' && typeof el.value === 'string')\n ) {\n const varName = `_jit_style_${importCounter++}`;\n resourceImports.push(\n `import ${varName} from '${el.value}?inline';`,\n );\n vars.push(varName);\n }\n }\n rewrittenProps.push(`styles: [${vars.join(', ')}]`);\n } else {\n rewrittenProps.push(sourceCode.slice(prop.start, prop.end));\n }\n }\n const rewrittenArgsText = `{${rewrittenProps.join(', ')}}`;\n decoratorMeta.push({ name: decName, argsText: rewrittenArgsText });\n return `{ type: ${decName}, args: [${rewrittenArgsText}] }`;\n }\n\n if (args.length > 0) {\n const argsText = args\n .map((a: any) => sourceCode.slice(a.start, a.end))\n .join(', ');\n decoratorMeta.push({ name: decName, argsText });\n return `{ type: ${decName}, args: [${argsText}] }`;\n }\n decoratorMeta.push({ name: decName, argsText: '{}' });\n return `{ type: ${decName} }`;\n });\n classStatements.push(\n `${className}.decorators = [${decoratorEntries.join(', ')}];`,\n );\n\n // 2b. Trigger JIT compilation with the rewritten decorator metadata\n for (const dm of decoratorMeta) {\n needsJitImport = true;\n switch (dm.name) {\n case 'Component':\n classStatements.push(\n `_jitCompileComponent(${className}, ${dm.argsText});`,\n );\n break;\n case 'Directive':\n classStatements.push(\n `_jitCompileDirective(${className}, ${dm.argsText});`,\n );\n break;\n case 'Pipe':\n classStatements.push(\n `_jitCompilePipe(${className}, ${dm.argsText});`,\n );\n break;\n case 'NgModule':\n classStatements.push(\n `_jitCompileNgModule(${className}, ${dm.argsText});`,\n );\n break;\n }\n }\n\n // 3. Emit Class.ctorParameters for constructor DI\n const ctorParams = buildCtorParameters(node, sourceCode, typeOnlyImports);\n if (ctorParams) {\n classStatements.push(\n `${className}.ctorParameters = () => [${ctorParams}];`,\n );\n }\n\n // 4. Emit Class.propDecorators for field decorators + signal APIs\n const propDecorators = buildPropDecorators(node, sourceCode);\n if (propDecorators) {\n classStatements.push(`${className}.propDecorators = ${propDecorators};`);\n }\n\n // 5. Remove member and parameter decorators from source now that\n // they have been extracted into static metadata above.\n const members: any[] = node.body?.body || [];\n for (const member of members) {\n const memberDecs: any[] = member.decorators || [];\n for (const dec of memberDecs) {\n const start: number = dec.start;\n let trimEnd: number = dec.end;\n while (trimEnd < sourceCode.length && /\\s/.test(sourceCode[trimEnd]))\n trimEnd++;\n ms.remove(start, trimEnd);\n }\n // Constructor parameter decorators\n if (member.type === 'MethodDefinition' && member.kind === 'constructor') {\n const params: any[] =\n member.value?.params?.items || member.value?.params || [];\n for (const param of params) {\n // Decorators may live on the TSParameterProperty wrapper or the inner param\n const allParamDecs: any[] = [\n ...(param.decorators || []),\n ...(param.type === 'TSParameterProperty' &&\n param.parameter?.decorators\n ? param.parameter.decorators\n : []),\n ];\n for (const dec of allParamDecs) {\n const start: number = dec.start;\n let trimEnd: number = dec.end;\n while (\n trimEnd < sourceCode.length &&\n /\\s/.test(sourceCode[trimEnd])\n )\n trimEnd++;\n ms.remove(start, trimEnd);\n }\n }\n }\n }\n\n // Insert this class's metadata statements directly after the class body\n // so they execute in the class's own lexical scope. `node.end` is the\n // position just past the closing brace (decorators were stripped before\n // `node.start`), so for a top-level class this is module scope and for a\n // class nested in a function/callback it is that enclosing scope —\n // keeping the class identifier in scope either way (#2360).\n if (classStatements.length > 0) {\n allEmittedStatements.push(...classStatements);\n ms.appendLeft(node.end, '\\n' + classStatements.join('\\n') + '\\n');\n }\n }\n\n if (!hasAngularClass) {\n return { code: sourceCode, map: null };\n }\n\n // Prepend ESM imports for external templates/styles\n if (resourceImports.length > 0) {\n ms.prepend(resourceImports.join('\\n') + '\\n');\n }\n\n // Prepend imports for decorator classes referenced by signal API downleveling\n // (e.g. input() → {type: Input}, model() → {type: Input} + {type: Output})\n const existingImports = new Set<string>();\n for (const stmt of program.body) {\n if (\n (stmt as any).type === 'ImportDeclaration' &&\n (stmt as any).source?.value === '@angular/core'\n ) {\n for (const spec of (stmt as any).specifiers || []) {\n if (spec.type === 'ImportSpecifier') {\n existingImports.add(spec.local?.name || spec.imported?.name);\n }\n }\n }\n }\n const allPostCode = allEmittedStatements.join('\\n');\n const missingDecorators: string[] = [];\n for (const dec of FIELD_DECORATORS) {\n if (allPostCode.includes(`type: ${dec}`) && !existingImports.has(dec)) {\n missingDecorators.push(dec);\n }\n }\n if (missingDecorators.length > 0) {\n ms.prepend(\n `import { ${missingDecorators.join(', ')} } from '@angular/core';\\n`,\n );\n }\n\n // Prepend JIT compiler imports\n if (needsJitImport) {\n ms.prepend(\n `import { ɵcompileComponent as _jitCompileComponent, ɵcompileDirective as _jitCompileDirective, ɵcompilePipe as _jitCompilePipe, ɵcompileNgModule as _jitCompileNgModule } from '@angular/core';\\n`,\n );\n }\n\n const map = ms.generateMap({\n source: fileName,\n file: fileName + '.js',\n includeContent: true,\n hires: 'boundary',\n });\n\n return { code: ms.toString(), map };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"jit-transform.js","names":[],"sources":["../../../../src/lib/compiler/jit-transform.ts"],"sourcesContent":["import { parseSync } from 'oxc-parser';\nimport MagicString from 'magic-string';\nimport { detectTypeOnlyImportNames } from './type-elision.js';\nimport {\n buildCtorParameters,\n buildPropDecorators,\n findConstructor,\n} from './jit-metadata.js';\nimport { ANGULAR_DECORATORS, FIELD_DECORATORS } from './constants.js';\n\nexport interface JitTransformResult {\n code: string;\n map: any;\n}\n\n/**\n * Recursively find all ClassDeclaration nodes in an OXC AST.\n * Handles top-level, exported, and nested classes (e.g. inside function scopes).\n */\nfunction findAllClasses(node: any): any[] {\n const result: any[] = [];\n if (!node || typeof node !== 'object') return result;\n if (Array.isArray(node)) {\n for (const item of node) {\n result.push(...findAllClasses(item));\n }\n return result;\n }\n if (node.type === 'ClassDeclaration' || node.type === 'ClassExpression') {\n result.push(node);\n }\n for (const key of Object.keys(node)) {\n if (\n key === 'type' ||\n key === 'start' ||\n key === 'end' ||\n key === 'range' ||\n key === 'loc'\n )\n continue;\n result.push(...findAllClasses(node[key]));\n }\n return result;\n}\n\n/**\n * `@Injectable` and `@Service` stay on the class — their decorator functions\n * self-register ɵprov/ɵfac at class definition time and there is no JIT\n * compile entry point to call instead.\n */\nfunction isSelfRegisteringDecorator(dec: any): boolean {\n const name: string | undefined = dec.expression?.callee?.name;\n return name === 'Injectable' || name === 'Service';\n}\n\n/** Remove a decorator along with its trailing whitespace. */\nfunction removeDecorator(ms: MagicString, sourceCode: string, dec: any): void {\n let trimEnd: number = dec.end;\n while (trimEnd < sourceCode.length && /\\s/.test(sourceCode[trimEnd]))\n trimEnd++;\n ms.remove(dec.start, trimEnd);\n}\n\nconst DI_PARAM_DECORATORS = new Set([\n 'Inject',\n 'Optional',\n 'Self',\n 'SkipSelf',\n 'Host',\n 'Attribute',\n]);\nconst PROVIDER_KEYS = new Set([\n 'useClass',\n 'useExisting',\n 'useFactory',\n 'useValue',\n]);\n\nfunction ctorParamDecorators(classNode: any): any[] {\n const ctor = findConstructor(classNode);\n const params: any[] = ctor?.value?.params?.items || ctor?.value?.params || [];\n // Decorators may live on the TSParameterProperty wrapper or the inner param\n return params.flatMap((param: any) => [\n ...(param.decorators || []),\n ...(param.type === 'TSParameterProperty' && param.parameter?.decorators\n ? param.parameter.decorators\n : []),\n ]);\n}\n\n/**\n * Whether an @Injectable/@Service class needs ctorParameters. Skipped when a\n * provider option replaces the constructor, or when a non-DI parameter\n * decorator must keep running as written.\n */\nfunction needsInjectableCtorParameters(node: any, decorators: any[]): boolean {\n const dec = decorators.find(isSelfRegisteringDecorator);\n const options = dec?.expression.arguments?.[0];\n return (\n !!dec &&\n node.type === 'ClassDeclaration' &&\n !options?.properties?.some((p: any) => PROVIDER_KEYS.has(p.key?.name)) &&\n ctorParamDecorators(node).every((d: any) =>\n DI_PARAM_DECORATORS.has(d.expression?.callee?.name),\n )\n );\n}\n\n/**\n * JIT transform for Angular files.\n *\n * Converts Angular decorators to static metadata arrays that Angular's\n * runtime JIT compiler reads via ReflectionCapabilities:\n *\n * - Class.decorators = [{ type: Component, args: [{...}] }]\n * - Class.ctorParameters = () => [{ type: ServiceA, decorators: [{type: Optional}] }]\n * - Class.propDecorators = { name: [{ type: Input }], ... }\n *\n * Also emits ɵfac (factory function) with constructor DI and downlevels\n * signal APIs (input, model, output, viewChild, etc.) to propDecorators.\n *\n * No template compilation — Angular's JIT compiler handles that at runtime.\n * Requires `import '@angular/compiler'` in main.ts for the browser JIT.\n *\n * Uses OXC's native Rust parser instead of TypeScript's parser for ~1.5x\n * faster parsing and source-position slicing instead of getText() calls.\n */\nexport function jitTransform(\n sourceCode: string,\n fileName: string,\n): JitTransformResult {\n const { program } = parseSync(fileName, sourceCode);\n const ms = new MagicString(sourceCode, { filename: fileName });\n const typeOnlyImports = detectTypeOnlyImportNames(sourceCode, program);\n let hasAngularClass = false;\n\n const allClasses = findAllClasses(program.body);\n\n // Accumulates every class's emitted statements so the post-loop import\n // detection (missing field-decorator imports) can scan all of them.\n // The statements themselves are inserted in-scope after each class via\n // `ms.appendLeft(node.end, ...)` rather than dumped at the end of the\n // file — a class declared inside a function/callback scope (e.g. a host\n // `@Component` defined inside a `describe(...)`/`it(...)` block in a test)\n // is not in scope at module end, so a file-end emit would reference an\n // undefined name (#2360).\n const allEmittedStatements: string[] = [];\n let importCounter = 0;\n const resourceImports: string[] = [];\n let needsJitImport = false;\n\n for (const node of allClasses) {\n const decorators: any[] = node.decorators || [];\n\n const angularDecs = decorators.filter((dec: any) => {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') return false;\n const name: string | undefined = expr.callee?.name;\n if (isSelfRegisteringDecorator(dec)) return false;\n return name !== undefined && ANGULAR_DECORATORS.has(name);\n });\n const className: string | undefined = node.id?.name;\n if (!className) continue;\n\n if (angularDecs.length === 0) {\n // @Injectable/@Service keep their decorator, but without a type\n // checker or emitDecoratorMetadata a param typed only by annotation\n // has no runtime DI token unless captured in ctorParameters. A class\n // expression's name is not in scope after it, so only declarations.\n const ctorParams =\n needsInjectableCtorParameters(node, decorators) &&\n buildCtorParameters(node, sourceCode, typeOnlyImports);\n if (ctorParams) {\n hasAngularClass = true;\n for (const dec of ctorParamDecorators(node)) {\n removeDecorator(ms, sourceCode, dec);\n }\n ms.appendLeft(\n node.end,\n `\\n${className}.ctorParameters = () => [${ctorParams}];\\n`,\n );\n }\n continue;\n }\n hasAngularClass = true;\n\n // Statements emitted for THIS class. Inserted directly after the class\n // body (see end of loop) so they run in the class's own lexical scope.\n const classStatements: string[] = [];\n\n // 1. Remove Angular decorators from source\n for (const dec of angularDecs) {\n removeDecorator(ms, sourceCode, dec);\n }\n\n // 2. Emit Class.decorators = [{ type: DecName, args: [...] }]\n // For @Component: convert templateUrl/styleUrl/styleUrls to ESM imports\n const decoratorMeta: { name: string; argsText: string }[] = [];\n const decoratorEntries = angularDecs.map((dec: any) => {\n const call = dec.expression;\n const decName: string = call.callee.name;\n const args: any[] = call.arguments || [];\n\n if (\n args.length > 0 &&\n decName === 'Component' &&\n args[0].type === 'ObjectExpression'\n ) {\n // Rewrite component metadata: convert external resources to imports\n const obj = args[0];\n const rewrittenProps: string[] = [];\n\n for (const prop of obj.properties) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property') {\n rewrittenProps.push(sourceCode.slice(prop.start, prop.end));\n continue;\n }\n const key: string = prop.key?.name || prop.key?.value;\n const val = prop.value;\n\n if (\n key === 'templateUrl' &&\n (val?.type === 'StringLiteral' ||\n (val?.type === 'Literal' && typeof val.value === 'string'))\n ) {\n // templateUrl: './foo.html' → template: _tpl0 (with import)\n const varName = `_jit_tpl_${importCounter++}`;\n resourceImports.push(`import ${varName} from '${val.value}?raw';`);\n rewrittenProps.push(`template: ${varName}`);\n } else if (\n key === 'styleUrl' &&\n (val?.type === 'StringLiteral' ||\n (val?.type === 'Literal' && typeof val.value === 'string'))\n ) {\n // styleUrl: './foo.scss' → styles: [_style0]\n const varName = `_jit_style_${importCounter++}`;\n resourceImports.push(\n `import ${varName} from '${val.value}?inline';`,\n );\n rewrittenProps.push(`styles: [${varName}]`);\n } else if (key === 'styleUrls' && val?.type === 'ArrayExpression') {\n // styleUrls: ['./a.scss', './b.css'] → styles: [_style0, _style1]\n const vars: string[] = [];\n for (const el of val.elements) {\n if (\n el?.type === 'StringLiteral' ||\n (el?.type === 'Literal' && typeof el.value === 'string')\n ) {\n const varName = `_jit_style_${importCounter++}`;\n resourceImports.push(\n `import ${varName} from '${el.value}?inline';`,\n );\n vars.push(varName);\n }\n }\n rewrittenProps.push(`styles: [${vars.join(', ')}]`);\n } else {\n rewrittenProps.push(sourceCode.slice(prop.start, prop.end));\n }\n }\n const rewrittenArgsText = `{${rewrittenProps.join(', ')}}`;\n decoratorMeta.push({ name: decName, argsText: rewrittenArgsText });\n return `{ type: ${decName}, args: [${rewrittenArgsText}] }`;\n }\n\n if (args.length > 0) {\n const argsText = args\n .map((a: any) => sourceCode.slice(a.start, a.end))\n .join(', ');\n decoratorMeta.push({ name: decName, argsText });\n return `{ type: ${decName}, args: [${argsText}] }`;\n }\n decoratorMeta.push({ name: decName, argsText: '{}' });\n return `{ type: ${decName} }`;\n });\n classStatements.push(\n `${className}.decorators = [${decoratorEntries.join(', ')}];`,\n );\n\n // 2b. Trigger JIT compilation with the rewritten decorator metadata\n for (const dm of decoratorMeta) {\n needsJitImport = true;\n switch (dm.name) {\n case 'Component':\n classStatements.push(\n `_jitCompileComponent(${className}, ${dm.argsText});`,\n );\n break;\n case 'Directive':\n classStatements.push(\n `_jitCompileDirective(${className}, ${dm.argsText});`,\n );\n break;\n case 'Pipe':\n classStatements.push(\n `_jitCompilePipe(${className}, ${dm.argsText});`,\n );\n break;\n case 'NgModule':\n classStatements.push(\n `_jitCompileNgModule(${className}, ${dm.argsText});`,\n );\n break;\n }\n }\n\n // 3. Emit Class.ctorParameters for constructor DI\n const ctorParams = buildCtorParameters(node, sourceCode, typeOnlyImports);\n if (ctorParams) {\n classStatements.push(\n `${className}.ctorParameters = () => [${ctorParams}];`,\n );\n }\n\n // 4. Emit Class.propDecorators for field decorators + signal APIs\n const propDecorators = buildPropDecorators(node, sourceCode);\n if (propDecorators) {\n classStatements.push(`${className}.propDecorators = ${propDecorators};`);\n }\n\n // 5. Remove member and parameter decorators from source now that\n // they have been extracted into static metadata above.\n const members: any[] = node.body?.body || [];\n for (const member of members) {\n for (const dec of member.decorators || []) {\n removeDecorator(ms, sourceCode, dec);\n }\n }\n for (const dec of ctorParamDecorators(node)) {\n removeDecorator(ms, sourceCode, dec);\n }\n\n // Insert this class's metadata statements directly after the class body\n // so they execute in the class's own lexical scope. `node.end` is the\n // position just past the closing brace (decorators were stripped before\n // `node.start`), so for a top-level class this is module scope and for a\n // class nested in a function/callback it is that enclosing scope —\n // keeping the class identifier in scope either way (#2360).\n if (classStatements.length > 0) {\n allEmittedStatements.push(...classStatements);\n ms.appendLeft(node.end, '\\n' + classStatements.join('\\n') + '\\n');\n }\n }\n\n if (!hasAngularClass) {\n return { code: sourceCode, map: null };\n }\n\n // Prepend ESM imports for external templates/styles\n if (resourceImports.length > 0) {\n ms.prepend(resourceImports.join('\\n') + '\\n');\n }\n\n // Prepend imports for decorator classes referenced by signal API downleveling\n // (e.g. input() → {type: Input}, model() → {type: Input} + {type: Output})\n const existingImports = new Set<string>();\n for (const stmt of program.body) {\n if (\n (stmt as any).type === 'ImportDeclaration' &&\n (stmt as any).source?.value === '@angular/core'\n ) {\n for (const spec of (stmt as any).specifiers || []) {\n if (spec.type === 'ImportSpecifier') {\n existingImports.add(spec.local?.name || spec.imported?.name);\n }\n }\n }\n }\n const allPostCode = allEmittedStatements.join('\\n');\n const missingDecorators: string[] = [];\n for (const dec of FIELD_DECORATORS) {\n if (allPostCode.includes(`type: ${dec}`) && !existingImports.has(dec)) {\n missingDecorators.push(dec);\n }\n }\n if (missingDecorators.length > 0) {\n ms.prepend(\n `import { ${missingDecorators.join(', ')} } from '@angular/core';\\n`,\n );\n }\n\n // Prepend JIT compiler imports\n if (needsJitImport) {\n ms.prepend(\n `import { ɵcompileComponent as _jitCompileComponent, ɵcompileDirective as _jitCompileDirective, ɵcompilePipe as _jitCompilePipe, ɵcompileNgModule as _jitCompileNgModule } from '@angular/core';\\n`,\n );\n }\n\n const map = ms.generateMap({\n source: fileName,\n file: fileName + '.js',\n includeContent: true,\n hires: 'boundary',\n });\n\n return { code: ms.toString(), map };\n}\n"],"mappings":"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"}
|
|
@@ -30,7 +30,14 @@ function getCallApi(call) {
|
|
|
30
30
|
* Returns `null` if the node is not statically resolvable.
|
|
31
31
|
*/
|
|
32
32
|
function stringValue(node, consts) {
|
|
33
|
+
while (node?.type === "TSAsExpression" || node?.type === "TSSatisfiesExpression" || node?.type === "ParenthesizedExpression") node = node.expression;
|
|
33
34
|
if (node?.type === "StringLiteral") return node.value;
|
|
35
|
+
if (node?.type === "BinaryExpression" && node.operator === "+") {
|
|
36
|
+
const operand = (n) => n?.type === "Identifier" ? consts?.get(n.name) ?? null : stringValue(n, consts);
|
|
37
|
+
const left = operand(node.left);
|
|
38
|
+
const right = left === null ? null : operand(node.right);
|
|
39
|
+
return right === null ? null : left + right;
|
|
40
|
+
}
|
|
34
41
|
if (node?.type === "Literal" && typeof node.value === "string") return node.value;
|
|
35
42
|
if (node?.type === "TemplateLiteral") {
|
|
36
43
|
const quasis = node.quasis ?? [];
|
|
@@ -94,6 +101,11 @@ function propKeyName(prop) {
|
|
|
94
101
|
if (!prop.key) return null;
|
|
95
102
|
return prop.key.name ?? prop.key.value ?? null;
|
|
96
103
|
}
|
|
104
|
+
/** Resolve a host key or value to a string literal or same-file string const. */
|
|
105
|
+
function hostString(node, consts) {
|
|
106
|
+
if (node?.type === "Identifier") return consts?.get(node.name) ?? null;
|
|
107
|
+
return stringValue(node, consts);
|
|
108
|
+
}
|
|
97
109
|
/**
|
|
98
110
|
* Extract decorator metadata from an OXC decorator AST node.
|
|
99
111
|
* Parses @Component, @Directive, @Pipe, @Injectable, @Service, @NgModule arguments.
|
|
@@ -137,12 +149,10 @@ function extractMetadata(dec, sourceCode, stringConsts) {
|
|
|
137
149
|
switch (key) {
|
|
138
150
|
case "host":
|
|
139
151
|
if (valNode.type === "ObjectExpression") for (const hp of valNode.properties || []) {
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
const hVal = sv !== null ? sv : sourceCode.slice(hp.value.start, hp.value.end).replace(/^['"`]|['"`]$/g, "");
|
|
145
|
-
meta.hostRaw[hKey.replace(/^['"`]|['"`]$/g, "")] = hVal;
|
|
152
|
+
const hKey = hp.computed ? hostString(hp.key, stringConsts) : propKeyName(hp);
|
|
153
|
+
const hVal = hostString(hp.value, stringConsts);
|
|
154
|
+
if (hKey === null || hVal === null) throw new Error(`[fast-compile] Cannot statically resolve host binding \`${sourceCode.slice(hp.start, hp.end)}\`. Only string literals and string constants declared in the same file are supported; use a string literal or @HostBinding/@HostListener instead.`);
|
|
155
|
+
meta.hostRaw[String(hKey).replace(/^['"`]|['"`]$/g, "")] = hVal;
|
|
146
156
|
}
|
|
147
157
|
break;
|
|
148
158
|
case "changeDetection":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.js","names":[],"sources":["../../../../src/lib/compiler/metadata.ts"],"sourcesContent":["import * as o from '@angular/compiler';\nimport { unwrapForwardRefOxc } from './utils.js';\nimport { FIELD_DECORATORS, SIGNAL_APIS } from './constants.js';\n\nfunction getCallApi(call: any): { api: string; required: boolean } | null {\n const callee = call.callee;\n if (!callee) return null;\n\n if (callee.type === 'Identifier') {\n return { api: callee.name, required: false };\n }\n\n if (\n (callee.type === 'StaticMemberExpression' ||\n callee.type === 'MemberExpression') &&\n callee.object?.type === 'Identifier' &&\n callee.property?.name === 'required'\n ) {\n return { api: callee.object.name, required: true };\n }\n\n return null;\n}\n\n/**\n * Extract the string value from an OXC string literal or template literal node.\n *\n * If `consts` is provided, interpolated template literals (e.g.\n * `\\`hello ${NAME}\\``) are resolved when every `${...}` expression is a bare\n * `Identifier` whose name is present in the map. This lets metadata fields\n * such as `template:` reference module-level string constants via JS\n * template-literal interpolation:\n *\n * const tw = `text-zinc-700 hover:text-zinc-900`;\n * @Component({ template: `<a class=\"${tw}\">x</a>` })\n *\n * Returns `null` if the node is not statically resolvable.\n */\nfunction stringValue(node: any, consts?: Map<string, string>): string | null {\n if (node?.type === 'StringLiteral') return node.value;\n if (node?.type === 'Literal' && typeof node.value === 'string')\n return node.value;\n if (node?.type === 'TemplateLiteral') {\n const quasis = node.quasis ?? [];\n const expressions = node.expressions ?? [];\n if (expressions.length === 0) {\n return quasis[0]?.value?.cooked ?? null;\n }\n if (!consts) return null;\n let result = '';\n for (let i = 0; i < quasis.length; i++) {\n const cooked = quasis[i]?.value?.cooked;\n if (cooked == null) return null;\n result += cooked;\n if (i < expressions.length) {\n const expr = expressions[i];\n if (expr?.type !== 'Identifier') return null;\n const resolved = consts.get(expr.name);\n if (resolved == null) return null;\n result += resolved;\n }\n }\n return result;\n }\n return null;\n}\n\n/** Check if an OXC node is a string-like literal. */\nfunction isStringLike(node: any, consts?: Map<string, string>): boolean {\n return stringValue(node, consts) !== null;\n}\n\n/**\n * Walk the top-level statements of an OXC program and collect a map of\n * statically-resolvable string-valued `const NAME = ...` declarations.\n *\n * Used so decorator metadata fields like `template:` can reference\n * module-level Tailwind class chains (or any other string constants) via\n * JS template-literal interpolation. Resolution is iterative: a const may\n * reference earlier-resolved consts via `${other}` interpolation.\n *\n * Only `const` declarations are considered. Non-string initializers,\n * function calls, member access, and any expression that cannot be reduced\n * to a string at parse time are ignored.\n */\nexport function collectStringConstants(oxcProgram: any): Map<string, string> {\n const rawDecls = new Map<string, any>();\n for (const stmt of oxcProgram?.body || []) {\n const decl =\n stmt.type === 'ExportNamedDeclaration' ? stmt.declaration : stmt;\n if (!decl || decl.type !== 'VariableDeclaration' || decl.kind !== 'const')\n continue;\n for (const d of decl.declarations || []) {\n if (d.id?.type === 'Identifier' && d.init) {\n rawDecls.set(d.id.name, d.init);\n }\n }\n }\n\n const resolved = new Map<string, string>();\n // Iterative fixpoint: each pass resolves consts whose dependencies are\n // already known. Bounded by the number of declarations to prevent cycles.\n for (let pass = 0; pass < rawDecls.size + 1; pass++) {\n let progress = false;\n for (const [name, init] of rawDecls) {\n if (resolved.has(name)) continue;\n const value = stringValue(init, resolved);\n if (value !== null) {\n resolved.set(name, value);\n progress = true;\n }\n }\n if (!progress) break;\n }\n return resolved;\n}\n\n/** Get the property key name from an OXC object property. */\nfunction propKeyName(prop: any): string | null {\n if (!prop.key) return null;\n return prop.key.name ?? prop.key.value ?? null;\n}\n\n/**\n * Extract decorator metadata from an OXC decorator AST node.\n * Parses @Component, @Directive, @Pipe, @Injectable, @Service, @NgModule arguments.\n *\n * `stringConsts`, when provided, lets string-typed metadata fields\n * (`template`, `selector`, `templateUrl`, `styles`, `styleUrl`, `styleUrls`,\n * `name`, `exportAs`, `providedIn`) resolve module-level string constants\n * referenced via template-literal interpolation, e.g.\n * `template: \\`<div class=\"${tw}\">x</div>\\``.\n */\nexport function extractMetadata(\n dec: any | undefined,\n sourceCode: string,\n stringConsts?: Map<string, string>,\n): any {\n if (!dec) return null;\n const call = dec.expression;\n if (!call || call.type !== 'CallExpression') return null;\n const arg = call.arguments?.[0];\n const meta: any = {\n hostRaw: {},\n inputs: {},\n outputs: {},\n standalone: true,\n imports: [],\n providers: null,\n viewProviders: null,\n animations: null,\n changeDetection: null,\n encapsulation: null,\n preserveWhitespaces: false,\n exportAs: null,\n selector: undefined,\n styles: [],\n templateUrl: null,\n styleUrls: [],\n };\n if (!arg || arg.type !== 'ObjectExpression') return meta;\n\n for (const p of arg.properties || []) {\n if (p.type !== 'ObjectProperty' && p.type !== 'Property') continue;\n const key = propKeyName(p);\n if (!key) continue;\n const valNode = p.value;\n const valText = sourceCode.slice(valNode.start, valNode.end);\n\n switch (key) {\n case 'host':\n if (valNode.type === 'ObjectExpression') {\n for (const hp of valNode.properties || []) {\n if (hp.type !== 'ObjectProperty' && hp.type !== 'Property')\n continue;\n const hKey = propKeyName(hp);\n if (!hKey) continue;\n // Prefer the parsed string value so embedded quotes (e.g. the\n // empty `\"\"` in `'expr ? \"\" : null'`) survive. Falling back to\n // the source slice for non-string values keeps prior behavior\n // for unusual host bindings (e.g. references to constants).\n const sv = stringValue(hp.value, stringConsts);\n const hVal =\n sv !== null\n ? sv\n : sourceCode\n .slice(hp.value.start, hp.value.end)\n .replace(/^['\"`]|['\"`]$/g, '');\n meta.hostRaw[hKey.replace(/^['\"`]|['\"`]$/g, '')] = hVal;\n }\n }\n break;\n case 'changeDetection':\n meta.changeDetection = valText.includes('OnPush') ? 0 : 1;\n break;\n case 'encapsulation':\n meta.encapsulation = valText.includes('None')\n ? 2\n : valText.includes('ShadowDom')\n ? 3\n : 0;\n break;\n case 'preserveWhitespaces':\n meta.preserveWhitespaces = valText === 'true';\n break;\n case 'pure':\n case 'standalone':\n meta[key] = valText !== 'false';\n break;\n case 'template':\n case 'selector':\n case 'name':\n case 'exportAs':\n case 'templateUrl':\n case 'providedIn': {\n const sv = stringValue(valNode, stringConsts);\n if (sv !== null) {\n meta[key] = sv;\n } else if (valNode.type === 'TemplateLiteral') {\n // Template literal with `${...}` interpolations that couldn't\n // all be resolved at parse time (e.g. they reference imports\n // or non-string values). The previous fallback stripped every\n // quote character from the source, which silently corrupted\n // templates such as `<a class=\"${cls} foo\">…</a>` into\n // `<a class=${cls} foo>…</a>` — making Angular's HTML parser\n // fail with confusing errors like `Opening tag \"a\" not\n // terminated`. Instead, walk the quasis and substitute each\n // unresolved interpolation with the empty string so the\n // surrounding HTML (including quoted attributes) is preserved.\n const quasis = valNode.quasis ?? [];\n const expressions = valNode.expressions ?? [];\n let result = '';\n for (let i = 0; i < quasis.length; i++) {\n result += quasis[i]?.value?.cooked ?? '';\n if (i < expressions.length) {\n const expr = expressions[i];\n if (expr?.type === 'Identifier') {\n const resolved = stringConsts?.get(expr.name);\n if (resolved != null) {\n result += resolved;\n continue;\n }\n }\n // Unresolvable — substitute empty string. This keeps the\n // surrounding HTML well-formed even if the resulting class\n // list is incomplete.\n }\n }\n meta[key] = result;\n } else {\n // Non-string, non-template-literal expression. Strip only the\n // outermost JS string delimiters, not every embedded quote.\n meta[key] = valText.replace(/^['\"`]|['\"`]$/g, '');\n }\n if (key === 'exportAs') meta.exportAs = [meta.exportAs];\n break;\n }\n case 'styleUrl': {\n const sv = stringValue(valNode, stringConsts);\n meta.styleUrls = [sv !== null ? sv : valText.replace(/['\"`]/g, '')];\n break;\n }\n case 'styleUrls':\n if (valNode.type === 'ArrayExpression') {\n meta.styleUrls = (valNode.elements || []).map((e: any) => {\n const sv = stringValue(e, stringConsts);\n return sv !== null\n ? sv\n : sourceCode.slice(e.start, e.end).replace(/['\"`]/g, '');\n });\n }\n break;\n case 'styles':\n if (valNode.type === 'ArrayExpression') {\n meta.styles = (valNode.elements || []).map((e: any) => {\n const sv = stringValue(e, stringConsts);\n return sv !== null\n ? sv\n : sourceCode.slice(e.start, e.end).replace(/['\"`]/g, '');\n });\n } else {\n const sv = stringValue(valNode, stringConsts);\n if (sv !== null) meta.styles = [sv];\n }\n break;\n case 'imports':\n case 'animations':\n case 'rawImports':\n case 'declarations':\n case 'exports':\n case 'bootstrap':\n if (valNode.type === 'ArrayExpression') {\n meta[key] = (valNode.elements || []).map(\n (e: any) => new o.WrappedNodeExpr(unwrapForwardRefOxc(e)),\n );\n }\n break;\n case 'providers':\n case 'viewProviders':\n if (valNode.type === 'ArrayExpression') {\n meta[key] = (valNode.elements || []).map(\n (e: any) => new o.WrappedNodeExpr(unwrapForwardRefOxc(e)),\n );\n } else {\n // `providers: safeProviders` / `viewProviders: SHARED_PROVIDERS`\n // — a reference to a module-level const (or any non-literal\n // expression such as a spread or function call) rather than an\n // inline array literal. ngtsc's partial evaluator expands the\n // identifier to its array; fastCompile does no static evaluation,\n // so it cannot. But Angular emits injector/host `providers` as a\n // single Expression and flattens nested arrays at runtime, so the\n // reference can be passed through by value. Storing it as a bare\n // `o.Expression` (not an array) signals the emission sites to emit\n // it directly instead of wrapping it in a `LiteralArrayExpr`.\n // Without this, the whole `providers` list is silently dropped and\n // every token it provides fails at runtime with NG0201.\n meta[key] = new o.WrappedNodeExpr(valNode);\n }\n break;\n // @Injectable provider configuration. Pass these through to\n // compileInjectable so the emitted `ɵprov` reflects the user's\n // intent. `useClass`/`useExisting`/`useValue` are\n // `MaybeForwardRefExpression` (`{ expression, forwardRef }`);\n // `useFactory` is a bare `Expression`.\n case 'useClass':\n case 'useExisting':\n case 'useValue': {\n const unwrapped = unwrapForwardRefOxc(valNode);\n const isForwardRef =\n valNode.type === 'CallExpression' && unwrapped !== valNode;\n meta[key] = {\n expression: new o.WrappedNodeExpr(unwrapped),\n forwardRef: isForwardRef ? 2 : 0,\n };\n break;\n }\n case 'useFactory':\n meta[key] = new o.WrappedNodeExpr(valNode);\n break;\n // `@Injectable({ deps: [...] })` — the dependency list for `useFactory`\n // / `useClass`. Each entry is either a bare token or a flag array such\n // as `[new Optional(), new SkipSelf(), Token]`. Without parsing this the\n // emitted factory ignores the deps and calls the factory/ctor with no\n // arguments.\n case 'deps':\n if (valNode.type === 'ArrayExpression') {\n meta.deps = extractInjectableDeps(valNode, sourceCode);\n }\n break;\n // `@Service` configuration. `autoProvided` defaults to `true`, so only\n // an explicit `false` is meaningful; `factory` is a bare expression\n // forwarded to compileService.\n case 'autoProvided':\n meta.autoProvided = valText === 'true';\n break;\n case 'factory':\n meta.factory = new o.WrappedNodeExpr(valNode);\n break;\n case 'hostDirectives':\n if (valNode.type === 'ArrayExpression') {\n meta.hostDirectives = (valNode.elements || [])\n .map((el: any) => {\n // Bare identifier: hostDirectives: [MatTooltip]\n if (el.type === 'Identifier' || el.type === 'CallExpression') {\n const unwrapped = unwrapForwardRefOxc(el);\n const ref = {\n value: new o.WrappedNodeExpr(unwrapped),\n type: new o.WrappedNodeExpr(unwrapped),\n };\n return {\n directive: ref,\n isForwardReference: el.type === 'CallExpression',\n inputs: null,\n outputs: null,\n };\n }\n // Object form: { directive: MatTooltip, inputs: [...], outputs: [...] }\n if (el.type === 'ObjectExpression') {\n let directiveNode: any = null;\n let isForwardRef = false;\n let inputs: Record<string, string> | null = null;\n let outputs: Record<string, string> | null = null;\n for (const prop of el.properties || []) {\n if (\n prop.type !== 'ObjectProperty' &&\n prop.type !== 'Property'\n )\n continue;\n const pName = propKeyName(prop);\n if (pName === 'directive') {\n directiveNode = unwrapForwardRefOxc(prop.value);\n isForwardRef =\n prop.value?.type === 'CallExpression' &&\n sourceCode\n .slice(prop.value.start, prop.value.end)\n .includes('forwardRef');\n } else if (\n pName === 'inputs' &&\n prop.value?.type === 'ArrayExpression'\n ) {\n inputs = {};\n for (const e of prop.value.elements || []) {\n const sv = stringValue(e);\n if (sv !== null) {\n const [source, alias = source] = sv\n .split(':')\n .map((part: string) => part.trim());\n if (source) inputs[source] = alias;\n }\n }\n } else if (\n pName === 'outputs' &&\n prop.value?.type === 'ArrayExpression'\n ) {\n outputs = {};\n for (const e of prop.value.elements || []) {\n const sv = stringValue(e);\n if (sv !== null) {\n const [source, alias = source] = sv\n .split(':')\n .map((part: string) => part.trim());\n if (source) outputs[source] = alias;\n }\n }\n }\n }\n if (directiveNode) {\n const ref = {\n value: new o.WrappedNodeExpr(directiveNode),\n type: new o.WrappedNodeExpr(directiveNode),\n };\n return {\n directive: ref,\n isForwardReference: isForwardRef,\n inputs,\n outputs,\n };\n }\n }\n return null;\n })\n .filter(Boolean);\n }\n break;\n default:\n meta[key] = valText.replace(/['\"`]/g, '');\n }\n }\n return meta;\n}\n\n/**\n * Detect signal-based APIs on class members: input(), model(), output(),\n * viewChild(), contentChild(), viewChildren(), contentChildren().\n */\nexport function detectSignals(classNode: any, sourceCode: string) {\n const inputs: any = {},\n outputs: any = {},\n viewQueries: any[] = [],\n contentQueries: any[] = [];\n\n const members: any[] = classNode.body?.body || [];\n\n for (const m of members) {\n if (\n m.type !== 'PropertyDefinition' ||\n !m.key?.name ||\n !m.value ||\n m.value.type !== 'CallExpression'\n )\n continue;\n\n const name: string = m.key.name;\n const signalCall = getCallApi(m.value);\n if (!signalCall) continue;\n\n const { api, required } = signalCall;\n if (!SIGNAL_APIS.has(api)) continue;\n\n // Skip signal synthesis when an explicit Angular decorator already\n // covers the same field. Mirrors Angular's transform behavior\n // (input_function.ts:42-48 et al.) and the JIT fix in\n // jit-metadata.ts. Without this, the downstream merge in compile.ts\n // overwrites decorator-derived metadata or, worse, concats duplicate\n // query entries that fire twice.\n const explicit = new Set<string>();\n for (const dec of m.decorators || []) {\n const decName: string | undefined = dec.expression?.callee?.name;\n if (decName && FIELD_DECORATORS.has(decName)) explicit.add(decName);\n }\n const hasInput = explicit.has('Input');\n const hasOutput = explicit.has('Output');\n const hasQuery =\n explicit.has('ViewChild') ||\n explicit.has('ViewChildren') ||\n explicit.has('ContentChild') ||\n explicit.has('ContentChildren');\n if (api === 'input' && hasInput) continue;\n if (api === 'model' && (hasInput || hasOutput)) continue;\n if ((api === 'output' || api === 'outputFromObservable') && hasOutput) {\n continue;\n }\n if (\n (api === 'viewChild' ||\n api === 'viewChildren' ||\n api === 'contentChild' ||\n api === 'contentChildren') &&\n hasQuery\n ) {\n continue;\n }\n\n const args: any[] = m.value.arguments || [];\n\n // 1. SIGNAL INPUTS (Standard & Required)\n if (api === 'input') {\n let alias: string | null = null;\n const optionsArg = required ? args[0] : args[1];\n if (optionsArg?.type === 'ObjectExpression') {\n for (const prop of optionsArg.properties || []) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property')\n continue;\n if (propKeyName(prop) === 'alias') {\n const sv = stringValue(prop.value);\n if (sv !== null) alias = sv;\n }\n }\n }\n inputs[name] = {\n classPropertyName: name,\n // The binding (public) name is the alias if provided, otherwise\n // the class property name. Without honoring `alias`, host\n // directives that map by public name (e.g.\n // `inputs: ['aria-label']` against `ariaLabel = input(null, {\n // alias: 'aria-label' })`) fail at runtime with NG0311.\n bindingPropertyName: alias ?? name,\n isSignal: true,\n required,\n // Always null for signal inputs. The input() factory already\n // applies the user's transform internally; forwarding it to the\n // directive metadata would make Angular's emitter set the\n // HasDecoratorInputTransform flag, causing the transform to run\n // again via the runtime input setter. Mirrors upstream\n // input_function.ts:74.\n transform: null,\n };\n }\n\n // 2. MODEL SIGNALS (Writable Inputs)\n else if (api === 'model') {\n // model() supports the same options object as input(); honor `alias`\n // for the same reason (host-directive mappings use the public name).\n let alias: string | null = null;\n const optionsArg = required ? args[0] : args[1];\n if (optionsArg?.type === 'ObjectExpression') {\n for (const prop of optionsArg.properties || []) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property')\n continue;\n if (propKeyName(prop) === 'alias') {\n const sv = stringValue(prop.value);\n if (sv !== null) alias = sv;\n }\n }\n }\n inputs[name] = {\n classPropertyName: name,\n bindingPropertyName: alias ?? name,\n isSignal: true,\n // Propagate `.required` so the runtime enforces the unbound-required\n // check. Without this, `model.required(...)` accepts an unbound parent\n // and the model signal stays at its undefined initial value silently.\n required,\n };\n // The compiled `outputs` field is `{ classPropertyName: bindingName }`.\n // Angular inverts this at runtime via\n // `parseAndConvertOutputsForDefinition`, producing the lookup map\n // `{ bindingName: classPropertyName }` used by `listenToOutput`.\n // For a `model()` signal, the class property is `name` and the\n // binding event is `${aliasOrName}Change`, and the model signal\n // itself is the subscribable, so `instance[name]` is what\n // `listenToOutput` needs to resolve.\n outputs[name] = (alias ?? name) + 'Change';\n }\n\n // 3. SIGNAL QUERIES (viewChild, contentChild)\n else if (\n api === 'viewChild' ||\n api === 'viewChildren' ||\n api === 'contentChild' ||\n api === 'contentChildren'\n ) {\n const isViewQuery = api === 'viewChild' || api === 'viewChildren';\n const isChildrenQuery =\n api === 'viewChildren' || api === 'contentChildren';\n\n const firstArg = args[0];\n const sv = stringValue(firstArg);\n\n // Parse the optional second-arg options object for `read` and\n // (content queries only) `descendants`. Without this, queries like\n // `viewChild('ref', { read: ElementRef })` and\n // `contentChildren(Foo, { descendants: false })` silently lose\n // their options at runtime.\n let read: any = null;\n // Defaults match Angular's signal-query API and the decorator\n // path (`isView || isFirst` in detectFieldDecorators):\n // viewChild → true (view queries always traverse)\n // viewChildren → true\n // contentChild → true (single-result content queries\n // traverse by default)\n // contentChildren → false (multi-result content queries are\n // shallow unless explicitly opted in)\n let descendants = isViewQuery || !isChildrenQuery;\n const optArg = args[1];\n if (optArg?.type === 'ObjectExpression') {\n for (const prop of optArg.properties || []) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property')\n continue;\n const k = propKeyName(prop);\n if (k === 'read') {\n read = new o.WrappedNodeExpr(unwrapForwardRefOxc(prop.value));\n } else if (k === 'descendants') {\n const t = prop.value?.type;\n if (\n t === 'BooleanLiteral' ||\n (t === 'Literal' && typeof prop.value.value === 'boolean')\n ) {\n descendants = prop.value.value;\n }\n }\n }\n }\n\n const query = {\n propertyName: name,\n // Class predicates must be wrapped in an `R3QueryReference`\n // (`{ forwardRef, expression }`); Angular's `getQueryPredicate`\n // dispatches on `predicate.forwardRef` and reads\n // `predicate.expression`, so a bare `WrappedNodeExpr` is silently\n // dropped to `undefined` and emitted as `null`, leaving the query\n // with no target. `0 = ForwardRefHandling.None`.\n predicate:\n sv !== null\n ? [sv]\n : { forwardRef: 0, expression: new o.WrappedNodeExpr(firstArg) },\n first: !isChildrenQuery,\n descendants,\n read,\n static: false,\n emitFlags: 0,\n isSignal: true,\n };\n\n if (isViewQuery) viewQueries.push(query);\n else contentQueries.push(query);\n }\n\n // 4. STANDARD OUTPUTS (output() and outputFromObservable())\n else if (api === 'output' || api === 'outputFromObservable') {\n let alias = name;\n // outputFromObservable(observable, options) — options is args[1].\n // output(options) — options is args[0]. Mirrors upstream\n // output_function.ts:81.\n const optArg = api === 'outputFromObservable' ? args[1] : args[0];\n if (optArg?.type === 'ObjectExpression') {\n for (const prop of optArg.properties || []) {\n if (\n (prop.type === 'ObjectProperty' || prop.type === 'Property') &&\n propKeyName(prop) === 'alias'\n ) {\n const sv = stringValue(prop.value);\n if (sv !== null) alias = sv;\n }\n }\n }\n outputs[name] = alias;\n }\n }\n\n return { inputs, outputs, viewQueries, contentQueries };\n}\n\n/**\n * Detect decorator-based field metadata: @Input, @Output, @ViewChild,\n * @ContentChild, @ViewChildren, @ContentChildren, @HostBinding, @HostListener.\n */\nexport function detectFieldDecorators(classNode: any, sourceCode: string) {\n const inputs: any = {};\n const outputs: any = {};\n const viewQueries: any[] = [];\n const contentQueries: any[] = [];\n const hostProperties: Record<string, string> = {};\n const hostListeners: Record<string, string> = {};\n\n const members: any[] = classNode.body?.body || [];\n\n for (const member of members) {\n const decorators: any[] = member.decorators || [];\n if (decorators.length === 0) continue;\n\n const memberName: string = member.key?.name || '';\n\n for (const dec of decorators) {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') continue;\n const decName: string | undefined = expr.callee?.name;\n if (!decName) continue;\n const args: any[] = expr.arguments || [];\n\n switch (decName) {\n case 'Input': {\n let bindingName = memberName;\n let required = false;\n let transformFunction: any = null;\n\n if (args.length > 0) {\n const arg = args[0];\n const sv = stringValue(arg);\n if (sv !== null) {\n bindingName = sv;\n } else if (arg.type === 'ObjectExpression') {\n for (const prop of arg.properties || []) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property')\n continue;\n const k = propKeyName(prop);\n if (k === 'alias') {\n const asv = stringValue(prop.value);\n if (asv !== null) bindingName = asv;\n }\n if (k === 'required')\n required =\n sourceCode.slice(prop.value.start, prop.value.end) ===\n 'true';\n if (k === 'transform')\n transformFunction = new o.WrappedNodeExpr(prop.value);\n }\n }\n }\n\n inputs[memberName] = {\n classPropertyName: memberName,\n bindingPropertyName: bindingName,\n isSignal: false,\n required,\n transformFunction,\n };\n break;\n }\n\n case 'Output': {\n const sv = args.length > 0 ? stringValue(args[0]) : null;\n const alias = sv !== null ? sv : memberName;\n outputs[memberName] = alias;\n break;\n }\n\n case 'ViewChild':\n case 'ViewChildren':\n case 'ContentChild':\n case 'ContentChildren': {\n const isView = decName.startsWith('View');\n const isFirst = decName === 'ViewChild' || decName === 'ContentChild';\n\n // Default predicate when no argument is given is the member\n // name. Class predicates (the non-string case) must be wrapped\n // in an `R3QueryReference` (`{ forwardRef, expression }`) so\n // Angular's `getQueryPredicate` can dispatch on `forwardRef`\n // and read `.expression`. A bare `WrappedNodeExpr` is silently\n // dropped to undefined and emitted as `null`.\n let predicate: any = [memberName];\n if (args.length > 0) {\n const pred = args[0];\n const sv = stringValue(pred);\n if (sv !== null) {\n predicate = [sv];\n } else {\n predicate = {\n forwardRef: 0,\n expression: new o.WrappedNodeExpr(unwrapForwardRefOxc(pred)),\n };\n }\n }\n\n let read: any = null;\n let isStatic = false;\n let descendants = isView || isFirst;\n\n if (args.length > 1 && args[1]?.type === 'ObjectExpression') {\n for (const prop of args[1].properties || []) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property')\n continue;\n const k = propKeyName(prop);\n if (k === 'read') read = new o.WrappedNodeExpr(prop.value);\n if (k === 'static')\n isStatic =\n sourceCode.slice(prop.value.start, prop.value.end) === 'true';\n if (k === 'descendants')\n descendants =\n sourceCode.slice(prop.value.start, prop.value.end) === 'true';\n }\n }\n\n const query = {\n propertyName: memberName,\n predicate,\n first: isFirst,\n descendants,\n read,\n static: isStatic,\n emitFlags: 0,\n isSignal: false,\n };\n\n if (isView) viewQueries.push(query);\n else contentQueries.push(query);\n break;\n }\n\n case 'HostBinding': {\n const sv = args.length > 0 ? stringValue(args[0]) : null;\n const target = sv !== null ? sv : memberName;\n hostProperties[target] = memberName;\n break;\n }\n\n case 'HostListener': {\n const sv = args.length > 0 ? stringValue(args[0]) : null;\n if (sv !== null) {\n const event = sv;\n let handler = `${memberName}()`;\n if (args.length > 1 && args[1]?.type === 'ArrayExpression') {\n const handlerArgs = (args[1].elements || [])\n .map((e: any) => stringValue(e))\n .filter((v: string | null): v is string => v !== null)\n .join(', ');\n handler = `${memberName}(${handlerArgs})`;\n }\n hostListeners[event] = handler;\n }\n break;\n }\n }\n }\n }\n\n return {\n inputs,\n outputs,\n viewQueries,\n contentQueries,\n hostProperties,\n hostListeners,\n };\n}\n\n/**\n * Analyze constructor parameters for dependency injection.\n * Returns:\n * - R3DependencyMetadata[] for normal constructors\n * - null if class extends another without own constructor (use inherited factory)\n * - 'invalid' if any parameter has a type-only import token\n *\n * Accepts an OXC ClassDeclaration node and the original source string.\n */\n/**\n * Parse an `@Injectable({ deps: [...] })` dependency list into\n * R3DependencyMetadata. Each element is either a bare token expression or a\n * flag array combining DI modifiers with the token, e.g.\n * `[new Optional(), new SkipSelf(), Token]` or `[new Inject(TOKEN)]`.\n */\nfunction extractInjectableDeps(depsNode: any, sourceCode: string): any[] {\n const deps: any[] = [];\n for (const el of depsNode.elements || []) {\n if (!el) continue;\n let tokenNode: any = el;\n let optional = false,\n self = false,\n skipSelf = false,\n host = false;\n\n if (el.type === 'ArrayExpression') {\n // Flag array: zero or more `new <Modifier>()` instances plus the token.\n tokenNode = null;\n for (const item of el.elements || []) {\n if (!item) continue;\n if (item.type === 'NewExpression') {\n switch (item.callee?.name) {\n case 'Optional':\n optional = true;\n continue;\n case 'Self':\n self = true;\n continue;\n case 'SkipSelf':\n skipSelf = true;\n continue;\n case 'Host':\n host = true;\n continue;\n case 'Inject':\n tokenNode = item.arguments?.[0] ?? null;\n continue;\n }\n }\n // Bare token (identifier, member expression, `new InjectionToken()`…)\n tokenNode = item;\n }\n }\n\n // Unwrap `forwardRef(() => TOKEN)` to TOKEN so the emitted factory\n // references the token directly — matching `extractConstructorDeps` and\n // covering every form (`deps: [forwardRef(...)]`,\n // `[new Inject(forwardRef(...))]`, `[[new Optional(), forwardRef(...)]]`).\n const resolvedToken = tokenNode ? unwrapForwardRefOxc(tokenNode) : null;\n const tokenStr = resolvedToken\n ? sourceCode.slice(resolvedToken.start, resolvedToken.end)\n : null;\n deps.push({\n token: tokenStr\n ? new o.WrappedNodeExpr(tokenStr)\n : new o.LiteralExpr(null),\n attributeNameType: null,\n host,\n optional,\n self,\n skipSelf,\n });\n }\n return deps;\n}\n\nexport function extractConstructorDeps(\n classNode: any,\n sourceCode: string,\n typeOnlyImports: Set<string>,\n): any[] | 'invalid' | null {\n const heritage: any[] = classNode.superClass ? [classNode.superClass] : [];\n const hasSuper = heritage.length > 0;\n\n const members: any[] = classNode.body?.body || [];\n const ctors = members.filter(\n (m: any) => m.type === 'MethodDefinition' && m.kind === 'constructor',\n );\n // With overloaded constructors, only the implementation carries the real\n // parameter list and parameter decorators; the overload *signatures* have\n // `value.body === null`. Picking the first constructor would read an\n // overload signature and emit a factory missing the remaining deps.\n const ctor = ctors.find((m: any) => m.value?.body != null) ?? ctors[0];\n\n if (!ctor) {\n return hasSuper ? null : [];\n }\n\n const params: any[] = ctor.value?.params?.items || ctor.value?.params || [];\n const deps: any[] = [];\n let invalid = false;\n\n for (const param of params) {\n let token: string | null = null;\n // For `@Attribute(...)` the injected value is the attribute name itself,\n // not a type token. `attributeToken` holds that name expression (a string\n // literal for `@Attribute('name')`, or the raw expression for a computed\n // name like `@Attribute(dynamicAttrName())`); `attributeNameType` being\n // non-null flags the dep as an attribute injection so the factory emits\n // `ɵɵinjectAttribute(<name>)` instead of `ɵɵdirectiveInject(...)`.\n let attributeToken: any = null;\n let attributeNameType: any = null;\n let host = false,\n optional = false,\n self = false,\n skipSelf = false;\n\n // Handle TSParameterProperty (e.g., constructor(private foo: Bar))\n const actualParam =\n param.type === 'TSParameterProperty' ? param.parameter : param;\n const typeAnn =\n actualParam?.typeAnnotation?.typeAnnotation ??\n param?.typeAnnotation?.typeAnnotation;\n\n // Extract type annotation as token\n if (typeAnn) {\n if (typeAnn.type === 'TSTypeReference' && typeAnn.typeName) {\n token =\n typeAnn.typeName.name ??\n sourceCode.slice(typeAnn.typeName.start, typeAnn.typeName.end);\n } else if (typeAnn.type === 'TSUnionType') {\n // Filter out null/undefined/void arms — `T | null` and\n // `T | undefined` are common patterns that should resolve to T.\n // Anything else (multiple TypeReference arms, primitives, etc.)\n // is ambiguous and ngtsc rejects it. Mark as invalid so the\n // factory falls through to ɵɵinvalidFactory rather than\n // silently picking the first arm.\n const nonNullTypes = (typeAnn.types || []).filter((t: any) => {\n if (!t) return false;\n if (t.type === 'TSNullKeyword') return false;\n if (t.type === 'TSUndefinedKeyword') return false;\n if (t.type === 'TSVoidKeyword') return false;\n if (\n t.type === 'TSLiteralType' &&\n (t.literal?.type === 'NullLiteral' ||\n (t.literal?.type === 'Literal' && t.literal.value === null))\n ) {\n return false;\n }\n return true;\n });\n if (\n nonNullTypes.length === 1 &&\n nonNullTypes[0].type === 'TSTypeReference' &&\n nonNullTypes[0].typeName\n ) {\n const t = nonNullTypes[0];\n token =\n t.typeName.name ??\n sourceCode.slice(t.typeName.start, t.typeName.end);\n } else {\n // Ambiguous union — no suitable injection token.\n invalid = true;\n continue;\n }\n } else if (typeAnn.type === 'TSIntersectionType') {\n // Intersection types (`A & B`) have no single injection token.\n invalid = true;\n continue;\n }\n }\n\n // Process parameter decorators (may live on TSParameterProperty or inner param)\n const paramDecs: any[] = [\n ...(param.decorators || []),\n ...(param.type === 'TSParameterProperty' && actualParam?.decorators\n ? actualParam.decorators\n : []),\n ];\n for (const dec of paramDecs) {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') continue;\n const decName: string | undefined = expr.callee?.name;\n if (!decName) continue;\n const args: any[] = expr.arguments || [];\n\n switch (decName) {\n case 'Inject':\n if (args.length > 0) {\n const sv = stringValue(args[0]);\n if (sv !== null) {\n token = sv;\n } else {\n // Unwrap `@Inject(forwardRef(() => TOKEN))` so the\n // emitted token references TOKEN directly. Without this\n // the raw `forwardRef(() => TOKEN)` source slice would\n // appear in the factory output, producing broken code\n // that calls forwardRef at definition time.\n const unwrapped = unwrapForwardRefOxc(args[0]);\n token = sourceCode.slice(unwrapped.start, unwrapped.end);\n }\n }\n break;\n case 'Optional':\n optional = true;\n break;\n case 'Self':\n self = true;\n break;\n case 'SkipSelf':\n skipSelf = true;\n break;\n case 'Host':\n host = true;\n break;\n case 'Attribute':\n if (args.length > 0) {\n const sv = stringValue(args[0]);\n if (sv !== null) {\n attributeToken = new o.LiteralExpr(sv);\n attributeNameType = new o.LiteralExpr(sv);\n } else {\n // Computed attribute name, e.g. `@Attribute(dynamicAttrName())`.\n // ngtsc emits `ɵɵinjectAttribute(<expr>)`; pass the expression\n // through by value. `attributeNameType` only feeds the (unused)\n // `.d.ts` type, so a placeholder is sufficient to flag the dep.\n attributeToken = new o.WrappedNodeExpr(args[0]);\n attributeNameType = new o.LiteralExpr('unknown');\n }\n token = '';\n }\n break;\n }\n }\n\n if (!token && !attributeToken) {\n invalid = true;\n continue;\n }\n\n if (token && typeOnlyImports.has(token)) {\n invalid = true;\n continue;\n }\n\n deps.push({\n token:\n attributeToken ??\n (token ? new o.WrappedNodeExpr(token) : new o.LiteralExpr(null)),\n attributeNameType,\n host,\n optional,\n self,\n skipSelf,\n });\n }\n\n return invalid ? 'invalid' : deps;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"metadata.js","names":[],"sources":["../../../../src/lib/compiler/metadata.ts"],"sourcesContent":["import * as o from '@angular/compiler';\nimport { unwrapForwardRefOxc } from './utils.js';\nimport { FIELD_DECORATORS, SIGNAL_APIS } from './constants.js';\n\nfunction getCallApi(call: any): { api: string; required: boolean } | null {\n const callee = call.callee;\n if (!callee) return null;\n\n if (callee.type === 'Identifier') {\n return { api: callee.name, required: false };\n }\n\n if (\n (callee.type === 'StaticMemberExpression' ||\n callee.type === 'MemberExpression') &&\n callee.object?.type === 'Identifier' &&\n callee.property?.name === 'required'\n ) {\n return { api: callee.object.name, required: true };\n }\n\n return null;\n}\n\n/**\n * Extract the string value from an OXC string literal or template literal node.\n *\n * If `consts` is provided, interpolated template literals (e.g.\n * `\\`hello ${NAME}\\``) are resolved when every `${...}` expression is a bare\n * `Identifier` whose name is present in the map. This lets metadata fields\n * such as `template:` reference module-level string constants via JS\n * template-literal interpolation:\n *\n * const tw = `text-zinc-700 hover:text-zinc-900`;\n * @Component({ template: `<a class=\"${tw}\">x</a>` })\n *\n * Returns `null` if the node is not statically resolvable.\n */\nfunction stringValue(node: any, consts?: Map<string, string>): string | null {\n // Type-only wrappers such as `'x' as const` and parentheses don't change the value.\n while (\n node?.type === 'TSAsExpression' ||\n node?.type === 'TSSatisfiesExpression' ||\n node?.type === 'ParenthesizedExpression'\n )\n node = node.expression;\n if (node?.type === 'StringLiteral') return node.value;\n if (node?.type === 'BinaryExpression' && node.operator === '+') {\n const operand = (n: any) =>\n n?.type === 'Identifier'\n ? (consts?.get(n.name) ?? null)\n : stringValue(n, consts);\n const left = operand(node.left);\n const right = left === null ? null : operand(node.right);\n return right === null ? null : left + right;\n }\n if (node?.type === 'Literal' && typeof node.value === 'string')\n return node.value;\n if (node?.type === 'TemplateLiteral') {\n const quasis = node.quasis ?? [];\n const expressions = node.expressions ?? [];\n if (expressions.length === 0) {\n return quasis[0]?.value?.cooked ?? null;\n }\n if (!consts) return null;\n let result = '';\n for (let i = 0; i < quasis.length; i++) {\n const cooked = quasis[i]?.value?.cooked;\n if (cooked == null) return null;\n result += cooked;\n if (i < expressions.length) {\n const expr = expressions[i];\n if (expr?.type !== 'Identifier') return null;\n const resolved = consts.get(expr.name);\n if (resolved == null) return null;\n result += resolved;\n }\n }\n return result;\n }\n return null;\n}\n\n/** Check if an OXC node is a string-like literal. */\nfunction isStringLike(node: any, consts?: Map<string, string>): boolean {\n return stringValue(node, consts) !== null;\n}\n\n/**\n * Walk the top-level statements of an OXC program and collect a map of\n * statically-resolvable string-valued `const NAME = ...` declarations.\n *\n * Used so decorator metadata fields like `template:` can reference\n * module-level Tailwind class chains (or any other string constants) via\n * JS template-literal interpolation. Resolution is iterative: a const may\n * reference earlier-resolved consts via `${other}` interpolation.\n *\n * Only `const` declarations are considered. Non-string initializers,\n * function calls, member access, and any expression that cannot be reduced\n * to a string at parse time are ignored.\n */\nexport function collectStringConstants(oxcProgram: any): Map<string, string> {\n const rawDecls = new Map<string, any>();\n for (const stmt of oxcProgram?.body || []) {\n const decl =\n stmt.type === 'ExportNamedDeclaration' ? stmt.declaration : stmt;\n if (!decl || decl.type !== 'VariableDeclaration' || decl.kind !== 'const')\n continue;\n for (const d of decl.declarations || []) {\n if (d.id?.type === 'Identifier' && d.init) {\n rawDecls.set(d.id.name, d.init);\n }\n }\n }\n\n const resolved = new Map<string, string>();\n // Iterative fixpoint: each pass resolves consts whose dependencies are\n // already known. Bounded by the number of declarations to prevent cycles.\n for (let pass = 0; pass < rawDecls.size + 1; pass++) {\n let progress = false;\n for (const [name, init] of rawDecls) {\n if (resolved.has(name)) continue;\n const value = stringValue(init, resolved);\n if (value !== null) {\n resolved.set(name, value);\n progress = true;\n }\n }\n if (!progress) break;\n }\n return resolved;\n}\n\n/** Get the property key name from an OXC object property. */\nfunction propKeyName(prop: any): string | null {\n if (!prop.key) return null;\n return prop.key.name ?? prop.key.value ?? null;\n}\n\n/** Resolve a host key or value to a string literal or same-file string const. */\nfunction hostString(node: any, consts?: Map<string, string>): string | null {\n if (node?.type === 'Identifier') return consts?.get(node.name) ?? null;\n return stringValue(node, consts);\n}\n\n/**\n * Extract decorator metadata from an OXC decorator AST node.\n * Parses @Component, @Directive, @Pipe, @Injectable, @Service, @NgModule arguments.\n *\n * `stringConsts`, when provided, lets string-typed metadata fields\n * (`template`, `selector`, `templateUrl`, `styles`, `styleUrl`, `styleUrls`,\n * `name`, `exportAs`, `providedIn`) resolve module-level string constants\n * referenced via template-literal interpolation, e.g.\n * `template: \\`<div class=\"${tw}\">x</div>\\``.\n */\nexport function extractMetadata(\n dec: any | undefined,\n sourceCode: string,\n stringConsts?: Map<string, string>,\n): any {\n if (!dec) return null;\n const call = dec.expression;\n if (!call || call.type !== 'CallExpression') return null;\n const arg = call.arguments?.[0];\n const meta: any = {\n hostRaw: {},\n inputs: {},\n outputs: {},\n standalone: true,\n imports: [],\n providers: null,\n viewProviders: null,\n animations: null,\n changeDetection: null,\n encapsulation: null,\n preserveWhitespaces: false,\n exportAs: null,\n selector: undefined,\n styles: [],\n templateUrl: null,\n styleUrls: [],\n };\n if (!arg || arg.type !== 'ObjectExpression') return meta;\n\n for (const p of arg.properties || []) {\n if (p.type !== 'ObjectProperty' && p.type !== 'Property') continue;\n const key = propKeyName(p);\n if (!key) continue;\n const valNode = p.value;\n const valText = sourceCode.slice(valNode.start, valNode.end);\n\n switch (key) {\n case 'host':\n if (valNode.type === 'ObjectExpression') {\n for (const hp of valNode.properties || []) {\n const hKey = hp.computed\n ? hostString(hp.key, stringConsts)\n : propKeyName(hp);\n const hVal = hostString(hp.value, stringConsts);\n // Spreads, imported constants, and other expressions cannot be\n // evaluated without a ts.Program; fail instead of emitting the\n // identifier name as the binding.\n if (hKey === null || hVal === null) {\n throw new Error(\n `[fast-compile] Cannot statically resolve host binding \\`${sourceCode.slice(hp.start, hp.end)}\\`. ` +\n 'Only string literals and string constants declared in the same file are supported; ' +\n 'use a string literal or @HostBinding/@HostListener instead.',\n );\n }\n meta.hostRaw[String(hKey).replace(/^['\"`]|['\"`]$/g, '')] = hVal;\n }\n }\n break;\n case 'changeDetection':\n meta.changeDetection = valText.includes('OnPush') ? 0 : 1;\n break;\n case 'encapsulation':\n meta.encapsulation = valText.includes('None')\n ? 2\n : valText.includes('ShadowDom')\n ? 3\n : 0;\n break;\n case 'preserveWhitespaces':\n meta.preserveWhitespaces = valText === 'true';\n break;\n case 'pure':\n case 'standalone':\n meta[key] = valText !== 'false';\n break;\n case 'template':\n case 'selector':\n case 'name':\n case 'exportAs':\n case 'templateUrl':\n case 'providedIn': {\n const sv = stringValue(valNode, stringConsts);\n if (sv !== null) {\n meta[key] = sv;\n } else if (valNode.type === 'TemplateLiteral') {\n // Template literal with `${...}` interpolations that couldn't\n // all be resolved at parse time (e.g. they reference imports\n // or non-string values). The previous fallback stripped every\n // quote character from the source, which silently corrupted\n // templates such as `<a class=\"${cls} foo\">…</a>` into\n // `<a class=${cls} foo>…</a>` — making Angular's HTML parser\n // fail with confusing errors like `Opening tag \"a\" not\n // terminated`. Instead, walk the quasis and substitute each\n // unresolved interpolation with the empty string so the\n // surrounding HTML (including quoted attributes) is preserved.\n const quasis = valNode.quasis ?? [];\n const expressions = valNode.expressions ?? [];\n let result = '';\n for (let i = 0; i < quasis.length; i++) {\n result += quasis[i]?.value?.cooked ?? '';\n if (i < expressions.length) {\n const expr = expressions[i];\n if (expr?.type === 'Identifier') {\n const resolved = stringConsts?.get(expr.name);\n if (resolved != null) {\n result += resolved;\n continue;\n }\n }\n // Unresolvable — substitute empty string. This keeps the\n // surrounding HTML well-formed even if the resulting class\n // list is incomplete.\n }\n }\n meta[key] = result;\n } else {\n // Non-string, non-template-literal expression. Strip only the\n // outermost JS string delimiters, not every embedded quote.\n meta[key] = valText.replace(/^['\"`]|['\"`]$/g, '');\n }\n if (key === 'exportAs') meta.exportAs = [meta.exportAs];\n break;\n }\n case 'styleUrl': {\n const sv = stringValue(valNode, stringConsts);\n meta.styleUrls = [sv !== null ? sv : valText.replace(/['\"`]/g, '')];\n break;\n }\n case 'styleUrls':\n if (valNode.type === 'ArrayExpression') {\n meta.styleUrls = (valNode.elements || []).map((e: any) => {\n const sv = stringValue(e, stringConsts);\n return sv !== null\n ? sv\n : sourceCode.slice(e.start, e.end).replace(/['\"`]/g, '');\n });\n }\n break;\n case 'styles':\n if (valNode.type === 'ArrayExpression') {\n meta.styles = (valNode.elements || []).map((e: any) => {\n const sv = stringValue(e, stringConsts);\n return sv !== null\n ? sv\n : sourceCode.slice(e.start, e.end).replace(/['\"`]/g, '');\n });\n } else {\n const sv = stringValue(valNode, stringConsts);\n if (sv !== null) meta.styles = [sv];\n }\n break;\n case 'imports':\n case 'animations':\n case 'rawImports':\n case 'declarations':\n case 'exports':\n case 'bootstrap':\n if (valNode.type === 'ArrayExpression') {\n meta[key] = (valNode.elements || []).map(\n (e: any) => new o.WrappedNodeExpr(unwrapForwardRefOxc(e)),\n );\n }\n break;\n case 'providers':\n case 'viewProviders':\n if (valNode.type === 'ArrayExpression') {\n meta[key] = (valNode.elements || []).map(\n (e: any) => new o.WrappedNodeExpr(unwrapForwardRefOxc(e)),\n );\n } else {\n // `providers: safeProviders` / `viewProviders: SHARED_PROVIDERS`\n // — a reference to a module-level const (or any non-literal\n // expression such as a spread or function call) rather than an\n // inline array literal. ngtsc's partial evaluator expands the\n // identifier to its array; fastCompile does no static evaluation,\n // so it cannot. But Angular emits injector/host `providers` as a\n // single Expression and flattens nested arrays at runtime, so the\n // reference can be passed through by value. Storing it as a bare\n // `o.Expression` (not an array) signals the emission sites to emit\n // it directly instead of wrapping it in a `LiteralArrayExpr`.\n // Without this, the whole `providers` list is silently dropped and\n // every token it provides fails at runtime with NG0201.\n meta[key] = new o.WrappedNodeExpr(valNode);\n }\n break;\n // @Injectable provider configuration. Pass these through to\n // compileInjectable so the emitted `ɵprov` reflects the user's\n // intent. `useClass`/`useExisting`/`useValue` are\n // `MaybeForwardRefExpression` (`{ expression, forwardRef }`);\n // `useFactory` is a bare `Expression`.\n case 'useClass':\n case 'useExisting':\n case 'useValue': {\n const unwrapped = unwrapForwardRefOxc(valNode);\n const isForwardRef =\n valNode.type === 'CallExpression' && unwrapped !== valNode;\n meta[key] = {\n expression: new o.WrappedNodeExpr(unwrapped),\n forwardRef: isForwardRef ? 2 : 0,\n };\n break;\n }\n case 'useFactory':\n meta[key] = new o.WrappedNodeExpr(valNode);\n break;\n // `@Injectable({ deps: [...] })` — the dependency list for `useFactory`\n // / `useClass`. Each entry is either a bare token or a flag array such\n // as `[new Optional(), new SkipSelf(), Token]`. Without parsing this the\n // emitted factory ignores the deps and calls the factory/ctor with no\n // arguments.\n case 'deps':\n if (valNode.type === 'ArrayExpression') {\n meta.deps = extractInjectableDeps(valNode, sourceCode);\n }\n break;\n // `@Service` configuration. `autoProvided` defaults to `true`, so only\n // an explicit `false` is meaningful; `factory` is a bare expression\n // forwarded to compileService.\n case 'autoProvided':\n meta.autoProvided = valText === 'true';\n break;\n case 'factory':\n meta.factory = new o.WrappedNodeExpr(valNode);\n break;\n case 'hostDirectives':\n if (valNode.type === 'ArrayExpression') {\n meta.hostDirectives = (valNode.elements || [])\n .map((el: any) => {\n // Bare identifier: hostDirectives: [MatTooltip]\n if (el.type === 'Identifier' || el.type === 'CallExpression') {\n const unwrapped = unwrapForwardRefOxc(el);\n const ref = {\n value: new o.WrappedNodeExpr(unwrapped),\n type: new o.WrappedNodeExpr(unwrapped),\n };\n return {\n directive: ref,\n isForwardReference: el.type === 'CallExpression',\n inputs: null,\n outputs: null,\n };\n }\n // Object form: { directive: MatTooltip, inputs: [...], outputs: [...] }\n if (el.type === 'ObjectExpression') {\n let directiveNode: any = null;\n let isForwardRef = false;\n let inputs: Record<string, string> | null = null;\n let outputs: Record<string, string> | null = null;\n for (const prop of el.properties || []) {\n if (\n prop.type !== 'ObjectProperty' &&\n prop.type !== 'Property'\n )\n continue;\n const pName = propKeyName(prop);\n if (pName === 'directive') {\n directiveNode = unwrapForwardRefOxc(prop.value);\n isForwardRef =\n prop.value?.type === 'CallExpression' &&\n sourceCode\n .slice(prop.value.start, prop.value.end)\n .includes('forwardRef');\n } else if (\n pName === 'inputs' &&\n prop.value?.type === 'ArrayExpression'\n ) {\n inputs = {};\n for (const e of prop.value.elements || []) {\n const sv = stringValue(e);\n if (sv !== null) {\n const [source, alias = source] = sv\n .split(':')\n .map((part: string) => part.trim());\n if (source) inputs[source] = alias;\n }\n }\n } else if (\n pName === 'outputs' &&\n prop.value?.type === 'ArrayExpression'\n ) {\n outputs = {};\n for (const e of prop.value.elements || []) {\n const sv = stringValue(e);\n if (sv !== null) {\n const [source, alias = source] = sv\n .split(':')\n .map((part: string) => part.trim());\n if (source) outputs[source] = alias;\n }\n }\n }\n }\n if (directiveNode) {\n const ref = {\n value: new o.WrappedNodeExpr(directiveNode),\n type: new o.WrappedNodeExpr(directiveNode),\n };\n return {\n directive: ref,\n isForwardReference: isForwardRef,\n inputs,\n outputs,\n };\n }\n }\n return null;\n })\n .filter(Boolean);\n }\n break;\n default:\n meta[key] = valText.replace(/['\"`]/g, '');\n }\n }\n return meta;\n}\n\n/**\n * Detect signal-based APIs on class members: input(), model(), output(),\n * viewChild(), contentChild(), viewChildren(), contentChildren().\n */\nexport function detectSignals(classNode: any, sourceCode: string) {\n const inputs: any = {},\n outputs: any = {},\n viewQueries: any[] = [],\n contentQueries: any[] = [];\n\n const members: any[] = classNode.body?.body || [];\n\n for (const m of members) {\n if (\n m.type !== 'PropertyDefinition' ||\n !m.key?.name ||\n !m.value ||\n m.value.type !== 'CallExpression'\n )\n continue;\n\n const name: string = m.key.name;\n const signalCall = getCallApi(m.value);\n if (!signalCall) continue;\n\n const { api, required } = signalCall;\n if (!SIGNAL_APIS.has(api)) continue;\n\n // Skip signal synthesis when an explicit Angular decorator already\n // covers the same field. Mirrors Angular's transform behavior\n // (input_function.ts:42-48 et al.) and the JIT fix in\n // jit-metadata.ts. Without this, the downstream merge in compile.ts\n // overwrites decorator-derived metadata or, worse, concats duplicate\n // query entries that fire twice.\n const explicit = new Set<string>();\n for (const dec of m.decorators || []) {\n const decName: string | undefined = dec.expression?.callee?.name;\n if (decName && FIELD_DECORATORS.has(decName)) explicit.add(decName);\n }\n const hasInput = explicit.has('Input');\n const hasOutput = explicit.has('Output');\n const hasQuery =\n explicit.has('ViewChild') ||\n explicit.has('ViewChildren') ||\n explicit.has('ContentChild') ||\n explicit.has('ContentChildren');\n if (api === 'input' && hasInput) continue;\n if (api === 'model' && (hasInput || hasOutput)) continue;\n if ((api === 'output' || api === 'outputFromObservable') && hasOutput) {\n continue;\n }\n if (\n (api === 'viewChild' ||\n api === 'viewChildren' ||\n api === 'contentChild' ||\n api === 'contentChildren') &&\n hasQuery\n ) {\n continue;\n }\n\n const args: any[] = m.value.arguments || [];\n\n // 1. SIGNAL INPUTS (Standard & Required)\n if (api === 'input') {\n let alias: string | null = null;\n const optionsArg = required ? args[0] : args[1];\n if (optionsArg?.type === 'ObjectExpression') {\n for (const prop of optionsArg.properties || []) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property')\n continue;\n if (propKeyName(prop) === 'alias') {\n const sv = stringValue(prop.value);\n if (sv !== null) alias = sv;\n }\n }\n }\n inputs[name] = {\n classPropertyName: name,\n // The binding (public) name is the alias if provided, otherwise\n // the class property name. Without honoring `alias`, host\n // directives that map by public name (e.g.\n // `inputs: ['aria-label']` against `ariaLabel = input(null, {\n // alias: 'aria-label' })`) fail at runtime with NG0311.\n bindingPropertyName: alias ?? name,\n isSignal: true,\n required,\n // Always null for signal inputs. The input() factory already\n // applies the user's transform internally; forwarding it to the\n // directive metadata would make Angular's emitter set the\n // HasDecoratorInputTransform flag, causing the transform to run\n // again via the runtime input setter. Mirrors upstream\n // input_function.ts:74.\n transform: null,\n };\n }\n\n // 2. MODEL SIGNALS (Writable Inputs)\n else if (api === 'model') {\n // model() supports the same options object as input(); honor `alias`\n // for the same reason (host-directive mappings use the public name).\n let alias: string | null = null;\n const optionsArg = required ? args[0] : args[1];\n if (optionsArg?.type === 'ObjectExpression') {\n for (const prop of optionsArg.properties || []) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property')\n continue;\n if (propKeyName(prop) === 'alias') {\n const sv = stringValue(prop.value);\n if (sv !== null) alias = sv;\n }\n }\n }\n inputs[name] = {\n classPropertyName: name,\n bindingPropertyName: alias ?? name,\n isSignal: true,\n // Propagate `.required` so the runtime enforces the unbound-required\n // check. Without this, `model.required(...)` accepts an unbound parent\n // and the model signal stays at its undefined initial value silently.\n required,\n };\n // The compiled `outputs` field is `{ classPropertyName: bindingName }`.\n // Angular inverts this at runtime via\n // `parseAndConvertOutputsForDefinition`, producing the lookup map\n // `{ bindingName: classPropertyName }` used by `listenToOutput`.\n // For a `model()` signal, the class property is `name` and the\n // binding event is `${aliasOrName}Change`, and the model signal\n // itself is the subscribable, so `instance[name]` is what\n // `listenToOutput` needs to resolve.\n outputs[name] = (alias ?? name) + 'Change';\n }\n\n // 3. SIGNAL QUERIES (viewChild, contentChild)\n else if (\n api === 'viewChild' ||\n api === 'viewChildren' ||\n api === 'contentChild' ||\n api === 'contentChildren'\n ) {\n const isViewQuery = api === 'viewChild' || api === 'viewChildren';\n const isChildrenQuery =\n api === 'viewChildren' || api === 'contentChildren';\n\n const firstArg = args[0];\n const sv = stringValue(firstArg);\n\n // Parse the optional second-arg options object for `read` and\n // (content queries only) `descendants`. Without this, queries like\n // `viewChild('ref', { read: ElementRef })` and\n // `contentChildren(Foo, { descendants: false })` silently lose\n // their options at runtime.\n let read: any = null;\n // Defaults match Angular's signal-query API and the decorator\n // path (`isView || isFirst` in detectFieldDecorators):\n // viewChild → true (view queries always traverse)\n // viewChildren → true\n // contentChild → true (single-result content queries\n // traverse by default)\n // contentChildren → false (multi-result content queries are\n // shallow unless explicitly opted in)\n let descendants = isViewQuery || !isChildrenQuery;\n const optArg = args[1];\n if (optArg?.type === 'ObjectExpression') {\n for (const prop of optArg.properties || []) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property')\n continue;\n const k = propKeyName(prop);\n if (k === 'read') {\n read = new o.WrappedNodeExpr(unwrapForwardRefOxc(prop.value));\n } else if (k === 'descendants') {\n const t = prop.value?.type;\n if (\n t === 'BooleanLiteral' ||\n (t === 'Literal' && typeof prop.value.value === 'boolean')\n ) {\n descendants = prop.value.value;\n }\n }\n }\n }\n\n const query = {\n propertyName: name,\n // Class predicates must be wrapped in an `R3QueryReference`\n // (`{ forwardRef, expression }`); Angular's `getQueryPredicate`\n // dispatches on `predicate.forwardRef` and reads\n // `predicate.expression`, so a bare `WrappedNodeExpr` is silently\n // dropped to `undefined` and emitted as `null`, leaving the query\n // with no target. `0 = ForwardRefHandling.None`.\n predicate:\n sv !== null\n ? [sv]\n : { forwardRef: 0, expression: new o.WrappedNodeExpr(firstArg) },\n first: !isChildrenQuery,\n descendants,\n read,\n static: false,\n emitFlags: 0,\n isSignal: true,\n };\n\n if (isViewQuery) viewQueries.push(query);\n else contentQueries.push(query);\n }\n\n // 4. STANDARD OUTPUTS (output() and outputFromObservable())\n else if (api === 'output' || api === 'outputFromObservable') {\n let alias = name;\n // outputFromObservable(observable, options) — options is args[1].\n // output(options) — options is args[0]. Mirrors upstream\n // output_function.ts:81.\n const optArg = api === 'outputFromObservable' ? args[1] : args[0];\n if (optArg?.type === 'ObjectExpression') {\n for (const prop of optArg.properties || []) {\n if (\n (prop.type === 'ObjectProperty' || prop.type === 'Property') &&\n propKeyName(prop) === 'alias'\n ) {\n const sv = stringValue(prop.value);\n if (sv !== null) alias = sv;\n }\n }\n }\n outputs[name] = alias;\n }\n }\n\n return { inputs, outputs, viewQueries, contentQueries };\n}\n\n/**\n * Detect decorator-based field metadata: @Input, @Output, @ViewChild,\n * @ContentChild, @ViewChildren, @ContentChildren, @HostBinding, @HostListener.\n */\nexport function detectFieldDecorators(classNode: any, sourceCode: string) {\n const inputs: any = {};\n const outputs: any = {};\n const viewQueries: any[] = [];\n const contentQueries: any[] = [];\n const hostProperties: Record<string, string> = {};\n const hostListeners: Record<string, string> = {};\n\n const members: any[] = classNode.body?.body || [];\n\n for (const member of members) {\n const decorators: any[] = member.decorators || [];\n if (decorators.length === 0) continue;\n\n const memberName: string = member.key?.name || '';\n\n for (const dec of decorators) {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') continue;\n const decName: string | undefined = expr.callee?.name;\n if (!decName) continue;\n const args: any[] = expr.arguments || [];\n\n switch (decName) {\n case 'Input': {\n let bindingName = memberName;\n let required = false;\n let transformFunction: any = null;\n\n if (args.length > 0) {\n const arg = args[0];\n const sv = stringValue(arg);\n if (sv !== null) {\n bindingName = sv;\n } else if (arg.type === 'ObjectExpression') {\n for (const prop of arg.properties || []) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property')\n continue;\n const k = propKeyName(prop);\n if (k === 'alias') {\n const asv = stringValue(prop.value);\n if (asv !== null) bindingName = asv;\n }\n if (k === 'required')\n required =\n sourceCode.slice(prop.value.start, prop.value.end) ===\n 'true';\n if (k === 'transform')\n transformFunction = new o.WrappedNodeExpr(prop.value);\n }\n }\n }\n\n inputs[memberName] = {\n classPropertyName: memberName,\n bindingPropertyName: bindingName,\n isSignal: false,\n required,\n transformFunction,\n };\n break;\n }\n\n case 'Output': {\n const sv = args.length > 0 ? stringValue(args[0]) : null;\n const alias = sv !== null ? sv : memberName;\n outputs[memberName] = alias;\n break;\n }\n\n case 'ViewChild':\n case 'ViewChildren':\n case 'ContentChild':\n case 'ContentChildren': {\n const isView = decName.startsWith('View');\n const isFirst = decName === 'ViewChild' || decName === 'ContentChild';\n\n // Default predicate when no argument is given is the member\n // name. Class predicates (the non-string case) must be wrapped\n // in an `R3QueryReference` (`{ forwardRef, expression }`) so\n // Angular's `getQueryPredicate` can dispatch on `forwardRef`\n // and read `.expression`. A bare `WrappedNodeExpr` is silently\n // dropped to undefined and emitted as `null`.\n let predicate: any = [memberName];\n if (args.length > 0) {\n const pred = args[0];\n const sv = stringValue(pred);\n if (sv !== null) {\n predicate = [sv];\n } else {\n predicate = {\n forwardRef: 0,\n expression: new o.WrappedNodeExpr(unwrapForwardRefOxc(pred)),\n };\n }\n }\n\n let read: any = null;\n let isStatic = false;\n let descendants = isView || isFirst;\n\n if (args.length > 1 && args[1]?.type === 'ObjectExpression') {\n for (const prop of args[1].properties || []) {\n if (prop.type !== 'ObjectProperty' && prop.type !== 'Property')\n continue;\n const k = propKeyName(prop);\n if (k === 'read') read = new o.WrappedNodeExpr(prop.value);\n if (k === 'static')\n isStatic =\n sourceCode.slice(prop.value.start, prop.value.end) === 'true';\n if (k === 'descendants')\n descendants =\n sourceCode.slice(prop.value.start, prop.value.end) === 'true';\n }\n }\n\n const query = {\n propertyName: memberName,\n predicate,\n first: isFirst,\n descendants,\n read,\n static: isStatic,\n emitFlags: 0,\n isSignal: false,\n };\n\n if (isView) viewQueries.push(query);\n else contentQueries.push(query);\n break;\n }\n\n case 'HostBinding': {\n const sv = args.length > 0 ? stringValue(args[0]) : null;\n const target = sv !== null ? sv : memberName;\n hostProperties[target] = memberName;\n break;\n }\n\n case 'HostListener': {\n const sv = args.length > 0 ? stringValue(args[0]) : null;\n if (sv !== null) {\n const event = sv;\n let handler = `${memberName}()`;\n if (args.length > 1 && args[1]?.type === 'ArrayExpression') {\n const handlerArgs = (args[1].elements || [])\n .map((e: any) => stringValue(e))\n .filter((v: string | null): v is string => v !== null)\n .join(', ');\n handler = `${memberName}(${handlerArgs})`;\n }\n hostListeners[event] = handler;\n }\n break;\n }\n }\n }\n }\n\n return {\n inputs,\n outputs,\n viewQueries,\n contentQueries,\n hostProperties,\n hostListeners,\n };\n}\n\n/**\n * Analyze constructor parameters for dependency injection.\n * Returns:\n * - R3DependencyMetadata[] for normal constructors\n * - null if class extends another without own constructor (use inherited factory)\n * - 'invalid' if any parameter has a type-only import token\n *\n * Accepts an OXC ClassDeclaration node and the original source string.\n */\n/**\n * Parse an `@Injectable({ deps: [...] })` dependency list into\n * R3DependencyMetadata. Each element is either a bare token expression or a\n * flag array combining DI modifiers with the token, e.g.\n * `[new Optional(), new SkipSelf(), Token]` or `[new Inject(TOKEN)]`.\n */\nfunction extractInjectableDeps(depsNode: any, sourceCode: string): any[] {\n const deps: any[] = [];\n for (const el of depsNode.elements || []) {\n if (!el) continue;\n let tokenNode: any = el;\n let optional = false,\n self = false,\n skipSelf = false,\n host = false;\n\n if (el.type === 'ArrayExpression') {\n // Flag array: zero or more `new <Modifier>()` instances plus the token.\n tokenNode = null;\n for (const item of el.elements || []) {\n if (!item) continue;\n if (item.type === 'NewExpression') {\n switch (item.callee?.name) {\n case 'Optional':\n optional = true;\n continue;\n case 'Self':\n self = true;\n continue;\n case 'SkipSelf':\n skipSelf = true;\n continue;\n case 'Host':\n host = true;\n continue;\n case 'Inject':\n tokenNode = item.arguments?.[0] ?? null;\n continue;\n }\n }\n // Bare token (identifier, member expression, `new InjectionToken()`…)\n tokenNode = item;\n }\n }\n\n // Unwrap `forwardRef(() => TOKEN)` to TOKEN so the emitted factory\n // references the token directly — matching `extractConstructorDeps` and\n // covering every form (`deps: [forwardRef(...)]`,\n // `[new Inject(forwardRef(...))]`, `[[new Optional(), forwardRef(...)]]`).\n const resolvedToken = tokenNode ? unwrapForwardRefOxc(tokenNode) : null;\n const tokenStr = resolvedToken\n ? sourceCode.slice(resolvedToken.start, resolvedToken.end)\n : null;\n deps.push({\n token: tokenStr\n ? new o.WrappedNodeExpr(tokenStr)\n : new o.LiteralExpr(null),\n attributeNameType: null,\n host,\n optional,\n self,\n skipSelf,\n });\n }\n return deps;\n}\n\nexport function extractConstructorDeps(\n classNode: any,\n sourceCode: string,\n typeOnlyImports: Set<string>,\n): any[] | 'invalid' | null {\n const heritage: any[] = classNode.superClass ? [classNode.superClass] : [];\n const hasSuper = heritage.length > 0;\n\n const members: any[] = classNode.body?.body || [];\n const ctors = members.filter(\n (m: any) => m.type === 'MethodDefinition' && m.kind === 'constructor',\n );\n // With overloaded constructors, only the implementation carries the real\n // parameter list and parameter decorators; the overload *signatures* have\n // `value.body === null`. Picking the first constructor would read an\n // overload signature and emit a factory missing the remaining deps.\n const ctor = ctors.find((m: any) => m.value?.body != null) ?? ctors[0];\n\n if (!ctor) {\n return hasSuper ? null : [];\n }\n\n const params: any[] = ctor.value?.params?.items || ctor.value?.params || [];\n const deps: any[] = [];\n let invalid = false;\n\n for (const param of params) {\n let token: string | null = null;\n // For `@Attribute(...)` the injected value is the attribute name itself,\n // not a type token. `attributeToken` holds that name expression (a string\n // literal for `@Attribute('name')`, or the raw expression for a computed\n // name like `@Attribute(dynamicAttrName())`); `attributeNameType` being\n // non-null flags the dep as an attribute injection so the factory emits\n // `ɵɵinjectAttribute(<name>)` instead of `ɵɵdirectiveInject(...)`.\n let attributeToken: any = null;\n let attributeNameType: any = null;\n let host = false,\n optional = false,\n self = false,\n skipSelf = false;\n\n // Handle TSParameterProperty (e.g., constructor(private foo: Bar))\n const actualParam =\n param.type === 'TSParameterProperty' ? param.parameter : param;\n const typeAnn =\n actualParam?.typeAnnotation?.typeAnnotation ??\n param?.typeAnnotation?.typeAnnotation;\n\n // Extract type annotation as token\n if (typeAnn) {\n if (typeAnn.type === 'TSTypeReference' && typeAnn.typeName) {\n token =\n typeAnn.typeName.name ??\n sourceCode.slice(typeAnn.typeName.start, typeAnn.typeName.end);\n } else if (typeAnn.type === 'TSUnionType') {\n // Filter out null/undefined/void arms — `T | null` and\n // `T | undefined` are common patterns that should resolve to T.\n // Anything else (multiple TypeReference arms, primitives, etc.)\n // is ambiguous and ngtsc rejects it. Mark as invalid so the\n // factory falls through to ɵɵinvalidFactory rather than\n // silently picking the first arm.\n const nonNullTypes = (typeAnn.types || []).filter((t: any) => {\n if (!t) return false;\n if (t.type === 'TSNullKeyword') return false;\n if (t.type === 'TSUndefinedKeyword') return false;\n if (t.type === 'TSVoidKeyword') return false;\n if (\n t.type === 'TSLiteralType' &&\n (t.literal?.type === 'NullLiteral' ||\n (t.literal?.type === 'Literal' && t.literal.value === null))\n ) {\n return false;\n }\n return true;\n });\n if (\n nonNullTypes.length === 1 &&\n nonNullTypes[0].type === 'TSTypeReference' &&\n nonNullTypes[0].typeName\n ) {\n const t = nonNullTypes[0];\n token =\n t.typeName.name ??\n sourceCode.slice(t.typeName.start, t.typeName.end);\n } else {\n // Ambiguous union — no suitable injection token.\n invalid = true;\n continue;\n }\n } else if (typeAnn.type === 'TSIntersectionType') {\n // Intersection types (`A & B`) have no single injection token.\n invalid = true;\n continue;\n }\n }\n\n // Process parameter decorators (may live on TSParameterProperty or inner param)\n const paramDecs: any[] = [\n ...(param.decorators || []),\n ...(param.type === 'TSParameterProperty' && actualParam?.decorators\n ? actualParam.decorators\n : []),\n ];\n for (const dec of paramDecs) {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') continue;\n const decName: string | undefined = expr.callee?.name;\n if (!decName) continue;\n const args: any[] = expr.arguments || [];\n\n switch (decName) {\n case 'Inject':\n if (args.length > 0) {\n const sv = stringValue(args[0]);\n if (sv !== null) {\n token = sv;\n } else {\n // Unwrap `@Inject(forwardRef(() => TOKEN))` so the\n // emitted token references TOKEN directly. Without this\n // the raw `forwardRef(() => TOKEN)` source slice would\n // appear in the factory output, producing broken code\n // that calls forwardRef at definition time.\n const unwrapped = unwrapForwardRefOxc(args[0]);\n token = sourceCode.slice(unwrapped.start, unwrapped.end);\n }\n }\n break;\n case 'Optional':\n optional = true;\n break;\n case 'Self':\n self = true;\n break;\n case 'SkipSelf':\n skipSelf = true;\n break;\n case 'Host':\n host = true;\n break;\n case 'Attribute':\n if (args.length > 0) {\n const sv = stringValue(args[0]);\n if (sv !== null) {\n attributeToken = new o.LiteralExpr(sv);\n attributeNameType = new o.LiteralExpr(sv);\n } else {\n // Computed attribute name, e.g. `@Attribute(dynamicAttrName())`.\n // ngtsc emits `ɵɵinjectAttribute(<expr>)`; pass the expression\n // through by value. `attributeNameType` only feeds the (unused)\n // `.d.ts` type, so a placeholder is sufficient to flag the dep.\n attributeToken = new o.WrappedNodeExpr(args[0]);\n attributeNameType = new o.LiteralExpr('unknown');\n }\n token = '';\n }\n break;\n }\n }\n\n if (!token && !attributeToken) {\n invalid = true;\n continue;\n }\n\n if (token && typeOnlyImports.has(token)) {\n invalid = true;\n continue;\n }\n\n deps.push({\n token:\n attributeToken ??\n (token ? new o.WrappedNodeExpr(token) : new o.LiteralExpr(null)),\n attributeNameType,\n host,\n optional,\n self,\n skipSelf,\n });\n }\n\n return invalid ? 'invalid' : deps;\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export declare const JIT_INLINE_STYLE_PREFIX = "virtual:angular:jit:style:inline;";
|
|
2
|
-
export declare function toJitInlineStyleId(encodedStyles: string): string;
|
|
3
|
-
export declare function getJitInlineStyles(
|
|
2
|
+
export declare function toJitInlineStyleId(encodedStyles: string, isTest: boolean): string;
|
|
3
|
+
export declare function getJitInlineStyles(idSuffix: string): string;
|
|
4
|
+
export declare function hashJitInlineStyles(encodedStyles: string): string;
|
|
@@ -2,15 +2,19 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
//#region packages/vite-plugin-angular/src/lib/utils/jit-inline-styles.ts
|
|
3
3
|
var JIT_INLINE_STYLE_PREFIX = "virtual:angular:jit:style:inline;";
|
|
4
4
|
var inlineStyles = /* @__PURE__ */ new Map();
|
|
5
|
-
function toJitInlineStyleId(encodedStyles) {
|
|
6
|
-
|
|
5
|
+
function toJitInlineStyleId(encodedStyles, isTest) {
|
|
6
|
+
if (isTest) return `${JIT_INLINE_STYLE_PREFIX}${encodedStyles}`;
|
|
7
|
+
const hash = hashJitInlineStyles(encodedStyles);
|
|
7
8
|
inlineStyles.set(hash, encodedStyles);
|
|
8
9
|
return `${JIT_INLINE_STYLE_PREFIX}${hash}`;
|
|
9
10
|
}
|
|
10
|
-
function getJitInlineStyles(
|
|
11
|
-
return inlineStyles.get(
|
|
11
|
+
function getJitInlineStyles(idSuffix) {
|
|
12
|
+
return inlineStyles.get(idSuffix) ?? idSuffix;
|
|
13
|
+
}
|
|
14
|
+
function hashJitInlineStyles(encodedStyles) {
|
|
15
|
+
return createHash("sha256").update(encodedStyles).digest("hex").slice(0, 16);
|
|
12
16
|
}
|
|
13
17
|
//#endregion
|
|
14
|
-
export { JIT_INLINE_STYLE_PREFIX, getJitInlineStyles, toJitInlineStyleId };
|
|
18
|
+
export { JIT_INLINE_STYLE_PREFIX, getJitInlineStyles, hashJitInlineStyles, toJitInlineStyleId };
|
|
15
19
|
|
|
16
20
|
//# sourceMappingURL=jit-inline-styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jit-inline-styles.js","names":[],"sources":["../../../../src/lib/utils/jit-inline-styles.ts"],"sourcesContent":["// Angular's JIT resource transformer emits inline component styles as\n// `angular:jit:style:inline;<base64 of the whole stylesheet>`. Keeping that\n// payload in the module id makes the emitted chunk name grow with the\n// stylesheet, so a large inline style blows past the 255-byte filename\n// limit and the build fails with ENAMETOOLONG. Hash the payload into the\n// id and keep the base64 in a lookup table instead. (#2459)\n\nimport { createHash } from 'node:crypto';\n\nexport const JIT_INLINE_STYLE_PREFIX = 'virtual:angular:jit:style:inline;';\n\nconst inlineStyles = new Map<string, string>();\n\nexport function toJitInlineStyleId(encodedStyles: string): string {\n
|
|
1
|
+
{"version":3,"file":"jit-inline-styles.js","names":[],"sources":["../../../../src/lib/utils/jit-inline-styles.ts"],"sourcesContent":["// Angular's JIT resource transformer emits inline component styles as\n// `angular:jit:style:inline;<base64 of the whole stylesheet>`. Keeping that\n// payload in the module id makes the emitted chunk name grow with the\n// stylesheet, so a large inline style blows past the 255-byte filename\n// limit and the build fails with ENAMETOOLONG. Hash the payload into the\n// id and keep the base64 in a lookup table instead. (#2459)\n\nimport { createHash } from 'node:crypto';\n\nexport const JIT_INLINE_STYLE_PREFIX = 'virtual:angular:jit:style:inline;';\n\nconst inlineStyles = new Map<string, string>();\n\nexport function toJitInlineStyleId(\n encodedStyles: string,\n isTest: boolean,\n): string {\n if (isTest) {\n return `${JIT_INLINE_STYLE_PREFIX}${encodedStyles}`;\n }\n\n const hash = hashJitInlineStyles(encodedStyles);\n inlineStyles.set(hash, encodedStyles);\n return `${JIT_INLINE_STYLE_PREFIX}${hash}`;\n}\n\nexport function getJitInlineStyles(idSuffix: string): string {\n return inlineStyles.get(idSuffix) ?? idSuffix;\n}\n\nexport function hashJitInlineStyles(encodedStyles: string): string {\n return createHash('sha256').update(encodedStyles).digest('hex').slice(0, 16);\n}\n"],"mappings":";;AASA,IAAa,0BAA0B;AAEvC,IAAM,+BAAe,IAAI,KAAqB;AAE9C,SAAgB,mBACd,eACA,QACQ;AACR,KAAI,OACF,QAAO,GAAG,0BAA0B;CAGtC,MAAM,OAAO,oBAAoB,cAAc;AAC/C,cAAa,IAAI,MAAM,cAAc;AACrC,QAAO,GAAG,0BAA0B;;AAGtC,SAAgB,mBAAmB,UAA0B;AAC3D,QAAO,aAAa,IAAI,SAAS,IAAI;;AAGvC,SAAgB,oBAAoB,eAA+B;AACjE,QAAO,WAAW,SAAS,CAAC,OAAO,cAAc,CAAC,OAAO,MAAM,CAAC,MAAM,GAAG,GAAG"}
|