@ng-native/schematics 0.17.0 → 0.18.0
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 +2 -1
- package/application/index.cjs +44 -15
- package/application/schema.json +10 -1
- package/builders/spawn-bin.cjs +22 -8
- package/builders/typecheck.cjs +30 -0
- package/builders/typecheck.json +7 -0
- package/builders.json +5 -0
- package/component/index.cjs +5 -4
- package/files/AGENTS.md +4 -0
- package/files/src/app/app.ts +2 -2
- package/files/src/main.ts +5 -3
- package/files/tsconfig.json +1 -1
- package/migrations.json +16 -1
- package/ng-add/index.cjs +1 -1
- package/ng-add/schema.json +6 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -22,8 +22,9 @@ ng serve native # expo start: Metro, with Expo Go or a simulato
|
|
|
22
22
|
ng build native # expo export, into dist/native
|
|
23
23
|
ng test native # vitest run, on the fake Fabric
|
|
24
24
|
ng run native:run-ios # expo run:ios
|
|
25
|
+
ng run native:typecheck # ngc: the templates as well as the code
|
|
25
26
|
|
|
26
|
-
cd projects/native && ng generate component profile-card # <view>, <text>,
|
|
27
|
+
cd projects/native && ng generate component profile-card # src/app/profile-card: <view>, <text>, a test
|
|
27
28
|
```
|
|
28
29
|
|
|
29
30
|
## What's in the package
|
package/application/index.cjs
CHANGED
|
@@ -27,7 +27,7 @@ function writeJson(tree, file, value) {
|
|
|
27
27
|
* The project's targets. Each is an Expo command run in the project's directory, which is where
|
|
28
28
|
* Expo reads `app.json` and `metro.config.js` from.
|
|
29
29
|
*/
|
|
30
|
-
function targets(root, name) {
|
|
30
|
+
function targets(root, name, lint = false) {
|
|
31
31
|
const expo = (command, args) => ({
|
|
32
32
|
builder: '@ng-native/schematics:expo',
|
|
33
33
|
options: args ? { command, args } : { command },
|
|
@@ -40,6 +40,19 @@ function targets(root, name) {
|
|
|
40
40
|
'run-ios': expo('run:ios'),
|
|
41
41
|
'run-android': expo('run:android'),
|
|
42
42
|
test: { builder: '@ng-native/schematics:vitest', options: {} },
|
|
43
|
+
typecheck: { builder: '@ng-native/schematics:typecheck', options: {} },
|
|
44
|
+
// With `--linter=eslint`, angular-eslint's builder, which `ng lint` runs, with the project's
|
|
45
|
+
// own config: the rules that know a device from a browser, which a workspace's config for its
|
|
46
|
+
// web apps does not.
|
|
47
|
+
...(lint && {
|
|
48
|
+
lint: {
|
|
49
|
+
builder: '@angular-eslint/builder:lint',
|
|
50
|
+
options: {
|
|
51
|
+
eslintConfig: path.join(root, 'eslint.config.mjs'),
|
|
52
|
+
lintFilePatterns: [path.join(root, '**/*.ts'), path.join(root, '**/*.html')],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
43
56
|
};
|
|
44
57
|
}
|
|
45
58
|
|
|
@@ -58,7 +71,7 @@ const WEB_SPECS = [
|
|
|
58
71
|
'service',
|
|
59
72
|
];
|
|
60
73
|
|
|
61
|
-
function project(root, name, prefix) {
|
|
74
|
+
function project(root, name, prefix, lint) {
|
|
62
75
|
return {
|
|
63
76
|
projectType: 'application',
|
|
64
77
|
root,
|
|
@@ -72,17 +85,19 @@ function project(root, name, prefix) {
|
|
|
72
85
|
schematics: Object.fromEntries(
|
|
73
86
|
WEB_SPECS.map((schematic) => [`@schematics/angular:${schematic}`, { skipTests: true }]),
|
|
74
87
|
),
|
|
75
|
-
architect: targets(root, name),
|
|
88
|
+
architect: targets(root, name, lint),
|
|
76
89
|
};
|
|
77
90
|
}
|
|
78
91
|
|
|
79
92
|
/** The Commands section of the app's `AGENTS.md`, as this workspace runs them. */
|
|
80
|
-
function commands(name) {
|
|
93
|
+
function commands(name, lint) {
|
|
81
94
|
const rows = [
|
|
82
95
|
[`ng serve ${name}`, 'Metro; press i or a for a simulator, or scan the QR code with Expo Go'],
|
|
83
96
|
[`ng run ${name}:run-ios`, 'the iOS simulator'],
|
|
84
97
|
[`ng run ${name}:run-android`, 'the Android emulator'],
|
|
85
98
|
[`ng test ${name}`, 'Vitest, in Node against a fake native layer: no simulator needed'],
|
|
99
|
+
[`ng run ${name}:typecheck`, 'ngc, which checks the templates as well as the code'],
|
|
100
|
+
...(lint ? [[`ng lint ${name}`, 'ESLint: what compiles but does nothing on a device']] : []),
|
|
86
101
|
[`ng build ${name}`, 'an exported bundle'],
|
|
87
102
|
];
|
|
88
103
|
const width = Math.max(...rows.map(([command]) => command.length)) + 2;
|
|
@@ -92,16 +107,19 @@ function commands(name) {
|
|
|
92
107
|
'```',
|
|
93
108
|
'',
|
|
94
109
|
'`src/main.ts` mounts the root component, `src/app/app.ts`. ' +
|
|
95
|
-
|
|
110
|
+
(lint
|
|
111
|
+
? `Run \`ng test ${name}\` and \`ng lint ${name}\` after a change; both are fast.`
|
|
112
|
+
: `Run \`ng test ${name}\` after a change; it is fast.`),
|
|
96
113
|
].join('\n');
|
|
97
114
|
}
|
|
98
115
|
|
|
99
|
-
function writeFiles(tree, root, name, bundleIdentifier) {
|
|
116
|
+
function writeFiles(tree, root, name, bundleIdentifier, lint) {
|
|
100
117
|
for (const file of native.SOURCE_FILES) {
|
|
101
118
|
tree.create(path.join(root, file), native.sourceFile(file));
|
|
102
119
|
}
|
|
103
120
|
tree.create(path.join(root, 'app.json'), native.appJson(name, bundleIdentifier));
|
|
104
|
-
tree.create(path.join(root, 'AGENTS.md'), native.agentsFile(commands(name)));
|
|
121
|
+
tree.create(path.join(root, 'AGENTS.md'), native.agentsFile(commands(name, lint)));
|
|
122
|
+
if (lint) tree.create(path.join(root, 'eslint.config.mjs'), native.ESLINT_CONFIG);
|
|
105
123
|
tree.create(path.join(root, 'CLAUDE.md'), '@AGENTS.md\n');
|
|
106
124
|
tree.create(path.join(root, '.gitignore'), native.GITIGNORE);
|
|
107
125
|
const manifest = native.projectManifest(name, readJson(tree, 'package.json'));
|
|
@@ -109,12 +127,19 @@ function writeFiles(tree, root, name, bundleIdentifier) {
|
|
|
109
127
|
}
|
|
110
128
|
|
|
111
129
|
/** Adds what is missing and leaves every version the workspace already chose alone. */
|
|
112
|
-
function addDependencies(tree, context) {
|
|
130
|
+
function addDependencies(tree, context, lint) {
|
|
113
131
|
const manifest = readJson(tree, 'package.json');
|
|
114
|
-
|
|
132
|
+
const linter = lint ? 'eslint' : 'none';
|
|
133
|
+
for (const problem of native.conflicts(manifest, { linter })) context.logger.warn(problem);
|
|
134
|
+
const wanted = {
|
|
135
|
+
dependencies: native.dependencies,
|
|
136
|
+
devDependencies: lint
|
|
137
|
+
? { ...native.devDependencies, ...native.lintDevDependencies }
|
|
138
|
+
: native.devDependencies,
|
|
139
|
+
};
|
|
115
140
|
for (const field of ['dependencies', 'devDependencies']) {
|
|
116
141
|
const existing = { ...manifest.dependencies, ...manifest.devDependencies };
|
|
117
|
-
const added = Object.entries(
|
|
142
|
+
const added = Object.entries(wanted[field]).filter(([name]) => !(name in existing));
|
|
118
143
|
manifest[field] = Object.fromEntries(
|
|
119
144
|
[...Object.entries(manifest[field] ?? {}), ...added].sort(([a], [b]) => (a < b ? -1 : 1)),
|
|
120
145
|
);
|
|
@@ -131,7 +156,7 @@ function ignoreExpo(tree) {
|
|
|
131
156
|
}
|
|
132
157
|
|
|
133
158
|
/**
|
|
134
|
-
* @param {{ name: string, directory?: string, prefix?: string, bundleIdentifier?: string, skipInstall?: boolean }} options
|
|
159
|
+
* @param {{ name: string, directory?: string, prefix?: string, bundleIdentifier?: string, linter?: 'eslint' | 'none', skipInstall?: boolean }} options
|
|
135
160
|
*/
|
|
136
161
|
function application(options) {
|
|
137
162
|
return (tree, context) => {
|
|
@@ -152,16 +177,20 @@ function application(options) {
|
|
|
152
177
|
const problem = native.bundleIdentifierProblem(bundleIdentifier);
|
|
153
178
|
if (problem) throw new SchematicsException(problem);
|
|
154
179
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
180
|
+
const lint = options.linter === 'eslint';
|
|
181
|
+
addDependencies(tree, context, lint);
|
|
182
|
+
writeFiles(tree, root, name, bundleIdentifier, lint);
|
|
183
|
+
const added = project(root, name, options.prefix, lint);
|
|
184
|
+
workspace.projects = { ...workspace.projects, [name]: added };
|
|
158
185
|
writeJson(tree, 'angular.json', workspace);
|
|
159
186
|
ignoreExpo(tree);
|
|
160
187
|
|
|
161
188
|
if (!options.skipInstall) context.addTask(new NodePackageInstallTask());
|
|
162
189
|
context.logger.info(
|
|
163
190
|
`Created ${root}. Run it with: ng serve ${name} (Metro), ng run ${name}:run-ios, ` +
|
|
164
|
-
`ng test ${name}, ng
|
|
191
|
+
`ng test ${name}, ng run ${name}:typecheck, ` +
|
|
192
|
+
(lint ? `ng lint ${name}, ` : '') +
|
|
193
|
+
`ng build ${name}.`,
|
|
165
194
|
);
|
|
166
195
|
};
|
|
167
196
|
}
|
package/application/schema.json
CHANGED
|
@@ -8,7 +8,10 @@
|
|
|
8
8
|
"type": "string",
|
|
9
9
|
"description": "The project name, in angular.json and as the Expo slug.",
|
|
10
10
|
"pattern": "^[a-z][a-z0-9-]*$",
|
|
11
|
-
"$default": {
|
|
11
|
+
"$default": {
|
|
12
|
+
"$source": "argv",
|
|
13
|
+
"index": 0
|
|
14
|
+
},
|
|
12
15
|
"x-prompt": "What should the native app be called?"
|
|
13
16
|
},
|
|
14
17
|
"directory": {
|
|
@@ -25,6 +28,12 @@
|
|
|
25
28
|
"type": "string",
|
|
26
29
|
"description": "The iOS bundle identifier and Android package: com.acme.mobile. Defaults to com.<workspace scope>.<name>."
|
|
27
30
|
},
|
|
31
|
+
"linter": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "eslint adds an eslint.config.mjs with @ng-native/eslint-plugin's recommended rules, its dependencies and a lint target.",
|
|
34
|
+
"enum": ["eslint", "none"],
|
|
35
|
+
"default": "none"
|
|
36
|
+
},
|
|
28
37
|
"skipInstall": {
|
|
29
38
|
"type": "boolean",
|
|
30
39
|
"description": "Write the files and package.json without installing.",
|
package/builders/spawn-bin.cjs
CHANGED
|
@@ -21,13 +21,14 @@ function findManifest(name, from) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* @param {string} name the package, `expo` or `
|
|
24
|
+
* @param {string} name the package, such as `expo`, `vitest` or `@angular/compiler-cli`
|
|
25
25
|
* @param {string} from the directory to resolve it from
|
|
26
|
+
* @param {string} command the entry of its `bin` to run, when not named for the package: `ngc`
|
|
26
27
|
*/
|
|
27
|
-
function resolveBin(name, from) {
|
|
28
|
+
function resolveBin(name, from, command = name) {
|
|
28
29
|
const manifestPath = findManifest(name, from);
|
|
29
30
|
const { bin } = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
30
|
-
const file = typeof bin === 'string' ? bin : bin[
|
|
31
|
+
const file = typeof bin === 'string' ? bin : bin[command];
|
|
31
32
|
return path.join(path.dirname(manifestPath), file);
|
|
32
33
|
}
|
|
33
34
|
|
|
@@ -56,12 +57,25 @@ const SIGNALS = ['SIGINT', 'SIGTERM', 'SIGHUP'];
|
|
|
56
57
|
*/
|
|
57
58
|
async function spawnBin(name, args, context) {
|
|
58
59
|
const cwd = await projectRoot(context);
|
|
59
|
-
|
|
60
|
+
return spawnFile(resolveBin(name, cwd), args, cwd, name, context);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Runs `file` with Node in `cwd`, logged and reported as `label`.
|
|
65
|
+
*
|
|
66
|
+
* @param {string} file
|
|
67
|
+
* @param {string[]} args
|
|
68
|
+
* @param {string} cwd
|
|
69
|
+
* @param {string} label
|
|
70
|
+
* @param {import('@angular-devkit/architect').BuilderContext} context
|
|
71
|
+
* @returns {Promise<{ success: boolean, error?: string }>}
|
|
72
|
+
*/
|
|
73
|
+
function spawnFile(file, args, cwd, label, context) {
|
|
60
74
|
context.logger.info(
|
|
61
|
-
`${
|
|
75
|
+
`${[label, ...args].join(' ')} (in ${path.relative(context.workspaceRoot, cwd)})`,
|
|
62
76
|
);
|
|
63
77
|
return new Promise((resolve) => {
|
|
64
|
-
const child = spawn(process.execPath, [
|
|
78
|
+
const child = spawn(process.execPath, [file, ...args], { cwd, stdio: 'inherit' });
|
|
65
79
|
// Ctrl-C reaches the whole process group, but a supervisor, CI or an IDE's task runner signals
|
|
66
80
|
// `ng` alone, and Metro would outlive it on its port. So a stop is passed on.
|
|
67
81
|
const stop = (signal) => child.kill(signal);
|
|
@@ -75,10 +89,10 @@ async function spawnBin(name, args, context) {
|
|
|
75
89
|
settle(
|
|
76
90
|
code === 0
|
|
77
91
|
? { success: true }
|
|
78
|
-
: { success: false, error: `${
|
|
92
|
+
: { success: false, error: `${label} exited with ${signal ?? `code ${code}`}` },
|
|
79
93
|
),
|
|
80
94
|
);
|
|
81
95
|
});
|
|
82
96
|
}
|
|
83
97
|
|
|
84
|
-
module.exports = { resolveBin, projectRoot, spawnBin };
|
|
98
|
+
module.exports = { resolveBin, projectRoot, spawnBin, spawnFile };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ng-native/schematics:typecheck`: the project's code and templates, checked by `ngc`.
|
|
3
|
+
*
|
|
4
|
+
* `tsc` reads no template, so a binding to an input a component does not have passes it. The Metro
|
|
5
|
+
* config is loaded first, as the template's `typecheck` script does: once Tailwind is added, it
|
|
6
|
+
* writes the sheet `src/main.ts` imports, which a fresh checkout does not have.
|
|
7
|
+
*/
|
|
8
|
+
const { createBuilder } = require('@angular-devkit/architect');
|
|
9
|
+
const { existsSync } = require('node:fs');
|
|
10
|
+
const path = require('node:path');
|
|
11
|
+
const { projectRoot, resolveBin, spawnFile } = require('./spawn-bin.cjs');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {import('@angular-devkit/architect').BuilderContext} context
|
|
15
|
+
* @returns {Promise<{ success: boolean, error?: string }>}
|
|
16
|
+
*/
|
|
17
|
+
async function runTypecheck(context) {
|
|
18
|
+
const cwd = await projectRoot(context);
|
|
19
|
+
// A project without one has no Tailwind sheet to write either.
|
|
20
|
+
const metroConfig = path.join(cwd, 'metro.config.js');
|
|
21
|
+
if (existsSync(metroConfig)) {
|
|
22
|
+
const config = await spawnFile(metroConfig, [], cwd, 'node metro.config.js', context);
|
|
23
|
+
if (!config.success) return config;
|
|
24
|
+
}
|
|
25
|
+
const ngc = resolveBin('@angular/compiler-cli', cwd, 'ngc');
|
|
26
|
+
return spawnFile(ngc, ['-p', 'tsconfig.json', '--noEmit'], cwd, 'ngc', context);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = createBuilder((_options, context) => runTypecheck(context));
|
|
30
|
+
module.exports.runTypecheck = runTypecheck;
|
package/builders.json
CHANGED
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"implementation": "./builders/vitest.cjs",
|
|
11
11
|
"schema": "./builders/vitest.json",
|
|
12
12
|
"description": "Runs the project's tests once with Vitest, through @ng-native/testing."
|
|
13
|
+
},
|
|
14
|
+
"typecheck": {
|
|
15
|
+
"implementation": "./builders/typecheck.cjs",
|
|
16
|
+
"schema": "./builders/typecheck.json",
|
|
17
|
+
"description": "Checks the project's code and templates with ngc, after loading its Metro config."
|
|
13
18
|
}
|
|
14
19
|
}
|
|
15
20
|
}
|
package/component/index.cjs
CHANGED
|
@@ -14,17 +14,18 @@ const { componentSource, testSource } = require('./sources.cjs');
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* The directory the component goes in: the one `ng generate` was run from if that is inside the
|
|
17
|
-
* project,
|
|
17
|
+
* project's `src`, and `src/app` otherwise, beside `app.ts`, as Angular's own schematic and
|
|
18
|
+
* `@ng-native/nx:component` put it. From the project's own directory that is `src/app` too.
|
|
18
19
|
*/
|
|
19
20
|
function directoryFor(workspace, options) {
|
|
20
21
|
const project = workspace.projects?.[options.project];
|
|
21
22
|
if (!project) {
|
|
22
23
|
throw new SchematicsException(`angular.json has no project called "${options.project}".`);
|
|
23
24
|
}
|
|
24
|
-
const
|
|
25
|
+
const src = path.join(project.root, 'src');
|
|
25
26
|
const cwd = path.normalize(options.path ?? '');
|
|
26
|
-
const inside = cwd ===
|
|
27
|
-
return { directory: inside ? cwd :
|
|
27
|
+
const inside = cwd === src || cwd.startsWith(src + '/');
|
|
28
|
+
return { directory: inside ? cwd : path.join(src, 'app'), prefix: project.prefix };
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
/**
|
package/files/AGENTS.md
CHANGED
|
@@ -83,3 +83,7 @@ change; both are fast.
|
|
|
83
83
|
`getByText` or `getByTestId` (which matches `nativeID` and `testID`), and act with
|
|
84
84
|
`userEvent.setup().press(...)` or `.type(...)`, all from `@ng-native/testing`. Tests run in Node
|
|
85
85
|
with no simulator, so write one alongside a change.
|
|
86
|
+
|
|
87
|
+
A service that depends on the platform injects `OS` and `OS_VERSION` from `@ng-native/device`
|
|
88
|
+
rather than importing `Platform` from `react-native`, which a test cannot load. A test provides
|
|
89
|
+
the values it wants: `{ provide: OS, useValue: 'android' }`.
|
package/files/src/app/app.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { Pressable, SafeAreaProvider, SafeAreaView, Text, View } from '@ng-nativ
|
|
|
3
3
|
import { StatusBar } from '@ng-native/device';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Element names are lowercase, and that is load-bearing rather than style: an uppercase name
|
|
7
|
-
*
|
|
6
|
+
* Element names are lowercase, and that is load-bearing rather than style: an uppercase name such
|
|
7
|
+
* as <View> matches no component's selector, and the Metro transform fails the build on it.
|
|
8
8
|
*/
|
|
9
9
|
@Component({
|
|
10
10
|
imports: [Pressable, SafeAreaProvider, SafeAreaView, Text, View],
|
package/files/src/main.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { App } from './app/app.ts';
|
|
|
10
10
|
|
|
11
11
|
registerPlatformComponents(Platform.OS);
|
|
12
12
|
|
|
13
|
-
AppRegistry.registerRunnable('main', ({ rootTag }
|
|
13
|
+
AppRegistry.registerRunnable('main', ({ rootTag }) => {
|
|
14
14
|
const app = mount(Number(rootTag), App, getFabricUIManager(), {
|
|
15
15
|
// Colours, as the integers the platform wants.
|
|
16
16
|
processColor,
|
|
@@ -26,6 +26,8 @@ AppRegistry.registerRunnable('main', ({ rootTag }: { rootTag: number | string })
|
|
|
26
26
|
|
|
27
27
|
// Re-resolves the conditions when the device rotates or the theme changes. A rotation dirties
|
|
28
28
|
// no component and no binding, so without this nothing re-renders and `dark:` stops following
|
|
29
|
-
// the system switch.
|
|
30
|
-
|
|
29
|
+
// the system switch. It stops with the app, which Android destroys when it recreates the
|
|
30
|
+
// activity, so the app mounted in its place is the only one still watching.
|
|
31
|
+
const stopWatching = watchConditions(app.engine);
|
|
32
|
+
app.applicationRef.onDestroy(stopWatching);
|
|
31
33
|
});
|
package/files/tsconfig.json
CHANGED
package/migrations.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "../../node_modules/@angular-devkit/schematics/collection-schema.json",
|
|
3
3
|
"schematics": {
|
|
4
4
|
"sync-app-versions": {
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.18.0",
|
|
6
6
|
"description": "Move the @ng-native packages each project's own package.json lists to the new version.",
|
|
7
7
|
"factory": "./migrations/run.cjs#sync-app-versions"
|
|
8
8
|
},
|
|
@@ -30,6 +30,21 @@
|
|
|
30
30
|
"version": "0.17.0",
|
|
31
31
|
"description": "Read an engine node's children, text, kind, host and sheet by their new names.",
|
|
32
32
|
"factory": "./migrations/run.cjs#engine-node-fields"
|
|
33
|
+
},
|
|
34
|
+
"library-typecheck-declaration-map": {
|
|
35
|
+
"version": "0.17.1",
|
|
36
|
+
"description": "Turn off declarationMap in each Nx library's tsconfig.typecheck.json, which TypeScript refuses beside composite: false.",
|
|
37
|
+
"factory": "./migrations/run.cjs#library-typecheck-declaration-map"
|
|
38
|
+
},
|
|
39
|
+
"native-typecheck-target": {
|
|
40
|
+
"version": "0.17.1",
|
|
41
|
+
"description": "Give each Angular Native project in angular.json a typecheck target, run by ngc.",
|
|
42
|
+
"factory": "./migrations/run.cjs#native-typecheck-target"
|
|
43
|
+
},
|
|
44
|
+
"stop-watching-conditions": {
|
|
45
|
+
"version": "0.17.2",
|
|
46
|
+
"description": "Keep what watchConditions returns in each app's entry point and stop it as the app is destroyed.",
|
|
47
|
+
"factory": "./migrations/run.cjs#stop-watching-conditions"
|
|
33
48
|
}
|
|
34
49
|
}
|
|
35
50
|
}
|
package/ng-add/index.cjs
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
const { application } = require('../application/index.cjs');
|
|
10
10
|
|
|
11
|
-
/** @param {{ name?: string, directory?: string, bundleIdentifier?: string, skipInstall?: boolean }} options */
|
|
11
|
+
/** @param {{ name?: string, directory?: string, bundleIdentifier?: string, linter?: 'eslint' | 'none', skipInstall?: boolean }} options */
|
|
12
12
|
function ngAdd(options) {
|
|
13
13
|
return application({ ...options, name: options.name ?? 'native', prefix: 'app' });
|
|
14
14
|
}
|
package/ng-add/schema.json
CHANGED
|
@@ -18,6 +18,12 @@
|
|
|
18
18
|
"type": "string",
|
|
19
19
|
"description": "The iOS bundle identifier and Android package: com.acme.mobile. Defaults to com.<workspace scope>.<name>."
|
|
20
20
|
},
|
|
21
|
+
"linter": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "eslint adds an eslint.config.mjs with @ng-native/eslint-plugin's recommended rules, its dependencies and a lint target.",
|
|
24
|
+
"enum": ["eslint", "none"],
|
|
25
|
+
"default": "none"
|
|
26
|
+
},
|
|
21
27
|
"skipInstall": {
|
|
22
28
|
"type": "boolean",
|
|
23
29
|
"description": "Write the files and package.json without installing.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ng-native/schematics",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "ng add and ng generate for Angular Native: an Expo app in an Angular CLI workspace, with builders that run it.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"@ng-native/analog",
|
|
29
29
|
"@ng-native/components",
|
|
30
30
|
"@ng-native/device",
|
|
31
|
+
"@ng-native/eslint-plugin",
|
|
31
32
|
"@ng-native/expo",
|
|
32
33
|
"@ng-native/fabric",
|
|
33
34
|
"@ng-native/icons",
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
"@angular-devkit/architect": ">=0.2200.0 <0.2300.0",
|
|
48
49
|
"@angular-devkit/core": "^22.0.0",
|
|
49
50
|
"@angular-devkit/schematics": "^22.0.0",
|
|
50
|
-
"@ng-native/migrate": "0.
|
|
51
|
+
"@ng-native/migrate": "0.18.0"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@schematics/angular": "22.1.9"
|