deeplink-parity 0.6.3 → 0.6.4
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 +18 -4
- package/dist/routes/extract.js +6 -0
- package/dist/routes/init.js +11 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,8 @@ npx deeplink-parity .
|
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
```
|
|
16
|
-
deeplink-parity · 3 domain(s) checked
|
|
16
|
+
deeplink-parity v0.6.4 · 3 domain(s) checked
|
|
17
|
+
routes: deeplink-parity.yml (iOS 74 · Android 73)
|
|
17
18
|
|
|
18
19
|
ERROR links.example.com
|
|
19
20
|
AASA responded with 404
|
|
@@ -24,7 +25,11 @@ WARN promo.example.com
|
|
|
24
25
|
Declared on iOS but not on Android
|
|
25
26
|
The same link opens the app on iOS and the browser on Android
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
WARN route-gap
|
|
29
|
+
/events is in the Android route table but not iOS's
|
|
30
|
+
A /events link navigates on Android and goes nowhere on iOS.
|
|
31
|
+
|
|
32
|
+
1 error, 2 warn, 0 info
|
|
28
33
|
```
|
|
29
34
|
|
|
30
35
|
<br>
|
|
@@ -57,6 +62,9 @@ Findings show up as annotations on the run. Add `sha256` to include the Android
|
|
|
57
62
|
key in the check, and `fail-on: never` to report without failing while an existing backlog
|
|
58
63
|
is cleared.
|
|
59
64
|
|
|
65
|
+
Domains are checked with zero setup. To also compare the **screens behind the links**,
|
|
66
|
+
run `npx deeplink-parity init` once — see [Route parity](#route-parity).
|
|
67
|
+
|
|
60
68
|
<br>
|
|
61
69
|
|
|
62
70
|
## Contents
|
|
@@ -111,6 +119,7 @@ No configuration file. Domains are discovered from your app, then the matching w
|
|
|
111
119
|
**Warnings** — one platform works and the other does not
|
|
112
120
|
|
|
113
121
|
- **A domain is declared on iOS but not Android, or the reverse**
|
|
122
|
+
- **A route is in one platform's route table but not the other's** (with [route parity](#route-parity) set up)
|
|
114
123
|
- An `https` intent-filter has no `autoVerify`
|
|
115
124
|
- A manifest host reference could not be resolved
|
|
116
125
|
|
|
@@ -135,6 +144,7 @@ npx deeplink-parity init [path...] # interactive setup for route com
|
|
|
135
144
|
--output <file> Also write the JSON result to a file
|
|
136
145
|
--format github GitHub Actions annotations (auto-detected on Actions)
|
|
137
146
|
--yes init only: accept the top suggestion without prompting
|
|
147
|
+
-v, --version Print the version
|
|
138
148
|
-h, --help Show this message
|
|
139
149
|
```
|
|
140
150
|
|
|
@@ -274,6 +284,8 @@ The **check never writes to the repositories it scans** — it reads files and G
|
|
|
274
284
|
public well-known files per domain, nothing else. `init` writes exactly one file,
|
|
275
285
|
`deeplink-parity.yml`, in your working directory, after printing its content and asking.
|
|
276
286
|
|
|
287
|
+
<br>
|
|
288
|
+
|
|
277
289
|
## Native, Flutter and React Native
|
|
278
290
|
|
|
279
291
|
Whatever the app is written in, deep links are declared in the same two native files and
|
|
@@ -316,7 +328,9 @@ read as browser registration rather than deep links.
|
|
|
316
328
|
|
|
317
329
|
- **Deferred deep links are out of scope.** Install-then-open attribution is decided at runtime by your attribution SDK's servers. No static check can confirm it, and reporting a pass would be worse than saying nothing.
|
|
318
330
|
- **It does not prove path equivalence.** iOS and Android use different path-matching engines. Differing path sets are reported as `info` with both sides shown, for a human to judge — not asserted as a bug.
|
|
319
|
-
- **It does not run your app.** Route
|
|
331
|
+
- **It does not run your app.** Route parity compares the declared tables; whether a
|
|
332
|
+
handler behind a route actually works, or a dynamically-matched route resolves, only
|
|
333
|
+
shows up on a device.
|
|
320
334
|
|
|
321
335
|
<br>
|
|
322
336
|
|
|
@@ -330,7 +344,7 @@ npm run typecheck
|
|
|
330
344
|
|
|
331
345
|
`fixtures/` holds synthetic iOS and Android projects covering literal hosts, chained
|
|
332
346
|
`@string` references resolved through gradle `resValue` and `.properties`, flavor-specific
|
|
333
|
-
values, and
|
|
347
|
+
values, unresolvable references, and route tables in both platforms' shapes.
|
|
334
348
|
|
|
335
349
|
<br>
|
|
336
350
|
|
package/dist/routes/extract.js
CHANGED
|
@@ -33,9 +33,11 @@ export async function extractRoutes(platform, config, roots) {
|
|
|
33
33
|
const findings = [];
|
|
34
34
|
const files = [];
|
|
35
35
|
const paths = new Set();
|
|
36
|
+
let unresolved = false;
|
|
36
37
|
for (const file of config.files) {
|
|
37
38
|
const hits = await resolveInRoots(file, roots);
|
|
38
39
|
if (hits.length === 0) {
|
|
40
|
+
unresolved = true;
|
|
39
41
|
findings.push({
|
|
40
42
|
severity: 'error',
|
|
41
43
|
rule: 'routes-file-missing',
|
|
@@ -45,6 +47,7 @@ export async function extractRoutes(platform, config, roots) {
|
|
|
45
47
|
continue;
|
|
46
48
|
}
|
|
47
49
|
if (hits.length > 1) {
|
|
50
|
+
unresolved = true;
|
|
48
51
|
findings.push({
|
|
49
52
|
severity: 'error',
|
|
50
53
|
rule: 'routes-file-ambiguous',
|
|
@@ -59,6 +62,9 @@ export async function extractRoutes(platform, config, roots) {
|
|
|
59
62
|
paths.add(m[1] ?? m[0]);
|
|
60
63
|
}
|
|
61
64
|
}
|
|
65
|
+
// a table missing any of its files is incomplete; diffing it would manufacture gaps
|
|
66
|
+
if (unresolved)
|
|
67
|
+
return { findings };
|
|
62
68
|
if (files.length > 0 && paths.size === 0) {
|
|
63
69
|
// matching nothing is a broken config, never a clean pass
|
|
64
70
|
findings.push({
|
package/dist/routes/init.js
CHANGED
|
@@ -35,7 +35,17 @@ async function pickFiles(rl, platform, candidates, yes) {
|
|
|
35
35
|
return [];
|
|
36
36
|
if (answer === 'm') {
|
|
37
37
|
const manual = (await rl.question('path: ')).trim();
|
|
38
|
-
|
|
38
|
+
if (!manual)
|
|
39
|
+
return [];
|
|
40
|
+
// a mistyped path written into the config would only surface at check time
|
|
41
|
+
try {
|
|
42
|
+
await access(manual);
|
|
43
|
+
return [manual];
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
console.log(` Not found: ${manual}`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
39
49
|
}
|
|
40
50
|
const tokens = answer.split(/[,\s]+/);
|
|
41
51
|
const indexes = tokens.map((t) => Number.parseInt(t, 10));
|
package/package.json
CHANGED