@ng-native/nx 0.18.1 → 0.19.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/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/migrations.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "generators": {
3
3
  "sync-app-versions": {
4
- "version": "0.18.1",
4
+ "version": "0.19.0",
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
  },
@@ -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.1",
3
+ "version": "0.19.0",
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",
@@ -26,9 +26,11 @@
26
26
  "@ng-native/eslint-plugin",
27
27
  "@ng-native/expo",
28
28
  "@ng-native/fabric",
29
+ "@ng-native/firebase-messaging",
29
30
  "@ng-native/icons",
30
31
  "@ng-native/metro",
31
32
  "@ng-native/migrate",
33
+ "@ng-native/nativescript",
32
34
  "@ng-native/nx",
33
35
  "@ng-native/platform",
34
36
  "@ng-native/router",
@@ -40,7 +42,7 @@
40
42
  ]
41
43
  },
42
44
  "dependencies": {
43
- "@ng-native/migrate": "0.18.1",
45
+ "@ng-native/migrate": "0.19.0",
44
46
  "@nx/devkit": "^23.0.0 || ^24.0.0",
45
47
  "minimatch": "^10.0.0",
46
48
  "semver": "^7.7.0"
@@ -85,6 +87,6 @@
85
87
  },
86
88
  "scripts": {
87
89
  "typecheck": "tsc -p tsconfig.json --noEmit",
88
- "test": "node --test \"*.test.ts\" \"{init,application,sync,library,component,migrations,tailwind}/*.test.ts\""
90
+ "test": "node --test \"*.test.ts\" \"{init,application,sync,library,component,migrations,tailwind,nativescript}/*.test.ts\""
89
91
  }
90
92
  }