@blotch/angular-lynx 22.2.2 → 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 +1 -1
- package/fesm2022/blotch-angular-lynx-web-glass-8MFrhPz0.mjs +951 -0
- package/fesm2022/blotch-angular-lynx-web-glass-8MFrhPz0.mjs.map +1 -0
- package/fesm2022/blotch-angular-lynx.mjs +2086 -774
- package/fesm2022/blotch-angular-lynx.mjs.map +1 -1
- package/package.json +1 -1
- package/schematics/add-i18n/index.js +24 -7
- package/schematics/add-tailwind/index.js +4 -5
- package/schematics/migrations/accessibility-traits/index.js +56 -0
- package/schematics/migrations/dev-logs-gitignore/index.js +9 -0
- package/schematics/migrations/extract-i18n-target/index.js +31 -0
- package/schematics/migrations/tailwind-html-templates/index.js +44 -0
- package/schematics/migrations.json +22 -1
- package/schematics/ng-add/index.js +19 -11
- package/schematics/utility/dev-logs-gitignore.js +25 -0
- package/schematics/utility/extract-i18n-target.js +58 -0
- package/types/blotch-angular-lynx.d.ts +785 -345
package/package.json
CHANGED
|
@@ -4,22 +4,26 @@ const schematics_1 = require("@angular-devkit/schematics");
|
|
|
4
4
|
const dependency_1 = require("@schematics/angular/utility/dependency");
|
|
5
5
|
const json_file_1 = require("@schematics/angular/utility/json-file");
|
|
6
6
|
const workspace_1 = require("@schematics/angular/utility/workspace");
|
|
7
|
+
const extract_i18n_target_1 = require("../utility/extract-i18n-target");
|
|
7
8
|
/**
|
|
8
9
|
* Wires Angular's `@angular/localize` package into an AngularLynx app and
|
|
9
10
|
* provides the Lynx-aware `provideLocale()` provider that reads the active
|
|
10
|
-
* locale from
|
|
11
|
+
* locale from the host app's `appLocale` global prop.
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
* 1. **angular.json `i18n` block** — declares the source locale
|
|
14
|
-
* `ng extract-i18n`
|
|
13
|
+
* Five-step setup, each step idempotent so re-running is safe:
|
|
14
|
+
* 1. **angular.json `i18n` block** — declares the source locale, which
|
|
15
|
+
* `ng extract-i18n` labels the messages with and `provideLocale()`
|
|
16
|
+
* falls back to.
|
|
15
17
|
* 2. **`@angular/localize/init` polyfill** — must run before the app boots
|
|
16
18
|
* so the global `$localize` function exists when components are
|
|
17
19
|
* instantiated.
|
|
18
20
|
* 3. **tsconfig `types`** — adds @angular/localize so $localize is typed
|
|
19
21
|
* and TypeScript doesn't flag it as an undefined global.
|
|
20
22
|
* 4. **provideLocale() in app.config** — registers the runtime provider
|
|
21
|
-
* that reads
|
|
22
|
-
* LOCALE_ID token.
|
|
23
|
+
* that reads `appLocale` (the apps `ng build --platform` makes send the
|
|
24
|
+
* phone's language) and applies it to Angular's LOCALE_ID token.
|
|
25
|
+
* 5. **`extract-i18n` target** — makes `ng extract-i18n` work, writing
|
|
26
|
+
* JSON to `src/locale`.
|
|
23
27
|
*/
|
|
24
28
|
exports.default = (options) => async (tree) => {
|
|
25
29
|
const workspace = await (0, workspace_1.getWorkspace)(tree);
|
|
@@ -33,10 +37,14 @@ exports.default = (options) => async (tree) => {
|
|
|
33
37
|
if (!project) {
|
|
34
38
|
throw new schematics_1.SchematicsException(`Project "${projectName}" not found in angular.json.`);
|
|
35
39
|
}
|
|
36
|
-
|
|
40
|
+
// Relative to the workspace root, as angular.json's paths are: the
|
|
41
|
+
// extract-i18n target's outputPath is one, so a root project's must be
|
|
42
|
+
// `src`, not `/src`.
|
|
43
|
+
const sourceRoot = project.sourceRoot ?? (project.root ? `${project.root}/src` : 'src');
|
|
37
44
|
const projectRoot = project.root;
|
|
38
45
|
return (0, schematics_1.chain)([
|
|
39
46
|
addI18nToAngularJson(projectName),
|
|
47
|
+
addExtractI18nTarget(projectName, sourceRoot),
|
|
40
48
|
addLocalizeTypes(projectRoot),
|
|
41
49
|
updateAppConfig(sourceRoot),
|
|
42
50
|
addLocalizeDependency(),
|
|
@@ -72,6 +80,15 @@ const addI18nToAngularJson = (projectName) => {
|
|
|
72
80
|
}
|
|
73
81
|
};
|
|
74
82
|
};
|
|
83
|
+
/**
|
|
84
|
+
* Gives the project an `extract-i18n` target (see useLynxExtractI18n) that
|
|
85
|
+
* writes JSON for `loadTranslations()`. `ng add` already wrote one with
|
|
86
|
+
* Angular's defaults (XLIFF at the workspace root), so this sets the format
|
|
87
|
+
* and path on it, unless the app set them itself.
|
|
88
|
+
*/
|
|
89
|
+
const addExtractI18nTarget = (projectName, sourceRoot) => (0, workspace_1.updateWorkspace)((workspace) => {
|
|
90
|
+
(0, extract_i18n_target_1.useLynxExtractI18n)(workspace.projects.get(projectName), (0, extract_i18n_target_1.jsonMessagesOptions)(sourceRoot));
|
|
91
|
+
});
|
|
75
92
|
const addLocalizeTypes = (projectRoot) => {
|
|
76
93
|
return (tree) => {
|
|
77
94
|
const tsconfigPath = `${projectRoot ? projectRoot + '/' : ''}tsconfig.app.json`;
|
|
@@ -42,15 +42,14 @@ exports.default = (options) => async (tree) => {
|
|
|
42
42
|
const addTailwindConfig = (projectRoot) => {
|
|
43
43
|
return (tree) => {
|
|
44
44
|
const configPath = `${projectRoot ? projectRoot + '/' : ''}tailwind.config.ts`;
|
|
45
|
-
// content
|
|
46
|
-
// inline
|
|
47
|
-
//
|
|
48
|
-
// the watcher down without finding anything.
|
|
45
|
+
// The build runs Tailwind with this `content`, so it has to take in both
|
|
46
|
+
// inline templates (.ts) and the .html templates `ng generate component`
|
|
47
|
+
// writes by default, as in Angular's own Tailwind setup.
|
|
49
48
|
const content = `import type { Config } from 'tailwindcss';
|
|
50
49
|
import preset from '@lynx-js/tailwind-preset';
|
|
51
50
|
|
|
52
51
|
const config: Config = {
|
|
53
|
-
content: ['./src/**/*.ts'],
|
|
52
|
+
content: ['./src/**/*.{html,ts}'],
|
|
54
53
|
presets: [preset],
|
|
55
54
|
};
|
|
56
55
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const workspace_1 = require("@schematics/angular/utility/workspace");
|
|
4
|
+
/**
|
|
5
|
+
* The singular name, as an attribute, a binding (`[accessibility-trait]`,
|
|
6
|
+
* `[attr.accessibility-trait]`) or a string, but not part of a longer name
|
|
7
|
+
* such as `accessibility-traits`.
|
|
8
|
+
*/
|
|
9
|
+
const SINGULAR = /(?<![\w-])accessibility-trait(?![\w-])/g;
|
|
10
|
+
/** Folders that hold no source of the app's own. */
|
|
11
|
+
const SKIPPED_DIRS = new Set(['node_modules', 'dist']);
|
|
12
|
+
/**
|
|
13
|
+
* Calls `visit` with the path of every template and TypeScript file under
|
|
14
|
+
* `dir`, skipping dependencies, build output and dot folders.
|
|
15
|
+
*/
|
|
16
|
+
const visitSources = (dir, visit) => {
|
|
17
|
+
for (const file of dir.subfiles) {
|
|
18
|
+
if (/\.(html|ts)$/.test(file) && !file.endsWith('.d.ts')) {
|
|
19
|
+
visit(dir.file(file).path);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (const sub of dir.subdirs) {
|
|
23
|
+
if (!SKIPPED_DIRS.has(sub) && !sub.startsWith('.')) {
|
|
24
|
+
visitSources(dir.dir(sub), visit);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Renames `accessibility-trait` to `accessibility-traits` in the app's
|
|
30
|
+
* templates.
|
|
31
|
+
*
|
|
32
|
+
* `LYNX_ELEMENTS` declared the input in the singular, but iOS, Android and
|
|
33
|
+
* Harmony read only the plural, so the attribute did nothing. Now the input
|
|
34
|
+
* is `accessibility-traits`, and a `[accessibility-trait]` binding no longer
|
|
35
|
+
* compiles. This renames both the bindings and the static attributes, in
|
|
36
|
+
* `.html` templates and in the `.ts` files that hold inline ones.
|
|
37
|
+
*/
|
|
38
|
+
exports.default = () => async (tree) => {
|
|
39
|
+
const workspace = await (0, workspace_1.getWorkspace)(tree);
|
|
40
|
+
const roots = new Set([
|
|
41
|
+
'',
|
|
42
|
+
...[...workspace.projects.values()].map((project) => project.root),
|
|
43
|
+
]);
|
|
44
|
+
// The workspace root takes in the projects under it, so a file can come up
|
|
45
|
+
// from more than one root.
|
|
46
|
+
const files = new Set();
|
|
47
|
+
for (const root of roots) {
|
|
48
|
+
visitSources(tree.getDir(root), (path) => files.add(path));
|
|
49
|
+
}
|
|
50
|
+
for (const file of files) {
|
|
51
|
+
const text = tree.readText(file);
|
|
52
|
+
const updated = text.replace(SINGULAR, 'accessibility-traits');
|
|
53
|
+
if (updated !== text)
|
|
54
|
+
tree.overwrite(file, updated);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const dev_logs_gitignore_1 = require("../../utility/dev-logs-gitignore");
|
|
4
|
+
/**
|
|
5
|
+
* Adds `.dev-logs`, where `ng serve` writes `LynxLogger`'s output, to the
|
|
6
|
+
* workspace's `.gitignore`. `ng add` now adds it to new apps; apps made before
|
|
7
|
+
* left it to the app, as the debugging guide said.
|
|
8
|
+
*/
|
|
9
|
+
exports.default = () => (0, dev_logs_gitignore_1.ignoreDevLogs)();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const workspace_1 = require("@schematics/angular/utility/workspace");
|
|
4
|
+
const extract_i18n_target_1 = require("../../utility/extract-i18n-target");
|
|
5
|
+
/**
|
|
6
|
+
* Gives every AngularLynx app in the workspace an `extract-i18n` target.
|
|
7
|
+
*
|
|
8
|
+
* Angular CLI can't pick an extractor for the Lynx build builder by itself,
|
|
9
|
+
* and neither `ng add` nor `add-i18n` wrote a target, so `ng extract-i18n`
|
|
10
|
+
* failed with "Cannot determine project or target for command." Now both
|
|
11
|
+
* write one with the AngularLynx extract-i18n builder. This gives an app made
|
|
12
|
+
* before the target those schematics would write today: `add-i18n`'s (JSON
|
|
13
|
+
* in `src/locale`) when the app has an `i18n` block in angular.json, and
|
|
14
|
+
* `ng add`'s (Angular's defaults) otherwise. A target the app added by hand
|
|
15
|
+
* with Angular's builder, as the i18n guide showed, switches to the Lynx one,
|
|
16
|
+
* which also handles imported images, and its options stay as they are: the
|
|
17
|
+
* app already extracts the format it chose.
|
|
18
|
+
*/
|
|
19
|
+
exports.default = () => (0, workspace_1.updateWorkspace)((workspace) => {
|
|
20
|
+
for (const project of workspace.projects.values()) {
|
|
21
|
+
if (project.targets.get('build')?.builder !==
|
|
22
|
+
'@blotch/angular-lynx-build:application') {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const sourceRoot = project.sourceRoot ?? (project.root ? `${project.root}/src` : 'src');
|
|
26
|
+
const isNew = !project.targets.has('extract-i18n');
|
|
27
|
+
(0, extract_i18n_target_1.useLynxExtractI18n)(project, isNew && project.extensions['i18n']
|
|
28
|
+
? (0, extract_i18n_target_1.jsonMessagesOptions)(sourceRoot)
|
|
29
|
+
: {});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const workspace_1 = require("@schematics/angular/utility/workspace");
|
|
4
|
+
/** The Tailwind config files the build looks for. */
|
|
5
|
+
const CONFIG_FILES = [
|
|
6
|
+
'tailwind.config.ts',
|
|
7
|
+
'tailwind.config.js',
|
|
8
|
+
'tailwind.config.mjs',
|
|
9
|
+
'tailwind.config.cjs',
|
|
10
|
+
];
|
|
11
|
+
/**
|
|
12
|
+
* The `content` glob that `ng add` and `add-tailwind` wrote, in either quote.
|
|
13
|
+
*/
|
|
14
|
+
const TS_ONLY_GLOB = /(['"])\.\/src\/\*\*\/\*\.ts\1/g;
|
|
15
|
+
/**
|
|
16
|
+
* Adds `.html` templates to the Tailwind `content` glob the schematics wrote.
|
|
17
|
+
*
|
|
18
|
+
* The build used to scan the modules it bundled instead of `content`, so the
|
|
19
|
+
* glob didn't matter, and classes used only in `.html` templates got no CSS.
|
|
20
|
+
* Now the build runs Tailwind with `content`, as Angular's own Tailwind setup
|
|
21
|
+
* does, and the schematics write `./src/**\/*.{html,ts}`. This brings the
|
|
22
|
+
* glob of an app made before up to date. A glob the app changed is left
|
|
23
|
+
* alone.
|
|
24
|
+
*/
|
|
25
|
+
exports.default = () => async (tree) => {
|
|
26
|
+
const workspace = await (0, workspace_1.getWorkspace)(tree);
|
|
27
|
+
// The schematics write the config at the project root, which is the
|
|
28
|
+
// workspace root for an app made by `ng new`.
|
|
29
|
+
const roots = new Set([
|
|
30
|
+
'',
|
|
31
|
+
...[...workspace.projects.values()].map((project) => project.root),
|
|
32
|
+
]);
|
|
33
|
+
for (const root of roots) {
|
|
34
|
+
for (const name of CONFIG_FILES) {
|
|
35
|
+
const file = root ? `${root}/${name}` : name;
|
|
36
|
+
if (!tree.exists(file))
|
|
37
|
+
continue;
|
|
38
|
+
const text = tree.readText(file);
|
|
39
|
+
const updated = text.replace(TS_ONLY_GLOB, (_glob, quote) => `${quote}./src/**/*.{html,ts}${quote}`);
|
|
40
|
+
if (updated !== text)
|
|
41
|
+
tree.overwrite(file, updated);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
|
|
3
|
-
"schematics": {
|
|
3
|
+
"schematics": {
|
|
4
|
+
"tailwind-html-templates": {
|
|
5
|
+
"version": "22.2.3",
|
|
6
|
+
"description": "Adds .html templates to the Tailwind content glob, which the build now reads",
|
|
7
|
+
"factory": "./migrations/tailwind-html-templates/index"
|
|
8
|
+
},
|
|
9
|
+
"accessibility-traits": {
|
|
10
|
+
"version": "22.2.3",
|
|
11
|
+
"description": "Renames accessibility-trait, which Lynx ignores, to accessibility-traits",
|
|
12
|
+
"factory": "./migrations/accessibility-traits/index"
|
|
13
|
+
},
|
|
14
|
+
"extract-i18n-target": {
|
|
15
|
+
"version": "22.2.3",
|
|
16
|
+
"description": "Adds the extract-i18n target that ng extract-i18n needs, with the AngularLynx builder",
|
|
17
|
+
"factory": "./migrations/extract-i18n-target/index"
|
|
18
|
+
},
|
|
19
|
+
"dev-logs-gitignore": {
|
|
20
|
+
"version": "22.2.3",
|
|
21
|
+
"description": "Adds .dev-logs, where ng serve writes LynxLogger's output, to .gitignore",
|
|
22
|
+
"factory": "./migrations/dev-logs-gitignore/index"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
4
25
|
}
|
|
@@ -4,14 +4,18 @@ const schematics_1 = require("@angular-devkit/schematics");
|
|
|
4
4
|
const dependency_1 = require("@schematics/angular/utility/dependency");
|
|
5
5
|
const json_file_1 = require("@schematics/angular/utility/json-file");
|
|
6
6
|
const workspace_1 = require("@schematics/angular/utility/workspace");
|
|
7
|
+
const dev_logs_gitignore_1 = require("../utility/dev-logs-gitignore");
|
|
8
|
+
const extract_i18n_target_1 = require("../utility/extract-i18n-target");
|
|
7
9
|
const versions_1 = require("./versions");
|
|
8
10
|
/**
|
|
9
11
|
* Transforms a standard `ng new` Angular project into a Lynx-native application.
|
|
10
12
|
* The schematic replaces browser-specific bootstrap (main.ts, app.config.ts,
|
|
11
|
-
* app.component.ts) with Lynx equivalents, points `ng build`, `ng serve
|
|
12
|
-
* `ng test`
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* app.component.ts) with Lynx equivalents, points `ng build`, `ng serve`,
|
|
14
|
+
* `ng test` and `ng extract-i18n` at the AngularLynx builders and
|
|
15
|
+
* `ng generate` at its schematics, git-ignores the `.dev-logs` file that
|
|
16
|
+
* `ng serve` writes `LynxLogger`'s output to, and optionally sets up Tailwind
|
|
17
|
+
* with the Lynx preset. Everything else stays as `ng new` left it: the app
|
|
18
|
+
* needs no build config besides angular.json.
|
|
15
19
|
* This is a one-shot destructive transform — the old browser-Angular files
|
|
16
20
|
* are deleted because they reference DOM APIs and HTML elements that don't
|
|
17
21
|
* exist on the Lynx runtime.
|
|
@@ -48,6 +52,7 @@ exports.default = (options) => async (tree) => {
|
|
|
48
52
|
useLynxBuilders(projectName),
|
|
49
53
|
useLynxSchematics(),
|
|
50
54
|
updatePackageScripts(),
|
|
55
|
+
(0, dev_logs_gitignore_1.ignoreDevLogs)(),
|
|
51
56
|
addCoreDependencies(),
|
|
52
57
|
];
|
|
53
58
|
// `"false"` is how `ng add ... --tailwind=false` arrives (see schema.ts).
|
|
@@ -280,12 +285,14 @@ const withLynxBudgets = (options) => {
|
|
|
280
285
|
};
|
|
281
286
|
};
|
|
282
287
|
/**
|
|
283
|
-
* Points `ng build`, `ng serve` and `ng
|
|
284
|
-
* The first two run rspeedy with
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
* `ng
|
|
288
|
+
* Points `ng build`, `ng serve`, `ng test` and `ng extract-i18n` at the
|
|
289
|
+
* AngularLynx builders. The first two run rspeedy with
|
|
290
|
+
* @blotch/rsbuild-plugin-angular-lynx added, and
|
|
291
|
+
* `ng build --platform ios|android` also produces the native app; the other
|
|
292
|
+
* two run Angular's unit-test and extract-i18n builders set up for Lynx. The
|
|
293
|
+
* build target keeps `ng new`'s Angular compiler options, which the build
|
|
294
|
+
* plugin, `ng test` and `ng extract-i18n` read, and gains the app's identity
|
|
295
|
+
* for native builds.
|
|
289
296
|
*/
|
|
290
297
|
const useLynxBuilders = (projectName) => (0, workspace_1.updateWorkspace)((workspace) => {
|
|
291
298
|
const project = workspace.projects.get(projectName);
|
|
@@ -365,6 +372,7 @@ const useLynxBuilders = (projectName) => (0, workspace_1.updateWorkspace)((works
|
|
|
365
372
|
defaultConfiguration: test.defaultConfiguration,
|
|
366
373
|
}),
|
|
367
374
|
});
|
|
375
|
+
(0, extract_i18n_target_1.useLynxExtractI18n)(project);
|
|
368
376
|
});
|
|
369
377
|
/**
|
|
370
378
|
* Makes `ng generate` reach AngularLynx's schematics first, so
|
|
@@ -422,7 +430,7 @@ const addTailwindConfig = (projectRoot) => {
|
|
|
422
430
|
import preset from '@lynx-js/tailwind-preset';
|
|
423
431
|
|
|
424
432
|
const config: Config = {
|
|
425
|
-
content: ['./src/**/*.ts'],
|
|
433
|
+
content: ['./src/**/*.{html,ts}'],
|
|
426
434
|
presets: [preset],
|
|
427
435
|
};
|
|
428
436
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ignoreDevLogs = void 0;
|
|
4
|
+
/** An entry that already ignores `.dev-logs`, anchored or not. */
|
|
5
|
+
const DEV_LOGS_ENTRY = /^\/?\.dev-logs\/?\s*$/m;
|
|
6
|
+
/**
|
|
7
|
+
* Adds `.dev-logs` to the workspace's `.gitignore`. `ng serve` writes
|
|
8
|
+
* `LynxLogger`'s output to that file, in the folder it runs from, and it
|
|
9
|
+
* shouldn't be committed. The entry has no leading slash, so it matches
|
|
10
|
+
* wherever the file is.
|
|
11
|
+
*
|
|
12
|
+
* A workspace without a `.gitignore` (`ng new --skip-git`) is left alone,
|
|
13
|
+
* and so is one that ignores the file already.
|
|
14
|
+
*/
|
|
15
|
+
const ignoreDevLogs = () => (tree) => {
|
|
16
|
+
const file = '/.gitignore';
|
|
17
|
+
if (!tree.exists(file))
|
|
18
|
+
return;
|
|
19
|
+
const text = tree.readText(file);
|
|
20
|
+
if (DEV_LOGS_ENTRY.test(text))
|
|
21
|
+
return;
|
|
22
|
+
const separator = text === '' || text.endsWith('\n') ? '' : '\n';
|
|
23
|
+
tree.overwrite(file, `${text}${separator}\n# LynxLogger's output while \`ng serve\` runs\n.dev-logs\n`);
|
|
24
|
+
};
|
|
25
|
+
exports.ignoreDevLogs = ignoreDevLogs;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jsonMessagesOptions = exports.useLynxExtractI18n = void 0;
|
|
4
|
+
const LYNX_EXTRACT_I18N_BUILDER = '@blotch/angular-lynx-build:extract-i18n';
|
|
5
|
+
/**
|
|
6
|
+
* Angular's extract-i18n builders. The Lynx builder hands its options to
|
|
7
|
+
* `@angular/build:extract-i18n`, and `@angular-devkit/build-angular`'s takes
|
|
8
|
+
* the same ones, so a target of either works with it unchanged.
|
|
9
|
+
*/
|
|
10
|
+
const ANGULAR_EXTRACT_I18N_BUILDERS = [
|
|
11
|
+
'@angular/build:extract-i18n',
|
|
12
|
+
'@angular-devkit/build-angular:extract-i18n',
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Points a project's `extract-i18n` target at the AngularLynx builder, so
|
|
16
|
+
* `ng extract-i18n` works. Angular CLI picks an extractor by itself only for
|
|
17
|
+
* a project built with one of Angular's own builders; for the Lynx build
|
|
18
|
+
* builder it fails with "Cannot determine project or target for command."
|
|
19
|
+
* Angular's extractor would fail anyway on the first imported image, which
|
|
20
|
+
* the Lynx builder sets it up for.
|
|
21
|
+
*
|
|
22
|
+
* `options` are set where the target doesn't set them already, so a format
|
|
23
|
+
* or path the app chose stays. A target of Angular's switches builder; a
|
|
24
|
+
* target with any other builder is the app's own choice, and stays as it is.
|
|
25
|
+
*/
|
|
26
|
+
const useLynxExtractI18n = (project, options = {}) => {
|
|
27
|
+
const target = project.targets.get('extract-i18n');
|
|
28
|
+
if (!target) {
|
|
29
|
+
project.targets.add({
|
|
30
|
+
name: 'extract-i18n',
|
|
31
|
+
builder: LYNX_EXTRACT_I18N_BUILDER,
|
|
32
|
+
...(Object.keys(options).length > 0 && { options }),
|
|
33
|
+
});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (target.builder !== LYNX_EXTRACT_I18N_BUILDER &&
|
|
37
|
+
!ANGULAR_EXTRACT_I18N_BUILDERS.includes(target.builder)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
target.builder = LYNX_EXTRACT_I18N_BUILDER;
|
|
41
|
+
const missing = Object.entries(options).filter(([name]) => !(name in (target.options ?? {})));
|
|
42
|
+
if (missing.length > 0) {
|
|
43
|
+
target.options = { ...target.options, ...Object.fromEntries(missing) };
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
exports.useLynxExtractI18n = useLynxExtractI18n;
|
|
47
|
+
/**
|
|
48
|
+
* The options `add-i18n` gives the `extract-i18n` target: the messages go as
|
|
49
|
+
* JSON to `<sourceRoot>/locale/messages.json`, where Angular's i18n guide
|
|
50
|
+
* keeps translation files. Angular's default format is XLIFF, but an app on
|
|
51
|
+
* Lynx loads its translations at runtime with `loadTranslations()`, which
|
|
52
|
+
* takes the JSON file's `translations` object as it is.
|
|
53
|
+
*/
|
|
54
|
+
const jsonMessagesOptions = (sourceRoot) => ({
|
|
55
|
+
format: 'json',
|
|
56
|
+
outputPath: `${sourceRoot}/locale`,
|
|
57
|
+
});
|
|
58
|
+
exports.jsonMessagesOptions = jsonMessagesOptions;
|