deeplink-parity 0.6.0 → 0.6.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/dist/cli.js +24 -1
- package/dist/routes/candidates.js +2 -2
- package/dist/routes/init.js +29 -18
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { writeFile } from 'node:fs/promises';
|
|
2
|
+
import { stat, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { localSource, networkSource } from './fetch/wellKnown.js';
|
|
5
5
|
import { exitCodeFor, printReport } from './report/console.js';
|
|
@@ -86,12 +86,35 @@ function parseArgs(argv) {
|
|
|
86
86
|
format,
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* A mistyped path must fail loudly. Scanning a directory that does not exist would
|
|
91
|
+
* read exactly like an empty repository — "no candidates", "nothing declared" — and
|
|
92
|
+
* a wrong answer that looks like a clean one is the failure mode this tool exists
|
|
93
|
+
* to prevent.
|
|
94
|
+
*/
|
|
95
|
+
async function assertRootsExist(roots) {
|
|
96
|
+
for (const root of roots) {
|
|
97
|
+
let ok = false;
|
|
98
|
+
try {
|
|
99
|
+
ok = (await stat(root)).isDirectory();
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// fall through to the error below
|
|
103
|
+
}
|
|
104
|
+
if (!ok) {
|
|
105
|
+
console.error(`Not a directory: ${root}`);
|
|
106
|
+
console.error('Pass the path to each checkout, e.g. deeplink-parity ./app-ios ./app-android');
|
|
107
|
+
process.exit(2);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
89
111
|
async function main() {
|
|
90
112
|
const opts = parseArgs(process.argv);
|
|
91
113
|
if (opts.help) {
|
|
92
114
|
console.log(USAGE);
|
|
93
115
|
return;
|
|
94
116
|
}
|
|
117
|
+
await assertRootsExist(opts.roots);
|
|
95
118
|
if (opts.command === 'init') {
|
|
96
119
|
process.exit(await runInit(opts.roots, opts.yes));
|
|
97
120
|
}
|
|
@@ -53,8 +53,8 @@ const SHAPES = [
|
|
|
53
53
|
{ name: 'when/switch branch', pattern: String.raw `"(\/[^"\s]+)"\s*->` },
|
|
54
54
|
{ name: 'any path string', pattern: String.raw `"(\/[a-z0-9][a-z0-9\/_-]*)"` },
|
|
55
55
|
];
|
|
56
|
-
export async function suggestRegex(
|
|
57
|
-
const content = await readFile(
|
|
56
|
+
export async function suggestRegex(files) {
|
|
57
|
+
const content = (await Promise.all(files.map((f) => readFile(f, 'utf8')))).join('\n');
|
|
58
58
|
const suggestions = [];
|
|
59
59
|
for (const shape of SHAPES) {
|
|
60
60
|
const paths = [
|
package/dist/routes/init.js
CHANGED
|
@@ -13,32 +13,41 @@ function rootRelative(file, roots) {
|
|
|
13
13
|
}
|
|
14
14
|
return file;
|
|
15
15
|
}
|
|
16
|
-
async function
|
|
16
|
+
async function pickFiles(rl, platform, candidates, yes) {
|
|
17
17
|
const top = candidates.filter((c) => c.platform === platform).slice(0, 5);
|
|
18
18
|
if (top.length === 0) {
|
|
19
19
|
if (yes)
|
|
20
|
-
return
|
|
20
|
+
return [];
|
|
21
21
|
const manual = (await rl.question(`No ${platform} route-file candidates found. Enter a path, or leave blank to skip: `)).trim();
|
|
22
|
-
return manual
|
|
22
|
+
return manual ? [manual] : [];
|
|
23
23
|
}
|
|
24
24
|
if (yes)
|
|
25
|
-
return top[0].file;
|
|
25
|
+
return [top[0].file];
|
|
26
26
|
console.log(`\n${platform === 'ios' ? 'iOS' : 'Android'} route file candidates:`);
|
|
27
27
|
top.forEach((c, i) => console.log(` ${i + 1}. ${c.file} (${c.pathStrings} path strings)`));
|
|
28
28
|
console.log(` m. enter a path manually`);
|
|
29
29
|
console.log(` s. skip ${platform}`);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
console.log(` (several numbers select several files, e.g. "1 2")`);
|
|
31
|
+
// an answer that cannot be interpreted is asked again — never silently narrowed
|
|
32
|
+
for (;;) {
|
|
33
|
+
const answer = (await rl.question('> ')).trim().toLowerCase();
|
|
34
|
+
if (answer === 's' || answer === '')
|
|
35
|
+
return [];
|
|
36
|
+
if (answer === 'm') {
|
|
37
|
+
const manual = (await rl.question('path: ')).trim();
|
|
38
|
+
return manual ? [manual] : [];
|
|
39
|
+
}
|
|
40
|
+
const tokens = answer.split(/[,\s]+/);
|
|
41
|
+
const indexes = tokens.map((t) => Number.parseInt(t, 10));
|
|
42
|
+
const valid = indexes.length > 0 &&
|
|
43
|
+
indexes.every((n, i) => Number.isInteger(n) && String(n) === tokens[i] && n >= 1 && n <= top.length);
|
|
44
|
+
if (valid)
|
|
45
|
+
return [...new Set(indexes)].map((n) => top[n - 1].file);
|
|
46
|
+
console.log(` Could not read "${answer}" — numbers 1-${top.length}, "m" or "s".`);
|
|
36
47
|
}
|
|
37
|
-
const index = Number.parseInt(answer, 10);
|
|
38
|
-
return Number.isInteger(index) && index >= 1 && index <= top.length ? top[index - 1].file : undefined;
|
|
39
48
|
}
|
|
40
|
-
async function pickRegex(rl,
|
|
41
|
-
const suggestions = await suggestRegex(
|
|
49
|
+
async function pickRegex(rl, files, yes) {
|
|
50
|
+
const suggestions = await suggestRegex(files);
|
|
42
51
|
if (suggestions.length > 0) {
|
|
43
52
|
const best = suggestions[0];
|
|
44
53
|
const preview = best.paths.slice(0, PREVIEW).join(', ');
|
|
@@ -70,13 +79,15 @@ export async function runInit(roots, yes) {
|
|
|
70
79
|
try {
|
|
71
80
|
const picks = {};
|
|
72
81
|
for (const platform of ['ios', 'android']) {
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
82
|
+
const files = await pickFiles(rl, platform, candidates, yes);
|
|
83
|
+
if (files.length === 0)
|
|
75
84
|
continue;
|
|
76
|
-
const match = await pickRegex(rl,
|
|
85
|
+
const match = await pickRegex(rl, files, yes);
|
|
77
86
|
if (!match)
|
|
78
87
|
continue;
|
|
79
|
-
|
|
88
|
+
const relative = files.map((f) => rootRelative(f, roots));
|
|
89
|
+
picks[platform] =
|
|
90
|
+
relative.length === 1 ? { file: relative[0], match } : { files: relative, match };
|
|
80
91
|
}
|
|
81
92
|
if (!picks.ios && !picks.android) {
|
|
82
93
|
console.log('\nNothing selected — no config written.');
|
package/package.json
CHANGED