@ng-native/nx 0.2.0 → 0.3.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.
@@ -0,0 +1,239 @@
1
+ /**
2
+ * `nx g @ng-native/nx:library packages/ui`: a library of native components, tested the way an
3
+ * Angular Native app is.
4
+ *
5
+ * The library itself is the workspace's own kind: `@nx/angular:library` where the workspace has
6
+ * `@nx/angular`, and `@nx/js:library` in the TypeScript preset, which cannot take `@nx/angular`
7
+ * because Angular does not support TypeScript project references. Either is run without its
8
+ * tests, which would be Analog on jsdom or a plain Vitest, neither of which can render a native
9
+ * component. In their place this writes the app's `vitest.config.mts`, a `test` target that runs
10
+ * it once, a `tsconfig.spec.json` for the tests, and a native component with a test for the fake
11
+ * Fabric in place of the one the generator wrote.
12
+ */
13
+ const { readFileSync } = require('node:fs');
14
+ const nodePath = require('node:path');
15
+ const path = nodePath.posix;
16
+ const {
17
+ addDependenciesToPackageJson,
18
+ ensurePackage,
19
+ formatFiles,
20
+ getProjects,
21
+ installPackagesTask,
22
+ joinPathFragments,
23
+ names,
24
+ readNxJson,
25
+ readJson,
26
+ updateJson,
27
+ updateProjectConfiguration,
28
+ } = require('@nx/devkit');
29
+ const native = require('../native-app.cjs');
30
+ const { workspaceNxVersion } = require('../init/index.cjs');
31
+ const { hasPathAliases } = require('../application/index.cjs');
32
+ const { usesWorkspaces } = require('../application/workspaces.cjs');
33
+ const { asSaved } = require('../save-exact.cjs');
34
+ const { writeComponent } = require('../component/index.cjs');
35
+
36
+ /**
37
+ * The defaults a generator's schema gives its options, from the copy installed at `root`.
38
+ *
39
+ * @param {string} root
40
+ * @param {string} pkg
41
+ * @param {string} generator
42
+ * @returns {Record<string, unknown>}
43
+ */
44
+ function schemaDefaults(root, pkg, generator) {
45
+ let manifest;
46
+ try {
47
+ manifest = require.resolve(`${pkg}/package.json`, { paths: [root] });
48
+ } catch {
49
+ return {};
50
+ }
51
+ const read = (file) =>
52
+ JSON.parse(readFileSync(nodePath.join(nodePath.dirname(manifest), file), 'utf8'));
53
+ const entry = read(read('package.json').generators).generators[generator];
54
+ const { properties = {} } = read(entry.schema);
55
+ return Object.fromEntries(
56
+ Object.entries(properties)
57
+ .filter(([, property]) => 'default' in property)
58
+ .map(([name, property]) => [name, property.default]),
59
+ );
60
+ }
61
+
62
+ /**
63
+ * The options `nx g <pkg>:<generator>` starts from: its schema's defaults, then the workspace's
64
+ * own in `nx.json`. A generator called from another gets neither, and `@nx/angular:library` called
65
+ * bare writes a library with strict type checking off.
66
+ *
67
+ * @param {import('@nx/devkit').Tree} tree
68
+ * @param {string} pkg
69
+ * @param {string} generator
70
+ */
71
+ function generatorDefaults(tree, pkg, generator, root = tree.root) {
72
+ const workspace = readNxJson(tree)?.generators ?? {};
73
+ return {
74
+ ...schemaDefaults(root, pkg, generator),
75
+ ...workspace[pkg]?.[generator],
76
+ ...workspace[`${pkg}:${generator}`],
77
+ };
78
+ }
79
+
80
+ /** The library generators this one builds on, at the workspace's Nx. Replaced in tests. */
81
+ const bases = {
82
+ /** @param {import('@nx/devkit').Tree} tree @param {object} options */
83
+ async angular(tree, options) {
84
+ // Only run where the workspace lists `@nx/angular`, whose root export has no generators.
85
+ const { libraryGenerator } = ensurePackage('@nx/angular/generators', workspaceNxVersion(tree));
86
+ return libraryGenerator(tree, {
87
+ ...generatorDefaults(tree, '@nx/angular', 'library'),
88
+ ...options,
89
+ });
90
+ },
91
+ /** @param {import('@nx/devkit').Tree} tree @param {object} options */
92
+ async js(tree, options) {
93
+ const { libraryGenerator } = ensurePackage('@nx/js', workspaceNxVersion(tree));
94
+ return libraryGenerator(tree, { ...generatorDefaults(tree, '@nx/js', 'library'), ...options });
95
+ },
96
+ };
97
+
98
+ /** What the component and its test import. */
99
+ const imports = {
100
+ dependencies: {
101
+ '@angular/core': native.dependencies['@angular/core'],
102
+ '@ng-native/components': native.dependencies['@ng-native/components'],
103
+ },
104
+ devDependencies: {
105
+ '@ng-native/testing': native.devDependencies['@ng-native/testing'],
106
+ vitest: native.devDependencies.vitest,
107
+ },
108
+ };
109
+
110
+ function projectAt(tree, root) {
111
+ for (const [name, project] of getProjects(tree))
112
+ if (project.root === root) return { name, project };
113
+ throw new Error(`No project was generated in ${root}.`);
114
+ }
115
+
116
+ /**
117
+ * The native component and its test, where the generator put its own component: in a folder of
118
+ * its own under `src/lib` from `@nx/angular`, with an external template and stylesheet this
119
+ * leaves out, or as `src/lib/<name>.ts` from `@nx/js`. `src/index.ts` already exports it.
120
+ */
121
+ function replaceComponent(tree, project, file) {
122
+ const lib = joinPathFragments(project.root, 'src', 'lib');
123
+ const folder = tree.exists(joinPathFragments(lib, file, `${file}.ts`))
124
+ ? joinPathFragments(lib, file)
125
+ : lib;
126
+ for (const extension of ['html', 'css', 'spec.ts']) {
127
+ const own = joinPathFragments(folder, `${file}.${extension}`);
128
+ if (tree.exists(own)) tree.delete(own);
129
+ }
130
+ writeComponent(tree, folder, file, project.prefix);
131
+ }
132
+
133
+ /**
134
+ * A `tsconfig.spec.json` like the one each generator writes with its tests, including the tests
135
+ * and the Vitest config. The tests import their component as `./ui.ts`, as the template's do.
136
+ */
137
+ function writeSpecConfig(tree, root, angular) {
138
+ const include = ['vitest.config.mts', 'src/**/*.test.ts'];
139
+ const spec = angular
140
+ ? {
141
+ extends: './tsconfig.json',
142
+ compilerOptions: { noEmit: true, allowImportingTsExtensions: true },
143
+ include,
144
+ }
145
+ : {
146
+ // A project reference of the TypeScript preset's, which emits declarations only.
147
+ extends: readJson(tree, joinPathFragments(root, 'tsconfig.lib.json')).extends,
148
+ compilerOptions: { outDir: './out-tsc/vitest', allowImportingTsExtensions: true },
149
+ include,
150
+ references: [{ path: './tsconfig.lib.json' }],
151
+ };
152
+ tree.write(joinPathFragments(root, 'tsconfig.spec.json'), JSON.stringify(spec, null, 2) + '\n');
153
+ updateJson(tree, joinPathFragments(root, 'tsconfig.json'), (config) => {
154
+ const references = config.references ?? [];
155
+ if (!references.some((reference) => reference.path === './tsconfig.spec.json')) {
156
+ references.push({ path: './tsconfig.spec.json' });
157
+ }
158
+ return { ...config, references };
159
+ });
160
+ updateJson(tree, joinPathFragments(root, 'tsconfig.lib.json'), (config) => {
161
+ const exclude = config.exclude ?? [];
162
+ if (!exclude.includes('src/**/*.test.ts')) exclude.push('src/**/*.test.ts');
163
+ return { ...config, exclude };
164
+ });
165
+ }
166
+
167
+ /**
168
+ * The packages the component and its test import: in the library's own `package.json` when it is
169
+ * a workspace package, which pnpm links from, and at the root otherwise. A version already there
170
+ * is left alone.
171
+ */
172
+ async function addImports(tree, root) {
173
+ const manifest = joinPathFragments(root, 'package.json');
174
+ const rootManifest = readJson(tree, 'package.json');
175
+ if (tree.exists(manifest)) {
176
+ const own = async (wanted) => asSaved(tree, native.reuseRootRanges(wanted, rootManifest));
177
+ return addDependenciesToPackageJson(
178
+ tree,
179
+ await own(imports.dependencies),
180
+ await own(imports.devDependencies),
181
+ manifest,
182
+ true,
183
+ );
184
+ }
185
+ const existing = Object.keys({ ...rootManifest.dependencies, ...rootManifest.devDependencies });
186
+ return addDependenciesToPackageJson(
187
+ tree,
188
+ await asSaved(tree, imports.dependencies, existing),
189
+ await asSaved(tree, imports.devDependencies, existing),
190
+ 'package.json',
191
+ true,
192
+ );
193
+ }
194
+
195
+ /**
196
+ * @param {import('@nx/devkit').Tree} tree
197
+ * @param {{ directory: string, name?: string, tags?: string, skipInstall?: boolean, skipFormat?: boolean }} options
198
+ */
199
+ async function library(tree, options) {
200
+ const directory = path.normalize(options.directory).replace(/\/$/, '');
201
+ const { dependencies, devDependencies } = readJson(tree, 'package.json');
202
+ const angular = Boolean({ ...dependencies, ...devDependencies }['@nx/angular']);
203
+ const shared = { directory, name: options.name, tags: options.tags, unitTestRunner: 'none' };
204
+ if (angular) await bases.angular(tree, { ...shared, skipFormat: true });
205
+ else await bases.js(tree, { ...shared, bundler: 'none', skipFormat: true });
206
+
207
+ const { name, project } = projectAt(tree, directory);
208
+ const file = names(options.name ?? path.basename(directory)).fileName;
209
+ replaceComponent(tree, project, file);
210
+
211
+ const aliases = hasPathAliases(tree, usesWorkspaces(tree));
212
+ tree.write(joinPathFragments(directory, 'vitest.config.mts'), native.vitestConfig(aliases));
213
+ writeSpecConfig(tree, directory, angular);
214
+ updateProjectConfiguration(tree, name, {
215
+ ...project,
216
+ targets: {
217
+ ...project.targets,
218
+ test: {
219
+ executor: 'nx:run-commands',
220
+ options: { cwd: directory, command: 'vitest run' },
221
+ cache: true,
222
+ inputs: ['default', '^production'],
223
+ },
224
+ },
225
+ });
226
+
227
+ await addImports(tree, directory);
228
+ // `nxViteTsPaths()`, which the Vitest config uses to reach the workspace's other libraries.
229
+ if (aliases) {
230
+ const vite = { '@nx/vite': workspaceNxVersion(tree) };
231
+ addDependenciesToPackageJson(tree, {}, vite, 'package.json', true);
232
+ }
233
+
234
+ if (!options.skipFormat) await formatFiles(tree);
235
+ if (options.skipInstall) return () => {};
236
+ return () => installPackagesTask(tree, true);
237
+ }
238
+
239
+ module.exports = { library, bases, generatorDefaults };
@@ -0,0 +1,36 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "NgNativeNxLibrary",
4
+ "title": "Angular Native library",
5
+ "description": "A library of native components, whose tests render on the fake Fabric as an app's do.",
6
+ "type": "object",
7
+ "properties": {
8
+ "directory": {
9
+ "type": "string",
10
+ "description": "Where the library goes, relative to the workspace root: packages/ui.",
11
+ "$default": { "$source": "argv", "index": 0 },
12
+ "x-prompt": "Which directory should the library be created in?"
13
+ },
14
+ "name": {
15
+ "type": "string",
16
+ "description": "The project name. Defaults to the directory's last segment.",
17
+ "pattern": "^[a-z][a-z0-9-]*$"
18
+ },
19
+ "tags": {
20
+ "type": "string",
21
+ "description": "Comma-separated tags for the project."
22
+ },
23
+ "skipInstall": {
24
+ "type": "boolean",
25
+ "description": "Write the files without installing.",
26
+ "default": false
27
+ },
28
+ "skipFormat": {
29
+ "type": "boolean",
30
+ "description": "Leave the generated files unformatted.",
31
+ "default": false,
32
+ "x-priority": "internal"
33
+ }
34
+ },
35
+ "required": ["directory"]
36
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * The migrations `nx migrate` runs, from `@ng-native/migrate`, where each one is written once for
3
+ * `nx migrate`, `ng update` and `npx @ng-native/migrate` alike.
4
+ */
5
+ module.exports = require('@ng-native/migrate').forNx();
@@ -0,0 +1,24 @@
1
+ {
2
+ "generators": {
3
+ "sync-app-versions": {
4
+ "version": "0.3.0",
5
+ "description": "Move the @ng-native packages each project's own package.json lists to the new version.",
6
+ "implementation": "./migrations/run.cjs#sync-app-versions"
7
+ },
8
+ "split-store-and-player": {
9
+ "version": "0.3.0",
10
+ "description": "Import Storage, SecureStorage, audioPlayer and videoPlayer from the entry points that now hold them.",
11
+ "implementation": "./migrations/run.cjs#split-store-and-player"
12
+ },
13
+ "tracking-available-getter": {
14
+ "version": "0.3.0",
15
+ "description": "Read Tracking's available as a property rather than calling it.",
16
+ "implementation": "./migrations/run.cjs#tracking-available-getter"
17
+ },
18
+ "device-react-native-import": {
19
+ "version": "0.3.0",
20
+ "description": "Note each import of reactNative or ReactNative from @ng-native/device, which no longer exports them.",
21
+ "implementation": "./migrations/run.cjs#device-react-native-import"
22
+ }
23
+ }
24
+ }
package/native-app.cjs CHANGED
@@ -2,9 +2,9 @@
2
2
  * What an Angular Native app is made of, in an Nx workspace.
3
3
  *
4
4
  * The source of truth is `template/`, the starter `create-expo-app` uses and the setup this project
5
- * verifies before every release. `files/` holds verbatim copies of the template's source files and
6
- * the versions below are the template's own, and `native-app.test.ts` fails the moment either
7
- * drifts from it.
5
+ * verifies before every release. `files/` holds verbatim copies of the template's source files,
6
+ * the versions are the template's own, and `native-app.test.ts` fails the moment either drifts
7
+ * from it.
8
8
  *
9
9
  * Three files differ from the template's, each because of something Nx does:
10
10
  *
@@ -16,59 +16,35 @@
16
16
  * - `vitest.config.mts` adds `nxViteTsPaths` when the workspace has `@nx/vite`, for the same
17
17
  * aliases, which Vitest does not read from tsconfig either.
18
18
  *
19
- * The `@ng-native/*` packages are pinned to this package's own version, because every one of them
20
- * is released in lockstep with it.
19
+ * What does not depend on Nx, the dependencies, `app.json` and bundle identifier among them, is
20
+ * `@ng-native/migrate/native-app.cjs`, which `@ng-native/schematics` builds its apps from too.
21
21
  */
22
22
  const { readFileSync } = require('node:fs');
23
23
  const path = require('node:path');
24
24
  const semver = require('semver');
25
+ const shared = require('@ng-native/migrate/native-app.cjs');
25
26
 
26
- const { version } = require('./package.json');
27
-
28
- const FRAMEWORK = [
29
- '@ng-native/components',
30
- '@ng-native/device',
31
- '@ng-native/fabric',
32
- '@ng-native/metro',
33
- '@ng-native/platform',
34
- ];
35
-
36
- /** @type {Record<string, string>} */
37
- const dependencies = {
38
- ...Object.fromEntries(FRAMEWORK.map((name) => [name, version])),
39
- '@angular/common': '^22.0.0',
40
- '@angular/core': '^22.0.0',
41
- expo: '~57.0.26',
42
- 'expo-status-bar': '~57.0.1',
43
- 'expo-system-ui': '~57.0.4',
44
- react: '19.2.3',
45
- 'react-native': '0.86.3',
46
- 'react-native-safe-area-context': '~5.7.0',
47
- };
27
+ const { dependencies, devDependencies, accepted } = shared;
48
28
 
49
29
  /**
50
30
  * What `nx add` puts beside `@nx/expo`, in place of the `@nx/expo:init` it does not run: see
51
- * `init/index.cjs`. `@expo/cli` and `@babel/runtime` are the ranges the template's `expo` depends
52
- * on.
31
+ * `init/index.cjs`. `@expo/cli`, `@babel/runtime` and `@expo/metro` are the ranges the template's
32
+ * `expo` depends on, and `@babel/core` is the app's own, which every plugin in Expo's Babel preset peers on.
53
33
  */
54
34
  const expoCompanions = {
55
35
  'react-dom': dependencies.react,
56
36
  '@expo/cli': '^57.0.27',
57
37
  '@babel/runtime': '^7.20.0',
38
+ '@babel/core': devDependencies['@babel/core'],
39
+ '@expo/metro': '~56.0.2',
58
40
  };
59
41
 
60
- /** @type {Record<string, string>} */
61
- const devDependencies = {
62
- // An Angular workspace already has Babel 8 through @angular/compiler-cli, and React Native's
63
- // Babel peer would otherwise take the newest copy there is.
64
- // The typecheck script compiles the templates too, which only the Angular compiler can.
65
- '@angular/compiler-cli': '^22.0.0',
66
- '@babel/core': '^7.29.7',
67
- '@ng-native/testing': version,
68
- '@types/react': '~19.2.2',
69
- typescript: '~6.0.3',
70
- vitest: '^5.0.0',
71
- };
42
+ /**
43
+ * The template's `typecheck` script. It loads the Metro config first, which builds the sheet
44
+ * `@ng-native/tailwind` generates into `.angular-native/` once and exits: `src/main.ts` imports it
45
+ * once Tailwind is added, and a fresh checkout has none until Metro has run.
46
+ */
47
+ const TYPECHECK = 'node metro.config.js && ngc -p tsconfig.json --noEmit';
72
48
 
73
49
  /** The template's files, copied verbatim into the new app. */
74
50
  const SOURCE_FILES = ['src/app/app.ts', 'src/main.ts', 'src/app/app.test.ts'];
@@ -91,74 +67,6 @@ function agentsFile(commands) {
91
67
  );
92
68
  }
93
69
 
94
- /** Java's reserved words, which Android refuses as a segment of a package name. */
95
- const JAVA_KEYWORDS = new Set(
96
- (
97
- 'abstract assert boolean break byte case catch char class const continue default do double ' +
98
- 'else enum extends false final finally float for goto if implements import instanceof int ' +
99
- 'interface long native new null package private protected public return short static ' +
100
- 'strictfp super switch synchronized this throw throws transient true try void volatile while'
101
- ).split(' '),
102
- );
103
-
104
- /**
105
- * Whether iOS takes `id` as a bundle identifier and Android as a package name: two or more
106
- * segments, each a letter and then letters or digits (iOS refuses `_`, Android `-`), none of them
107
- * a Java keyword.
108
- *
109
- * @param {string} id
110
- */
111
- function isBundleIdentifier(id) {
112
- const segments = id.split('.');
113
- return (
114
- segments.length > 1 &&
115
- segments.every((s) => /^[a-z][a-z0-9]*$/i.test(s) && !JAVA_KEYWORDS.has(s))
116
- );
117
- }
118
-
119
- /**
120
- * `com.<scope>.<name>`, for an app given no `--bundleIdentifier`, where prebuild would otherwise
121
- * make it `com.anonymous.<name>`. The scope is left out when it cannot be made a segment.
122
- *
123
- * @param {string} name the app's name, without a scope
124
- * @param {string | undefined} scope the workspace's npm scope, `@acme`
125
- */
126
- function bundleIdentifier(name, scope) {
127
- const clean = (text) => text.toLowerCase().replace(/[^a-z0-9]/g, '');
128
- const valid = (segment) => /^[a-z]/.test(segment) && !JAVA_KEYWORDS.has(segment);
129
- const org = clean(scope ?? '');
130
- const app = clean(name);
131
- return ['com', ...(valid(org) ? [org] : []), valid(app) ? app : `app${app}`].join('.');
132
- }
133
-
134
- /**
135
- * The template's `app.json`, named for this app, without the template's icons: they are the
136
- * template's branding, and Expo draws its own default until `icon` is set.
137
- *
138
- * @param {string} name the project name, which is also the Expo slug
139
- * @param {string} [id] the iOS bundle identifier and Android package, by default one from `name`
140
- */
141
- function appJson(name, id) {
142
- const slug = name.replace(/^@[^/]+\//, '');
143
- const bundle = id ?? bundleIdentifier(slug, name.match(/^@[^/]+/)?.[0]);
144
- const expo = {
145
- name: slug,
146
- slug,
147
- version: '1.0.0',
148
- // Not left to Expo, which adds `web` whenever `react-dom` resolves, and @nx/react puts one there.
149
- platforms: ['ios', 'android'],
150
- orientation: 'portrait',
151
- userInterfaceStyle: 'dark',
152
- ios: { supportsTablet: true, bundleIdentifier: bundle },
153
- android: { package: bundle, predictiveBackGestureEnabled: false },
154
- scheme: slug.replace(/[^a-z0-9]/gi, '').toLowerCase(),
155
- // The template's: Expo otherwise guesses a router root from src/app and says so on every start.
156
- extra: { router: { root: 'src/app' } },
157
- plugins: ['@ng-native/metro'],
158
- };
159
- return JSON.stringify({ expo }, null, 2) + '\n';
160
- }
161
-
162
70
  const METRO_CONFIG = `const { withNxMetro } = require('@nx/expo');
163
71
  const { getDefaultConfig } = require('expo/metro-config');
164
72
  const { withAngularNative } = require('@ng-native/metro/config.cjs');
@@ -226,32 +134,6 @@ function vitestConfig(withPaths) {
226
134
  .replace('plugins: [ngNative()],', 'plugins: [nxViteTsPaths(), ngNative()],');
227
135
  }
228
136
 
229
- /**
230
- * The dependencies an integrated workspace's app lists in its own `package.json`, at the ranges
231
- * the root installs, though nothing installs from it.
232
- *
233
- * All of them, because Expo's autolinking links the native modules the app's `package.json` names
234
- * and no others: without `react-native-safe-area-context` here, Android crashed on RNCSafeAreaView.
235
- * And `expo prebuild`, which `expo run:ios` starts with, adds `expo`, `react` or `react-native` if
236
- * it does not find them and then offers to install them into the app's directory, which would put a
237
- * second copy of React Native beside the root's.
238
- *
239
- * @param {{ dependencies?: Record<string, string>, devDependencies?: Record<string, string> }} root
240
- */
241
- function prebuildPins(root) {
242
- const installed = { ...root.devDependencies, ...root.dependencies };
243
- return Object.fromEntries(
244
- Object.keys(dependencies).map((pkg) => [pkg, installed[pkg] ?? dependencies[pkg]]),
245
- );
246
- }
247
-
248
- /**
249
- * Where what a workspace already has can be older than what a new app is given: `@ng-native/testing`
250
- * installs Vitest 5 but its plugin runs on 4, which `ng new` 22.1 and the Nx preset still start on.
251
- * The range here is that package's `vitest` peer, and a test holds the two together.
252
- */
253
- const accepted = { vitest: '^4.0.8 || ^5.0.0' };
254
-
255
137
  /**
256
138
  * The ranges a workspace package's `package.json` lists: the root's own where everything it can
257
139
  * resolve to is a version Angular Native accepts, so that pnpm does not install a second Vitest
@@ -276,49 +158,15 @@ function reuseRootRanges(wanted, root) {
276
158
  );
277
159
  }
278
160
 
279
- /**
280
- * Why an existing dependency would stop this app installing or running, as a sentence each.
281
- *
282
- * Only ranges already in the manifest are judged, and only a range that cannot overlap the one
283
- * wanted is a conflict: `~6.0.2` and `~6.0.3` resolve to the same TypeScript. A missing package is
284
- * added at the version above. Nothing is rewritten, because moving a workspace's Angular or Vitest
285
- * is an upgrade of every project in it, and that belongs to `nx migrate`, not to a generator.
286
- *
287
- * @param {{ dependencies?: Record<string, string>, devDependencies?: Record<string, string> }} manifest
288
- * @returns {string[]}
289
- */
290
- function conflicts(manifest) {
291
- const existing = { ...manifest.dependencies, ...manifest.devDependencies };
292
- const problems = [];
293
- for (const [name, installed] of Object.entries({ ...dependencies, ...devDependencies })) {
294
- const range = existing[name];
295
- const wanted = accepted[name] ?? installed;
296
- if (!range || name.startsWith('@ng-native/')) continue;
297
- if (semver.validRange(range) && !semver.intersects(range, wanted)) {
298
- problems.push(
299
- `${name} is ${range} here, and Angular Native needs ${wanted}. ` +
300
- `npm will refuse the install until it is moved.`,
301
- );
302
- }
303
- }
304
- return problems;
305
- }
306
-
307
161
  module.exports = {
308
- dependencies,
309
- devDependencies,
162
+ ...shared,
310
163
  SOURCE_FILES,
311
164
  sourceFile,
312
165
  agentsFile,
313
- appJson,
314
- bundleIdentifier,
315
- isBundleIdentifier,
316
166
  METRO_CONFIG,
167
+ TYPECHECK,
317
168
  tsconfig,
318
169
  vitestConfig,
319
- prebuildPins,
320
170
  reuseRootRanges,
321
171
  expoCompanions,
322
- conflicts,
323
- accepted,
324
172
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ng-native/nx",
3
- "version": "0.2.0",
4
- "description": "Nx generators for Angular Native: nx add, and an Expo app project whose targets run it.",
3
+ "version": "0.3.0",
4
+ "description": "Nx generators for Angular Native: nx add, an Expo app project whose targets run it, and native libraries and components.",
5
5
  "keywords": [
6
6
  "angular",
7
7
  "react-native",
@@ -17,7 +17,27 @@
17
17
  ],
18
18
  "type": "module",
19
19
  "generators": "./generators.json",
20
+ "nx-migrations": {
21
+ "migrations": "./migrations.json",
22
+ "packageGroup": [
23
+ "@ng-native/components",
24
+ "@ng-native/device",
25
+ "@ng-native/expo",
26
+ "@ng-native/fabric",
27
+ "@ng-native/icons",
28
+ "@ng-native/metro",
29
+ "@ng-native/migrate",
30
+ "@ng-native/nx",
31
+ "@ng-native/platform",
32
+ "@ng-native/router",
33
+ "@ng-native/schematics",
34
+ "@ng-native/tailwind",
35
+ "@ng-native/testing",
36
+ "@ng-native/web"
37
+ ]
38
+ },
20
39
  "dependencies": {
40
+ "@ng-native/migrate": "0.3.0",
21
41
  "@nx/devkit": "^23.0.0",
22
42
  "minimatch": "^10.0.0",
23
43
  "semver": "^7.7.0"
@@ -26,9 +46,11 @@
26
46
  "nx": "^23.0.0"
27
47
  },
28
48
  "devDependencies": {
29
- "@types/semver": "^7.7.0"
49
+ "@types/semver": "^7.7.0",
50
+ "typescript": "~6.0.3"
30
51
  },
31
52
  "nx": {
53
+ "projectType": "library",
32
54
  "tags": [
33
55
  "scope:nx",
34
56
  "layer:build"
@@ -47,6 +69,7 @@
47
69
  "files": [
48
70
  "*.cjs",
49
71
  "generators.json",
72
+ "migrations.json",
50
73
  "*/*.cjs",
51
74
  "*/*.json",
52
75
  "files"
@@ -56,6 +79,6 @@
56
79
  },
57
80
  "scripts": {
58
81
  "typecheck": "tsc -p tsconfig.json --noEmit",
59
- "test": "node --test \"*.test.ts\" \"{init,application}/*.test.ts\""
82
+ "test": "node --test \"*.test.ts\" \"{init,application,sync,library,component,migrations,tailwind}/*.test.ts\""
60
83
  }
61
84
  }