@analogjs/vite-plugin-angular 3.0.0-alpha.4 → 3.0.0-alpha.40

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 (168) hide show
  1. package/README.md +28 -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 +25 -12
  11. package/src/index.d.ts +3 -2
  12. package/src/index.js +6 -2
  13. package/src/index.js.map +1 -1
  14. package/src/lib/angular-build-optimizer-plugin.d.ts +4 -4
  15. package/src/lib/angular-build-optimizer-plugin.js +48 -62
  16. package/src/lib/angular-build-optimizer-plugin.js.map +1 -1
  17. package/src/lib/angular-jit-plugin.d.ts +3 -3
  18. package/src/lib/angular-jit-plugin.js +42 -37
  19. package/src/lib/angular-jit-plugin.js.map +1 -1
  20. package/src/lib/angular-pending-tasks.plugin.d.ts +7 -7
  21. package/src/lib/angular-pending-tasks.plugin.js +17 -18
  22. package/src/lib/angular-pending-tasks.plugin.js.map +1 -1
  23. package/src/lib/angular-vite-plugin.d.ts +250 -40
  24. package/src/lib/angular-vite-plugin.js +2216 -964
  25. package/src/lib/angular-vite-plugin.js.map +1 -1
  26. package/src/lib/angular-vitest-plugin.d.ts +19 -15
  27. package/src/lib/angular-vitest-plugin.js +99 -114
  28. package/src/lib/angular-vitest-plugin.js.map +1 -1
  29. package/src/lib/compiler/angular-version.d.ts +19 -0
  30. package/src/lib/compiler/angular-version.js +16 -0
  31. package/src/lib/compiler/angular-version.js.map +1 -0
  32. package/src/lib/compiler/class-field-lowering.d.ts +23 -0
  33. package/src/lib/compiler/class-field-lowering.js +131 -0
  34. package/src/lib/compiler/class-field-lowering.js.map +1 -0
  35. package/src/lib/compiler/compile.d.ts +44 -0
  36. package/src/lib/compiler/compile.js +731 -0
  37. package/src/lib/compiler/compile.js.map +1 -0
  38. package/src/lib/compiler/constants.d.ts +18 -0
  39. package/src/lib/compiler/constants.js +52 -0
  40. package/src/lib/compiler/constants.js.map +1 -0
  41. package/src/lib/compiler/debug.d.ts +22 -0
  42. package/src/lib/compiler/debug.js +20 -0
  43. package/src/lib/compiler/debug.js.map +1 -0
  44. package/src/lib/compiler/defer.d.ts +47 -0
  45. package/src/lib/compiler/defer.js +138 -0
  46. package/src/lib/compiler/defer.js.map +1 -0
  47. package/src/lib/compiler/dts-reader.d.ts +35 -0
  48. package/src/lib/compiler/dts-reader.js +365 -0
  49. package/src/lib/compiler/dts-reader.js.map +1 -0
  50. package/src/lib/compiler/hmr.d.ts +16 -0
  51. package/src/lib/compiler/hmr.js +69 -0
  52. package/src/lib/compiler/hmr.js.map +1 -0
  53. package/src/lib/compiler/index.d.ts +7 -0
  54. package/src/lib/compiler/index.js +7 -0
  55. package/src/lib/compiler/jit-metadata.d.ts +14 -0
  56. package/src/lib/compiler/jit-metadata.js +146 -0
  57. package/src/lib/compiler/jit-metadata.js.map +1 -0
  58. package/src/lib/compiler/jit-transform.d.ts +24 -0
  59. package/src/lib/compiler/jit-transform.js +200 -0
  60. package/src/lib/compiler/jit-transform.js.map +1 -0
  61. package/src/lib/compiler/js-emitter.d.ts +10 -0
  62. package/src/lib/compiler/js-emitter.js +420 -0
  63. package/src/lib/compiler/js-emitter.js.map +1 -0
  64. package/src/lib/compiler/metadata.d.ts +45 -0
  65. package/src/lib/compiler/metadata.js +633 -0
  66. package/src/lib/compiler/metadata.js.map +1 -0
  67. package/src/lib/compiler/registry.d.ts +49 -0
  68. package/src/lib/compiler/registry.js +164 -0
  69. package/src/lib/compiler/registry.js.map +1 -0
  70. package/src/lib/compiler/resource-inliner.d.ts +21 -0
  71. package/src/lib/compiler/resource-inliner.js +152 -0
  72. package/src/lib/compiler/resource-inliner.js.map +1 -0
  73. package/src/lib/compiler/style-ast.d.ts +8 -0
  74. package/src/lib/compiler/style-ast.js +54 -0
  75. package/src/lib/compiler/style-ast.js.map +1 -0
  76. package/src/lib/compiler/styles.d.ts +13 -0
  77. package/src/lib/compiler/test-helpers.d.ts +7 -0
  78. package/src/lib/compiler/type-elision.d.ts +26 -0
  79. package/src/lib/compiler/type-elision.js +211 -0
  80. package/src/lib/compiler/type-elision.js.map +1 -0
  81. package/src/lib/compiler/utils.d.ts +10 -0
  82. package/src/lib/compiler/utils.js +35 -0
  83. package/src/lib/compiler/utils.js.map +1 -0
  84. package/src/lib/compiler-plugin.d.ts +11 -11
  85. package/src/lib/compiler-plugin.js +43 -44
  86. package/src/lib/compiler-plugin.js.map +1 -1
  87. package/src/lib/component-resolvers.d.ts +23 -5
  88. package/src/lib/component-resolvers.js +153 -63
  89. package/src/lib/component-resolvers.js.map +1 -1
  90. package/src/lib/fast-compile-plugin.d.ts +14 -0
  91. package/src/lib/fast-compile-plugin.js +270 -0
  92. package/src/lib/fast-compile-plugin.js.map +1 -0
  93. package/src/lib/host.d.ts +10 -8
  94. package/src/lib/host.js +111 -101
  95. package/src/lib/host.js.map +1 -1
  96. package/src/lib/live-reload-plugin.d.ts +5 -5
  97. package/src/lib/live-reload-plugin.js +61 -62
  98. package/src/lib/live-reload-plugin.js.map +1 -1
  99. package/src/lib/models.d.ts +9 -9
  100. package/src/lib/nx-folder-plugin.d.ts +5 -5
  101. package/src/lib/nx-folder-plugin.js +18 -16
  102. package/src/lib/nx-folder-plugin.js.map +1 -1
  103. package/src/lib/plugins/file-replacements.plugin.d.ts +4 -4
  104. package/src/lib/plugins/file-replacements.plugin.js +40 -62
  105. package/src/lib/plugins/file-replacements.plugin.js.map +1 -1
  106. package/src/lib/router-plugin.d.ts +1 -1
  107. package/src/lib/router-plugin.js +23 -23
  108. package/src/lib/router-plugin.js.map +1 -1
  109. package/src/lib/style-pipeline.d.ts +15 -0
  110. package/src/lib/style-pipeline.js +31 -0
  111. package/src/lib/style-pipeline.js.map +1 -0
  112. package/src/lib/style-preprocessor.d.ts +35 -0
  113. package/src/lib/style-preprocessor.js +35 -0
  114. package/src/lib/style-preprocessor.js.map +1 -0
  115. package/src/lib/stylesheet-registry.d.ts +73 -0
  116. package/src/lib/stylesheet-registry.js +168 -0
  117. package/src/lib/stylesheet-registry.js.map +1 -0
  118. package/src/lib/tools/package.json +2 -7
  119. package/src/lib/tools/src/builders/vite/vite-build.impl.js +31 -38
  120. package/src/lib/tools/src/builders/vite/vite-build.impl.js.map +1 -1
  121. package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.js +51 -62
  122. package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.js.map +1 -1
  123. package/src/lib/tools/src/index.js +0 -2
  124. package/src/lib/utils/compiler-plugin-options.d.ts +11 -11
  125. package/src/lib/utils/debug-harness.d.ts +23 -0
  126. package/src/lib/utils/debug-harness.js +88 -0
  127. package/src/lib/utils/debug-harness.js.map +1 -0
  128. package/src/lib/utils/debug-log-file.d.ts +5 -0
  129. package/src/lib/utils/debug-log-file.js +56 -0
  130. package/src/lib/utils/debug-log-file.js.map +1 -0
  131. package/src/lib/utils/debug.d.ts +28 -0
  132. package/src/lib/utils/debug.js +39 -0
  133. package/src/lib/utils/debug.js.map +1 -0
  134. package/src/lib/utils/devkit.d.ts +6 -6
  135. package/src/lib/utils/devkit.js +34 -38
  136. package/src/lib/utils/devkit.js.map +1 -1
  137. package/src/lib/utils/hmr-candidates.d.ts +28 -28
  138. package/src/lib/utils/plugin-config.d.ts +30 -0
  139. package/src/lib/utils/plugin-config.js +64 -0
  140. package/src/lib/utils/plugin-config.js.map +1 -0
  141. package/src/lib/utils/rolldown.d.ts +2 -0
  142. package/src/lib/utils/rolldown.js +12 -0
  143. package/src/lib/utils/rolldown.js.map +1 -0
  144. package/src/lib/utils/source-file-cache.d.ts +8 -15
  145. package/src/lib/utils/source-file-cache.js +35 -37
  146. package/src/lib/utils/source-file-cache.js.map +1 -1
  147. package/src/lib/utils/tailwind-reference.d.ts +12 -0
  148. package/src/lib/utils/tailwind-reference.js +99 -0
  149. package/src/lib/utils/tailwind-reference.js.map +1 -0
  150. package/src/lib/utils/virtual-ids.d.ts +8 -0
  151. package/src/lib/utils/virtual-ids.js +35 -0
  152. package/src/lib/utils/virtual-ids.js.map +1 -0
  153. package/src/lib/utils/virtual-resources.d.ts +47 -0
  154. package/src/lib/utils/virtual-resources.js +89 -0
  155. package/src/lib/utils/virtual-resources.js.map +1 -0
  156. package/src/test-setup.d.ts +2 -0
  157. package/setup-vitest.d.ts +0 -4
  158. package/setup-vitest.js +0 -215
  159. package/setup-vitest.js.map +0 -1
  160. package/src/lib/models.js +0 -1
  161. package/src/lib/models.js.map +0 -1
  162. package/src/lib/tools/README.md +0 -3
  163. package/src/lib/tools/src/index.d.ts +0 -0
  164. package/src/lib/tools/src/index.js.map +0 -1
  165. package/src/lib/utils/compiler-plugin-options.js +0 -1
  166. package/src/lib/utils/compiler-plugin-options.js.map +0 -1
  167. package/src/lib/utils/hmr-candidates.js +0 -272
  168. package/src/lib/utils/hmr-candidates.js.map +0 -1
@@ -1,22 +1,26 @@
1
- import { Plugin } from 'vite';
1
+ import type { Plugin } from "vite";
2
2
  /**
3
- * Sets up test config for Vitest
4
- * and downlevels any dependencies that use
5
- * async/await to support zone.js testing
6
- * and tests w/fakeAsync
7
- */
3
+ * Sets up test config for Vitest and downlevels Angular FESM bundles and
4
+ * `@angular/cdk` from modern async/await to ES2016 so that Zone.js can
5
+ * intercept promises during `fakeAsync` tests.
6
+ *
7
+ * Under Vite 8+ (Rolldown) downleveling is not needed.
8
+ * Under Vite ≤7, esbuild handles the downlevel.
9
+ */
8
10
  export declare function angularVitestPlugin(): Plugin;
9
11
  /**
10
- * This eagerly disables esbuild so Vitest
11
- * disables it when its internal plugin
12
- * is configured.
13
- */
12
+ * Eagerly disables the built-in JS transformer (esbuild on Vite ≤7, OXC on
13
+ * Vite 8+) so Vitest's internal plugin doesn't race with the Angular
14
+ * compiler. Must run at `enforce: 'pre'` to take effect before Vitest
15
+ * reads the resolved config.
16
+ */
14
17
  export declare function angularVitestEsbuildPlugin(): Plugin;
15
18
  /**
16
- * This plugin does post-processing with esbuild
17
- * instead of preprocessing to re-align
18
- * the sourcemaps so breakpoints and coverage reports
19
- * work correctly.
20
- */
19
+ * Post-processes `.ts` files with the JS transformer (esbuild / OXC) to
20
+ * re-align sourcemaps so breakpoints and coverage reports work correctly.
21
+ *
22
+ * Inline style/template virtual modules (`?inline`) are excluded because
23
+ * they are already handled by the Angular compiler.
24
+ */
21
25
  export declare function angularVitestSourcemapPlugin(): Plugin;
22
26
  export declare function angularVitestPlugins(): Plugin[];
@@ -1,122 +1,107 @@
1
- import * as vite from 'vite';
1
+ import { getJsTransformConfigKey, isRolldown } from "./utils/rolldown.js";
2
+ import * as vite from "vite";
3
+ //#region packages/vite-plugin-angular/src/lib/angular-vitest-plugin.ts
4
+ var vitestAngularSetupEntries = [
5
+ "@analogjs/vitest-angular/setup-testbed",
6
+ "@analogjs/vitest-angular/setup-zone",
7
+ "@analogjs/vitest-angular/setup-snapshots",
8
+ "@analogjs/vitest-angular/setup-serializers"
9
+ ];
2
10
  /**
3
- * Sets up test config for Vitest
4
- * and downlevels any dependencies that use
5
- * async/await to support zone.js testing
6
- * and tests w/fakeAsync
7
- */
8
- export function angularVitestPlugin() {
9
- return {
10
- name: '@analogjs/vitest-angular-esm-plugin',
11
- apply: 'serve',
12
- enforce: 'post',
13
- config(userConfig) {
14
- return {
15
- optimizeDeps: {
16
- include: ['tslib'],
17
- },
18
- ssr: {
19
- noExternal: [
20
- '@analogjs/vitest-angular/setup-testbed',
21
- /fesm2022(.*?)testing/,
22
- /fesm2015/,
23
- ],
24
- },
25
- test: {
26
- pool: userConfig.test?.pool ?? 'vmThreads',
27
- },
28
- };
29
- },
30
- async transform(_code, id) {
31
- if ((/fesm2022/.test(id) && _code.includes('async ')) ||
32
- _code.includes('@angular/cdk')) {
33
- if (vite.rolldownVersion) {
34
- const { code, map } = await vite.transformWithOxc(_code, id, {
35
- lang: 'js',
36
- target: 'es2016',
37
- sourcemap: true,
38
- });
39
- return {
40
- code,
41
- map,
42
- };
43
- }
44
- else {
45
- const { code, map } = await vite.transformWithEsbuild(_code, id, {
46
- loader: 'js',
47
- format: 'esm',
48
- target: 'es2016',
49
- sourcemap: true,
50
- sourcefile: id,
51
- });
52
- return {
53
- code,
54
- map,
55
- };
56
- }
57
- }
58
- return undefined;
59
- },
60
- };
11
+ * Sets up test config for Vitest and downlevels Angular FESM bundles and
12
+ * `@angular/cdk` from modern async/await to ES2016 so that Zone.js can
13
+ * intercept promises during `fakeAsync` tests.
14
+ *
15
+ * Under Vite 8+ (Rolldown) downleveling is not needed.
16
+ * Under Vite ≤7, esbuild handles the downlevel.
17
+ */
18
+ function angularVitestPlugin() {
19
+ return {
20
+ name: "@analogjs/vitest-angular-esm-plugin",
21
+ apply: "serve",
22
+ enforce: "post",
23
+ config(userConfig) {
24
+ return {
25
+ optimizeDeps: { include: [
26
+ "tslib",
27
+ "@angular/core",
28
+ "@angular/core/testing",
29
+ "@angular/platform-browser/testing"
30
+ ] },
31
+ ssr: { noExternal: [
32
+ ...vitestAngularSetupEntries,
33
+ /fesm2022(.*?)testing/,
34
+ /fesm2015/
35
+ ] },
36
+ test: { pool: userConfig.test?.pool ?? "vmThreads" }
37
+ };
38
+ },
39
+ transform: {
40
+ filter: { id: /fesm2022|@angular\/cdk/ },
41
+ async handler(_code, id) {
42
+ if (/fesm2022/.test(id) && _code.includes("async ") || _code.includes("@angular/cdk")) {
43
+ if (isRolldown()) return;
44
+ const { code, map } = await vite.transformWithEsbuild(_code, id, {
45
+ loader: "js",
46
+ format: "esm",
47
+ target: "es2016",
48
+ sourcemap: true,
49
+ sourcefile: id
50
+ });
51
+ return {
52
+ code,
53
+ map
54
+ };
55
+ }
56
+ }
57
+ }
58
+ };
61
59
  }
62
60
  /**
63
- * This eagerly disables esbuild so Vitest
64
- * disables it when its internal plugin
65
- * is configured.
66
- */
67
- export function angularVitestEsbuildPlugin() {
68
- return {
69
- name: '@analogjs/vitest-angular-esbuild-oxc-plugin',
70
- enforce: 'pre',
71
- config(userConfig) {
72
- if (vite.rolldownVersion) {
73
- return {
74
- oxc: userConfig.oxc ?? false,
75
- };
76
- }
77
- return {
78
- esbuild: userConfig.esbuild ?? false,
79
- };
80
- },
81
- };
61
+ * Eagerly disables the built-in JS transformer (esbuild on Vite ≤7, OXC on
62
+ * Vite 8+) so Vitest's internal plugin doesn't race with the Angular
63
+ * compiler. Must run at `enforce: 'pre'` to take effect before Vitest
64
+ * reads the resolved config.
65
+ */
66
+ function angularVitestEsbuildPlugin() {
67
+ return {
68
+ name: "@analogjs/vitest-angular-esbuild-oxc-plugin",
69
+ enforce: "pre",
70
+ config(userConfig) {
71
+ const jsTransformConfigKey = getJsTransformConfigKey();
72
+ return { [jsTransformConfigKey]: jsTransformConfigKey === "oxc" ? userConfig.oxc ?? false : userConfig.esbuild ?? false };
73
+ }
74
+ };
82
75
  }
83
76
  /**
84
- * This plugin does post-processing with esbuild
85
- * instead of preprocessing to re-align
86
- * the sourcemaps so breakpoints and coverage reports
87
- * work correctly.
88
- */
89
- export function angularVitestSourcemapPlugin() {
90
- return {
91
- name: '@analogjs/vitest-angular-sourcemap-plugin',
92
- async transform(code, id) {
93
- if (!/\.ts/.test(id)) {
94
- return;
95
- }
96
- const [, query] = id.split('?');
97
- if (query && query.includes('inline')) {
98
- return;
99
- }
100
- if (vite.rolldownVersion) {
101
- const result = await vite.transformWithOxc(code, id, {
102
- lang: 'js',
103
- });
104
- return result;
105
- }
106
- else {
107
- const result = await vite.transformWithEsbuild(code, id, {
108
- loader: 'js',
109
- });
110
- return result;
111
- }
112
- },
113
- };
77
+ * Post-processes `.ts` files with the JS transformer (esbuild / OXC) to
78
+ * re-align sourcemaps so breakpoints and coverage reports work correctly.
79
+ *
80
+ * Inline style/template virtual modules (`?inline`) are excluded because
81
+ * they are already handled by the Angular compiler.
82
+ */
83
+ function angularVitestSourcemapPlugin() {
84
+ return {
85
+ name: "@analogjs/vitest-angular-sourcemap-plugin",
86
+ transform: {
87
+ filter: { id: /\.ts(?:\?|$)/ },
88
+ async handler(code, id) {
89
+ const [, query] = id.split("?");
90
+ if (query && query.includes("inline")) return;
91
+ if (isRolldown()) return await vite.transformWithOxc(code, id, { lang: "ts" });
92
+ else return await vite.transformWithEsbuild(code, id, { loader: "ts" });
93
+ }
94
+ }
95
+ };
114
96
  }
115
- export function angularVitestPlugins() {
116
- return [
117
- angularVitestPlugin(),
118
- angularVitestEsbuildPlugin(),
119
- angularVitestSourcemapPlugin(),
120
- ];
97
+ function angularVitestPlugins() {
98
+ return [
99
+ angularVitestPlugin(),
100
+ angularVitestEsbuildPlugin(),
101
+ angularVitestSourcemapPlugin()
102
+ ];
121
103
  }
104
+ //#endregion
105
+ export { angularVitestPlugins };
106
+
122
107
  //# sourceMappingURL=angular-vitest-plugin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"angular-vitest-plugin.js","sourceRoot":"","sources":["../../../../../packages/vite-plugin-angular/src/lib/angular-vitest-plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"angular-vitest-plugin.js","names":[],"sources":["../../../src/lib/angular-vitest-plugin.ts"],"sourcesContent":["import type { Plugin, TransformResult, UserConfig } from 'vite';\n// Use the namespace import so these runtime helpers still resolve on Vite 6,\n// which does not expose them as named exports.\nimport * as vite from 'vite';\nimport { getJsTransformConfigKey, isRolldown } from './utils/rolldown.js';\n\nconst vitestAngularSetupEntries = [\n '@analogjs/vitest-angular/setup-testbed',\n '@analogjs/vitest-angular/setup-zone',\n '@analogjs/vitest-angular/setup-snapshots',\n '@analogjs/vitest-angular/setup-serializers',\n];\n\n/**\n * Sets up test config for Vitest and downlevels Angular FESM bundles and\n * `@angular/cdk` from modern async/await to ES2016 so that Zone.js can\n * intercept promises during `fakeAsync` tests.\n *\n * Under Vite 8+ (Rolldown) downleveling is not needed.\n * Under Vite ≤7, esbuild handles the downlevel.\n */\nexport function angularVitestPlugin(): Plugin {\n return {\n name: '@analogjs/vitest-angular-esm-plugin',\n apply: 'serve',\n enforce: 'post',\n config(userConfig) {\n return {\n optimizeDeps: {\n include: [\n 'tslib',\n '@angular/core',\n '@angular/core/testing',\n '@angular/platform-browser/testing',\n ],\n },\n ssr: {\n noExternal: [\n ...vitestAngularSetupEntries,\n /fesm2022(.*?)testing/,\n /fesm2015/,\n ],\n },\n test: {\n pool: (userConfig as any).test?.pool ?? 'vmThreads',\n },\n };\n },\n // Filter by module ID so only Angular FESM2022 bundles and CDK enter\n // the handler. The inner guards add a secondary code-content check\n // (`async` keyword) for fesm2022 to avoid needless transforms.\n transform: {\n filter: {\n id: /fesm2022|@angular\\/cdk/,\n },\n async handler(_code, id) {\n if (\n (/fesm2022/.test(id) && _code.includes('async ')) ||\n _code.includes('@angular/cdk')\n ) {\n if (isRolldown()) {\n return undefined;\n }\n\n const { code, map } = await vite.transformWithEsbuild(_code, id, {\n loader: 'js',\n format: 'esm',\n target: 'es2016',\n sourcemap: true,\n sourcefile: id,\n });\n\n return {\n code,\n map,\n };\n }\n\n return undefined;\n },\n },\n };\n}\n\n/**\n * Eagerly disables the built-in JS transformer (esbuild on Vite ≤7, OXC on\n * Vite 8+) so Vitest's internal plugin doesn't race with the Angular\n * compiler. Must run at `enforce: 'pre'` to take effect before Vitest\n * reads the resolved config.\n */\nexport function angularVitestEsbuildPlugin(): Plugin {\n return {\n name: '@analogjs/vitest-angular-esbuild-oxc-plugin',\n enforce: 'pre',\n config(userConfig: UserConfig) {\n const jsTransformConfigKey = getJsTransformConfigKey();\n\n return {\n [jsTransformConfigKey]:\n jsTransformConfigKey === 'oxc'\n ? (userConfig.oxc ?? false)\n : (userConfig.esbuild ?? false),\n };\n },\n };\n}\n\n/**\n * Post-processes `.ts` files with the JS transformer (esbuild / OXC) to\n * re-align sourcemaps so breakpoints and coverage reports work correctly.\n *\n * Inline style/template virtual modules (`?inline`) are excluded because\n * they are already handled by the Angular compiler.\n */\nexport function angularVitestSourcemapPlugin(): Plugin {\n return {\n name: '@analogjs/vitest-angular-sourcemap-plugin',\n transform: {\n filter: {\n // Match `.ts` at the end of the path OR before a `?` query string.\n // Vite/Vitest appends query params for virtual modules (e.g.\n // `component.ts?inline`), so a plain `$` anchor would reject them\n // and leave sourcemaps misaligned — causing Angular TestBed teardown\n // crashes (`_doc` undefined in `removeAllRootElements`).\n // The negative lookahead `(?!x)` prevents matching `.tsx` or `.d.ts`.\n id: /\\.ts(?:\\?|$)/,\n },\n async handler(code: string, id: string) {\n const [, query] = id.split('?');\n\n if (query && query.includes('inline')) {\n return;\n }\n\n if (isRolldown()) {\n // lang must be 'ts' (not 'js') so OXC parses TypeScript syntax;\n // using 'js' would cause parse errors on type annotations.\n const result = await vite.transformWithOxc(code, id, {\n lang: 'ts',\n });\n\n return result as unknown as TransformResult;\n } else {\n const result = await vite.transformWithEsbuild(code, id, {\n loader: 'ts',\n });\n\n return result;\n }\n },\n },\n };\n}\n\nexport function angularVitestPlugins(): Plugin[] {\n return [\n angularVitestPlugin(),\n angularVitestEsbuildPlugin(),\n angularVitestSourcemapPlugin(),\n ];\n}\n"],"mappings":";;;AAMA,IAAM,4BAA4B;CAChC;CACA;CACA;CACA;CACD;;;;;;;;;AAUD,SAAgB,sBAA8B;AAC5C,QAAO;EACL,MAAM;EACN,OAAO;EACP,SAAS;EACT,OAAO,YAAY;AACjB,UAAO;IACL,cAAc,EACZ,SAAS;KACP;KACA;KACA;KACA;KACD,EACF;IACD,KAAK,EACH,YAAY;KACV,GAAG;KACH;KACA;KACD,EACF;IACD,MAAM,EACJ,MAAO,WAAmB,MAAM,QAAQ,aACzC;IACF;;EAKH,WAAW;GACT,QAAQ,EACN,IAAI,0BACL;GACD,MAAM,QAAQ,OAAO,IAAI;AACvB,QACG,WAAW,KAAK,GAAG,IAAI,MAAM,SAAS,SAAS,IAChD,MAAM,SAAS,eAAe,EAC9B;AACA,SAAI,YAAY,CACd;KAGF,MAAM,EAAE,MAAM,QAAQ,MAAM,KAAK,qBAAqB,OAAO,IAAI;MAC/D,QAAQ;MACR,QAAQ;MACR,QAAQ;MACR,WAAW;MACX,YAAY;MACb,CAAC;AAEF,YAAO;MACL;MACA;MACD;;;GAKN;EACF;;;;;;;;AASH,SAAgB,6BAAqC;AACnD,QAAO;EACL,MAAM;EACN,SAAS;EACT,OAAO,YAAwB;GAC7B,MAAM,uBAAuB,yBAAyB;AAEtD,UAAO,GACJ,uBACC,yBAAyB,QACpB,WAAW,OAAO,QAClB,WAAW,WAAW,OAC9B;;EAEJ;;;;;;;;;AAUH,SAAgB,+BAAuC;AACrD,QAAO;EACL,MAAM;EACN,WAAW;GACT,QAAQ,EAON,IAAI,gBACL;GACD,MAAM,QAAQ,MAAc,IAAY;IACtC,MAAM,GAAG,SAAS,GAAG,MAAM,IAAI;AAE/B,QAAI,SAAS,MAAM,SAAS,SAAS,CACnC;AAGF,QAAI,YAAY,CAOd,QAJe,MAAM,KAAK,iBAAiB,MAAM,IAAI,EACnD,MAAM,MACP,CAAC;QAQF,QAJe,MAAM,KAAK,qBAAqB,MAAM,IAAI,EACvD,QAAQ,MACT,CAAC;;GAKP;EACF;;AAGH,SAAgB,uBAAiC;AAC/C,QAAO;EACL,qBAAqB;EACrB,4BAA4B;EAC5B,8BAA8B;EAC/B"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The major version of the installed `@angular/compiler` package, parsed
3
+ * from `o.VERSION.major`. Falls back to `DEFAULT_ASSUMED_MAJOR` when the
4
+ * version is unavailable.
5
+ */
6
+ export declare const ANGULAR_MAJOR: number;
7
+ /**
8
+ * Returns `true` when the installed Angular major is at least `major`.
9
+ * Use this to gate code paths that depend on APIs introduced in a
10
+ * specific Angular release.
11
+ *
12
+ * @example
13
+ * if (angularVersionAtLeast(21)) {
14
+ * // Use Angular 21+ API
15
+ * } else {
16
+ * // Fall back to v19/v20 behavior
17
+ * }
18
+ */
19
+ export declare function angularVersionAtLeast(major: number): boolean;
@@ -0,0 +1,16 @@
1
+ import * as o from "@angular/compiler";
2
+ //#region packages/vite-plugin-angular/src/lib/compiler/angular-version.ts
3
+ var DEFAULT_ASSUMED_MAJOR = 22;
4
+ /**
5
+ * The major version of the installed `@angular/compiler` package, parsed
6
+ * from `o.VERSION.major`. Falls back to `DEFAULT_ASSUMED_MAJOR` when the
7
+ * version is unavailable.
8
+ */
9
+ var ANGULAR_MAJOR = (() => {
10
+ const major = Number.parseInt(o.VERSION?.major ?? "", 10);
11
+ return Number.isFinite(major) && major > 0 ? major : DEFAULT_ASSUMED_MAJOR;
12
+ })();
13
+ //#endregion
14
+ export { ANGULAR_MAJOR };
15
+
16
+ //# sourceMappingURL=angular-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"angular-version.js","names":[],"sources":["../../../../src/lib/compiler/angular-version.ts"],"sourcesContent":["import * as o from '@angular/compiler';\n\n// Detect the installed @angular/compiler major version once at module load\n// time and expose helpers for version-aware code paths.\n//\n// Why this matters: Angular's compiler API surface (enum members,\n// metadata shapes, output formats) shifts between major versions in ways\n// that can't always be papered over with duck typing. The compatibility\n// matrix in .github/workflows/compiler-compat.yml runs the test\n// suite against multiple installed versions to catch this drift, and the\n// version-aware code paths in compile.ts / js-emitter.ts / metadata.ts\n// gate behavior on `ANGULAR_MAJOR` to keep the compiler working across\n// the supported `peerDependencies` range (currently >=19.0.0).\n//\n// Default fallback: when the version string is missing or unparseable\n// (vendored builds, monkey-patched test environments), assume the latest\n// known major. This biases toward the most-tested code path.\nconst DEFAULT_ASSUMED_MAJOR = 22;\n\n/**\n * The major version of the installed `@angular/compiler` package, parsed\n * from `o.VERSION.major`. Falls back to `DEFAULT_ASSUMED_MAJOR` when the\n * version is unavailable.\n */\nexport const ANGULAR_MAJOR: number = (() => {\n const major = Number.parseInt(o.VERSION?.major ?? '', 10);\n return Number.isFinite(major) && major > 0 ? major : DEFAULT_ASSUMED_MAJOR;\n})();\n\n/**\n * Returns `true` when the installed Angular major is at least `major`.\n * Use this to gate code paths that depend on APIs introduced in a\n * specific Angular release.\n *\n * @example\n * if (angularVersionAtLeast(21)) {\n * // Use Angular 21+ API\n * } else {\n * // Fall back to v19/v20 behavior\n * }\n */\nexport function angularVersionAtLeast(major: number): boolean {\n return ANGULAR_MAJOR >= major;\n}\n"],"mappings":";;AAiBA,IAAM,wBAAwB;;;;;;AAO9B,IAAa,uBAA+B;CAC1C,MAAM,QAAQ,OAAO,SAAS,EAAE,SAAS,SAAS,IAAI,GAAG;AACzD,QAAO,OAAO,SAAS,MAAM,IAAI,QAAQ,IAAI,QAAQ;IACnD"}
@@ -0,0 +1,23 @@
1
+ import MagicString from "magic-string";
2
+ /**
3
+ * Lower instance class field initializers into constructor assignments.
4
+ *
5
+ * When `useDefineForClassFields` is `false` (the standard Angular tsconfig),
6
+ * field initializers must run as assignments inside the constructor body
7
+ * rather than as native ES class field initializers. This ensures:
8
+ *
9
+ * 1. `inject()` calls in fields have an active injection context
10
+ * 2. Fields referencing other injected fields work (sequential assignment)
11
+ * 3. Constructor parameter properties are available to field initializers
12
+ * 4. Inheritance works (parent constructor runs before child field assignments)
13
+ *
14
+ * Rules:
15
+ * - Regular fields with initializers: remove declaration, add `this.field = value;`
16
+ * - Private fields (`#field`) with initializers: keep `#field;` declaration, add `this.#field = value;`
17
+ * - Static fields: not lowered
18
+ * - Fields without initializers: not lowered
19
+ * - `declare` fields: not lowered
20
+ * - Assignments are inserted after `super()` (if present), before existing constructor body
21
+ * - If no constructor exists, one is created (with `super(...args)` for subclasses)
22
+ */
23
+ export declare function lowerClassFields(ms: MagicString, sourceCode: string, oxcProgram: any): void;
@@ -0,0 +1,131 @@
1
+ //#region packages/vite-plugin-angular/src/lib/compiler/class-field-lowering.ts
2
+ /**
3
+ * Lower instance class field initializers into constructor assignments.
4
+ *
5
+ * When `useDefineForClassFields` is `false` (the standard Angular tsconfig),
6
+ * field initializers must run as assignments inside the constructor body
7
+ * rather than as native ES class field initializers. This ensures:
8
+ *
9
+ * 1. `inject()` calls in fields have an active injection context
10
+ * 2. Fields referencing other injected fields work (sequential assignment)
11
+ * 3. Constructor parameter properties are available to field initializers
12
+ * 4. Inheritance works (parent constructor runs before child field assignments)
13
+ *
14
+ * Rules:
15
+ * - Regular fields with initializers: remove declaration, add `this.field = value;`
16
+ * - Private fields (`#field`) with initializers: keep `#field;` declaration, add `this.#field = value;`
17
+ * - Static fields: not lowered
18
+ * - Fields without initializers: not lowered
19
+ * - `declare` fields: not lowered
20
+ * - Assignments are inserted after `super()` (if present), before existing constructor body
21
+ * - If no constructor exists, one is created (with `super(...args)` for subclasses)
22
+ */
23
+ function lowerClassFields(ms, sourceCode, oxcProgram) {
24
+ for (const stmt of oxcProgram.body) {
25
+ const decl = stmt.type === "ExportNamedDeclaration" || stmt.type === "ExportDefaultDeclaration" ? stmt.declaration : stmt;
26
+ if (!decl || decl.type !== "ClassDeclaration" && decl.type !== "ClassExpression" || !decl.body) continue;
27
+ lowerClassFieldsForClass(ms, sourceCode, decl);
28
+ }
29
+ }
30
+ function lowerClassFieldsForClass(ms, sourceCode, classNode) {
31
+ const body = classNode.body;
32
+ const members = body.body;
33
+ const fieldsToLower = [];
34
+ for (const member of members) {
35
+ if (!shouldLowerField(member)) continue;
36
+ const accessor = getFieldAccessor(member, sourceCode);
37
+ const initializer = sourceCode.slice(member.value.start, member.value.end);
38
+ fieldsToLower.push({
39
+ node: member,
40
+ accessor,
41
+ initializer,
42
+ isPrivate: member.type === "PropertyDefinition" && member.key?.type === "PrivateIdentifier"
43
+ });
44
+ }
45
+ if (fieldsToLower.length === 0) return;
46
+ const assignments = fieldsToLower.map((f) => ` this${f.accessor} = ${f.initializer};`);
47
+ const ctor = members.find((m) => m.type === "MethodDefinition" && m.kind === "constructor");
48
+ const hasSuperClass = !!classNode.superClass;
49
+ if (ctor) insertIntoExistingConstructor(ms, sourceCode, ctor, assignments);
50
+ else createConstructorWithAssignments(ms, sourceCode, body, members, assignments, hasSuperClass);
51
+ for (const field of fieldsToLower) if (field.isPrivate) {
52
+ const eqStart = findEqualsSign(sourceCode, field.node.typeAnnotation ? field.node.typeAnnotation.end : field.node.key.end, field.node.value.start);
53
+ ms.remove(eqStart, field.node.value.end);
54
+ } else {
55
+ let end = field.node.end;
56
+ const nextChar = sourceCode[end];
57
+ const charAfterNewline = nextChar === "\n" ? sourceCode[end + 1] : nextChar === "\r" && sourceCode[end + 1] === "\n" ? sourceCode[end + 2] : null;
58
+ if (charAfterNewline !== null && charAfterNewline !== "}") {
59
+ if (nextChar === "\n") end++;
60
+ else if (nextChar === "\r" && sourceCode[end + 1] === "\n") end += 2;
61
+ }
62
+ ms.remove(field.node.start, end);
63
+ }
64
+ }
65
+ function shouldLowerField(member) {
66
+ if (member.type !== "PropertyDefinition") return false;
67
+ if (!member.value) return false;
68
+ if (member.static) return false;
69
+ if (member.declare) return false;
70
+ return true;
71
+ }
72
+ /**
73
+ * Build the member-access expression to append after `this` for a class field
74
+ * being lowered. Returns the accessor with its leading punctuation:
75
+ *
76
+ * - `.name` — non-computed identifier key
77
+ * - `.#priv` — private identifier key
78
+ * - `[expr]` — computed key (square brackets in source)
79
+ * - `['some-key']` — string literal key
80
+ * - `[123]` — numeric literal key
81
+ *
82
+ * Without this, fields with non-identifier keys produced invalid syntax like
83
+ * `this.'some-key' = …` which OXC parses as "Cannot assign to this expression".
84
+ */
85
+ function getFieldAccessor(member, sourceCode) {
86
+ const key = member.key;
87
+ if (key.type === "PrivateIdentifier") return ".#" + key.name;
88
+ if (member.computed) return "[" + sourceCode.slice(key.start, key.end) + "]";
89
+ if (key.type === "Identifier") return "." + key.name;
90
+ if (key.type === "StringLiteral" || key.type === "Literal" && typeof key.value === "string") return "[" + JSON.stringify(key.value) + "]";
91
+ if (key.type === "NumericLiteral" || key.type === "Literal" && typeof key.value === "number") return "[" + key.value + "]";
92
+ return "[" + sourceCode.slice(key.start, key.end) + "]";
93
+ }
94
+ function findEqualsSign(sourceCode, from, to) {
95
+ for (let i = from; i < to; i++) if (sourceCode[i] === "=") return i;
96
+ return from;
97
+ }
98
+ function insertIntoExistingConstructor(ms, sourceCode, ctor, assignments) {
99
+ const ctorBody = ctor.value.body;
100
+ if (!ctorBody) return;
101
+ const bodyStatements = ctorBody.body;
102
+ const assignmentBlock = "\n" + assignments.join("\n");
103
+ let insertPos = null;
104
+ for (const stmt of bodyStatements) if (isSuperCall(stmt)) {
105
+ insertPos = stmt.end;
106
+ break;
107
+ }
108
+ if (insertPos !== null) ms.appendRight(insertPos, assignmentBlock);
109
+ else if (bodyStatements.length > 0) ms.appendRight(bodyStatements[0].start, assignments.join("\n") + "\n ");
110
+ else ms.appendRight(ctorBody.start + 1, assignmentBlock + "\n ");
111
+ }
112
+ function createConstructorWithAssignments(ms, sourceCode, classBody, members, assignments, hasSuperClass) {
113
+ const superCall = hasSuperClass ? " super(...args);\n" : "";
114
+ const ctorCode = [
115
+ ` constructor(${hasSuperClass ? "...args" : ""}) {`,
116
+ superCall ? superCall.trimEnd() : null,
117
+ ...assignments,
118
+ " }"
119
+ ].filter((l) => l !== null).join("\n");
120
+ ms.appendRight(classBody.start + 1, "\n" + ctorCode + "\n");
121
+ }
122
+ function isSuperCall(stmt) {
123
+ if (stmt.type !== "ExpressionStatement") return false;
124
+ const expr = stmt.expression;
125
+ if (expr.type !== "CallExpression") return false;
126
+ return expr.callee?.type === "Super";
127
+ }
128
+ //#endregion
129
+ export { lowerClassFields };
130
+
131
+ //# sourceMappingURL=class-field-lowering.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"class-field-lowering.js","names":[],"sources":["../../../../src/lib/compiler/class-field-lowering.ts"],"sourcesContent":["import MagicString from 'magic-string';\n\n/**\n * Lower instance class field initializers into constructor assignments.\n *\n * When `useDefineForClassFields` is `false` (the standard Angular tsconfig),\n * field initializers must run as assignments inside the constructor body\n * rather than as native ES class field initializers. This ensures:\n *\n * 1. `inject()` calls in fields have an active injection context\n * 2. Fields referencing other injected fields work (sequential assignment)\n * 3. Constructor parameter properties are available to field initializers\n * 4. Inheritance works (parent constructor runs before child field assignments)\n *\n * Rules:\n * - Regular fields with initializers: remove declaration, add `this.field = value;`\n * - Private fields (`#field`) with initializers: keep `#field;` declaration, add `this.#field = value;`\n * - Static fields: not lowered\n * - Fields without initializers: not lowered\n * - `declare` fields: not lowered\n * - Assignments are inserted after `super()` (if present), before existing constructor body\n * - If no constructor exists, one is created (with `super(...args)` for subclasses)\n */\nexport function lowerClassFields(\n ms: MagicString,\n sourceCode: string,\n oxcProgram: any,\n): void {\n for (const stmt of oxcProgram.body) {\n const decl =\n stmt.type === 'ExportNamedDeclaration' ||\n stmt.type === 'ExportDefaultDeclaration'\n ? (stmt as any).declaration\n : stmt;\n\n if (\n !decl ||\n (decl.type !== 'ClassDeclaration' && decl.type !== 'ClassExpression') ||\n !decl.body\n ) {\n continue;\n }\n\n lowerClassFieldsForClass(ms, sourceCode, decl);\n }\n}\n\ninterface FieldToLower {\n /** The full property definition node */\n node: any;\n /** The member access expression to append after `this`, e.g. `.name`, `.#priv`, `[expr]`, `['some-key']`, `[123]` */\n accessor: string;\n /** The initializer source text */\n initializer: string;\n /** Whether this is a private field (#field) */\n isPrivate: boolean;\n}\n\nfunction lowerClassFieldsForClass(\n ms: MagicString,\n sourceCode: string,\n classNode: any,\n): void {\n const body = classNode.body;\n const members: any[] = body.body;\n const fieldsToLower: FieldToLower[] = [];\n\n for (const member of members) {\n if (!shouldLowerField(member)) continue;\n\n const accessor = getFieldAccessor(member, sourceCode);\n const initializer = sourceCode.slice(member.value.start, member.value.end);\n\n fieldsToLower.push({\n node: member,\n accessor,\n initializer,\n isPrivate:\n member.type === 'PropertyDefinition' &&\n member.key?.type === 'PrivateIdentifier',\n });\n }\n\n if (fieldsToLower.length === 0) return;\n\n // Build assignment statements\n const assignments = fieldsToLower.map(\n (f) => ` this${f.accessor} = ${f.initializer};`,\n );\n\n // Find existing constructor\n const ctor = members.find(\n (m: any) => m.type === 'MethodDefinition' && m.kind === 'constructor',\n );\n\n // Check if class has a superclass\n const hasSuperClass = !!classNode.superClass;\n\n if (ctor) {\n insertIntoExistingConstructor(ms, sourceCode, ctor, assignments);\n } else {\n createConstructorWithAssignments(\n ms,\n sourceCode,\n body,\n members,\n assignments,\n hasSuperClass,\n );\n }\n\n // Remove or strip field declarations\n for (const field of fieldsToLower) {\n if (field.isPrivate) {\n // Keep declaration without initializer: `#field;`\n // Start scanning after the type annotation (if present) to avoid\n // matching `=` inside `=>` of arrow function type annotations.\n const scanFrom = field.node.typeAnnotation\n ? field.node.typeAnnotation.end\n : field.node.key.end;\n const eqStart = findEqualsSign(\n sourceCode,\n scanFrom,\n field.node.value.start,\n );\n ms.remove(eqStart, field.node.value.end);\n } else {\n // Remove the field declaration. Include the trailing newline to avoid\n // leaving blank lines, BUT only if the character after the newline isn't\n // the closing `}` of the class. Otherwise the removal range ends at the\n // same position where Ivy static definitions are appendLeft-inserted,\n // and MagicString consumes those insertions as part of the removed range.\n let end = field.node.end;\n const nextChar = sourceCode[end];\n const charAfterNewline =\n nextChar === '\\n'\n ? sourceCode[end + 1]\n : nextChar === '\\r' && sourceCode[end + 1] === '\\n'\n ? sourceCode[end + 2]\n : null;\n // Only consume newline(s) when the next non-whitespace char is not `}`\n const safeToConsumeNewline =\n charAfterNewline !== null && charAfterNewline !== '}';\n if (safeToConsumeNewline) {\n if (nextChar === '\\n') end++;\n else if (nextChar === '\\r' && sourceCode[end + 1] === '\\n') end += 2;\n }\n ms.remove(field.node.start, end);\n }\n }\n}\n\nfunction shouldLowerField(member: any): boolean {\n // Must be a PropertyDefinition with an initializer (value)\n if (member.type !== 'PropertyDefinition') return false;\n if (!member.value) return false;\n // Don't lower static fields\n if (member.static) return false;\n // Don't lower declare fields\n if (member.declare) return false;\n\n return true;\n}\n\n/**\n * Build the member-access expression to append after `this` for a class field\n * being lowered. Returns the accessor with its leading punctuation:\n *\n * - `.name` — non-computed identifier key\n * - `.#priv` — private identifier key\n * - `[expr]` — computed key (square brackets in source)\n * - `['some-key']` — string literal key\n * - `[123]` — numeric literal key\n *\n * Without this, fields with non-identifier keys produced invalid syntax like\n * `this.'some-key' = …` which OXC parses as \"Cannot assign to this expression\".\n */\nfunction getFieldAccessor(member: any, sourceCode: string): string {\n const key = member.key;\n if (key.type === 'PrivateIdentifier') {\n return '.#' + key.name;\n }\n // Computed key: `[expr] = value` → `this[expr] = value`\n // OXC marks the parent PropertyDefinition with `computed: true`.\n if (member.computed) {\n return '[' + sourceCode.slice(key.start, key.end) + ']';\n }\n if (key.type === 'Identifier') {\n return '.' + key.name;\n }\n // String literal key: `'some-key' = value` → `this['some-key'] = value`\n if (\n key.type === 'StringLiteral' ||\n (key.type === 'Literal' && typeof key.value === 'string')\n ) {\n return '[' + JSON.stringify(key.value) + ']';\n }\n // Numeric literal key: `123 = value` → `this[123] = value`\n if (\n key.type === 'NumericLiteral' ||\n (key.type === 'Literal' && typeof key.value === 'number')\n ) {\n return '[' + key.value + ']';\n }\n // Fallback: bracket-access with the original source text\n return '[' + sourceCode.slice(key.start, key.end) + ']';\n}\n\nfunction findEqualsSign(sourceCode: string, from: number, to: number): number {\n for (let i = from; i < to; i++) {\n if (sourceCode[i] === '=') return i;\n }\n return from;\n}\n\nfunction insertIntoExistingConstructor(\n ms: MagicString,\n sourceCode: string,\n ctor: any,\n assignments: string[],\n): void {\n const ctorBody = ctor.value.body;\n if (!ctorBody) return;\n\n const bodyStatements: any[] = ctorBody.body;\n const assignmentBlock = '\\n' + assignments.join('\\n');\n\n // Find the position after super() call (if any)\n let insertPos: number | null = null;\n for (const stmt of bodyStatements) {\n if (isSuperCall(stmt)) {\n // Insert after super() statement including its semicolon\n insertPos = stmt.end;\n break;\n }\n }\n\n if (insertPos !== null) {\n ms.appendRight(insertPos, assignmentBlock);\n } else if (bodyStatements.length > 0) {\n // Insert before the first statement\n ms.appendRight(bodyStatements[0].start, assignments.join('\\n') + '\\n ');\n } else {\n // Empty constructor body — insert after opening {\n ms.appendRight(ctorBody.start + 1, assignmentBlock + '\\n ');\n }\n}\n\nfunction createConstructorWithAssignments(\n ms: MagicString,\n sourceCode: string,\n classBody: any,\n members: any[],\n assignments: string[],\n hasSuperClass: boolean,\n): void {\n const superCall = hasSuperClass ? ' super(...args);\\n' : '';\n const args = hasSuperClass ? '...args' : '';\n const ctorCode = [\n ` constructor(${args}) {`,\n superCall ? superCall.trimEnd() : null,\n ...assignments,\n ' }',\n ]\n .filter((l) => l !== null)\n .join('\\n');\n\n // Insert constructor at the beginning of the class body (after opening {)\n ms.appendRight(classBody.start + 1, '\\n' + ctorCode + '\\n');\n}\n\nfunction isSuperCall(stmt: any): boolean {\n if (stmt.type !== 'ExpressionStatement') return false;\n const expr = stmt.expression;\n if (expr.type !== 'CallExpression') return false;\n return expr.callee?.type === 'Super';\n}\n"],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import MagicString from "magic-string";
2
+ import { ComponentRegistry } from "./registry.js";
3
+ /**
4
+ * COMPLETE EXHAUSTIVE ANGULAR LITE COMPILER
5
+ * Translates Angular Decorators + Signals to Ivy Static Definitions.
6
+ *
7
+ * @param registry - Optional external registry from the global analysis plugin.
8
+ * When provided, used to resolve component/directive selectors for template compilation.
9
+ */
10
+ export interface CompileResult {
11
+ code: string;
12
+ /** Source map for the transformation */
13
+ map: ReturnType<MagicString["generateMap"]>;
14
+ /** Absolute paths of external resources (templateUrl, styleUrl) read during compilation */
15
+ resourceDependencies: string[];
16
+ }
17
+ export interface CompileOptions {
18
+ registry?: ComponentRegistry;
19
+ /** Pre-resolved style contents keyed by absolute file path (e.g. SCSS already compiled to CSS). */
20
+ resolvedStyles?: Map<string, string>;
21
+ /** Pre-processed inline styles (index in styles array → compiled CSS). */
22
+ resolvedInlineStyles?: Map<number, string>;
23
+ /**
24
+ * When `false` (default), instance class field initializers are lowered to
25
+ * constructor assignments (matching TypeScript's `useDefineForClassFields: false`
26
+ * behavior). This is required for Angular's `inject()` and constructor DI to
27
+ * work correctly with the standard Angular tsconfig.
28
+ */
29
+ useDefineForClassFields?: boolean;
30
+ /** Enable legacy i18n message ID format (default: true). */
31
+ enableI18nLegacyMessageIdFormat?: boolean;
32
+ /** Normalize line endings in ICU expressions (default: true). */
33
+ i18nNormalizeLineEndingsInICUs?: boolean;
34
+ /** Use external IDs in `$localize` calls (for Closure Compiler compatibility). */
35
+ i18nUseExternalIds?: boolean;
36
+ /**
37
+ * Compilation output mode.
38
+ * - `'full'` (default): Emit final Ivy definitions (`ɵɵdefineComponent`) for application builds.
39
+ * - `'partial'`: Emit partial declarations (`ɵɵngDeclareComponent`) for library publishing.
40
+ * Partial output is version-stable and linked at application build time.
41
+ */
42
+ compilationMode?: "full" | "partial";
43
+ }
44
+ export declare function compile(sourceCode: string, fileName: string, optionsOrRegistry?: CompileOptions | ComponentRegistry): CompileResult;