monkeypatchlist 0.0.0-stage → 0.1.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.
Files changed (221) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +61 -0
  3. package/README.md +183 -2
  4. package/catalog/catalog.json +552211 -0
  5. package/catalog/catalog.schema.json +787 -0
  6. package/catalog/changelog.json +3 -0
  7. package/dist/bin/monkeypatchlist.d.ts +2 -0
  8. package/dist/bin/monkeypatchlist.js +3 -0
  9. package/dist/catalog.d.ts +561 -0
  10. package/dist/catalog.js +58 -0
  11. package/dist/cli.d.ts +84 -0
  12. package/dist/cli.js +470 -0
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.js +1 -0
  15. package/dist/lockfile-input.d.ts +9 -0
  16. package/dist/lockfile-input.js +91 -0
  17. package/dist/packages/analysis/binding.d.ts +2 -0
  18. package/dist/packages/analysis/binding.js +5 -0
  19. package/dist/packages/analysis/index.d.ts +10 -0
  20. package/dist/packages/analysis/index.js +13 -0
  21. package/dist/packages/analysis/job.d.ts +33 -0
  22. package/dist/packages/analysis/job.js +85 -0
  23. package/dist/packages/analysis/lib/absence-tags.d.ts +34 -0
  24. package/dist/packages/analysis/lib/absence-tags.js +340 -0
  25. package/dist/packages/analysis/lib/ast.d.ts +28 -0
  26. package/dist/packages/analysis/lib/ast.js +64 -0
  27. package/dist/packages/analysis/lib/binding.d.ts +36 -0
  28. package/dist/packages/analysis/lib/binding.js +66 -0
  29. package/dist/packages/analysis/lib/budget.d.ts +80 -0
  30. package/dist/packages/analysis/lib/budget.js +31 -0
  31. package/dist/packages/analysis/lib/catch-arms.d.ts +19 -0
  32. package/dist/packages/analysis/lib/catch-arms.js +351 -0
  33. package/dist/packages/analysis/lib/chunk-loads.d.ts +160 -0
  34. package/dist/packages/analysis/lib/chunk-loads.js +882 -0
  35. package/dist/packages/analysis/lib/chunk-registry.d.ts +45 -0
  36. package/dist/packages/analysis/lib/chunk-registry.js +334 -0
  37. package/dist/packages/analysis/lib/code-routes.d.ts +52 -0
  38. package/dist/packages/analysis/lib/code-routes.js +921 -0
  39. package/dist/packages/analysis/lib/collisions.d.ts +22 -0
  40. package/dist/packages/analysis/lib/collisions.js +103 -0
  41. package/dist/packages/analysis/lib/definitions.d.ts +76 -0
  42. package/dist/packages/analysis/lib/definitions.js +782 -0
  43. package/dist/packages/analysis/lib/early-exits.d.ts +39 -0
  44. package/dist/packages/analysis/lib/early-exits.js +161 -0
  45. package/dist/packages/analysis/lib/effect.d.ts +138 -0
  46. package/dist/packages/analysis/lib/effect.js +800 -0
  47. package/dist/packages/analysis/lib/global-object.d.ts +581 -0
  48. package/dist/packages/analysis/lib/global-object.js +8240 -0
  49. package/dist/packages/analysis/lib/keys.d.ts +33 -0
  50. package/dist/packages/analysis/lib/keys.js +82 -0
  51. package/dist/packages/analysis/lib/line-starts.d.ts +41 -0
  52. package/dist/packages/analysis/lib/line-starts.js +79 -0
  53. package/dist/packages/analysis/lib/link-group.d.ts +51 -0
  54. package/dist/packages/analysis/lib/link-group.js +487 -0
  55. package/dist/packages/analysis/lib/module-links.d.ts +117 -0
  56. package/dist/packages/analysis/lib/module-links.js +1060 -0
  57. package/dist/packages/analysis/lib/nested-code.d.ts +38 -0
  58. package/dist/packages/analysis/lib/nested-code.js +200 -0
  59. package/dist/packages/analysis/lib/numeric.d.ts +16 -0
  60. package/dist/packages/analysis/lib/numeric.js +216 -0
  61. package/dist/packages/analysis/lib/once-flags.d.ts +12 -0
  62. package/dist/packages/analysis/lib/once-flags.js +190 -0
  63. package/dist/packages/analysis/lib/parameter-arguments.d.ts +12 -0
  64. package/dist/packages/analysis/lib/parameter-arguments.js +34 -0
  65. package/dist/packages/analysis/lib/parse.d.ts +10 -0
  66. package/dist/packages/analysis/lib/parse.js +39 -0
  67. package/dist/packages/analysis/lib/partial.d.ts +60 -0
  68. package/dist/packages/analysis/lib/partial.js +518 -0
  69. package/dist/packages/analysis/lib/print.d.ts +3 -0
  70. package/dist/packages/analysis/lib/print.js +150 -0
  71. package/dist/packages/analysis/lib/reachability.d.ts +137 -0
  72. package/dist/packages/analysis/lib/reachability.js +1295 -0
  73. package/dist/packages/analysis/lib/resolver.d.ts +13 -0
  74. package/dist/packages/analysis/lib/resolver.js +2886 -0
  75. package/dist/packages/analysis/lib/restores.d.ts +42 -0
  76. package/dist/packages/analysis/lib/restores.js +482 -0
  77. package/dist/packages/analysis/lib/rewritten-deletes.d.ts +6 -0
  78. package/dist/packages/analysis/lib/rewritten-deletes.js +142 -0
  79. package/dist/packages/analysis/lib/scope.d.ts +110 -0
  80. package/dist/packages/analysis/lib/scope.js +443 -0
  81. package/dist/packages/analysis/lib/script-loads.d.ts +56 -0
  82. package/dist/packages/analysis/lib/script-loads.js +359 -0
  83. package/dist/packages/analysis/lib/summaries.d.ts +177 -0
  84. package/dist/packages/analysis/lib/summaries.js +498 -0
  85. package/dist/packages/analysis/lib/types.d.ts +632 -0
  86. package/dist/packages/analysis/lib/types.js +128 -0
  87. package/dist/packages/analysis/lib/wrap.d.ts +34 -0
  88. package/dist/packages/analysis/lib/wrap.js +407 -0
  89. package/dist/packages/analysis/lib/writes.d.ts +358 -0
  90. package/dist/packages/analysis/lib/writes.js +1612 -0
  91. package/dist/packages/analysis/visit-order.d.ts +3 -0
  92. package/dist/packages/analysis/visit-order.js +23 -0
  93. package/dist/packages/attribution/index.d.ts +233 -0
  94. package/dist/packages/attribution/index.js +444 -0
  95. package/dist/packages/attribution/lib/containing-package.d.ts +76 -0
  96. package/dist/packages/attribution/lib/containing-package.js +304 -0
  97. package/dist/packages/attribution/lib/first-party.d.ts +37 -0
  98. package/dist/packages/attribution/lib/first-party.js +153 -0
  99. package/dist/packages/attribution/lib/lockfile-graph.d.ts +99 -0
  100. package/dist/packages/attribution/lib/lockfile-graph.js +158 -0
  101. package/dist/packages/attribution/lib/lockfile.d.ts +33 -0
  102. package/dist/packages/attribution/lib/lockfile.js +330 -0
  103. package/dist/packages/attribution/lib/path-rules.d.ts +29 -0
  104. package/dist/packages/attribution/lib/path-rules.js +84 -0
  105. package/dist/packages/attribution/lib/pnpm.d.ts +4 -0
  106. package/dist/packages/attribution/lib/pnpm.js +133 -0
  107. package/dist/packages/attribution/lib/remote-url.d.ts +7 -0
  108. package/dist/packages/attribution/lib/remote-url.js +24 -0
  109. package/dist/packages/attribution/lib/source-map.d.ts +51 -0
  110. package/dist/packages/attribution/lib/source-map.js +125 -0
  111. package/dist/packages/attribution/lib/yaml.d.ts +9 -0
  112. package/dist/packages/attribution/lib/yaml.js +277 -0
  113. package/dist/packages/attribution/lib/yarn.d.ts +7 -0
  114. package/dist/packages/attribution/lib/yarn.js +227 -0
  115. package/dist/packages/baseline/index.d.ts +45 -0
  116. package/dist/packages/baseline/index.js +41 -0
  117. package/dist/packages/baseline/lib/error.d.ts +15 -0
  118. package/dist/packages/baseline/lib/error.js +25 -0
  119. package/dist/packages/baseline/lib/format.d.ts +49 -0
  120. package/dist/packages/baseline/lib/format.js +22 -0
  121. package/dist/packages/baseline/lib/migrations.d.ts +19 -0
  122. package/dist/packages/baseline/lib/migrations.js +7 -0
  123. package/dist/packages/baseline/lib/previous.d.ts +23 -0
  124. package/dist/packages/baseline/lib/previous.js +64 -0
  125. package/dist/packages/baseline/lib/read.d.ts +39 -0
  126. package/dist/packages/baseline/lib/read.js +219 -0
  127. package/dist/packages/baseline/lib/report.d.ts +25 -0
  128. package/dist/packages/baseline/lib/report.js +104 -0
  129. package/dist/packages/baseline/lib/skew.d.ts +51 -0
  130. package/dist/packages/baseline/lib/skew.js +75 -0
  131. package/dist/packages/compare/index.d.ts +120 -0
  132. package/dist/packages/compare/index.js +274 -0
  133. package/dist/packages/compare/lib/catalog-notes.d.ts +73 -0
  134. package/dist/packages/compare/lib/catalog-notes.js +224 -0
  135. package/dist/packages/completeness/index.d.ts +246 -0
  136. package/dist/packages/completeness/index.js +249 -0
  137. package/dist/packages/confidence/index.d.ts +54 -0
  138. package/dist/packages/confidence/index.js +71 -0
  139. package/dist/packages/config/index.d.ts +107 -0
  140. package/dist/packages/config/index.js +95 -0
  141. package/dist/packages/config/lib/command-line.d.ts +23 -0
  142. package/dist/packages/config/lib/command-line.js +239 -0
  143. package/dist/packages/config/lib/config-file.d.ts +11 -0
  144. package/dist/packages/config/lib/config-file.js +119 -0
  145. package/dist/packages/config/lib/scan-config-id.d.ts +28 -0
  146. package/dist/packages/config/lib/scan-config-id.js +54 -0
  147. package/dist/packages/config/lib/schema.d.ts +2 -0
  148. package/dist/packages/config/lib/schema.js +31 -0
  149. package/dist/packages/config/lib/types.d.ts +64 -0
  150. package/dist/packages/config/lib/types.js +6 -0
  151. package/dist/packages/config/lib/urls.d.ts +6 -0
  152. package/dist/packages/config/lib/urls.js +9 -0
  153. package/dist/packages/discovery/index.d.ts +277 -0
  154. package/dist/packages/discovery/index.js +1950 -0
  155. package/dist/packages/discovery/lib/import-map.d.ts +68 -0
  156. package/dist/packages/discovery/lib/import-map.js +180 -0
  157. package/dist/packages/discovery/lib/requests.d.ts +58 -0
  158. package/dist/packages/discovery/lib/requests.js +591 -0
  159. package/dist/packages/discovery/lib/scopes.d.ts +6 -0
  160. package/dist/packages/discovery/lib/scopes.js +286 -0
  161. package/dist/packages/discovery/lib/source-maps.d.ts +56 -0
  162. package/dist/packages/discovery/lib/source-maps.js +209 -0
  163. package/dist/packages/discovery/lib/swept-code.d.ts +27 -0
  164. package/dist/packages/discovery/lib/swept-code.js +107 -0
  165. package/dist/packages/discovery/lib/syntax.d.ts +17 -0
  166. package/dist/packages/discovery/lib/syntax.js +39 -0
  167. package/dist/packages/findings/index.d.ts +106 -0
  168. package/dist/packages/findings/index.js +254 -0
  169. package/dist/packages/findings/lib/scope.d.ts +38 -0
  170. package/dist/packages/findings/lib/scope.js +110 -0
  171. package/dist/packages/parallel/index.d.ts +2 -0
  172. package/dist/packages/parallel/index.js +5 -0
  173. package/dist/packages/parallel/lib/protocol.d.ts +15 -0
  174. package/dist/packages/parallel/lib/protocol.js +2 -0
  175. package/dist/packages/parallel/lib/runner.d.ts +36 -0
  176. package/dist/packages/parallel/lib/runner.js +96 -0
  177. package/dist/packages/parallel/lib/schedule.d.ts +16 -0
  178. package/dist/packages/parallel/lib/schedule.js +52 -0
  179. package/dist/packages/parallel/lib/worker.d.ts +1 -0
  180. package/dist/packages/parallel/lib/worker.js +18 -0
  181. package/dist/packages/policy/index.d.ts +36 -0
  182. package/dist/packages/policy/index.js +22 -0
  183. package/dist/packages/report/explain.d.ts +26 -0
  184. package/dist/packages/report/explain.js +99 -0
  185. package/dist/packages/report/index.d.ts +210 -0
  186. package/dist/packages/report/index.js +388 -0
  187. package/dist/packages/report/terminal.d.ts +11 -0
  188. package/dist/packages/report/terminal.js +331 -0
  189. package/dist/packages/source-store/fixture.d.ts +22 -0
  190. package/dist/packages/source-store/fixture.js +58 -0
  191. package/dist/packages/source-store/index.d.ts +278 -0
  192. package/dist/packages/source-store/index.js +322 -0
  193. package/dist/packages/source-store/lib/addresses.d.ts +6 -0
  194. package/dist/packages/source-store/lib/addresses.js +91 -0
  195. package/dist/packages/source-store/lib/connection.d.ts +15 -0
  196. package/dist/packages/source-store/lib/connection.js +135 -0
  197. package/dist/packages/source-store/lib/content-types.d.ts +16 -0
  198. package/dist/packages/source-store/lib/content-types.js +75 -0
  199. package/dist/packages/source-store/lib/data-urls.d.ts +10 -0
  200. package/dist/packages/source-store/lib/data-urls.js +85 -0
  201. package/dist/packages/source-store/lib/deadline.d.ts +18 -0
  202. package/dist/packages/source-store/lib/deadline.js +44 -0
  203. package/dist/packages/source-store/lib/exchange.d.ts +29 -0
  204. package/dist/packages/source-store/lib/exchange.js +112 -0
  205. package/dist/packages/source-store/lib/integrity.d.ts +19 -0
  206. package/dist/packages/source-store/lib/integrity.js +86 -0
  207. package/dist/packages/source-store/lib/outcomes.d.ts +12 -0
  208. package/dist/packages/source-store/lib/outcomes.js +22 -0
  209. package/dist/packages/source-store/lib/proxy.d.ts +11 -0
  210. package/dist/packages/source-store/lib/proxy.js +53 -0
  211. package/dist/packages/source-store/lib/session.d.ts +12 -0
  212. package/dist/packages/source-store/lib/session.js +139 -0
  213. package/dist/packages/source-store/lib/urls.d.ts +6 -0
  214. package/dist/packages/source-store/lib/urls.js +15 -0
  215. package/dist/packages/source-store/resolve.d.ts +59 -0
  216. package/dist/packages/source-store/resolve.js +45 -0
  217. package/dist/scan.d.ts +65 -0
  218. package/dist/scan.js +592 -0
  219. package/package.json +95 -4
  220. package/schema/config.schema.json +133 -0
  221. package/schema/report.schema.json +1905 -0
@@ -0,0 +1,54 @@
1
+ // The scan-config id (§16 Scan configuration identity, ADR 0017): a hash of the settings that decide which findings
2
+ // can exist, recorded in a baseline so that it is never compared with a scan of something else.
3
+ import { createHash } from 'node:crypto';
4
+ import { posix } from 'node:path';
5
+ import { realms } from "../../../catalog.js";
6
+ /**
7
+ * The fields the id is made of, in the order of its parts. The mode, the source-map directories and the lockfile are
8
+ * not among them: remote gaps already become `unconfirmed`, and maps and lockfile are optional evidence (ADR 0006).
9
+ */
10
+ export const scanConfigFields = ['entries', 'mappings', 'surface', 'realms'];
11
+ /**
12
+ * The scan-config id: one 12-hex-digit part per field of `scanConfigFields`, joined with `.`, so that two ids name the
13
+ * fields that differ (§16). Each part is the start of the SHA-256 of the field's canonical JSON:
14
+ *
15
+ * - entries: `[file, url]` pairs, sorted
16
+ * - mappings: `[url, dir]` pairs, sorted
17
+ * - surface: the scope
18
+ * - realms: the realm set, sorted. R1 has no setting that narrows it, so every scan covers all four realms (§2).
19
+ *
20
+ * Only what decides the findings counts: the order of entries and mappings doesn't (the longest mapping prefix wins),
21
+ * and a path is normalized, without a trailing `/`.
22
+ */
23
+ export function scanConfigId(config) {
24
+ const fields = {
25
+ entries: config.entries.map(({ file, url }) => [path(file), url]).sort(comparePairs),
26
+ mappings: config.mappings.map(({ url, dir }) => [url, path(dir)]).sort(comparePairs),
27
+ surface: config.surface,
28
+ realms: [...realms].sort(),
29
+ };
30
+ return scanConfigFields.map((field) => digest(fields[field])).join('.');
31
+ }
32
+ /**
33
+ * The fields in which two scan-config ids differ, in the order of `scanConfigFields`: none when they are the same id.
34
+ * An id that doesn't have one part per field can't be read part by part, so it differs in every field.
35
+ */
36
+ export function differingScanConfigFields(a, b) {
37
+ const [ours, theirs] = [a.split('.'), b.split('.')];
38
+ const readable = ours.length === scanConfigFields.length && theirs.length === scanConfigFields.length;
39
+ return scanConfigFields.filter((_, i) => !readable || ours[i] !== theirs[i]);
40
+ }
41
+ function digest(value) {
42
+ return createHash('sha256').update(JSON.stringify(value)).digest('hex').slice(0, 12);
43
+ }
44
+ /** A relative path in one spelling: `./assets/` and `assets` are the same directory. */
45
+ function path(value) {
46
+ const normalized = posix.normalize(value);
47
+ return normalized.length > 1 && normalized.endsWith('/') ? normalized.slice(0, -1) : normalized;
48
+ }
49
+ function comparePairs(a, b) {
50
+ return compare(a[0], b[0]) || compare(a[1], b[1]);
51
+ }
52
+ function compare(a, b) {
53
+ return a < b ? -1 : a > b ? 1 : 0;
54
+ }
@@ -0,0 +1,2 @@
1
+ /** Validates a parsed config file against the shipped schema. Returns one line per problem, each naming its path. */
2
+ export declare function schemaProblems(value: unknown): string[];
@@ -0,0 +1,31 @@
1
+ // The config JSON Schema (§16) that ships in the package, at `schema/config.schema.json`. It validates the file.
2
+ import { readFileSync } from 'node:fs';
3
+ import { Ajv2020 } from 'ajv/dist/2020.js';
4
+ let validate;
5
+ /** Validates a parsed config file against the shipped schema. Returns one line per problem, each naming its path. */
6
+ export function schemaProblems(value) {
7
+ validate ??= new Ajv2020({ allErrors: true, strict: true }).compile(JSON.parse(readFileSync(new URL('../../../../schema/config.schema.json', import.meta.url), 'utf8')));
8
+ return validate(value) ? [] : (validate.errors ?? []).map(problem);
9
+ }
10
+ /** A validation error as `<JSON Pointer>: <what is wrong>`. */
11
+ function problem({ keyword, instancePath, params, message }) {
12
+ switch (keyword) {
13
+ case 'additionalProperties':
14
+ return `${instancePath}/${escape(params.additionalProperty)}: unknown key`;
15
+ case 'required':
16
+ return `${instancePath}/${escape(params.missingProperty)}: is required`;
17
+ case 'enum': {
18
+ const allowed = params.allowedValues;
19
+ return `${at(instancePath)}: must be one of ${allowed.map((value) => JSON.stringify(value)).join(', ')}`;
20
+ }
21
+ default:
22
+ return `${at(instancePath)}: ${message}`;
23
+ }
24
+ }
25
+ function at(pointer) {
26
+ return pointer === '' ? '(top level)' : pointer;
27
+ }
28
+ /** Escapes a key as a JSON Pointer reference token (RFC 6901). */
29
+ function escape(key) {
30
+ return key.replaceAll('~', '~0').replaceAll('/', '~1');
31
+ }
@@ -0,0 +1,64 @@
1
+ /** A URL→path mapping (§2): URLs under `url` are files under `dir`, relative to the build directory. */
2
+ export interface Mapping {
3
+ url: string;
4
+ dir: string;
5
+ }
6
+ /** An entry document (§2): its file, relative to the build directory, and its URL. */
7
+ export interface Entry {
8
+ file: string;
9
+ url: string;
10
+ }
11
+ /** The surface a scan reports, baselines and gates (§12, §16 `--surface`). */
12
+ export type SurfaceScope = 'protected' | 'all';
13
+ /** The remote retrieval mode (§17 Modes, §16 `--mode`): `offline` never fetches, and `resolve` does. */
14
+ export type Mode = 'offline' | 'resolve';
15
+ /** The baseline states the gate can fail on (§11 The gate, §16 `--fail-on`): `removed` and `unconfirmed` can't gate. */
16
+ export declare const failOnStates: readonly ["added", "changed"];
17
+ export type FailOnState = (typeof failOnStates)[number];
18
+ /** The commands (§16 Commands) built so far. */
19
+ export type Command = 'scan' | BaselineCommand;
20
+ /** The baseline commands (§11 Commands): each writes the baseline `--out` names. */
21
+ export type BaselineCommand = 'baseline init' | 'baseline update';
22
+ /** Bad flags or configuration: exit code 2 (§16). */
23
+ export declare class UsageError extends Error {
24
+ name: string;
25
+ }
26
+ /**
27
+ * What the config file and the flags each give (§16): every field is optional, and a flag overrides the file field by
28
+ * field. An entry's URL may be left out; it defaults to the first mapping's URL.
29
+ */
30
+ export interface Settings {
31
+ name?: string;
32
+ entries?: {
33
+ file: string;
34
+ url?: string;
35
+ }[];
36
+ mappings?: Mapping[];
37
+ sourceMaps?: string[];
38
+ surface?: SurfaceScope;
39
+ mode?: Mode;
40
+ /**
41
+ * The lockfile (§10 Introducing dependencies): `--lockfile` sets `path`, and the config key `lockfile.importer` names
42
+ * the workspace of the scanned application.
43
+ */
44
+ lockfile?: {
45
+ path?: string;
46
+ importer?: string;
47
+ };
48
+ json?: string;
49
+ out?: string;
50
+ baseline?: string;
51
+ /** `--previous`: a previous JSON scan report, for the reachability and install-context notes (§16). */
52
+ previous?: string;
53
+ failOn?: FailOnState[];
54
+ allowIncomplete?: boolean;
55
+ allowDowngrade?: boolean;
56
+ /** The saved JSON report `explain` reads (§16 `--report`). */
57
+ report?: string;
58
+ /** `--verbose`: the terminal report cards existing findings too (§15 Terminal). */
59
+ verbose?: boolean;
60
+ /** `--list-ineffective`: the terminal report lists the ineffective-write records (§3, §16). */
61
+ listIneffective?: boolean;
62
+ /** `--no-color`: the terminal report is never colored (§15 Formatting). */
63
+ noColor?: boolean;
64
+ }
@@ -0,0 +1,6 @@
1
+ /** The baseline states the gate can fail on (§11 The gate, §16 `--fail-on`): `removed` and `unconfirmed` can't gate. */
2
+ export const failOnStates = ['added', 'changed'];
3
+ /** Bad flags or configuration: exit code 2 (§16). */
4
+ export class UsageError extends Error {
5
+ name = 'UsageError';
6
+ }
@@ -0,0 +1,6 @@
1
+ /** The canonical form of an absolute `http:` or `https:` URL, or why `value` is not one. */
2
+ export declare function httpUrl(value: string): {
3
+ href: string;
4
+ } | {
5
+ problem: string;
6
+ };
@@ -0,0 +1,9 @@
1
+ /** The canonical form of an absolute `http:` or `https:` URL, or why `value` is not one. */
2
+ export function httpUrl(value) {
3
+ const url = URL.parse(value);
4
+ if (url === null)
5
+ return { problem: `'${value}' is not an absolute URL` };
6
+ if (url.protocol !== 'http:' && url.protocol !== 'https:')
7
+ return { problem: `'${value}' is not an http: or https: URL` };
8
+ return { href: url.href };
9
+ }
@@ -0,0 +1,277 @@
1
+ import type { Realm, SerializedCatalog } from '../../catalog.ts';
2
+ import type { GeneratedLocation } from '../analysis/index.ts';
3
+ import type { HtmlCounters, LimitationRecord, SourceMapDirectoryCounts, SourceMapPairing, SweptFiles, UnreadMaps } from '../completeness/index.ts';
4
+ import type { Entry } from '../config/index.ts';
5
+ import { type Retrieval, type SourceStore } from '../source-store/index.ts';
6
+ import { type LineReading } from './lib/source-maps.ts';
7
+ /** A script artifact of the artifact graph (§2). */
8
+ export interface Artifact {
9
+ url: string;
10
+ /** Build-relative POSIX path, for a local file; null for an inline script. */
11
+ path: string | null;
12
+ /**
13
+ * The content hash: `sha256:` and the hex digest of the artifact's bytes (an inline script's UTF-8 text); null when
14
+ * its bytes could not be read, or were withheld because they don't match their integrity value (§17 Integrity).
15
+ */
16
+ hash: string | null;
17
+ /**
18
+ * Where it is served from (§2): the build (`local-build`, through a URL mapping), the entry document itself
19
+ * (`inline`), or elsewhere, on the entry document's origin (`same-origin`) or another (`cross-origin`).
20
+ */
21
+ origin: 'local-build' | 'same-origin' | 'cross-origin' | 'inline';
22
+ /**
23
+ * How it was found (§2): by following a reference, as a script the page's code injects (`injected`), or only by the
24
+ * build-directory sweep.
25
+ */
26
+ discovery: 'reference' | 'injected' | 'sweep';
27
+ /**
28
+ * `module` for a module script: a `type=module` script, a `<link rel=modulepreload>`, what a module request (a
29
+ * static or dynamic import, or a re-export) names, or a worker created with `type: "module"`. `script` for a classic
30
+ * one. A file only a `<link rel=preload as=script>` names, or only preloads that disagree, and a worker created with
31
+ * options that can't be read statically, are typed by their syntax, as a sweep-only file is (§2). A URL a page runs
32
+ * both ways is an artifact each way.
33
+ */
34
+ sourceType: 'script' | 'module';
35
+ /**
36
+ * The realm it runs in, from how it was referenced (§2 Realm): `window` for what an entry document references, the
37
+ * worker's realm for a worker script (`new Worker`, `new SharedWorker`, `navigator.serviceWorker.register`), and the
38
+ * realm of the code that references it for an import or an `importScripts`. A URL referenced in two realms is an
39
+ * artifact in each.
40
+ */
41
+ realm: Realm;
42
+ /**
43
+ * How its realm is known (§2 Realm): from how it was referenced (`reference`), or assumed to be `window` because only
44
+ * the sweep found it, only a `<link rel=preload as=script>` names it, or only the module requests of code whose realm
45
+ * is assumed name it (`assumed`).
46
+ */
47
+ realmBasis: 'reference' | 'assumed';
48
+ /**
49
+ * The URL of what first references it in its realm (§2 parent or importer): the entry document whose element names
50
+ * it, or the script or module that imports it or creates the worker. Null for an artifact only the sweep found.
51
+ */
52
+ parent: string | null;
53
+ /**
54
+ * Its source map (§2 Source maps): the first candidate that verifies, found by the `SourceMap` header of a fetched
55
+ * artifact, then its `sourceMappingURL` annotation, then a `<file>.map` sidecar, then a map in the build directory with
56
+ * its `debugId`, then in each source-map directory, a map with its `debugId`, its annotation mirrored there, and its
57
+ * sidecar mirrored there.
58
+ */
59
+ sourceMap: SourceMapPairing;
60
+ /**
61
+ * The source map that verified, for attribution (§10), which reads it from its raw JSON: that JSON, and the line
62
+ * reading of the artifact's text that verified it (§2 Verification). Null when none did. It isn't reported.
63
+ */
64
+ map: PairedMap | null;
65
+ /**
66
+ * How many candidate maps failed verification against it (§2 Source maps), each counted `stale`: those before the
67
+ * one that verified, or every one, when none did. A source-map directory's map verified only to count it, after one
68
+ * already verified, is not counted.
69
+ */
70
+ staleCandidates: number;
71
+ /**
72
+ * The maps it names, as a remote artifact, that weren't read (§17 Content types): refused by the safety floor, failed,
73
+ * or a build file that exists but can't be read. They change counters only, never completeness.
74
+ */
75
+ unreadMaps: UnreadMaps;
76
+ /** How its bytes were retrieved (§17 What is recorded): whether they were read (`ok`), or why not. */
77
+ retrieval: Retrieval;
78
+ /**
79
+ * Whether a reference runs it. It does not when only preloads name it (`<link rel=preload as=script>` or `<link
80
+ * rel=modulepreload>`), or module requests of files that don't run: a preload joins the artifact graph, but never
81
+ * makes a file run (§19 HTML rules), and a module runs only when its importer does. Nor does it when only the sweep
82
+ * found it.
83
+ */
84
+ runs: boolean;
85
+ /** The script's source text, when its bytes were read. */
86
+ text: string | null;
87
+ }
88
+ /**
89
+ * A verified source map (§2 Source maps): its raw JSON, the line reading of the artifact that verified it, and `base`,
90
+ * the build-relative path whose directory its relative sources resolve against (§10): the map's own path. A
91
+ * source-map directory's map has its path inside the directory, as if the directory mirrored the build, however it
92
+ * was paired, and a `data:` URL map has its script's path (§10 Roots with no shared place). Null for a fetched map,
93
+ * which has no place in the build.
94
+ */
95
+ export interface PairedMap {
96
+ raw: unknown;
97
+ reading: LineReading;
98
+ base: string | null;
99
+ }
100
+ export type { LineReading };
101
+ /** What discovery finds: the artifact graph, and what it could not follow (§13). */
102
+ export interface Discovered {
103
+ /** Every artifact, in the order it was first found. */
104
+ artifacts: Artifact[];
105
+ limitations: LimitationRecord[];
106
+ /** HTML content that is counted, not analyzed (§19 HTML rules). */
107
+ html: HtmlCounters;
108
+ /** The build files the sweep found and did not analyze (§2 Sweep, §13 Counters), by path, sorted. */
109
+ swept: SweptFiles;
110
+ /** What became of each source-map directory's maps (§13 Attribution block), in the order they were declared. */
111
+ sourceMapDirectories: SourceMapDirectoryCounts[];
112
+ /**
113
+ * Each module request a script's code makes that resolves to a URL (§6 Module links): the realm and URL of the script
114
+ * it is in, the entry document that followed it, whose import maps resolved it, its specifier, and the URL it names.
115
+ * A sweep-only file's requests are recorded too, with no document, resolved against its URL with no import map: they
116
+ * are followed (§2 Sweep), except that an import of another swept file leaves it the sweep's.
117
+ */
118
+ imports: ModuleImport[];
119
+ /**
120
+ * The artifacts that module requests name and no other reference runs, by realm and URL: no script element, worker
121
+ * or other reference does, though a preload may name them. They are analyzed only as members of their importers' link
122
+ * groups (§19 Link groups).
123
+ */
124
+ importedOnly: {
125
+ realm: Realm;
126
+ url: string;
127
+ }[];
128
+ /**
129
+ * The entry documents whose references other than module requests name each artifact, by realm and URL, in the order
130
+ * of the entries: each runs it with its own import maps.
131
+ */
132
+ documents: {
133
+ realm: Realm;
134
+ url: string;
135
+ documents: string[];
136
+ }[];
137
+ /**
138
+ * Each remote chunk a loader's folded chunk URL names (§2, §19 References only the resolver can see): the realm, the
139
+ * loader (its URL, and the URL it was fetched at when that isn't its URL) and the chunk's URL. A remote chunk joins
140
+ * the link group of a loader that loads it, and no other group, through the registry it pushes into (§6 idiom 6).
141
+ */
142
+ remoteChunks: {
143
+ realm: Realm;
144
+ loader: {
145
+ url: string;
146
+ fetched?: string;
147
+ };
148
+ chunk: string;
149
+ }[];
150
+ }
151
+ /** A module request that resolves to a URL (`Discovered.imports`). */
152
+ export interface ModuleImport {
153
+ realm: Realm;
154
+ document: string | null;
155
+ /** The importing script's URL, and the URL it was fetched at when that isn't its URL (§11). */
156
+ from: {
157
+ url: string;
158
+ fetched?: string;
159
+ };
160
+ specifier: string;
161
+ /** The module's URL, and the URL it is fetched at when that isn't its URL (§11). */
162
+ to: {
163
+ url: string;
164
+ fetched?: string;
165
+ };
166
+ }
167
+ /**
168
+ * Finds the classic and module scripts each entry document runs, following the HTML rules of §19: its inline scripts,
169
+ * and the files its `script[src]` elements name, resolved against the document's base URL. A file that only a
170
+ * `<link rel=preload as=script>` or a `<link rel=modulepreload>` names joins the graph too, and does not run. It
171
+ * counts the HTML content it does not analyze: classic `nomodule` scripts, inline event handlers and `javascript:`
172
+ * URLs.
173
+ *
174
+ * Then it follows the module requests of every script it found, and of every module those name, in turn (§2): static
175
+ * imports, re-exports and dynamic imports with a literal specifier, resolved through the document's import maps in
176
+ * browser order (§2 Import maps). An inline module script's requests resolve through the maps before it in tree order,
177
+ * and every other request through all of them. Each names a module, which runs when its importer does. A request with
178
+ * an import attribute names no JavaScript module, and is not followed. A static import or re-export with an attribute a
179
+ * browser doesn't support fails every module graph that contains it (§2 Import attributes): each root of such a graph
180
+ * (a module script element, a dynamic import or a module worker) gives nothing, and nothing is followed through it
181
+ * from a hint. A dynamic import whose specifier is not a literal, or whose options have a part that can't be read and
182
+ * could decide whether it names a JavaScript module, and a specifier that doesn't resolve, such as a bare specifier no
183
+ * import map maps, give an `unresolved-reference` record.
184
+ *
185
+ * It follows the worker scripts they load with a literal URL too (§2, §19 Discovery), where the realm has the function
186
+ * that loads them: a `new Worker` is a dedicated worker, a `new SharedWorker` a shared worker, and a
187
+ * `navigator.serviceWorker.register` a service worker, each in its own realm, and an `importScripts` loads a classic
188
+ * script into its own worker. A service worker whose script falls outside every URL mapping, like a `<link
189
+ * rel=modulepreload as=serviceworker>` outside every mapping, gives an `unresolved-reference` record instead. A
190
+ * dedicated or shared worker's script on another origin than its creator's is not followed, as a browser won't run it,
191
+ * and a `data:` worker's is code the page carries, as a `data:` script is.
192
+ *
193
+ * A file a `<link rel=preload as=script>` names that no running reference names, in any realm, is followed last, as the
194
+ * syntax of the preload's own bytes says, in URL order. Its realm is assumed to be `window` when nothing else names it,
195
+ * as it is for the modules it requests (§2 Files that don't run as referenced). One a running reference runs in another
196
+ * realm has no window artifact. One whose code has worker markers gives a `realm-uncertain` record, as a file only the
197
+ * sweep found does.
198
+ *
199
+ * A remote script is fetched with the integrity metadata its reference carries (§17 Integrity): a `script` or `link`
200
+ * element's `integrity` attribute, or, for a module with none, its URL's entry in the document's import maps. A
201
+ * fetched script's own references are fetched against the URL its bytes came from, after any redirects, though it
202
+ * keeps the URL it was requested at. They are keyed, as artifacts, by the URL resolved against the script's own URL as
203
+ * requested (its key URL), so a key doesn't change when a redirect target moves (§11 Remote URL normalization). One
204
+ * fetched URL reached under two key URLs is an artifact of each, sharing the one fetch, and one key URL reached through
205
+ * two fetched URLs is an artifact of each too, both analyzed, told apart by `retrieval.requestedUrl`.
206
+ *
207
+ * A `data:` URL is code the page carries (§2 Other script URLs): its script is an `inline` artifact of the referencing
208
+ * realm, loaded as the reference loads it, unless a browser would refuse to run it, when it gives nothing, as a `data:`
209
+ * service worker always does. A script URL with any other scheme but `http:` and `https:` (`javascript:`, `blob:`,
210
+ * `file:`, `about:`, …) gives nothing wherever it appears.
211
+ *
212
+ * An entry document or a local script that can't be read gives an `unreadable` record, and a remote script that isn't
213
+ * read gives an `offline-skipped`, `remote-refused`, `fetch-failed` or `sri-mismatch` one (§17 Outcomes); the script
214
+ * is still an artifact. Each URL, and each inline script, is an artifact of its own, whatever bytes it shares with
215
+ * another (§2 Artifacts): the scan analyzes identical bytes once, and gives each copy its findings.
216
+ *
217
+ * Last, it pairs each artifact with the first source map that verifies against it (§2 Source maps): one a fetched
218
+ * artifact's `SourceMap` header names, then one its annotation names, then its sidecar in the build directory, then a
219
+ * map there with its `debugId`. A map that fails verification is `stale`, and counted. A missing or broken map gives no
220
+ * record: it is counted in the attribution block (§13), and never changes completeness. A map the annotation of a
221
+ * local-build or inline artifact names, or its sidecar, that exists but can't be read gives an `unreadable` record. A
222
+ * remote artifact's maps are fetched only here, after every script: each one the safety floor refuses, whose fetch
223
+ * fails, or that is a build file that exists but can't be read, is only counted (§17, `unreadMaps`).
224
+ * Then each source-map directory is searched, one at a time, in the order they were declared (`pairInDirectory`): one
225
+ * that can't be listed gives an `unreadable` record, and one none of whose maps verifies against an artifact a
226
+ * `source-maps-unpaired` record.
227
+ */
228
+ export declare function discover(input: {
229
+ entries: readonly Entry[];
230
+ store: SourceStore;
231
+ /**
232
+ * The source-map directories (§2 Source maps), by their names as declared, in the order they are searched. The store
233
+ * reads them.
234
+ */
235
+ sourceMaps?: readonly string[];
236
+ /** The catalog, read for the names of event handlers and for the globals each realm has. */
237
+ catalog: SerializedCatalog;
238
+ /**
239
+ * The references only the resolver can see that earlier rounds found (§19 References only the resolver can see), in
240
+ * URL order. Discovery follows them as it follows its own, so a round's artifact graph depends only on the set.
241
+ */
242
+ references?: readonly ResolvedReference[];
243
+ }): Promise<Discovered>;
244
+ /**
245
+ * A reference only the resolver can see (§19 References only the resolver can see), as a round found it: the realm of
246
+ * the link group it was found in, the artifact whose code holds it (its URL, and the URL it was fetched at when that
247
+ * isn't its URL), its kind, and its URL as the code builds it, unresolved.
248
+ * - A `chunk` reference's `load` is how the load site loads it: a created script element's `src`, `importScripts` or
249
+ * `import()`. A `partial` record's URL is only the constant prefix of an alternative that doesn't fold ('' for none),
250
+ * which decides whether that chunk URL is local (§2).
251
+ * - An `injected` reference is a script element's `src` (§2), with the element's `type` as it folds (absent when
252
+ * none is set, null when it doesn't fold) and its folded `integrity`, if any.
253
+ * - A `worker` reference is a worker URL that isn't a literal, located at the call's URL argument.
254
+ * A `partial` injected or worker record stands for one alternative that doesn't fold, located at `alternative`.
255
+ */
256
+ export interface ResolvedReference {
257
+ realm: Realm;
258
+ from: {
259
+ url: string;
260
+ fetched?: string;
261
+ };
262
+ kind: 'chunk' | 'injected' | 'worker';
263
+ url: string;
264
+ load?: 'element' | 'import-scripts' | 'import';
265
+ partial?: true;
266
+ alternative?: GeneratedLocation;
267
+ /** For a `worker` site: its URL folds to no value, as when it throws (`new URL("x.js")`), so it loads nothing. */
268
+ none?: true;
269
+ type?: string | null;
270
+ /** The integrity value code sets on the chunk's script element, when it folds (§17 Integrity). */
271
+ integrity?: string;
272
+ /** For an `injected` reference: the constants its element's `integrity` may be, when each write folds. */
273
+ integrityAlternatives?: string[];
274
+ /** For an `injected` reference: its element's `noModule` is set (`yes`), or may be (`maybe`). */
275
+ noModule?: 'yes' | 'maybe';
276
+ location: GeneratedLocation;
277
+ }