deeplink-doctor 1.0.1
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/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +188 -0
- package/dist/checks/calculateExitCode.d.ts +4 -0
- package/dist/checks/calculateExitCode.js +4 -0
- package/dist/checks/calculateExitCode.js.map +1 -0
- package/dist/checks/checkAasaAppIds.d.ts +2 -0
- package/dist/checks/checkAasaAppIds.js +15 -0
- package/dist/checks/checkAasaAppIds.js.map +1 -0
- package/dist/checks/checkAppIdentifiers.d.ts +2 -0
- package/dist/checks/checkAppIdentifiers.js +13 -0
- package/dist/checks/checkAppIdentifiers.js.map +1 -0
- package/dist/checks/checkAssetlinks.d.ts +2 -0
- package/dist/checks/checkAssetlinks.js +21 -0
- package/dist/checks/checkAssetlinks.js.map +1 -0
- package/dist/checks/checkAssociatedDomains.d.ts +3 -0
- package/dist/checks/checkAssociatedDomains.js +7 -0
- package/dist/checks/checkAssociatedDomains.js.map +1 -0
- package/dist/checks/checkAutoVerifyHosts.d.ts +2 -0
- package/dist/checks/checkAutoVerifyHosts.js +6 -0
- package/dist/checks/checkAutoVerifyHosts.js.map +1 -0
- package/dist/checks/checkConfig.d.ts +2 -0
- package/dist/checks/checkConfig.js +11 -0
- package/dist/checks/checkConfig.js.map +1 -0
- package/dist/checks/checkDeadLinks.d.ts +2 -0
- package/dist/checks/checkDeadLinks.js +9 -0
- package/dist/checks/checkDeadLinks.js.map +1 -0
- package/dist/checks/checkRemote.d.ts +2 -0
- package/dist/checks/checkRemote.js +4 -0
- package/dist/checks/checkRemote.js.map +1 -0
- package/dist/checks/checkScheme.d.ts +3 -0
- package/dist/checks/checkScheme.js +13 -0
- package/dist/checks/checkScheme.js.map +1 -0
- package/dist/checks/checkUnreachableRoutes.d.ts +2 -0
- package/dist/checks/checkUnreachableRoutes.js +11 -0
- package/dist/checks/checkUnreachableRoutes.js.map +1 -0
- package/dist/checks/runChecks.d.ts +2 -0
- package/dist/checks/runChecks.js +8 -0
- package/dist/checks/runChecks.js.map +1 -0
- package/dist/checks/targetMatchesRoute.d.ts +2 -0
- package/dist/checks/targetMatchesRoute.js +14 -0
- package/dist/checks/targetMatchesRoute.js.map +1 -0
- package/dist/commands/check.d.ts +21 -0
- package/dist/commands/check.js +42 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/config/findingExplanations.d.ts +2 -0
- package/dist/config/findingExplanations.js +19 -0
- package/dist/config/findingExplanations.js.map +1 -0
- package/dist/config/findingSeverities.d.ts +2 -0
- package/dist/config/findingSeverities.js +16 -0
- package/dist/config/findingSeverities.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/generateFinding.d.ts +5 -0
- package/dist/lib/generateFinding.js +8 -0
- package/dist/lib/generateFinding.js.map +1 -0
- package/dist/links/extractDomains.d.ts +2 -0
- package/dist/links/extractDomains.js +11 -0
- package/dist/links/extractDomains.js.map +1 -0
- package/dist/links/extractLinkConfig.d.ts +2 -0
- package/dist/links/extractLinkConfig.js +15 -0
- package/dist/links/extractLinkConfig.js.map +1 -0
- package/dist/links/extractLinkTargets.d.ts +2 -0
- package/dist/links/extractLinkTargets.js +25 -0
- package/dist/links/extractLinkTargets.js.map +1 -0
- package/dist/parsers/expoConfig.d.ts +4 -0
- package/dist/parsers/expoConfig.js +16 -0
- package/dist/parsers/expoConfig.js.map +1 -0
- package/dist/parsers/routes.d.ts +2 -0
- package/dist/parsers/routes.js +23 -0
- package/dist/parsers/routes.js.map +1 -0
- package/dist/report/human.d.ts +3 -0
- package/dist/report/human.js +72 -0
- package/dist/report/human.js.map +1 -0
- package/dist/report/json.d.ts +3 -0
- package/dist/report/json.js +19 -0
- package/dist/report/json.js.map +1 -0
- package/dist/routes/parseRoutePath.d.ts +3 -0
- package/dist/routes/parseRoutePath.js +53 -0
- package/dist/routes/parseRoutePath.js.map +1 -0
- package/dist/routes/routeHandlesPath.d.ts +2 -0
- package/dist/routes/routeHandlesPath.js +12 -0
- package/dist/routes/routeHandlesPath.js.map +1 -0
- package/dist/routes/routeHandlesPrefix.d.ts +2 -0
- package/dist/routes/routeHandlesPrefix.js +15 -0
- package/dist/routes/routeHandlesPrefix.js.map +1 -0
- package/dist/sources/aasa.d.ts +2 -0
- package/dist/sources/aasa.js +16 -0
- package/dist/sources/aasa.js.map +1 -0
- package/dist/sources/assetlinks.d.ts +2 -0
- package/dist/sources/assetlinks.js +13 -0
- package/dist/sources/assetlinks.js.map +1 -0
- package/dist/sources/httpFetcher.d.ts +2 -0
- package/dist/sources/httpFetcher.js +5 -0
- package/dist/sources/httpFetcher.js.map +1 -0
- package/dist/sources/loadAssociations.d.ts +2 -0
- package/dist/sources/loadAssociations.js +49 -0
- package/dist/sources/loadAssociations.js.map +1 -0
- package/dist/suppressions/applySuppressions.d.ts +5 -0
- package/dist/suppressions/applySuppressions.js +38 -0
- package/dist/suppressions/applySuppressions.js.map +1 -0
- package/dist/suppressions/parseSuppressionConfig.d.ts +2 -0
- package/dist/suppressions/parseSuppressionConfig.js +28 -0
- package/dist/suppressions/parseSuppressionConfig.js.map +1 -0
- package/dist/suppressions/readSuppressionConfig.d.ts +5 -0
- package/dist/suppressions/readSuppressionConfig.js +32 -0
- package/dist/suppressions/readSuppressionConfig.js.map +1 -0
- package/dist/types.d.ts +92 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/package.json +83 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const FINDING_SEVERITIES = {
|
|
2
|
+
DL001: 'error',
|
|
3
|
+
DL002: 'warn',
|
|
4
|
+
DL003: 'error',
|
|
5
|
+
DL101: 'error',
|
|
6
|
+
DL102: 'error',
|
|
7
|
+
DL103: 'error',
|
|
8
|
+
DL104: 'warn',
|
|
9
|
+
DL201: 'error',
|
|
10
|
+
DL202: 'error',
|
|
11
|
+
DL203: 'error',
|
|
12
|
+
DL204: 'warn',
|
|
13
|
+
DL901: 'warn',
|
|
14
|
+
DL902: 'warn',
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=findingSeverities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findingSeverities.js","sourceRoot":"","sources":["../../src/config/findingSeverities.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAA6C;IAC1E,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,MAAM;CACd,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { runCheck } from './commands/check.js';
|
|
6
|
+
import { readLinkConfig } from './parsers/expoConfig.js';
|
|
7
|
+
import { parseRoutes } from './parsers/routes.js';
|
|
8
|
+
import * as human from './report/human.js';
|
|
9
|
+
import * as json from './report/json.js';
|
|
10
|
+
import { loadAssociations } from './sources/loadAssociations.js';
|
|
11
|
+
import { readSuppressionConfig } from './suppressions/readSuppressionConfig.js';
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
const pkg = require('../package.json');
|
|
14
|
+
const program = new Command();
|
|
15
|
+
program.name('deeplink-doctor').description(pkg.description).version(pkg.version, '-v, --version');
|
|
16
|
+
program
|
|
17
|
+
.command('routes')
|
|
18
|
+
.description('Print the route tree parsed from the app/ directory')
|
|
19
|
+
.option('--json', 'Emit machine-readable JSON; suppress human output')
|
|
20
|
+
.action((options) => {
|
|
21
|
+
try {
|
|
22
|
+
const routes = parseRoutes(process.cwd());
|
|
23
|
+
if (options.json) {
|
|
24
|
+
console.log(json.renderRoutes(routes));
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.log(human.renderRoutes(routes));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
32
|
+
process.exitCode = 2;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
program
|
|
36
|
+
.command('check', { isDefault: true })
|
|
37
|
+
.description('Reconcile routes against native deep-link config and report mismatches')
|
|
38
|
+
.option('--json', 'Emit machine-readable JSON; suppress human output')
|
|
39
|
+
.option('--strict', 'Promote warnings to failures (exit non-zero on any finding)')
|
|
40
|
+
.option('--remote', 'Also fetch and check hosted association files (AASA, assetlinks) — makes network requests')
|
|
41
|
+
.option('--domain <host>', 'Override the domain(s) probed by --remote')
|
|
42
|
+
.option('--config <path>', 'Path to a deeplink.config.json (defaults to the project root)')
|
|
43
|
+
.option('--silent', 'Hide warnings (errors only); ignored when --strict is set')
|
|
44
|
+
.option('--explain', 'Append a long-form explanation to each finding')
|
|
45
|
+
.action(async (options) => {
|
|
46
|
+
if (options.domain && !options.remote) {
|
|
47
|
+
console.warn(chalk.yellow('Warning: --domain has no effect without --remote; no association files will be fetched'));
|
|
48
|
+
}
|
|
49
|
+
const { report, exitCode } = await runCheck(process.cwd(), { readRoutes: parseRoutes, readLinkConfig, readSuppressionConfig, loadAssociations }, options);
|
|
50
|
+
if (exitCode === 2) {
|
|
51
|
+
console.error(report);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
console.log(report);
|
|
55
|
+
}
|
|
56
|
+
process.exitCode = exitCode;
|
|
57
|
+
});
|
|
58
|
+
program.parse(process.argv);
|
|
59
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateFinding.js","sourceRoot":"","sources":["../../src/lib/generateFinding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGpE,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,IAAiB,EACjB,OAAe,EACf,QAA6C,EAAE,EACtC,EAAE,CAAC,CAAC;IACb,IAAI;IACJ,QAAQ,EAAE,kBAAkB,CAAC,IAAI,CAAC;IAClC,OAAO;IACP,GAAG,KAAK;CACT,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const extractDomains = (config) => {
|
|
2
|
+
const associatedDomains = config?.ios?.associatedDomains ?? [];
|
|
3
|
+
const intentFilters = config?.android?.intentFilters ?? [];
|
|
4
|
+
const iosDomains = associatedDomains
|
|
5
|
+
.filter((domain) => domain.startsWith('applinks:'))
|
|
6
|
+
.map((domain) => domain.slice(domain.indexOf(':') + 1, domain.indexOf('?') !== -1 ? domain.indexOf('?') : undefined));
|
|
7
|
+
const androidDomains = intentFilters.flatMap(({ data }) => data.flatMap((d) => (d?.host ? [d.host] : [])));
|
|
8
|
+
const domains = new Set([...iosDomains, ...androidDomains]);
|
|
9
|
+
return [...domains];
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=extractDomains.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractDomains.js","sourceRoot":"","sources":["../../src/links/extractDomains.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAkB,EAAY,EAAE;IAC7D,MAAM,iBAAiB,GAAG,MAAM,EAAE,GAAG,EAAE,iBAAiB,IAAI,EAAE,CAAC;IAC/D,MAAM,aAAa,GAAG,MAAM,EAAE,OAAO,EAAE,aAAa,IAAI,EAAE,CAAC;IAE3D,MAAM,UAAU,GAAG,iBAAiB;SACjC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;SAClD,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CACd,MAAM,CAAC,KAAK,CACV,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EACvB,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAC7D,CACF,CAAC;IAEJ,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CACxD,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAC/C,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,UAAU,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC;IAE5D,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AACtB,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const extractLinkConfig = (config) => {
|
|
2
|
+
const normalizedSchemes = typeof config.scheme === 'string' ? [config.scheme] : config.scheme;
|
|
3
|
+
return {
|
|
4
|
+
schemes: normalizedSchemes ?? [],
|
|
5
|
+
ios: {
|
|
6
|
+
...(config.ios?.bundleIdentifier ? { bundleIdentifier: config.ios.bundleIdentifier } : {}),
|
|
7
|
+
associatedDomains: config.ios?.associatedDomains ?? [],
|
|
8
|
+
},
|
|
9
|
+
android: {
|
|
10
|
+
...(config.android?.package ? { package: config.android.package } : {}),
|
|
11
|
+
intentFilters: config.android?.intentFilters ?? [],
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=extractLinkConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractLinkConfig.js","sourceRoot":"","sources":["../../src/links/extractLinkConfig.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAA0B,EAAc,EAAE;IAC1E,MAAM,iBAAiB,GAAG,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;IAE9F,OAAO;QACL,OAAO,EAAE,iBAAiB,IAAI,EAAE;QAChC,GAAG,EAAE;YACH,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1F,iBAAiB,EAAE,MAAM,CAAC,GAAG,EAAE,iBAAiB,IAAI,EAAE;SACvD;QACD,OAAO,EAAE;YACP,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,aAAa,EAAE,MAAM,CAAC,OAAO,EAAE,aAAa,IAAI,EAAE;SACnD;KACF,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const calculateKind = (pathPrefix, pathPattern) => {
|
|
2
|
+
if (pathPrefix) {
|
|
3
|
+
return 'prefix';
|
|
4
|
+
}
|
|
5
|
+
if (pathPattern) {
|
|
6
|
+
return 'pattern';
|
|
7
|
+
}
|
|
8
|
+
return 'exact';
|
|
9
|
+
};
|
|
10
|
+
export const extractLinkTargets = (config) => {
|
|
11
|
+
const intentFilters = config.android.intentFilters;
|
|
12
|
+
return intentFilters.flatMap(({ data }) => data.map(({ scheme, host, path, pathPrefix, pathPattern }) => {
|
|
13
|
+
const raw = path ?? pathPrefix ?? pathPattern ?? '/';
|
|
14
|
+
const kind = calculateKind(pathPrefix, pathPattern);
|
|
15
|
+
const segments = raw.split('/').filter(Boolean);
|
|
16
|
+
return {
|
|
17
|
+
raw,
|
|
18
|
+
kind,
|
|
19
|
+
segments,
|
|
20
|
+
...(host !== undefined && { host }),
|
|
21
|
+
...(scheme !== undefined && { scheme }),
|
|
22
|
+
};
|
|
23
|
+
}));
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=extractLinkTargets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractLinkTargets.js","sourceRoot":"","sources":["../../src/links/extractLinkTargets.ts"],"names":[],"mappings":"AAEA,MAAM,aAAa,GAAG,CAAC,UAAmB,EAAE,WAAoB,EAAE,EAAE;IAClE,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAAkB,EAAgB,EAAE;IACrE,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;IAEnD,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CACxC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,EAAE;QAC3D,MAAM,GAAG,GAAG,IAAI,IAAI,UAAU,IAAI,WAAW,IAAI,GAAG,CAAC;QACrD,MAAM,IAAI,GAAG,aAAa,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEhD,OAAO;YACL,GAAG;YACH,IAAI;YACJ,QAAQ;YACR,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,CAAC;YACnC,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC;SACxC,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { extractLinkConfig } from '../links/extractLinkConfig.js';
|
|
3
|
+
const runExpoConfig = (projectRoot) => execFileSync('npx', ['expo', 'config', '--json'], { cwd: projectRoot, encoding: 'utf8' });
|
|
4
|
+
export const readLinkConfig = (projectRoot, run = runExpoConfig) => {
|
|
5
|
+
try {
|
|
6
|
+
const runOutput = run(projectRoot);
|
|
7
|
+
const parsed = JSON.parse(runOutput);
|
|
8
|
+
return extractLinkConfig(parsed);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
12
|
+
throw new Error(`Failed to read Expo config via \`npx expo config --json\` in "${projectRoot}": ${reason}. ` +
|
|
13
|
+
`Ensure this is an Expo project with expo installed.`, { cause: error });
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=expoConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expoConfig.js","sourceRoot":"","sources":["../../src/parsers/expoConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAKlE,MAAM,aAAa,GAAiB,CAAC,WAAW,EAAE,EAAE,CAClD,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;AAE5F,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,WAAmB,EACnB,MAAoB,aAAa,EACrB,EAAE;IACd,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAErC,OAAO,iBAAiB,CAAC,MAA4B,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,MAAM,IAAI,KAAK,CACb,iEAAiE,WAAW,MAAM,MAAM,IAAI;YAC1F,qDAAqD,EACvD,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;IACJ,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
2
|
+
import { join, relative, sep } from 'node:path';
|
|
3
|
+
import { parseRoutePath } from '../routes/parseRoutePath.js';
|
|
4
|
+
const ROUTE_FILE = /(?<!\.(d|test|stories|spec))\.(js|ts|jsx|tsx)$/;
|
|
5
|
+
const resolveAppDir = (projectRoot) => {
|
|
6
|
+
const appPath = join(projectRoot, 'app');
|
|
7
|
+
if (existsSync(appPath)) {
|
|
8
|
+
return appPath;
|
|
9
|
+
}
|
|
10
|
+
const srcAppPath = join(projectRoot, 'src', 'app');
|
|
11
|
+
if (existsSync(srcAppPath)) {
|
|
12
|
+
return srcAppPath;
|
|
13
|
+
}
|
|
14
|
+
throw new Error(`No expo-router app directory found in "${projectRoot}" (looked for ./app and ./src/app).`);
|
|
15
|
+
};
|
|
16
|
+
export const parseRoutes = (projectRoot) => {
|
|
17
|
+
const appDir = resolveAppDir(projectRoot);
|
|
18
|
+
return readdirSync(appDir, { recursive: true, withFileTypes: true })
|
|
19
|
+
.filter((entry) => entry.isFile() && ROUTE_FILE.test(entry.name))
|
|
20
|
+
.map(({ name, parentPath }) => parseRoutePath(relative(appDir, join(parentPath, name)).split(sep).join('/')))
|
|
21
|
+
.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/parsers/routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAG7D,MAAM,UAAU,GAAG,gDAAgD,CAAC;AAEpE,MAAM,aAAa,GAAG,CAAC,WAAmB,EAAU,EAAE;IACpD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IACzC,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACnD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,MAAM,IAAI,KAAK,CACb,0CAA0C,WAAW,qCAAqC,CAC3F,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,WAAmB,EAAc,EAAE;IAC7D,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAE1C,OAAO,WAAW,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SACjE,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SAChE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,CAC5B,cAAc,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAC9E;SACA,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC1D,CAAC,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { FINDING_EXPLANATIONS } from '../config/findingExplanations.js';
|
|
3
|
+
import { isLinkableRoute } from '../routes/parseRoutePath.js';
|
|
4
|
+
// Greedy word-wrap into lines no wider than `width`, without mutation.
|
|
5
|
+
const wrap = (text, width) => text.split(' ').reduce((lines, word) => {
|
|
6
|
+
const last = lines.at(-1);
|
|
7
|
+
if (last !== undefined && `${last} ${word}`.length <= width) {
|
|
8
|
+
return [...lines.slice(0, -1), `${last} ${word}`];
|
|
9
|
+
}
|
|
10
|
+
return [...lines, word];
|
|
11
|
+
}, []);
|
|
12
|
+
const tagsFor = (route) => {
|
|
13
|
+
const tags = [
|
|
14
|
+
[route.segments.some((s) => s.kind === 'dynamic'), 'dynamic'],
|
|
15
|
+
[route.segments.some((s) => s.kind === 'catchall'), 'catchall'],
|
|
16
|
+
[route.inGroup, 'group'],
|
|
17
|
+
[route.isLayout, 'layout'],
|
|
18
|
+
[route.isSpecial, 'special'],
|
|
19
|
+
[route.isApi, 'api'],
|
|
20
|
+
];
|
|
21
|
+
return tags.filter(([active]) => active).map(([, label]) => label);
|
|
22
|
+
};
|
|
23
|
+
export const renderRoutes = (routes) => {
|
|
24
|
+
if (routes.length === 0) {
|
|
25
|
+
return chalk.yellow('No routes found in app/.');
|
|
26
|
+
}
|
|
27
|
+
const width = Math.max(...routes.map((route) => route.pathname.length));
|
|
28
|
+
const renderRoute = (route) => {
|
|
29
|
+
const tags = tagsFor(route);
|
|
30
|
+
const suffix = tags.length > 0 ? chalk.dim(` [${tags.join(', ')}]`) : '';
|
|
31
|
+
return ` ${route.pathname.padEnd(width)} ${chalk.dim(route.filePath)}${suffix}`;
|
|
32
|
+
};
|
|
33
|
+
const linkable = routes.filter(isLinkableRoute);
|
|
34
|
+
const other = routes.filter((route) => !isLinkableRoute(route));
|
|
35
|
+
const sections = [chalk.bold(`Routes (${routes.length})`)];
|
|
36
|
+
if (linkable.length > 0) {
|
|
37
|
+
sections.push(linkable.map(renderRoute).join('\n'));
|
|
38
|
+
}
|
|
39
|
+
if (other.length > 0) {
|
|
40
|
+
const heading = chalk.dim('Not link targets (layouts, special files, API routes):');
|
|
41
|
+
sections.push(`${heading}\n${other.map(renderRoute).join('\n')}`);
|
|
42
|
+
}
|
|
43
|
+
return sections.join('\n\n');
|
|
44
|
+
};
|
|
45
|
+
const plural = (count, word) => `${word}${count === 1 ? '' : 's'}`;
|
|
46
|
+
const SEVERITY_LABEL = {
|
|
47
|
+
error: chalk.red('error'),
|
|
48
|
+
warn: chalk.yellow('warn'),
|
|
49
|
+
};
|
|
50
|
+
const renderFinding = (finding, explain) => {
|
|
51
|
+
const line = ` ${chalk.dim(finding.code)} ${SEVERITY_LABEL[finding.severity]} ${finding.message}`;
|
|
52
|
+
if (!explain) {
|
|
53
|
+
return line;
|
|
54
|
+
}
|
|
55
|
+
const explanation = wrap(FINDING_EXPLANATIONS[finding.code], 76)
|
|
56
|
+
.map((wrapped) => chalk.dim(` ${wrapped}`))
|
|
57
|
+
.join('\n');
|
|
58
|
+
return `${line}\n${explanation}`;
|
|
59
|
+
};
|
|
60
|
+
export const renderFindings = (findings, suppressed = [], explain = false) => {
|
|
61
|
+
const suppressedNote = suppressed.length > 0 ? chalk.dim(` (${suppressed.length} suppressed)`) : '';
|
|
62
|
+
if (findings.length === 0) {
|
|
63
|
+
return chalk.green('✓ No deep-link issues found.') + suppressedNote;
|
|
64
|
+
}
|
|
65
|
+
const body = findings.map((finding) => renderFinding(finding, explain));
|
|
66
|
+
const errors = findings.filter((finding) => finding.severity === 'error').length;
|
|
67
|
+
const warnings = findings.filter((finding) => finding.severity === 'warn').length;
|
|
68
|
+
const summary = chalk.bold(`${findings.length} ${plural(findings.length, 'issue')} ` +
|
|
69
|
+
`(${errors} ${plural(errors, 'error')}, ${warnings} ${plural(warnings, 'warning')})`) + suppressedNote;
|
|
70
|
+
return [body.join(explain ? '\n\n' : '\n'), '', summary].join('\n');
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=human.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"human.js","sourceRoot":"","sources":["../../src/report/human.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isLinkableRoute } from '../routes/parseRoutePath.js';
|
|
2
|
+
export const renderRoutes = (routes) => JSON.stringify({
|
|
3
|
+
summary: {
|
|
4
|
+
total: routes.length,
|
|
5
|
+
linkable: routes.filter(isLinkableRoute).length,
|
|
6
|
+
},
|
|
7
|
+
routes,
|
|
8
|
+
}, null, 2);
|
|
9
|
+
export const renderFindings = (findings, suppressed = []) => JSON.stringify({
|
|
10
|
+
summary: {
|
|
11
|
+
total: findings.length,
|
|
12
|
+
errors: findings.filter((finding) => finding.severity === 'error').length,
|
|
13
|
+
warnings: findings.filter((finding) => finding.severity === 'warn').length,
|
|
14
|
+
suppressed: suppressed.length,
|
|
15
|
+
},
|
|
16
|
+
findings,
|
|
17
|
+
suppressed,
|
|
18
|
+
}, null, 2);
|
|
19
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/report/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAG9D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAkB,EAAU,EAAE,CACzD,IAAI,CAAC,SAAS,CACZ;IACE,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC,MAAM;QACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,MAAM;KAChD;IACD,MAAM;CACP,EACD,IAAI,EACJ,CAAC,CACF,CAAC;AAEJ,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAmB,EAAE,aAAwB,EAAE,EAAU,EAAE,CACxF,IAAI,CAAC,SAAS,CACZ;IACE,OAAO,EAAE;QACP,KAAK,EAAE,QAAQ,CAAC,MAAM;QACtB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM;QACzE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM;QAC1E,UAAU,EAAE,UAAU,CAAC,MAAM;KAC9B;IACD,QAAQ;IACR,UAAU;CACX,EACD,IAAI,EACJ,CAAC,CACF,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const INDEX_REGEX = /\/?index\.(js|ts|jsx|tsx)$/;
|
|
2
|
+
const LAYOUT_REGEX = /\/?_layout\.(js|ts|jsx|tsx)$/;
|
|
3
|
+
const API_REGEX = /\+api\.(js|ts)$/;
|
|
4
|
+
const SPECIAL_REGEX = /^\+(not-found|html|native-intent)\.(js|ts|jsx|tsx)$/;
|
|
5
|
+
const GROUP_REGEX = /\/?\([^()]+\)/g;
|
|
6
|
+
const stripFileType = (path) => path.replace(/\.(js|ts|jsx|tsx)$/, '');
|
|
7
|
+
const isGroupSegment = (segment) => segment.startsWith('(') && segment.endsWith(')');
|
|
8
|
+
const renderSegment = (segment) => {
|
|
9
|
+
if (segment.kind === 'dynamic') {
|
|
10
|
+
return `[${segment.value}]`;
|
|
11
|
+
}
|
|
12
|
+
if (segment.kind === 'catchall') {
|
|
13
|
+
return `[...${segment.value}]`;
|
|
14
|
+
}
|
|
15
|
+
return segment.value;
|
|
16
|
+
};
|
|
17
|
+
const formatSegment = (segmentPath) => {
|
|
18
|
+
const segment = stripFileType(segmentPath);
|
|
19
|
+
if (segment.startsWith('[') && segment.endsWith(']')) {
|
|
20
|
+
const isCatchall = segment.startsWith('[...');
|
|
21
|
+
const segmentName = segment.replace(/^\[(\.\.\.)?([^\]]+)\]$/, '$2');
|
|
22
|
+
return {
|
|
23
|
+
kind: isCatchall ? 'catchall' : 'dynamic',
|
|
24
|
+
value: segmentName,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return { kind: 'static', value: segment };
|
|
28
|
+
};
|
|
29
|
+
export const parseRoutePath = (path) => {
|
|
30
|
+
const segments = path.split('/');
|
|
31
|
+
const basename = segments.at(-1) ?? '';
|
|
32
|
+
const group = path.match(GROUP_REGEX);
|
|
33
|
+
const isLayout = LAYOUT_REGEX.test(basename);
|
|
34
|
+
const isApi = API_REGEX.test(basename);
|
|
35
|
+
const isSpecial = SPECIAL_REGEX.test(basename);
|
|
36
|
+
const formattedSegments = segments
|
|
37
|
+
.filter((s) => !s.match(INDEX_REGEX) && !s.match(LAYOUT_REGEX) && !isGroupSegment(s))
|
|
38
|
+
.map(formatSegment);
|
|
39
|
+
const pathname = `/${formattedSegments.map(renderSegment).join('/')}`;
|
|
40
|
+
return {
|
|
41
|
+
pathname,
|
|
42
|
+
filePath: path,
|
|
43
|
+
segments: formattedSegments,
|
|
44
|
+
isLayout,
|
|
45
|
+
inGroup: group !== null,
|
|
46
|
+
isApi,
|
|
47
|
+
isSpecial,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export const isLinkableRoute = (pathData) => {
|
|
51
|
+
return !pathData.isLayout && !pathData.isApi && !pathData.isSpecial;
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=parseRoutePath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseRoutePath.js","sourceRoot":"","sources":["../../src/routes/parseRoutePath.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const routeHandlesPath = (route, pathSegments) => {
|
|
2
|
+
if (pathSegments.length < route.segments.length) {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
if (pathSegments.length > route.segments.length) {
|
|
6
|
+
const nonCatchAllSegments = route.segments.filter(({ kind }) => kind !== 'catchall');
|
|
7
|
+
return (route.segments.at(-1)?.kind === 'catchall' &&
|
|
8
|
+
nonCatchAllSegments.every((s, i) => s.kind === 'static' ? s.value === pathSegments[i] : s.kind === 'dynamic'));
|
|
9
|
+
}
|
|
10
|
+
return route.segments.every((segment, i) => segment.kind === 'static' ? segment.value === pathSegments[i] : true);
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=routeHandlesPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeHandlesPath.js","sourceRoot":"","sources":["../../src/routes/routeHandlesPath.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAe,EAAE,YAAsB,EAAW,EAAE;IACnF,IAAI,YAAY,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAChD,MAAM,mBAAmB,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;QACrF,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,UAAU;YAC1C,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACjC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CACzE,CACF,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CACzC,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CACrE,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const routeHandlesPrefix = (route, pathSegments) => {
|
|
2
|
+
if (pathSegments.length === 0) {
|
|
3
|
+
return true;
|
|
4
|
+
}
|
|
5
|
+
if (pathSegments.length < route.segments.length) {
|
|
6
|
+
return pathSegments.every((segment, i) => route.segments[i].kind === 'static' ? route.segments[i].value === segment : true);
|
|
7
|
+
}
|
|
8
|
+
if (pathSegments.length > route.segments.length) {
|
|
9
|
+
const nonCatchAllSegments = route.segments.filter(({ kind }) => kind !== 'catchall');
|
|
10
|
+
return (route.segments.at(-1)?.kind === 'catchall' &&
|
|
11
|
+
nonCatchAllSegments.every((s, i) => s.kind === 'static' ? s.value === pathSegments[i] : s.kind === 'dynamic'));
|
|
12
|
+
}
|
|
13
|
+
return route.segments.every((segment, i) => segment.kind === 'static' ? segment.value === pathSegments[i] : true);
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=routeHandlesPrefix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routeHandlesPrefix.js","sourceRoot":"","sources":["../../src/routes/routeHandlesPrefix.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAe,EAAE,YAAsB,EAAW,EAAE;IACrF,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAChD,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CACvC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CACjF,CAAC;IACJ,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QAChD,MAAM,mBAAmB,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;QACrF,OAAO,CACL,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,UAAU;YAC1C,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACjC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CACzE,CACF,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CACzC,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CACrE,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const parseAasa = (body) => {
|
|
2
|
+
const data = JSON.parse(body);
|
|
3
|
+
const details = data?.applinks?.details;
|
|
4
|
+
if (!Array.isArray(details)) {
|
|
5
|
+
return { appIDs: [] };
|
|
6
|
+
}
|
|
7
|
+
const appIDs = details.flatMap((detail) => {
|
|
8
|
+
const { appID, appIDs } = (detail ?? {});
|
|
9
|
+
if (Array.isArray(appIDs)) {
|
|
10
|
+
return appIDs.filter((id) => typeof id === 'string');
|
|
11
|
+
}
|
|
12
|
+
return typeof appID === 'string' ? [appID] : [];
|
|
13
|
+
});
|
|
14
|
+
return { appIDs };
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=aasa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aasa.js","sourceRoot":"","sources":["../../src/sources/aasa.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAa,EAAE;IACnD,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEvC,MAAM,OAAO,GAAI,IAA6C,EAAE,QAAQ,EAAE,OAAO,CAAC;IAClF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACxB,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,MAAe,EAAE,EAAE;QACjD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,CAA0C,CAAC;QAClF,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC;QACrE,CAAC;QACD,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const parseAssetlinks = (body) => {
|
|
2
|
+
const data = JSON.parse(body);
|
|
3
|
+
if (!Array.isArray(data)) {
|
|
4
|
+
return [];
|
|
5
|
+
}
|
|
6
|
+
return data
|
|
7
|
+
.map((statement) => ({
|
|
8
|
+
packageName: statement?.target?.package_name,
|
|
9
|
+
fingerprints: statement?.target?.sha256_cert_fingerprints ?? [],
|
|
10
|
+
}))
|
|
11
|
+
.filter((t) => !!t.packageName);
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=assetlinks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assetlinks.js","sourceRoot":"","sources":["../../src/sources/assetlinks.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAY,EAAoB,EAAE;IAChE,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEvC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,IAAI;SACR,GAAG,CAAC,CAAC,SAAuB,EAAE,EAAE,CAAC,CAAC;QACjC,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY;QAC5C,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,wBAAwB,IAAI,EAAE;KAChE,CAAC,CAAC;SACF,MAAM,CAAC,CAAC,CAAC,EAAuB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;AACzD,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpFetcher.js","sourceRoot":"","sources":["../../src/sources/httpFetcher.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAY,KAAK,EAAE,GAAG,EAAE,EAAE;IAChD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;AACpF,CAAC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { generateFinding } from '../lib/generateFinding.js';
|
|
2
|
+
import { parseAasa } from './aasa.js';
|
|
3
|
+
import { parseAssetlinks } from './assetlinks.js';
|
|
4
|
+
import { httpFetcher } from './httpFetcher.js';
|
|
5
|
+
const createAasaUrl = (domain) => `https://${domain}/.well-known/apple-app-site-association`;
|
|
6
|
+
const createAssetlinksUrl = (domain) => `https://${domain}/.well-known/assetlinks.json`;
|
|
7
|
+
const associationFinding = (url, reason) => generateFinding('DL201', `${url} ${reason}`, { target: url });
|
|
8
|
+
const fetchFile = async (fetcher, url) => {
|
|
9
|
+
try {
|
|
10
|
+
const { status, redirected, body } = await fetcher(url);
|
|
11
|
+
if (redirected) {
|
|
12
|
+
return { body: null, finding: associationFinding(url, 'is served via a redirect') };
|
|
13
|
+
}
|
|
14
|
+
if (status < 200 || status >= 300) {
|
|
15
|
+
return { body: null, finding: associationFinding(url, `responded with status ${status}`) };
|
|
16
|
+
}
|
|
17
|
+
return { body, finding: null };
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return { body: null, finding: associationFinding(url, 'is unreachable') };
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const parseFile = (fetched, url, parse) => {
|
|
24
|
+
if (fetched.body === null) {
|
|
25
|
+
return { value: null, findings: [fetched.finding] };
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
return { value: parse(fetched.body), findings: [] };
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return { value: null, findings: [associationFinding(url, 'did not return valid JSON')] };
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
export const loadAssociations = async (domain, fetcher = httpFetcher) => {
|
|
35
|
+
const aasaUrl = createAasaUrl(domain);
|
|
36
|
+
const assetlinksUrl = createAssetlinksUrl(domain);
|
|
37
|
+
const [aasaFetch, assetlinksFetch] = await Promise.all([
|
|
38
|
+
fetchFile(fetcher, aasaUrl),
|
|
39
|
+
fetchFile(fetcher, assetlinksUrl),
|
|
40
|
+
]);
|
|
41
|
+
const aasa = parseFile(aasaFetch, aasaUrl, parseAasa);
|
|
42
|
+
const assetlinks = parseFile(assetlinksFetch, assetlinksUrl, parseAssetlinks);
|
|
43
|
+
return {
|
|
44
|
+
aasa: aasa.value ?? { appIDs: [] },
|
|
45
|
+
assetlinks: assetlinks.value ?? [],
|
|
46
|
+
findings: [...aasa.findings, ...assetlinks.findings],
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=loadAssociations.js.map
|