@blotch/angular-lynx-build 22.2.2 → 22.2.4
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 +20 -10
- package/builders/angular-build.js +117 -0
- package/builders/builders.json +5 -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/unit-test/index.js +10 -121
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @blotch/angular-lynx-build
|
|
2
2
|
|
|
3
|
-
The Angular CLI builders for [AngularLynx](https://github.com/Blotch-Smart-Frames/AngularLynx): `ng build`, `ng serve` and `ng
|
|
3
|
+
The Angular CLI builders for [AngularLynx](https://github.com/Blotch-Smart-Frames/AngularLynx): `ng build`, `ng serve`, `ng test` and `ng extract-i18n` for Lynx, and `ng build --platform ios|android|all` for native apps.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
ng add @blotch/angular-lynx # installs this package and sets up angular.json
|
|
@@ -31,16 +31,20 @@ It is the only build dependency an AngularLynx app needs, as `@angular/build` is
|
|
|
31
31
|
},
|
|
32
32
|
"test": {
|
|
33
33
|
"builder": "@blotch/angular-lynx-build:unit-test"
|
|
34
|
+
},
|
|
35
|
+
"extract-i18n": {
|
|
36
|
+
"builder": "@blotch/angular-lynx-build:extract-i18n"
|
|
34
37
|
}
|
|
35
38
|
```
|
|
36
39
|
|
|
37
|
-
| Builder
|
|
38
|
-
|
|
|
39
|
-
| `application`
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
| `dev-server`
|
|
43
|
-
| `unit-test`
|
|
40
|
+
| Builder | Command | What it does |
|
|
41
|
+
| -------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
42
|
+
| `application` | `ng build` | Builds the Lynx bundle (and the web preview bundle) into `dist/` with [rspeedy](https://lynxjs.org/rspeedy/) |
|
|
43
|
+
| | `ng build --watch` | Rebuilds the bundle whenever a file changes |
|
|
44
|
+
| | `ng build --platform ios` | Then builds the iOS app (`--platform android` or `all` for the others) into `dist/<platform>/` |
|
|
45
|
+
| `dev-server` | `ng serve` | Runs rspeedy's dev server for Lynx Explorer and the web preview, and prints the QR code Lynx Explorer scans |
|
|
46
|
+
| `unit-test` | `ng test` | Runs the unit tests with Angular's own unit-test builder (Vitest), set up for Lynx |
|
|
47
|
+
| `extract-i18n` | `ng extract-i18n` | Extracts the i18n messages with Angular's own extract-i18n builder, set up for Lynx |
|
|
44
48
|
|
|
45
49
|
They behave like Angular's own builders:
|
|
46
50
|
|
|
@@ -50,7 +54,7 @@ They behave like Angular's own builders:
|
|
|
50
54
|
- **Budgets are enforced.** The `budgets` in the build target are checked against the Lynx bundle and the component stylesheets, with Angular's messages; `ng add` sizes the `initial` budget for a Lynx bundle. See the plugin's [README](../rsbuild-plugin-angular-lynx/README.md#budgets).
|
|
51
55
|
- **`--watch` rebuilds only the bundle.** It can't be combined with `--platform`: use `ng serve` while developing, and `ng build --platform` for the app.
|
|
52
56
|
|
|
53
|
-
The options are in [`builders/application/schema.json`](builders/application/schema.json), [`builders/dev-server/schema.json`](builders/dev-server/schema.json)
|
|
57
|
+
The options are in [`builders/application/schema.json`](builders/application/schema.json), [`builders/dev-server/schema.json`](builders/dev-server/schema.json), [`builders/unit-test/schema.json`](builders/unit-test/schema.json) and [`builders/extract-i18n/schema.json`](builders/extract-i18n/schema.json).
|
|
54
58
|
|
|
55
59
|
## ng test
|
|
56
60
|
|
|
@@ -66,6 +70,12 @@ Two things work as in any Angular app, and differ from a plain Vitest setup:
|
|
|
66
70
|
- **Templates are checked strictly.** A component that uses Lynx elements imports `LYNX_ELEMENTS`, as the Angular Language Service already requires (generated components do). The app build is laxer: it adds `CUSTOM_ELEMENTS_SCHEMA` to every component, which Angular's test build has no hook for.
|
|
67
71
|
- **Test code is type-checked**, and test files share one module graph (Angular's runner isn't isolated by default). `vi.mock` of a relative import isn't supported, and mocking `@angular/core` would leak into other test files.
|
|
68
72
|
|
|
73
|
+
## ng extract-i18n
|
|
74
|
+
|
|
75
|
+
The `extract-i18n` builder is Angular's `@angular/build:extract-i18n`, set up for Lynx. Its options are Angular's (`format`, `outputPath`, `outFile`, ...), and, as for `ng test`, its schema is a copy of Angular's that a test keeps in step. Angular CLI picks an extractor by itself only for a project built with one of Angular's builders, so an AngularLynx app needs the target: `ng add` writes it, and `add-i18n` makes it write JSON to `src/locale`, which `loadTranslations()` takes.
|
|
76
|
+
|
|
77
|
+
Angular's extractor compiles the app with Angular's application builder. As in `ng test`, it gets the build target as an Angular one, and imported images, fonts and media load as file URLs: without a loader for them, Angular's build stops at the first imported image. Without `@angular/localize`, it says to run `add-i18n` rather than Angular's `ng add @angular/localize`, which only sets up Angular's own builders.
|
|
78
|
+
|
|
69
79
|
## lynx.config.ts
|
|
70
80
|
|
|
71
81
|
An app doesn't need one. Without it, `ng build` and `ng serve` take what rspeedy needs from angular.json and the defaults an AngularLynx app wants:
|
|
@@ -98,4 +108,4 @@ This package is the Angular CLI layer. The work happens in its dependencies:
|
|
|
98
108
|
- **[`@blotch/angular-lynx-native`](../native)** turns the Lynx bundle into iOS and Android apps.
|
|
99
109
|
- **[rspeedy](https://lynxjs.org/rspeedy/)** and its QR code plugin. The builders always run the versions they were released and tested with, so an app doesn't install them.
|
|
100
110
|
|
|
101
|
-
`ng test`
|
|
111
|
+
`ng test` and `ng extract-i18n` run Angular's builders from the project's own `@angular/build`, which `ng new` installs: it must match the project's Angular version.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.asAngularBuildTargets = exports.ASSET_LOADERS = exports.ANGULAR_BUILD_OPTIONS = exports.importAngularBuild = void 0;
|
|
4
|
+
const project_import_1 = require("./project-import");
|
|
5
|
+
/**
|
|
6
|
+
* @angular/build comes from the project, like Angular's own builders: its
|
|
7
|
+
* version must match the project's Angular version, which `ng new` installs
|
|
8
|
+
* it for.
|
|
9
|
+
*/
|
|
10
|
+
const importAngularBuild = (projectRoot) => (0, project_import_1.importFromProject)('@angular/build', projectRoot, 'Run `npm install --save-dev @angular/build` (`ng new` adds it).');
|
|
11
|
+
exports.importAngularBuild = importAngularBuild;
|
|
12
|
+
const LYNX_APPLICATION_BUILDER = '@blotch/angular-lynx-build:application';
|
|
13
|
+
const ANGULAR_APPLICATION_BUILDER = '@angular/build:application';
|
|
14
|
+
/**
|
|
15
|
+
* The options of the Lynx application builder that are Angular's application
|
|
16
|
+
* builder's too, and mean the same. The rest (native app settings, rspeedy's
|
|
17
|
+
* `config` and `environment`) are Lynx-only; Angular's schema rejects them.
|
|
18
|
+
*/
|
|
19
|
+
exports.ANGULAR_BUILD_OPTIONS = [
|
|
20
|
+
'browser',
|
|
21
|
+
'tsConfig',
|
|
22
|
+
'polyfills',
|
|
23
|
+
'styles',
|
|
24
|
+
'assets',
|
|
25
|
+
'scripts',
|
|
26
|
+
'inlineStyleLanguage',
|
|
27
|
+
'fileReplacements',
|
|
28
|
+
'aot',
|
|
29
|
+
'optimization',
|
|
30
|
+
'sourceMap',
|
|
31
|
+
'outputHashing',
|
|
32
|
+
'i18nMissingTranslation',
|
|
33
|
+
'budgets',
|
|
34
|
+
'extractLicenses',
|
|
35
|
+
'outputPath',
|
|
36
|
+
'index',
|
|
37
|
+
'watch',
|
|
38
|
+
];
|
|
39
|
+
/**
|
|
40
|
+
* How Angular's build loads imported assets (`import logo from
|
|
41
|
+
* './logo.png'`): as files, so the import is the file's URL, as rspeedy
|
|
42
|
+
* makes it in the app. Angular's build has no loader for them by default and
|
|
43
|
+
* fails on the import.
|
|
44
|
+
*/
|
|
45
|
+
exports.ASSET_LOADERS = Object.fromEntries([
|
|
46
|
+
// Images
|
|
47
|
+
'png',
|
|
48
|
+
'jpg',
|
|
49
|
+
'jpeg',
|
|
50
|
+
'gif',
|
|
51
|
+
'webp',
|
|
52
|
+
'avif',
|
|
53
|
+
'bmp',
|
|
54
|
+
'ico',
|
|
55
|
+
'svg',
|
|
56
|
+
// Fonts
|
|
57
|
+
'woff',
|
|
58
|
+
'woff2',
|
|
59
|
+
'ttf',
|
|
60
|
+
'otf',
|
|
61
|
+
'eot',
|
|
62
|
+
// Audio and video
|
|
63
|
+
'mp4',
|
|
64
|
+
'webm',
|
|
65
|
+
'mov',
|
|
66
|
+
'mp3',
|
|
67
|
+
'wav',
|
|
68
|
+
'ogg',
|
|
69
|
+
'm4a',
|
|
70
|
+
'aac',
|
|
71
|
+
].map((extension) => [`.${extension}`, 'file']));
|
|
72
|
+
/**
|
|
73
|
+
* The builder context Angular's unit-test and extract-i18n builders get.
|
|
74
|
+
* Both compile the app with Angular's application builder, taking its
|
|
75
|
+
* options (tsconfig, polyfills, styles, file replacements) from the build
|
|
76
|
+
* target, and only know Angular's own application builder: for any other the
|
|
77
|
+
* unit-test builder warns that "unexpected behavior or build failures may
|
|
78
|
+
* occur", and both validate the options against that builder's schema. A
|
|
79
|
+
* Lynx build target therefore reaches them as an Angular one, with the
|
|
80
|
+
* options both builders share, which Angular's schema validates and
|
|
81
|
+
* completes with its defaults, the asset loaders rspeedy's defaults
|
|
82
|
+
* correspond to, and `lynxPolyfills` after the app's own polyfills.
|
|
83
|
+
*/
|
|
84
|
+
const asAngularBuildTargets = (context, lynxPolyfills = []) => {
|
|
85
|
+
const isLynxApplication = async (target) => (await context.getBuilderNameForTarget(target)) ===
|
|
86
|
+
LYNX_APPLICATION_BUILDER;
|
|
87
|
+
const overrides = {
|
|
88
|
+
getBuilderNameForTarget: async (target) => (await isLynxApplication(target))
|
|
89
|
+
? ANGULAR_APPLICATION_BUILDER
|
|
90
|
+
: context.getBuilderNameForTarget(target),
|
|
91
|
+
getTargetOptions: async (target) => {
|
|
92
|
+
const options = await context.getTargetOptions(target);
|
|
93
|
+
if (!(await isLynxApplication(target))) {
|
|
94
|
+
return options;
|
|
95
|
+
}
|
|
96
|
+
const polyfills = options['polyfills'];
|
|
97
|
+
return {
|
|
98
|
+
...Object.fromEntries(Object.entries(options).filter(([key]) => exports.ANGULAR_BUILD_OPTIONS.includes(key))),
|
|
99
|
+
loader: exports.ASSET_LOADERS,
|
|
100
|
+
polyfills: [
|
|
101
|
+
...(Array.isArray(polyfills)
|
|
102
|
+
? polyfills
|
|
103
|
+
: typeof polyfills === 'string'
|
|
104
|
+
? [polyfills]
|
|
105
|
+
: []),
|
|
106
|
+
...lynxPolyfills,
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
return new Proxy(context, {
|
|
112
|
+
get: (target, property) => property in overrides
|
|
113
|
+
? overrides[property]
|
|
114
|
+
: Reflect.get(target, property),
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
exports.asAngularBuildTargets = asAngularBuildTargets;
|
package/builders/builders.json
CHANGED
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
"implementation": "./unit-test/index",
|
|
15
15
|
"schema": "./unit-test/schema.json",
|
|
16
16
|
"description": "Runs the unit tests with Angular's unit-test builder, set up for AngularLynx"
|
|
17
|
+
},
|
|
18
|
+
"extract-i18n": {
|
|
19
|
+
"implementation": "./extract-i18n/index",
|
|
20
|
+
"schema": "./extract-i18n/schema.json",
|
|
21
|
+
"description": "Extracts the i18n messages with Angular's extract-i18n builder, set up for AngularLynx"
|
|
17
22
|
}
|
|
18
23
|
}
|
|
19
24
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
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.runExtractI18n = exports.hasLocalize = 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
|
+
/** Whether the project has @angular/localize, which the extractor runs. */
|
|
12
|
+
const hasLocalize = (projectRoot) => {
|
|
13
|
+
try {
|
|
14
|
+
(0, node_module_1.createRequire)(node_path_1.default.join(projectRoot, 'package.json')).resolve('@angular/localize/package.json');
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.hasLocalize = hasLocalize;
|
|
22
|
+
const defaultDeps = {
|
|
23
|
+
importAngularBuild: (projectRoot) => (0, angular_build_1.importAngularBuild)(projectRoot),
|
|
24
|
+
hasLocalize: exports.hasLocalize,
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Angular's own message for a project without @angular/localize suggests
|
|
28
|
+
* `ng add @angular/localize`, which only sets up Angular's builders: on a
|
|
29
|
+
* Lynx app, `$localize` would then be missing at runtime.
|
|
30
|
+
*/
|
|
31
|
+
const NO_LOCALIZE = 'i18n extraction requires the @angular/localize package. Run `ng generate @blotch/angular-lynx:add-i18n` to install it and set up i18n.';
|
|
32
|
+
/**
|
|
33
|
+
* `ng extract-i18n`: Angular's extract-i18n builder
|
|
34
|
+
* (`@angular/build:extract-i18n`), so the options, formats and messages file
|
|
35
|
+
* are the ones Angular developers know. Angular CLI picks that builder on its
|
|
36
|
+
* own only for a project built with one of Angular's builders, so without a
|
|
37
|
+
* target that names this one, `ng extract-i18n` fails with "Cannot determine
|
|
38
|
+
* project or target for command."
|
|
39
|
+
*
|
|
40
|
+
* Angular's extractor compiles the app with Angular's application builder
|
|
41
|
+
* from the build target's options. The Lynx build target reaches it as an
|
|
42
|
+
* Angular one, as in `ng test`: Angular's builder neither rejects the
|
|
43
|
+
* Lynx-only options nor fails on an imported image, which it has no loader
|
|
44
|
+
* for by default. No Lynx polyfills load, since the extractor only reads the
|
|
45
|
+
* compiled code and never runs it.
|
|
46
|
+
*/
|
|
47
|
+
const runExtractI18n = async (options, context, deps = defaultDeps) => {
|
|
48
|
+
const projectName = context.target?.project;
|
|
49
|
+
if (!projectName) {
|
|
50
|
+
return { success: false, error: 'The builder needs a project target.' };
|
|
51
|
+
}
|
|
52
|
+
const metadata = await context.getProjectMetadata(projectName);
|
|
53
|
+
const projectRoot = node_path_1.default.join(context.workspaceRoot, metadata['root'] ?? '');
|
|
54
|
+
if (!deps.hasLocalize(projectRoot)) {
|
|
55
|
+
return { success: false, error: NO_LOCALIZE };
|
|
56
|
+
}
|
|
57
|
+
let angularBuild;
|
|
58
|
+
try {
|
|
59
|
+
angularBuild = await deps.importAngularBuild(projectRoot);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
error: error instanceof Error ? error.message : String(error),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return angularBuild.executeExtractI18nBuilder(options, (0, angular_build_1.asAngularBuildTargets)(context));
|
|
68
|
+
};
|
|
69
|
+
exports.runExtractI18n = runExtractI18n;
|
|
70
|
+
exports.default = (0, architect_1.createBuilder)((options, context) => (0, exports.runExtractI18n)(options, context));
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema",
|
|
3
|
+
"$id": "AngularLynxExtractI18nBuilder",
|
|
4
|
+
"title": "AngularLynx extract-i18n builder",
|
|
5
|
+
"description": "Extracts the i18n messages with Angular's extract-i18n builder (@angular/build:extract-i18n), 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": "A builder target to extract i18n messages in the format of `project:target[:configuration]`. You can also pass in more than one configuration name as a comma-separated list. Example: `project:target:production,staging`.",
|
|
11
|
+
"pattern": "^[^:\\s]*:[^:\\s]*(:[^\\s]+)?$"
|
|
12
|
+
},
|
|
13
|
+
"format": {
|
|
14
|
+
"type": "string",
|
|
15
|
+
"description": "Output format for the generated file.",
|
|
16
|
+
"default": "xlf",
|
|
17
|
+
"enum": [
|
|
18
|
+
"xmb",
|
|
19
|
+
"xlf",
|
|
20
|
+
"xlif",
|
|
21
|
+
"xliff",
|
|
22
|
+
"xlf2",
|
|
23
|
+
"xliff2",
|
|
24
|
+
"json",
|
|
25
|
+
"arb",
|
|
26
|
+
"legacy-migrate"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"progress": {
|
|
30
|
+
"type": "boolean",
|
|
31
|
+
"description": "Log progress to the console.",
|
|
32
|
+
"default": true
|
|
33
|
+
},
|
|
34
|
+
"outputPath": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"description": "Path where output will be placed."
|
|
37
|
+
},
|
|
38
|
+
"outFile": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"description": "Name of the file to output."
|
|
41
|
+
},
|
|
42
|
+
"i18nDuplicateTranslation": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"description": "How to handle duplicate translations.",
|
|
45
|
+
"enum": ["error", "warning", "ignore"]
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"additionalProperties": false
|
|
49
|
+
}
|
|
@@ -3,17 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.runUnitTest = exports.
|
|
6
|
+
exports.runUnitTest = exports.hasTestingLibrary = void 0;
|
|
7
7
|
const architect_1 = require("@angular-devkit/architect");
|
|
8
8
|
const node_module_1 = require("node:module");
|
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
-
const
|
|
11
|
-
/**
|
|
12
|
-
* @angular/build comes from the project, like Angular's own builders: its
|
|
13
|
-
* version must match the project's Angular version, which `ng new` installs
|
|
14
|
-
* it for.
|
|
15
|
-
*/
|
|
16
|
-
const importAngularBuild = (projectRoot) => (0, project_import_1.importFromProject)('@angular/build', projectRoot, 'Run `npm install --save-dev @angular/build` (`ng new` adds it).');
|
|
10
|
+
const angular_build_1 = require("../angular-build");
|
|
17
11
|
/**
|
|
18
12
|
* Whether the project has @blotch/angular-lynx-testing-library. Its package.json
|
|
19
13
|
* isn't in its `exports` in every version, and Node then refuses to resolve
|
|
@@ -30,120 +24,9 @@ const hasTestingLibrary = (projectRoot) => {
|
|
|
30
24
|
};
|
|
31
25
|
exports.hasTestingLibrary = hasTestingLibrary;
|
|
32
26
|
const defaultDeps = {
|
|
33
|
-
importAngularBuild,
|
|
27
|
+
importAngularBuild: (projectRoot) => (0, angular_build_1.importAngularBuild)(projectRoot),
|
|
34
28
|
hasTestingLibrary: exports.hasTestingLibrary,
|
|
35
29
|
};
|
|
36
|
-
const LYNX_APPLICATION_BUILDER = '@blotch/angular-lynx-build:application';
|
|
37
|
-
const ANGULAR_APPLICATION_BUILDER = '@angular/build:application';
|
|
38
|
-
/**
|
|
39
|
-
* The options of the Lynx application builder that are Angular's application
|
|
40
|
-
* builder's too, and mean the same. The rest (native app settings, rspeedy's
|
|
41
|
-
* `config` and `environment`) are Lynx-only; Angular's schema rejects them.
|
|
42
|
-
*/
|
|
43
|
-
exports.ANGULAR_BUILD_OPTIONS = [
|
|
44
|
-
'browser',
|
|
45
|
-
'tsConfig',
|
|
46
|
-
'polyfills',
|
|
47
|
-
'styles',
|
|
48
|
-
'assets',
|
|
49
|
-
'scripts',
|
|
50
|
-
'inlineStyleLanguage',
|
|
51
|
-
'fileReplacements',
|
|
52
|
-
'aot',
|
|
53
|
-
'optimization',
|
|
54
|
-
'sourceMap',
|
|
55
|
-
'outputHashing',
|
|
56
|
-
'i18nMissingTranslation',
|
|
57
|
-
'budgets',
|
|
58
|
-
'extractLicenses',
|
|
59
|
-
'outputPath',
|
|
60
|
-
'index',
|
|
61
|
-
'watch',
|
|
62
|
-
];
|
|
63
|
-
/**
|
|
64
|
-
* How Angular's test build loads imported assets (`import logo from
|
|
65
|
-
* './logo.png'`): as files, so the import is the file's URL, as rspeedy
|
|
66
|
-
* makes it in the app. Angular's build has no loader for them by default and
|
|
67
|
-
* fails on the import.
|
|
68
|
-
*/
|
|
69
|
-
exports.ASSET_LOADERS = Object.fromEntries([
|
|
70
|
-
// Images
|
|
71
|
-
'png',
|
|
72
|
-
'jpg',
|
|
73
|
-
'jpeg',
|
|
74
|
-
'gif',
|
|
75
|
-
'webp',
|
|
76
|
-
'avif',
|
|
77
|
-
'bmp',
|
|
78
|
-
'ico',
|
|
79
|
-
'svg',
|
|
80
|
-
// Fonts
|
|
81
|
-
'woff',
|
|
82
|
-
'woff2',
|
|
83
|
-
'ttf',
|
|
84
|
-
'otf',
|
|
85
|
-
'eot',
|
|
86
|
-
// Audio and video
|
|
87
|
-
'mp4',
|
|
88
|
-
'webm',
|
|
89
|
-
'mov',
|
|
90
|
-
'mp3',
|
|
91
|
-
'wav',
|
|
92
|
-
'ogg',
|
|
93
|
-
'm4a',
|
|
94
|
-
'aac',
|
|
95
|
-
].map((extension) => [`.${extension}`, 'file']));
|
|
96
|
-
/**
|
|
97
|
-
* The builder context Angular's unit-test builder gets. It reads the
|
|
98
|
-
* compiler options (tsconfig, polyfills, styles, file replacements) from the
|
|
99
|
-
* build target, and only knows Angular's own application builder: for any
|
|
100
|
-
* other it warns that "unexpected behavior or build failures may occur" and
|
|
101
|
-
* validates the options against that builder's schema. A Lynx build target
|
|
102
|
-
* therefore reaches it as an Angular one, with the options both builders
|
|
103
|
-
* share, which Angular's schema validates and completes with its defaults,
|
|
104
|
-
* the asset loaders rspeedy's defaults correspond to, and `lynxPolyfills`
|
|
105
|
-
* after the app's own polyfills.
|
|
106
|
-
*
|
|
107
|
-
* The Lynx setup goes in as polyfills rather than `setupFiles` because
|
|
108
|
-
* Angular compiles setup files with the tests, and TypeScript rejects one
|
|
109
|
-
* outside the tsconfig's folder when the tsconfig sets an `outDir`, as
|
|
110
|
-
* `ng new`'s tsconfig.spec.json does: a package in the workspace's
|
|
111
|
-
* node_modules is outside a project in `projects/`. Polyfills are bundled as
|
|
112
|
-
* modules, and run first.
|
|
113
|
-
*/
|
|
114
|
-
const asAngularBuildTargets = (context, lynxPolyfills) => {
|
|
115
|
-
const isLynxApplication = async (target) => (await context.getBuilderNameForTarget(target)) ===
|
|
116
|
-
LYNX_APPLICATION_BUILDER;
|
|
117
|
-
const overrides = {
|
|
118
|
-
getBuilderNameForTarget: async (target) => (await isLynxApplication(target))
|
|
119
|
-
? ANGULAR_APPLICATION_BUILDER
|
|
120
|
-
: context.getBuilderNameForTarget(target),
|
|
121
|
-
getTargetOptions: async (target) => {
|
|
122
|
-
const options = await context.getTargetOptions(target);
|
|
123
|
-
if (!(await isLynxApplication(target))) {
|
|
124
|
-
return options;
|
|
125
|
-
}
|
|
126
|
-
const polyfills = options['polyfills'];
|
|
127
|
-
return {
|
|
128
|
-
...Object.fromEntries(Object.entries(options).filter(([key]) => exports.ANGULAR_BUILD_OPTIONS.includes(key))),
|
|
129
|
-
loader: exports.ASSET_LOADERS,
|
|
130
|
-
polyfills: [
|
|
131
|
-
...(Array.isArray(polyfills)
|
|
132
|
-
? polyfills
|
|
133
|
-
: typeof polyfills === 'string'
|
|
134
|
-
? [polyfills]
|
|
135
|
-
: []),
|
|
136
|
-
...lynxPolyfills,
|
|
137
|
-
],
|
|
138
|
-
};
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
return new Proxy(context, {
|
|
142
|
-
get: (target, property) => property in overrides
|
|
143
|
-
? overrides[property]
|
|
144
|
-
: Reflect.get(target, property),
|
|
145
|
-
});
|
|
146
|
-
};
|
|
147
30
|
/**
|
|
148
31
|
* The options as Angular CLI hands them to Angular's own builders. For a
|
|
149
32
|
* builder outside `@angular/build`, it sets every array option the user left
|
|
@@ -195,13 +78,19 @@ const runUnitTest = async function* (options, context, deps = defaultDeps) {
|
|
|
195
78
|
};
|
|
196
79
|
return;
|
|
197
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.
|
|
198
87
|
const lynxPolyfills = [
|
|
199
88
|
'@blotch/angular-lynx-build/unit-test/lynx-globals',
|
|
200
89
|
...(deps.hasTestingLibrary(projectRoot)
|
|
201
90
|
? ['@blotch/angular-lynx-testing-library/setup']
|
|
202
91
|
: []),
|
|
203
92
|
];
|
|
204
|
-
yield* angularBuild.executeUnitTestBuilder(withoutEmptyLists(options), asAngularBuildTargets(context, lynxPolyfills));
|
|
93
|
+
yield* angularBuild.executeUnitTestBuilder(withoutEmptyLists(options), (0, angular_build_1.asAngularBuildTargets)(context, lynxPolyfills));
|
|
205
94
|
};
|
|
206
95
|
exports.runUnitTest = runUnitTest;
|
|
207
96
|
exports.default = (0, architect_1.createBuilder)((options, context) => (0, exports.runUnitTest)(options, context));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blotch/angular-lynx-build",
|
|
3
|
-
"version": "22.2.
|
|
3
|
+
"version": "22.2.4",
|
|
4
4
|
"description": "Angular CLI builders for AngularLynx: ng build, ng serve and ng test for Lynx, and native iOS and Android apps",
|
|
5
5
|
"homepage": "https://github.com/Blotch-Smart-Frames/AngularLynx#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"publish:local": "yalc publish --push"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@blotch/angular-lynx-native": "22.2.
|
|
55
|
-
"@blotch/rsbuild-plugin-angular-lynx": "22.2.
|
|
54
|
+
"@blotch/angular-lynx-native": "22.2.4",
|
|
55
|
+
"@blotch/rsbuild-plugin-angular-lynx": "22.2.4",
|
|
56
56
|
"@lynx-js/qrcode-rsbuild-plugin": "^0.7.3",
|
|
57
57
|
"@lynx-js/rspeedy": "^0.18.0"
|
|
58
58
|
},
|