@blotch/angular-lynx-build 0.0.0-stage → 22.2.3
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 +110 -2
- package/builders/angular-build.js +117 -0
- package/builders/application/index.js +165 -0
- package/builders/application/native-cache.js +56 -0
- package/builders/application/schema.js +2 -0
- package/builders/application/schema.json +229 -0
- package/builders/builders.json +24 -0
- package/builders/dev-server/index.js +82 -0
- package/builders/dev-server/schema.js +2 -0
- package/builders/dev-server/schema.json +28 -0
- package/builders/extract-i18n/index.js +70 -0
- package/builders/extract-i18n/schema.js +2 -0
- package/builders/extract-i18n/schema.json +49 -0
- package/builders/package.json +3 -0
- package/builders/project-import.js +64 -0
- package/builders/rspeedy.js +162 -0
- package/builders/unit-test/index.js +96 -0
- package/builders/unit-test/lynx-globals.d.mts +3 -0
- package/builders/unit-test/lynx-globals.mjs +18 -0
- package/builders/unit-test/schema.js +2 -0
- package/builders/unit-test/schema.json +311 -0
- package/client.d.ts +8 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +14 -0
- package/package.json +80 -4
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createRspeedy = exports.modeFromOptimization = exports.importQRCodePlugin = exports.importPlugin = exports.importRspeedy = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
/**
|
|
10
|
+
* Like the rsbuild plugin, rspeedy is this package's own dependency, so the
|
|
11
|
+
* builders always run the rspeedy version they were released and tested with,
|
|
12
|
+
* and an app needs no build tool in its package.json besides this package
|
|
13
|
+
* (as one from `ng new` needs only `@angular/build`).
|
|
14
|
+
*/
|
|
15
|
+
const importRspeedy = () => import('@lynx-js/rspeedy');
|
|
16
|
+
exports.importRspeedy = importRspeedy;
|
|
17
|
+
/**
|
|
18
|
+
* Unlike rspeedy, the plugin is this package's own dependency, so it is
|
|
19
|
+
* resolved from here rather than from the project: the builders always run
|
|
20
|
+
* the plugin version they were released with.
|
|
21
|
+
*/
|
|
22
|
+
const importPlugin = () => import('@blotch/rsbuild-plugin-angular-lynx');
|
|
23
|
+
exports.importPlugin = importPlugin;
|
|
24
|
+
const importQRCodePlugin = () => import('@lynx-js/qrcode-rsbuild-plugin');
|
|
25
|
+
exports.importQRCodePlugin = importQRCodePlugin;
|
|
26
|
+
/** The name `pluginAngularLynx()` registers itself under. */
|
|
27
|
+
const ANGULAR_PLUGIN_NAME = 'lynx:angular';
|
|
28
|
+
/** The name `pluginQRCode()` registers itself under. */
|
|
29
|
+
const QR_CODE_PLUGIN_NAME = 'lynx:rsbuild:qrcode';
|
|
30
|
+
/**
|
|
31
|
+
* The files rspeedy looks for when no `config` option names one, in its order
|
|
32
|
+
* (`resolveConfigPath` in @lynx-js/rspeedy).
|
|
33
|
+
*/
|
|
34
|
+
const DEFAULT_CONFIG_FILES = [
|
|
35
|
+
'lynx.config.ts',
|
|
36
|
+
'lynx.config.js',
|
|
37
|
+
'lynx.config.mts',
|
|
38
|
+
'lynx.config.mjs',
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* Whether an rspeedy `plugins` list holds the plugin named `name`. The list
|
|
42
|
+
* takes Rsbuild's shapes: plugins, falsy entries (from `cond && plugin()`),
|
|
43
|
+
* promises of either, and nested lists.
|
|
44
|
+
*/
|
|
45
|
+
const hasPlugin = async (plugins, name) => {
|
|
46
|
+
const plugin = await plugins;
|
|
47
|
+
if (Array.isArray(plugin)) {
|
|
48
|
+
for (const item of plugin) {
|
|
49
|
+
if (await hasPlugin(item, name)) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
return plugin?.name === name;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* The rspeedy mode for a build target's options. Angular has no mode option:
|
|
59
|
+
* its `optimization` decides, and a build that doesn't optimize scripts runs
|
|
60
|
+
* in dev mode (`ngDevMode` on). The same switch picks rspeedy's mode, so
|
|
61
|
+
* `ng build -c development` (`optimization: false`) is a development build
|
|
62
|
+
* and `ng serve -c production` a production one.
|
|
63
|
+
*/
|
|
64
|
+
const modeFromOptimization = (optimization) => {
|
|
65
|
+
// Angular's own reading of the option (normalizeOptimization in
|
|
66
|
+
// @angular/build): on by default, and in object form `scripts` decides.
|
|
67
|
+
const scripts = typeof optimization === 'object' && optimization !== null
|
|
68
|
+
? !!optimization.scripts
|
|
69
|
+
: optimization !== false;
|
|
70
|
+
return scripts ? 'production' : 'development';
|
|
71
|
+
};
|
|
72
|
+
exports.modeFromOptimization = modeFromOptimization;
|
|
73
|
+
/**
|
|
74
|
+
* Loads lynx.config.ts as `rspeedy build` and `rspeedy dev` would. Unlike
|
|
75
|
+
* them, a project without one builds too, from the defaults
|
|
76
|
+
* {@link createRspeedy} fills in: angular.json holds what the config would
|
|
77
|
+
* repeat, as it does for any Angular app. A `config` option must name a file
|
|
78
|
+
* that exists.
|
|
79
|
+
*/
|
|
80
|
+
const loadProjectConfig = async (rspeedy, projectRoot, config) => {
|
|
81
|
+
if (!config &&
|
|
82
|
+
!DEFAULT_CONFIG_FILES.some((file) => (0, node_fs_1.existsSync)(node_path_1.default.join(projectRoot, file)))) {
|
|
83
|
+
return { content: {} };
|
|
84
|
+
}
|
|
85
|
+
return rspeedy.loadConfig({ cwd: projectRoot, configPath: config });
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Creates an rspeedy instance the way `rspeedy build` and `rspeedy dev` do:
|
|
89
|
+
* load lynx.config.ts, then apply the command-line overrides, which here come
|
|
90
|
+
* from the builder options.
|
|
91
|
+
*
|
|
92
|
+
* What lynx.config.ts leaves out comes from angular.json and the defaults an
|
|
93
|
+
* AngularLynx app needs, so most apps don't need the file at all:
|
|
94
|
+
*
|
|
95
|
+
* - `source.entry` is the build target's `browser` option.
|
|
96
|
+
* - `environments` are `lynx` (the native bundle) and `web` (the browser
|
|
97
|
+
* preview).
|
|
98
|
+
* - The mode follows the build target's `optimization` (see
|
|
99
|
+
* {@link modeFromOptimization}).
|
|
100
|
+
*
|
|
101
|
+
* It also adds plugins, each unless lynx.config.ts lists it itself (to pass
|
|
102
|
+
* it options): the AngularLynx plugin, which compiles Angular, and for the
|
|
103
|
+
* dev server the QR code plugin, which prints the link Lynx Explorer opens.
|
|
104
|
+
* And the Angular CLI context plugin hands the AngularLynx plugin the project
|
|
105
|
+
* and its build options as Angular CLI resolved them (`-c` and command-line
|
|
106
|
+
* overrides included), which it would otherwise read from angular.json under
|
|
107
|
+
* the default configuration.
|
|
108
|
+
*/
|
|
109
|
+
const createRspeedy = async ({ rspeedy, plugin, qrCode, projectRoot, angularCli, config, environment, server, }) => {
|
|
110
|
+
const mode = (0, exports.modeFromOptimization)(angularCli.buildOptions['optimization']);
|
|
111
|
+
// As the rspeedy CLI does before anything else, so plugins (Tailwind,
|
|
112
|
+
// PostCSS) that read NODE_ENV agree with the mode. The CLI derives it from
|
|
113
|
+
// the command; here the mode decides, as `optimization` does for Angular.
|
|
114
|
+
if (!process.env['NODE_ENV']) {
|
|
115
|
+
process.env['NODE_ENV'] = mode;
|
|
116
|
+
}
|
|
117
|
+
const { content, configPath } = await loadProjectConfig(rspeedy, projectRoot, config);
|
|
118
|
+
// As `rspeedy build` does: a persistent build cache must be invalidated
|
|
119
|
+
// when lynx.config.ts itself changes.
|
|
120
|
+
const performance = content['performance'];
|
|
121
|
+
if (configPath) {
|
|
122
|
+
if (performance?.buildCache === true) {
|
|
123
|
+
performance.buildCache = { buildDependencies: [configPath] };
|
|
124
|
+
}
|
|
125
|
+
else if (performance?.buildCache) {
|
|
126
|
+
(performance.buildCache.buildDependencies ??= []).push(configPath);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
content.mode = mode;
|
|
130
|
+
content['environments'] ??= { lynx: {}, web: {} };
|
|
131
|
+
const browser = angularCli.buildOptions['browser'];
|
|
132
|
+
const source = (content['source'] ??= {});
|
|
133
|
+
if (source.entry === undefined && typeof browser === 'string') {
|
|
134
|
+
source.entry = node_path_1.default.join(angularCli.workspaceRoot, browser);
|
|
135
|
+
}
|
|
136
|
+
if (server?.port !== undefined || server?.host !== undefined) {
|
|
137
|
+
content['server'] = {
|
|
138
|
+
...content['server'],
|
|
139
|
+
...(server.port !== undefined && { port: server.port }),
|
|
140
|
+
...(server.host !== undefined && { host: server.host }),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const plugins = Array.isArray(content['plugins']) ? content['plugins'] : [];
|
|
144
|
+
content['plugins'] = [
|
|
145
|
+
plugin.pluginAngularCliContext(angularCli),
|
|
146
|
+
...plugins,
|
|
147
|
+
...((await hasPlugin(plugins, ANGULAR_PLUGIN_NAME))
|
|
148
|
+
? []
|
|
149
|
+
: [plugin.pluginAngularLynx()]),
|
|
150
|
+
// `fullscreen` opens the app in Lynx Explorer without its navigation
|
|
151
|
+
// bar, as the rspeedy project template does.
|
|
152
|
+
...(qrCode && !(await hasPlugin(plugins, QR_CODE_PLUGIN_NAME))
|
|
153
|
+
? [qrCode.pluginQRCode({ fullscreen: true })]
|
|
154
|
+
: []),
|
|
155
|
+
];
|
|
156
|
+
return rspeedy.createRspeedy({
|
|
157
|
+
cwd: projectRoot,
|
|
158
|
+
rspeedyConfig: content,
|
|
159
|
+
environment: environment ?? [],
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
exports.createRspeedy = createRspeedy;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runUnitTest = exports.hasTestingLibrary = void 0;
|
|
7
|
+
const architect_1 = require("@angular-devkit/architect");
|
|
8
|
+
const node_module_1 = require("node:module");
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const angular_build_1 = require("../angular-build");
|
|
11
|
+
/**
|
|
12
|
+
* Whether the project has @blotch/angular-lynx-testing-library. Its package.json
|
|
13
|
+
* isn't in its `exports` in every version, and Node then refuses to resolve
|
|
14
|
+
* it, but only when the package is there.
|
|
15
|
+
*/
|
|
16
|
+
const hasTestingLibrary = (projectRoot) => {
|
|
17
|
+
try {
|
|
18
|
+
(0, node_module_1.createRequire)(node_path_1.default.join(projectRoot, 'package.json')).resolve('@blotch/angular-lynx-testing-library/package.json');
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
return (error.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED');
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
exports.hasTestingLibrary = hasTestingLibrary;
|
|
26
|
+
const defaultDeps = {
|
|
27
|
+
importAngularBuild: (projectRoot) => (0, angular_build_1.importAngularBuild)(projectRoot),
|
|
28
|
+
hasTestingLibrary: exports.hasTestingLibrary,
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* The options as Angular CLI hands them to Angular's own builders. For a
|
|
32
|
+
* builder outside `@angular/build`, it sets every array option the user left
|
|
33
|
+
* out to `[]` (and nested ones too, e.g. `coverageWatermarks.lines`), which
|
|
34
|
+
* Angular's unit-test builder reads as set: `reporters: []` runs Vitest with
|
|
35
|
+
* no reporter, so `ng test` printed nothing. An empty list never means more
|
|
36
|
+
* than an absent one here, so empty lists are dropped.
|
|
37
|
+
*/
|
|
38
|
+
const withoutEmptyLists = (value) => {
|
|
39
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
return Object.fromEntries(Object.entries(value)
|
|
43
|
+
.filter(([, item]) => !(Array.isArray(item) && item.length === 0))
|
|
44
|
+
.map(([key, item]) => [key, withoutEmptyLists(item)]));
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* `ng test`: Angular's unit-test builder (`@angular/build:unit-test`), so the
|
|
48
|
+
* options, test discovery (`*.spec.ts` and `*.test.ts`), TestBed, watch mode
|
|
49
|
+
* and coverage are the ones Angular developers know, and the tests compile
|
|
50
|
+
* ahead of time like the app. Two modules load first: one defines the
|
|
51
|
+
* compile-time flags the AngularLynx runtime reads, and, when the project has
|
|
52
|
+
* @blotch/angular-lynx-testing-library, its setup prepares the Lynx
|
|
53
|
+
* environment its `render()` needs.
|
|
54
|
+
*
|
|
55
|
+
* Tests render through Angular's DOM renderer under TestBed and through the
|
|
56
|
+
* Lynx renderer under the testing library's `render()`. Either way the test
|
|
57
|
+
* compile checks templates strictly, as the Angular Language Service does:
|
|
58
|
+
* a component that uses Lynx elements imports LYNX_ELEMENTS (as generated
|
|
59
|
+
* ones do). The app build is laxer, because it adds CUSTOM_ELEMENTS_SCHEMA to
|
|
60
|
+
* every component, which Angular's test build has no hook for.
|
|
61
|
+
*/
|
|
62
|
+
const runUnitTest = async function* (options, context, deps = defaultDeps) {
|
|
63
|
+
const projectName = context.target?.project;
|
|
64
|
+
if (!projectName) {
|
|
65
|
+
yield { success: false, error: 'The builder needs a project target.' };
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const metadata = await context.getProjectMetadata(projectName);
|
|
69
|
+
const projectRoot = node_path_1.default.join(context.workspaceRoot, metadata['root'] ?? '');
|
|
70
|
+
let angularBuild;
|
|
71
|
+
try {
|
|
72
|
+
angularBuild = await deps.importAngularBuild(projectRoot);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
yield {
|
|
76
|
+
success: false,
|
|
77
|
+
error: error instanceof Error ? error.message : String(error),
|
|
78
|
+
};
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// The Lynx setup goes in as polyfills rather than `setupFiles` because
|
|
82
|
+
// Angular compiles setup files with the tests, and TypeScript rejects one
|
|
83
|
+
// outside the tsconfig's folder when the tsconfig sets an `outDir`, as
|
|
84
|
+
// `ng new`'s tsconfig.spec.json does: a package in the workspace's
|
|
85
|
+
// node_modules is outside a project in `projects/`. Polyfills are bundled
|
|
86
|
+
// as modules, and run first.
|
|
87
|
+
const lynxPolyfills = [
|
|
88
|
+
'@blotch/angular-lynx-build/unit-test/lynx-globals',
|
|
89
|
+
...(deps.hasTestingLibrary(projectRoot)
|
|
90
|
+
? ['@blotch/angular-lynx-testing-library/setup']
|
|
91
|
+
: []),
|
|
92
|
+
];
|
|
93
|
+
yield* angularBuild.executeUnitTestBuilder(withoutEmptyLists(options), (0, angular_build_1.asAngularBuildTargets)(context, lynxPolyfills));
|
|
94
|
+
};
|
|
95
|
+
exports.runUnitTest = runUnitTest;
|
|
96
|
+
exports.default = (0, architect_1.createBuilder)((options, context) => (0, exports.runUnitTest)(options, context));
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// The first module `ng test` loads, as a polyfill: before Angular's TestBed,
|
|
2
|
+
// the testing library's setup, and any test that imports @blotch/angular-lynx.
|
|
3
|
+
//
|
|
4
|
+
// The runtime reads these compile-time flags, which the rsbuild plugin
|
|
5
|
+
// defines for each thread when it bundles the app. Angular's unit-test build
|
|
6
|
+
// leaves packages unbundled, so a `define` couldn't reach the runtime's code;
|
|
7
|
+
// globals do. Tests run the way the native main thread does: in development,
|
|
8
|
+
// not on the web, without profiling or SSR.
|
|
9
|
+
//
|
|
10
|
+
// Plain JavaScript, so it isn't compiled to CommonJS with the builders:
|
|
11
|
+
// Angular bundles polyfills as ES modules.
|
|
12
|
+
Object.assign(globalThis, {
|
|
13
|
+
__DEV__: true,
|
|
14
|
+
__MAIN_THREAD__: true,
|
|
15
|
+
__WEB__: false,
|
|
16
|
+
__PROFILE__: false,
|
|
17
|
+
__ENABLE_SSR__: false,
|
|
18
|
+
});
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema",
|
|
3
|
+
"$id": "AngularLynxUnitTestBuilder",
|
|
4
|
+
"title": "AngularLynx unit-test builder",
|
|
5
|
+
"description": "Runs the unit tests with Angular's unit-test builder (@angular/build:unit-test), set up for AngularLynx. The options are Angular's: this file copies its schema.json, and a test keeps the two in step.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"buildTarget": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"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`.",
|
|
11
|
+
"pattern": "^[^:\\s]*:[^:\\s]*(:[^\\s]+)?$"
|
|
12
|
+
},
|
|
13
|
+
"tsConfig": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"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."
|
|
16
|
+
},
|
|
17
|
+
"runner": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Specifies the test runner to use for test execution.",
|
|
20
|
+
"default": "vitest",
|
|
21
|
+
"enum": ["karma", "vitest"]
|
|
22
|
+
},
|
|
23
|
+
"runnerConfig": {
|
|
24
|
+
"type": ["string", "boolean"],
|
|
25
|
+
"description": "Specifies the configuration file for the selected test runner. If a string is provided, it will be used as the path to the configuration file. If `true`, the builder will search for a default configuration file (e.g., `vitest-base.config.mts` or `karma.conf.js`). If `false`, no external configuration file will be used.\\nFor Vitest, this enables advanced options and the use of custom plugins. Please note that while the file is loaded, the Angular team does not provide direct support for its specific contents or any third-party plugins used within it.",
|
|
26
|
+
"default": false
|
|
27
|
+
},
|
|
28
|
+
"browsers": {
|
|
29
|
+
"description": "Specifies the browsers to use for test execution. When not specified, tests are run in a Node.js environment using jsdom. For both Vitest and Karma, browser names ending with 'Headless' (e.g., 'ChromeHeadless') will enable headless mode.",
|
|
30
|
+
"type": "array",
|
|
31
|
+
"items": {
|
|
32
|
+
"type": "string"
|
|
33
|
+
},
|
|
34
|
+
"minItems": 1
|
|
35
|
+
},
|
|
36
|
+
"browserViewport": {
|
|
37
|
+
"description": "Specifies the browser viewport dimensions for browser-based tests in the format `widthxheight`.",
|
|
38
|
+
"type": "string",
|
|
39
|
+
"pattern": "^\\d+x\\d+$"
|
|
40
|
+
},
|
|
41
|
+
"include": {
|
|
42
|
+
"type": "array",
|
|
43
|
+
"items": {
|
|
44
|
+
"type": "string"
|
|
45
|
+
},
|
|
46
|
+
"default": ["**/*.spec.ts", "**/*.test.ts"],
|
|
47
|
+
"description": "Specifies glob patterns of files to include for testing, relative to the project source root. This option also has special handling for directory paths (includes all test files within) and file paths (includes the corresponding test file if one exists)."
|
|
48
|
+
},
|
|
49
|
+
"exclude": {
|
|
50
|
+
"type": "array",
|
|
51
|
+
"items": {
|
|
52
|
+
"type": "string"
|
|
53
|
+
},
|
|
54
|
+
"description": "Specifies glob patterns of files to exclude from testing, relative to the project source root."
|
|
55
|
+
},
|
|
56
|
+
"filter": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"description": "Specifies a regular expression pattern to match against test suite and test names. Only tests with a name matching the pattern will be executed. For example, `^App` will run only tests in suites beginning with 'App'."
|
|
59
|
+
},
|
|
60
|
+
"watch": {
|
|
61
|
+
"type": "boolean",
|
|
62
|
+
"description": "Enables watch mode, which re-runs tests when source files change. Defaults to `true` in TTY environments and `false` otherwise."
|
|
63
|
+
},
|
|
64
|
+
"headless": {
|
|
65
|
+
"type": "boolean",
|
|
66
|
+
"description": "Forces all configured browsers to run in headless mode. When using the Vitest runner, this option is ignored if no browsers are configured. The Karma runner does not support this option."
|
|
67
|
+
},
|
|
68
|
+
"debug": {
|
|
69
|
+
"type": "boolean",
|
|
70
|
+
"description": "Enables debugging mode for tests, allowing the use of the Node Inspector.",
|
|
71
|
+
"default": false
|
|
72
|
+
},
|
|
73
|
+
"ui": {
|
|
74
|
+
"type": "boolean",
|
|
75
|
+
"description": "Enables the Vitest UI for interactive test execution. This option is only available for the Vitest runner."
|
|
76
|
+
},
|
|
77
|
+
"isolate": {
|
|
78
|
+
"type": "boolean",
|
|
79
|
+
"description": "Enables isolation for test execution. When true, Vitest runs tests in separate threads or processes. This option is only available for the Vitest runner. Defaults to false to align with the Karma/Jasmine experience."
|
|
80
|
+
},
|
|
81
|
+
"splitting": {
|
|
82
|
+
"type": "boolean",
|
|
83
|
+
"description": "Enables code splitting for test execution. When enabled, shared code between test files is split into separate chunks. Issues with live ESM bindings in Node.js environments (such as uninitialized exports or mocking failures) can be resolved by disabling splitting. This option is only available for the Vitest runner.",
|
|
84
|
+
"default": true,
|
|
85
|
+
"x-deprecated": "No longer needed with Vitest 5."
|
|
86
|
+
},
|
|
87
|
+
"quiet": {
|
|
88
|
+
"type": "boolean",
|
|
89
|
+
"description": "Suppresses the verbose build summary and stats table on each rebuild. Defaults to `true` locally and `false` in CI environments."
|
|
90
|
+
},
|
|
91
|
+
"coverage": {
|
|
92
|
+
"type": "boolean",
|
|
93
|
+
"description": "Enables coverage reporting for tests. If not specified, the coverage configuration from a runner configuration file will be used if present. Otherwise, coverage is disabled by default."
|
|
94
|
+
},
|
|
95
|
+
"coverageInclude": {
|
|
96
|
+
"type": "array",
|
|
97
|
+
"description": "Specifies glob patterns of files to include in the coverage report.",
|
|
98
|
+
"items": {
|
|
99
|
+
"type": "string"
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"coverageExclude": {
|
|
103
|
+
"type": "array",
|
|
104
|
+
"description": "Specifies glob patterns of files to exclude from the coverage report.",
|
|
105
|
+
"items": {
|
|
106
|
+
"type": "string"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"coverageReporters": {
|
|
110
|
+
"type": "array",
|
|
111
|
+
"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'.",
|
|
112
|
+
"items": {
|
|
113
|
+
"oneOf": [
|
|
114
|
+
{
|
|
115
|
+
"enum": [
|
|
116
|
+
"html",
|
|
117
|
+
"lcov",
|
|
118
|
+
"lcovonly",
|
|
119
|
+
"text",
|
|
120
|
+
"text-summary",
|
|
121
|
+
"cobertura",
|
|
122
|
+
"json",
|
|
123
|
+
"json-summary"
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"type": "array",
|
|
128
|
+
"minItems": 1,
|
|
129
|
+
"maxItems": 2,
|
|
130
|
+
"items": [
|
|
131
|
+
{
|
|
132
|
+
"enum": [
|
|
133
|
+
"html",
|
|
134
|
+
"lcov",
|
|
135
|
+
"lcovonly",
|
|
136
|
+
"text",
|
|
137
|
+
"text-summary",
|
|
138
|
+
"cobertura",
|
|
139
|
+
"json",
|
|
140
|
+
"json-summary"
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"type": "object"
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"coverageThresholds": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"description": "Specifies minimum coverage thresholds that must be met. If thresholds are not met, the builder will exit with an error.",
|
|
154
|
+
"properties": {
|
|
155
|
+
"perFile": {
|
|
156
|
+
"type": "boolean",
|
|
157
|
+
"description": "When true, thresholds are enforced for each file individually."
|
|
158
|
+
},
|
|
159
|
+
"statements": {
|
|
160
|
+
"type": "number",
|
|
161
|
+
"description": "Minimum percentage of statements covered."
|
|
162
|
+
},
|
|
163
|
+
"branches": {
|
|
164
|
+
"type": "number",
|
|
165
|
+
"description": "Minimum percentage of branches covered."
|
|
166
|
+
},
|
|
167
|
+
"functions": {
|
|
168
|
+
"type": "number",
|
|
169
|
+
"description": "Minimum percentage of functions covered."
|
|
170
|
+
},
|
|
171
|
+
"lines": {
|
|
172
|
+
"type": "number",
|
|
173
|
+
"description": "Minimum percentage of lines covered."
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
"additionalProperties": false
|
|
177
|
+
},
|
|
178
|
+
"coverageWatermarks": {
|
|
179
|
+
"type": "object",
|
|
180
|
+
"description": "Specifies coverage watermarks for the HTML reporter. These determine the color coding for high, medium, and low coverage.",
|
|
181
|
+
"properties": {
|
|
182
|
+
"statements": {
|
|
183
|
+
"type": "array",
|
|
184
|
+
"description": "The high and low watermarks for statements coverage. `[low, high]`",
|
|
185
|
+
"items": {
|
|
186
|
+
"type": "number"
|
|
187
|
+
},
|
|
188
|
+
"minItems": 2,
|
|
189
|
+
"maxItems": 2
|
|
190
|
+
},
|
|
191
|
+
"branches": {
|
|
192
|
+
"type": "array",
|
|
193
|
+
"description": "The high and low watermarks for branches coverage. `[low, high]`",
|
|
194
|
+
"items": {
|
|
195
|
+
"type": "number"
|
|
196
|
+
},
|
|
197
|
+
"minItems": 2,
|
|
198
|
+
"maxItems": 2
|
|
199
|
+
},
|
|
200
|
+
"functions": {
|
|
201
|
+
"type": "array",
|
|
202
|
+
"description": "The high and low watermarks for functions coverage. `[low, high]`",
|
|
203
|
+
"items": {
|
|
204
|
+
"type": "number"
|
|
205
|
+
},
|
|
206
|
+
"minItems": 2,
|
|
207
|
+
"maxItems": 2
|
|
208
|
+
},
|
|
209
|
+
"lines": {
|
|
210
|
+
"type": "array",
|
|
211
|
+
"description": "The high and low watermarks for lines coverage. `[low, high]`",
|
|
212
|
+
"items": {
|
|
213
|
+
"type": "number"
|
|
214
|
+
},
|
|
215
|
+
"minItems": 2,
|
|
216
|
+
"maxItems": 2
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
"additionalProperties": false
|
|
220
|
+
},
|
|
221
|
+
"reporters": {
|
|
222
|
+
"type": "array",
|
|
223
|
+
"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.",
|
|
224
|
+
"items": {
|
|
225
|
+
"oneOf": [
|
|
226
|
+
{
|
|
227
|
+
"anyOf": [
|
|
228
|
+
{
|
|
229
|
+
"type": "string"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"enum": [
|
|
233
|
+
"default",
|
|
234
|
+
"verbose",
|
|
235
|
+
"dots",
|
|
236
|
+
"json",
|
|
237
|
+
"junit",
|
|
238
|
+
"tap",
|
|
239
|
+
"tap-flat",
|
|
240
|
+
"html"
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
]
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"type": "array",
|
|
247
|
+
"minItems": 1,
|
|
248
|
+
"maxItems": 2,
|
|
249
|
+
"items": [
|
|
250
|
+
{
|
|
251
|
+
"anyOf": [
|
|
252
|
+
{
|
|
253
|
+
"type": "string"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"enum": [
|
|
257
|
+
"default",
|
|
258
|
+
"verbose",
|
|
259
|
+
"dots",
|
|
260
|
+
"json",
|
|
261
|
+
"junit",
|
|
262
|
+
"tap",
|
|
263
|
+
"tap-flat",
|
|
264
|
+
"html"
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
]
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
"type": "object"
|
|
271
|
+
}
|
|
272
|
+
]
|
|
273
|
+
}
|
|
274
|
+
]
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
"outputFile": {
|
|
278
|
+
"type": "string",
|
|
279
|
+
"description": "Specifies a file path for the test report, applying only to the first reporter. To configure output files for multiple reporters, use the tuple format `['reporter-name', { outputFile: '...' }]` within the `reporters` option. When not provided, output is written to the console."
|
|
280
|
+
},
|
|
281
|
+
"providersFile": {
|
|
282
|
+
"type": "string",
|
|
283
|
+
"description": "Specifies the path to a TypeScript file that provides an array of Angular providers for the test environment. The file must contain a default export of the provider array.",
|
|
284
|
+
"minLength": 1
|
|
285
|
+
},
|
|
286
|
+
"setupFiles": {
|
|
287
|
+
"type": "array",
|
|
288
|
+
"items": {
|
|
289
|
+
"type": "string"
|
|
290
|
+
},
|
|
291
|
+
"description": "A list of paths to global setup files that are executed before the test files. The application's polyfills and the Angular TestBed are always initialized before these files."
|
|
292
|
+
},
|
|
293
|
+
"progress": {
|
|
294
|
+
"type": "boolean",
|
|
295
|
+
"description": "Shows build progress information in the console. Defaults to the `progress` setting of the specified `buildTarget`."
|
|
296
|
+
},
|
|
297
|
+
"listTests": {
|
|
298
|
+
"type": "boolean",
|
|
299
|
+
"description": "Lists all discovered test files and exits the process without building or executing the tests.",
|
|
300
|
+
"default": false
|
|
301
|
+
},
|
|
302
|
+
"dumpVirtualFiles": {
|
|
303
|
+
"type": "boolean",
|
|
304
|
+
"description": "Dumps build output files to the `.angular/cache` directory for debugging purposes.",
|
|
305
|
+
"default": false,
|
|
306
|
+
"visible": false
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
"additionalProperties": false,
|
|
310
|
+
"required": []
|
|
311
|
+
}
|
package/client.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Types for what the bundler handles in app code: asset and CSS module
|
|
2
|
+
// imports, `import.meta.env`, `import.meta.webpackHot`. Apps reference them
|
|
3
|
+
// from here (`/// <reference types="@blotch/angular-lynx-build/client" />`)
|
|
4
|
+
// rather than from rspeedy, which is this package's dependency, not theirs:
|
|
5
|
+
// under strict package managers (pnpm, Yarn PnP) the app couldn't resolve it.
|
|
6
|
+
/// <reference types="@lynx-js/rspeedy/client" />
|
|
7
|
+
|
|
8
|
+
export {};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rsbuild plugin `ng build` and `ng serve` apply, for a lynx.config.ts
|
|
3
|
+
* that passes it options or runs under plain rspeedy. A config that lists it
|
|
4
|
+
* keeps that instance; otherwise the builders add `pluginAngularLynx()`
|
|
5
|
+
* themselves. Re-exported so the import works with strict package managers
|
|
6
|
+
* (pnpm, Yarn PnP), where the plugin is a dependency of this package rather
|
|
7
|
+
* than of the app.
|
|
8
|
+
*/
|
|
9
|
+
export * from '@blotch/rsbuild-plugin-angular-lynx';
|
|
10
|
+
/**
|
|
11
|
+
* rspeedy's config helper, for the same reason: rspeedy is this package's
|
|
12
|
+
* dependency, so an app's lynx.config.ts imports it from here.
|
|
13
|
+
*/
|
|
14
|
+
export { defineConfig } from '@lynx-js/rspeedy';
|
|
15
|
+
export type { Config } from '@lynx-js/rspeedy';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rsbuild plugin `ng build` and `ng serve` apply, for a lynx.config.ts
|
|
3
|
+
* that passes it options or runs under plain rspeedy. A config that lists it
|
|
4
|
+
* keeps that instance; otherwise the builders add `pluginAngularLynx()`
|
|
5
|
+
* themselves. Re-exported so the import works with strict package managers
|
|
6
|
+
* (pnpm, Yarn PnP), where the plugin is a dependency of this package rather
|
|
7
|
+
* than of the app.
|
|
8
|
+
*/
|
|
9
|
+
export * from '@blotch/rsbuild-plugin-angular-lynx';
|
|
10
|
+
/**
|
|
11
|
+
* rspeedy's config helper, for the same reason: rspeedy is this package's
|
|
12
|
+
* dependency, so an app's lynx.config.ts imports it from here.
|
|
13
|
+
*/
|
|
14
|
+
export { defineConfig } from '@lynx-js/rspeedy';
|