@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.
- package/README.md +28 -0
- package/migrations/migrate-setup-vitest/migrate-setup-vitest.d.ts +2 -0
- package/migrations/migrate-setup-vitest/migrate-setup-vitest.js +49 -0
- package/migrations/migrate-setup-vitest/migrate-setup-vitest.js.map +1 -0
- package/migrations/migration.json +7 -1
- package/migrations/migrations.json +9 -0
- package/migrations/update-3-0-0/migrate-setup-vitest.d.ts +2 -0
- package/migrations/update-3-0-0/migrate-setup-vitest.js +36 -0
- package/migrations/update-3-0-0/migrate-setup-vitest.js.map +1 -0
- package/package.json +25 -12
- package/src/index.d.ts +3 -2
- package/src/index.js +6 -2
- package/src/index.js.map +1 -1
- package/src/lib/angular-build-optimizer-plugin.d.ts +4 -4
- package/src/lib/angular-build-optimizer-plugin.js +48 -62
- package/src/lib/angular-build-optimizer-plugin.js.map +1 -1
- package/src/lib/angular-jit-plugin.d.ts +3 -3
- package/src/lib/angular-jit-plugin.js +42 -37
- package/src/lib/angular-jit-plugin.js.map +1 -1
- package/src/lib/angular-pending-tasks.plugin.d.ts +7 -7
- package/src/lib/angular-pending-tasks.plugin.js +17 -18
- package/src/lib/angular-pending-tasks.plugin.js.map +1 -1
- package/src/lib/angular-vite-plugin.d.ts +250 -40
- package/src/lib/angular-vite-plugin.js +2216 -964
- package/src/lib/angular-vite-plugin.js.map +1 -1
- package/src/lib/angular-vitest-plugin.d.ts +19 -15
- package/src/lib/angular-vitest-plugin.js +99 -114
- package/src/lib/angular-vitest-plugin.js.map +1 -1
- package/src/lib/compiler/angular-version.d.ts +19 -0
- package/src/lib/compiler/angular-version.js +16 -0
- package/src/lib/compiler/angular-version.js.map +1 -0
- package/src/lib/compiler/class-field-lowering.d.ts +23 -0
- package/src/lib/compiler/class-field-lowering.js +131 -0
- package/src/lib/compiler/class-field-lowering.js.map +1 -0
- package/src/lib/compiler/compile.d.ts +44 -0
- package/src/lib/compiler/compile.js +731 -0
- package/src/lib/compiler/compile.js.map +1 -0
- package/src/lib/compiler/constants.d.ts +18 -0
- package/src/lib/compiler/constants.js +52 -0
- package/src/lib/compiler/constants.js.map +1 -0
- package/src/lib/compiler/debug.d.ts +22 -0
- package/src/lib/compiler/debug.js +20 -0
- package/src/lib/compiler/debug.js.map +1 -0
- package/src/lib/compiler/defer.d.ts +47 -0
- package/src/lib/compiler/defer.js +138 -0
- package/src/lib/compiler/defer.js.map +1 -0
- package/src/lib/compiler/dts-reader.d.ts +35 -0
- package/src/lib/compiler/dts-reader.js +365 -0
- package/src/lib/compiler/dts-reader.js.map +1 -0
- package/src/lib/compiler/hmr.d.ts +16 -0
- package/src/lib/compiler/hmr.js +69 -0
- package/src/lib/compiler/hmr.js.map +1 -0
- package/src/lib/compiler/index.d.ts +7 -0
- package/src/lib/compiler/index.js +7 -0
- package/src/lib/compiler/jit-metadata.d.ts +14 -0
- package/src/lib/compiler/jit-metadata.js +146 -0
- package/src/lib/compiler/jit-metadata.js.map +1 -0
- package/src/lib/compiler/jit-transform.d.ts +24 -0
- package/src/lib/compiler/jit-transform.js +200 -0
- package/src/lib/compiler/jit-transform.js.map +1 -0
- package/src/lib/compiler/js-emitter.d.ts +10 -0
- package/src/lib/compiler/js-emitter.js +420 -0
- package/src/lib/compiler/js-emitter.js.map +1 -0
- package/src/lib/compiler/metadata.d.ts +45 -0
- package/src/lib/compiler/metadata.js +633 -0
- package/src/lib/compiler/metadata.js.map +1 -0
- package/src/lib/compiler/registry.d.ts +49 -0
- package/src/lib/compiler/registry.js +164 -0
- package/src/lib/compiler/registry.js.map +1 -0
- package/src/lib/compiler/resource-inliner.d.ts +21 -0
- package/src/lib/compiler/resource-inliner.js +152 -0
- package/src/lib/compiler/resource-inliner.js.map +1 -0
- package/src/lib/compiler/style-ast.d.ts +8 -0
- package/src/lib/compiler/style-ast.js +54 -0
- package/src/lib/compiler/style-ast.js.map +1 -0
- package/src/lib/compiler/styles.d.ts +13 -0
- package/src/lib/compiler/test-helpers.d.ts +7 -0
- package/src/lib/compiler/type-elision.d.ts +26 -0
- package/src/lib/compiler/type-elision.js +211 -0
- package/src/lib/compiler/type-elision.js.map +1 -0
- package/src/lib/compiler/utils.d.ts +10 -0
- package/src/lib/compiler/utils.js +35 -0
- package/src/lib/compiler/utils.js.map +1 -0
- package/src/lib/compiler-plugin.d.ts +11 -11
- package/src/lib/compiler-plugin.js +43 -44
- package/src/lib/compiler-plugin.js.map +1 -1
- package/src/lib/component-resolvers.d.ts +23 -5
- package/src/lib/component-resolvers.js +153 -63
- package/src/lib/component-resolvers.js.map +1 -1
- package/src/lib/fast-compile-plugin.d.ts +14 -0
- package/src/lib/fast-compile-plugin.js +270 -0
- package/src/lib/fast-compile-plugin.js.map +1 -0
- package/src/lib/host.d.ts +10 -8
- package/src/lib/host.js +111 -101
- package/src/lib/host.js.map +1 -1
- package/src/lib/live-reload-plugin.d.ts +5 -5
- package/src/lib/live-reload-plugin.js +61 -62
- package/src/lib/live-reload-plugin.js.map +1 -1
- package/src/lib/models.d.ts +9 -9
- package/src/lib/nx-folder-plugin.d.ts +5 -5
- package/src/lib/nx-folder-plugin.js +18 -16
- package/src/lib/nx-folder-plugin.js.map +1 -1
- package/src/lib/plugins/file-replacements.plugin.d.ts +4 -4
- package/src/lib/plugins/file-replacements.plugin.js +40 -62
- package/src/lib/plugins/file-replacements.plugin.js.map +1 -1
- package/src/lib/router-plugin.d.ts +1 -1
- package/src/lib/router-plugin.js +23 -23
- package/src/lib/router-plugin.js.map +1 -1
- package/src/lib/style-pipeline.d.ts +15 -0
- package/src/lib/style-pipeline.js +31 -0
- package/src/lib/style-pipeline.js.map +1 -0
- package/src/lib/style-preprocessor.d.ts +35 -0
- package/src/lib/style-preprocessor.js +35 -0
- package/src/lib/style-preprocessor.js.map +1 -0
- package/src/lib/stylesheet-registry.d.ts +73 -0
- package/src/lib/stylesheet-registry.js +168 -0
- package/src/lib/stylesheet-registry.js.map +1 -0
- package/src/lib/tools/package.json +2 -7
- package/src/lib/tools/src/builders/vite/vite-build.impl.js +31 -38
- package/src/lib/tools/src/builders/vite/vite-build.impl.js.map +1 -1
- package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.js +51 -62
- package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.js.map +1 -1
- package/src/lib/tools/src/index.js +0 -2
- package/src/lib/utils/compiler-plugin-options.d.ts +11 -11
- package/src/lib/utils/debug-harness.d.ts +23 -0
- package/src/lib/utils/debug-harness.js +88 -0
- package/src/lib/utils/debug-harness.js.map +1 -0
- package/src/lib/utils/debug-log-file.d.ts +5 -0
- package/src/lib/utils/debug-log-file.js +56 -0
- package/src/lib/utils/debug-log-file.js.map +1 -0
- package/src/lib/utils/debug.d.ts +28 -0
- package/src/lib/utils/debug.js +39 -0
- package/src/lib/utils/debug.js.map +1 -0
- package/src/lib/utils/devkit.d.ts +6 -6
- package/src/lib/utils/devkit.js +34 -38
- package/src/lib/utils/devkit.js.map +1 -1
- package/src/lib/utils/hmr-candidates.d.ts +28 -28
- package/src/lib/utils/plugin-config.d.ts +30 -0
- package/src/lib/utils/plugin-config.js +64 -0
- package/src/lib/utils/plugin-config.js.map +1 -0
- package/src/lib/utils/rolldown.d.ts +2 -0
- package/src/lib/utils/rolldown.js +12 -0
- package/src/lib/utils/rolldown.js.map +1 -0
- package/src/lib/utils/source-file-cache.d.ts +8 -15
- package/src/lib/utils/source-file-cache.js +35 -37
- package/src/lib/utils/source-file-cache.js.map +1 -1
- package/src/lib/utils/tailwind-reference.d.ts +12 -0
- package/src/lib/utils/tailwind-reference.js +99 -0
- package/src/lib/utils/tailwind-reference.js.map +1 -0
- package/src/lib/utils/virtual-ids.d.ts +8 -0
- package/src/lib/utils/virtual-ids.js +35 -0
- package/src/lib/utils/virtual-ids.js.map +1 -0
- package/src/lib/utils/virtual-resources.d.ts +47 -0
- package/src/lib/utils/virtual-resources.js +89 -0
- package/src/lib/utils/virtual-resources.js.map +1 -0
- package/src/test-setup.d.ts +2 -0
- package/setup-vitest.d.ts +0 -4
- package/setup-vitest.js +0 -215
- package/setup-vitest.js.map +0 -1
- package/src/lib/models.js +0 -1
- package/src/lib/models.js.map +0 -1
- package/src/lib/tools/README.md +0 -3
- package/src/lib/tools/src/index.d.ts +0 -0
- package/src/lib/tools/src/index.js.map +0 -1
- package/src/lib/utils/compiler-plugin-options.js +0 -1
- package/src/lib/utils/compiler-plugin-options.js.map +0 -1
- package/src/lib/utils/hmr-candidates.js +0 -272
- package/src/lib/utils/hmr-candidates.js.map +0 -1
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
import { Plugin } from
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
2
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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","
|
|
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;
|