@ng-native/nx 0.18.0 → 0.18.2
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/application/index.cjs +3 -4
- package/generators.json +5 -0
- package/library/index.cjs +2 -3
- package/migrations.json +6 -1
- package/native-app.cjs +16 -4
- package/nativescript/index.cjs +126 -0
- package/nativescript/schema.json +28 -0
- package/package.json +4 -3
package/application/index.cjs
CHANGED
|
@@ -29,7 +29,7 @@ const {
|
|
|
29
29
|
addDependenciesToPackageJson,
|
|
30
30
|
} = require('@nx/devkit');
|
|
31
31
|
const native = require('../native-app.cjs');
|
|
32
|
-
const { init
|
|
32
|
+
const { init } = require('../init/index.cjs');
|
|
33
33
|
const { usesWorkspaces, includeInWorkspaces } = require('./workspaces.cjs');
|
|
34
34
|
const { asSaved } = require('../save-exact.cjs');
|
|
35
35
|
const { registerSyncGenerator } = require('../sync/index.cjs');
|
|
@@ -268,12 +268,11 @@ async function application(tree, options) {
|
|
|
268
268
|
true,
|
|
269
269
|
);
|
|
270
270
|
}
|
|
271
|
-
// `
|
|
271
|
+
// `tsconfigPaths()`, which the app's Vitest config uses to reach the workspace's libraries.
|
|
272
272
|
// Added now rather than only when present, because a library generated later is the ordinary
|
|
273
273
|
// case and nothing would come back to add it then.
|
|
274
274
|
if (hasPathAliases(tree, workspaces)) {
|
|
275
|
-
|
|
276
|
-
addDependenciesToPackageJson(tree, {}, vite, 'package.json', true);
|
|
275
|
+
addDependenciesToPackageJson(tree, {}, native.vitestPathsDependencies, 'package.json', true);
|
|
277
276
|
}
|
|
278
277
|
await writeFiles(tree, resolved);
|
|
279
278
|
addProjectConfiguration(tree, projectName, {
|
package/generators.json
CHANGED
|
@@ -35,6 +35,11 @@
|
|
|
35
35
|
"factory": "./component/index.cjs#component",
|
|
36
36
|
"schema": "./component/schema.json",
|
|
37
37
|
"description": "A component for an Angular Native app or library, with native elements and a test that runs in Node."
|
|
38
|
+
},
|
|
39
|
+
"nativescript": {
|
|
40
|
+
"factory": "./nativescript/index.cjs#nativescript",
|
|
41
|
+
"schema": "./nativescript/schema.json",
|
|
42
|
+
"description": "Sets up @ng-native/nativescript in an Angular Native app: the packages, the config plugin, the iOS types and provideNativeScript()."
|
|
38
43
|
}
|
|
39
44
|
}
|
|
40
45
|
}
|
package/library/index.cjs
CHANGED
|
@@ -328,10 +328,9 @@ async function library(tree, options) {
|
|
|
328
328
|
});
|
|
329
329
|
|
|
330
330
|
await addImports(tree, directory, angular ? {} : typecheckDependencies);
|
|
331
|
-
// `
|
|
331
|
+
// `tsconfigPaths()`, which the Vitest config uses to reach the workspace's other libraries.
|
|
332
332
|
if (aliases) {
|
|
333
|
-
|
|
334
|
-
addDependenciesToPackageJson(tree, {}, vite, 'package.json', true);
|
|
333
|
+
addDependenciesToPackageJson(tree, {}, native.vitestPathsDependencies, 'package.json', true);
|
|
335
334
|
}
|
|
336
335
|
|
|
337
336
|
if (!options.skipFormat) await formatFiles(tree);
|
package/migrations.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"generators": {
|
|
3
3
|
"sync-app-versions": {
|
|
4
|
-
"version": "0.18.
|
|
4
|
+
"version": "0.18.2",
|
|
5
5
|
"description": "Move the @ng-native packages each project's own package.json lists to the new version.",
|
|
6
6
|
"implementation": "./migrations/run.cjs#sync-app-versions"
|
|
7
7
|
},
|
|
@@ -44,6 +44,11 @@
|
|
|
44
44
|
"version": "0.17.2",
|
|
45
45
|
"description": "Keep what watchConditions returns in each app's entry point and stop it as the app is destroyed.",
|
|
46
46
|
"implementation": "./migrations/run.cjs#stop-watching-conditions"
|
|
47
|
+
},
|
|
48
|
+
"vitest-tsconfig-paths": {
|
|
49
|
+
"version": "0.18.1",
|
|
50
|
+
"description": "Resolve the workspace's path aliases in Nx Vitest configs with vite-tsconfig-paths, as nxViteTsPaths does nothing from Nx 24.",
|
|
51
|
+
"implementation": "./migrations/run.cjs#vitest-tsconfig-paths"
|
|
47
52
|
}
|
|
48
53
|
}
|
|
49
54
|
}
|
package/native-app.cjs
CHANGED
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
* import a library at all: Metro reports `Cannot resolve @org/ui`.
|
|
14
14
|
* - `tsconfig.json` also extends the workspace's `tsconfig.base.json` when there is one, which is
|
|
15
15
|
* where those aliases live, and puts back the Expo settings the workspace's base overrides.
|
|
16
|
-
* - `vitest.config.mts` adds `
|
|
17
|
-
* aliases, which Vitest does not read from tsconfig either.
|
|
16
|
+
* - `vitest.config.mts` adds `vite-tsconfig-paths` when the workspace has path aliases, for the
|
|
17
|
+
* same aliases, which Vitest does not read from tsconfig either. It is what Nx 24 writes in its
|
|
18
|
+
* own Vite configs: `nxViteTsPaths` from `@nx/vite` is an inert stub there.
|
|
18
19
|
*
|
|
19
20
|
* What does not depend on Nx, the dependencies, `app.json` and bundle identifier among them, is
|
|
20
21
|
* `@ng-native/migrate/native-app.cjs`, which `@ng-native/schematics` builds its apps from too.
|
|
@@ -153,12 +154,22 @@ function vitestConfig(withPaths) {
|
|
|
153
154
|
return template
|
|
154
155
|
.replace(
|
|
155
156
|
"import { defineConfig } from 'vitest/config';",
|
|
156
|
-
"import
|
|
157
|
+
"import tsconfigPaths from 'vite-tsconfig-paths';\n" +
|
|
157
158
|
"import { defineConfig } from 'vitest/config';",
|
|
158
159
|
)
|
|
159
|
-
.replace('plugins: [ngNative()],', 'plugins: [
|
|
160
|
+
.replace('plugins: [ngNative()],', 'plugins: [tsconfigPaths(), ngNative()],');
|
|
160
161
|
}
|
|
161
162
|
|
|
163
|
+
/**
|
|
164
|
+
* What `vitestConfig(true)` imports, at the range Nx 24 adds for its own Vite configs, and Vite at
|
|
165
|
+
* the range `@ng-native/testing` peers on. Both peer on Vite optionally, so npm installs it for
|
|
166
|
+
* neither, and an integrated workspace from the `angular-monorepo` preset may have none at its root.
|
|
167
|
+
*/
|
|
168
|
+
const vitestPathsDependencies = {
|
|
169
|
+
'vite-tsconfig-paths': '^5.1.4',
|
|
170
|
+
vite: '^6.0.0 || ^7.0.0 || ^8.0.0',
|
|
171
|
+
};
|
|
172
|
+
|
|
162
173
|
/**
|
|
163
174
|
* The ranges a workspace package's `package.json` lists: the root's own where everything it can
|
|
164
175
|
* resolve to is a version Angular Native accepts, so that pnpm does not install a second Vitest
|
|
@@ -195,6 +206,7 @@ module.exports = {
|
|
|
195
206
|
tsconfig,
|
|
196
207
|
typecheckTsconfig,
|
|
197
208
|
vitestConfig,
|
|
209
|
+
vitestPathsDependencies,
|
|
198
210
|
reuseRootRanges,
|
|
199
211
|
expoCompanions,
|
|
200
212
|
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nx g @ng-native/nx:nativescript mobile`: NativeScript's iOS and Android APIs in an Angular
|
|
3
|
+
* Native app, through `@ng-native/nativescript`.
|
|
4
|
+
*
|
|
5
|
+
* An app needs the packages, `@ng-native/nativescript` among its config plugins (which links the
|
|
6
|
+
* runtime and its metadata into the native build), the iOS and Android SDKs' types, and `provideNativeScript()`
|
|
7
|
+
* among the providers `mount` is given. Metro supplies the Babel config: see `@ng-native/metro`'s
|
|
8
|
+
* `nativescript-babel.cjs`.
|
|
9
|
+
*
|
|
10
|
+
* It only adds, so running it again changes nothing. A file it cannot follow is left alone, with a
|
|
11
|
+
* warning saying what to add by hand.
|
|
12
|
+
*/
|
|
13
|
+
const {
|
|
14
|
+
addDependenciesToPackageJson,
|
|
15
|
+
formatFiles,
|
|
16
|
+
getProjects,
|
|
17
|
+
installPackagesTask,
|
|
18
|
+
joinPathFragments,
|
|
19
|
+
logger,
|
|
20
|
+
readJson,
|
|
21
|
+
} = require('@nx/devkit');
|
|
22
|
+
const native = require('../native-app.cjs');
|
|
23
|
+
const { usesWorkspaces } = require('../application/workspaces.cjs');
|
|
24
|
+
|
|
25
|
+
// The iOS SDK's types ship with the runtime; Android's are a package of their own.
|
|
26
|
+
const TYPES =
|
|
27
|
+
'/// <reference types="@nativescript/react-native/types/ios" />\n' +
|
|
28
|
+
'/// <reference types="@nativescript/types-android" />\n';
|
|
29
|
+
const PROVIDER = 'provideNativeScript()';
|
|
30
|
+
|
|
31
|
+
/** The `react-native-worklets` each Expo SDK bundles, by its major; the template's SDK otherwise. */
|
|
32
|
+
const WORKLETS = { 57: '0.10.1', 58: '0.13.0' };
|
|
33
|
+
const worklets = (expo) => WORKLETS[/\d+/.exec(expo ?? '')?.[0]] ?? WORKLETS[58];
|
|
34
|
+
|
|
35
|
+
function byHand(file, what) {
|
|
36
|
+
logger.warn(`Could not update ${file}: ${what}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function addPlugin(tree, root) {
|
|
40
|
+
const file = joinPathFragments(root, 'app.json');
|
|
41
|
+
const text = tree.read(file, 'utf-8');
|
|
42
|
+
if (text === null) return byHand(file, 'it does not exist.');
|
|
43
|
+
const config = JSON.parse(text);
|
|
44
|
+
const expo = (config.expo ??= {});
|
|
45
|
+
const plugins = (expo.plugins ??= []);
|
|
46
|
+
const named = (plugin) => (Array.isArray(plugin) ? plugin[0] : plugin);
|
|
47
|
+
if (plugins.some((plugin) => named(plugin) === '@ng-native/nativescript')) return;
|
|
48
|
+
plugins.push('@ng-native/nativescript');
|
|
49
|
+
tree.write(file, `${JSON.stringify(config, null, 2)}\n`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Where the `mount(...)` call's parentheses close, counting brackets; -1 if they never do. */
|
|
53
|
+
function callEnd(source, open) {
|
|
54
|
+
let depth = 0;
|
|
55
|
+
for (let at = open; at < source.length; at++) {
|
|
56
|
+
if ('([{'.includes(source[at])) depth++;
|
|
57
|
+
else if (')]}'.includes(source[at]) && --depth === 0) return at;
|
|
58
|
+
}
|
|
59
|
+
return -1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const IMPORTED =
|
|
63
|
+
/\bimport\s*\{[^}]*\bprovideNativeScript\b[^}]*\}\s*from\s*['"]@ng-native\/nativescript['"]/;
|
|
64
|
+
|
|
65
|
+
function addProvider(tree, root) {
|
|
66
|
+
const file = joinPathFragments(root, 'src/main.ts');
|
|
67
|
+
const main = tree.read(file, 'utf-8');
|
|
68
|
+
if (main === null) return byHand(file, 'it does not exist.');
|
|
69
|
+
if (main.includes(PROVIDER)) return;
|
|
70
|
+
const imports = [...main.matchAll(/^import .+;$/gm)];
|
|
71
|
+
const options = /(\bmount\([^\n]*\{\n)([ \t]*)/.exec(main);
|
|
72
|
+
const open = options ? options.index + options[0].indexOf('(') : -1;
|
|
73
|
+
const end = options ? callEnd(main, open) : -1;
|
|
74
|
+
if (!imports.length || end < 0) {
|
|
75
|
+
return byHand(
|
|
76
|
+
file,
|
|
77
|
+
`import { provideNativeScript } from '@ng-native/nativescript' and add ${PROVIDER} to the ` +
|
|
78
|
+
'providers mount is given.',
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
// Only a providers list inside the call: one elsewhere in the file is not the app's.
|
|
82
|
+
const call = main.slice(open, end);
|
|
83
|
+
const listed = /(\bproviders:\s*\[)/.exec(call);
|
|
84
|
+
// A second providers key would replace the app's own, so one that is not a list is left alone.
|
|
85
|
+
if (!listed && /\bproviders\s*[:,}]/.test(call)) {
|
|
86
|
+
return byHand(file, `add ${PROVIDER} to the providers mount is given.`);
|
|
87
|
+
}
|
|
88
|
+
const edited = listed
|
|
89
|
+
? call.replace(listed[0], `${listed[1]}${PROVIDER}, `)
|
|
90
|
+
: call.replace(
|
|
91
|
+
options[0].slice(options[0].indexOf('(')),
|
|
92
|
+
(found) => `${found}${options[2]}providers: [${PROVIDER}],\n${options[2]}`,
|
|
93
|
+
);
|
|
94
|
+
const updated = main.slice(0, open) + edited + main.slice(end);
|
|
95
|
+
if (IMPORTED.test(updated)) return tree.write(file, updated);
|
|
96
|
+
const last = imports.at(-1);
|
|
97
|
+
const at = updated.indexOf(last[0]) + last[0].length;
|
|
98
|
+
const imported = "\nimport { provideNativeScript } from '@ng-native/nativescript';";
|
|
99
|
+
tree.write(file, updated.slice(0, at) + imported + updated.slice(at));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function nativescript(tree, options) {
|
|
103
|
+
const app = getProjects(tree).get(options.project);
|
|
104
|
+
if (!app) throw new Error(`The workspace has no project called "${options.project}".`);
|
|
105
|
+
addPlugin(tree, app.root);
|
|
106
|
+
addProvider(tree, app.root);
|
|
107
|
+
const types = joinPathFragments(app.root, 'src/nativescript.d.ts');
|
|
108
|
+
if (!tree.exists(types)) tree.write(types, TYPES);
|
|
109
|
+
|
|
110
|
+
const own = joinPathFragments(app.root, 'package.json');
|
|
111
|
+
const manifest = usesWorkspaces(tree) && tree.exists(own) ? own : 'package.json';
|
|
112
|
+
const install = addDependenciesToPackageJson(
|
|
113
|
+
tree,
|
|
114
|
+
{
|
|
115
|
+
'@ng-native/nativescript': native.dependencies['@ng-native/components'],
|
|
116
|
+
'@nativescript/react-native': '^9.1.2',
|
|
117
|
+
'react-native-worklets': worklets(readJson(tree, manifest).dependencies?.expo),
|
|
118
|
+
},
|
|
119
|
+
{ '@nativescript/types-android': '^9.1.1' },
|
|
120
|
+
manifest,
|
|
121
|
+
);
|
|
122
|
+
if (!options.skipFormat) await formatFiles(tree);
|
|
123
|
+
return options.skipInstall ? () => {} : () => (install(), installPackagesTask(tree));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
module.exports = { nativescript, default: nativescript };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/schema",
|
|
3
|
+
"$id": "NgNativeNxNativeScript",
|
|
4
|
+
"title": "NativeScript in an Angular Native app",
|
|
5
|
+
"description": "Sets up @ng-native/nativescript in an Angular Native app: the packages, the config plugin, the iOS types and provideNativeScript().",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"project": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "The Angular Native app.",
|
|
11
|
+
"$default": { "$source": "argv", "index": 0 },
|
|
12
|
+
"x-prompt": "Which app should NativeScript be set up in?",
|
|
13
|
+
"x-dropdown": "projects"
|
|
14
|
+
},
|
|
15
|
+
"skipInstall": {
|
|
16
|
+
"type": "boolean",
|
|
17
|
+
"description": "Write the files without installing.",
|
|
18
|
+
"default": false
|
|
19
|
+
},
|
|
20
|
+
"skipFormat": {
|
|
21
|
+
"type": "boolean",
|
|
22
|
+
"description": "Leave the generated files unformatted.",
|
|
23
|
+
"default": false,
|
|
24
|
+
"x-priority": "internal"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"required": ["project"]
|
|
28
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ng-native/nx",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.2",
|
|
4
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",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"@ng-native/icons",
|
|
30
30
|
"@ng-native/metro",
|
|
31
31
|
"@ng-native/migrate",
|
|
32
|
+
"@ng-native/nativescript",
|
|
32
33
|
"@ng-native/nx",
|
|
33
34
|
"@ng-native/platform",
|
|
34
35
|
"@ng-native/router",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
]
|
|
41
42
|
},
|
|
42
43
|
"dependencies": {
|
|
43
|
-
"@ng-native/migrate": "0.18.
|
|
44
|
+
"@ng-native/migrate": "0.18.2",
|
|
44
45
|
"@nx/devkit": "^23.0.0 || ^24.0.0",
|
|
45
46
|
"minimatch": "^10.0.0",
|
|
46
47
|
"semver": "^7.7.0"
|
|
@@ -85,6 +86,6 @@
|
|
|
85
86
|
},
|
|
86
87
|
"scripts": {
|
|
87
88
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
88
|
-
"test": "node --test \"*.test.ts\" \"{init,application,sync,library,component,migrations,tailwind}/*.test.ts\""
|
|
89
|
+
"test": "node --test \"*.test.ts\" \"{init,application,sync,library,component,migrations,tailwind,nativescript}/*.test.ts\""
|
|
89
90
|
}
|
|
90
91
|
}
|