@angular/build 21.0.0-next.5 → 21.0.0-next.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -8
- package/src/builders/karma/application_builder.js +7 -0
- package/src/builders/unit-test/builder.js +10 -2
- package/src/builders/unit-test/options.d.ts +15 -2
- package/src/builders/unit-test/options.js +36 -4
- package/src/builders/unit-test/runners/karma/executor.js +26 -3
- package/src/builders/unit-test/runners/karma/index.js +1 -1
- package/src/builders/unit-test/runners/vitest/browser-provider.d.ts +4 -1
- package/src/builders/unit-test/runners/vitest/browser-provider.js +6 -2
- package/src/builders/unit-test/runners/vitest/build-options.js +1 -2
- package/src/builders/unit-test/runners/vitest/executor.d.ts +1 -0
- package/src/builders/unit-test/runners/vitest/executor.js +67 -11
- package/src/builders/unit-test/runners/vitest/index.js +1 -1
- package/src/builders/unit-test/schema.d.ts +88 -13
- package/src/builders/unit-test/schema.js +12 -12
- package/src/builders/unit-test/schema.json +121 -33
- package/src/builders/unit-test/test-discovery.js +1 -0
- package/src/tools/babel/plugins/pure-toplevel-functions.d.ts +0 -1
- package/src/tools/babel/plugins/pure-toplevel-functions.js +21 -5
- package/src/tools/esbuild/angular/compiler-plugin.js +38 -14
- package/src/tools/esbuild/javascript-transformer-worker.js +2 -8
- package/src/utils/normalize-cache.js +1 -1
- package/src/utils/server-rendering/utils.d.ts +1 -1
- package/src/utils/service-worker.d.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular/build",
|
|
3
|
-
"version": "21.0.0-next.
|
|
3
|
+
"version": "21.0.0-next.7",
|
|
4
4
|
"description": "Official build system for Angular",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Angular CLI",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"builders": "builders.json",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@ampproject/remapping": "2.3.0",
|
|
26
|
-
"@angular-devkit/architect": "0.2100.0-next.
|
|
26
|
+
"@angular-devkit/architect": "0.2100.0-next.7",
|
|
27
27
|
"@babel/core": "7.28.4",
|
|
28
28
|
"@babel/helper-annotate-as-pure": "7.27.3",
|
|
29
29
|
"@babel/helper-split-export-declaration": "7.24.7",
|
|
@@ -41,16 +41,16 @@
|
|
|
41
41
|
"parse5-html-rewriting-stream": "8.0.0",
|
|
42
42
|
"picomatch": "4.0.3",
|
|
43
43
|
"piscina": "5.1.3",
|
|
44
|
-
"rolldown": "1.0.0-beta.
|
|
45
|
-
"sass": "1.93.
|
|
44
|
+
"rolldown": "1.0.0-beta.42",
|
|
45
|
+
"sass": "1.93.2",
|
|
46
46
|
"semver": "7.7.2",
|
|
47
47
|
"source-map-support": "0.5.21",
|
|
48
48
|
"tinyglobby": "0.2.15",
|
|
49
|
-
"vite": "7.1.
|
|
49
|
+
"vite": "7.1.9",
|
|
50
50
|
"watchpack": "2.4.4"
|
|
51
51
|
},
|
|
52
52
|
"optionalDependencies": {
|
|
53
|
-
"lmdb": "3.4.
|
|
53
|
+
"lmdb": "3.4.3"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@angular/core": "^21.0.0-next.0",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"@angular/platform-browser": "^21.0.0-next.0",
|
|
61
61
|
"@angular/platform-server": "^21.0.0-next.0",
|
|
62
62
|
"@angular/service-worker": "^21.0.0-next.0",
|
|
63
|
-
"@angular/ssr": "^21.0.0-next.
|
|
63
|
+
"@angular/ssr": "^21.0.0-next.7",
|
|
64
64
|
"karma": "^6.4.0",
|
|
65
65
|
"less": "^4.2.0",
|
|
66
66
|
"ng-packagr": "^21.0.0-next.0",
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"type": "git",
|
|
113
113
|
"url": "https://github.com/angular/angular-cli.git"
|
|
114
114
|
},
|
|
115
|
-
"packageManager": "pnpm@10.
|
|
115
|
+
"packageManager": "pnpm@10.18.1",
|
|
116
116
|
"engines": {
|
|
117
117
|
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
|
|
118
118
|
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
|
@@ -45,6 +45,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
45
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
46
|
exports.execute = execute;
|
|
47
47
|
const node_crypto_1 = require("node:crypto");
|
|
48
|
+
const node_fs_1 = require("node:fs");
|
|
48
49
|
const fs = __importStar(require("node:fs/promises"));
|
|
49
50
|
const node_path_1 = __importDefault(require("node:path"));
|
|
50
51
|
const web_1 = require("node:stream/web");
|
|
@@ -105,8 +106,14 @@ function execute(options, context, transforms) {
|
|
|
105
106
|
async function initializeApplication(options, context, karmaOptions, transforms) {
|
|
106
107
|
const karma = await Promise.resolve().then(() => __importStar(require('karma')));
|
|
107
108
|
const projectSourceRoot = await (0, utils_1.getProjectSourceRoot)(context);
|
|
109
|
+
// Setup temporary output path and ensure it is empty
|
|
108
110
|
const outputPath = node_path_1.default.join(context.workspaceRoot, 'dist/test-out', (0, node_crypto_1.randomUUID)());
|
|
109
111
|
await fs.rm(outputPath, { recursive: true, force: true });
|
|
112
|
+
// Setup exit cleanup for temporary directory
|
|
113
|
+
const handleProcessExit = () => (0, node_fs_1.rmSync)(outputPath, { recursive: true, force: true });
|
|
114
|
+
process.once('exit', handleProcessExit);
|
|
115
|
+
process.once('SIGINT', handleProcessExit);
|
|
116
|
+
process.once('uncaughtException', handleProcessExit);
|
|
110
117
|
const { buildOptions, mainName } = await setupBuildOptions(options, context, projectSourceRoot, outputPath);
|
|
111
118
|
const [buildOutput, buildIterator] = await runEsbuild(buildOptions, context, projectSourceRoot);
|
|
112
119
|
const karmaConfig = await configureKarma(karma, context, karmaOptions, options, buildOptions, buildOutput, mainName, transforms);
|
|
@@ -266,7 +266,15 @@ async function* execute(options, context, extensions) {
|
|
|
266
266
|
// Get base build options from the buildTarget
|
|
267
267
|
let buildTargetOptions;
|
|
268
268
|
try {
|
|
269
|
-
|
|
269
|
+
const builderName = await context.getBuilderNameForTarget(normalizedOptions.buildTarget);
|
|
270
|
+
if (builderName !== '@angular/build:application' &&
|
|
271
|
+
// TODO: Add comprehensive support for ng-packagr.
|
|
272
|
+
builderName !== '@angular/build:ng-packagr') {
|
|
273
|
+
context.logger.warn(`The 'buildTarget' is configured to use '${builderName}', which is not supported. ` +
|
|
274
|
+
`The 'unit-test' builder is designed to work with '@angular/build:application'. ` +
|
|
275
|
+
'Unexpected behavior or build failures may occur.');
|
|
276
|
+
}
|
|
277
|
+
buildTargetOptions = (await context.validateOptions(await context.getTargetOptions(normalizedOptions.buildTarget), builderName));
|
|
270
278
|
}
|
|
271
279
|
catch (e) {
|
|
272
280
|
(0, error_1.assertIsError)(e);
|
|
@@ -303,8 +311,8 @@ async function* execute(options, context, extensions) {
|
|
|
303
311
|
...buildTargetOptions,
|
|
304
312
|
...runnerBuildOptions,
|
|
305
313
|
watch: normalizedOptions.watch,
|
|
306
|
-
tsConfig: normalizedOptions.tsConfig,
|
|
307
314
|
progress: normalizedOptions.buildProgress ?? buildTargetOptions.progress,
|
|
315
|
+
...(normalizedOptions.tsConfig ? { tsConfig: normalizedOptions.tsConfig } : {}),
|
|
308
316
|
};
|
|
309
317
|
const dumpDirectory = normalizedOptions.dumpVirtualFiles
|
|
310
318
|
? node_path_1.default.join(normalizedOptions.cacheOptions.path, 'unit-test', 'output-files')
|
|
@@ -18,15 +18,28 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
|
|
|
18
18
|
exclude: string[] | undefined;
|
|
19
19
|
filter: string | undefined;
|
|
20
20
|
runnerName: import("./schema").Runner;
|
|
21
|
-
|
|
21
|
+
coverage: {
|
|
22
|
+
all: boolean | undefined;
|
|
22
23
|
exclude: string[] | undefined;
|
|
24
|
+
include: string[] | undefined;
|
|
23
25
|
reporters: [string, Record<string, unknown>][] | undefined;
|
|
26
|
+
thresholds: import("./schema").CoverageThresholds | undefined;
|
|
27
|
+
watermarks: {
|
|
28
|
+
statements?: [number, number];
|
|
29
|
+
branches?: [number, number];
|
|
30
|
+
functions?: [number, number];
|
|
31
|
+
lines?: [number, number];
|
|
32
|
+
};
|
|
24
33
|
} | undefined;
|
|
25
|
-
tsConfig: string;
|
|
34
|
+
tsConfig: string | undefined;
|
|
26
35
|
buildProgress: boolean | undefined;
|
|
27
36
|
reporters: [string, Record<string, unknown>][] | undefined;
|
|
28
37
|
outputFile: string | undefined;
|
|
29
38
|
browsers: string[] | undefined;
|
|
39
|
+
browserViewport: {
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
} | undefined;
|
|
30
43
|
watch: boolean;
|
|
31
44
|
debug: boolean;
|
|
32
45
|
providersFile: string | undefined;
|
|
@@ -13,10 +13,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
13
13
|
exports.normalizeOptions = normalizeOptions;
|
|
14
14
|
exports.injectTestingPolyfills = injectTestingPolyfills;
|
|
15
15
|
const architect_1 = require("@angular-devkit/architect");
|
|
16
|
+
const node_fs_1 = require("node:fs");
|
|
16
17
|
const node_path_1 = __importDefault(require("node:path"));
|
|
17
18
|
const normalize_cache_1 = require("../../utils/normalize-cache");
|
|
18
19
|
const project_metadata_1 = require("../../utils/project-metadata");
|
|
19
20
|
const tty_1 = require("../../utils/tty");
|
|
21
|
+
async function exists(path) {
|
|
22
|
+
try {
|
|
23
|
+
await node_fs_1.promises.access(path, node_fs_1.constants.F_OK);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
20
30
|
function normalizeReporterOption(reporters) {
|
|
21
31
|
return reporters?.map((entry) => typeof entry === 'string'
|
|
22
32
|
? [entry, {}]
|
|
@@ -33,7 +43,22 @@ async function normalizeOptions(context, projectName, options) {
|
|
|
33
43
|
// Target specifier defaults to the current project's build target using a development configuration
|
|
34
44
|
const buildTargetSpecifier = options.buildTarget ?? `::development`;
|
|
35
45
|
const buildTarget = (0, architect_1.targetFromTargetString)(buildTargetSpecifier, projectName, 'build');
|
|
36
|
-
const {
|
|
46
|
+
const { runner, browsers, progress, filter, browserViewport } = options;
|
|
47
|
+
const [width, height] = browserViewport?.split('x').map(Number) ?? [];
|
|
48
|
+
let tsConfig = options.tsConfig;
|
|
49
|
+
if (tsConfig) {
|
|
50
|
+
const fullTsConfigPath = node_path_1.default.join(workspaceRoot, tsConfig);
|
|
51
|
+
if (!(await exists(fullTsConfigPath))) {
|
|
52
|
+
throw new Error(`The specified tsConfig file '${tsConfig}' does not exist.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
const tsconfigSpecPath = node_path_1.default.join(projectRoot, 'tsconfig.spec.json');
|
|
57
|
+
if (await exists(tsconfigSpecPath)) {
|
|
58
|
+
// The application builder expects a path relative to the workspace root.
|
|
59
|
+
tsConfig = node_path_1.default.relative(workspaceRoot, tsconfigSpecPath);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
37
62
|
return {
|
|
38
63
|
// Project/workspace information
|
|
39
64
|
workspaceRoot,
|
|
@@ -46,10 +71,16 @@ async function normalizeOptions(context, projectName, options) {
|
|
|
46
71
|
exclude: options.exclude,
|
|
47
72
|
filter,
|
|
48
73
|
runnerName: runner,
|
|
49
|
-
|
|
74
|
+
coverage: options.coverage
|
|
50
75
|
? {
|
|
51
|
-
|
|
52
|
-
|
|
76
|
+
all: options.coverageAll,
|
|
77
|
+
exclude: options.coverageExclude,
|
|
78
|
+
include: options.coverageInclude,
|
|
79
|
+
reporters: normalizeReporterOption(options.coverageReporters),
|
|
80
|
+
thresholds: options.coverageThresholds,
|
|
81
|
+
// The schema generation tool doesn't support tuple types for items, but the schema validation
|
|
82
|
+
// does ensure that the array has exactly two numbers.
|
|
83
|
+
watermarks: options.coverageWatermarks,
|
|
53
84
|
}
|
|
54
85
|
: undefined,
|
|
55
86
|
tsConfig,
|
|
@@ -57,6 +88,7 @@ async function normalizeOptions(context, projectName, options) {
|
|
|
57
88
|
reporters: normalizeReporterOption(options.reporters),
|
|
58
89
|
outputFile: options.outputFile,
|
|
59
90
|
browsers,
|
|
91
|
+
browserViewport: width && height ? { width, height } : undefined,
|
|
60
92
|
watch: options.watch ?? (0, tty_1.isTTY)(),
|
|
61
93
|
debug: options.debug ?? false,
|
|
62
94
|
providersFile: options.providersFile && node_path_1.default.join(workspaceRoot, options.providersFile),
|
|
@@ -50,15 +50,24 @@ class KarmaExecutor {
|
|
|
50
50
|
}
|
|
51
51
|
async *execute() {
|
|
52
52
|
const { context, options: unitTestOptions } = this;
|
|
53
|
+
if (unitTestOptions.browserViewport) {
|
|
54
|
+
context.logger.warn('The "karma" test runner does not support the "browserViewport" option. The option will be ignored.');
|
|
55
|
+
}
|
|
53
56
|
if (unitTestOptions.debug) {
|
|
54
57
|
context.logger.warn('The "karma" test runner does not support the "debug" option. The option will be ignored.');
|
|
55
58
|
}
|
|
56
59
|
if (unitTestOptions.setupFiles.length) {
|
|
57
60
|
context.logger.warn('The "karma" test runner does not support the "setupFiles" option. The option will be ignored.');
|
|
58
61
|
}
|
|
62
|
+
if (unitTestOptions.coverage?.all) {
|
|
63
|
+
context.logger.warn('The "karma" test runner does not support the "coverageAll" option. The option will be ignored.');
|
|
64
|
+
}
|
|
65
|
+
if (unitTestOptions.coverage?.include) {
|
|
66
|
+
context.logger.warn('The "karma" test runner does not support the "coverageInclude" option. The option will be ignored.');
|
|
67
|
+
}
|
|
59
68
|
const buildTargetOptions = (await context.validateOptions(await context.getTargetOptions(unitTestOptions.buildTarget), await context.getBuilderNameForTarget(unitTestOptions.buildTarget)));
|
|
60
69
|
const karmaOptions = {
|
|
61
|
-
tsConfig: unitTestOptions.tsConfig,
|
|
70
|
+
tsConfig: unitTestOptions.tsConfig ?? buildTargetOptions.tsConfig,
|
|
62
71
|
polyfills: buildTargetOptions.polyfills,
|
|
63
72
|
assets: buildTargetOptions.assets,
|
|
64
73
|
scripts: buildTargetOptions.scripts,
|
|
@@ -76,8 +85,8 @@ class KarmaExecutor {
|
|
|
76
85
|
poll: buildTargetOptions.poll,
|
|
77
86
|
preserveSymlinks: buildTargetOptions.preserveSymlinks,
|
|
78
87
|
browsers: unitTestOptions.browsers?.join(','),
|
|
79
|
-
codeCoverage: !!unitTestOptions.
|
|
80
|
-
codeCoverageExclude: unitTestOptions.
|
|
88
|
+
codeCoverage: !!unitTestOptions.coverage,
|
|
89
|
+
codeCoverageExclude: unitTestOptions.coverage?.exclude,
|
|
81
90
|
fileReplacements: buildTargetOptions.fileReplacements,
|
|
82
91
|
reporters: unitTestOptions.reporters?.map((reporter) => {
|
|
83
92
|
// Karma only supports string reporters.
|
|
@@ -104,6 +113,20 @@ class KarmaExecutor {
|
|
|
104
113
|
options.client.args ??= [];
|
|
105
114
|
options.client.args.push('--grep', filter);
|
|
106
115
|
}
|
|
116
|
+
// Add coverage options
|
|
117
|
+
if (unitTestOptions.coverage) {
|
|
118
|
+
const { thresholds, watermarks } = unitTestOptions.coverage;
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
120
|
+
const coverageReporter = (options.coverageReporter ??= {});
|
|
121
|
+
if (thresholds) {
|
|
122
|
+
coverageReporter.check = thresholds.perFile
|
|
123
|
+
? { each: thresholds }
|
|
124
|
+
: { global: thresholds };
|
|
125
|
+
}
|
|
126
|
+
if (watermarks) {
|
|
127
|
+
coverageReporter.watermarks = watermarks;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
107
130
|
return options;
|
|
108
131
|
},
|
|
109
132
|
};
|
|
@@ -9,4 +9,7 @@ export interface BrowserConfiguration {
|
|
|
9
9
|
browser?: import('vitest/node').BrowserConfigOptions;
|
|
10
10
|
errors?: string[];
|
|
11
11
|
}
|
|
12
|
-
export declare function setupBrowserConfiguration(browsers: string[] | undefined, debug: boolean, projectSourceRoot: string
|
|
12
|
+
export declare function setupBrowserConfiguration(browsers: string[] | undefined, debug: boolean, projectSourceRoot: string, viewport: {
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
} | undefined): BrowserConfiguration;
|
|
@@ -28,7 +28,7 @@ function normalizeBrowserName(browserName) {
|
|
|
28
28
|
const normalized = browserName.toLowerCase();
|
|
29
29
|
return normalized.replace(/headless$/, '');
|
|
30
30
|
}
|
|
31
|
-
function setupBrowserConfiguration(browsers, debug, projectSourceRoot) {
|
|
31
|
+
function setupBrowserConfiguration(browsers, debug, projectSourceRoot, viewport) {
|
|
32
32
|
if (browsers === undefined) {
|
|
33
33
|
return {};
|
|
34
34
|
}
|
|
@@ -57,10 +57,14 @@ function setupBrowserConfiguration(browsers, debug, projectSourceRoot) {
|
|
|
57
57
|
if (errors) {
|
|
58
58
|
return { errors };
|
|
59
59
|
}
|
|
60
|
+
const isCI = !!process.env['CI'];
|
|
61
|
+
const headless = isCI || browsers.some((name) => name.toLowerCase().includes('headless'));
|
|
60
62
|
const browser = {
|
|
61
63
|
enabled: true,
|
|
62
64
|
provider,
|
|
63
|
-
headless
|
|
65
|
+
headless,
|
|
66
|
+
ui: !headless,
|
|
67
|
+
viewport,
|
|
64
68
|
instances: browsers.map((browserName) => ({
|
|
65
69
|
browser: normalizeBrowserName(browserName),
|
|
66
70
|
})),
|
|
@@ -55,7 +55,7 @@ function adjustOutputHashing(hashing) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
async function getVitestBuildOptions(options, baseBuildOptions) {
|
|
58
|
-
const { workspaceRoot, projectSourceRoot, include, exclude = [], watch,
|
|
58
|
+
const { workspaceRoot, projectSourceRoot, include, exclude = [], watch, providersFile } = options;
|
|
59
59
|
// Find test files
|
|
60
60
|
const testFiles = await (0, test_discovery_1.findTests)(include, exclude, workspaceRoot, projectSourceRoot);
|
|
61
61
|
if (testFiles.length === 0) {
|
|
@@ -87,7 +87,6 @@ async function getVitestBuildOptions(options, baseBuildOptions) {
|
|
|
87
87
|
sourceMap: { scripts: true, vendor: false, styles: false },
|
|
88
88
|
outputHashing: adjustOutputHashing(baseBuildOptions.outputHashing),
|
|
89
89
|
optimization: false,
|
|
90
|
-
tsConfig,
|
|
91
90
|
entryPoints,
|
|
92
91
|
externalDependencies: ['vitest', '@vitest/browser/context'],
|
|
93
92
|
};
|
|
@@ -11,6 +11,7 @@ import { NormalizedUnitTestBuilderOptions } from '../../options';
|
|
|
11
11
|
import type { TestExecutor } from '../api';
|
|
12
12
|
export declare class VitestExecutor implements TestExecutor {
|
|
13
13
|
private vitest;
|
|
14
|
+
private normalizePath;
|
|
14
15
|
private readonly projectName;
|
|
15
16
|
private readonly options;
|
|
16
17
|
private readonly buildResultFiles;
|
|
@@ -6,6 +6,39 @@
|
|
|
6
6
|
* Use of this source code is governed by an MIT-style license that can be
|
|
7
7
|
* found in the LICENSE file at https://angular.dev/license
|
|
8
8
|
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
9
42
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
43
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
44
|
};
|
|
@@ -21,6 +54,7 @@ const browser_provider_1 = require("./browser-provider");
|
|
|
21
54
|
const plugins_1 = require("./plugins");
|
|
22
55
|
class VitestExecutor {
|
|
23
56
|
vitest;
|
|
57
|
+
normalizePath;
|
|
24
58
|
projectName;
|
|
25
59
|
options;
|
|
26
60
|
buildResultFiles = new Map();
|
|
@@ -41,18 +75,19 @@ class VitestExecutor {
|
|
|
41
75
|
}
|
|
42
76
|
}
|
|
43
77
|
async *execute(buildResult) {
|
|
78
|
+
this.normalizePath ??= (await Promise.resolve().then(() => __importStar(require('vite')))).normalizePath;
|
|
44
79
|
if (buildResult.kind === results_1.ResultKind.Full) {
|
|
45
80
|
this.buildResultFiles.clear();
|
|
46
81
|
for (const [path, file] of Object.entries(buildResult.files)) {
|
|
47
|
-
this.buildResultFiles.set(path, file);
|
|
82
|
+
this.buildResultFiles.set(this.normalizePath(path), file);
|
|
48
83
|
}
|
|
49
84
|
}
|
|
50
85
|
else {
|
|
51
86
|
for (const file of buildResult.removed) {
|
|
52
|
-
this.buildResultFiles.delete(file.path);
|
|
87
|
+
this.buildResultFiles.delete(this.normalizePath(file.path));
|
|
53
88
|
}
|
|
54
89
|
for (const [path, file] of Object.entries(buildResult.files)) {
|
|
55
|
-
this.buildResultFiles.set(path, file);
|
|
90
|
+
this.buildResultFiles.set(this.normalizePath(path), file);
|
|
56
91
|
}
|
|
57
92
|
}
|
|
58
93
|
// Initialize Vitest if not already present.
|
|
@@ -101,7 +136,7 @@ class VitestExecutor {
|
|
|
101
136
|
return testSetupFiles;
|
|
102
137
|
}
|
|
103
138
|
async initializeVitest() {
|
|
104
|
-
const {
|
|
139
|
+
const { coverage, reporters, outputFile, workspaceRoot, browsers, debug, watch, browserViewport, } = this.options;
|
|
105
140
|
let vitestNodeModule;
|
|
106
141
|
try {
|
|
107
142
|
vitestNodeModule = await (0, load_esm_1.loadEsmModule)('vitest/node');
|
|
@@ -115,7 +150,7 @@ class VitestExecutor {
|
|
|
115
150
|
}
|
|
116
151
|
const { startVitest } = vitestNodeModule;
|
|
117
152
|
// Setup vitest browser options if configured
|
|
118
|
-
const browserOptions = (0, browser_provider_1.setupBrowserConfiguration)(browsers, debug, this.options.projectSourceRoot);
|
|
153
|
+
const browserOptions = (0, browser_provider_1.setupBrowserConfiguration)(browsers, debug, this.options.projectSourceRoot, browserViewport);
|
|
119
154
|
if (browserOptions.errors?.length) {
|
|
120
155
|
throw new Error(browserOptions.errors.join('\n'));
|
|
121
156
|
}
|
|
@@ -148,7 +183,7 @@ class VitestExecutor {
|
|
|
148
183
|
reporters: reporters ?? ['default'],
|
|
149
184
|
outputFile,
|
|
150
185
|
watch,
|
|
151
|
-
coverage: generateCoverageOption(
|
|
186
|
+
coverage: await generateCoverageOption(coverage, this.projectName),
|
|
152
187
|
...debugOptions,
|
|
153
188
|
}, {
|
|
154
189
|
server: {
|
|
@@ -161,20 +196,41 @@ class VitestExecutor {
|
|
|
161
196
|
}
|
|
162
197
|
}
|
|
163
198
|
exports.VitestExecutor = VitestExecutor;
|
|
164
|
-
function generateCoverageOption(
|
|
165
|
-
if (!
|
|
199
|
+
async function generateCoverageOption(coverage, projectName) {
|
|
200
|
+
if (!coverage) {
|
|
166
201
|
return {
|
|
167
202
|
enabled: false,
|
|
168
203
|
};
|
|
169
204
|
}
|
|
205
|
+
let defaultExcludes = [];
|
|
206
|
+
if (coverage.exclude) {
|
|
207
|
+
try {
|
|
208
|
+
const vitestConfig = await (0, load_esm_1.loadEsmModule)('vitest/config');
|
|
209
|
+
defaultExcludes = vitestConfig.coverageConfigDefaults.exclude;
|
|
210
|
+
}
|
|
211
|
+
catch { }
|
|
212
|
+
}
|
|
170
213
|
return {
|
|
171
214
|
enabled: true,
|
|
215
|
+
all: coverage.all,
|
|
172
216
|
excludeAfterRemap: true,
|
|
217
|
+
include: coverage.include,
|
|
173
218
|
reportsDirectory: (0, path_1.toPosixPath)(node_path_1.default.join('coverage', projectName)),
|
|
219
|
+
thresholds: coverage.thresholds,
|
|
220
|
+
watermarks: coverage.watermarks,
|
|
174
221
|
// Special handling for `exclude`/`reporters` due to an undefined value causing upstream failures
|
|
175
|
-
...(
|
|
176
|
-
|
|
177
|
-
|
|
222
|
+
...(coverage.exclude
|
|
223
|
+
? {
|
|
224
|
+
exclude: [
|
|
225
|
+
// Augment the default exclude https://vitest.dev/config/#coverage-exclude
|
|
226
|
+
// with the user defined exclusions
|
|
227
|
+
...coverage.exclude,
|
|
228
|
+
...defaultExcludes,
|
|
229
|
+
],
|
|
230
|
+
}
|
|
231
|
+
: {}),
|
|
232
|
+
...(coverage.reporters
|
|
233
|
+
? { reporter: coverage.reporters }
|
|
178
234
|
: {}),
|
|
179
235
|
};
|
|
180
236
|
}
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
* Unit testing options for Angular applications.
|
|
3
3
|
*/
|
|
4
4
|
export type Schema = {
|
|
5
|
+
/**
|
|
6
|
+
* Specifies the browser viewport dimensions for browser-based tests in the format
|
|
7
|
+
* `widthxheight`.
|
|
8
|
+
*/
|
|
9
|
+
browserViewport?: string;
|
|
5
10
|
/**
|
|
6
11
|
* Specifies the browsers to use for test execution. When not specified, tests are run in a
|
|
7
12
|
* Node.js environment using jsdom. For both Vitest and Karma, browser names ending with
|
|
@@ -10,25 +15,45 @@ export type Schema = {
|
|
|
10
15
|
browsers?: string[];
|
|
11
16
|
/**
|
|
12
17
|
* Specifies the build target to use for the unit test build in the format
|
|
13
|
-
* `project:target[:configuration]`.
|
|
18
|
+
* `project:target[:configuration]`. This defaults to the `build` target of the current
|
|
19
|
+
* project with the `development` configuration. You can also pass a comma-separated list of
|
|
14
20
|
* configurations. Example: `project:target:production,staging`.
|
|
15
21
|
*/
|
|
16
|
-
buildTarget
|
|
22
|
+
buildTarget?: string;
|
|
17
23
|
/**
|
|
18
|
-
* Enables
|
|
24
|
+
* Enables coverage reporting for tests.
|
|
19
25
|
*/
|
|
20
|
-
|
|
26
|
+
coverage?: boolean;
|
|
21
27
|
/**
|
|
22
|
-
*
|
|
28
|
+
* Includes all files that match the `coverageInclude` pattern in the coverage report, not
|
|
29
|
+
* just those touched by tests.
|
|
23
30
|
*/
|
|
24
|
-
|
|
31
|
+
coverageAll?: boolean;
|
|
25
32
|
/**
|
|
26
|
-
* Specifies
|
|
33
|
+
* Specifies glob patterns of files to exclude from the coverage report.
|
|
34
|
+
*/
|
|
35
|
+
coverageExclude?: string[];
|
|
36
|
+
/**
|
|
37
|
+
* Specifies glob patterns of files to include in the coverage report.
|
|
38
|
+
*/
|
|
39
|
+
coverageInclude?: string[];
|
|
40
|
+
/**
|
|
41
|
+
* Specifies the reporters to use for coverage results. Each reporter can be a string
|
|
27
42
|
* representing its name, or a tuple containing the name and an options object. Built-in
|
|
28
43
|
* reporters include 'html', 'lcov', 'lcovonly', 'text', 'text-summary', 'cobertura',
|
|
29
44
|
* 'json', and 'json-summary'.
|
|
30
45
|
*/
|
|
31
|
-
|
|
46
|
+
coverageReporters?: SchemaCoverageReporter[];
|
|
47
|
+
/**
|
|
48
|
+
* Specifies minimum coverage thresholds that must be met. If thresholds are not met, the
|
|
49
|
+
* builder will exit with an error.
|
|
50
|
+
*/
|
|
51
|
+
coverageThresholds?: CoverageThresholds;
|
|
52
|
+
/**
|
|
53
|
+
* Specifies coverage watermarks for the HTML reporter. These determine the color coding for
|
|
54
|
+
* high, medium, and low coverage.
|
|
55
|
+
*/
|
|
56
|
+
coverageWatermarks?: CoverageWatermarks;
|
|
32
57
|
/**
|
|
33
58
|
* Enables debugging mode for tests, allowing the use of the Node Inspector.
|
|
34
59
|
*/
|
|
@@ -92,20 +117,22 @@ export type Schema = {
|
|
|
92
117
|
*/
|
|
93
118
|
setupFiles?: string[];
|
|
94
119
|
/**
|
|
95
|
-
* The path to the TypeScript configuration file, relative to the workspace root.
|
|
120
|
+
* The path to the TypeScript configuration file, relative to the workspace root. Defaults
|
|
121
|
+
* to `tsconfig.spec.json` in the project root if it exists. If not specified and the
|
|
122
|
+
* default does not exist, the `tsConfig` from the specified `buildTarget` will be used.
|
|
96
123
|
*/
|
|
97
|
-
tsConfig
|
|
124
|
+
tsConfig?: string;
|
|
98
125
|
/**
|
|
99
126
|
* Enables watch mode, which re-runs tests when source files change. Defaults to `true` in
|
|
100
127
|
* TTY environments and `false` otherwise.
|
|
101
128
|
*/
|
|
102
129
|
watch?: boolean;
|
|
103
130
|
};
|
|
104
|
-
export type
|
|
105
|
-
export type
|
|
131
|
+
export type SchemaCoverageReporter = CoverageReporterCoverageReporterUnion[] | CoverageReporterEnum;
|
|
132
|
+
export type CoverageReporterCoverageReporterUnion = CoverageReporterEnum | {
|
|
106
133
|
[key: string]: any;
|
|
107
134
|
};
|
|
108
|
-
export declare enum
|
|
135
|
+
export declare enum CoverageReporterEnum {
|
|
109
136
|
Cobertura = "cobertura",
|
|
110
137
|
Html = "html",
|
|
111
138
|
Json = "json",
|
|
@@ -115,6 +142,54 @@ export declare enum CoverageReporters {
|
|
|
115
142
|
Text = "text",
|
|
116
143
|
TextSummary = "text-summary"
|
|
117
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Specifies minimum coverage thresholds that must be met. If thresholds are not met, the
|
|
147
|
+
* builder will exit with an error.
|
|
148
|
+
*/
|
|
149
|
+
export type CoverageThresholds = {
|
|
150
|
+
/**
|
|
151
|
+
* Minimum percentage of branches covered.
|
|
152
|
+
*/
|
|
153
|
+
branches?: number;
|
|
154
|
+
/**
|
|
155
|
+
* Minimum percentage of functions covered.
|
|
156
|
+
*/
|
|
157
|
+
functions?: number;
|
|
158
|
+
/**
|
|
159
|
+
* Minimum percentage of lines covered.
|
|
160
|
+
*/
|
|
161
|
+
lines?: number;
|
|
162
|
+
/**
|
|
163
|
+
* When true, thresholds are enforced for each file individually.
|
|
164
|
+
*/
|
|
165
|
+
perFile?: boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Minimum percentage of statements covered.
|
|
168
|
+
*/
|
|
169
|
+
statements?: number;
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Specifies coverage watermarks for the HTML reporter. These determine the color coding for
|
|
173
|
+
* high, medium, and low coverage.
|
|
174
|
+
*/
|
|
175
|
+
export type CoverageWatermarks = {
|
|
176
|
+
/**
|
|
177
|
+
* The high and low watermarks for branches coverage. `[low, high]`
|
|
178
|
+
*/
|
|
179
|
+
branches?: number[];
|
|
180
|
+
/**
|
|
181
|
+
* The high and low watermarks for functions coverage. `[low, high]`
|
|
182
|
+
*/
|
|
183
|
+
functions?: number[];
|
|
184
|
+
/**
|
|
185
|
+
* The high and low watermarks for lines coverage. `[low, high]`
|
|
186
|
+
*/
|
|
187
|
+
lines?: number[];
|
|
188
|
+
/**
|
|
189
|
+
* The high and low watermarks for statements coverage. `[low, high]`
|
|
190
|
+
*/
|
|
191
|
+
statements?: number[];
|
|
192
|
+
};
|
|
118
193
|
export type SchemaReporter = ReporterReporter[] | string;
|
|
119
194
|
export type ReporterReporter = {
|
|
120
195
|
[key: string]: any;
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
|
|
3
3
|
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.Runner = exports.
|
|
6
|
-
var
|
|
7
|
-
(function (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
})(
|
|
5
|
+
exports.Runner = exports.CoverageReporterEnum = void 0;
|
|
6
|
+
var CoverageReporterEnum;
|
|
7
|
+
(function (CoverageReporterEnum) {
|
|
8
|
+
CoverageReporterEnum["Cobertura"] = "cobertura";
|
|
9
|
+
CoverageReporterEnum["Html"] = "html";
|
|
10
|
+
CoverageReporterEnum["Json"] = "json";
|
|
11
|
+
CoverageReporterEnum["JsonSummary"] = "json-summary";
|
|
12
|
+
CoverageReporterEnum["Lcov"] = "lcov";
|
|
13
|
+
CoverageReporterEnum["Lcovonly"] = "lcovonly";
|
|
14
|
+
CoverageReporterEnum["Text"] = "text";
|
|
15
|
+
CoverageReporterEnum["TextSummary"] = "text-summary";
|
|
16
|
+
})(CoverageReporterEnum || (exports.CoverageReporterEnum = CoverageReporterEnum = {}));
|
|
17
17
|
/**
|
|
18
18
|
* Specifies the test runner to use for test execution.
|
|
19
19
|
*/
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"properties": {
|
|
7
7
|
"buildTarget": {
|
|
8
8
|
"type": "string",
|
|
9
|
-
"description": "Specifies the build target to use for the unit test build in the format `project:target[:configuration]`. You can also pass a comma-separated list of configurations. Example: `project:target:production,staging`.",
|
|
9
|
+
"description": "Specifies the build target to use for the unit test build in the format `project:target[:configuration]`. This defaults to the `build` target of the current project with the `development` configuration. You can also pass a comma-separated list of configurations. Example: `project:target:production,staging`.",
|
|
10
10
|
"pattern": "^[^:\\s]*:[^:\\s]*(:[^\\s]+)?$"
|
|
11
11
|
},
|
|
12
12
|
"tsConfig": {
|
|
13
13
|
"type": "string",
|
|
14
|
-
"description": "The path to the TypeScript configuration file, relative to the workspace root."
|
|
14
|
+
"description": "The path to the TypeScript configuration file, relative to the workspace root. Defaults to `tsconfig.spec.json` in the project root if it exists. If not specified and the default does not exist, the `tsConfig` from the specified `buildTarget` will be used."
|
|
15
15
|
},
|
|
16
16
|
"runner": {
|
|
17
17
|
"type": "string",
|
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
},
|
|
27
27
|
"minItems": 1
|
|
28
28
|
},
|
|
29
|
+
"browserViewport": {
|
|
30
|
+
"description": "Specifies the browser viewport dimensions for browser-based tests in the format `widthxheight`.",
|
|
31
|
+
"type": "string",
|
|
32
|
+
"pattern": "^\\d+x\\d+$"
|
|
33
|
+
},
|
|
29
34
|
"include": {
|
|
30
35
|
"type": "array",
|
|
31
36
|
"items": {
|
|
@@ -54,25 +59,46 @@
|
|
|
54
59
|
"description": "Enables debugging mode for tests, allowing the use of the Node Inspector.",
|
|
55
60
|
"default": false
|
|
56
61
|
},
|
|
57
|
-
"
|
|
62
|
+
"coverage": {
|
|
58
63
|
"type": "boolean",
|
|
59
|
-
"description": "Enables
|
|
64
|
+
"description": "Enables coverage reporting for tests.",
|
|
60
65
|
"default": false
|
|
61
66
|
},
|
|
62
|
-
"
|
|
67
|
+
"coverageAll": {
|
|
68
|
+
"type": "boolean",
|
|
69
|
+
"description": "Includes all files that match the `coverageInclude` pattern in the coverage report, not just those touched by tests.",
|
|
70
|
+
"default": true
|
|
71
|
+
},
|
|
72
|
+
"coverageInclude": {
|
|
63
73
|
"type": "array",
|
|
64
|
-
"description": "Specifies glob patterns of files to
|
|
74
|
+
"description": "Specifies glob patterns of files to include in the coverage report.",
|
|
65
75
|
"items": {
|
|
66
76
|
"type": "string"
|
|
67
77
|
}
|
|
68
78
|
},
|
|
69
|
-
"
|
|
79
|
+
"coverageExclude": {
|
|
70
80
|
"type": "array",
|
|
71
|
-
"description": "Specifies
|
|
81
|
+
"description": "Specifies glob patterns of files to exclude from the coverage report.",
|
|
82
|
+
"items": {
|
|
83
|
+
"type": "string"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"coverageReporters": {
|
|
87
|
+
"type": "array",
|
|
88
|
+
"description": "Specifies the reporters to use for coverage results. Each reporter can be a string representing its name, or a tuple containing the name and an options object. Built-in reporters include 'html', 'lcov', 'lcovonly', 'text', 'text-summary', 'cobertura', 'json', and 'json-summary'.",
|
|
72
89
|
"items": {
|
|
73
90
|
"oneOf": [
|
|
74
91
|
{
|
|
75
|
-
"
|
|
92
|
+
"enum": [
|
|
93
|
+
"html",
|
|
94
|
+
"lcov",
|
|
95
|
+
"lcovonly",
|
|
96
|
+
"text",
|
|
97
|
+
"text-summary",
|
|
98
|
+
"cobertura",
|
|
99
|
+
"json",
|
|
100
|
+
"json-summary"
|
|
101
|
+
]
|
|
76
102
|
},
|
|
77
103
|
{
|
|
78
104
|
"type": "array",
|
|
@@ -80,7 +106,16 @@
|
|
|
80
106
|
"maxItems": 2,
|
|
81
107
|
"items": [
|
|
82
108
|
{
|
|
83
|
-
"
|
|
109
|
+
"enum": [
|
|
110
|
+
"html",
|
|
111
|
+
"lcov",
|
|
112
|
+
"lcovonly",
|
|
113
|
+
"text",
|
|
114
|
+
"text-summary",
|
|
115
|
+
"cobertura",
|
|
116
|
+
"json",
|
|
117
|
+
"json-summary"
|
|
118
|
+
]
|
|
84
119
|
},
|
|
85
120
|
{
|
|
86
121
|
"type": "object"
|
|
@@ -90,6 +125,68 @@
|
|
|
90
125
|
]
|
|
91
126
|
}
|
|
92
127
|
},
|
|
128
|
+
"coverageThresholds": {
|
|
129
|
+
"type": "object",
|
|
130
|
+
"description": "Specifies minimum coverage thresholds that must be met. If thresholds are not met, the builder will exit with an error.",
|
|
131
|
+
"properties": {
|
|
132
|
+
"perFile": {
|
|
133
|
+
"type": "boolean",
|
|
134
|
+
"description": "When true, thresholds are enforced for each file individually."
|
|
135
|
+
},
|
|
136
|
+
"statements": {
|
|
137
|
+
"type": "number",
|
|
138
|
+
"description": "Minimum percentage of statements covered."
|
|
139
|
+
},
|
|
140
|
+
"branches": {
|
|
141
|
+
"type": "number",
|
|
142
|
+
"description": "Minimum percentage of branches covered."
|
|
143
|
+
},
|
|
144
|
+
"functions": {
|
|
145
|
+
"type": "number",
|
|
146
|
+
"description": "Minimum percentage of functions covered."
|
|
147
|
+
},
|
|
148
|
+
"lines": {
|
|
149
|
+
"type": "number",
|
|
150
|
+
"description": "Minimum percentage of lines covered."
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"additionalProperties": false
|
|
154
|
+
},
|
|
155
|
+
"coverageWatermarks": {
|
|
156
|
+
"type": "object",
|
|
157
|
+
"description": "Specifies coverage watermarks for the HTML reporter. These determine the color coding for high, medium, and low coverage.",
|
|
158
|
+
"properties": {
|
|
159
|
+
"statements": {
|
|
160
|
+
"type": "array",
|
|
161
|
+
"description": "The high and low watermarks for statements coverage. `[low, high]`",
|
|
162
|
+
"items": { "type": "number" },
|
|
163
|
+
"minItems": 2,
|
|
164
|
+
"maxItems": 2
|
|
165
|
+
},
|
|
166
|
+
"branches": {
|
|
167
|
+
"type": "array",
|
|
168
|
+
"description": "The high and low watermarks for branches coverage. `[low, high]`",
|
|
169
|
+
"items": { "type": "number" },
|
|
170
|
+
"minItems": 2,
|
|
171
|
+
"maxItems": 2
|
|
172
|
+
},
|
|
173
|
+
"functions": {
|
|
174
|
+
"type": "array",
|
|
175
|
+
"description": "The high and low watermarks for functions coverage. `[low, high]`",
|
|
176
|
+
"items": { "type": "number" },
|
|
177
|
+
"minItems": 2,
|
|
178
|
+
"maxItems": 2
|
|
179
|
+
},
|
|
180
|
+
"lines": {
|
|
181
|
+
"type": "array",
|
|
182
|
+
"description": "The high and low watermarks for lines coverage. `[low, high]`",
|
|
183
|
+
"items": { "type": "number" },
|
|
184
|
+
"minItems": 2,
|
|
185
|
+
"maxItems": 2
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"additionalProperties": false
|
|
189
|
+
},
|
|
93
190
|
"reporters": {
|
|
94
191
|
"type": "array",
|
|
95
192
|
"description": "Specifies the reporters to use during test execution. Each reporter can be a string representing its name, or a tuple containing the name and an options object. Built-in reporters include 'default', 'verbose', 'dots', 'json', 'junit', 'tap', 'tap-flat', and 'html'. You can also provide a path to a custom reporter.",
|
|
@@ -98,10 +195,10 @@
|
|
|
98
195
|
{
|
|
99
196
|
"anyOf": [
|
|
100
197
|
{
|
|
101
|
-
"
|
|
198
|
+
"type": "string"
|
|
102
199
|
},
|
|
103
200
|
{
|
|
104
|
-
"
|
|
201
|
+
"enum": ["default", "verbose", "dots", "json", "junit", "tap", "tap-flat", "html"]
|
|
105
202
|
}
|
|
106
203
|
]
|
|
107
204
|
},
|
|
@@ -113,10 +210,19 @@
|
|
|
113
210
|
{
|
|
114
211
|
"anyOf": [
|
|
115
212
|
{
|
|
116
|
-
"
|
|
213
|
+
"type": "string"
|
|
117
214
|
},
|
|
118
215
|
{
|
|
119
|
-
"
|
|
216
|
+
"enum": [
|
|
217
|
+
"default",
|
|
218
|
+
"verbose",
|
|
219
|
+
"dots",
|
|
220
|
+
"json",
|
|
221
|
+
"junit",
|
|
222
|
+
"tap",
|
|
223
|
+
"tap-flat",
|
|
224
|
+
"html"
|
|
225
|
+
]
|
|
120
226
|
}
|
|
121
227
|
]
|
|
122
228
|
},
|
|
@@ -161,23 +267,5 @@
|
|
|
161
267
|
}
|
|
162
268
|
},
|
|
163
269
|
"additionalProperties": false,
|
|
164
|
-
"required": ["
|
|
165
|
-
"definitions": {
|
|
166
|
-
"coverage-reporters": {
|
|
167
|
-
"enum": [
|
|
168
|
-
"html",
|
|
169
|
-
"lcov",
|
|
170
|
-
"lcovonly",
|
|
171
|
-
"text",
|
|
172
|
-
"text-summary",
|
|
173
|
-
"cobertura",
|
|
174
|
-
"json",
|
|
175
|
-
"json-summary"
|
|
176
|
-
]
|
|
177
|
-
},
|
|
178
|
-
"reporters-enum": {
|
|
179
|
-
"type": "string",
|
|
180
|
-
"enum": ["default", "verbose", "dots", "json", "junit", "tap", "tap-flat", "html"]
|
|
181
|
-
}
|
|
182
|
-
}
|
|
270
|
+
"required": ["runner"]
|
|
183
271
|
}
|
|
@@ -48,6 +48,7 @@ async function findTests(include, exclude, workspaceRoot, projectSourceRoot) {
|
|
|
48
48
|
const globMatches = await (0, tinyglobby_1.glob)(dynamicPatterns, {
|
|
49
49
|
cwd: projectSourceRoot,
|
|
50
50
|
absolute: true,
|
|
51
|
+
expandDirectories: false,
|
|
51
52
|
ignore: ['**/node_modules/**', ...normalizedExcludes],
|
|
52
53
|
});
|
|
53
54
|
for (const match of globMatches) {
|
|
@@ -47,7 +47,11 @@ exports.default = default_1;
|
|
|
47
47
|
const helper_annotate_as_pure_1 = __importDefault(require("@babel/helper-annotate-as-pure"));
|
|
48
48
|
const tslib = __importStar(require("tslib"));
|
|
49
49
|
/**
|
|
50
|
-
* A
|
|
50
|
+
* A set of constructor names that are considered to be side-effect free.
|
|
51
|
+
*/
|
|
52
|
+
const sideEffectFreeConstructors = new Set(['InjectionToken']);
|
|
53
|
+
/**
|
|
54
|
+
* A set of TypeScript helper function names used by the helper name matcher utility function.
|
|
51
55
|
*/
|
|
52
56
|
const tslibHelpers = new Set(Object.keys(tslib).filter((h) => h.startsWith('__')));
|
|
53
57
|
/**
|
|
@@ -76,13 +80,16 @@ function isBabelHelperName(name) {
|
|
|
76
80
|
}
|
|
77
81
|
/**
|
|
78
82
|
* A babel plugin factory function for adding the PURE annotation to top-level new and call expressions.
|
|
79
|
-
*
|
|
80
83
|
* @returns A babel plugin object instance.
|
|
81
84
|
*/
|
|
82
85
|
function default_1() {
|
|
83
86
|
return {
|
|
84
87
|
visitor: {
|
|
85
|
-
CallExpression(path) {
|
|
88
|
+
CallExpression(path, state) {
|
|
89
|
+
const { topLevelSafeMode = false } = state.opts;
|
|
90
|
+
if (topLevelSafeMode) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
86
93
|
// If the expression has a function parent, it is not top-level
|
|
87
94
|
if (path.getFunctionParent()) {
|
|
88
95
|
return;
|
|
@@ -100,9 +107,18 @@ function default_1() {
|
|
|
100
107
|
}
|
|
101
108
|
(0, helper_annotate_as_pure_1.default)(path);
|
|
102
109
|
},
|
|
103
|
-
NewExpression(path) {
|
|
110
|
+
NewExpression(path, state) {
|
|
104
111
|
// If the expression has a function parent, it is not top-level
|
|
105
|
-
if (
|
|
112
|
+
if (path.getFunctionParent()) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const { topLevelSafeMode = false } = state.opts;
|
|
116
|
+
if (!topLevelSafeMode) {
|
|
117
|
+
(0, helper_annotate_as_pure_1.default)(path);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const callee = path.get('callee');
|
|
121
|
+
if (callee.isIdentifier() && sideEffectFreeConstructors.has(callee.node.name)) {
|
|
106
122
|
(0, helper_annotate_as_pure_1.default)(path);
|
|
107
123
|
}
|
|
108
124
|
},
|
|
@@ -46,6 +46,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
46
46
|
exports.createCompilerPlugin = createCompilerPlugin;
|
|
47
47
|
const node_assert_1 = __importDefault(require("node:assert"));
|
|
48
48
|
const node_crypto_1 = require("node:crypto");
|
|
49
|
+
const promises_1 = require("node:fs/promises");
|
|
49
50
|
const path = __importStar(require("node:path"));
|
|
50
51
|
const environment_options_1 = require("../../../utils/environment-options");
|
|
51
52
|
const compilation_1 = require("../../angular/compilation");
|
|
@@ -344,11 +345,21 @@ function createCompilerPlugin(pluginOptions, compilationOrFactory, stylesheetBun
|
|
|
344
345
|
if (!shouldTsIgnoreJs && isJS) {
|
|
345
346
|
return undefined;
|
|
346
347
|
}
|
|
348
|
+
const diangosticRoot = build.initialOptions.absWorkingDir ?? '';
|
|
349
|
+
// Evaluate whether the file requires the Angular compiler transpilation.
|
|
350
|
+
// If not, issue a warning but allow bundler to process the file (no type-checking).
|
|
351
|
+
const directContents = await (0, promises_1.readFile)(request, 'utf-8');
|
|
352
|
+
if (!requiresAngularCompiler(directContents)) {
|
|
353
|
+
return {
|
|
354
|
+
warnings: [createMissingFileDiagnostic(request, args.path, diangosticRoot, false)],
|
|
355
|
+
contents,
|
|
356
|
+
loader: 'ts',
|
|
357
|
+
resolveDir: path.dirname(request),
|
|
358
|
+
};
|
|
359
|
+
}
|
|
347
360
|
// Otherwise return an error
|
|
348
361
|
return {
|
|
349
|
-
errors: [
|
|
350
|
-
createMissingFileError(request, args.path, build.initialOptions.absWorkingDir ?? ''),
|
|
351
|
-
],
|
|
362
|
+
errors: [createMissingFileDiagnostic(request, args.path, diangosticRoot, true)],
|
|
352
363
|
};
|
|
353
364
|
}
|
|
354
365
|
else if (typeof contents === 'string' && (useTypeScriptTranspilation || isJS)) {
|
|
@@ -585,21 +596,34 @@ function bundleWebWorker(build, pluginOptions, workerFile) {
|
|
|
585
596
|
throw error;
|
|
586
597
|
}
|
|
587
598
|
}
|
|
588
|
-
function
|
|
599
|
+
function createMissingFileDiagnostic(request, original, root, angular) {
|
|
589
600
|
const relativeRequest = path.relative(root, request);
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
notes
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
601
|
+
const notes = [];
|
|
602
|
+
if (angular) {
|
|
603
|
+
notes.push({
|
|
604
|
+
text: `Files containing Angular metadata ('@Component'/'@Directive'/etc.) must be part of the TypeScript compilation.` +
|
|
605
|
+
` You can ensure the file is part of the TypeScript program via the 'files' or 'include' property.`,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
notes.push({
|
|
610
|
+
text: `The file will be bundled and included in the output but will not be type-checked at build time.` +
|
|
611
|
+
` To remove this message you can add the file to the TypeScript program via the 'files' or 'include' property.`,
|
|
612
|
+
});
|
|
613
|
+
}
|
|
598
614
|
const relativeOriginal = path.relative(root, original);
|
|
599
615
|
if (relativeRequest !== relativeOriginal) {
|
|
600
|
-
|
|
616
|
+
notes.push({
|
|
601
617
|
text: `File is requested from a file replacement of '${relativeOriginal}'.`,
|
|
602
618
|
});
|
|
603
619
|
}
|
|
604
|
-
|
|
620
|
+
const diagnostic = {
|
|
621
|
+
text: `File '${relativeRequest}' not found in TypeScript compilation.`,
|
|
622
|
+
notes,
|
|
623
|
+
};
|
|
624
|
+
return diagnostic;
|
|
625
|
+
}
|
|
626
|
+
const POTENTIAL_METADATA_REGEX = /@angular\/core|@Component|@Directive|@Injectable|@Pipe|@NgModule/;
|
|
627
|
+
function requiresAngularCompiler(contents) {
|
|
628
|
+
return POTENTIAL_METADATA_REGEX.test(contents);
|
|
605
629
|
}
|
|
@@ -84,16 +84,10 @@ async function transformWithBabel(filename, data, options) {
|
|
|
84
84
|
plugins.push(linkerPlugin);
|
|
85
85
|
}
|
|
86
86
|
if (options.advancedOptimizations) {
|
|
87
|
+
const { adjustStaticMembers, adjustTypeScriptEnums, elideAngularMetadata, markTopLevelPure } = await Promise.resolve().then(() => __importStar(require('../babel/plugins')));
|
|
87
88
|
const sideEffectFree = options.sideEffects === false;
|
|
88
89
|
const safeAngularPackage = sideEffectFree && /[\\/]node_modules[\\/]@angular[\\/]/.test(filename);
|
|
89
|
-
|
|
90
|
-
if (safeAngularPackage) {
|
|
91
|
-
plugins.push(markTopLevelPure);
|
|
92
|
-
}
|
|
93
|
-
plugins.push(elideAngularMetadata, adjustTypeScriptEnums, [
|
|
94
|
-
adjustStaticMembers,
|
|
95
|
-
{ wrapDecorators: sideEffectFree },
|
|
96
|
-
]);
|
|
90
|
+
plugins.push([markTopLevelPure, { topLevelSafeMode: !safeAngularPackage }], elideAngularMetadata, adjustTypeScriptEnums, [adjustStaticMembers, { wrapDecorators: sideEffectFree }]);
|
|
97
91
|
}
|
|
98
92
|
// If no additional transformations are needed, return the data directly
|
|
99
93
|
if (plugins.length === 0) {
|
|
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.normalizeCacheOptions = normalizeCacheOptions;
|
|
11
11
|
const node_path_1 = require("node:path");
|
|
12
12
|
/** Version placeholder is replaced during the build process with actual package version */
|
|
13
|
-
const VERSION = '21.0.0-next.
|
|
13
|
+
const VERSION = '21.0.0-next.7';
|
|
14
14
|
function hasCacheMetadata(value) {
|
|
15
15
|
return (!!value &&
|
|
16
16
|
typeof value === 'object' &&
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
8
|
import type { createRequestHandler } from '@angular/ssr';
|
|
9
|
-
import type { createNodeRequestHandler } from '@angular/ssr/node';
|
|
9
|
+
import type { createNodeRequestHandler } from '@angular/ssr/node' with { 'resolution-mode': 'import' };
|
|
10
10
|
export declare function isSsrNodeRequestHandler(value: unknown): value is ReturnType<typeof createNodeRequestHandler>;
|
|
11
11
|
export declare function isSsrRequestHandler(value: unknown): value is ReturnType<typeof createRequestHandler>;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
|
-
import type { Config, Filesystem } from '@angular/service-worker/config';
|
|
8
|
+
import type { Config, Filesystem } from '@angular/service-worker/config' with { 'resolution-mode': 'import' };
|
|
9
9
|
import { promises as fsPromises } from 'node:fs';
|
|
10
10
|
import { BuildOutputFile } from '../tools/esbuild/bundler-context';
|
|
11
11
|
import { BuildOutputAsset } from '../tools/esbuild/bundler-execution-result';
|