@analogjs/vite-plugin-angular 3.0.0-alpha.36 → 3.0.0-alpha.38
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/README.md +22 -0
- package/package.json +3 -4
- package/src/lib/angular-jit-plugin.js +3 -0
- package/src/lib/angular-jit-plugin.js.map +1 -1
- package/src/lib/angular-vite-plugin.d.ts +12 -7
- package/src/lib/angular-vite-plugin.js +7 -5
- package/src/lib/angular-vite-plugin.js.map +1 -1
- package/src/lib/compiler/angular-version.d.ts +19 -0
- package/src/lib/compiler/angular-version.js +16 -0
- package/src/lib/compiler/angular-version.js.map +1 -0
- package/src/lib/compiler/class-field-lowering.d.ts +23 -0
- package/src/lib/compiler/class-field-lowering.js +131 -0
- package/src/lib/compiler/class-field-lowering.js.map +1 -0
- package/src/lib/compiler/compile.d.ts +44 -0
- package/src/lib/compiler/compile.js +731 -0
- package/src/lib/compiler/compile.js.map +1 -0
- package/src/lib/compiler/constants.d.ts +18 -0
- package/src/lib/compiler/constants.js +52 -0
- package/src/lib/compiler/constants.js.map +1 -0
- package/src/lib/compiler/debug.d.ts +22 -0
- package/src/lib/compiler/debug.js +20 -0
- package/src/lib/compiler/debug.js.map +1 -0
- package/src/lib/compiler/defer.d.ts +47 -0
- package/src/lib/compiler/defer.js +138 -0
- package/src/lib/compiler/defer.js.map +1 -0
- package/src/lib/compiler/dts-reader.d.ts +35 -0
- package/src/lib/compiler/dts-reader.js +365 -0
- package/src/lib/compiler/dts-reader.js.map +1 -0
- package/src/lib/compiler/hmr.d.ts +16 -0
- package/src/lib/compiler/hmr.js +69 -0
- package/src/lib/compiler/hmr.js.map +1 -0
- package/src/lib/compiler/index.d.ts +7 -0
- package/src/lib/compiler/index.js +7 -0
- package/src/lib/compiler/jit-metadata.d.ts +14 -0
- package/src/lib/compiler/jit-metadata.js +146 -0
- package/src/lib/compiler/jit-metadata.js.map +1 -0
- package/src/lib/compiler/jit-transform.d.ts +24 -0
- package/src/lib/compiler/jit-transform.js +200 -0
- package/src/lib/compiler/jit-transform.js.map +1 -0
- package/src/lib/compiler/js-emitter.d.ts +10 -0
- package/src/lib/compiler/js-emitter.js +420 -0
- package/src/lib/compiler/js-emitter.js.map +1 -0
- package/src/lib/compiler/metadata.d.ts +45 -0
- package/src/lib/compiler/metadata.js +633 -0
- package/src/lib/compiler/metadata.js.map +1 -0
- package/src/lib/compiler/registry.d.ts +49 -0
- package/src/lib/compiler/registry.js +164 -0
- package/src/lib/compiler/registry.js.map +1 -0
- package/src/lib/compiler/resource-inliner.d.ts +21 -0
- package/src/lib/compiler/resource-inliner.js +152 -0
- package/src/lib/compiler/resource-inliner.js.map +1 -0
- package/src/lib/compiler/style-ast.d.ts +8 -0
- package/src/lib/compiler/style-ast.js +54 -0
- package/src/lib/compiler/style-ast.js.map +1 -0
- package/src/lib/compiler/styles.d.ts +13 -0
- package/src/lib/compiler/test-helpers.d.ts +7 -0
- package/src/lib/compiler/type-elision.d.ts +26 -0
- package/src/lib/compiler/type-elision.js +211 -0
- package/src/lib/compiler/type-elision.js.map +1 -0
- package/src/lib/compiler/utils.d.ts +10 -0
- package/src/lib/compiler/utils.js +35 -0
- package/src/lib/compiler/utils.js.map +1 -0
- package/src/lib/{analog-compiler-plugin.d.ts → fast-compile-plugin.d.ts} +3 -3
- package/src/lib/{analog-compiler-plugin.js → fast-compile-plugin.js} +46 -33
- package/src/lib/fast-compile-plugin.js.map +1 -0
- package/src/lib/utils/virtual-resources.d.ts +16 -0
- package/src/lib/utils/virtual-resources.js +31 -2
- package/src/lib/utils/virtual-resources.js.map +1 -1
- package/src/lib/analog-compiler-plugin.js.map +0 -1
|
@@ -0,0 +1,633 @@
|
|
|
1
|
+
import { SIGNAL_APIS } from "./constants.js";
|
|
2
|
+
import { unwrapForwardRefOxc } from "./utils.js";
|
|
3
|
+
import * as o from "@angular/compiler";
|
|
4
|
+
//#region packages/vite-plugin-angular/src/lib/compiler/metadata.ts
|
|
5
|
+
function getCallApi(call) {
|
|
6
|
+
const callee = call.callee;
|
|
7
|
+
if (!callee) return null;
|
|
8
|
+
if (callee.type === "Identifier") return {
|
|
9
|
+
api: callee.name,
|
|
10
|
+
required: false
|
|
11
|
+
};
|
|
12
|
+
if ((callee.type === "StaticMemberExpression" || callee.type === "MemberExpression") && callee.object?.type === "Identifier" && callee.property?.name === "required") return {
|
|
13
|
+
api: callee.object.name,
|
|
14
|
+
required: true
|
|
15
|
+
};
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Extract the string value from an OXC string literal or template literal node.
|
|
20
|
+
*
|
|
21
|
+
* If `consts` is provided, interpolated template literals (e.g.
|
|
22
|
+
* `\`hello ${NAME}\``) are resolved when every `${...}` expression is a bare
|
|
23
|
+
* `Identifier` whose name is present in the map. This lets metadata fields
|
|
24
|
+
* such as `template:` reference module-level string constants via JS
|
|
25
|
+
* template-literal interpolation:
|
|
26
|
+
*
|
|
27
|
+
* const tw = `text-zinc-700 hover:text-zinc-900`;
|
|
28
|
+
* @Component({ template: `<a class="${tw}">x</a>` })
|
|
29
|
+
*
|
|
30
|
+
* Returns `null` if the node is not statically resolvable.
|
|
31
|
+
*/
|
|
32
|
+
function stringValue(node, consts) {
|
|
33
|
+
if (node?.type === "StringLiteral") return node.value;
|
|
34
|
+
if (node?.type === "Literal" && typeof node.value === "string") return node.value;
|
|
35
|
+
if (node?.type === "TemplateLiteral") {
|
|
36
|
+
const quasis = node.quasis ?? [];
|
|
37
|
+
const expressions = node.expressions ?? [];
|
|
38
|
+
if (expressions.length === 0) return quasis[0]?.value?.cooked ?? null;
|
|
39
|
+
if (!consts) return null;
|
|
40
|
+
let result = "";
|
|
41
|
+
for (let i = 0; i < quasis.length; i++) {
|
|
42
|
+
const cooked = quasis[i]?.value?.cooked;
|
|
43
|
+
if (cooked == null) return null;
|
|
44
|
+
result += cooked;
|
|
45
|
+
if (i < expressions.length) {
|
|
46
|
+
const expr = expressions[i];
|
|
47
|
+
if (expr?.type !== "Identifier") return null;
|
|
48
|
+
const resolved = consts.get(expr.name);
|
|
49
|
+
if (resolved == null) return null;
|
|
50
|
+
result += resolved;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Walk the top-level statements of an OXC program and collect a map of
|
|
59
|
+
* statically-resolvable string-valued `const NAME = ...` declarations.
|
|
60
|
+
*
|
|
61
|
+
* Used so decorator metadata fields like `template:` can reference
|
|
62
|
+
* module-level Tailwind class chains (or any other string constants) via
|
|
63
|
+
* JS template-literal interpolation. Resolution is iterative: a const may
|
|
64
|
+
* reference earlier-resolved consts via `${other}` interpolation.
|
|
65
|
+
*
|
|
66
|
+
* Only `const` declarations are considered. Non-string initializers,
|
|
67
|
+
* function calls, member access, and any expression that cannot be reduced
|
|
68
|
+
* to a string at parse time are ignored.
|
|
69
|
+
*/
|
|
70
|
+
function collectStringConstants(oxcProgram) {
|
|
71
|
+
const rawDecls = /* @__PURE__ */ new Map();
|
|
72
|
+
for (const stmt of oxcProgram?.body || []) {
|
|
73
|
+
const decl = stmt.type === "ExportNamedDeclaration" ? stmt.declaration : stmt;
|
|
74
|
+
if (!decl || decl.type !== "VariableDeclaration" || decl.kind !== "const") continue;
|
|
75
|
+
for (const d of decl.declarations || []) if (d.id?.type === "Identifier" && d.init) rawDecls.set(d.id.name, d.init);
|
|
76
|
+
}
|
|
77
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
78
|
+
for (let pass = 0; pass < rawDecls.size + 1; pass++) {
|
|
79
|
+
let progress = false;
|
|
80
|
+
for (const [name, init] of rawDecls) {
|
|
81
|
+
if (resolved.has(name)) continue;
|
|
82
|
+
const value = stringValue(init, resolved);
|
|
83
|
+
if (value !== null) {
|
|
84
|
+
resolved.set(name, value);
|
|
85
|
+
progress = true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!progress) break;
|
|
89
|
+
}
|
|
90
|
+
return resolved;
|
|
91
|
+
}
|
|
92
|
+
/** Get the property key name from an OXC object property. */
|
|
93
|
+
function propKeyName(prop) {
|
|
94
|
+
if (!prop.key) return null;
|
|
95
|
+
return prop.key.name ?? prop.key.value ?? null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Extract decorator metadata from an OXC decorator AST node.
|
|
99
|
+
* Parses @Component, @Directive, @Pipe, @Injectable, @NgModule arguments.
|
|
100
|
+
*
|
|
101
|
+
* `stringConsts`, when provided, lets string-typed metadata fields
|
|
102
|
+
* (`template`, `selector`, `templateUrl`, `styles`, `styleUrl`, `styleUrls`,
|
|
103
|
+
* `name`, `exportAs`, `providedIn`) resolve module-level string constants
|
|
104
|
+
* referenced via template-literal interpolation, e.g.
|
|
105
|
+
* `template: \`<div class="${tw}">x</div>\``.
|
|
106
|
+
*/
|
|
107
|
+
function extractMetadata(dec, sourceCode, stringConsts) {
|
|
108
|
+
if (!dec) return null;
|
|
109
|
+
const call = dec.expression;
|
|
110
|
+
if (!call || call.type !== "CallExpression") return null;
|
|
111
|
+
const arg = call.arguments?.[0];
|
|
112
|
+
const meta = {
|
|
113
|
+
hostRaw: {},
|
|
114
|
+
inputs: {},
|
|
115
|
+
outputs: {},
|
|
116
|
+
standalone: true,
|
|
117
|
+
imports: [],
|
|
118
|
+
providers: null,
|
|
119
|
+
viewProviders: null,
|
|
120
|
+
animations: null,
|
|
121
|
+
changeDetection: null,
|
|
122
|
+
encapsulation: null,
|
|
123
|
+
preserveWhitespaces: false,
|
|
124
|
+
exportAs: null,
|
|
125
|
+
selector: void 0,
|
|
126
|
+
styles: [],
|
|
127
|
+
templateUrl: null,
|
|
128
|
+
styleUrls: []
|
|
129
|
+
};
|
|
130
|
+
if (!arg || arg.type !== "ObjectExpression") return meta;
|
|
131
|
+
for (const p of arg.properties || []) {
|
|
132
|
+
if (p.type !== "ObjectProperty" && p.type !== "Property") continue;
|
|
133
|
+
const key = propKeyName(p);
|
|
134
|
+
if (!key) continue;
|
|
135
|
+
const valNode = p.value;
|
|
136
|
+
const valText = sourceCode.slice(valNode.start, valNode.end);
|
|
137
|
+
switch (key) {
|
|
138
|
+
case "host":
|
|
139
|
+
if (valNode.type === "ObjectExpression") for (const hp of valNode.properties || []) {
|
|
140
|
+
if (hp.type !== "ObjectProperty" && hp.type !== "Property") continue;
|
|
141
|
+
const hKey = propKeyName(hp);
|
|
142
|
+
if (!hKey) continue;
|
|
143
|
+
const sv = stringValue(hp.value, stringConsts);
|
|
144
|
+
const hVal = sv !== null ? sv : sourceCode.slice(hp.value.start, hp.value.end).replace(/^['"`]|['"`]$/g, "");
|
|
145
|
+
meta.hostRaw[hKey.replace(/^['"`]|['"`]$/g, "")] = hVal;
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
case "changeDetection":
|
|
149
|
+
meta.changeDetection = valText.includes("OnPush") ? 0 : 1;
|
|
150
|
+
break;
|
|
151
|
+
case "encapsulation":
|
|
152
|
+
meta.encapsulation = valText.includes("None") ? 2 : valText.includes("ShadowDom") ? 3 : 0;
|
|
153
|
+
break;
|
|
154
|
+
case "preserveWhitespaces":
|
|
155
|
+
meta.preserveWhitespaces = valText === "true";
|
|
156
|
+
break;
|
|
157
|
+
case "pure":
|
|
158
|
+
case "standalone":
|
|
159
|
+
meta[key] = valText !== "false";
|
|
160
|
+
break;
|
|
161
|
+
case "template":
|
|
162
|
+
case "selector":
|
|
163
|
+
case "name":
|
|
164
|
+
case "exportAs":
|
|
165
|
+
case "templateUrl":
|
|
166
|
+
case "providedIn": {
|
|
167
|
+
const sv = stringValue(valNode, stringConsts);
|
|
168
|
+
if (sv !== null) meta[key] = sv;
|
|
169
|
+
else if (valNode.type === "TemplateLiteral") {
|
|
170
|
+
const quasis = valNode.quasis ?? [];
|
|
171
|
+
const expressions = valNode.expressions ?? [];
|
|
172
|
+
let result = "";
|
|
173
|
+
for (let i = 0; i < quasis.length; i++) {
|
|
174
|
+
result += quasis[i]?.value?.cooked ?? "";
|
|
175
|
+
if (i < expressions.length) {
|
|
176
|
+
const expr = expressions[i];
|
|
177
|
+
if (expr?.type === "Identifier") {
|
|
178
|
+
const resolved = stringConsts?.get(expr.name);
|
|
179
|
+
if (resolved != null) {
|
|
180
|
+
result += resolved;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
meta[key] = result;
|
|
187
|
+
} else meta[key] = valText.replace(/^['"`]|['"`]$/g, "");
|
|
188
|
+
if (key === "exportAs") meta.exportAs = [meta.exportAs];
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
case "styleUrl": {
|
|
192
|
+
const sv = stringValue(valNode, stringConsts);
|
|
193
|
+
meta.styleUrls = [sv !== null ? sv : valText.replace(/['"`]/g, "")];
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case "styleUrls":
|
|
197
|
+
if (valNode.type === "ArrayExpression") meta.styleUrls = (valNode.elements || []).map((e) => {
|
|
198
|
+
const sv = stringValue(e, stringConsts);
|
|
199
|
+
return sv !== null ? sv : sourceCode.slice(e.start, e.end).replace(/['"`]/g, "");
|
|
200
|
+
});
|
|
201
|
+
break;
|
|
202
|
+
case "styles":
|
|
203
|
+
if (valNode.type === "ArrayExpression") meta.styles = (valNode.elements || []).map((e) => {
|
|
204
|
+
const sv = stringValue(e, stringConsts);
|
|
205
|
+
return sv !== null ? sv : sourceCode.slice(e.start, e.end).replace(/['"`]/g, "");
|
|
206
|
+
});
|
|
207
|
+
else {
|
|
208
|
+
const sv = stringValue(valNode, stringConsts);
|
|
209
|
+
if (sv !== null) meta.styles = [sv];
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
case "imports":
|
|
213
|
+
case "providers":
|
|
214
|
+
case "viewProviders":
|
|
215
|
+
case "animations":
|
|
216
|
+
case "rawImports":
|
|
217
|
+
case "declarations":
|
|
218
|
+
case "exports":
|
|
219
|
+
case "bootstrap":
|
|
220
|
+
if (valNode.type === "ArrayExpression") meta[key] = (valNode.elements || []).map((e) => new o.WrappedNodeExpr(unwrapForwardRefOxc(e)));
|
|
221
|
+
break;
|
|
222
|
+
case "useClass":
|
|
223
|
+
case "useExisting":
|
|
224
|
+
case "useValue": {
|
|
225
|
+
const unwrapped = unwrapForwardRefOxc(valNode);
|
|
226
|
+
const isForwardRef = valNode.type === "CallExpression" && unwrapped !== valNode;
|
|
227
|
+
meta[key] = {
|
|
228
|
+
expression: new o.WrappedNodeExpr(unwrapped),
|
|
229
|
+
forwardRef: isForwardRef ? 2 : 0
|
|
230
|
+
};
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
case "useFactory":
|
|
234
|
+
meta[key] = new o.WrappedNodeExpr(valNode);
|
|
235
|
+
break;
|
|
236
|
+
case "hostDirectives":
|
|
237
|
+
if (valNode.type === "ArrayExpression") meta.hostDirectives = (valNode.elements || []).map((el) => {
|
|
238
|
+
if (el.type === "Identifier" || el.type === "CallExpression") {
|
|
239
|
+
const unwrapped = unwrapForwardRefOxc(el);
|
|
240
|
+
return {
|
|
241
|
+
directive: {
|
|
242
|
+
value: new o.WrappedNodeExpr(unwrapped),
|
|
243
|
+
type: new o.WrappedNodeExpr(unwrapped)
|
|
244
|
+
},
|
|
245
|
+
isForwardReference: el.type === "CallExpression",
|
|
246
|
+
inputs: null,
|
|
247
|
+
outputs: null
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
if (el.type === "ObjectExpression") {
|
|
251
|
+
let directiveNode = null;
|
|
252
|
+
let isForwardRef = false;
|
|
253
|
+
let inputs = null;
|
|
254
|
+
let outputs = null;
|
|
255
|
+
for (const prop of el.properties || []) {
|
|
256
|
+
if (prop.type !== "ObjectProperty" && prop.type !== "Property") continue;
|
|
257
|
+
const pName = propKeyName(prop);
|
|
258
|
+
if (pName === "directive") {
|
|
259
|
+
directiveNode = unwrapForwardRefOxc(prop.value);
|
|
260
|
+
isForwardRef = prop.value?.type === "CallExpression" && sourceCode.slice(prop.value.start, prop.value.end).includes("forwardRef");
|
|
261
|
+
} else if (pName === "inputs" && prop.value?.type === "ArrayExpression") {
|
|
262
|
+
inputs = {};
|
|
263
|
+
for (const e of prop.value.elements || []) {
|
|
264
|
+
const sv = stringValue(e);
|
|
265
|
+
if (sv !== null) {
|
|
266
|
+
const [source, alias = source] = sv.split(":").map((part) => part.trim());
|
|
267
|
+
if (source) inputs[source] = alias;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
} else if (pName === "outputs" && prop.value?.type === "ArrayExpression") {
|
|
271
|
+
outputs = {};
|
|
272
|
+
for (const e of prop.value.elements || []) {
|
|
273
|
+
const sv = stringValue(e);
|
|
274
|
+
if (sv !== null) {
|
|
275
|
+
const [source, alias = source] = sv.split(":").map((part) => part.trim());
|
|
276
|
+
if (source) outputs[source] = alias;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (directiveNode) return {
|
|
282
|
+
directive: {
|
|
283
|
+
value: new o.WrappedNodeExpr(directiveNode),
|
|
284
|
+
type: new o.WrappedNodeExpr(directiveNode)
|
|
285
|
+
},
|
|
286
|
+
isForwardReference: isForwardRef,
|
|
287
|
+
inputs,
|
|
288
|
+
outputs
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
return null;
|
|
292
|
+
}).filter(Boolean);
|
|
293
|
+
break;
|
|
294
|
+
default: meta[key] = valText.replace(/['"`]/g, "");
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return meta;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Detect signal-based APIs on class members: input(), model(), output(),
|
|
301
|
+
* viewChild(), contentChild(), viewChildren(), contentChildren().
|
|
302
|
+
*/
|
|
303
|
+
function detectSignals(classNode, sourceCode) {
|
|
304
|
+
const inputs = {}, outputs = {}, viewQueries = [], contentQueries = [];
|
|
305
|
+
const members = classNode.body?.body || [];
|
|
306
|
+
for (const m of members) {
|
|
307
|
+
if (m.type !== "PropertyDefinition" || !m.key?.name || !m.value || m.value.type !== "CallExpression") continue;
|
|
308
|
+
const name = m.key.name;
|
|
309
|
+
const signalCall = getCallApi(m.value);
|
|
310
|
+
if (!signalCall) continue;
|
|
311
|
+
const { api, required } = signalCall;
|
|
312
|
+
if (!SIGNAL_APIS.has(api)) continue;
|
|
313
|
+
const args = m.value.arguments || [];
|
|
314
|
+
if (api === "input") {
|
|
315
|
+
let transform = null;
|
|
316
|
+
let alias = null;
|
|
317
|
+
const optionsArg = required ? args[0] : args[1];
|
|
318
|
+
if (optionsArg?.type === "ObjectExpression") for (const prop of optionsArg.properties || []) {
|
|
319
|
+
if (prop.type !== "ObjectProperty" && prop.type !== "Property") continue;
|
|
320
|
+
const k = propKeyName(prop);
|
|
321
|
+
if (k === "transform") transform = new o.WrappedNodeExpr(prop.value);
|
|
322
|
+
else if (k === "alias") {
|
|
323
|
+
const sv = stringValue(prop.value);
|
|
324
|
+
if (sv !== null) alias = sv;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
inputs[name] = {
|
|
328
|
+
classPropertyName: name,
|
|
329
|
+
bindingPropertyName: alias ?? name,
|
|
330
|
+
isSignal: true,
|
|
331
|
+
required,
|
|
332
|
+
transform
|
|
333
|
+
};
|
|
334
|
+
} else if (api === "model") {
|
|
335
|
+
let alias = null;
|
|
336
|
+
const optionsArg = required ? args[0] : args[1];
|
|
337
|
+
if (optionsArg?.type === "ObjectExpression") for (const prop of optionsArg.properties || []) {
|
|
338
|
+
if (prop.type !== "ObjectProperty" && prop.type !== "Property") continue;
|
|
339
|
+
if (propKeyName(prop) === "alias") {
|
|
340
|
+
const sv = stringValue(prop.value);
|
|
341
|
+
if (sv !== null) alias = sv;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
inputs[name] = {
|
|
345
|
+
classPropertyName: name,
|
|
346
|
+
bindingPropertyName: alias ?? name,
|
|
347
|
+
isSignal: true
|
|
348
|
+
};
|
|
349
|
+
outputs[name] = (alias ?? name) + "Change";
|
|
350
|
+
} else if (api === "viewChild" || api === "viewChildren" || api === "contentChild" || api === "contentChildren") {
|
|
351
|
+
const isViewQuery = api === "viewChild" || api === "viewChildren";
|
|
352
|
+
const isChildrenQuery = api === "viewChildren" || api === "contentChildren";
|
|
353
|
+
const firstArg = args[0];
|
|
354
|
+
const sv = stringValue(firstArg);
|
|
355
|
+
let read = null;
|
|
356
|
+
let descendants = isViewQuery || !isChildrenQuery;
|
|
357
|
+
const optArg = args[1];
|
|
358
|
+
if (optArg?.type === "ObjectExpression") for (const prop of optArg.properties || []) {
|
|
359
|
+
if (prop.type !== "ObjectProperty" && prop.type !== "Property") continue;
|
|
360
|
+
const k = propKeyName(prop);
|
|
361
|
+
if (k === "read") read = new o.WrappedNodeExpr(unwrapForwardRefOxc(prop.value));
|
|
362
|
+
else if (k === "descendants") {
|
|
363
|
+
const t = prop.value?.type;
|
|
364
|
+
if (t === "BooleanLiteral" || t === "Literal" && typeof prop.value.value === "boolean") descendants = prop.value.value;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const query = {
|
|
368
|
+
propertyName: name,
|
|
369
|
+
predicate: sv !== null ? [sv] : {
|
|
370
|
+
forwardRef: 0,
|
|
371
|
+
expression: new o.WrappedNodeExpr(firstArg)
|
|
372
|
+
},
|
|
373
|
+
first: !isChildrenQuery,
|
|
374
|
+
descendants,
|
|
375
|
+
read,
|
|
376
|
+
static: false,
|
|
377
|
+
emitFlags: 0,
|
|
378
|
+
isSignal: true
|
|
379
|
+
};
|
|
380
|
+
if (isViewQuery) viewQueries.push(query);
|
|
381
|
+
else contentQueries.push(query);
|
|
382
|
+
} else if (api === "output" || api === "outputFromObservable") {
|
|
383
|
+
let alias = name;
|
|
384
|
+
const optArg = args[0];
|
|
385
|
+
if (optArg?.type === "ObjectExpression") {
|
|
386
|
+
for (const prop of optArg.properties || []) if ((prop.type === "ObjectProperty" || prop.type === "Property") && propKeyName(prop) === "alias") {
|
|
387
|
+
const sv = stringValue(prop.value);
|
|
388
|
+
if (sv !== null) alias = sv;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
outputs[name] = alias;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
inputs,
|
|
396
|
+
outputs,
|
|
397
|
+
viewQueries,
|
|
398
|
+
contentQueries
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Detect decorator-based field metadata: @Input, @Output, @ViewChild,
|
|
403
|
+
* @ContentChild, @ViewChildren, @ContentChildren, @HostBinding, @HostListener.
|
|
404
|
+
*/
|
|
405
|
+
function detectFieldDecorators(classNode, sourceCode) {
|
|
406
|
+
const inputs = {};
|
|
407
|
+
const outputs = {};
|
|
408
|
+
const viewQueries = [];
|
|
409
|
+
const contentQueries = [];
|
|
410
|
+
const hostProperties = {};
|
|
411
|
+
const hostListeners = {};
|
|
412
|
+
const members = classNode.body?.body || [];
|
|
413
|
+
for (const member of members) {
|
|
414
|
+
const decorators = member.decorators || [];
|
|
415
|
+
if (decorators.length === 0) continue;
|
|
416
|
+
const memberName = member.key?.name || "";
|
|
417
|
+
for (const dec of decorators) {
|
|
418
|
+
const expr = dec.expression;
|
|
419
|
+
if (!expr || expr.type !== "CallExpression") continue;
|
|
420
|
+
const decName = expr.callee?.name;
|
|
421
|
+
if (!decName) continue;
|
|
422
|
+
const args = expr.arguments || [];
|
|
423
|
+
switch (decName) {
|
|
424
|
+
case "Input": {
|
|
425
|
+
let bindingName = memberName;
|
|
426
|
+
let required = false;
|
|
427
|
+
let transformFunction = null;
|
|
428
|
+
if (args.length > 0) {
|
|
429
|
+
const arg = args[0];
|
|
430
|
+
const sv = stringValue(arg);
|
|
431
|
+
if (sv !== null) bindingName = sv;
|
|
432
|
+
else if (arg.type === "ObjectExpression") for (const prop of arg.properties || []) {
|
|
433
|
+
if (prop.type !== "ObjectProperty" && prop.type !== "Property") continue;
|
|
434
|
+
const k = propKeyName(prop);
|
|
435
|
+
if (k === "alias") {
|
|
436
|
+
const asv = stringValue(prop.value);
|
|
437
|
+
if (asv !== null) bindingName = asv;
|
|
438
|
+
}
|
|
439
|
+
if (k === "required") required = sourceCode.slice(prop.value.start, prop.value.end) === "true";
|
|
440
|
+
if (k === "transform") transformFunction = new o.WrappedNodeExpr(prop.value);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
inputs[memberName] = {
|
|
444
|
+
classPropertyName: memberName,
|
|
445
|
+
bindingPropertyName: bindingName,
|
|
446
|
+
isSignal: false,
|
|
447
|
+
required,
|
|
448
|
+
transformFunction
|
|
449
|
+
};
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
case "Output": {
|
|
453
|
+
const sv = args.length > 0 ? stringValue(args[0]) : null;
|
|
454
|
+
outputs[memberName] = sv !== null ? sv : memberName;
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
case "ViewChild":
|
|
458
|
+
case "ViewChildren":
|
|
459
|
+
case "ContentChild":
|
|
460
|
+
case "ContentChildren": {
|
|
461
|
+
const isView = decName.startsWith("View");
|
|
462
|
+
const isFirst = decName === "ViewChild" || decName === "ContentChild";
|
|
463
|
+
let predicate = [memberName];
|
|
464
|
+
if (args.length > 0) {
|
|
465
|
+
const pred = args[0];
|
|
466
|
+
const sv = stringValue(pred);
|
|
467
|
+
if (sv !== null) predicate = [sv];
|
|
468
|
+
else predicate = {
|
|
469
|
+
forwardRef: 0,
|
|
470
|
+
expression: new o.WrappedNodeExpr(unwrapForwardRefOxc(pred))
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
let read = null;
|
|
474
|
+
let isStatic = false;
|
|
475
|
+
let descendants = isView || isFirst;
|
|
476
|
+
if (args.length > 1 && args[1]?.type === "ObjectExpression") for (const prop of args[1].properties || []) {
|
|
477
|
+
if (prop.type !== "ObjectProperty" && prop.type !== "Property") continue;
|
|
478
|
+
const k = propKeyName(prop);
|
|
479
|
+
if (k === "read") read = new o.WrappedNodeExpr(prop.value);
|
|
480
|
+
if (k === "static") isStatic = sourceCode.slice(prop.value.start, prop.value.end) === "true";
|
|
481
|
+
if (k === "descendants") descendants = sourceCode.slice(prop.value.start, prop.value.end) === "true";
|
|
482
|
+
}
|
|
483
|
+
const query = {
|
|
484
|
+
propertyName: memberName,
|
|
485
|
+
predicate,
|
|
486
|
+
first: isFirst,
|
|
487
|
+
descendants,
|
|
488
|
+
read,
|
|
489
|
+
static: isStatic,
|
|
490
|
+
emitFlags: 0,
|
|
491
|
+
isSignal: false
|
|
492
|
+
};
|
|
493
|
+
if (isView) viewQueries.push(query);
|
|
494
|
+
else contentQueries.push(query);
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
case "HostBinding": {
|
|
498
|
+
const sv = args.length > 0 ? stringValue(args[0]) : null;
|
|
499
|
+
const target = sv !== null ? sv : memberName;
|
|
500
|
+
hostProperties[target] = memberName;
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
case "HostListener": {
|
|
504
|
+
const sv = args.length > 0 ? stringValue(args[0]) : null;
|
|
505
|
+
if (sv !== null) {
|
|
506
|
+
const event = sv;
|
|
507
|
+
let handler = `${memberName}()`;
|
|
508
|
+
if (args.length > 1 && args[1]?.type === "ArrayExpression") handler = `${memberName}(${(args[1].elements || []).map((e) => stringValue(e)).filter((v) => v !== null).join(", ")})`;
|
|
509
|
+
hostListeners[event] = handler;
|
|
510
|
+
}
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return {
|
|
517
|
+
inputs,
|
|
518
|
+
outputs,
|
|
519
|
+
viewQueries,
|
|
520
|
+
contentQueries,
|
|
521
|
+
hostProperties,
|
|
522
|
+
hostListeners
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Analyze constructor parameters for dependency injection.
|
|
527
|
+
* Returns:
|
|
528
|
+
* - R3DependencyMetadata[] for normal constructors
|
|
529
|
+
* - null if class extends another without own constructor (use inherited factory)
|
|
530
|
+
* - 'invalid' if any parameter has a type-only import token
|
|
531
|
+
*
|
|
532
|
+
* Accepts an OXC ClassDeclaration node and the original source string.
|
|
533
|
+
*/
|
|
534
|
+
function extractConstructorDeps(classNode, sourceCode, typeOnlyImports) {
|
|
535
|
+
const hasSuper = (classNode.superClass ? [classNode.superClass] : []).length > 0;
|
|
536
|
+
const ctor = (classNode.body?.body || []).find((m) => m.type === "MethodDefinition" && m.kind === "constructor");
|
|
537
|
+
if (!ctor) return hasSuper ? null : [];
|
|
538
|
+
const params = ctor.value?.params?.items || ctor.value?.params || [];
|
|
539
|
+
const deps = [];
|
|
540
|
+
let invalid = false;
|
|
541
|
+
for (const param of params) {
|
|
542
|
+
let token = null;
|
|
543
|
+
let attributeNameType = null;
|
|
544
|
+
let host = false, optional = false, self = false, skipSelf = false;
|
|
545
|
+
const actualParam = param.type === "TSParameterProperty" ? param.parameter : param;
|
|
546
|
+
const typeAnn = actualParam?.typeAnnotation?.typeAnnotation ?? param?.typeAnnotation?.typeAnnotation;
|
|
547
|
+
if (typeAnn) {
|
|
548
|
+
if (typeAnn.type === "TSTypeReference" && typeAnn.typeName) token = typeAnn.typeName.name ?? sourceCode.slice(typeAnn.typeName.start, typeAnn.typeName.end);
|
|
549
|
+
else if (typeAnn.type === "TSUnionType") {
|
|
550
|
+
const nonNullTypes = (typeAnn.types || []).filter((t) => {
|
|
551
|
+
if (!t) return false;
|
|
552
|
+
if (t.type === "TSNullKeyword") return false;
|
|
553
|
+
if (t.type === "TSUndefinedKeyword") return false;
|
|
554
|
+
if (t.type === "TSVoidKeyword") return false;
|
|
555
|
+
if (t.type === "TSLiteralType" && (t.literal?.type === "NullLiteral" || t.literal?.type === "Literal" && t.literal.value === null)) return false;
|
|
556
|
+
return true;
|
|
557
|
+
});
|
|
558
|
+
if (nonNullTypes.length === 1 && nonNullTypes[0].type === "TSTypeReference" && nonNullTypes[0].typeName) {
|
|
559
|
+
const t = nonNullTypes[0];
|
|
560
|
+
token = t.typeName.name ?? sourceCode.slice(t.typeName.start, t.typeName.end);
|
|
561
|
+
} else {
|
|
562
|
+
invalid = true;
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
} else if (typeAnn.type === "TSIntersectionType") {
|
|
566
|
+
invalid = true;
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const paramDecs = [...param.decorators || [], ...param.type === "TSParameterProperty" && actualParam?.decorators ? actualParam.decorators : []];
|
|
571
|
+
for (const dec of paramDecs) {
|
|
572
|
+
const expr = dec.expression;
|
|
573
|
+
if (!expr || expr.type !== "CallExpression") continue;
|
|
574
|
+
const decName = expr.callee?.name;
|
|
575
|
+
if (!decName) continue;
|
|
576
|
+
const args = expr.arguments || [];
|
|
577
|
+
switch (decName) {
|
|
578
|
+
case "Inject":
|
|
579
|
+
if (args.length > 0) {
|
|
580
|
+
const sv = stringValue(args[0]);
|
|
581
|
+
if (sv !== null) token = sv;
|
|
582
|
+
else {
|
|
583
|
+
const unwrapped = unwrapForwardRefOxc(args[0]);
|
|
584
|
+
token = sourceCode.slice(unwrapped.start, unwrapped.end);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
break;
|
|
588
|
+
case "Optional":
|
|
589
|
+
optional = true;
|
|
590
|
+
break;
|
|
591
|
+
case "Self":
|
|
592
|
+
self = true;
|
|
593
|
+
break;
|
|
594
|
+
case "SkipSelf":
|
|
595
|
+
skipSelf = true;
|
|
596
|
+
break;
|
|
597
|
+
case "Host":
|
|
598
|
+
host = true;
|
|
599
|
+
break;
|
|
600
|
+
case "Attribute":
|
|
601
|
+
if (args.length > 0) {
|
|
602
|
+
const sv = stringValue(args[0]);
|
|
603
|
+
if (sv !== null) {
|
|
604
|
+
attributeNameType = new o.LiteralExpr(sv);
|
|
605
|
+
token = "";
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
break;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (!token && !attributeNameType) {
|
|
612
|
+
invalid = true;
|
|
613
|
+
continue;
|
|
614
|
+
}
|
|
615
|
+
if (token && typeOnlyImports.has(token)) {
|
|
616
|
+
invalid = true;
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
deps.push({
|
|
620
|
+
token: token ? new o.WrappedNodeExpr(token) : new o.LiteralExpr(null),
|
|
621
|
+
attributeNameType,
|
|
622
|
+
host,
|
|
623
|
+
optional,
|
|
624
|
+
self,
|
|
625
|
+
skipSelf
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
return invalid ? "invalid" : deps;
|
|
629
|
+
}
|
|
630
|
+
//#endregion
|
|
631
|
+
export { collectStringConstants, detectFieldDecorators, detectSignals, extractConstructorDeps, extractMetadata };
|
|
632
|
+
|
|
633
|
+
//# sourceMappingURL=metadata.js.map
|