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,133 @@
1
+ // `pnpm-lock.yaml` (§10 Introducing dependencies): `lockfileVersion` 6.0 and 9.x; any other version is unusable.
2
+ // It records each importer's direct dependencies, dev ones apart, and each package's resolved dependencies, peers
3
+ // included. It is keyed by name and version, not by install path, so it gives no version (§10 Version). Pure.
4
+ import { graph, isRecord, normalizeFolder, placeByName, readManifest, } from "./lockfile-graph.js";
5
+ import { readYaml } from "./yaml.js";
6
+ /** A dependency map's references: a 9.0 or 6.0 package's `name: version`, or an importer's `name: { version }`. */
7
+ function references(value) {
8
+ if (!isRecord(value))
9
+ return [];
10
+ return Object.entries(value).flatMap(([name, each]) => {
11
+ const version = isRecord(each) ? each.version : each;
12
+ return typeof version === 'string' ? [[name, version]] : [];
13
+ });
14
+ }
15
+ /** A package key's name and version: `name@1.0.0(peer@2.0.0)`, or 6.0's `/name@1.0.0(peer@2.0.0)`. */
16
+ function identOf(key) {
17
+ const bare = key.startsWith('/') ? key.slice(1) : key;
18
+ const split = bare.indexOf('@', 1);
19
+ if (split <= 0)
20
+ return null;
21
+ const rest = bare.slice(split + 1);
22
+ const peers = rest.indexOf('(');
23
+ return { name: bare.slice(0, split), version: peers < 0 ? rest : rest.slice(0, peers) };
24
+ }
25
+ export function readPnpm(text, file, manifests) {
26
+ const doc = readYaml(text);
27
+ if (!isRecord(doc))
28
+ return { unusable: `${file} is not a pnpm lockfile` };
29
+ const version = typeof doc.lockfileVersion === 'string' ? doc.lockfileVersion : null;
30
+ const v9 = version !== null && /^9\.\d+$/.test(version);
31
+ if (!v9 && version !== '6.0')
32
+ return { unusable: `${file} lockfileVersion ${version ?? 'null'}` };
33
+ // A 6.0 lockfile of a project with no workspaces keeps its importer's lists at the top.
34
+ const importers = isRecord(doc.importers) ? doc.importers : { '.': doc };
35
+ const snapshots = v9 ? doc.snapshots : doc.packages;
36
+ const nodes = new Map();
37
+ for (const [key, entry] of Object.entries(isRecord(snapshots) ? snapshots : {})) {
38
+ const ident = identOf(key);
39
+ if (ident === null)
40
+ continue;
41
+ const own = isRecord(entry) ? entry : {};
42
+ nodes.set(key, {
43
+ key,
44
+ ...ident,
45
+ production: [...references(own.dependencies), ...references(own.optionalDependencies)],
46
+ development: [],
47
+ });
48
+ }
49
+ const workspaces = [];
50
+ const importerNodes = new Map();
51
+ for (const [path, entry] of Object.entries(importers)) {
52
+ if (!isRecord(entry))
53
+ continue;
54
+ const folder = normalizeFolder(path);
55
+ // pnpm records no importer's name or version: a linked workspace's come from its manifest, when it is readable.
56
+ const manifest = readManifest(manifests[folder]);
57
+ workspaces.push({ folder, name: null, version: null });
58
+ importerNodes.set(folder, {
59
+ key: `importer:${folder}`,
60
+ name: manifest?.name ?? '',
61
+ version: manifest?.version ?? '',
62
+ folder,
63
+ production: [...references(entry.dependencies), ...references(entry.optionalDependencies)],
64
+ development: references(entry.devDependencies),
65
+ });
66
+ }
67
+ /** The node a reference from `from` names: a linked importer, a package key, or an alias's key. */
68
+ const target = (from, name, reference) => {
69
+ if (reference.startsWith('link:')) {
70
+ const linked = importerNodes.get(normalizeFolder(`${from.folder ?? ''}/${reference.slice('link:'.length)}`));
71
+ return linked === undefined ? [] : [linked];
72
+ }
73
+ const keys = v9 ? [`${name}@${reference}`, reference] : [`/${name}@${reference}`, reference, `/${reference}`];
74
+ for (const key of keys) {
75
+ const found = nodes.get(key);
76
+ if (found !== undefined)
77
+ return [found];
78
+ }
79
+ return [];
80
+ };
81
+ const edges = (node) => {
82
+ const own = node;
83
+ return own.production.flatMap(([name, reference]) => target(own, name, reference));
84
+ };
85
+ const direct = (workspace) => {
86
+ const importer = importerNodes.get(workspace.folder);
87
+ if (importer === undefined)
88
+ return [];
89
+ return [...importer.production, ...importer.development].flatMap(([name, reference]) => target(importer, name, reference));
90
+ };
91
+ // Each importer is named by what refers to it when its manifest doesn't name it.
92
+ for (const node of [...nodes.values(), ...importerNodes.values()]) {
93
+ for (const [name, reference] of [...node.production, ...node.development]) {
94
+ if (!reference.startsWith('link:'))
95
+ continue;
96
+ const linked = importerNodes.get(normalizeFolder(`${node.folder ?? ''}/${reference.slice('link:'.length)}`));
97
+ if (linked !== undefined && linked.name === '')
98
+ linked.name = name;
99
+ }
100
+ }
101
+ const all = [...nodes.values(), ...[...importerNodes.values()].filter((node) => node.name !== '')];
102
+ const byName = new Map();
103
+ // A named workspace is installed too (linked into `node_modules`), so code under its name there is no vendored code.
104
+ // The root is no package anything installs.
105
+ for (const node of all) {
106
+ if (node.folder === '' || node.name === '')
107
+ continue;
108
+ const list = byName.get(node.name);
109
+ if (list === undefined)
110
+ byName.set(node.name, [node]);
111
+ else
112
+ list.push(node);
113
+ }
114
+ return {
115
+ lockfile: graph({
116
+ format: 'pnpm',
117
+ keyedByInstallPath: false,
118
+ confidence: 'high',
119
+ nodes: all,
120
+ workspaces,
121
+ edges,
122
+ direct,
123
+ place: (directory) => placeByName(directory, byName, workspaces, edges, direct),
124
+ }),
125
+ };
126
+ }
127
+ /** The importer folders a `pnpm-lock.yaml` names, besides its own directory, whose manifests name linked workspaces. */
128
+ export function pnpmFolders(text) {
129
+ const doc = readYaml(text);
130
+ if (!isRecord(doc) || !isRecord(doc.importers))
131
+ return [];
132
+ return Object.keys(doc.importers).map(normalizeFolder).filter((folder) => folder !== '');
133
+ }
@@ -0,0 +1,7 @@
1
+ import type { RemoteUrlNormalization } from '../../../catalog.ts';
2
+ /**
3
+ * Normalizes a remote artifact's URL, as referenced, by the catalog's rules (§11 Remote URL normalization): its scheme
4
+ * (step 1), then its host, port, query and fragment (step 2), then each rewrite of its path, in order (steps 3 and 4).
5
+ * The path rules see the path only, so hosts are kept.
6
+ */
7
+ export declare function normalizeRemoteUrl(href: string, rules: RemoteUrlNormalization): string;
@@ -0,0 +1,24 @@
1
+ /** The default port of each scheme a remote script is fetched over (URL § Special schemes). */
2
+ const defaultPorts = { 'http:': '80', 'https:': '443' };
3
+ /**
4
+ * Normalizes a remote artifact's URL, as referenced, by the catalog's rules (§11 Remote URL normalization): its scheme
5
+ * (step 1), then its host, port, query and fragment (step 2), then each rewrite of its path, in order (steps 3 and 4).
6
+ * The path rules see the path only, so hosts are kept.
7
+ */
8
+ export function normalizeRemoteUrl(href, rules) {
9
+ const url = new URL(href);
10
+ if (rules.scheme.from.includes(url.protocol))
11
+ url.protocol = rules.scheme.to;
12
+ url.hostname = url.hostname.toLowerCase();
13
+ if (rules.drop.includes('default-port') && url.port === defaultPorts[url.protocol])
14
+ url.port = '';
15
+ if (rules.drop.includes('query'))
16
+ url.search = '';
17
+ if (rules.drop.includes('fragment'))
18
+ url.hash = '';
19
+ const { pathname, search, hash } = url;
20
+ const origin = url.href.slice(0, url.href.length - pathname.length - search.length - hash.length);
21
+ // The path is rewritten as a string: the URL setters would percent-encode the `#` a hex run becomes.
22
+ const path = rules.path.reduce((rewritten, { pattern, replacement }) => rewritten.replace(new RegExp(pattern, 'gu'), replacement), pathname);
23
+ return `${origin}${path}${search}${hash}`;
24
+ }
@@ -0,0 +1,51 @@
1
+ import { type TraceMap } from '@jridgewell/trace-mapping';
2
+ /** How an artifact's text splits into lines: the reading that verified its map (§2 Verification). */
3
+ export type LineReading = 'ecmascript' | 'lf-cr';
4
+ /** A verified map, read: its flattened mappings, and each source's raw entry, relative `sourceRoot` and content. */
5
+ export interface ReadMap {
6
+ trace: TraceMap;
7
+ sources: SourceEntry[];
8
+ }
9
+ /**
10
+ * A `sources` entry: `raw` as the map writes it (null for a null entry), the relative `sourceRoot` of its map or
11
+ * section, which §10 step 1 joins only to an entry with no scheme that isn't absolute (null when there is none), its
12
+ * `sourcesContent` entry, null when the map has none for it, and whether its map or section's ignore list names it:
13
+ * `ignoreList` when the map has one, and `x_google_ignoreList` only otherwise (§10).
14
+ */
15
+ export interface SourceEntry {
16
+ raw: string | null;
17
+ sourceRoot: string | null;
18
+ content: string | null;
19
+ ignored: boolean;
20
+ }
21
+ /** Reads a map's raw JSON, which verification has already read with `FlattenMap` (§2), or null if it can't. */
22
+ export declare function readMap(raw: unknown): ReadMap | null;
23
+ /**
24
+ * The mapped original position of a generated one (§10 lookup point): trace-mapping's greatest lower bound on the same
25
+ * generated line (0-based line and column). A 1-field segment, or no segment at or before the column, is unmapped.
26
+ */
27
+ export declare function originalAt(map: ReadMap, line: number, column: number): {
28
+ source: SourceEntry;
29
+ index: number;
30
+ line: number;
31
+ column: number;
32
+ } | null;
33
+ /**
34
+ * How an original source's text may split into lines (§10 Token check): an artifact's two readings, or at LF only, as
35
+ * tools such as magic-string number an original's lines.
36
+ */
37
+ type OriginalLineReading = LineReading | 'lf';
38
+ /** Where each line of `text` starts, under a line reading: a CRLF ends one line. */
39
+ export declare function lineStarts(text: string, reading: OriginalLineReading): number[];
40
+ /** The 0-based line and column of a UTF-16 offset, through a line-start table. */
41
+ export declare function position(starts: readonly number[], offset: number): {
42
+ line: number;
43
+ column: number;
44
+ };
45
+ /**
46
+ * The token check (§10): whether `token` appears as a whole identifier, case-sensitive, within ±1 line of the 0-based
47
+ * original `line` in `content`, under any of three line readings of the original: at §5's terminators, at LF and CR,
48
+ * or at LF only.
49
+ */
50
+ export declare function tokenAppears(content: string, line: number, token: string): boolean;
51
+ export {};
@@ -0,0 +1,125 @@
1
+ // Reading a verified source map for attribution (§10, §19 Discovery): positions are looked up with
2
+ // `@jridgewell/trace-mapping` (`FlattenMap`, which flattens a sectioned map), and the raw `sources`, `sourceRoot` and
3
+ // `sourcesContent` are read from the map's raw JSON, in `FlattenMap`'s section order.
4
+ import { FlattenMap, traceSegment } from '@jridgewell/trace-mapping';
5
+ import { relativeSourceRoot } from "./containing-package.js";
6
+ /** Reads a map's raw JSON, which verification has already read with `FlattenMap` (§2), or null if it can't. */
7
+ export function readMap(raw) {
8
+ try {
9
+ const trace = new FlattenMap(raw);
10
+ return { trace, sources: flattenedSources(raw) };
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ }
16
+ /**
17
+ * The sources of a map in `FlattenMap`'s order: a sectioned map's sections in turn, each flattened the same way, and a
18
+ * plain map's `sources` with its own `sourceRoot` and `sourcesContent`.
19
+ */
20
+ function flattenedSources(raw) {
21
+ const map = typeof raw === 'string' ? JSON.parse(raw) : raw;
22
+ if (!isObject(map))
23
+ return [];
24
+ if (Array.isArray(map.sections)) {
25
+ return map.sections.flatMap((section) => (isObject(section) ? flattenedSources(section.map) : []));
26
+ }
27
+ const sources = Array.isArray(map.sources) ? map.sources : [];
28
+ const contents = Array.isArray(map.sourcesContent) ? map.sourcesContent : [];
29
+ const sourceRoot = relativeSourceRoot(map.sourceRoot);
30
+ const ignoreList = Array.isArray(map.ignoreList)
31
+ ? map.ignoreList
32
+ : Array.isArray(map.x_google_ignoreList)
33
+ ? map.x_google_ignoreList
34
+ : [];
35
+ return sources.map((source, index) => {
36
+ const content = contents[index];
37
+ return {
38
+ raw: typeof source === 'string' ? source : null,
39
+ sourceRoot,
40
+ content: typeof content === 'string' ? content : null,
41
+ ignored: ignoreList.includes(index),
42
+ };
43
+ });
44
+ }
45
+ /**
46
+ * The mapped original position of a generated one (§10 lookup point): trace-mapping's greatest lower bound on the same
47
+ * generated line (0-based line and column). A 1-field segment, or no segment at or before the column, is unmapped.
48
+ */
49
+ export function originalAt(map, line, column) {
50
+ const segment = traceSegment(map.trace, line, column);
51
+ if (segment === null || segment.length === 1)
52
+ return null;
53
+ const [, index, originalLine, originalColumn] = segment;
54
+ const source = map.sources[index] ?? { raw: null, sourceRoot: null, content: null, ignored: false };
55
+ return { source, index, line: originalLine, column: originalColumn };
56
+ }
57
+ /** The terminators of each line reading (§2 Verification, §10 Token check). */
58
+ const terminators = {
59
+ ecmascript: (code) => code === 0x0a || code === 0x0d || code === 0x2028 || code === 0x2029,
60
+ 'lf-cr': (code) => code === 0x0a || code === 0x0d,
61
+ lf: (code) => code === 0x0a,
62
+ };
63
+ /** The line readings the token check tries on an original, any of which passes it (§10 Token check). */
64
+ const originalReadings = ['ecmascript', 'lf-cr', 'lf'];
65
+ /** Where each line of `text` starts, under a line reading: a CRLF ends one line. */
66
+ export function lineStarts(text, reading) {
67
+ const ends = terminators[reading];
68
+ const starts = [0];
69
+ for (let i = 0; i < text.length; i++) {
70
+ const code = text.charCodeAt(i);
71
+ if (code === 0x0d && text.charCodeAt(i + 1) === 0x0a)
72
+ i++;
73
+ if (ends(code))
74
+ starts.push(i + 1);
75
+ }
76
+ return starts;
77
+ }
78
+ /** The 0-based line and column of a UTF-16 offset, through a line-start table. */
79
+ export function position(starts, offset) {
80
+ let low = 0;
81
+ let high = starts.length - 1;
82
+ while (low < high) {
83
+ const middle = (low + high + 1) >> 1;
84
+ if (starts[middle] <= offset)
85
+ low = middle;
86
+ else
87
+ high = middle - 1;
88
+ }
89
+ return { line: low, column: offset - starts[low] };
90
+ }
91
+ /**
92
+ * The token check (§10): whether `token` appears as a whole identifier, case-sensitive, within ±1 line of the 0-based
93
+ * original `line` in `content`, under any of three line readings of the original: at §5's terminators, at LF and CR,
94
+ * or at LF only.
95
+ */
96
+ export function tokenAppears(content, line, token) {
97
+ return originalReadings.some((reading) => appearsNear(content, lineStarts(content, reading), line, token));
98
+ }
99
+ /** Whether `token` appears as a whole identifier within ±1 line of `line`, through a line-start table. */
100
+ function appearsNear(content, starts, line, token) {
101
+ const from = starts[Math.max(0, line - 1)] ?? content.length;
102
+ const to = starts[line + 2] ?? content.length;
103
+ const window = content.slice(from, to);
104
+ for (let at = window.indexOf(token); at >= 0; at = window.indexOf(token, at + 1)) {
105
+ const before = window.charCodeAt(at - 1);
106
+ const after = window.charCodeAt(at + token.length);
107
+ if (!identifierPart(before) && !identifierPart(after))
108
+ return true;
109
+ }
110
+ return false;
111
+ }
112
+ const identifierPartPattern = /[$\u200c\u200d\p{ID_Continue}]/u;
113
+ /** Whether a UTF-16 code unit is an identifier part (ECMA-262 IdentifierPartChar). NaN, past either end, is not. */
114
+ function identifierPart(code) {
115
+ if (Number.isNaN(code))
116
+ return false;
117
+ if (code < 0x80) {
118
+ return (code >= 0x30 && code <= 0x39) || (code >= 0x41 && code <= 0x5a) || (code >= 0x61 && code <= 0x7a) ||
119
+ code === 0x24 || code === 0x5f;
120
+ }
121
+ return identifierPartPattern.test(String.fromCharCode(code));
122
+ }
123
+ function isObject(value) {
124
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
125
+ }
@@ -0,0 +1,9 @@
1
+ /** A value read from lockfile YAML: every scalar is a string. */
2
+ export type YamlValue = string | null | YamlValue[] | {
3
+ [key: string]: YamlValue;
4
+ };
5
+ /**
6
+ * Reads lockfile YAML, or returns null when the text is outside the subset. A stream of several documents (pnpm writes
7
+ * its environment lockfile first) reads as its last document.
8
+ */
9
+ export declare function readYaml(input: string): YamlValue | null;
@@ -0,0 +1,277 @@
1
+ // The YAML that `pnpm-lock.yaml` and Yarn Berry's `yarn.lock` are written in (§10 Introducing dependencies): block
2
+ // mappings and sequences, flow mappings and sequences, and plain or quoted scalars, every scalar read as a string.
3
+ // Anchors, tags and block scalars, which neither lockfile writes, make the text unreadable. Pure.
4
+ /** Thrown for text outside the lockfile subset. */
5
+ class Unreadable extends Error {
6
+ }
7
+ /**
8
+ * Reads lockfile YAML, or returns null when the text is outside the subset. A stream of several documents (pnpm writes
9
+ * its environment lockfile first) reads as its last document.
10
+ */
11
+ export function readYaml(input) {
12
+ const text = input.startsWith('') ? input.slice(1) : input;
13
+ const documents = [[]];
14
+ for (const raw of text.split(/\r?\n/)) {
15
+ if (/^---\s*$/.test(raw)) {
16
+ documents.push([]);
17
+ continue;
18
+ }
19
+ if (/^\.\.\.\s*$/.test(raw))
20
+ continue;
21
+ const body = withoutComment(raw).trimEnd();
22
+ if (body.trim() === '')
23
+ continue;
24
+ if (body.includes('\t') && /^\s*\t/.test(body))
25
+ return null;
26
+ const indent = body.length - body.trimStart().length;
27
+ documents.at(-1).push({ indent, text: body.trimStart() });
28
+ }
29
+ const lines = documents.filter((each) => each.length > 0).at(-1) ?? [];
30
+ try {
31
+ if (lines.length === 0)
32
+ return null;
33
+ const at = { i: 0 };
34
+ const value = block(lines, at, lines[0].indent);
35
+ if (at.i < lines.length)
36
+ throw new Unreadable();
37
+ return value;
38
+ }
39
+ catch (error) {
40
+ if (error instanceof Unreadable)
41
+ return null;
42
+ throw error;
43
+ }
44
+ }
45
+ /** A line without its comment: `#` at the start or after a space, outside quotes. */
46
+ function withoutComment(line) {
47
+ let quote = null;
48
+ for (let i = 0; i < line.length; i++) {
49
+ const c = line[i];
50
+ if (quote !== null) {
51
+ if (quote === "'" && c === "'" && line[i + 1] === "'")
52
+ i++;
53
+ else if (quote === '"' && c === '\\')
54
+ i++;
55
+ else if (c === quote)
56
+ quote = null;
57
+ }
58
+ else if (c === "'" || c === '"') {
59
+ if (i === 0 || /[\s:[{,-]/.test(line[i - 1]))
60
+ quote = c;
61
+ }
62
+ else if (c === '#' && (i === 0 || /\s/.test(line[i - 1])))
63
+ return line.slice(0, i);
64
+ }
65
+ return line;
66
+ }
67
+ /** The block at `indent` starting at `at.i`: a sequence when its first line is a `- ` item, else a mapping. */
68
+ function block(lines, at, indent) {
69
+ const first = lines[at.i];
70
+ if (first.text === '-' || first.text.startsWith('- '))
71
+ return sequence(lines, at, indent);
72
+ return mapping(lines, at, indent);
73
+ }
74
+ function sequence(lines, at, indent) {
75
+ const out = [];
76
+ while (at.i < lines.length) {
77
+ const line = lines[at.i];
78
+ if (line.indent < indent)
79
+ break;
80
+ if (line.indent > indent || !(line.text === '-' || line.text.startsWith('- ')))
81
+ throw new Unreadable();
82
+ const rest = line.text.slice(1).trimStart();
83
+ at.i++;
84
+ if (rest === '') {
85
+ out.push(nested(lines, at, indent));
86
+ }
87
+ else if (keyOf(rest) !== null) {
88
+ // An item that is a mapping: its first key sits on the item's line.
89
+ const shifted = [{ indent: indent + (line.text.length - rest.length), text: rest }];
90
+ const inner = { i: 0 };
91
+ const own = [...shifted];
92
+ while (at.i < lines.length && lines[at.i].indent > indent)
93
+ own.push(lines[at.i++]);
94
+ out.push(mapping(own, inner, shifted[0].indent));
95
+ if (inner.i < own.length)
96
+ throw new Unreadable();
97
+ }
98
+ else
99
+ out.push(inline(rest));
100
+ }
101
+ return out;
102
+ }
103
+ /** The more-indented block after a line that ends in `:` or `-`, or null when none follows. */
104
+ function nested(lines, at, indent) {
105
+ const next = lines[at.i];
106
+ if (next === undefined || next.indent <= indent) {
107
+ // A block sequence may sit at its key's own indent.
108
+ if (next !== undefined && next.indent === indent && (next.text === '-' || next.text.startsWith('- '))) {
109
+ return sequence(lines, at, indent);
110
+ }
111
+ return null;
112
+ }
113
+ return block(lines, at, next.indent);
114
+ }
115
+ function mapping(lines, at, indent) {
116
+ const out = {};
117
+ while (at.i < lines.length) {
118
+ const line = lines[at.i];
119
+ if (line.indent < indent)
120
+ break;
121
+ if (line.indent > indent)
122
+ throw new Unreadable();
123
+ const found = keyOf(line.text);
124
+ if (found === null)
125
+ throw new Unreadable();
126
+ const { key, rest } = found;
127
+ at.i++;
128
+ const value = rest === '' ? nested(lines, at, indent) : inline(rest);
129
+ Object.defineProperty(out, key, { value, enumerable: true, writable: true, configurable: true });
130
+ }
131
+ return out;
132
+ }
133
+ /** A mapping line's key and the text after its `:`, or null when the line is no `key:` line. */
134
+ function keyOf(text) {
135
+ if (text.startsWith('"') || text.startsWith("'")) {
136
+ const { value, end } = quoted(text, 0);
137
+ const after = text.slice(end).trimStart();
138
+ if (!after.startsWith(':'))
139
+ return null;
140
+ if (after.length > 1 && after[1] !== ' ')
141
+ return null;
142
+ return { key: value, rest: after.slice(1).trim() };
143
+ }
144
+ if (/^[[{&*!|>%@`]/.test(text))
145
+ return null;
146
+ for (let i = 0; i < text.length; i++) {
147
+ if (text[i] === ':' && (i + 1 === text.length || text[i + 1] === ' ')) {
148
+ return { key: text.slice(0, i).trimEnd(), rest: text.slice(i + 1).trim() };
149
+ }
150
+ }
151
+ return null;
152
+ }
153
+ /** A value written on its key's line: a flow collection or a scalar. */
154
+ function inline(text) {
155
+ if (/^[&*!|>]/.test(text))
156
+ throw new Unreadable();
157
+ const at = { i: 0 };
158
+ const value = flow(text, at);
159
+ if (text.slice(at.i).trim() !== '')
160
+ throw new Unreadable();
161
+ return value;
162
+ }
163
+ /** A flow value at `at.i`: `{…}`, `[…]`, a quoted scalar, or a plain scalar that ends at `,`, `]` or `}`. */
164
+ function flow(text, at, inCollection = false) {
165
+ skipSpaces(text, at);
166
+ const c = text[at.i];
167
+ if (c === '{') {
168
+ at.i++;
169
+ const out = {};
170
+ for (;;) {
171
+ skipSpaces(text, at);
172
+ if (text[at.i] === '}') {
173
+ at.i++;
174
+ return out;
175
+ }
176
+ const key = flowScalar(text, at, true);
177
+ skipSpaces(text, at);
178
+ let value = null;
179
+ if (text[at.i] === ':') {
180
+ at.i++;
181
+ value = flow(text, at, true);
182
+ }
183
+ Object.defineProperty(out, key ?? '', { value, enumerable: true, writable: true, configurable: true });
184
+ skipSpaces(text, at);
185
+ if (text[at.i] === ',')
186
+ at.i++;
187
+ else if (text[at.i] !== '}')
188
+ throw new Unreadable();
189
+ }
190
+ }
191
+ if (c === '[') {
192
+ at.i++;
193
+ const out = [];
194
+ for (;;) {
195
+ skipSpaces(text, at);
196
+ if (text[at.i] === ']') {
197
+ at.i++;
198
+ return out;
199
+ }
200
+ out.push(flow(text, at, true));
201
+ skipSpaces(text, at);
202
+ if (text[at.i] === ',')
203
+ at.i++;
204
+ else if (text[at.i] !== ']')
205
+ throw new Unreadable();
206
+ }
207
+ }
208
+ return flowScalar(text, at, inCollection);
209
+ }
210
+ function flowScalar(text, at, inCollection) {
211
+ skipSpaces(text, at);
212
+ const c = text[at.i];
213
+ if (c === '"' || c === "'") {
214
+ const { value, end } = quoted(text, at.i);
215
+ at.i = end;
216
+ return value;
217
+ }
218
+ const start = at.i;
219
+ while (at.i < text.length) {
220
+ const d = text[at.i];
221
+ if (inCollection && (d === ',' || d === ']' || d === '}'))
222
+ break;
223
+ if (inCollection && d === ':' && (at.i + 1 === text.length || /[\s,\]}]/.test(text[at.i + 1])))
224
+ break;
225
+ at.i++;
226
+ }
227
+ const plain = text.slice(start, at.i).trim();
228
+ if (plain === '')
229
+ return inCollection ? null : '';
230
+ return plain === '~' || plain === 'null' ? null : plain;
231
+ }
232
+ /** A quoted scalar starting at `start`: its value and the index after its closing quote. */
233
+ function quoted(text, start) {
234
+ const quote = text[start];
235
+ let value = '';
236
+ for (let i = start + 1; i < text.length; i++) {
237
+ const c = text[i];
238
+ if (quote === "'") {
239
+ if (c === "'") {
240
+ if (text[i + 1] === "'") {
241
+ value += "'";
242
+ i++;
243
+ continue;
244
+ }
245
+ return { value, end: i + 1 };
246
+ }
247
+ value += c;
248
+ }
249
+ else {
250
+ if (c === '"')
251
+ return { value, end: i + 1 };
252
+ if (c === '\\') {
253
+ const e = text[++i];
254
+ const escapes = { n: '\n', t: '\t', '"': '"', '\\': '\\', '/': '/', '0': '\0', r: '\r' };
255
+ if (e === 'u' || e === 'x') {
256
+ const length = e === 'u' ? 4 : 2;
257
+ const hex = text.slice(i + 1, i + 1 + length);
258
+ if (!/^[0-9a-fA-F]+$/.test(hex) || hex.length !== length)
259
+ throw new Unreadable();
260
+ value += String.fromCharCode(parseInt(hex, 16));
261
+ i += length;
262
+ }
263
+ else if (e !== undefined && e in escapes)
264
+ value += escapes[e];
265
+ else
266
+ throw new Unreadable();
267
+ }
268
+ else
269
+ value += c;
270
+ }
271
+ }
272
+ throw new Unreadable();
273
+ }
274
+ function skipSpaces(text, at) {
275
+ while (at.i < text.length && text[at.i] === ' ')
276
+ at.i++;
277
+ }
@@ -0,0 +1,7 @@
1
+ import { type ReadLockfile } from './lockfile-graph.ts';
2
+ /** The manifests a `yarn.lock` needs besides its own directory's: Berry's workspace folders, or v1's globs. */
3
+ export declare function yarnManifests(text: string, root: string | null): {
4
+ folders: string[];
5
+ globs: string[];
6
+ };
7
+ export declare function readYarn(text: string, file: string, manifests: Readonly<Record<string, string | null>>): ReadLockfile;