@analogjs/vite-plugin-angular 3.0.0-alpha.8 → 3.0.0-alpha.81

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.
Files changed (194) hide show
  1. package/README.md +30 -0
  2. package/migrations/migrate-setup-vitest/migrate-setup-vitest.d.ts +2 -0
  3. package/migrations/migrate-setup-vitest/migrate-setup-vitest.js +49 -0
  4. package/migrations/migrate-setup-vitest/migrate-setup-vitest.js.map +1 -0
  5. package/migrations/migration.json +7 -1
  6. package/migrations/migrations.json +9 -0
  7. package/migrations/update-3-0-0/migrate-setup-vitest.d.ts +2 -0
  8. package/migrations/update-3-0-0/migrate-setup-vitest.js +36 -0
  9. package/migrations/update-3-0-0/migrate-setup-vitest.js.map +1 -0
  10. package/package.json +51 -14
  11. package/src/index.d.ts +6 -2
  12. package/src/index.js +6 -2
  13. package/src/index.js.map +1 -1
  14. package/src/lib/analog-plugin-interop.d.ts +78 -0
  15. package/src/lib/analog-plugin-interop.js +97 -0
  16. package/src/lib/analog-plugin-interop.js.map +1 -0
  17. package/src/lib/angular-build-optimizer-plugin.d.ts +4 -4
  18. package/src/lib/angular-build-optimizer-plugin.js +57 -63
  19. package/src/lib/angular-build-optimizer-plugin.js.map +1 -1
  20. package/src/lib/angular-jit-plugin.d.ts +3 -3
  21. package/src/lib/angular-jit-plugin.js +49 -37
  22. package/src/lib/angular-jit-plugin.js.map +1 -1
  23. package/src/lib/angular-pending-tasks.plugin.d.ts +7 -7
  24. package/src/lib/angular-pending-tasks.plugin.js +17 -18
  25. package/src/lib/angular-pending-tasks.plugin.js.map +1 -1
  26. package/src/lib/angular-vite-plugin.d.ts +82 -69
  27. package/src/lib/angular-vite-plugin.js +1201 -1085
  28. package/src/lib/angular-vite-plugin.js.map +1 -1
  29. package/src/lib/angular-vitest-plugin.d.ts +26 -21
  30. package/src/lib/angular-vitest-plugin.js +106 -135
  31. package/src/lib/angular-vitest-plugin.js.map +1 -1
  32. package/src/lib/compilation-api/compilation-api-plugin.d.ts +18 -0
  33. package/src/lib/compilation-api/compilation-api-plugin.js +488 -0
  34. package/src/lib/compilation-api/compilation-api-plugin.js.map +1 -0
  35. package/src/lib/compilation-api/index.d.ts +1 -0
  36. package/src/lib/compilation-api/index.js +1 -0
  37. package/src/lib/compiler/angular-version.d.ts +19 -0
  38. package/src/lib/compiler/angular-version.js +31 -0
  39. package/src/lib/compiler/angular-version.js.map +1 -0
  40. package/src/lib/compiler/class-field-lowering.d.ts +23 -0
  41. package/src/lib/compiler/class-field-lowering.js +131 -0
  42. package/src/lib/compiler/class-field-lowering.js.map +1 -0
  43. package/src/lib/compiler/compile.d.ts +50 -0
  44. package/src/lib/compiler/compile.js +814 -0
  45. package/src/lib/compiler/compile.js.map +1 -0
  46. package/src/lib/compiler/constants.d.ts +24 -0
  47. package/src/lib/compiler/constants.js +59 -0
  48. package/src/lib/compiler/constants.js.map +1 -0
  49. package/src/lib/compiler/debug.d.ts +22 -0
  50. package/src/lib/compiler/debug.js +20 -0
  51. package/src/lib/compiler/debug.js.map +1 -0
  52. package/src/lib/compiler/defer.d.ts +57 -0
  53. package/src/lib/compiler/defer.js +154 -0
  54. package/src/lib/compiler/defer.js.map +1 -0
  55. package/src/lib/compiler/dts-reader.d.ts +45 -0
  56. package/src/lib/compiler/dts-reader.js +395 -0
  57. package/src/lib/compiler/dts-reader.js.map +1 -0
  58. package/src/lib/compiler/hmr.d.ts +16 -0
  59. package/src/lib/compiler/hmr.js +69 -0
  60. package/src/lib/compiler/hmr.js.map +1 -0
  61. package/src/lib/compiler/index.d.ts +8 -0
  62. package/src/lib/compiler/index.js +8 -0
  63. package/src/lib/compiler/jit-metadata.d.ts +14 -0
  64. package/src/lib/compiler/jit-metadata.js +168 -0
  65. package/src/lib/compiler/jit-metadata.js.map +1 -0
  66. package/src/lib/compiler/jit-transform.d.ts +24 -0
  67. package/src/lib/compiler/jit-transform.js +204 -0
  68. package/src/lib/compiler/jit-transform.js.map +1 -0
  69. package/src/lib/compiler/js-emitter.d.ts +10 -0
  70. package/src/lib/compiler/js-emitter.js +446 -0
  71. package/src/lib/compiler/js-emitter.js.map +1 -0
  72. package/src/lib/compiler/metadata.d.ts +36 -0
  73. package/src/lib/compiler/metadata.js +710 -0
  74. package/src/lib/compiler/metadata.js.map +1 -0
  75. package/src/lib/compiler/registry.d.ts +56 -0
  76. package/src/lib/compiler/registry.js +176 -0
  77. package/src/lib/compiler/registry.js.map +1 -0
  78. package/src/lib/compiler/resource-inliner.d.ts +43 -0
  79. package/src/lib/compiler/resource-inliner.js +230 -0
  80. package/src/lib/compiler/resource-inliner.js.map +1 -0
  81. package/src/lib/compiler/style-ast.d.ts +9 -0
  82. package/src/lib/compiler/style-ast.js +54 -0
  83. package/src/lib/compiler/style-ast.js.map +1 -0
  84. package/src/lib/compiler/styles.d.ts +13 -0
  85. package/src/lib/compiler/test-helpers.d.ts +7 -0
  86. package/src/lib/compiler/type-elision.d.ts +28 -0
  87. package/src/lib/compiler/type-elision.js +211 -0
  88. package/src/lib/compiler/type-elision.js.map +1 -0
  89. package/src/lib/compiler/utils.d.ts +40 -0
  90. package/src/lib/compiler/utils.js +76 -0
  91. package/src/lib/compiler/utils.js.map +1 -0
  92. package/src/lib/compiler-plugin.d.ts +13 -12
  93. package/src/lib/compiler-plugin.js +40 -44
  94. package/src/lib/compiler-plugin.js.map +1 -1
  95. package/src/lib/component-resolvers.d.ts +20 -4
  96. package/src/lib/component-resolvers.js +101 -120
  97. package/src/lib/component-resolvers.js.map +1 -1
  98. package/src/lib/encapsulation-plugin.d.ts +18 -0
  99. package/src/lib/encapsulation-plugin.js +53 -0
  100. package/src/lib/encapsulation-plugin.js.map +1 -0
  101. package/src/lib/fast-compile-plugin.d.ts +13 -0
  102. package/src/lib/fast-compile-plugin.js +419 -0
  103. package/src/lib/fast-compile-plugin.js.map +1 -0
  104. package/src/lib/host.d.ts +10 -8
  105. package/src/lib/host.js +111 -101
  106. package/src/lib/host.js.map +1 -1
  107. package/src/lib/live-reload-plugin.d.ts +5 -5
  108. package/src/lib/live-reload-plugin.js +61 -63
  109. package/src/lib/live-reload-plugin.js.map +1 -1
  110. package/src/lib/models.d.ts +9 -9
  111. package/src/lib/nx-folder-plugin.d.ts +5 -5
  112. package/src/lib/nx-folder-plugin.js +18 -16
  113. package/src/lib/nx-folder-plugin.js.map +1 -1
  114. package/src/lib/plugins/file-replacements.plugin.d.ts +4 -4
  115. package/src/lib/plugins/file-replacements.plugin.js +40 -62
  116. package/src/lib/plugins/file-replacements.plugin.js.map +1 -1
  117. package/src/lib/router-plugin.d.ts +1 -1
  118. package/src/lib/router-plugin.js +35 -23
  119. package/src/lib/router-plugin.js.map +1 -1
  120. package/src/lib/style-preprocessor.d.ts +35 -0
  121. package/src/lib/style-preprocessor.js +35 -0
  122. package/src/lib/style-preprocessor.js.map +1 -0
  123. package/src/lib/stylesheet-registry.d.ts +74 -0
  124. package/src/lib/stylesheet-registry.js +174 -0
  125. package/src/lib/stylesheet-registry.js.map +1 -0
  126. package/src/lib/tools/package.json +2 -7
  127. package/src/lib/tools/src/builders/vite/vite-build.impl.js +33 -38
  128. package/src/lib/tools/src/builders/vite/vite-build.impl.js.map +1 -1
  129. package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.js +51 -62
  130. package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.js.map +1 -1
  131. package/src/lib/tools/src/index.js +0 -2
  132. package/src/lib/utils/compilation-shared.d.ts +62 -0
  133. package/src/lib/utils/compilation-shared.js +138 -0
  134. package/src/lib/utils/compilation-shared.js.map +1 -0
  135. package/src/lib/utils/compiler-plugin-options.d.ts +11 -11
  136. package/src/lib/utils/css-extension-resolver.d.ts +32 -0
  137. package/src/lib/utils/css-extension-resolver.js +73 -0
  138. package/src/lib/utils/css-extension-resolver.js.map +1 -0
  139. package/src/lib/utils/debug-harness.d.ts +23 -0
  140. package/src/lib/utils/debug-harness.js +88 -0
  141. package/src/lib/utils/debug-harness.js.map +1 -0
  142. package/src/lib/utils/debug-log-file.d.ts +5 -0
  143. package/src/lib/utils/debug-log-file.js +56 -0
  144. package/src/lib/utils/debug-log-file.js.map +1 -0
  145. package/src/lib/utils/debug.d.ts +26 -0
  146. package/src/lib/utils/debug.js +35 -0
  147. package/src/lib/utils/debug.js.map +1 -0
  148. package/src/lib/utils/devkit.d.ts +6 -6
  149. package/src/lib/utils/devkit.js +34 -38
  150. package/src/lib/utils/devkit.js.map +1 -1
  151. package/src/lib/utils/hmr-candidates.d.ts +28 -28
  152. package/src/lib/utils/jit-inline-styles.d.ts +3 -0
  153. package/src/lib/utils/jit-inline-styles.js +16 -0
  154. package/src/lib/utils/jit-inline-styles.js.map +1 -0
  155. package/src/lib/utils/plugin-config.d.ts +41 -0
  156. package/src/lib/utils/plugin-config.js +85 -0
  157. package/src/lib/utils/plugin-config.js.map +1 -0
  158. package/src/lib/utils/rolldown.d.ts +1 -1
  159. package/src/lib/utils/rolldown.js +9 -5
  160. package/src/lib/utils/rolldown.js.map +1 -1
  161. package/src/lib/utils/safe-module-paths.d.ts +16 -0
  162. package/src/lib/utils/safe-module-paths.js +29 -0
  163. package/src/lib/utils/safe-module-paths.js.map +1 -0
  164. package/src/lib/utils/source-file-cache.d.ts +8 -15
  165. package/src/lib/utils/source-file-cache.js +35 -37
  166. package/src/lib/utils/source-file-cache.js.map +1 -1
  167. package/src/lib/utils/transform-cache.d.ts +43 -0
  168. package/src/lib/utils/transform-cache.js +97 -0
  169. package/src/lib/utils/transform-cache.js.map +1 -0
  170. package/src/lib/utils/tsconfig-resolver.d.ts +34 -0
  171. package/src/lib/utils/tsconfig-resolver.js +203 -0
  172. package/src/lib/utils/tsconfig-resolver.js.map +1 -0
  173. package/src/lib/utils/virtual-ids.d.ts +4 -0
  174. package/src/lib/utils/virtual-ids.js +23 -0
  175. package/src/lib/utils/virtual-ids.js.map +1 -0
  176. package/src/lib/utils/virtual-resources.d.ts +19 -0
  177. package/src/lib/utils/virtual-resources.js +38 -0
  178. package/src/lib/utils/virtual-resources.js.map +1 -0
  179. package/src/lib/virtual-modules-plugin.d.ts +5 -0
  180. package/src/lib/virtual-modules-plugin.js +23 -0
  181. package/src/lib/virtual-modules-plugin.js.map +1 -0
  182. package/src/test-setup.d.ts +2 -0
  183. package/setup-vitest.d.ts +0 -4
  184. package/setup-vitest.js +0 -215
  185. package/setup-vitest.js.map +0 -1
  186. package/src/lib/models.js +0 -1
  187. package/src/lib/models.js.map +0 -1
  188. package/src/lib/tools/README.md +0 -3
  189. package/src/lib/tools/src/index.d.ts +0 -0
  190. package/src/lib/tools/src/index.js.map +0 -1
  191. package/src/lib/utils/compiler-plugin-options.js +0 -1
  192. package/src/lib/utils/compiler-plugin-options.js.map +0 -1
  193. package/src/lib/utils/hmr-candidates.js +0 -272
  194. package/src/lib/utils/hmr-candidates.js.map +0 -1
@@ -0,0 +1,230 @@
1
+ import { extractInlineStyles as extractInlineStyles$1 } from "./style-ast.js";
2
+ import * as fs from "node:fs";
3
+ import * as path$1 from "node:path";
4
+ import { parseSync } from "oxc-parser";
5
+ import MagicString from "magic-string";
6
+ //#region packages/vite-plugin-angular/src/lib/compiler/resource-inliner.ts
7
+ /** Whether a node is an inline style value (string literal or single-quasi template). */
8
+ function isInlineStyleValue(node) {
9
+ return node?.type === "Literal" && typeof node.value === "string" || node?.type === "TemplateLiteral" && node.quasis?.length === 1;
10
+ }
11
+ /** Count the elements of a `styles: [...]` array that {@link extractInlineStyles} would emit. */
12
+ function countInlineStyleLiterals(arrayExpr) {
13
+ let count = 0;
14
+ for (const el of arrayExpr.elements ?? []) if (el?.type === "Literal" && typeof el.value === "string") count++;
15
+ else if (el?.type === "TemplateLiteral" && el.quasis?.length === 1) count++;
16
+ return count;
17
+ }
18
+ /**
19
+ * Inline external templateUrl and styleUrl/styleUrls into the source code
20
+ * using OXC parser for precise AST-based rewriting.
21
+ *
22
+ * Replaces:
23
+ * templateUrl: './file.html' → template: "...file contents..."
24
+ * styleUrl: './file.scss' → styles: ["...file contents..."]
25
+ * styleUrls: ['./a.scss'] → styles: ["...contents..."]
26
+ *
27
+ * When the decorator already has a `styles: [...]` array, inlined CSS is
28
+ * merged into that existing array instead of emitting a second `styles`
29
+ * property (which would be a duplicate object literal key).
30
+ *
31
+ * Returns the modified source code plus the per-style-index extension map
32
+ * (see {@link InlineResourceResult}).
33
+ */
34
+ async function inlineResourceUrls(code, fileName) {
35
+ const styleExtensions = /* @__PURE__ */ new Map();
36
+ if (!code.includes("templateUrl") && !code.includes("styleUrl")) return {
37
+ code,
38
+ styleExtensions,
39
+ resourceDependencies: []
40
+ };
41
+ const { program } = parseSync(fileName, code);
42
+ const ms = new MagicString(code);
43
+ let changed = false;
44
+ const dir = path$1.dirname(fileName);
45
+ const plans = [];
46
+ for (const node of program.body) {
47
+ const decl = node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration" ? node.declaration : node;
48
+ if (!decl || decl.type !== "ClassDeclaration") continue;
49
+ for (const dec of decl.decorators || []) {
50
+ const expr = dec.expression;
51
+ if (!expr || expr.type !== "CallExpression") continue;
52
+ if (expr.callee?.name !== "Component") continue;
53
+ const arg = expr.arguments?.[0];
54
+ if (!arg || arg.type !== "ObjectExpression") continue;
55
+ let existingStylesProp = null;
56
+ let existingStylesArray = null;
57
+ for (const prop of arg.properties) {
58
+ if (prop.type !== "Property") continue;
59
+ if ((prop.key?.name ?? prop.key?.value) === "styles") {
60
+ existingStylesProp = prop;
61
+ if (prop.value?.type === "ArrayExpression") existingStylesArray = prop.value;
62
+ break;
63
+ }
64
+ }
65
+ const existingInlineCount = existingStylesArray ? countInlineStyleLiterals(existingStylesArray) : isInlineStyleValue(existingStylesProp?.value) ? 1 : 0;
66
+ const resourceProps = [];
67
+ for (const prop of arg.properties) {
68
+ if (prop.type !== "Property") continue;
69
+ const key = prop.key?.name ?? prop.key?.value;
70
+ const val = prop.value;
71
+ if (key === "templateUrl" && val?.type === "Literal" && typeof val.value === "string") {
72
+ resourceProps.push({
73
+ kind: "templateUrl",
74
+ prop,
75
+ resolvedPath: path$1.resolve(dir, val.value)
76
+ });
77
+ continue;
78
+ }
79
+ if (key === "styleUrl" && val?.type === "Literal" && typeof val.value === "string") {
80
+ resourceProps.push({
81
+ kind: "styleUrl",
82
+ prop,
83
+ resolvedPath: path$1.resolve(dir, val.value)
84
+ });
85
+ continue;
86
+ }
87
+ if (key === "styleUrls" && val?.type === "ArrayExpression") {
88
+ const resolvedPaths = [];
89
+ for (const el of val.elements) if (el?.type === "Literal" && typeof el.value === "string") resolvedPaths.push(path$1.resolve(dir, el.value));
90
+ resourceProps.push({
91
+ kind: "styleUrls",
92
+ prop,
93
+ resolvedPaths
94
+ });
95
+ }
96
+ }
97
+ plans.push({
98
+ existingStylesProp,
99
+ existingStylesArray,
100
+ existingInlineCount,
101
+ resourceProps
102
+ });
103
+ }
104
+ }
105
+ const pathsToRead = /* @__PURE__ */ new Set();
106
+ for (const plan of plans) for (const rp of plan.resourceProps) if (rp.kind === "styleUrls") for (const p of rp.resolvedPaths) pathsToRead.add(p);
107
+ else pathsToRead.add(rp.resolvedPath);
108
+ const fileContents = /* @__PURE__ */ new Map();
109
+ await Promise.all([...pathsToRead].map(async (p) => {
110
+ fileContents.set(p, await fs.promises.readFile(p, "utf-8").catch(() => void 0));
111
+ }));
112
+ let flatStyleBase = 0;
113
+ for (const plan of plans) {
114
+ const { existingStylesProp, existingStylesArray, existingInlineCount } = plan;
115
+ const templateUrlRewrites = [];
116
+ const cssProps = [];
117
+ for (const rp of plan.resourceProps) if (rp.kind === "templateUrl") {
118
+ const content = fileContents.get(rp.resolvedPath);
119
+ if (content !== void 0) templateUrlRewrites.push({
120
+ prop: rp.prop,
121
+ content
122
+ });
123
+ } else if (rp.kind === "styleUrl") {
124
+ const content = fileContents.get(rp.resolvedPath);
125
+ if (content !== void 0) cssProps.push({
126
+ prop: rp.prop,
127
+ contents: [content],
128
+ extensions: [extensionOf(rp.resolvedPath)]
129
+ });
130
+ } else {
131
+ const contents = [];
132
+ const extensions = [];
133
+ let allRead = true;
134
+ for (const p of rp.resolvedPaths) {
135
+ const content = fileContents.get(p);
136
+ if (content === void 0) {
137
+ allRead = false;
138
+ break;
139
+ }
140
+ contents.push(content);
141
+ extensions.push(extensionOf(p));
142
+ }
143
+ if (allRead && contents.length > 0) cssProps.push({
144
+ prop: rp.prop,
145
+ contents,
146
+ extensions
147
+ });
148
+ }
149
+ for (const { prop, content } of templateUrlRewrites) {
150
+ ms.overwrite(prop.start, prop.end, `template: ${JSON.stringify(content)}`);
151
+ changed = true;
152
+ }
153
+ if (cssProps.length > 0) {
154
+ const allContents = cssProps.flatMap((c) => c.contents);
155
+ const allExtensions = cssProps.flatMap((c) => c.extensions);
156
+ if (existingStylesArray) {
157
+ const realElements = existingStylesArray.elements.filter((e) => e != null);
158
+ if (realElements.length > 0) {
159
+ const lastElement = realElements[realElements.length - 1];
160
+ const insertion = allContents.map((c) => `, ${JSON.stringify(c)}`).join("");
161
+ ms.appendRight(lastElement.end, insertion);
162
+ } else {
163
+ const insertion = allContents.map((c) => JSON.stringify(c)).join(", ");
164
+ ms.appendLeft(existingStylesArray.end - 1, insertion);
165
+ }
166
+ for (const { prop } of cssProps) removePropertyWithSeparator(ms, code, prop.start, prop.end);
167
+ } else if (isInlineStyleValue(existingStylesProp?.value)) {
168
+ const original = code.slice(existingStylesProp.value.start, existingStylesProp.value.end);
169
+ const merged = allContents.map((c) => `, ${JSON.stringify(c)}`).join("");
170
+ ms.overwrite(existingStylesProp.value.start, existingStylesProp.value.end, `[${original}${merged}]`);
171
+ for (const { prop } of cssProps) removePropertyWithSeparator(ms, code, prop.start, prop.end);
172
+ } else {
173
+ const [first, ...rest] = cssProps;
174
+ ms.overwrite(first.prop.start, first.prop.end, `styles: [${allContents.map((c) => JSON.stringify(c)).join(", ")}]`);
175
+ for (const { prop } of rest) removePropertyWithSeparator(ms, code, prop.start, prop.end);
176
+ }
177
+ changed = true;
178
+ const externalBase = flatStyleBase + existingInlineCount;
179
+ allExtensions.forEach((ext, k) => {
180
+ if (ext) styleExtensions.set(externalBase + k, ext);
181
+ });
182
+ flatStyleBase = externalBase + allContents.length;
183
+ } else flatStyleBase += existingInlineCount;
184
+ }
185
+ return {
186
+ code: changed ? ms.toString() : code,
187
+ styleExtensions,
188
+ resourceDependencies: [...pathsToRead].filter((p) => fileContents.get(p) !== void 0)
189
+ };
190
+ }
191
+ /** Lower-cased file extension without the leading dot (e.g. `scss`), or `''`. */
192
+ function extensionOf(filePath) {
193
+ return path$1.extname(filePath).slice(1).toLowerCase();
194
+ }
195
+ /**
196
+ * Remove a property from an object literal while also eating one surrounding
197
+ * comma so the resulting object stays syntactically valid. Prefers the
198
+ * trailing comma; falls back to the leading comma when the property is the
199
+ * last entry in the object.
200
+ */
201
+ function removePropertyWithSeparator(ms, code, propStart, propEnd) {
202
+ let i = propEnd;
203
+ while (i < code.length && isWhitespace(code[i])) i++;
204
+ if (code[i] === ",") {
205
+ ms.remove(propStart, i + 1);
206
+ return;
207
+ }
208
+ let j = propStart - 1;
209
+ while (j >= 0 && isWhitespace(code[j])) j--;
210
+ if (code[j] === ",") {
211
+ ms.remove(j, propEnd);
212
+ return;
213
+ }
214
+ ms.remove(propStart, propEnd);
215
+ }
216
+ function isWhitespace(ch) {
217
+ return ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v";
218
+ }
219
+ /**
220
+ * Extract inline style strings from Angular @Component decorator using OXC parser.
221
+ * Returns an array of style string values for preprocessing.
222
+ */
223
+ function extractInlineStyles(code, fileName, program) {
224
+ if (!code.includes("styles")) return [];
225
+ return extractInlineStyles$1(code, fileName, program);
226
+ }
227
+ //#endregion
228
+ export { extractInlineStyles, inlineResourceUrls };
229
+
230
+ //# sourceMappingURL=resource-inliner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-inliner.js","names":[],"sources":["../../../../src/lib/compiler/resource-inliner.ts"],"sourcesContent":["import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { parseSync } from 'oxc-parser';\nimport MagicString from 'magic-string';\nimport { extractInlineStyles as extractStylesFromAst } from './style-ast.js';\n\nexport interface InlineResourceResult {\n /** The modified source code, or the original if no changes were needed. */\n code: string;\n /**\n * Source extension (without the leading dot, lower-cased — e.g. `scss`) of\n * each inlined external style, keyed by its position in the flat per-file\n * style list produced by {@link extractInlineStyles}. Lets the caller run\n * each external `styleUrl` through the right preprocessor by its own file\n * extension, independent of the `inlineStylesExtension` option (which governs\n * truly-inline `styles: [...]` template strings).\n */\n styleExtensions: Map<number, string>;\n /**\n * Absolute paths of every external resource file successfully read and\n * inlined. Callers record these so a later edit to the resource file can\n * invalidate the owning source module — the inlined copy is otherwise\n * invisible to the module graph.\n */\n resourceDependencies: string[];\n}\n\n/** Whether a node is an inline style value (string literal or single-quasi template). */\nfunction isInlineStyleValue(node: any): boolean {\n return (\n (node?.type === 'Literal' && typeof node.value === 'string') ||\n (node?.type === 'TemplateLiteral' && node.quasis?.length === 1)\n );\n}\n\n/** Count the elements of a `styles: [...]` array that {@link extractInlineStyles} would emit. */\nfunction countInlineStyleLiterals(arrayExpr: any): number {\n let count = 0;\n for (const el of arrayExpr.elements ?? []) {\n if (el?.type === 'Literal' && typeof el.value === 'string') count++;\n else if (el?.type === 'TemplateLiteral' && el.quasis?.length === 1) count++;\n }\n return count;\n}\n\n/**\n * Inline external templateUrl and styleUrl/styleUrls into the source code\n * using OXC parser for precise AST-based rewriting.\n *\n * Replaces:\n * templateUrl: './file.html' → template: \"...file contents...\"\n * styleUrl: './file.scss' → styles: [\"...file contents...\"]\n * styleUrls: ['./a.scss'] → styles: [\"...contents...\"]\n *\n * When the decorator already has a `styles: [...]` array, inlined CSS is\n * merged into that existing array instead of emitting a second `styles`\n * property (which would be a duplicate object literal key).\n *\n * Returns the modified source code plus the per-style-index extension map\n * (see {@link InlineResourceResult}).\n */\nexport async function inlineResourceUrls(\n code: string,\n fileName: string,\n): Promise<InlineResourceResult> {\n const styleExtensions = new Map<number, string>();\n\n if (!code.includes('templateUrl') && !code.includes('styleUrl')) {\n return { code, styleExtensions, resourceDependencies: [] };\n }\n\n const { program } = parseSync(fileName, code);\n const ms = new MagicString(code);\n let changed = false;\n const dir = path.dirname(fileName);\n\n // Phase 1: walk the AST and collect resource descriptors per decorator,\n // in source order — no I/O during the walk. A plan is recorded for every\n // `@Component` decorator (even without url props) because the flat style\n // index bookkeeping below advances per decorator.\n type ResourceProp =\n | { kind: 'templateUrl'; prop: any; resolvedPath: string }\n | { kind: 'styleUrl'; prop: any; resolvedPath: string }\n | { kind: 'styleUrls'; prop: any; resolvedPaths: string[] };\n interface DecoratorPlan {\n existingStylesProp: any;\n existingStylesArray: any;\n existingInlineCount: number;\n resourceProps: ResourceProp[];\n }\n const plans: DecoratorPlan[] = [];\n\n for (const node of program.body) {\n const decl =\n node.type === 'ExportNamedDeclaration' ||\n node.type === 'ExportDefaultDeclaration'\n ? (node as any).declaration\n : node;\n if (!decl || decl.type !== 'ClassDeclaration') continue;\n\n for (const dec of decl.decorators || []) {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') continue;\n if (expr.callee?.name !== 'Component') continue;\n\n const arg = expr.arguments?.[0];\n if (!arg || arg.type !== 'ObjectExpression') continue;\n\n // First pass: locate an existing `styles` property in the same decorator.\n // Inlined CSS is merged into it — converting a singular string/template\n // value to an array when needed — to avoid emitting a duplicate `styles`\n // key.\n let existingStylesProp: any = null;\n let existingStylesArray: any = null;\n for (const prop of arg.properties) {\n if (prop.type !== 'Property') continue;\n const key: string = prop.key?.name ?? prop.key?.value;\n if (key === 'styles') {\n existingStylesProp = prop;\n if (prop.value?.type === 'ArrayExpression') {\n existingStylesArray = prop.value;\n }\n break;\n }\n }\n\n // Inline `styles` entries already present come first in the flat list;\n // appended external styles follow them.\n const existingInlineCount = existingStylesArray\n ? countInlineStyleLiterals(existingStylesArray)\n : isInlineStyleValue(existingStylesProp?.value)\n ? 1\n : 0;\n\n const resourceProps: ResourceProp[] = [];\n\n for (const prop of arg.properties) {\n if (prop.type !== 'Property') continue;\n const key: string = prop.key?.name ?? prop.key?.value;\n const val = prop.value;\n\n if (\n key === 'templateUrl' &&\n val?.type === 'Literal' &&\n typeof val.value === 'string'\n ) {\n resourceProps.push({\n kind: 'templateUrl',\n prop,\n resolvedPath: path.resolve(dir, val.value),\n });\n continue;\n }\n\n if (\n key === 'styleUrl' &&\n val?.type === 'Literal' &&\n typeof val.value === 'string'\n ) {\n resourceProps.push({\n kind: 'styleUrl',\n prop,\n resolvedPath: path.resolve(dir, val.value),\n });\n continue;\n }\n\n if (key === 'styleUrls' && val?.type === 'ArrayExpression') {\n const resolvedPaths: string[] = [];\n for (const el of val.elements) {\n if (el?.type === 'Literal' && typeof el.value === 'string') {\n resolvedPaths.push(path.resolve(dir, el.value));\n }\n }\n resourceProps.push({ kind: 'styleUrls', prop, resolvedPaths });\n }\n }\n\n plans.push({\n existingStylesProp,\n existingStylesArray,\n existingInlineCount,\n resourceProps,\n });\n }\n }\n\n // Phase 2: read every referenced resource without blocking the event\n // loop. Each read catches its own failure to `undefined` — one missing\n // file must not abort sibling reads that succeed.\n const pathsToRead = new Set<string>();\n for (const plan of plans) {\n for (const rp of plan.resourceProps) {\n if (rp.kind === 'styleUrls') {\n for (const p of rp.resolvedPaths) pathsToRead.add(p);\n } else {\n pathsToRead.add(rp.resolvedPath);\n }\n }\n }\n const fileContents = new Map<string, string | undefined>();\n await Promise.all(\n [...pathsToRead].map(async (p) => {\n fileContents.set(\n p,\n await fs.promises.readFile(p, 'utf-8').catch(() => undefined),\n );\n }),\n );\n\n // Phase 3: apply MagicString rewrites in the original AST order so the\n // flat style index bookkeeping matches `extractInlineStyles`.\n\n // Running base index into the flat per-file style list (matching the order\n // `extractInlineStyles` walks classes/decorators/properties) so external\n // styles can be mapped to the index `resolvedInlineStyles` later keys on.\n let flatStyleBase = 0;\n\n for (const plan of plans) {\n const { existingStylesProp, existingStylesArray, existingInlineCount } =\n plan;\n\n // Collect the props we want to rewrite. Contents from styleUrl /\n // styleUrls are accumulated so that multiple url-based props in one\n // decorator collapse into a single `styles` array write. `extensions`\n // tracks each content's source extension in the same order.\n const templateUrlRewrites: Array<{ prop: any; content: string }> = [];\n const cssProps: Array<{\n prop: any;\n contents: string[];\n extensions: string[];\n }> = [];\n\n for (const rp of plan.resourceProps) {\n if (rp.kind === 'templateUrl') {\n // Keep original if file can't be read\n const content = fileContents.get(rp.resolvedPath);\n if (content !== undefined) {\n templateUrlRewrites.push({ prop: rp.prop, content });\n }\n } else if (rp.kind === 'styleUrl') {\n // Keep original if file can't be read\n const content = fileContents.get(rp.resolvedPath);\n if (content !== undefined) {\n cssProps.push({\n prop: rp.prop,\n contents: [content],\n extensions: [extensionOf(rp.resolvedPath)],\n });\n }\n } else {\n // styleUrls is all-or-nothing: keep the original property if any\n // entry failed to read.\n const contents: string[] = [];\n const extensions: string[] = [];\n let allRead = true;\n for (const p of rp.resolvedPaths) {\n const content = fileContents.get(p);\n if (content === undefined) {\n allRead = false;\n break;\n }\n contents.push(content);\n extensions.push(extensionOf(p));\n }\n if (allRead && contents.length > 0) {\n cssProps.push({ prop: rp.prop, contents, extensions });\n }\n }\n }\n\n for (const { prop, content } of templateUrlRewrites) {\n ms.overwrite(\n prop.start,\n prop.end,\n `template: ${JSON.stringify(content)}`,\n );\n changed = true;\n }\n\n if (cssProps.length > 0) {\n const allContents = cssProps.flatMap((c) => c.contents);\n const allExtensions = cssProps.flatMap((c) => c.extensions);\n\n if (existingStylesArray) {\n // Filter out null holes in case the source already has a sparse array.\n const realElements = (existingStylesArray.elements as any[]).filter(\n (e) => e != null,\n );\n\n if (realElements.length > 0) {\n // Insert right after the last real element. This preserves any\n // trailing comma the source may have (e.g. Prettier output) and\n // avoids producing a sparse `[existing, , \"new\"]` element, which\n // would crash downstream decorator metadata extraction.\n const lastElement = realElements[realElements.length - 1];\n const insertion = allContents\n .map((c) => `, ${JSON.stringify(c)}`)\n .join('');\n ms.appendRight(lastElement.end, insertion);\n } else {\n // Empty array — drop the leading comma.\n const insertion = allContents\n .map((c) => JSON.stringify(c))\n .join(', ');\n ms.appendLeft(existingStylesArray.end - 1, insertion);\n }\n\n for (const { prop } of cssProps) {\n removePropertyWithSeparator(ms, code, prop.start, prop.end);\n }\n } else if (isInlineStyleValue(existingStylesProp?.value)) {\n // Singular `styles: '...'` / `styles: \\`...\\`` — wrap the original\n // value into an array merged with the inlined styles, then drop the\n // styleUrl props so only one `styles` key remains.\n const original = code.slice(\n existingStylesProp.value.start,\n existingStylesProp.value.end,\n );\n const merged = allContents\n .map((c) => `, ${JSON.stringify(c)}`)\n .join('');\n ms.overwrite(\n existingStylesProp.value.start,\n existingStylesProp.value.end,\n `[${original}${merged}]`,\n );\n for (const { prop } of cssProps) {\n removePropertyWithSeparator(ms, code, prop.start, prop.end);\n }\n } else {\n // No existing `styles` array — rewrite the first styleUrl/styleUrls\n // prop with the merged contents and drop any additional ones so we\n // don't emit multiple `styles` properties.\n const [first, ...rest] = cssProps;\n ms.overwrite(\n first.prop.start,\n first.prop.end,\n `styles: [${allContents.map((c) => JSON.stringify(c)).join(', ')}]`,\n );\n for (const { prop } of rest) {\n removePropertyWithSeparator(ms, code, prop.start, prop.end);\n }\n }\n changed = true;\n\n // The appended external styles occupy the flat indices after any\n // pre-existing inline styles for this component.\n const externalBase = flatStyleBase + existingInlineCount;\n allExtensions.forEach((ext, k) => {\n if (ext) styleExtensions.set(externalBase + k, ext);\n });\n flatStyleBase = externalBase + allContents.length;\n } else {\n flatStyleBase += existingInlineCount;\n }\n }\n\n return {\n code: changed ? ms.toString() : code,\n styleExtensions,\n resourceDependencies: [...pathsToRead].filter(\n (p) => fileContents.get(p) !== undefined,\n ),\n };\n}\n\n/** Lower-cased file extension without the leading dot (e.g. `scss`), or `''`. */\nfunction extensionOf(filePath: string): string {\n return path.extname(filePath).slice(1).toLowerCase();\n}\n\n/**\n * Remove a property from an object literal while also eating one surrounding\n * comma so the resulting object stays syntactically valid. Prefers the\n * trailing comma; falls back to the leading comma when the property is the\n * last entry in the object.\n */\nfunction removePropertyWithSeparator(\n ms: MagicString,\n code: string,\n propStart: number,\n propEnd: number,\n): void {\n let i = propEnd;\n while (i < code.length && isWhitespace(code[i])) i++;\n if (code[i] === ',') {\n ms.remove(propStart, i + 1);\n return;\n }\n let j = propStart - 1;\n while (j >= 0 && isWhitespace(code[j])) j--;\n if (code[j] === ',') {\n ms.remove(j, propEnd);\n return;\n }\n ms.remove(propStart, propEnd);\n}\n\nfunction isWhitespace(ch: string): boolean {\n return (\n ch === ' ' ||\n ch === '\\t' ||\n ch === '\\n' ||\n ch === '\\r' ||\n ch === '\\f' ||\n ch === '\\v'\n );\n}\n\n/**\n * Extract inline style strings from Angular @Component decorator using OXC parser.\n * Returns an array of style string values for preprocessing.\n */\nexport function extractInlineStyles(\n code: string,\n fileName: string,\n program?: ReturnType<typeof parseSync>['program'],\n): string[] {\n if (!code.includes('styles')) return [];\n return extractStylesFromAst(code, fileName, program);\n}\n"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { parseSync } from "oxc-parser";
2
+ /**
3
+ * Extract styleUrl/styleUrls values from Angular @Component decorators.
4
+ */
5
+ export declare function extractStyleUrls(code: string, fileName: string): string[];
6
+ /**
7
+ * Extract inline style strings from Angular @Component decorators.
8
+ */
9
+ export declare function extractInlineStyles(code: string, fileName: string, program?: ReturnType<typeof parseSync>["program"]): string[];
@@ -0,0 +1,54 @@
1
+ import { parseSync } from "oxc-parser";
2
+ //#region packages/vite-plugin-angular/src/lib/compiler/style-ast.ts
3
+ function getClassDeclaration(node) {
4
+ return node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration" ? node.declaration : node;
5
+ }
6
+ function getPropertyKey(prop) {
7
+ return prop.key?.name || prop.key?.value;
8
+ }
9
+ function getTemplateLiteralText(node) {
10
+ if (node?.type !== "TemplateLiteral" || node.quasis?.length !== 1) return;
11
+ return node.quasis[0].value.cooked || node.quasis[0].value.raw;
12
+ }
13
+ /**
14
+ * Extract inline style strings from Angular @Component decorators.
15
+ */
16
+ function extractInlineStyles(code, fileName, program) {
17
+ const styles = [];
18
+ program ??= parseSync(fileName, code).program;
19
+ for (const node of program.body) {
20
+ const decl = getClassDeclaration(node);
21
+ if (!decl || decl.type !== "ClassDeclaration") continue;
22
+ for (const dec of decl.decorators || []) {
23
+ const expr = dec.expression;
24
+ if (!expr || expr.type !== "CallExpression") continue;
25
+ if (expr.callee?.name !== "Component") continue;
26
+ const arg = expr.arguments?.[0];
27
+ if (!arg || arg.type !== "ObjectExpression") continue;
28
+ for (const prop of arg.properties) {
29
+ if (prop.type !== "Property") continue;
30
+ const key = getPropertyKey(prop);
31
+ const val = prop.value;
32
+ if (key !== "styles") continue;
33
+ if (val?.type === "ArrayExpression") for (const el of val.elements) {
34
+ if (el?.type === "Literal" && typeof el.value === "string") {
35
+ styles.push(el.value);
36
+ continue;
37
+ }
38
+ const templateText = getTemplateLiteralText(el);
39
+ if (templateText !== void 0) styles.push(templateText);
40
+ }
41
+ else if (val?.type === "Literal" && typeof val.value === "string") styles.push(val.value);
42
+ else {
43
+ const templateText = getTemplateLiteralText(val);
44
+ if (templateText !== void 0) styles.push(templateText);
45
+ }
46
+ }
47
+ }
48
+ }
49
+ return styles;
50
+ }
51
+ //#endregion
52
+ export { extractInlineStyles };
53
+
54
+ //# sourceMappingURL=style-ast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-ast.js","names":[],"sources":["../../../../src/lib/compiler/style-ast.ts"],"sourcesContent":["import { parseSync } from 'oxc-parser';\n\ntype ProgramNode = ReturnType<typeof parseSync>['program']['body'][number];\n\nfunction getClassDeclaration(node: ProgramNode): any {\n return node.type === 'ExportNamedDeclaration' ||\n node.type === 'ExportDefaultDeclaration'\n ? (node as any).declaration\n : node;\n}\n\nfunction getPropertyKey(prop: any): string | undefined {\n return prop.key?.name || prop.key?.value;\n}\n\nfunction getTemplateLiteralText(node: any): string | undefined {\n if (node?.type !== 'TemplateLiteral' || node.quasis?.length !== 1) {\n return undefined;\n }\n\n return node.quasis[0].value.cooked || node.quasis[0].value.raw;\n}\n\n/**\n * Extract styleUrl/styleUrls values from Angular @Component decorators.\n */\nexport function extractStyleUrls(code: string, fileName: string): string[] {\n const urls: string[] = [];\n const { program } = parseSync(fileName, code);\n\n for (const node of program.body) {\n const decl = getClassDeclaration(node);\n if (!decl || decl.type !== 'ClassDeclaration') continue;\n\n for (const dec of decl.decorators || []) {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') continue;\n if (expr.callee?.name !== 'Component') continue;\n\n const arg = expr.arguments?.[0];\n if (!arg || arg.type !== 'ObjectExpression') continue;\n\n for (const prop of arg.properties) {\n if (prop.type !== 'Property') continue;\n const key = getPropertyKey(prop);\n const val = prop.value;\n\n if (\n key === 'styleUrl' &&\n val?.type === 'Literal' &&\n typeof val.value === 'string'\n ) {\n urls.push(val.value);\n }\n\n if (key === 'styleUrls' && val?.type === 'ArrayExpression') {\n for (const el of val.elements) {\n if (el?.type === 'Literal' && typeof el.value === 'string') {\n urls.push(el.value);\n }\n }\n }\n }\n }\n }\n\n return urls;\n}\n\n/**\n * Extract inline style strings from Angular @Component decorators.\n */\nexport function extractInlineStyles(\n code: string,\n fileName: string,\n program?: ReturnType<typeof parseSync>['program'],\n): string[] {\n const styles: string[] = [];\n program ??= parseSync(fileName, code).program;\n\n for (const node of program.body) {\n const decl = getClassDeclaration(node);\n if (!decl || decl.type !== 'ClassDeclaration') continue;\n\n for (const dec of decl.decorators || []) {\n const expr = dec.expression;\n if (!expr || expr.type !== 'CallExpression') continue;\n if (expr.callee?.name !== 'Component') continue;\n\n const arg = expr.arguments?.[0];\n if (!arg || arg.type !== 'ObjectExpression') continue;\n\n for (const prop of arg.properties) {\n if (prop.type !== 'Property') continue;\n const key = getPropertyKey(prop);\n const val = prop.value;\n\n if (key !== 'styles') continue;\n\n if (val?.type === 'ArrayExpression') {\n for (const el of val.elements) {\n if (el?.type === 'Literal' && typeof el.value === 'string') {\n styles.push(el.value);\n continue;\n }\n\n const templateText = getTemplateLiteralText(el);\n if (templateText !== undefined) {\n styles.push(templateText);\n }\n }\n } else if (val?.type === 'Literal' && typeof val.value === 'string') {\n styles.push(val.value);\n } else {\n const templateText = getTemplateLiteralText(val);\n if (templateText !== undefined) {\n styles.push(templateText);\n }\n }\n }\n }\n }\n\n return styles;\n}\n"],"mappings":";;AAIA,SAAS,oBAAoB,MAAwB;AACnD,QAAO,KAAK,SAAS,4BACnB,KAAK,SAAS,6BACX,KAAa,cACd;;AAGN,SAAS,eAAe,MAA+B;AACrD,QAAO,KAAK,KAAK,QAAQ,KAAK,KAAK;;AAGrC,SAAS,uBAAuB,MAA+B;AAC7D,KAAI,MAAM,SAAS,qBAAqB,KAAK,QAAQ,WAAW,EAC9D;AAGF,QAAO,KAAK,OAAO,GAAG,MAAM,UAAU,KAAK,OAAO,GAAG,MAAM;;;;;AAoD7D,SAAgB,oBACd,MACA,UACA,SACU;CACV,MAAM,SAAmB,EAAE;AAC3B,aAAY,UAAU,UAAU,KAAK,CAAC;AAEtC,MAAK,MAAM,QAAQ,QAAQ,MAAM;EAC/B,MAAM,OAAO,oBAAoB,KAAK;AACtC,MAAI,CAAC,QAAQ,KAAK,SAAS,mBAAoB;AAE/C,OAAK,MAAM,OAAO,KAAK,cAAc,EAAE,EAAE;GACvC,MAAM,OAAO,IAAI;AACjB,OAAI,CAAC,QAAQ,KAAK,SAAS,iBAAkB;AAC7C,OAAI,KAAK,QAAQ,SAAS,YAAa;GAEvC,MAAM,MAAM,KAAK,YAAY;AAC7B,OAAI,CAAC,OAAO,IAAI,SAAS,mBAAoB;AAE7C,QAAK,MAAM,QAAQ,IAAI,YAAY;AACjC,QAAI,KAAK,SAAS,WAAY;IAC9B,MAAM,MAAM,eAAe,KAAK;IAChC,MAAM,MAAM,KAAK;AAEjB,QAAI,QAAQ,SAAU;AAEtB,QAAI,KAAK,SAAS,kBAChB,MAAK,MAAM,MAAM,IAAI,UAAU;AAC7B,SAAI,IAAI,SAAS,aAAa,OAAO,GAAG,UAAU,UAAU;AAC1D,aAAO,KAAK,GAAG,MAAM;AACrB;;KAGF,MAAM,eAAe,uBAAuB,GAAG;AAC/C,SAAI,iBAAiB,KAAA,EACnB,QAAO,KAAK,aAAa;;aAGpB,KAAK,SAAS,aAAa,OAAO,IAAI,UAAU,SACzD,QAAO,KAAK,IAAI,MAAM;SACjB;KACL,MAAM,eAAe,uBAAuB,IAAI;AAChD,SAAI,iBAAiB,KAAA,EACnB,QAAO,KAAK,aAAa;;;;;AAOnC,QAAO"}
@@ -0,0 +1,13 @@
1
+ import { type ResolvedConfig } from "vite";
2
+ /**
3
+ * Extract styleUrl/styleUrls from source using OXC parser,
4
+ * read and preprocess them via Vite.
5
+ * Returns a Map of absolute path → compiled CSS for the compiler to use.
6
+ */
7
+ export declare function resolveStyleFiles(code: string, id: string, resolvedConfig: ResolvedConfig): Promise<Map<string, string> | undefined>;
8
+ /**
9
+ * Preprocess inline styles that contain SCSS/Sass syntax.
10
+ * Uses OXC parser to extract style strings from decorator arguments
11
+ * and runs them through Vite's preprocessCSS.
12
+ */
13
+ export declare function preprocessInlineStyles(code: string, id: string, inlineStyleLanguage: string, resolvedConfig: ResolvedConfig): Promise<Map<number, string> | undefined>;
@@ -0,0 +1,7 @@
1
+ import { ComponentRegistry } from "./registry";
2
+ export declare function buildRegistry(files: Record<string, string>): ComponentRegistry;
3
+ /** Convenience wrapper: compile and return just the code string. */
4
+ export declare function compileCode(sourceCode: string, fileName: string, registry?: ComponentRegistry): string;
5
+ /** Compile in partial mode and return just the code string. */
6
+ export declare function compilePartialCode(sourceCode: string, fileName: string, registry?: ComponentRegistry): string;
7
+ export declare function expectCompiles(result: string);
@@ -0,0 +1,28 @@
1
+ import MagicString from "magic-string";
2
+ import { parseSync } from "oxc-parser";
3
+ /**
4
+ * Analyse compiled TypeScript source and return the set of imported names
5
+ * that are only referenced in type positions (type annotations, implements
6
+ * clauses, generics, etc.) and can safely be elided.
7
+ *
8
+ * Uses oxc-parser for fast, Rust-based AST analysis — no type-checker needed.
9
+ */
10
+ export declare function detectTypeOnlyImportNames(code: string, program?: ReturnType<typeof parseSync>["program"]): Set<string>;
11
+ /**
12
+ * Elide import specifiers (or entire import declarations) for names that are
13
+ * only used in type positions. Operates on the compiler's TypeScript output
14
+ * (before OXC strips remaining TS syntax).
15
+ *
16
+ * Returns the modified source code, or the original if nothing was elided.
17
+ */
18
+ export declare function elideTypeOnlyImports(code: string): string;
19
+ /**
20
+ * Elide type-only imports directly on a MagicString instance, so that
21
+ * subsequent `ms.generateMap()` calls produce an accurate sourcemap.
22
+ *
23
+ * Detects type-only names from `ms.toString()` (the fully-mutated code),
24
+ * but reads import positions from `ms.original` (the coordinate system
25
+ * MagicString expects). `originalProgram`, when provided, must be a parse
26
+ * of `ms.original` — never of the mutated text.
27
+ */
28
+ export declare function elideTypeOnlyImportsMagicString(ms: MagicString, originalProgram?: ReturnType<typeof parseSync>["program"]): void;
@@ -0,0 +1,211 @@
1
+ import { parseSync } from "oxc-parser";
2
+ import "magic-string";
3
+ //#region packages/vite-plugin-angular/src/lib/compiler/type-elision.ts
4
+ /**
5
+ * AST property keys that represent type-only positions in TypeScript.
6
+ * Identifiers found only under these keys are never emitted as runtime values.
7
+ */
8
+ var TYPE_POSITION_KEYS = new Set([
9
+ "typeAnnotation",
10
+ "typeParameters",
11
+ "superTypeParameters",
12
+ "implements",
13
+ "returnType",
14
+ "typeArguments"
15
+ ]);
16
+ /**
17
+ * AST node types that represent type-level constructs.
18
+ * Any identifier nested inside one of these nodes is in a type position.
19
+ */
20
+ var TYPE_NODE_TYPES = new Set([
21
+ "TSTypeAnnotation",
22
+ "TSTypeReference",
23
+ "TSTypeParameterInstantiation",
24
+ "TSTypeParameterDeclaration",
25
+ "TSInterfaceDeclaration",
26
+ "TSTypeAliasDeclaration",
27
+ "TSAsExpression",
28
+ "TSSatisfiesExpression",
29
+ "TSUnionType",
30
+ "TSIntersectionType",
31
+ "TSArrayType",
32
+ "TSTupleType",
33
+ "TSFunctionType",
34
+ "TSConstructorType",
35
+ "TSMappedType",
36
+ "TSConditionalType",
37
+ "TSIndexedAccessType",
38
+ "TSTypeQuery",
39
+ "TSTypeLiteral",
40
+ "TSQualifiedName",
41
+ "TSInterfaceBody"
42
+ ]);
43
+ /**
44
+ * Internal helper: parse code and return both the AST and the set of
45
+ * type-only imported names. Avoids double-parsing when both are needed.
46
+ */
47
+ function analyzeTypeOnlyImports(code, program) {
48
+ const ast = program ?? parseSync("file.ts", code).program;
49
+ const importedNames = /* @__PURE__ */ new Set();
50
+ for (const node of ast.body) {
51
+ if (node.type !== "ImportDeclaration") continue;
52
+ if (node.importKind === "type") continue;
53
+ for (const spec of node.specifiers ?? []) {
54
+ if (spec.importKind === "type") continue;
55
+ importedNames.add(spec.local.name);
56
+ }
57
+ }
58
+ if (importedNames.size === 0) return {
59
+ ast,
60
+ typeOnlyNames: /* @__PURE__ */ new Set()
61
+ };
62
+ const valueReferenced = /* @__PURE__ */ new Set();
63
+ collectConstructorDiTokens(ast, importedNames, valueReferenced);
64
+ function walk(node, inTypePosition) {
65
+ if (!node || typeof node !== "object") return;
66
+ if (Array.isArray(node)) {
67
+ for (const item of node) walk(item, inTypePosition);
68
+ return;
69
+ }
70
+ if (valueReferenced.size === importedNames.size) return;
71
+ if (!inTypePosition && TYPE_NODE_TYPES.has(node.type)) {
72
+ if (node.type === "TSAsExpression" || node.type === "TSSatisfiesExpression") {
73
+ walk(node.expression, false);
74
+ walk(node.typeAnnotation, true);
75
+ return;
76
+ }
77
+ inTypePosition = true;
78
+ }
79
+ if (!inTypePosition && node.type === "ExportNamedDeclaration" && !node.source) {
80
+ if (node.declaration) walk(node.declaration, false);
81
+ for (const spec of node.specifiers ?? []) {
82
+ if (node.exportKind === "type" || spec.exportKind === "type") continue;
83
+ walk(spec, false);
84
+ }
85
+ return;
86
+ }
87
+ if (!inTypePosition && node.type === "Identifier" && importedNames.has(node.name)) {
88
+ valueReferenced.add(node.name);
89
+ return;
90
+ }
91
+ for (const key of Object.keys(node)) {
92
+ if (key === "type" || key === "start" || key === "end" || key === "range" || key === "loc") continue;
93
+ const isTypePos = inTypePosition || TYPE_POSITION_KEYS.has(key);
94
+ walk(node[key], isTypePos);
95
+ }
96
+ }
97
+ for (const node of ast.body) if (node.type !== "ImportDeclaration") walk(node, false);
98
+ const typeOnly = /* @__PURE__ */ new Set();
99
+ for (const name of importedNames) if (!valueReferenced.has(name)) typeOnly.add(name);
100
+ return {
101
+ ast,
102
+ typeOnlyNames: typeOnly
103
+ };
104
+ }
105
+ /**
106
+ * Walk the program looking for decorated classes with constructors and add
107
+ * the type names from constructor parameter annotations to `valueReferenced`.
108
+ *
109
+ * Constructor parameter types are TypeScript type positions, but for decorated
110
+ * classes they double as runtime DI tokens — Angular's compiler reads them
111
+ * via `compileFactoryFunction` to wire `ɵɵdirectiveInject(...)` calls. The
112
+ * import of the type therefore must NOT be elided as type-only.
113
+ */
114
+ function collectConstructorDiTokens(ast, importedNames, valueReferenced) {
115
+ for (const stmt of ast.body || []) {
116
+ const classNode = stmt.type === "ExportNamedDeclaration" || stmt.type === "ExportDefaultDeclaration" ? stmt.declaration : stmt;
117
+ if (!classNode || classNode.type !== "ClassDeclaration" && classNode.type !== "ClassExpression") continue;
118
+ if (!classNode.decorators?.length) continue;
119
+ const ctor = (classNode.body?.body || []).find((m) => m.type === "MethodDefinition" && m.kind === "constructor");
120
+ if (!ctor) continue;
121
+ const params = ctor.value?.params?.items || ctor.value?.params || [];
122
+ for (const param of params) {
123
+ const typeAnn = (param.type === "TSParameterProperty" ? param.parameter : param)?.typeAnnotation?.typeAnnotation ?? param?.typeAnnotation?.typeAnnotation;
124
+ if (!typeAnn) continue;
125
+ collectTypeReferenceNames(typeAnn, importedNames, valueReferenced);
126
+ }
127
+ }
128
+ }
129
+ /**
130
+ * Recursively extract identifier names from a TS type expression and mark
131
+ * any that match an imported name as value-referenced.
132
+ */
133
+ function collectTypeReferenceNames(typeNode, importedNames, valueReferenced) {
134
+ if (!typeNode || typeof typeNode !== "object") return;
135
+ if (typeNode.type === "TSTypeReference" && typeNode.typeName) {
136
+ const name = typeNode.typeName.name;
137
+ if (name && importedNames.has(name)) valueReferenced.add(name);
138
+ if (typeNode.typeArguments) collectTypeReferenceNames(typeNode.typeArguments, importedNames, valueReferenced);
139
+ } else if (typeNode.type === "TSUnionType" || typeNode.type === "TSIntersectionType") for (const t of typeNode.types || []) collectTypeReferenceNames(t, importedNames, valueReferenced);
140
+ else if (Array.isArray(typeNode)) for (const t of typeNode) collectTypeReferenceNames(t, importedNames, valueReferenced);
141
+ else if (typeNode.params) for (const t of typeNode.params) collectTypeReferenceNames(t, importedNames, valueReferenced);
142
+ }
143
+ /**
144
+ * Analyse compiled TypeScript source and return the set of imported names
145
+ * that are only referenced in type positions (type annotations, implements
146
+ * clauses, generics, etc.) and can safely be elided.
147
+ *
148
+ * Uses oxc-parser for fast, Rust-based AST analysis — no type-checker needed.
149
+ */
150
+ function detectTypeOnlyImportNames(code, program) {
151
+ return analyzeTypeOnlyImports(code, program).typeOnlyNames;
152
+ }
153
+ /**
154
+ * Apply import elision edits to a MagicString instance using positions from
155
+ * a parsed AST. Shared logic for both the string-based and MagicString APIs.
156
+ */
157
+ function applyElisionEdits(ms, ast, src, typeOnlyNames) {
158
+ let edited = false;
159
+ for (const node of ast.body) {
160
+ if (node.type !== "ImportDeclaration") continue;
161
+ if (node.importKind === "type") continue;
162
+ const allSpecs = node.specifiers ?? [];
163
+ const defaultSpec = allSpecs.find((s) => s.type === "ImportDefaultSpecifier");
164
+ const namedSpecs = allSpecs.filter((s) => s.type === "ImportSpecifier" && s.importKind !== "type");
165
+ const elideDefault = defaultSpec && typeOnlyNames.has(defaultSpec.local.name);
166
+ const keptNamed = namedSpecs.filter((s) => !typeOnlyNames.has(s.local.name));
167
+ const removingNamed = namedSpecs.length - keptNamed.length;
168
+ if (!elideDefault && removingNamed === 0) continue;
169
+ let declEnd = node.end;
170
+ while (declEnd < src.length && (src[declEnd] === "\n" || src[declEnd] === "\r")) declEnd++;
171
+ const keepDefault = defaultSpec && !elideDefault;
172
+ const hasKeptNamed = keptNamed.length > 0;
173
+ if (!keepDefault && !hasKeptNamed) {
174
+ ms.remove(node.start, declEnd);
175
+ edited = true;
176
+ } else {
177
+ const parts = [];
178
+ if (keepDefault) parts.push(defaultSpec.local.name);
179
+ if (hasKeptNamed) {
180
+ const namedList = keptNamed.map((s) => {
181
+ const imported = s.imported?.name ?? s.local.name;
182
+ return imported === s.local.name ? s.local.name : `${imported} as ${s.local.name}`;
183
+ });
184
+ parts.push(`{ ${namedList.join(", ")} }`);
185
+ }
186
+ const source = node.source.value;
187
+ const quote = src[node.source.start];
188
+ ms.overwrite(node.start, node.end, `import ${parts.join(", ")} from ${quote}${source}${quote};`);
189
+ edited = true;
190
+ }
191
+ }
192
+ return edited;
193
+ }
194
+ /**
195
+ * Elide type-only imports directly on a MagicString instance, so that
196
+ * subsequent `ms.generateMap()` calls produce an accurate sourcemap.
197
+ *
198
+ * Detects type-only names from `ms.toString()` (the fully-mutated code),
199
+ * but reads import positions from `ms.original` (the coordinate system
200
+ * MagicString expects). `originalProgram`, when provided, must be a parse
201
+ * of `ms.original` — never of the mutated text.
202
+ */
203
+ function elideTypeOnlyImportsMagicString(ms, originalProgram) {
204
+ const typeOnlyNames = detectTypeOnlyImportNames(ms.toString());
205
+ if (typeOnlyNames.size === 0) return;
206
+ applyElisionEdits(ms, originalProgram ?? parseSync("file.ts", ms.original).program, ms.original, typeOnlyNames);
207
+ }
208
+ //#endregion
209
+ export { detectTypeOnlyImportNames, elideTypeOnlyImportsMagicString };
210
+
211
+ //# sourceMappingURL=type-elision.js.map