@analogjs/vite-plugin-angular 3.0.0-alpha.56 → 3.0.0-alpha.58
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 +3 -3
- package/src/lib/compiler/jit-metadata.js +44 -22
- package/src/lib/compiler/jit-metadata.js.map +1 -1
- package/src/lib/compiler/jit-transform.js +14 -10
- package/src/lib/compiler/jit-transform.js.map +1 -1
- package/src/lib/compiler/metadata.js +18 -8
- package/src/lib/compiler/metadata.js.map +1 -1
- package/src/lib/fast-compile-plugin.js +2 -1
- package/src/lib/fast-compile-plugin.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@analogjs/vite-plugin-angular",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.58",
|
|
4
4
|
"description": "Vite Plugin for Angular",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"url": "https://github.com/sponsors/brandonroberts"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@angular-devkit/build-angular": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0",
|
|
28
|
-
"@angular/build": "^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0"
|
|
27
|
+
"@angular-devkit/build-angular": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
|
|
28
|
+
"@angular/build": "^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependenciesMeta": {
|
|
31
31
|
"@angular-devkit/build-angular": {
|
|
@@ -22,6 +22,28 @@ function getCallApi(call) {
|
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
+
* Read a string-literal `alias` value out of an OXC ObjectExpression.
|
|
26
|
+
* Returns null when the arg isn't an object literal, has no alias, or
|
|
27
|
+
* the alias value isn't a static string. Shorthand `{alias}` is skipped
|
|
28
|
+
* because the identifier wouldn't be in scope when the propDecorators
|
|
29
|
+
* static block is evaluated at class top level.
|
|
30
|
+
*/
|
|
31
|
+
function extractAlias(optArg) {
|
|
32
|
+
if (!optArg || optArg.type !== "ObjectExpression") return null;
|
|
33
|
+
for (const p of optArg.properties || []) {
|
|
34
|
+
if (p.type !== "ObjectProperty" && p.type !== "Property") continue;
|
|
35
|
+
if (p.shorthand) continue;
|
|
36
|
+
if ((p.key?.name || p.key?.value) !== "alias") continue;
|
|
37
|
+
const v = p.value;
|
|
38
|
+
if (v?.type === "StringLiteral") return v.value;
|
|
39
|
+
if (v?.type === "Literal" && typeof v.value === "string") return v.value;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
function escapeStringLiteral(s) {
|
|
44
|
+
return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
25
47
|
* Build ctorParameters for constructor DI in JIT format:
|
|
26
48
|
* [{ type: ServiceA }, { type: ServiceB, decorators: [{type: Optional}] }]
|
|
27
49
|
*
|
|
@@ -78,12 +100,14 @@ function buildPropDecorators(classNode, sourceCode) {
|
|
|
78
100
|
for (const member of members) {
|
|
79
101
|
const memberName = member.key?.name;
|
|
80
102
|
if (!memberName) continue;
|
|
103
|
+
const explicitDecoratorNames = /* @__PURE__ */ new Set();
|
|
81
104
|
const decorators = member.decorators || [];
|
|
82
105
|
for (const dec of decorators) {
|
|
83
106
|
const expr = dec.expression;
|
|
84
107
|
if (!expr || expr.type !== "CallExpression") continue;
|
|
85
108
|
const decName = expr.callee?.name;
|
|
86
109
|
if (!decName || !FIELD_DECORATORS.has(decName)) continue;
|
|
110
|
+
explicitDecoratorNames.add(decName);
|
|
87
111
|
if (!props[memberName]) props[memberName] = [];
|
|
88
112
|
const args = expr.arguments || [];
|
|
89
113
|
if (args.length > 0) props[memberName].push(`{type: ${decName}, args: [${args.map((a) => sourceCode.slice(a.start, a.end)).join(", ")}]}`);
|
|
@@ -94,45 +118,43 @@ function buildPropDecorators(classNode, sourceCode) {
|
|
|
94
118
|
if (!signalCall) continue;
|
|
95
119
|
const { api, required } = signalCall;
|
|
96
120
|
const args = member.value.arguments || [];
|
|
121
|
+
const hasInput = explicitDecoratorNames.has("Input");
|
|
122
|
+
const hasOutput = explicitDecoratorNames.has("Output");
|
|
123
|
+
const hasQuery = explicitDecoratorNames.has("ViewChild") || explicitDecoratorNames.has("ViewChildren") || explicitDecoratorNames.has("ContentChild") || explicitDecoratorNames.has("ContentChildren");
|
|
124
|
+
if (api === "input" && hasInput) continue;
|
|
125
|
+
if (api === "model" && (hasInput || hasOutput)) continue;
|
|
126
|
+
if ((api === "output" || api === "outputFromObservable") && hasOutput) continue;
|
|
127
|
+
if ((api === "viewChild" || api === "viewChildren" || api === "contentChild" || api === "contentChildren") && hasQuery) continue;
|
|
97
128
|
if (api === "input") {
|
|
98
129
|
if (!props[memberName]) props[memberName] = [];
|
|
99
130
|
const optArg = required ? args[0] : args[1];
|
|
100
131
|
const optParts = [];
|
|
101
132
|
if (optArg?.type === "ObjectExpression") for (const p of optArg.properties || []) {
|
|
102
133
|
if (p.type !== "ObjectProperty" && p.type !== "Property") continue;
|
|
134
|
+
if (p.shorthand) continue;
|
|
103
135
|
const pKey = p.key?.name || p.key?.value;
|
|
104
|
-
if (pKey === "isSignal" || pKey === "required") continue;
|
|
136
|
+
if (pKey === "isSignal" || pKey === "required" || pKey === "transform") continue;
|
|
105
137
|
optParts.push(sourceCode.slice(p.start, p.end));
|
|
106
138
|
}
|
|
107
139
|
optParts.push(`isSignal: true`, `required: ${required}`);
|
|
108
140
|
props[memberName].push(`{type: Input, args: [{${optParts.join(", ")}}]}`);
|
|
109
141
|
} else if (api === "model") {
|
|
110
142
|
if (!props[memberName]) props[memberName] = [];
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
props[changeName].push(`{type: Output, args: ['${changeName}']}`);
|
|
143
|
+
const bindingName = extractAlias(required ? args[0] : args[1]) ?? memberName;
|
|
144
|
+
props[memberName].push(`{type: Input, args: [{isSignal: true, alias: '${escapeStringLiteral(bindingName)}', required: ${required}}]}`);
|
|
145
|
+
props[memberName].push(`{type: Output, args: ['${escapeStringLiteral(bindingName + "Change")}']}`);
|
|
115
146
|
} else if (api === "output" || api === "outputFromObservable") {
|
|
116
147
|
if (!props[memberName]) props[memberName] = [];
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (optArg?.type === "ObjectExpression") {
|
|
120
|
-
for (const p of optArg.properties || []) if ((p.type === "ObjectProperty" || p.type === "Property") && (p.key?.name || p.key?.value) === "alias") {
|
|
121
|
-
if (p.value?.type === "StringLiteral" || p.value?.type === "Literal" && typeof p.value.value === "string") alias = p.value.value;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
if (alias) props[memberName].push(`{type: Output, args: ['${alias}']}`);
|
|
148
|
+
const alias = extractAlias(api === "outputFromObservable" ? args[1] : args[0]);
|
|
149
|
+
if (alias !== null) props[memberName].push(`{type: Output, args: ['${escapeStringLiteral(alias)}']}`);
|
|
125
150
|
else props[memberName].push(`{type: Output}`);
|
|
126
|
-
} else if (api === "viewChild" || api === "viewChildren") {
|
|
127
|
-
if (!props[memberName]) props[memberName] = [];
|
|
128
|
-
const queryType = api === "viewChildren" ? "ViewChildren" : "ViewChild";
|
|
129
|
-
if (args.length > 0) props[memberName].push(`{type: ${queryType}, args: [${sourceCode.slice(args[0].start, args[0].end)}]}`);
|
|
130
|
-
else props[memberName].push(`{type: ${queryType}}`);
|
|
131
|
-
} else if (api === "contentChild" || api === "contentChildren") {
|
|
151
|
+
} else if (api === "viewChild" || api === "viewChildren" || api === "contentChild" || api === "contentChildren") {
|
|
132
152
|
if (!props[memberName]) props[memberName] = [];
|
|
133
|
-
const queryType = api === "contentChildren" ? "ContentChildren" : "ContentChild";
|
|
134
|
-
if (args.length > 0)
|
|
135
|
-
|
|
153
|
+
const queryType = api === "viewChildren" ? "ViewChildren" : api === "viewChild" ? "ViewChild" : api === "contentChildren" ? "ContentChildren" : "ContentChild";
|
|
154
|
+
if (args.length > 0) {
|
|
155
|
+
const opts = args.length > 1 ? `{...${sourceCode.slice(args[1].start, args[1].end)}, isSignal: true}` : `{isSignal: true}`;
|
|
156
|
+
props[memberName].push(`{type: ${queryType}, args: [${sourceCode.slice(args[0].start, args[0].end)}, ${opts}]}`);
|
|
157
|
+
} else props[memberName].push(`{type: ${queryType}, args: [undefined, {isSignal: true}]}`);
|
|
136
158
|
}
|
|
137
159
|
}
|
|
138
160
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jit-metadata.js","names":[],"sources":["../../../../src/lib/compiler/jit-metadata.ts"],"sourcesContent":["/**\n * JIT metadata helpers — OXC AST edition.\n *\n * Builds static metadata arrays that Angular's ReflectionCapabilities reads\n * at runtime for JIT compilation (ctorParameters, propDecorators).\n *\n * Uses source-position slicing instead of AST getText() for speed.\n */\nimport { FIELD_DECORATORS } 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 * Build ctorParameters for constructor DI in JIT format:\n * [{ type: ServiceA }, { type: ServiceB, decorators: [{type: Optional}] }]\n *\n * Accepts an OXC ClassDeclaration node and the original source string.\n */\nexport function buildCtorParameters(\n classNode: any,\n sourceCode: string,\n typeOnlyImports: Set<string>,\n): string | null {\n const members: any[] = classNode.body?.body || [];\n const ctor = members.find(\n (m: any) => m.type === 'MethodDefinition' && m.kind === 'constructor',\n );\n if (!ctor) return null;\n\n const params: any[] = ctor.value?.params?.items || ctor.value?.params || [];\n if (params.length === 0) return null;\n\n const result: string[] = [];\n for (const param of params) {\n const parts: string[] = [];\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 name from annotation\n let typeName: string | null = null;\n if (typeAnn) {\n if (typeAnn.type === 'TSTypeReference' && typeAnn.typeName) {\n typeName =\n typeAnn.typeName.name ??\n sourceCode.slice(typeAnn.typeName.start, typeAnn.typeName.end);\n } else if (typeAnn.type === 'TSUnionType') {\n for (const t of typeAnn.types || []) {\n if (t.type === 'TSTypeReference' && t.typeName) {\n typeName =\n t.typeName.name ??\n sourceCode.slice(t.typeName.start, t.typeName.end);\n break;\n }\n }\n }\n }\n\n if (typeName && !typeOnlyImports.has(typeName)) {\n parts.push(`type: ${typeName}`);\n } else {\n parts.push(`type: undefined`);\n }\n\n // Extract parameter decorators (may live on TSParameterProperty or the param itself)\n const paramDecs: any[] = param.decorators || actualParam?.decorators || [];\n if (paramDecs.length > 0) {\n const decEntries = paramDecs\n .map((dec: any) => {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') return '';\n const name = expr.callee?.name;\n if (!name) return '';\n const args: any[] = expr.arguments || [];\n if (args.length > 0) {\n return `{type: ${name}, args: [${args.map((a: any) => sourceCode.slice(a.start, a.end)).join(', ')}]}`;\n }\n return `{type: ${name}}`;\n })\n .filter(Boolean);\n if (decEntries.length > 0) {\n parts.push(`decorators: [${decEntries.join(', ')}]`);\n }\n }\n\n result.push(`{${parts.join(', ')}}`);\n }\n\n return result.join(', ');\n}\n\n/**\n * Build propDecorators for field decorators + signal API downleveling.\n * Returns a JS object literal string or null if no props.\n *\n * Accepts an OXC ClassDeclaration node and the original source string.\n */\nexport function buildPropDecorators(\n classNode: any,\n sourceCode: string,\n): string | null {\n const props: Record<string, string[]> = {};\n const members: any[] = classNode.body?.body || [];\n\n for (const member of members) {\n const memberName: string | undefined = member.key?.name;\n if (!memberName) continue;\n\n // Check for field decorators (@Input, @Output, @ViewChild, etc.)\n const decorators: any[] = member.decorators || [];\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 || !FIELD_DECORATORS.has(decName)) continue;\n\n if (!props[memberName]) props[memberName] = [];\n const args: any[] = expr.arguments || [];\n if (args.length > 0) {\n props[memberName].push(\n `{type: ${decName}, args: [${args.map((a: any) => sourceCode.slice(a.start, a.end)).join(', ')}]}`,\n );\n } else {\n props[memberName].push(`{type: ${decName}}`);\n }\n }\n\n // Signal API downleveling\n if (\n member.type === 'PropertyDefinition' &&\n member.value?.type === 'CallExpression'\n ) {\n const signalCall = getCallApi(member.value);\n if (!signalCall) continue;\n\n const { api, required } = signalCall;\n const args: any[] = member.value.arguments || [];\n\n if (api === 'input') {\n if (!props[memberName]) props[memberName] = [];\n // Preserve all original options from the input() call and overlay isSignal/required\n const optArg = required ? args[0] : args[1];\n const optParts: string[] = [];\n if (optArg?.type === 'ObjectExpression') {\n for (const p of optArg.properties || []) {\n if (p.type !== 'ObjectProperty' && p.type !== 'Property') continue;\n const pKey = p.key?.name || p.key?.value;\n // Skip isSignal/required — we override them below\n if (pKey === 'isSignal' || pKey === 'required') continue;\n optParts.push(sourceCode.slice(p.start, p.end));\n }\n }\n optParts.push(`isSignal: true`, `required: ${required}`);\n props[memberName].push(\n `{type: Input, args: [{${optParts.join(', ')}}]}`,\n );\n } else if (api === 'model') {\n if (!props[memberName]) props[memberName] = [];\n props[memberName].push(`{type: Input, args: [{isSignal: true}]}`);\n // Model also generates a Change output\n const changeName = memberName + 'Change';\n if (!props[changeName]) props[changeName] = [];\n props[changeName].push(`{type: Output, args: ['${changeName}']}`);\n } else if (api === 'output' || api === 'outputFromObservable') {\n if (!props[memberName]) props[memberName] = [];\n // Extract alias\n let alias: string | null = null;\n const optArg = args[0];\n if (optArg?.type === 'ObjectExpression') {\n for (const p of optArg.properties || []) {\n if (\n (p.type === 'ObjectProperty' || p.type === 'Property') &&\n (p.key?.name || p.key?.value) === 'alias'\n ) {\n if (\n p.value?.type === 'StringLiteral' ||\n (p.value?.type === 'Literal' &&\n typeof p.value.value === 'string')\n ) {\n alias = p.value.value;\n }\n }\n }\n }\n if (alias) {\n props[memberName].push(`{type: Output, args: ['${alias}']}`);\n } else {\n props[memberName].push(`{type: Output}`);\n }\n } else if (api === 'viewChild' || api === 'viewChildren') {\n if (!props[memberName]) props[memberName] = [];\n const queryType = api === 'viewChildren' ? 'ViewChildren' : 'ViewChild';\n if (args.length > 0) {\n props[memberName].push(\n `{type: ${queryType}, args: [${sourceCode.slice(args[0].start, args[0].end)}]}`,\n );\n } else {\n props[memberName].push(`{type: ${queryType}}`);\n }\n } else if (api === 'contentChild' || api === 'contentChildren') {\n if (!props[memberName]) props[memberName] = [];\n const queryType =\n api === 'contentChildren' ? 'ContentChildren' : 'ContentChild';\n if (args.length > 0) {\n props[memberName].push(\n `{type: ${queryType}, args: [${sourceCode.slice(args[0].start, args[0].end)}]}`,\n );\n } else {\n props[memberName].push(`{type: ${queryType}}`);\n }\n }\n }\n }\n\n const entries = Object.entries(props);\n if (entries.length === 0) return null;\n\n const propsStr = entries\n .map(([key, decs]) => `${key}: [${decs.join(', ')}]`)\n .join(', ');\n return `{${propsStr}}`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"jit-metadata.js","names":[],"sources":["../../../../src/lib/compiler/jit-metadata.ts"],"sourcesContent":["/**\n * JIT metadata helpers — OXC AST edition.\n *\n * Builds static metadata arrays that Angular's ReflectionCapabilities reads\n * at runtime for JIT compilation (ctorParameters, propDecorators).\n *\n * Uses source-position slicing instead of AST getText() for speed.\n */\nimport { FIELD_DECORATORS } 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 * Read a string-literal `alias` value out of an OXC ObjectExpression.\n * Returns null when the arg isn't an object literal, has no alias, or\n * the alias value isn't a static string. Shorthand `{alias}` is skipped\n * because the identifier wouldn't be in scope when the propDecorators\n * static block is evaluated at class top level.\n */\nfunction extractAlias(optArg: any): string | null {\n if (!optArg || optArg.type !== 'ObjectExpression') return null;\n for (const p of optArg.properties || []) {\n if (p.type !== 'ObjectProperty' && p.type !== 'Property') continue;\n if (p.shorthand) continue;\n const pKey = p.key?.name || p.key?.value;\n if (pKey !== 'alias') continue;\n const v = p.value;\n if (v?.type === 'StringLiteral') return v.value;\n if (v?.type === 'Literal' && typeof v.value === 'string') return v.value;\n }\n return null;\n}\n\nfunction escapeStringLiteral(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n/**\n * Build ctorParameters for constructor DI in JIT format:\n * [{ type: ServiceA }, { type: ServiceB, decorators: [{type: Optional}] }]\n *\n * Accepts an OXC ClassDeclaration node and the original source string.\n */\nexport function buildCtorParameters(\n classNode: any,\n sourceCode: string,\n typeOnlyImports: Set<string>,\n): string | null {\n const members: any[] = classNode.body?.body || [];\n const ctor = members.find(\n (m: any) => m.type === 'MethodDefinition' && m.kind === 'constructor',\n );\n if (!ctor) return null;\n\n const params: any[] = ctor.value?.params?.items || ctor.value?.params || [];\n if (params.length === 0) return null;\n\n const result: string[] = [];\n for (const param of params) {\n const parts: string[] = [];\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 name from annotation\n let typeName: string | null = null;\n if (typeAnn) {\n if (typeAnn.type === 'TSTypeReference' && typeAnn.typeName) {\n typeName =\n typeAnn.typeName.name ??\n sourceCode.slice(typeAnn.typeName.start, typeAnn.typeName.end);\n } else if (typeAnn.type === 'TSUnionType') {\n for (const t of typeAnn.types || []) {\n if (t.type === 'TSTypeReference' && t.typeName) {\n typeName =\n t.typeName.name ??\n sourceCode.slice(t.typeName.start, t.typeName.end);\n break;\n }\n }\n }\n }\n\n if (typeName && !typeOnlyImports.has(typeName)) {\n parts.push(`type: ${typeName}`);\n } else {\n parts.push(`type: undefined`);\n }\n\n // Extract parameter decorators (may live on TSParameterProperty or the param itself)\n const paramDecs: any[] = param.decorators || actualParam?.decorators || [];\n if (paramDecs.length > 0) {\n const decEntries = paramDecs\n .map((dec: any) => {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') return '';\n const name = expr.callee?.name;\n if (!name) return '';\n const args: any[] = expr.arguments || [];\n if (args.length > 0) {\n return `{type: ${name}, args: [${args.map((a: any) => sourceCode.slice(a.start, a.end)).join(', ')}]}`;\n }\n return `{type: ${name}}`;\n })\n .filter(Boolean);\n if (decEntries.length > 0) {\n parts.push(`decorators: [${decEntries.join(', ')}]`);\n }\n }\n\n result.push(`{${parts.join(', ')}}`);\n }\n\n return result.join(', ');\n}\n\n/**\n * Build propDecorators for field decorators + signal API downleveling.\n * Returns a JS object literal string or null if no props.\n *\n * Accepts an OXC ClassDeclaration node and the original source string.\n */\nexport function buildPropDecorators(\n classNode: any,\n sourceCode: string,\n): string | null {\n const props: Record<string, string[]> = {};\n const members: any[] = classNode.body?.body || [];\n\n for (const member of members) {\n const memberName: string | undefined = member.key?.name;\n if (!memberName) continue;\n\n // Check for field decorators (@Input, @Output, @ViewChild, etc.)\n const explicitDecoratorNames = new Set<string>();\n const decorators: any[] = member.decorators || [];\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 || !FIELD_DECORATORS.has(decName)) continue;\n\n explicitDecoratorNames.add(decName);\n if (!props[memberName]) props[memberName] = [];\n const args: any[] = expr.arguments || [];\n if (args.length > 0) {\n props[memberName].push(\n `{type: ${decName}, args: [${args.map((a: any) => sourceCode.slice(a.start, a.end)).join(', ')}]}`,\n );\n } else {\n props[memberName].push(`{type: ${decName}}`);\n }\n }\n\n // Signal API downleveling. Skip when a matching explicit decorator\n // is already on the field — Angular's transform bails in that case\n // (input_function.ts, model_function.ts, output_function.ts,\n // query_functions.ts) to avoid duplicate metadata entries.\n if (\n member.type === 'PropertyDefinition' &&\n member.value?.type === 'CallExpression'\n ) {\n const signalCall = getCallApi(member.value);\n if (!signalCall) continue;\n\n const { api, required } = signalCall;\n const args: any[] = member.value.arguments || [];\n\n const hasInput = explicitDecoratorNames.has('Input');\n const hasOutput = explicitDecoratorNames.has('Output');\n const hasQuery =\n explicitDecoratorNames.has('ViewChild') ||\n explicitDecoratorNames.has('ViewChildren') ||\n explicitDecoratorNames.has('ContentChild') ||\n explicitDecoratorNames.has('ContentChildren');\n\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 if (api === 'input') {\n if (!props[memberName]) props[memberName] = [];\n // Preserve original options from the input() call and overlay\n // isSignal/required. `transform` is dropped: the input signal\n // already applies it internally, so forwarding it to the\n // decorator would make Angular's runtime JIT wrap it a second\n // time via the directive metadata's transformFunction slot.\n // Shorthand props ({alias}) are skipped — the identifier\n // wouldn't be in scope when the propDecorators block runs at\n // class top level.\n const optArg = required ? args[0] : args[1];\n const optParts: string[] = [];\n if (optArg?.type === 'ObjectExpression') {\n for (const p of optArg.properties || []) {\n if (p.type !== 'ObjectProperty' && p.type !== 'Property') continue;\n if (p.shorthand) continue;\n const pKey = p.key?.name || p.key?.value;\n if (\n pKey === 'isSignal' ||\n pKey === 'required' ||\n pKey === 'transform'\n ) {\n continue;\n }\n optParts.push(sourceCode.slice(p.start, p.end));\n }\n }\n optParts.push(`isSignal: true`, `required: ${required}`);\n props[memberName].push(\n `{type: Input, args: [{${optParts.join(', ')}}]}`,\n );\n } else if (api === 'model') {\n // Both Input and Output must live on the SAME propDecorators key\n // (the class field name). Angular's JIT facade indexes outputs by\n // classPropertyName and reads `instance[classPropertyName]` for\n // the EventEmitter — for a model that's the signal itself, which\n // exposes the emitter via [SIGNAL]. Splitting Output onto a\n // synthetic `<name>Change` key would point at a field that does\n // not exist on the class, breaking two-way bindings.\n if (!props[memberName]) props[memberName] = [];\n const optArg = required ? args[0] : args[1];\n const alias = extractAlias(optArg);\n const bindingName = alias ?? memberName;\n props[memberName].push(\n `{type: Input, args: [{isSignal: true, alias: '${escapeStringLiteral(bindingName)}', required: ${required}}]}`,\n );\n props[memberName].push(\n `{type: Output, args: ['${escapeStringLiteral(bindingName + 'Change')}']}`,\n );\n } else if (api === 'output' || api === 'outputFromObservable') {\n if (!props[memberName]) props[memberName] = [];\n // outputFromObservable(observable, options) — options is args[1].\n // output(options) — options is args[0].\n const optArg = api === 'outputFromObservable' ? args[1] : args[0];\n const alias = extractAlias(optArg);\n if (alias !== null) {\n props[memberName].push(\n `{type: Output, args: ['${escapeStringLiteral(alias)}']}`,\n );\n } else {\n props[memberName].push(`{type: Output}`);\n }\n } else if (\n api === 'viewChild' ||\n api === 'viewChildren' ||\n api === 'contentChild' ||\n api === 'contentChildren'\n ) {\n if (!props[memberName]) props[memberName] = [];\n const queryType =\n api === 'viewChildren'\n ? 'ViewChildren'\n : api === 'viewChild'\n ? 'ViewChild'\n : api === 'contentChildren'\n ? 'ContentChildren'\n : 'ContentChild';\n // Signal queries need `isSignal: true` so the runtime JIT compiler\n // wires them through the signal query infrastructure rather than\n // treating them as plain @ViewChild/@ContentChild assignments.\n // Mirrors Angular's own JIT transform in\n // compiler-cli/.../initializer_api_transforms/query_functions.ts.\n if (args.length > 0) {\n const opts =\n args.length > 1\n ? `{...${sourceCode.slice(args[1].start, args[1].end)}, isSignal: true}`\n : `{isSignal: true}`;\n props[memberName].push(\n `{type: ${queryType}, args: [${sourceCode.slice(args[0].start, args[0].end)}, ${opts}]}`,\n );\n } else {\n props[memberName].push(\n `{type: ${queryType}, args: [undefined, {isSignal: true}]}`,\n );\n }\n }\n }\n }\n\n const entries = Object.entries(props);\n if (entries.length === 0) return null;\n\n const propsStr = entries\n .map(([key, decs]) => `${key}: [${decs.join(', ')}]`)\n .join(', ');\n return `{${propsStr}}`;\n}\n"],"mappings":"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"}
|
|
@@ -47,7 +47,7 @@ function jitTransform(sourceCode, fileName) {
|
|
|
47
47
|
const typeOnlyImports = detectTypeOnlyImportNames(sourceCode);
|
|
48
48
|
let hasAngularClass = false;
|
|
49
49
|
const allClasses = findAllClasses(program.body);
|
|
50
|
-
const
|
|
50
|
+
const allEmittedStatements = [];
|
|
51
51
|
let importCounter = 0;
|
|
52
52
|
const resourceImports = [];
|
|
53
53
|
let needsJitImport = false;
|
|
@@ -63,6 +63,7 @@ function jitTransform(sourceCode, fileName) {
|
|
|
63
63
|
const className = node.id?.name;
|
|
64
64
|
if (!className) continue;
|
|
65
65
|
hasAngularClass = true;
|
|
66
|
+
const classStatements = [];
|
|
66
67
|
for (const dec of angularDecs) {
|
|
67
68
|
const start = dec.start;
|
|
68
69
|
let trimEnd = dec.end;
|
|
@@ -123,28 +124,28 @@ function jitTransform(sourceCode, fileName) {
|
|
|
123
124
|
});
|
|
124
125
|
return `{ type: ${decName} }`;
|
|
125
126
|
});
|
|
126
|
-
|
|
127
|
+
classStatements.push(`${className}.decorators = [${decoratorEntries.join(", ")}];`);
|
|
127
128
|
for (const dm of decoratorMeta) {
|
|
128
129
|
needsJitImport = true;
|
|
129
130
|
switch (dm.name) {
|
|
130
131
|
case "Component":
|
|
131
|
-
|
|
132
|
+
classStatements.push(`_jitCompileComponent(${className}, ${dm.argsText});`);
|
|
132
133
|
break;
|
|
133
134
|
case "Directive":
|
|
134
|
-
|
|
135
|
+
classStatements.push(`_jitCompileDirective(${className}, ${dm.argsText});`);
|
|
135
136
|
break;
|
|
136
137
|
case "Pipe":
|
|
137
|
-
|
|
138
|
+
classStatements.push(`_jitCompilePipe(${className}, ${dm.argsText});`);
|
|
138
139
|
break;
|
|
139
140
|
case "NgModule":
|
|
140
|
-
|
|
141
|
+
classStatements.push(`_jitCompileNgModule(${className}, ${dm.argsText});`);
|
|
141
142
|
break;
|
|
142
143
|
}
|
|
143
144
|
}
|
|
144
145
|
const ctorParams = buildCtorParameters(node, sourceCode, typeOnlyImports);
|
|
145
|
-
if (ctorParams)
|
|
146
|
+
if (ctorParams) classStatements.push(`${className}.ctorParameters = () => [${ctorParams}];`);
|
|
146
147
|
const propDecorators = buildPropDecorators(node, sourceCode);
|
|
147
|
-
if (propDecorators)
|
|
148
|
+
if (propDecorators) classStatements.push(`${className}.propDecorators = ${propDecorators};`);
|
|
148
149
|
const members = node.body?.body || [];
|
|
149
150
|
for (const member of members) {
|
|
150
151
|
const memberDecs = member.decorators || [];
|
|
@@ -167,6 +168,10 @@ function jitTransform(sourceCode, fileName) {
|
|
|
167
168
|
}
|
|
168
169
|
}
|
|
169
170
|
}
|
|
171
|
+
if (classStatements.length > 0) {
|
|
172
|
+
allEmittedStatements.push(...classStatements);
|
|
173
|
+
ms.appendLeft(node.end, "\n" + classStatements.join("\n") + "\n");
|
|
174
|
+
}
|
|
170
175
|
}
|
|
171
176
|
if (!hasAngularClass) return {
|
|
172
177
|
code: sourceCode,
|
|
@@ -177,12 +182,11 @@ function jitTransform(sourceCode, fileName) {
|
|
|
177
182
|
for (const stmt of program.body) if (stmt.type === "ImportDeclaration" && stmt.source?.value === "@angular/core") {
|
|
178
183
|
for (const spec of stmt.specifiers || []) if (spec.type === "ImportSpecifier") existingImports.add(spec.local?.name || spec.imported?.name);
|
|
179
184
|
}
|
|
180
|
-
const allPostCode =
|
|
185
|
+
const allPostCode = allEmittedStatements.join("\n");
|
|
181
186
|
const missingDecorators = [];
|
|
182
187
|
for (const dec of FIELD_DECORATORS) if (allPostCode.includes(`type: ${dec}`) && !existingImports.has(dec)) missingDecorators.push(dec);
|
|
183
188
|
if (missingDecorators.length > 0) ms.prepend(`import { ${missingDecorators.join(", ")} } from '@angular/core';\n`);
|
|
184
189
|
if (needsJitImport) ms.prepend(`import { ɵcompileComponent as _jitCompileComponent, ɵcompileDirective as _jitCompileDirective, ɵcompilePipe as _jitCompilePipe, ɵcompileNgModule as _jitCompileNgModule } from '@angular/core';\n`);
|
|
185
|
-
if (postClassStatements.length > 0) ms.append("\n" + postClassStatements.join("\n") + "\n");
|
|
186
190
|
const map = ms.generateMap({
|
|
187
191
|
source: fileName,
|
|
188
192
|
file: fileName + ".js",
|
|
@@ -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);\n let hasAngularClass = false;\n\n const allClasses = findAllClasses(program.body);\n\n const postClassStatements: 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 // 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 postClassStatements.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 postClassStatements.push(\n `_jitCompileComponent(${className}, ${dm.argsText});`,\n );\n break;\n case 'Directive':\n postClassStatements.push(\n `_jitCompileDirective(${className}, ${dm.argsText});`,\n );\n break;\n case 'Pipe':\n postClassStatements.push(\n `_jitCompilePipe(${className}, ${dm.argsText});`,\n );\n break;\n case 'NgModule':\n postClassStatements.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 postClassStatements.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 postClassStatements.push(\n `${className}.propDecorators = ${propDecorators};`,\n );\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\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 = postClassStatements.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 // Append all post-class statements at the end\n if (postClassStatements.length > 0) {\n ms.append('\\n' + postClassStatements.join('\\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 { 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);\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,4 +1,4 @@
|
|
|
1
|
-
import { SIGNAL_APIS } from "./constants.js";
|
|
1
|
+
import { FIELD_DECORATORS, SIGNAL_APIS } from "./constants.js";
|
|
2
2
|
import { unwrapForwardRefOxc } from "./utils.js";
|
|
3
3
|
import * as o from "@angular/compiler";
|
|
4
4
|
//#region packages/vite-plugin-angular/src/lib/compiler/metadata.ts
|
|
@@ -316,16 +316,25 @@ function detectSignals(classNode, sourceCode) {
|
|
|
316
316
|
if (!signalCall) continue;
|
|
317
317
|
const { api, required } = signalCall;
|
|
318
318
|
if (!SIGNAL_APIS.has(api)) continue;
|
|
319
|
+
const explicit = /* @__PURE__ */ new Set();
|
|
320
|
+
for (const dec of m.decorators || []) {
|
|
321
|
+
const decName = dec.expression?.callee?.name;
|
|
322
|
+
if (decName && FIELD_DECORATORS.has(decName)) explicit.add(decName);
|
|
323
|
+
}
|
|
324
|
+
const hasInput = explicit.has("Input");
|
|
325
|
+
const hasOutput = explicit.has("Output");
|
|
326
|
+
const hasQuery = explicit.has("ViewChild") || explicit.has("ViewChildren") || explicit.has("ContentChild") || explicit.has("ContentChildren");
|
|
327
|
+
if (api === "input" && hasInput) continue;
|
|
328
|
+
if (api === "model" && (hasInput || hasOutput)) continue;
|
|
329
|
+
if ((api === "output" || api === "outputFromObservable") && hasOutput) continue;
|
|
330
|
+
if ((api === "viewChild" || api === "viewChildren" || api === "contentChild" || api === "contentChildren") && hasQuery) continue;
|
|
319
331
|
const args = m.value.arguments || [];
|
|
320
332
|
if (api === "input") {
|
|
321
|
-
let transform = null;
|
|
322
333
|
let alias = null;
|
|
323
334
|
const optionsArg = required ? args[0] : args[1];
|
|
324
335
|
if (optionsArg?.type === "ObjectExpression") for (const prop of optionsArg.properties || []) {
|
|
325
336
|
if (prop.type !== "ObjectProperty" && prop.type !== "Property") continue;
|
|
326
|
-
|
|
327
|
-
if (k === "transform") transform = new o.WrappedNodeExpr(prop.value);
|
|
328
|
-
else if (k === "alias") {
|
|
337
|
+
if (propKeyName(prop) === "alias") {
|
|
329
338
|
const sv = stringValue(prop.value);
|
|
330
339
|
if (sv !== null) alias = sv;
|
|
331
340
|
}
|
|
@@ -335,7 +344,7 @@ function detectSignals(classNode, sourceCode) {
|
|
|
335
344
|
bindingPropertyName: alias ?? name,
|
|
336
345
|
isSignal: true,
|
|
337
346
|
required,
|
|
338
|
-
transform
|
|
347
|
+
transform: null
|
|
339
348
|
};
|
|
340
349
|
} else if (api === "model") {
|
|
341
350
|
let alias = null;
|
|
@@ -350,7 +359,8 @@ function detectSignals(classNode, sourceCode) {
|
|
|
350
359
|
inputs[name] = {
|
|
351
360
|
classPropertyName: name,
|
|
352
361
|
bindingPropertyName: alias ?? name,
|
|
353
|
-
isSignal: true
|
|
362
|
+
isSignal: true,
|
|
363
|
+
required
|
|
354
364
|
};
|
|
355
365
|
outputs[name] = (alias ?? name) + "Change";
|
|
356
366
|
} else if (api === "viewChild" || api === "viewChildren" || api === "contentChild" || api === "contentChildren") {
|
|
@@ -387,7 +397,7 @@ function detectSignals(classNode, sourceCode) {
|
|
|
387
397
|
else contentQueries.push(query);
|
|
388
398
|
} else if (api === "output" || api === "outputFromObservable") {
|
|
389
399
|
let alias = name;
|
|
390
|
-
const optArg = args[0];
|
|
400
|
+
const optArg = api === "outputFromObservable" ? args[1] : args[0];
|
|
391
401
|
if (optArg?.type === "ObjectExpression") {
|
|
392
402
|
for (const prop of optArg.properties || []) if ((prop.type === "ObjectProperty" || prop.type === "Property") && propKeyName(prop) === "alias") {
|
|
393
403
|
const sv = stringValue(prop.value);
|
|
@@ -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 { 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 'providers':\n case 'viewProviders':\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 // @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 // `@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 const args: any[] = m.value.arguments || [];\n\n // 1. SIGNAL INPUTS (Standard & Required)\n if (api === 'input') {\n let transform: any = null;\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 const k = propKeyName(prop);\n if (k === 'transform') {\n transform = new o.WrappedNodeExpr(prop.value);\n } else if (k === '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 transform,\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 };\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 const optArg = 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 */\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 ctor = members.find(\n (m: any) => m.type === 'MethodDefinition' && m.kind === 'constructor',\n );\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 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 attributeNameType = new o.LiteralExpr(sv);\n token = '';\n }\n }\n break;\n }\n }\n\n if (!token && !attributeNameType) {\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: 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 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 'providers':\n case 'viewProviders':\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 // @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 // `@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 */\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 ctor = members.find(\n (m: any) => m.type === 'MethodDefinition' && m.kind === 'constructor',\n );\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 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 attributeNameType = new o.LiteralExpr(sv);\n token = '';\n }\n }\n break;\n }\n }\n\n if (!token && !attributeNameType) {\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: 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fast-compile-plugin.js","names":[],"sources":["../../../src/lib/fast-compile-plugin.ts"],"sourcesContent":["import { promises as fsPromises } from 'node:fs';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport * as vite from 'vite';\n\nimport * as compilerCli from '@angular/compiler-cli';\nimport { normalizePath, Plugin, preprocessCSS, ResolvedConfig } from 'vite';\n\nimport {\n compile,\n scanFile,\n scanPackageDts,\n collectImportedPackages,\n collectRelativeReExports,\n jitTransform,\n inlineResourceUrls,\n extractInlineStyles,\n generateHmrCode,\n debugCompile,\n debugRegistry,\n type ComponentRegistry,\n} from './compiler/index.js';\n\nimport {\n TS_EXT_REGEX,\n getTsConfigPath,\n createDepOptimizerConfig,\n type TsConfigResolutionContext,\n} from './utils/plugin-config.js';\nimport { VIRTUAL_RAW_PREFIX, toVirtualRawId } from './utils/virtual-ids.js';\nimport {\n loadVirtualRawModule,\n rewriteHtmlRawImport,\n} from './utils/virtual-resources.js';\nimport { markStylePathSafe } from './utils/safe-module-paths.js';\n\ndeclare global {\n /**\n * Shared convention for out-of-tree compilers (e.g. `@tsrx/analog`) that\n * produce Angular Ivy definitions from a non-TS source format. Populate\n * this map with directive/component metadata for any class fastCompile\n * can't reach through its own tsconfig-driven scan, and the per-compile\n * registry lookup in `fastCompilePlugin` will merge those entries in —\n * so TS `@Component({ imports: [X] })` references to such classes\n * resolve statically instead of hitting the `_unresolved-${className}`\n * sentinel.\n */\n // eslint-disable-next-line no-var\n var __ANALOG_EXTERNAL_REGISTRY__: ComponentRegistry | undefined;\n}\n\nexport interface FastCompilePluginOptions {\n tsconfigGetter: () => string;\n workspaceRoot: string;\n inlineStylesExtension: string;\n jit: boolean;\n liveReload: boolean;\n supportedBrowsers: string[];\n transformFilter?: (code: string, id: string) => boolean;\n isTest: boolean;\n isAstroIntegration: boolean;\n fastCompileMode?: 'full' | 'partial';\n}\n\nexport function fastCompilePlugin(\n pluginOptions: FastCompilePluginOptions,\n): Plugin {\n let resolvedConfig: ResolvedConfig;\n let tsConfigResolutionContext: TsConfigResolutionContext | null = null;\n let watchMode = false;\n\n // fast-compile plugin state\n const registry: ComponentRegistry = new Map();\n const resourceToSource = new Map<string, string>();\n const scannedDtsPackages = new Set<string>();\n let projectRoot = '';\n let useDefineForClassFields = true;\n\n /**\n * Scan a file into the registry, then recursively walk its relative\n * `export *` / `export { … } from './x'` chain so any underlying\n * directive classes also land in the registry. Used both at\n * `buildStart` (for tsconfig path entries) and at dev time (file\n * `add` and `handleHotUpdate`) so newly added barrels stay in sync\n * without requiring a server restart.\n *\n * The `visited` set prevents infinite recursion within a single\n * top-level call. Each fresh scan should pass an empty set (so HMR\n * re-scans aren't blocked by buildStart's earlier visits).\n */\n async function scanBarrelExports(\n file: string,\n visited: Set<string> = new Set(),\n overwrite = false,\n ): Promise<void> {\n if (visited.has(file)) return;\n visited.add(file);\n let code: string;\n try {\n code = await fsPromises.readFile(file, 'utf-8');\n } catch (e) {\n if (debugRegistry.enabled) {\n debugRegistry(\n 'scanBarrelExports: failed to read %s: %s',\n file,\n (e as Error)?.message,\n );\n }\n return;\n }\n const entries = scanFile(code, file);\n for (const entry of entries) {\n // At buildStart we want stable registry entries (don't overwrite\n // an earlier scan with a barrel re-scan); HMR explicitly asks\n // for overwrite so updated metadata replaces stale entries.\n if (overwrite || !registry.has(entry.className)) {\n registry.set(entry.className, entry);\n }\n }\n // Collect every relative re-export specifier via OXC AST so\n // recursive scans can't trip over each other (a shared `/g` regex\n // would have its `lastIndex` reset by each recursive call and\n // silently skip half of an outer barrel's re-exports, which\n // previously left directives like `HlmRadioGroup` unregistered).\n const dir = dirname(file);\n for (const rel of collectRelativeReExports(code, file)) {\n // NodeNext-style libraries write `export * from './foo.js'`\n // even though the source is `./foo.ts`. Strip the ESM\n // extension before probing or the candidates would be\n // `foo.js.ts` / `foo.js/index.ts`, which never exist.\n const normalizedRel = rel.replace(/\\.(?:js|mjs)$/u, '');\n const reExportCandidates = [\n resolve(dir, normalizedRel + '.ts'),\n resolve(dir, normalizedRel, 'index.ts'),\n ];\n let resolved = false;\n for (const candidate of reExportCandidates) {\n try {\n await fsPromises.access(candidate);\n await scanBarrelExports(candidate, visited, overwrite);\n resolved = true;\n break;\n } catch {\n // try next candidate\n }\n }\n if (!resolved && debugRegistry.enabled) {\n debugRegistry(\n 'scanBarrelExports: %s re-export %s did not resolve to %o',\n file,\n rel,\n reExportCandidates,\n );\n }\n }\n }\n\n async function initFastCompile() {\n if (pluginOptions.jit) return; // JIT: no registry scan needed\n\n // Scan all source files to build the registry\n registry.clear();\n scannedDtsPackages.clear();\n const resolvedTsConfigPath = resolveTsConfigPath();\n projectRoot = dirname(resolvedTsConfigPath);\n const config = compilerCli.readConfiguration(resolvedTsConfigPath);\n useDefineForClassFields = config.options?.useDefineForClassFields ?? true;\n\n // Collect candidate files: tsconfig rootNames PLUS the entry points\n // named in `compilerOptions.paths`. App tsconfigs typically only\n // include the app's own sources, so workspace library entry barrels\n // (e.g. `HlmSelectImports = [HlmSelect, HlmSelectContent, ...] as\n // const`) live outside `rootNames` and would otherwise miss the\n // initial scan. The compiler then can't see that `HlmSelectImports`\n // is a tuple barrel and emits the bare identifier into the parent\n // component's `dependencies()` list, where Angular's runtime\n // silently drops it because arrays don't have a directive def.\n const candidates = new Set<string>(config.rootNames);\n const tsPaths = config.options?.paths;\n const baseUrl = (config.options?.baseUrl ?? projectRoot) as string;\n if (tsPaths) {\n for (const targets of Object.values(tsPaths)) {\n for (const target of targets as string[]) {\n // Skip wildcard patterns — entry barrels are normally exact\n // file paths like \"libs/helm/select/src/index.ts\".\n if (target.includes('*')) continue;\n candidates.add(resolve(baseUrl, target));\n }\n }\n }\n const results = await Promise.all(\n Array.from(candidates).map(async (file) => {\n try {\n const code = await fsPromises.readFile(file, 'utf-8');\n return scanFile(code, file);\n } catch (e) {\n if (debugRegistry.enabled) {\n debugRegistry(\n 'initFastCompile: skipping unreadable %s: %s',\n file,\n (e as Error)?.message,\n );\n }\n return []; // Skip unreadable files\n }\n }),\n );\n\n for (const entries of results) {\n for (const entry of entries) {\n registry.set(entry.className, entry);\n }\n }\n\n // Library barrels typically `export * from './lib/...'` rather than\n // declaring directives directly, so the entry file alone gives us\n // the tuple consts but not the directive classes they reference.\n // Walk the relative `export *` chain so the underlying classes also\n // land in the registry. Use a SHARED visited set across all\n // barrels so recursive walks don't double-scan a file that's\n // re-exported from multiple entry points.\n const buildStartVisited = new Set<string>();\n if (tsPaths) {\n const barrelCandidates: string[] = [];\n for (const targets of Object.values(tsPaths)) {\n for (const target of targets as string[]) {\n if (target.includes('*')) continue;\n barrelCandidates.push(resolve(baseUrl, target));\n }\n }\n await Promise.all(\n barrelCandidates.map((c) => scanBarrelExports(c, buildStartVisited)),\n );\n }\n debugRegistry(\n 'initFastCompile done: %d entries from %d candidate files',\n registry.size,\n candidates.size,\n );\n }\n\n function ensureDtsRegistryForSource(code: string, id: string) {\n for (const pkg of collectImportedPackages(code, id)) {\n if (scannedDtsPackages.has(pkg)) continue;\n scannedDtsPackages.add(pkg);\n\n try {\n const dtsEntries = scanPackageDts(pkg, projectRoot);\n for (const entry of dtsEntries) {\n if (!registry.has(entry.className)) {\n registry.set(entry.className, entry);\n }\n }\n } catch {\n // Package may not have .d.ts files or may not be Angular\n }\n }\n }\n\n async function handleFastCompileTransform(\n code: string,\n id: string,\n ): Promise<{ code: string; map: any } | undefined> {\n if (!/(Component|Directive|Pipe|Injectable|NgModule)\\(/.test(code)) {\n // Non-Angular file — strip TS-only syntax ourselves so barrels\n // like `export { Foo, type Bar } from './x'` and other TS-only\n // forms don't leak unstripped to Rolldown. In rolldown-vite the\n // built-in `vite:oxc` strip is registered as a Rust-side native\n // plugin (`viteTransformPlugin` from `rolldown/experimental`); if\n // its hook-filter treats files our `transform.filter.id.include`\n // claimed as already-handled, no JS-side fallback runs and raw\n // TS reaches the parser → `SyntaxError: Unexpected identifier`.\n const stripped = vite.transformWithOxc\n ? await vite.transformWithOxc(code, id, {\n lang: 'ts',\n sourcemap: true,\n decorator: { legacy: false, emitDecoratorMetadata: false },\n })\n : await vite.transformWithEsbuild(code, id, {\n loader: 'ts',\n sourcemap: true,\n });\n return { code: stripped.code, map: stripped.map };\n }\n\n // JIT mode\n if (pluginOptions.jit) {\n const result = jitTransform(code, id);\n // Strip TypeScript-only syntax (e.g. `readonly`, parameter property\n // modifiers, type annotations on fields) so the output is valid JS\n // for Rolldown. `angularVitestSourcemapPlugin` normally runs this\n // strip downstream in tests, but it is intentionally skipped on\n // StackBlitz / WebContainer — and the production build pipeline\n // does not register it either — so the JIT path must self-strip\n // to stay safe across environments.\n //\n // Pass the jitTransform map as `inMap` so OXC/esbuild emit a map\n // composed with the original `.ts` source — without this, debug\n // stack traces and breakpoints land on the wrong lines once the\n // strip removes any TS-only token. `jitTransform` returns\n // `map: null` for files with no Angular class (no edits made);\n // passing that to OXC/esbuild as `inMap` throws, so coerce to\n // `undefined` in that case.\n const inMap = result.map ?? undefined;\n const stripped = vite.transformWithOxc\n ? await vite.transformWithOxc(\n result.code,\n id,\n {\n lang: 'ts',\n sourcemap: true,\n decorator: { legacy: false, emitDecoratorMetadata: false },\n },\n inMap,\n )\n : await vite.transformWithEsbuild(\n result.code,\n id,\n { loader: 'ts', sourcemap: true },\n inMap,\n );\n return { code: stripped.code, map: stripped.map };\n }\n\n // Inline external templateUrl/styleUrl(s) into the source before compilation\n code = inlineResourceUrls(code, id);\n\n // Pre-resolve inline styles that need preprocessing (SCSS/Sass/Less)\n let resolvedStyles: Map<string, string> | undefined;\n let resolvedInlineStyles: Map<number, string> | undefined;\n\n if (pluginOptions.inlineStylesExtension !== 'css') {\n const styleStrings = extractInlineStyles(code, id);\n\n if (styleStrings.length > 0) {\n resolvedInlineStyles = new Map();\n for (let i = 0; i < styleStrings.length; i++) {\n try {\n const fakePath = id.replace(\n /\\.ts$/,\n `.inline-${i}.${pluginOptions.inlineStylesExtension}`,\n );\n const processed = await preprocessCSS(\n styleStrings[i],\n fakePath,\n resolvedConfig,\n );\n resolvedInlineStyles.set(i, processed.code);\n } catch (e) {\n if (debugCompile.enabled) {\n debugCompile(\n 'inline style #%d preprocessing failed in %s: %s',\n i,\n id,\n (e as Error)?.message,\n );\n }\n // Skip styles that can't be preprocessed\n }\n }\n if (resolvedInlineStyles.size === 0) resolvedInlineStyles = undefined;\n }\n }\n\n ensureDtsRegistryForSource(code, id);\n\n // Merge entries from the shared external-registry global into this\n // compile's lookup view. Convention: out-of-tree compilers populate\n // `globalThis.__ANALOG_EXTERNAL_REGISTRY__` with directive metadata\n // for classes fastCompile can't reach through its tsconfig-driven\n // scan (e.g. `.tsrx` files compiled by `@tsrx/analog`). Without this\n // merge, a TS `@Component({ imports: [X] })` that references such a\n // class hits `_unresolved-${className}` as its selector and the tag\n // never matches at runtime.\n let compileRegistry: ComponentRegistry = registry;\n const externalRegistry = globalThis.__ANALOG_EXTERNAL_REGISTRY__;\n if (externalRegistry && externalRegistry.size > 0) {\n compileRegistry = new Map(registry);\n for (const [k, v] of externalRegistry) compileRegistry.set(k, v);\n }\n\n const result = compile(code, id, {\n registry: compileRegistry,\n resolvedStyles,\n resolvedInlineStyles,\n useDefineForClassFields,\n compilationMode: pluginOptions.fastCompileMode,\n });\n\n // Track resource dependencies for HMR\n for (const dep of result.resourceDependencies) {\n resourceToSource.set(dep, id);\n }\n\n // Strip TypeScript-only syntax\n const stripped = vite.transformWithOxc\n ? await vite.transformWithOxc(result.code, id, {\n lang: 'ts',\n sourcemap: false,\n decorator: { legacy: false, emitDecoratorMetadata: false },\n })\n : await vite.transformWithEsbuild(result.code, id, {\n loader: 'ts',\n sourcemap: false,\n });\n let outputCode = stripped.code;\n\n // Append HMR code in dev mode\n if (watchMode && pluginOptions.liveReload) {\n const fileDeclarations = [...registry.values()].filter(\n (e) => e.fileName === id,\n );\n if (fileDeclarations.length > 0) {\n const localDepClassNames = fileDeclarations.map((e) => e.className);\n outputCode += generateHmrCode(fileDeclarations, localDepClassNames);\n }\n }\n\n return { code: outputCode, map: result.map };\n }\n\n function resolveTsConfigPath() {\n const { root, isProd, isLib } = tsConfigResolutionContext!;\n return getTsConfigPath(\n root,\n pluginOptions.tsconfigGetter(),\n isProd,\n pluginOptions.isTest,\n isLib,\n );\n }\n\n return {\n name: '@analogjs/vite-plugin-angular-fast-compile',\n enforce: 'pre' as const,\n async config(config, { command }) {\n watchMode = command === 'serve';\n const isProd =\n config.mode === 'production' ||\n process.env['NODE_ENV'] === 'production';\n\n tsConfigResolutionContext = {\n root: config.root || '.',\n isProd,\n isLib: !!config?.build?.lib,\n };\n\n const preliminaryTsConfigPath = resolveTsConfigPath();\n\n const depOptimizer = createDepOptimizerConfig({\n tsconfig: preliminaryTsConfigPath,\n isProd,\n jit: pluginOptions.jit,\n watchMode,\n isTest: pluginOptions.isTest,\n isAstroIntegration: pluginOptions.isAstroIntegration,\n });\n\n // No `resolve.conditions` extension here: the `style` condition is\n // scoped to `.css`-extension requests by\n // `cssExtensionStyleResolverPlugin`, registered once at the\n // `angular()` factory level (which is the only public entry point\n // that wires this plugin in).\n return {\n ...(vite.rolldownVersion ? { oxc: {} as any } : { esbuild: false }),\n ...depOptimizer,\n };\n },\n configResolved(config) {\n resolvedConfig = config;\n },\n configureServer(server) {\n // Watch for new .ts files and scan them into the registry. Use\n // the barrel-aware scanner so a newly added re-export entry\n // (`export * from './x'`) also expands its underlying directive\n // classes — otherwise the registry stays stale until restart.\n server.watcher.on('add', async (filePath) => {\n if (\n filePath.endsWith('.ts') &&\n !filePath.endsWith('.spec.ts') &&\n !filePath.endsWith('.d.ts')\n ) {\n await scanBarrelExports(filePath, new Set(), true);\n }\n });\n },\n async buildStart() {\n await initFastCompile();\n },\n async handleHotUpdate(ctx) {\n // Resource file changes → invalidate parent .ts module\n if (resourceToSource.has(ctx.file)) {\n const parentSource = resourceToSource.get(ctx.file)!;\n const parentModule = ctx.server.moduleGraph.getModuleById(parentSource);\n if (parentModule) {\n return [parentModule];\n }\n }\n\n if (TS_EXT_REGEX.test(ctx.file)) {\n const [fileId] = ctx.file.split('?');\n\n // Remove old entries from this file\n const oldEntries = [...registry.entries()]\n .filter(([_, v]) => v.fileName === fileId)\n .map(([k]) => k);\n for (const key of oldEntries) {\n registry.delete(key);\n }\n\n // Rescan the changed file via the barrel-aware scanner so an\n // edited barrel re-export picks up newly-referenced files.\n // Pass overwrite=true so updated metadata replaces stale\n // entries from the previous scan.\n await scanBarrelExports(fileId, new Set(), true);\n }\n\n // Let Vite handle the rest — the transform hook will recompile\n return ctx.modules;\n },\n resolveId(id, importer) {\n if (id.startsWith(VIRTUAL_RAW_PREFIX)) {\n return `\\0${id}`;\n }\n\n if (pluginOptions.jit && id.startsWith('angular:jit:')) {\n const filePath = normalizePath(\n resolve(dirname(importer as string), id.split(';')[1]),\n );\n if (id.includes(':style')) {\n markStylePathSafe(resolvedConfig, filePath);\n return filePath + '?inline';\n }\n return toVirtualRawId(filePath);\n }\n\n const rawRewrite = rewriteHtmlRawImport(id, importer);\n if (rawRewrite) return rawRewrite;\n\n // User `.scss?inline` / `.css?inline` imports: resolve and mark\n // safe so Vite's native CSS pipeline handles them.\n if (/\\.(css|scss|sass|less)\\?inline$/.test(id) && importer) {\n const filePath = id.split('?')[0];\n const resolved = isAbsolute(filePath)\n ? normalizePath(filePath)\n : normalizePath(resolve(dirname(importer), filePath));\n markStylePathSafe(resolvedConfig, resolved);\n return resolved + '?inline';\n }\n\n return undefined;\n },\n async load(id) {\n const rawModule = await loadVirtualRawModule(this, id);\n if (rawModule !== undefined) return rawModule;\n\n // Vitest fallback: module-runner can skip resolveId, so the bare\n // ?inline query reaches load. Mark safe and let Vite handle it.\n if (/\\.(css|scss|sass|less)\\?inline$/.test(id)) {\n markStylePathSafe(resolvedConfig, id.split('?')[0]);\n }\n\n return;\n },\n transform: {\n filter: {\n id: {\n include: [TS_EXT_REGEX],\n exclude: [/node_modules/, 'type=script', '@ng/component'],\n },\n },\n async handler(code, id) {\n if (\n pluginOptions.transformFilter &&\n !(pluginOptions.transformFilter(code, id) ?? true)\n ) {\n return;\n }\n\n if (id.includes('.ts?')) {\n id = id.replace(/\\?(.*)/, '');\n }\n return handleFastCompileTransform(code, id);\n },\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fast-compile-plugin.js","names":[],"sources":["../../../src/lib/fast-compile-plugin.ts"],"sourcesContent":["import { promises as fsPromises } from 'node:fs';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport * as vite from 'vite';\n\nimport * as compilerCli from '@angular/compiler-cli';\nimport { normalizePath, Plugin, preprocessCSS, ResolvedConfig } from 'vite';\n\nimport {\n compile,\n scanFile,\n scanPackageDts,\n collectImportedPackages,\n collectRelativeReExports,\n jitTransform,\n inlineResourceUrls,\n extractInlineStyles,\n generateHmrCode,\n debugCompile,\n debugRegistry,\n type ComponentRegistry,\n} from './compiler/index.js';\n\nimport {\n TS_EXT_REGEX,\n getTsConfigPath,\n createDepOptimizerConfig,\n type TsConfigResolutionContext,\n} from './utils/plugin-config.js';\nimport { VIRTUAL_RAW_PREFIX, toVirtualRawId } from './utils/virtual-ids.js';\nimport {\n loadVirtualRawModule,\n rewriteHtmlRawImport,\n} from './utils/virtual-resources.js';\nimport { markStylePathSafe } from './utils/safe-module-paths.js';\n\ndeclare global {\n /**\n * Shared convention for out-of-tree compilers (e.g. `@tsrx/analog`) that\n * produce Angular Ivy definitions from a non-TS source format. Populate\n * this map with directive/component metadata for any class fastCompile\n * can't reach through its own tsconfig-driven scan, and the per-compile\n * registry lookup in `fastCompilePlugin` will merge those entries in —\n * so TS `@Component({ imports: [X] })` references to such classes\n * resolve statically instead of hitting the `_unresolved-${className}`\n * sentinel.\n */\n // eslint-disable-next-line no-var\n var __ANALOG_EXTERNAL_REGISTRY__: ComponentRegistry | undefined;\n}\n\nexport interface FastCompilePluginOptions {\n tsconfigGetter: () => string;\n workspaceRoot: string;\n inlineStylesExtension: string;\n jit: boolean;\n liveReload: boolean;\n supportedBrowsers: string[];\n transformFilter?: (code: string, id: string) => boolean;\n isTest: boolean;\n isAstroIntegration: boolean;\n fastCompileMode?: 'full' | 'partial';\n}\n\nexport function fastCompilePlugin(\n pluginOptions: FastCompilePluginOptions,\n): Plugin {\n let resolvedConfig: ResolvedConfig;\n let tsConfigResolutionContext: TsConfigResolutionContext | null = null;\n let watchMode = false;\n\n // fast-compile plugin state\n const registry: ComponentRegistry = new Map();\n const resourceToSource = new Map<string, string>();\n const scannedDtsPackages = new Set<string>();\n let projectRoot = '';\n let useDefineForClassFields = true;\n\n /**\n * Scan a file into the registry, then recursively walk its relative\n * `export *` / `export { … } from './x'` chain so any underlying\n * directive classes also land in the registry. Used both at\n * `buildStart` (for tsconfig path entries) and at dev time (file\n * `add` and `handleHotUpdate`) so newly added barrels stay in sync\n * without requiring a server restart.\n *\n * The `visited` set prevents infinite recursion within a single\n * top-level call. Each fresh scan should pass an empty set (so HMR\n * re-scans aren't blocked by buildStart's earlier visits).\n */\n async function scanBarrelExports(\n file: string,\n visited: Set<string> = new Set(),\n overwrite = false,\n ): Promise<void> {\n if (visited.has(file)) return;\n visited.add(file);\n let code: string;\n try {\n code = await fsPromises.readFile(file, 'utf-8');\n } catch (e) {\n if (debugRegistry.enabled) {\n debugRegistry(\n 'scanBarrelExports: failed to read %s: %s',\n file,\n (e as Error)?.message,\n );\n }\n return;\n }\n const entries = scanFile(code, file);\n for (const entry of entries) {\n // At buildStart we want stable registry entries (don't overwrite\n // an earlier scan with a barrel re-scan); HMR explicitly asks\n // for overwrite so updated metadata replaces stale entries.\n if (overwrite || !registry.has(entry.className)) {\n registry.set(entry.className, entry);\n }\n }\n // Collect every relative re-export specifier via OXC AST so\n // recursive scans can't trip over each other (a shared `/g` regex\n // would have its `lastIndex` reset by each recursive call and\n // silently skip half of an outer barrel's re-exports, which\n // previously left directives like `HlmRadioGroup` unregistered).\n const dir = dirname(file);\n for (const rel of collectRelativeReExports(code, file)) {\n // NodeNext-style libraries write `export * from './foo.js'`\n // even though the source is `./foo.ts`. Strip the ESM\n // extension before probing or the candidates would be\n // `foo.js.ts` / `foo.js/index.ts`, which never exist.\n const normalizedRel = rel.replace(/\\.(?:js|mjs)$/u, '');\n const reExportCandidates = [\n resolve(dir, normalizedRel + '.ts'),\n resolve(dir, normalizedRel, 'index.ts'),\n ];\n let resolved = false;\n for (const candidate of reExportCandidates) {\n try {\n await fsPromises.access(candidate);\n await scanBarrelExports(candidate, visited, overwrite);\n resolved = true;\n break;\n } catch {\n // try next candidate\n }\n }\n if (!resolved && debugRegistry.enabled) {\n debugRegistry(\n 'scanBarrelExports: %s re-export %s did not resolve to %o',\n file,\n rel,\n reExportCandidates,\n );\n }\n }\n }\n\n async function initFastCompile() {\n if (pluginOptions.jit) return; // JIT: no registry scan needed\n\n // Scan all source files to build the registry\n registry.clear();\n scannedDtsPackages.clear();\n const resolvedTsConfigPath = resolveTsConfigPath();\n projectRoot = dirname(resolvedTsConfigPath);\n const config = compilerCli.readConfiguration(resolvedTsConfigPath);\n useDefineForClassFields = config.options?.useDefineForClassFields ?? true;\n\n // Collect candidate files: tsconfig rootNames PLUS the entry points\n // named in `compilerOptions.paths`. App tsconfigs typically only\n // include the app's own sources, so workspace library entry barrels\n // (e.g. `HlmSelectImports = [HlmSelect, HlmSelectContent, ...] as\n // const`) live outside `rootNames` and would otherwise miss the\n // initial scan. The compiler then can't see that `HlmSelectImports`\n // is a tuple barrel and emits the bare identifier into the parent\n // component's `dependencies()` list, where Angular's runtime\n // silently drops it because arrays don't have a directive def.\n const candidates = new Set<string>(config.rootNames);\n const tsPaths = config.options?.paths;\n const baseUrl = (config.options?.baseUrl ?? projectRoot) as string;\n if (tsPaths) {\n for (const targets of Object.values(tsPaths)) {\n for (const target of targets as string[]) {\n // Skip wildcard patterns — entry barrels are normally exact\n // file paths like \"libs/helm/select/src/index.ts\".\n if (target.includes('*')) continue;\n candidates.add(resolve(baseUrl, target));\n }\n }\n }\n const results = await Promise.all(\n Array.from(candidates).map(async (file) => {\n try {\n const code = await fsPromises.readFile(file, 'utf-8');\n return scanFile(code, file);\n } catch (e) {\n if (debugRegistry.enabled) {\n debugRegistry(\n 'initFastCompile: skipping unreadable %s: %s',\n file,\n (e as Error)?.message,\n );\n }\n return []; // Skip unreadable files\n }\n }),\n );\n\n for (const entries of results) {\n for (const entry of entries) {\n registry.set(entry.className, entry);\n }\n }\n\n // Library barrels typically `export * from './lib/...'` rather than\n // declaring directives directly, so the entry file alone gives us\n // the tuple consts but not the directive classes they reference.\n // Walk the relative `export *` chain so the underlying classes also\n // land in the registry. Use a SHARED visited set across all\n // barrels so recursive walks don't double-scan a file that's\n // re-exported from multiple entry points.\n const buildStartVisited = new Set<string>();\n if (tsPaths) {\n const barrelCandidates: string[] = [];\n for (const targets of Object.values(tsPaths)) {\n for (const target of targets as string[]) {\n if (target.includes('*')) continue;\n barrelCandidates.push(resolve(baseUrl, target));\n }\n }\n await Promise.all(\n barrelCandidates.map((c) => scanBarrelExports(c, buildStartVisited)),\n );\n }\n debugRegistry(\n 'initFastCompile done: %d entries from %d candidate files',\n registry.size,\n candidates.size,\n );\n }\n\n function ensureDtsRegistryForSource(code: string, id: string) {\n for (const pkg of collectImportedPackages(code, id)) {\n if (scannedDtsPackages.has(pkg)) continue;\n scannedDtsPackages.add(pkg);\n\n try {\n const dtsEntries = scanPackageDts(pkg, projectRoot);\n for (const entry of dtsEntries) {\n if (!registry.has(entry.className)) {\n registry.set(entry.className, entry);\n }\n }\n } catch {\n // Package may not have .d.ts files or may not be Angular\n }\n }\n }\n\n async function handleFastCompileTransform(\n code: string,\n id: string,\n ): Promise<{ code: string; map: any } | undefined> {\n if (!/(Component|Directive|Pipe|Injectable|NgModule)\\(/.test(code)) {\n // Non-Angular file — strip TS-only syntax ourselves so barrels\n // like `export { Foo, type Bar } from './x'` and other TS-only\n // forms don't leak unstripped to Rolldown. In rolldown-vite the\n // built-in `vite:oxc` strip is registered as a Rust-side native\n // plugin (`viteTransformPlugin` from `rolldown/experimental`); if\n // its hook-filter treats files our `transform.filter.id.include`\n // claimed as already-handled, no JS-side fallback runs and raw\n // TS reaches the parser → `SyntaxError: Unexpected identifier`.\n const stripped = vite.transformWithOxc\n ? await vite.transformWithOxc(code, id, {\n lang: 'ts',\n sourcemap: true,\n decorator: { legacy: false, emitDecoratorMetadata: false },\n })\n : await vite.transformWithEsbuild(code, id, {\n loader: 'ts',\n sourcemap: true,\n });\n return { code: stripped.code, map: stripped.map };\n }\n\n // JIT mode\n if (pluginOptions.jit) {\n const result = jitTransform(code, id);\n // Strip TypeScript-only syntax (e.g. `readonly`, parameter property\n // modifiers, type annotations on fields) so the output is valid JS\n // for Rolldown. `angularVitestSourcemapPlugin` normally runs this\n // strip downstream in tests, but it is intentionally skipped on\n // StackBlitz / WebContainer — and the production build pipeline\n // does not register it either — so the JIT path must self-strip\n // to stay safe across environments.\n //\n // Pass the jitTransform map as `inMap` so OXC/esbuild emit a map\n // composed with the original `.ts` source — without this, debug\n // stack traces and breakpoints land on the wrong lines once the\n // strip removes any TS-only token. `jitTransform` returns\n // `map: null` for files with no Angular class (no edits made);\n // passing that to OXC/esbuild as `inMap` throws, so coerce to\n // `undefined` in that case.\n const inMap = result.map ?? undefined;\n const stripped = vite.transformWithOxc\n ? await vite.transformWithOxc(\n result.code,\n id,\n {\n lang: 'ts',\n sourcemap: true,\n decorator: { legacy: false, emitDecoratorMetadata: false },\n },\n inMap,\n )\n : await vite.transformWithEsbuild(\n result.code,\n id,\n { loader: 'ts', sourcemap: true },\n inMap,\n );\n return { code: stripped.code, map: stripped.map };\n }\n\n // Inline external templateUrl/styleUrl(s) into the source before compilation\n code = inlineResourceUrls(code, id);\n\n // Pre-resolve inline styles that need preprocessing (SCSS/Sass/Less)\n let resolvedStyles: Map<string, string> | undefined;\n let resolvedInlineStyles: Map<number, string> | undefined;\n\n if (pluginOptions.inlineStylesExtension !== 'css') {\n const styleStrings = extractInlineStyles(code, id);\n\n if (styleStrings.length > 0) {\n resolvedInlineStyles = new Map();\n for (let i = 0; i < styleStrings.length; i++) {\n try {\n const fakePath = id.replace(\n /\\.ts$/,\n `.inline-${i}.${pluginOptions.inlineStylesExtension}`,\n );\n const processed = await preprocessCSS(\n styleStrings[i],\n fakePath,\n resolvedConfig,\n );\n resolvedInlineStyles.set(i, processed.code);\n } catch (e) {\n if (debugCompile.enabled) {\n debugCompile(\n 'inline style #%d preprocessing failed in %s: %s',\n i,\n id,\n (e as Error)?.message,\n );\n }\n // Skip styles that can't be preprocessed\n }\n }\n if (resolvedInlineStyles.size === 0) resolvedInlineStyles = undefined;\n }\n }\n\n ensureDtsRegistryForSource(code, id);\n\n // Merge entries from the shared external-registry global into this\n // compile's lookup view. Convention: out-of-tree compilers populate\n // `globalThis.__ANALOG_EXTERNAL_REGISTRY__` with directive metadata\n // for classes fastCompile can't reach through its tsconfig-driven\n // scan (e.g. `.tsrx` files compiled by `@tsrx/analog`). Without this\n // merge, a TS `@Component({ imports: [X] })` that references such a\n // class hits `_unresolved-${className}` as its selector and the tag\n // never matches at runtime.\n let compileRegistry: ComponentRegistry = registry;\n const externalRegistry = globalThis.__ANALOG_EXTERNAL_REGISTRY__;\n if (externalRegistry && externalRegistry.size > 0) {\n compileRegistry = new Map(registry);\n for (const [k, v] of externalRegistry) compileRegistry.set(k, v);\n }\n\n const result = compile(code, id, {\n registry: compileRegistry,\n resolvedStyles,\n resolvedInlineStyles,\n useDefineForClassFields,\n compilationMode: pluginOptions.fastCompileMode,\n });\n\n // Track resource dependencies for HMR\n for (const dep of result.resourceDependencies) {\n resourceToSource.set(dep, id);\n }\n\n // Strip TypeScript-only syntax\n const stripped = vite.transformWithOxc\n ? await vite.transformWithOxc(result.code, id, {\n lang: 'ts',\n sourcemap: false,\n decorator: { legacy: false, emitDecoratorMetadata: false },\n })\n : await vite.transformWithEsbuild(result.code, id, {\n loader: 'ts',\n sourcemap: false,\n });\n let outputCode = stripped.code;\n\n // Append HMR code in dev mode\n if (watchMode && pluginOptions.liveReload) {\n const fileDeclarations = [...registry.values()].filter(\n (e) => e.fileName === id,\n );\n if (fileDeclarations.length > 0) {\n const localDepClassNames = fileDeclarations.map((e) => e.className);\n outputCode += generateHmrCode(fileDeclarations, localDepClassNames);\n }\n }\n\n return { code: outputCode, map: result.map };\n }\n\n function resolveTsConfigPath() {\n const { root, isProd, isLib } = tsConfigResolutionContext!;\n return getTsConfigPath(\n root,\n pluginOptions.tsconfigGetter(),\n isProd,\n pluginOptions.isTest,\n isLib,\n );\n }\n\n return {\n name: '@analogjs/vite-plugin-angular-fast-compile',\n enforce: 'pre' as const,\n async config(config, { command }) {\n watchMode = command === 'serve';\n const isProd =\n config.mode === 'production' ||\n process.env['NODE_ENV'] === 'production';\n\n tsConfigResolutionContext = {\n root: config.root || '.',\n isProd,\n isLib: !!config?.build?.lib,\n };\n\n const preliminaryTsConfigPath = resolveTsConfigPath();\n\n const depOptimizer = createDepOptimizerConfig({\n tsconfig: preliminaryTsConfigPath,\n isProd,\n jit: pluginOptions.jit,\n watchMode,\n isTest: pluginOptions.isTest,\n isAstroIntegration: pluginOptions.isAstroIntegration,\n });\n\n // No `resolve.conditions` extension here: the `style` condition is\n // scoped to `.css`-extension requests by\n // `cssExtensionStyleResolverPlugin`, registered once at the\n // `angular()` factory level (which is the only public entry point\n // that wires this plugin in).\n return {\n ...(vite.rolldownVersion ? { oxc: {} as any } : { esbuild: false }),\n ...depOptimizer,\n };\n },\n configResolved(config) {\n resolvedConfig = config;\n },\n configureServer(server) {\n // Watch for new .ts files and scan them into the registry. Use\n // the barrel-aware scanner so a newly added re-export entry\n // (`export * from './x'`) also expands its underlying directive\n // classes — otherwise the registry stays stale until restart.\n server.watcher.on('add', async (filePath) => {\n if (\n filePath.endsWith('.ts') &&\n !filePath.endsWith('.spec.ts') &&\n !filePath.endsWith('.d.ts')\n ) {\n await scanBarrelExports(filePath, new Set(), true);\n }\n });\n },\n async buildStart() {\n await initFastCompile();\n },\n async handleHotUpdate(ctx) {\n // Resource file changes → invalidate parent .ts module\n if (resourceToSource.has(ctx.file)) {\n const parentSource = resourceToSource.get(ctx.file)!;\n const parentModule = ctx.server.moduleGraph.getModuleById(parentSource);\n if (parentModule) {\n return [parentModule];\n }\n }\n\n if (TS_EXT_REGEX.test(ctx.file)) {\n const [fileId] = ctx.file.split('?');\n\n // Remove old entries from this file\n const oldEntries = [...registry.entries()]\n .filter(([_, v]) => v.fileName === fileId)\n .map(([k]) => k);\n for (const key of oldEntries) {\n registry.delete(key);\n }\n\n // Rescan the changed file via the barrel-aware scanner so an\n // edited barrel re-export picks up newly-referenced files.\n // Pass overwrite=true so updated metadata replaces stale\n // entries from the previous scan.\n await scanBarrelExports(fileId, new Set(), true);\n }\n\n // Let Vite handle the rest — the transform hook will recompile\n return ctx.modules;\n },\n resolveId(id, importer) {\n if (id.startsWith(VIRTUAL_RAW_PREFIX)) {\n return `\\0${id}`;\n }\n\n if (pluginOptions.jit && id.startsWith('angular:jit:')) {\n const filePath = normalizePath(\n resolve(dirname(importer as string), id.split(';')[1]),\n );\n if (id.includes(':style')) {\n markStylePathSafe(resolvedConfig, filePath);\n return filePath + '?inline';\n }\n return toVirtualRawId(filePath);\n }\n\n const rawRewrite = rewriteHtmlRawImport(id, importer);\n if (rawRewrite) return rawRewrite;\n\n // User `.scss?inline` / `.css?inline` imports: resolve and mark\n // safe so Vite's native CSS pipeline handles them.\n if (/\\.(css|scss|sass|less)\\?inline$/.test(id) && importer) {\n const filePath = id.split('?')[0];\n const resolved = isAbsolute(filePath)\n ? normalizePath(filePath)\n : normalizePath(resolve(dirname(importer), filePath));\n markStylePathSafe(resolvedConfig, resolved);\n return resolved + '?inline';\n }\n\n return undefined;\n },\n async load(id) {\n const rawModule = await loadVirtualRawModule(this, id);\n if (rawModule !== undefined) return rawModule;\n\n // Vitest fallback: module-runner can skip resolveId, so the bare\n // ?inline query reaches load. Mark safe and let Vite handle it.\n if (/\\.(css|scss|sass|less)\\?inline$/.test(id)) {\n markStylePathSafe(resolvedConfig, id.split('?')[0]);\n }\n\n return;\n },\n transform: {\n filter: {\n id: {\n include: [TS_EXT_REGEX],\n // `?raw` ids already carry Vite's native raw-loader output\n // (`export default \"<source>\"`). Recompiling them as Angular/TS\n // would strip that default export, so leave them to Vite (#2356).\n exclude: [\n /node_modules/,\n 'type=script',\n '@ng/component',\n /[?&]raw\\b/,\n ],\n },\n },\n async handler(code, id) {\n if (\n pluginOptions.transformFilter &&\n !(pluginOptions.transformFilter(code, id) ?? true)\n ) {\n return;\n }\n\n if (id.includes('.ts?')) {\n id = id.replace(/\\?(.*)/, '');\n }\n return handleFastCompileTransform(code, id);\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA+DA,SAAgB,kBACd,eACQ;CACR,IAAI;CACJ,IAAI,4BAA8D;CAClE,IAAI,YAAY;CAGhB,MAAM,2BAA8B,IAAI,KAAK;CAC7C,MAAM,mCAAmB,IAAI,KAAqB;CAClD,MAAM,qCAAqB,IAAI,KAAa;CAC5C,IAAI,cAAc;CAClB,IAAI,0BAA0B;;;;;;;;;;;;;CAc9B,eAAe,kBACb,MACA,0BAAuB,IAAI,KAAK,EAChC,YAAY,OACG;AACf,MAAI,QAAQ,IAAI,KAAK,CAAE;AACvB,UAAQ,IAAI,KAAK;EACjB,IAAI;AACJ,MAAI;AACF,UAAO,MAAM,SAAW,SAAS,MAAM,QAAQ;WACxC,GAAG;AACV,OAAI,cAAc,QAChB,eACE,4CACA,MACC,GAAa,QACf;AAEH;;EAEF,MAAM,UAAU,SAAS,MAAM,KAAK;AACpC,OAAK,MAAM,SAAS,QAIlB,KAAI,aAAa,CAAC,SAAS,IAAI,MAAM,UAAU,CAC7C,UAAS,IAAI,MAAM,WAAW,MAAM;EAQxC,MAAM,MAAM,QAAQ,KAAK;AACzB,OAAK,MAAM,OAAO,yBAAyB,MAAM,KAAK,EAAE;GAKtD,MAAM,gBAAgB,IAAI,QAAQ,kBAAkB,GAAG;GACvD,MAAM,qBAAqB,CACzB,QAAQ,KAAK,gBAAgB,MAAM,EACnC,QAAQ,KAAK,eAAe,WAAW,CACxC;GACD,IAAI,WAAW;AACf,QAAK,MAAM,aAAa,mBACtB,KAAI;AACF,UAAM,SAAW,OAAO,UAAU;AAClC,UAAM,kBAAkB,WAAW,SAAS,UAAU;AACtD,eAAW;AACX;WACM;AAIV,OAAI,CAAC,YAAY,cAAc,QAC7B,eACE,4DACA,MACA,KACA,mBACD;;;CAKP,eAAe,kBAAkB;AAC/B,MAAI,cAAc,IAAK;AAGvB,WAAS,OAAO;AAChB,qBAAmB,OAAO;EAC1B,MAAM,uBAAuB,qBAAqB;AAClD,gBAAc,QAAQ,qBAAqB;EAC3C,MAAM,SAAS,YAAY,kBAAkB,qBAAqB;AAClE,4BAA0B,OAAO,SAAS,2BAA2B;EAWrE,MAAM,aAAa,IAAI,IAAY,OAAO,UAAU;EACpD,MAAM,UAAU,OAAO,SAAS;EAChC,MAAM,UAAW,OAAO,SAAS,WAAW;AAC5C,MAAI,QACF,MAAK,MAAM,WAAW,OAAO,OAAO,QAAQ,CAC1C,MAAK,MAAM,UAAU,SAAqB;AAGxC,OAAI,OAAO,SAAS,IAAI,CAAE;AAC1B,cAAW,IAAI,QAAQ,SAAS,OAAO,CAAC;;EAI9C,MAAM,UAAU,MAAM,QAAQ,IAC5B,MAAM,KAAK,WAAW,CAAC,IAAI,OAAO,SAAS;AACzC,OAAI;AAEF,WAAO,SADM,MAAM,SAAW,SAAS,MAAM,QAAQ,EAC/B,KAAK;YACpB,GAAG;AACV,QAAI,cAAc,QAChB,eACE,+CACA,MACC,GAAa,QACf;AAEH,WAAO,EAAE;;IAEX,CACH;AAED,OAAK,MAAM,WAAW,QACpB,MAAK,MAAM,SAAS,QAClB,UAAS,IAAI,MAAM,WAAW,MAAM;EAWxC,MAAM,oCAAoB,IAAI,KAAa;AAC3C,MAAI,SAAS;GACX,MAAM,mBAA6B,EAAE;AACrC,QAAK,MAAM,WAAW,OAAO,OAAO,QAAQ,CAC1C,MAAK,MAAM,UAAU,SAAqB;AACxC,QAAI,OAAO,SAAS,IAAI,CAAE;AAC1B,qBAAiB,KAAK,QAAQ,SAAS,OAAO,CAAC;;AAGnD,SAAM,QAAQ,IACZ,iBAAiB,KAAK,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,CACrE;;AAEH,gBACE,4DACA,SAAS,MACT,WAAW,KACZ;;CAGH,SAAS,2BAA2B,MAAc,IAAY;AAC5D,OAAK,MAAM,OAAO,wBAAwB,MAAM,GAAG,EAAE;AACnD,OAAI,mBAAmB,IAAI,IAAI,CAAE;AACjC,sBAAmB,IAAI,IAAI;AAE3B,OAAI;IACF,MAAM,aAAa,eAAe,KAAK,YAAY;AACnD,SAAK,MAAM,SAAS,WAClB,KAAI,CAAC,SAAS,IAAI,MAAM,UAAU,CAChC,UAAS,IAAI,MAAM,WAAW,MAAM;WAGlC;;;CAMZ,eAAe,2BACb,MACA,IACiD;AACjD,MAAI,CAAC,mDAAmD,KAAK,KAAK,EAAE;GASlE,MAAM,WAAW,KAAK,mBAClB,MAAM,KAAK,iBAAiB,MAAM,IAAI;IACpC,MAAM;IACN,WAAW;IACX,WAAW;KAAE,QAAQ;KAAO,uBAAuB;KAAO;IAC3D,CAAC,GACF,MAAM,KAAK,qBAAqB,MAAM,IAAI;IACxC,QAAQ;IACR,WAAW;IACZ,CAAC;AACN,UAAO;IAAE,MAAM,SAAS;IAAM,KAAK,SAAS;IAAK;;AAInD,MAAI,cAAc,KAAK;GACrB,MAAM,SAAS,aAAa,MAAM,GAAG;GAgBrC,MAAM,QAAQ,OAAO,OAAO,KAAA;GAC5B,MAAM,WAAW,KAAK,mBAClB,MAAM,KAAK,iBACT,OAAO,MACP,IACA;IACE,MAAM;IACN,WAAW;IACX,WAAW;KAAE,QAAQ;KAAO,uBAAuB;KAAO;IAC3D,EACD,MACD,GACD,MAAM,KAAK,qBACT,OAAO,MACP,IACA;IAAE,QAAQ;IAAM,WAAW;IAAM,EACjC,MACD;AACL,UAAO;IAAE,MAAM,SAAS;IAAM,KAAK,SAAS;IAAK;;AAInD,SAAO,mBAAmB,MAAM,GAAG;EAGnC,IAAI;EACJ,IAAI;AAEJ,MAAI,cAAc,0BAA0B,OAAO;GACjD,MAAM,eAAe,oBAAoB,MAAM,GAAG;AAElD,OAAI,aAAa,SAAS,GAAG;AAC3B,2CAAuB,IAAI,KAAK;AAChC,SAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,IACvC,KAAI;KACF,MAAM,WAAW,GAAG,QAClB,SACA,WAAW,EAAE,GAAG,cAAc,wBAC/B;KACD,MAAM,YAAY,MAAM,cACtB,aAAa,IACb,UACA,eACD;AACD,0BAAqB,IAAI,GAAG,UAAU,KAAK;aACpC,GAAG;AACV,SAAI,aAAa,QACf,cACE,mDACA,GACA,IACC,GAAa,QACf;;AAKP,QAAI,qBAAqB,SAAS,EAAG,wBAAuB,KAAA;;;AAIhE,6BAA2B,MAAM,GAAG;EAUpC,IAAI,kBAAqC;EACzC,MAAM,mBAAmB,WAAW;AACpC,MAAI,oBAAoB,iBAAiB,OAAO,GAAG;AACjD,qBAAkB,IAAI,IAAI,SAAS;AACnC,QAAK,MAAM,CAAC,GAAG,MAAM,iBAAkB,iBAAgB,IAAI,GAAG,EAAE;;EAGlE,MAAM,SAAS,QAAQ,MAAM,IAAI;GAC/B,UAAU;GACV;GACA;GACA;GACA,iBAAiB,cAAc;GAChC,CAAC;AAGF,OAAK,MAAM,OAAO,OAAO,qBACvB,kBAAiB,IAAI,KAAK,GAAG;EAc/B,IAAI,cAVa,KAAK,mBAClB,MAAM,KAAK,iBAAiB,OAAO,MAAM,IAAI;GAC3C,MAAM;GACN,WAAW;GACX,WAAW;IAAE,QAAQ;IAAO,uBAAuB;IAAO;GAC3D,CAAC,GACF,MAAM,KAAK,qBAAqB,OAAO,MAAM,IAAI;GAC/C,QAAQ;GACR,WAAW;GACZ,CAAC,EACoB;AAG1B,MAAI,aAAa,cAAc,YAAY;GACzC,MAAM,mBAAmB,CAAC,GAAG,SAAS,QAAQ,CAAC,CAAC,QAC7C,MAAM,EAAE,aAAa,GACvB;AACD,OAAI,iBAAiB,SAAS,GAAG;IAC/B,MAAM,qBAAqB,iBAAiB,KAAK,MAAM,EAAE,UAAU;AACnE,kBAAc,gBAAgB,kBAAkB,mBAAmB;;;AAIvE,SAAO;GAAE,MAAM;GAAY,KAAK,OAAO;GAAK;;CAG9C,SAAS,sBAAsB;EAC7B,MAAM,EAAE,MAAM,QAAQ,UAAU;AAChC,SAAO,gBACL,MACA,cAAc,gBAAgB,EAC9B,QACA,cAAc,QACd,MACD;;AAGH,QAAO;EACL,MAAM;EACN,SAAS;EACT,MAAM,OAAO,QAAQ,EAAE,WAAW;AAChC,eAAY,YAAY;GACxB,MAAM,SACJ,OAAO,SAAS,gBAAA,QAAA,IAAA,aACY;AAE9B,+BAA4B;IAC1B,MAAM,OAAO,QAAQ;IACrB;IACA,OAAO,CAAC,CAAC,QAAQ,OAAO;IACzB;GAID,MAAM,eAAe,yBAAyB;IAC5C,UAH8B,qBAAqB;IAInD;IACA,KAAK,cAAc;IACnB;IACA,QAAQ,cAAc;IACtB,oBAAoB,cAAc;IACnC,CAAC;AAOF,UAAO;IACL,GAAI,KAAK,kBAAkB,EAAE,KAAK,EAAE,EAAS,GAAG,EAAE,SAAS,OAAO;IAClE,GAAG;IACJ;;EAEH,eAAe,QAAQ;AACrB,oBAAiB;;EAEnB,gBAAgB,QAAQ;AAKtB,UAAO,QAAQ,GAAG,OAAO,OAAO,aAAa;AAC3C,QACE,SAAS,SAAS,MAAM,IACxB,CAAC,SAAS,SAAS,WAAW,IAC9B,CAAC,SAAS,SAAS,QAAQ,CAE3B,OAAM,kBAAkB,0BAAU,IAAI,KAAK,EAAE,KAAK;KAEpD;;EAEJ,MAAM,aAAa;AACjB,SAAM,iBAAiB;;EAEzB,MAAM,gBAAgB,KAAK;AAEzB,OAAI,iBAAiB,IAAI,IAAI,KAAK,EAAE;IAClC,MAAM,eAAe,iBAAiB,IAAI,IAAI,KAAK;IACnD,MAAM,eAAe,IAAI,OAAO,YAAY,cAAc,aAAa;AACvE,QAAI,aACF,QAAO,CAAC,aAAa;;AAIzB,OAAI,aAAa,KAAK,IAAI,KAAK,EAAE;IAC/B,MAAM,CAAC,UAAU,IAAI,KAAK,MAAM,IAAI;IAGpC,MAAM,aAAa,CAAC,GAAG,SAAS,SAAS,CAAC,CACvC,QAAQ,CAAC,GAAG,OAAO,EAAE,aAAa,OAAO,CACzC,KAAK,CAAC,OAAO,EAAE;AAClB,SAAK,MAAM,OAAO,WAChB,UAAS,OAAO,IAAI;AAOtB,UAAM,kBAAkB,wBAAQ,IAAI,KAAK,EAAE,KAAK;;AAIlD,UAAO,IAAI;;EAEb,UAAU,IAAI,UAAU;AACtB,OAAI,GAAG,WAAA,6CAA8B,CACnC,QAAO,KAAK;AAGd,OAAI,cAAc,OAAO,GAAG,WAAW,eAAe,EAAE;IACtD,MAAM,WAAW,cACf,QAAQ,QAAQ,SAAmB,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,CACvD;AACD,QAAI,GAAG,SAAS,SAAS,EAAE;AACzB,uBAAkB,gBAAgB,SAAS;AAC3C,YAAO,WAAW;;AAEpB,WAAO,eAAe,SAAS;;GAGjC,MAAM,aAAa,qBAAqB,IAAI,SAAS;AACrD,OAAI,WAAY,QAAO;AAIvB,OAAI,kCAAkC,KAAK,GAAG,IAAI,UAAU;IAC1D,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;IAC/B,MAAM,WAAW,WAAW,SAAS,GACjC,cAAc,SAAS,GACvB,cAAc,QAAQ,QAAQ,SAAS,EAAE,SAAS,CAAC;AACvD,sBAAkB,gBAAgB,SAAS;AAC3C,WAAO,WAAW;;;EAKtB,MAAM,KAAK,IAAI;GACb,MAAM,YAAY,MAAM,qBAAqB,MAAM,GAAG;AACtD,OAAI,cAAc,KAAA,EAAW,QAAO;AAIpC,OAAI,kCAAkC,KAAK,GAAG,CAC5C,mBAAkB,gBAAgB,GAAG,MAAM,IAAI,CAAC,GAAG;;EAKvD,WAAW;GACT,QAAQ,EACN,IAAI;IACF,SAAS,CAAC,aAAa;IAIvB,SAAS;KACP;KACA;KACA;KACA;KACD;IACF,EACF;GACD,MAAM,QAAQ,MAAM,IAAI;AACtB,QACE,cAAc,mBACd,EAAE,cAAc,gBAAgB,MAAM,GAAG,IAAI,MAE7C;AAGF,QAAI,GAAG,SAAS,OAAO,CACrB,MAAK,GAAG,QAAQ,UAAU,GAAG;AAE/B,WAAO,2BAA2B,MAAM,GAAG;;GAE9C;EACF"}
|