@stll/oxlint-config 1.4.0 → 1.5.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 (69) hide show
  1. package/README.md +90 -14
  2. package/dist/cloud-setup-cli.cjs +3 -3
  3. package/dist/cloud-setup-cli.mjs +3 -3
  4. package/dist/consumer-compat-cli.cjs +2 -2
  5. package/dist/consumer-compat-cli.mjs +2 -2
  6. package/dist/dependabot-cli.cjs +34 -10
  7. package/dist/dependabot-cli.cjs.map +1 -1
  8. package/dist/dependabot-cli.mjs +35 -11
  9. package/dist/dependabot-cli.mjs.map +1 -1
  10. package/dist/dependabot.cjs +2 -0
  11. package/dist/dependabot.d.cts +12 -2
  12. package/dist/dependabot.d.mts +12 -2
  13. package/dist/dependabot.mjs +2 -2
  14. package/dist/generated-file.cjs +2 -2
  15. package/dist/generated-file.mjs +2 -2
  16. package/dist/git-tracked-output.cjs +2 -2
  17. package/dist/git-tracked-output.mjs +1 -1
  18. package/dist/jsonc.cjs +66 -0
  19. package/dist/jsonc.cjs.map +1 -0
  20. package/dist/jsonc.mjs +61 -0
  21. package/dist/jsonc.mjs.map +1 -0
  22. package/dist/publish-artifact-syntax.cjs +2 -2
  23. package/dist/publish-artifact-syntax.mjs +2 -2
  24. package/dist/publish-build-target-vite-dts-helper2.cjs +1 -1
  25. package/dist/publish-build-target-vite-dts-helper2.mjs +1 -1
  26. package/dist/publish-contract-cli.cjs +2 -2
  27. package/dist/publish-contract-cli.mjs +1 -1
  28. package/dist/quarantine-cli.cjs +66 -0
  29. package/dist/quarantine-cli.cjs.map +1 -0
  30. package/dist/quarantine-cli.d.cts +1 -0
  31. package/dist/quarantine-cli.d.mts +1 -0
  32. package/dist/quarantine-cli.mjs +66 -0
  33. package/dist/quarantine-cli.mjs.map +1 -0
  34. package/dist/quarantine-policy.cjs +10 -0
  35. package/dist/quarantine-policy.d.cts +27 -0
  36. package/dist/quarantine-policy.d.mts +27 -0
  37. package/dist/quarantine-policy.mjs +1 -0
  38. package/dist/quarantine-policy2.cjs +399 -0
  39. package/dist/quarantine-policy2.cjs.map +1 -0
  40. package/dist/quarantine-policy2.mjs +352 -0
  41. package/dist/quarantine-policy2.mjs.map +1 -0
  42. package/dist/toolchain-changed.cjs +11 -66
  43. package/dist/toolchain-changed.cjs.map +1 -1
  44. package/dist/toolchain-changed.mjs +13 -68
  45. package/dist/toolchain-changed.mjs.map +1 -1
  46. package/dist/toolchain-check-cli.cjs +1 -0
  47. package/dist/toolchain-check-cli.cjs.map +1 -1
  48. package/dist/toolchain-check-cli.mjs +1 -0
  49. package/dist/toolchain-check-cli.mjs.map +1 -1
  50. package/dist/toolchain-dependabot.cjs +77 -3
  51. package/dist/toolchain-dependabot.cjs.map +1 -1
  52. package/dist/toolchain-dependabot.mjs +66 -4
  53. package/dist/toolchain-dependabot.mjs.map +1 -1
  54. package/dist/toolchain-guard.cjs +49 -10
  55. package/dist/toolchain-guard.cjs.map +1 -1
  56. package/dist/toolchain-guard.mjs +51 -12
  57. package/dist/toolchain-guard.mjs.map +1 -1
  58. package/dist/toolchain-inputs.cjs +104 -18
  59. package/dist/toolchain-inputs.cjs.map +1 -1
  60. package/dist/toolchain-inputs.mjs +106 -20
  61. package/dist/toolchain-inputs.mjs.map +1 -1
  62. package/dist/typecheck-parity.cjs +4 -3
  63. package/dist/typecheck-parity.cjs.map +1 -1
  64. package/dist/typecheck-parity.mjs +4 -3
  65. package/dist/typecheck-parity.mjs.map +1 -1
  66. package/dist/typecheck-probe-cli.cjs +2 -2
  67. package/dist/typecheck-probe-cli.mjs +2 -2
  68. package/package.json +13 -1
  69. package/toolchain.json +11 -4
@@ -0,0 +1,352 @@
1
+ import { t as parseJsonc } from "./jsonc.mjs";
2
+ import { parse } from "smol-toml";
3
+ //#region src/quarantine-policy-core.ts
4
+ const REQUIRED_RELEASE_AGE_SECONDS = 432e3;
5
+ const NPM_REGISTRY = "https://registry.npmjs.org";
6
+ const EXACT_UTC_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u;
7
+ const HOUR_MS = 36e5;
8
+ const EXACT_PACKAGE = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u;
9
+ const REGISTRY_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u;
10
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
11
+ const fail = (message) => {
12
+ throw new Error(message);
13
+ };
14
+ const ownPackage = (name) => name.startsWith("@stll/");
15
+ const exactPackage = (name) => name.length <= 214 && EXACT_PACKAGE.test(name);
16
+ const isFirstPartyPackageName = (name) => exactPackage(name) && ownPackage(name);
17
+ const exactTimestamp = (value) => {
18
+ const timestamp = Date.parse(value);
19
+ return EXACT_UTC_TIMESTAMP.test(value) && !Number.isNaN(timestamp) && new Date(timestamp).toISOString() === value;
20
+ };
21
+ const readParsedExcludes = (bunfig, parseToml) => {
22
+ const parsed = parseToml(bunfig);
23
+ if (!isRecord(parsed) || !isRecord(parsed["install"])) return fail("bunfig.toml must contain an [install] table");
24
+ const install = parsed["install"];
25
+ if ("registry" in install && install["registry"] !== "https://registry.npmjs.org" || "scopes" in install && (!isRecord(install["scopes"]) || Object.keys(install["scopes"]).length > 0)) fail("bunfig.toml quarantine policy requires the canonical npm registry");
26
+ if (install["minimumReleaseAge"] !== 432e3) fail(`bunfig.toml must set minimumReleaseAge = ${REQUIRED_RELEASE_AGE_SECONDS}`);
27
+ if (!Array.isArray(install["minimumReleaseAgeExcludes"])) return fail("bunfig.toml must declare minimumReleaseAgeExcludes as an array");
28
+ const names = [];
29
+ for (const value of install["minimumReleaseAgeExcludes"]) {
30
+ if (typeof value !== "string" || !exactPackage(value)) return fail("bunfig.toml minimumReleaseAgeExcludes must contain only exact npm package names");
31
+ names.push(value);
32
+ }
33
+ if (new Set(names).size !== names.length) fail("bunfig.toml minimumReleaseAgeExcludes must not contain duplicates");
34
+ return names;
35
+ };
36
+ const tokensOf = (text) => {
37
+ const tokens = [];
38
+ let index = 0;
39
+ while (index < text.length) {
40
+ const start = index;
41
+ const character = text.charAt(index++);
42
+ if (character === "\n") {
43
+ tokens.push({
44
+ type: "newline",
45
+ start,
46
+ end: index,
47
+ text: character
48
+ });
49
+ continue;
50
+ }
51
+ if (/\s/u.test(character)) continue;
52
+ let type;
53
+ if (character === "#") {
54
+ type = "comment";
55
+ while (index < text.length && text.charAt(index) !== "\n") index++;
56
+ } else if (character === "\"" || character === "'") {
57
+ type = "string";
58
+ const triple = text.slice(start, start + 3) === character.repeat(3);
59
+ if (triple) index = start + 3;
60
+ while (index < text.length) {
61
+ const current = text.charAt(index++);
62
+ if (character === "\"" && current === "\\") {
63
+ index++;
64
+ continue;
65
+ }
66
+ if (current !== character) continue;
67
+ if (!triple) break;
68
+ if (text.slice(index - 1, index + 2) !== character.repeat(3)) continue;
69
+ index += 2;
70
+ while (text.charAt(index) === character) index++;
71
+ break;
72
+ }
73
+ } else if ("[]=.,{}".includes(character)) type = "punctuation";
74
+ else {
75
+ type = "atom";
76
+ while (index < text.length && !/[\s#[\]=.,{}"']/u.test(text.charAt(index))) index++;
77
+ }
78
+ tokens.push({
79
+ type,
80
+ start,
81
+ end: index,
82
+ text: type === "comment" ? text.slice(start, index).replace(/\r$/u, "") : text.slice(start, index)
83
+ });
84
+ }
85
+ return tokens;
86
+ };
87
+ const stringValue = (token, parseToml) => {
88
+ const parsed = parseToml(`value = ${token.text}`);
89
+ if (!isRecord(parsed) || typeof parsed["value"] !== "string") return fail("bunfig.toml has an unsupported quarantine string");
90
+ return parsed["value"];
91
+ };
92
+ const keyParts = (tokens, parseToml) => tokens.filter(({ text }) => text !== ".").map((token) => token.type === "string" ? stringValue(token, parseToml) : token.text);
93
+ const readSourceArray = (bunfig, parseToml) => {
94
+ const names = readParsedExcludes(bunfig, parseToml);
95
+ let table = [];
96
+ let statement = [];
97
+ let depth = 0;
98
+ let found;
99
+ const visitStatement = () => {
100
+ const meaningful = statement.filter(({ type }) => type !== "comment" && type !== "newline");
101
+ if (meaningful.at(0)?.text === "[") {
102
+ if (meaningful.at(-1)?.text === "]") table = keyParts(meaningful.slice(1, -1), parseToml);
103
+ return;
104
+ }
105
+ const equals = meaningful.findIndex(({ text }) => text === "=");
106
+ if (equals < 0) return;
107
+ const key = [...table, ...keyParts(meaningful.slice(0, equals), parseToml)];
108
+ if (key.join(".") !== "install.minimumReleaseAgeExcludes" || key.length !== 2) return;
109
+ const open = meaningful.at(equals + 1);
110
+ const close = meaningful.at(-1);
111
+ if (open === void 0 || close === void 0 || open.text !== "[" || close.text !== "]" || found !== void 0) fail("bunfig.toml must declare a single install minimumReleaseAgeExcludes array");
112
+ const values = meaningful.slice(equals + 2, -1);
113
+ if (values.some(({ type, text }) => type !== "string" && text !== ",")) fail("bunfig.toml quarantine array must contain package strings");
114
+ const strings = values.filter(({ type }) => type === "string");
115
+ const comments = statement.filter(({ type }) => type === "comment");
116
+ const entries = strings.map((token, index) => {
117
+ const next = strings.at(index + 1)?.start ?? Number.POSITIVE_INFINITY;
118
+ const comment = comments.find((candidate) => candidate.start >= token.end && candidate.start < next && !bunfig.slice(token.end, candidate.start).includes("\n"));
119
+ const following = values.find((candidate) => candidate.start >= token.end);
120
+ return {
121
+ name: stringValue(token, parseToml),
122
+ token,
123
+ comment,
124
+ comma: following?.text === "," ? following : void 0
125
+ };
126
+ });
127
+ if (entries.length !== names.length || entries.some(({ name }, index) => name !== names.at(index))) fail("bunfig.toml quarantine source does not match its parsed install array");
128
+ found = {
129
+ open,
130
+ close,
131
+ entries,
132
+ comments
133
+ };
134
+ };
135
+ for (const token of tokensOf(bunfig)) {
136
+ if (token.type === "newline" && depth === 0) {
137
+ visitStatement();
138
+ statement = [];
139
+ continue;
140
+ }
141
+ statement.push(token);
142
+ if (token.type !== "punctuation") continue;
143
+ if (token.text === "[" || token.text === "{") depth++;
144
+ if (token.text === "]" || token.text === "}") depth--;
145
+ }
146
+ visitStatement();
147
+ if (found === void 0) return fail("bunfig.toml must declare an explicit [install] minimumReleaseAgeExcludes array");
148
+ return found;
149
+ };
150
+ const annotationOf = ({ comment }) => {
151
+ if (comment === void 0) return { type: "none" };
152
+ const match = /^#\s*quarantine-(expires|excluded-since):\s*(\S+)\s*$/u.exec(comment.text);
153
+ const marker = match?.at(1);
154
+ const timestamp = match?.at(2);
155
+ if ((marker === "expires" || marker === "excluded-since") && timestamp !== void 0) return {
156
+ type: marker,
157
+ timestamp
158
+ };
159
+ return { type: "invalid" };
160
+ };
161
+ const readRegistryFirstPartyPackages = (lockfile) => {
162
+ if (lockfile === void 0) return /* @__PURE__ */ new Set();
163
+ const parsed = parseJsonc(lockfile);
164
+ if (!isRecord(parsed) || !isRecord(parsed["packages"])) return fail("bun.lock must contain a packages mapping");
165
+ const names = /* @__PURE__ */ new Set();
166
+ for (const value of Object.values(parsed["packages"])) {
167
+ if (!Array.isArray(value)) continue;
168
+ const identity = value.at(0);
169
+ if (typeof identity !== "string") continue;
170
+ const separator = identity.lastIndexOf("@");
171
+ const name = identity.slice(0, separator);
172
+ if (exactPackage(name) && ownPackage(name) && REGISTRY_VERSION.test(identity.slice(separator + 1))) names.add(name);
173
+ }
174
+ return names;
175
+ };
176
+ const ownNames = (names) => {
177
+ const result = new Set(names);
178
+ for (const name of result) if (!exactPackage(name) || !ownPackage(name)) fail(`Expected an exact first-party npm package name: ${name}`);
179
+ return result;
180
+ };
181
+ const validNow = (now) => {
182
+ if (!Number.isFinite(now.getTime())) return fail("Quarantine policy requires a valid current date");
183
+ return now.getTime();
184
+ };
185
+ const checkQuarantinePolicy = ({ bunfig, lockfile, parseToml, npmrcPresent = false, now = /* @__PURE__ */ new Date(), firstPartyPackages }) => {
186
+ const errors = [];
187
+ const warnings = [];
188
+ try {
189
+ const nowMs = validNow(now);
190
+ const { entries } = readSourceArray(bunfig, parseToml);
191
+ if (npmrcPresent) errors.push("bunfig.toml quarantine policy does not allow a repository .npmrc");
192
+ for (const entry of entries) {
193
+ const annotation = annotationOf(entry);
194
+ if (ownPackage(entry.name) && annotation.type === "none") continue;
195
+ if (annotation.type === "none" || annotation.type === "invalid") {
196
+ errors.push(`bunfig.toml has an unannotated or malformed quarantine exclude: ${entry.name}`);
197
+ continue;
198
+ }
199
+ if (!exactTimestamp(annotation.timestamp)) {
200
+ errors.push(`bunfig.toml quarantine exclude "${entry.name}" has an invalid UTC timestamp: ${annotation.timestamp}`);
201
+ continue;
202
+ }
203
+ const timestampMs = Date.parse(annotation.timestamp);
204
+ if (ownPackage(entry.name)) {
205
+ if (annotation.type !== "excluded-since") errors.push(`bunfig.toml first-party quarantine exclude "${entry.name}" must be permanent (quarantine-excluded-since: or no timestamp)`);
206
+ else if (timestampMs > nowMs) errors.push(`bunfig.toml first-party quarantine exclude "${entry.name}" has a future exclusion date`);
207
+ continue;
208
+ }
209
+ if (annotation.type !== "expires") {
210
+ errors.push(`bunfig.toml third-party quarantine exclude "${entry.name}" must use quarantine-expires:`);
211
+ continue;
212
+ }
213
+ if (nowMs >= timestampMs + 24 * HOUR_MS) errors.push(`bunfig.toml temporary quarantine exclude "${entry.name}" expired at ${annotation.timestamp} and is still present`);
214
+ else if (nowMs >= timestampMs) warnings.push(`bunfig.toml temporary quarantine exclude "${entry.name}" expired at ${annotation.timestamp}; its removal PR should be merged`);
215
+ else if (nowMs >= timestampMs - 48 * HOUR_MS) warnings.push(`bunfig.toml temporary quarantine exclude "${entry.name}" expires at ${annotation.timestamp}; prepare its removal PR`);
216
+ }
217
+ const required = readRegistryFirstPartyPackages(lockfile);
218
+ if (firstPartyPackages !== void 0) for (const name of ownNames(firstPartyPackages)) required.add(name);
219
+ const declared = new Set(entries.map(({ name }) => name));
220
+ const missing = [...required].filter((name) => !declared.has(name)).sort();
221
+ if (missing.length > 0) errors.push(`bunfig.toml is missing registry-backed first-party quarantine excludes: ${missing.join(", ")}`);
222
+ } catch (error) {
223
+ errors.push(error instanceof Error ? error.message : String(error));
224
+ }
225
+ return {
226
+ errors,
227
+ warnings
228
+ };
229
+ };
230
+ const pruneExpiredExcludes = ({ bunfig, parseToml, now = /* @__PURE__ */ new Date() }) => {
231
+ const nowMs = validNow(now);
232
+ const { entries, close } = readSourceArray(bunfig, parseToml);
233
+ const removals = [];
234
+ const pruned = [];
235
+ for (const entry of entries) {
236
+ if (ownPackage(entry.name)) continue;
237
+ const annotation = annotationOf(entry);
238
+ if (annotation.type !== "expires" || !exactTimestamp(annotation.timestamp)) return fail(`bunfig.toml third-party quarantine exclude "${entry.name}" must have an exact UTC quarantine-expires: annotation`);
239
+ if (nowMs < Date.parse(annotation.timestamp)) continue;
240
+ const lineStart = bunfig.lastIndexOf("\n", entry.token.start - 1) + 1;
241
+ const nextNewline = bunfig.indexOf("\n", entry.token.end);
242
+ const lineEnd = nextNewline < 0 ? bunfig.length : nextNewline;
243
+ const commentInside = entry.comment !== void 0 && entry.comment.start < close.start;
244
+ const end = commentInside ? entry.comment?.end ?? entry.token.end : entry.comma?.end ?? entry.token.end;
245
+ if (bunfig.slice(lineStart, entry.token.start).trim() === "" && bunfig.slice(end, lineEnd).trim() === "") removals.push({
246
+ start: lineStart,
247
+ end: nextNewline < 0 ? lineEnd : lineEnd + 1
248
+ });
249
+ else removals.push({
250
+ start: entry.token.start,
251
+ end
252
+ });
253
+ if (entry.comment !== void 0 && !commentInside) removals.push({
254
+ start: entry.comment.start,
255
+ end: entry.comment.end
256
+ });
257
+ pruned.push(entry.name);
258
+ }
259
+ let result = bunfig;
260
+ for (const removal of removals.toReversed()) result = result.slice(0, removal.start) + result.slice(removal.end);
261
+ readSourceArray(result, parseToml);
262
+ return {
263
+ bunfig: result,
264
+ pruned
265
+ };
266
+ };
267
+ const synchronizeFirstPartyExcludes = ({ bunfig, firstPartyPackages, parseToml, now = /* @__PURE__ */ new Date() }) => {
268
+ validNow(now);
269
+ const required = ownNames(firstPartyPackages);
270
+ const { open, close, entries, comments } = readSourceArray(bunfig, parseToml);
271
+ const attachedComments = new Set(entries.flatMap(({ comment }) => comment === void 0 ? [] : [comment]));
272
+ const lines = comments.filter((comment) => !attachedComments.has(comment)).map(({ text }) => ` ${text}`);
273
+ const seen = /* @__PURE__ */ new Set();
274
+ for (const entry of entries) {
275
+ if (!ownPackage(entry.name)) {
276
+ const annotation = annotationOf(entry);
277
+ if (annotation.type !== "expires" || !exactTimestamp(annotation.timestamp)) return fail(`bunfig.toml third-party quarantine exclude "${entry.name}" must have an exact UTC quarantine-expires: annotation`);
278
+ lines.push(` ${entry.token.text},${entry.comment === void 0 ? "" : ` ${entry.comment.text}`}`);
279
+ continue;
280
+ }
281
+ if (!required.has(entry.name)) continue;
282
+ seen.add(entry.name);
283
+ const annotation = annotationOf(entry);
284
+ const timestamp = annotation.type === "excluded-since" && exactTimestamp(annotation.timestamp) ? annotation.timestamp : now.toISOString();
285
+ lines.push(` ${JSON.stringify(entry.name)}, # quarantine-excluded-since: ${timestamp}`);
286
+ }
287
+ for (const name of [...required].filter((requiredPackage) => !seen.has(requiredPackage)).sort()) lines.push(` ${JSON.stringify(name)}, # quarantine-excluded-since: ${now.toISOString()}`);
288
+ const newline = bunfig.includes("\r\n") ? "\r\n" : "\n";
289
+ const trailingComment = entries.at(-1)?.comment;
290
+ const end = trailingComment !== void 0 && trailingComment.start > close.end ? trailingComment.end : close.end;
291
+ const result = bunfig.slice(0, open.start) + `[${newline}${lines.join(newline)}${lines.length === 0 ? "" : newline}]` + bunfig.slice(end);
292
+ readSourceArray(result, parseToml);
293
+ return result;
294
+ };
295
+ //#endregion
296
+ //#region src/quarantine-policy.ts
297
+ const record = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
298
+ /** Derive exact registry identities before install, including catalog references. */
299
+ const declaredFirstPartyPackages = (files) => {
300
+ const names = /* @__PURE__ */ new Set();
301
+ for (const [file, text] of Object.entries(files)) {
302
+ if (!/(?:^|\/)package\.json$/.test(file)) continue;
303
+ const manifest = JSON.parse(text);
304
+ if (!record(manifest)) throw new Error(`${file} must contain an object`);
305
+ for (const field of [
306
+ "dependencies",
307
+ "devDependencies",
308
+ "optionalDependencies",
309
+ "peerDependencies"
310
+ ]) {
311
+ const dependencies = manifest[field];
312
+ if (!record(dependencies)) continue;
313
+ for (const [name, specifier] of Object.entries(dependencies)) {
314
+ if (typeof specifier !== "string") continue;
315
+ if (/^(?:workspace:|file:|link:|git(?:\+|:)|https?:|github:|\.\.?\/|\/)/.test(specifier)) continue;
316
+ if (specifier.startsWith("npm:")) {
317
+ const alias = /^npm:(@[^/]+\/[^@]+|[^@]+)@/.exec(specifier)?.at(1);
318
+ if (alias !== void 0 && isFirstPartyPackageName(alias)) names.add(alias);
319
+ continue;
320
+ }
321
+ if (isFirstPartyPackageName(name)) names.add(name);
322
+ }
323
+ }
324
+ }
325
+ return names;
326
+ };
327
+ const checkRepositoryQuarantine = ({ files, now, npmrcPresent }) => checkQuarantinePolicy({
328
+ bunfig: files["bunfig.toml"] ?? "",
329
+ lockfile: files["bun.lock"],
330
+ firstPartyPackages: declaredFirstPartyPackages(files),
331
+ parseToml: parse,
332
+ ...now === void 0 ? {} : { now },
333
+ ...npmrcPresent === void 0 ? {} : { npmrcPresent }
334
+ });
335
+ const synchronizeRepositoryQuarantine = ({ files, now }) => {
336
+ const firstPartyPackages = /* @__PURE__ */ new Set([...declaredFirstPartyPackages(files), ...readRegistryFirstPartyPackages(files["bun.lock"])]);
337
+ return synchronizeFirstPartyExcludes({
338
+ bunfig: files["bunfig.toml"] ?? `[install]\nminimumReleaseAge = 432000\nminimumReleaseAgeExcludes = []\n`,
339
+ firstPartyPackages,
340
+ parseToml: parse,
341
+ ...now === void 0 ? {} : { now }
342
+ });
343
+ };
344
+ const pruneRepositoryQuarantine = ({ files, now }) => pruneExpiredExcludes({
345
+ bunfig: files["bunfig.toml"] ?? "",
346
+ parseToml: parse,
347
+ ...now === void 0 ? {} : { now }
348
+ });
349
+ //#endregion
350
+ export { EXACT_UTC_TIMESTAMP as a, exactTimestamp as c, synchronizeRepositoryQuarantine as i, declaredFirstPartyPackages as n, NPM_REGISTRY as o, pruneRepositoryQuarantine as r, REQUIRED_RELEASE_AGE_SECONDS as s, checkRepositoryQuarantine as t };
351
+
352
+ //# sourceMappingURL=quarantine-policy2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quarantine-policy2.mjs","names":[],"sources":["../src/quarantine-policy-core.ts","../src/quarantine-policy.ts"],"sourcesContent":["import { parseJsonc } from \"./jsonc\";\n\nexport const REQUIRED_RELEASE_AGE_SECONDS = 5 * 24 * 60 * 60;\nexport const NPM_REGISTRY = \"https://registry.npmjs.org\";\nexport const EXACT_UTC_TIMESTAMP =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/u;\nconst HOUR_MS = 60 * 60 * 1000;\nconst EXACT_PACKAGE = /^(?:@[a-z0-9][a-z0-9._-]*\\/)?[a-z0-9][a-z0-9._-]*$/u;\nconst REGISTRY_VERSION =\n /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/u;\n\ntype ParseToml = (text: string) => unknown;\ntype FirstPartyPackages = ReadonlySet<string> | readonly string[];\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\nconst fail: (message: string) => never = (message) => {\n throw new Error(message);\n};\nconst ownPackage = (name: string) => name.startsWith(\"@stll/\");\nconst exactPackage = (name: string) =>\n name.length <= 214 && EXACT_PACKAGE.test(name);\nexport const isFirstPartyPackageName = (name: string): boolean =>\n exactPackage(name) && ownPackage(name);\n\nexport const exactTimestamp = (value: string): boolean => {\n const timestamp = Date.parse(value);\n return (\n EXACT_UTC_TIMESTAMP.test(value) &&\n !Number.isNaN(timestamp) &&\n new Date(timestamp).toISOString() === value\n );\n};\n\nexport const readParsedExcludes = (\n bunfig: string,\n parseToml: ParseToml,\n): string[] => {\n const parsed = parseToml(bunfig);\n if (!isRecord(parsed) || !isRecord(parsed[\"install\"]))\n return fail(\"bunfig.toml must contain an [install] table\");\n const install = parsed[\"install\"];\n if (\n (\"registry\" in install && install[\"registry\"] !== NPM_REGISTRY) ||\n (\"scopes\" in install &&\n (!isRecord(install[\"scopes\"]) ||\n Object.keys(install[\"scopes\"]).length > 0))\n )\n fail(\"bunfig.toml quarantine policy requires the canonical npm registry\");\n if (install[\"minimumReleaseAge\"] !== REQUIRED_RELEASE_AGE_SECONDS)\n fail(\n `bunfig.toml must set minimumReleaseAge = ${REQUIRED_RELEASE_AGE_SECONDS}`,\n );\n if (!Array.isArray(install[\"minimumReleaseAgeExcludes\"]))\n return fail(\n \"bunfig.toml must declare minimumReleaseAgeExcludes as an array\",\n );\n const names: string[] = [];\n for (const value of install[\"minimumReleaseAgeExcludes\"]) {\n if (typeof value !== \"string\" || !exactPackage(value))\n return fail(\n \"bunfig.toml minimumReleaseAgeExcludes must contain only exact npm package names\",\n );\n names.push(value);\n }\n if (new Set(names).size !== names.length)\n fail(\"bunfig.toml minimumReleaseAgeExcludes must not contain duplicates\");\n return names;\n};\n\ntype Token = {\n type: \"string\" | \"atom\" | \"punctuation\" | \"comment\" | \"newline\";\n start: number;\n end: number;\n text: string;\n};\n// Tokenize before locating declarations: text in comments, multiline strings and\n// unrelated tables cannot masquerade as the install policy's source array.\nconst tokensOf = (text: string): Token[] => {\n const tokens: Token[] = [];\n let index = 0;\n while (index < text.length) {\n const start = index;\n const character = text.charAt(index++);\n if (character === \"\\n\") {\n tokens.push({ type: \"newline\", start, end: index, text: character });\n continue;\n }\n if (/\\s/u.test(character)) continue;\n let type: Token[\"type\"];\n if (character === \"#\") {\n type = \"comment\";\n while (index < text.length && text.charAt(index) !== \"\\n\") index++;\n } else if (character === '\"' || character === \"'\") {\n type = \"string\";\n const triple = text.slice(start, start + 3) === character.repeat(3);\n if (triple) index = start + 3;\n while (index < text.length) {\n const current = text.charAt(index++);\n if (character === '\"' && current === \"\\\\\") {\n index++;\n continue;\n }\n if (current !== character) continue;\n if (!triple) break;\n if (text.slice(index - 1, index + 2) !== character.repeat(3)) continue;\n index += 2;\n while (text.charAt(index) === character) index++;\n break;\n }\n } else if (\"[]=.,{}\".includes(character)) type = \"punctuation\";\n else {\n type = \"atom\";\n while (\n index < text.length &&\n !/[\\s#[\\]=.,{}\"']/u.test(text.charAt(index))\n )\n index++;\n }\n tokens.push({\n type,\n start,\n end: index,\n text:\n type === \"comment\"\n ? text.slice(start, index).replace(/\\r$/u, \"\")\n : text.slice(start, index),\n });\n }\n return tokens;\n};\n\nconst stringValue = (token: Token, parseToml: ParseToml): string => {\n const parsed = parseToml(`value = ${token.text}`);\n if (!isRecord(parsed) || typeof parsed[\"value\"] !== \"string\")\n return fail(\"bunfig.toml has an unsupported quarantine string\");\n return parsed[\"value\"];\n};\nconst keyParts = (tokens: readonly Token[], parseToml: ParseToml): string[] =>\n tokens\n .filter(({ text }) => text !== \".\")\n .map((token) =>\n token.type === \"string\" ? stringValue(token, parseToml) : token.text,\n );\n\ntype Entry = {\n name: string;\n token: Token;\n comment: Token | undefined;\n comma: Token | undefined;\n};\ntype SourceArray = {\n open: Token;\n close: Token;\n entries: Entry[];\n comments: Token[];\n};\nconst readSourceArray = (bunfig: string, parseToml: ParseToml): SourceArray => {\n const names = readParsedExcludes(bunfig, parseToml);\n let table: string[] = [];\n let statement: Token[] = [];\n let depth = 0;\n let found: SourceArray | undefined;\n const visitStatement = () => {\n const meaningful = statement.filter(\n ({ type }) => type !== \"comment\" && type !== \"newline\",\n );\n const first = meaningful.at(0);\n if (first?.text === \"[\") {\n const end = meaningful.at(-1);\n if (end?.text === \"]\")\n table = keyParts(meaningful.slice(1, -1), parseToml);\n return;\n }\n const equals = meaningful.findIndex(({ text }) => text === \"=\");\n if (equals < 0) return;\n const key = [...table, ...keyParts(meaningful.slice(0, equals), parseToml)];\n if (\n key.join(\".\") !== \"install.minimumReleaseAgeExcludes\" ||\n key.length !== 2\n )\n return;\n const open = meaningful.at(equals + 1);\n const close = meaningful.at(-1);\n if (\n open === undefined ||\n close === undefined ||\n open.text !== \"[\" ||\n close.text !== \"]\" ||\n found !== undefined\n )\n fail(\n \"bunfig.toml must declare a single install minimumReleaseAgeExcludes array\",\n );\n const values = meaningful.slice(equals + 2, -1);\n if (values.some(({ type, text }) => type !== \"string\" && text !== \",\"))\n fail(\"bunfig.toml quarantine array must contain package strings\");\n const strings = values.filter(({ type }) => type === \"string\");\n const comments = statement.filter(({ type }) => type === \"comment\");\n const entries = strings.map((token, index) => {\n const next = strings.at(index + 1)?.start ?? Number.POSITIVE_INFINITY;\n const comment = comments.find(\n (candidate) =>\n candidate.start >= token.end &&\n candidate.start < next &&\n !bunfig.slice(token.end, candidate.start).includes(\"\\n\"),\n );\n const following = values.find(\n (candidate) => candidate.start >= token.end,\n );\n return {\n name: stringValue(token, parseToml),\n token,\n comment,\n comma: following?.text === \",\" ? following : undefined,\n };\n });\n if (\n entries.length !== names.length ||\n entries.some(({ name }, index) => name !== names.at(index))\n )\n fail(\n \"bunfig.toml quarantine source does not match its parsed install array\",\n );\n found = { open, close, entries, comments };\n };\n for (const token of tokensOf(bunfig)) {\n if (token.type === \"newline\" && depth === 0) {\n visitStatement();\n statement = [];\n continue;\n }\n statement.push(token);\n if (token.type !== \"punctuation\") continue;\n if (token.text === \"[\" || token.text === \"{\") depth++;\n if (token.text === \"]\" || token.text === \"}\") depth--;\n }\n visitStatement();\n if (found === undefined)\n return fail(\n \"bunfig.toml must declare an explicit [install] minimumReleaseAgeExcludes array\",\n );\n return found;\n};\n\ntype Annotation =\n | { type: \"none\" }\n | { type: \"invalid\" }\n | { type: \"expires\" | \"excluded-since\"; timestamp: string };\nconst annotationOf = ({ comment }: Entry): Annotation => {\n if (comment === undefined) return { type: \"none\" };\n const match = /^#\\s*quarantine-(expires|excluded-since):\\s*(\\S+)\\s*$/u.exec(\n comment.text,\n );\n const marker = match?.at(1);\n const timestamp = match?.at(2);\n if (\n (marker === \"expires\" || marker === \"excluded-since\") &&\n timestamp !== undefined\n )\n return { type: marker, timestamp };\n return { type: \"invalid\" };\n};\n\nexport const readRegistryFirstPartyPackages = (\n lockfile: string | undefined,\n): Set<string> => {\n if (lockfile === undefined) return new Set();\n const parsed = parseJsonc(lockfile);\n if (!isRecord(parsed) || !isRecord(parsed[\"packages\"]))\n return fail(\"bun.lock must contain a packages mapping\");\n const names = new Set<string>();\n for (const value of Object.values(parsed[\"packages\"])) {\n if (!Array.isArray(value)) continue;\n const identity: unknown = value.at(0);\n if (typeof identity !== \"string\") continue;\n const separator = identity.lastIndexOf(\"@\");\n const name = identity.slice(0, separator);\n if (\n exactPackage(name) &&\n ownPackage(name) &&\n REGISTRY_VERSION.test(identity.slice(separator + 1))\n )\n names.add(name);\n }\n return names;\n};\n\nconst ownNames = (names: FirstPartyPackages): Set<string> => {\n const result = new Set(names);\n for (const name of result)\n if (!exactPackage(name) || !ownPackage(name))\n fail(`Expected an exact first-party npm package name: ${name}`);\n return result;\n};\nconst validNow = (now: Date): number => {\n if (!Number.isFinite(now.getTime()))\n return fail(\"Quarantine policy requires a valid current date\");\n return now.getTime();\n};\nexport type CheckResult = { errors: string[]; warnings: string[] };\ntype CheckOptions = {\n bunfig: string;\n lockfile: string | undefined;\n parseToml: ParseToml;\n npmrcPresent?: boolean;\n now?: Date;\n firstPartyPackages?: FirstPartyPackages;\n};\nexport const checkQuarantinePolicy = ({\n bunfig,\n lockfile,\n parseToml,\n npmrcPresent = false,\n now = new Date(),\n firstPartyPackages,\n}: CheckOptions): CheckResult => {\n const errors: string[] = [];\n const warnings: string[] = [];\n try {\n const nowMs = validNow(now);\n const { entries } = readSourceArray(bunfig, parseToml);\n if (npmrcPresent)\n errors.push(\n \"bunfig.toml quarantine policy does not allow a repository .npmrc\",\n );\n for (const entry of entries) {\n const annotation = annotationOf(entry);\n if (ownPackage(entry.name) && annotation.type === \"none\") continue;\n if (annotation.type === \"none\" || annotation.type === \"invalid\") {\n errors.push(\n `bunfig.toml has an unannotated or malformed quarantine exclude: ${entry.name}`,\n );\n continue;\n }\n if (!exactTimestamp(annotation.timestamp)) {\n errors.push(\n `bunfig.toml quarantine exclude \"${entry.name}\" has an invalid UTC timestamp: ${annotation.timestamp}`,\n );\n continue;\n }\n const timestampMs = Date.parse(annotation.timestamp);\n if (ownPackage(entry.name)) {\n if (annotation.type !== \"excluded-since\")\n errors.push(\n `bunfig.toml first-party quarantine exclude \"${entry.name}\" must be permanent (quarantine-excluded-since: or no timestamp)`,\n );\n else if (timestampMs > nowMs)\n errors.push(\n `bunfig.toml first-party quarantine exclude \"${entry.name}\" has a future exclusion date`,\n );\n continue;\n }\n if (annotation.type !== \"expires\") {\n errors.push(\n `bunfig.toml third-party quarantine exclude \"${entry.name}\" must use quarantine-expires:`,\n );\n continue;\n }\n if (nowMs >= timestampMs + 24 * HOUR_MS)\n errors.push(\n `bunfig.toml temporary quarantine exclude \"${entry.name}\" expired at ${annotation.timestamp} and is still present`,\n );\n else if (nowMs >= timestampMs)\n warnings.push(\n `bunfig.toml temporary quarantine exclude \"${entry.name}\" expired at ${annotation.timestamp}; its removal PR should be merged`,\n );\n else if (nowMs >= timestampMs - 48 * HOUR_MS)\n warnings.push(\n `bunfig.toml temporary quarantine exclude \"${entry.name}\" expires at ${annotation.timestamp}; prepare its removal PR`,\n );\n }\n const required = readRegistryFirstPartyPackages(lockfile);\n if (firstPartyPackages !== undefined) {\n for (const name of ownNames(firstPartyPackages)) required.add(name);\n }\n const declared = new Set(entries.map(({ name }) => name));\n const missing = [...required].filter((name) => !declared.has(name)).sort();\n if (missing.length > 0)\n errors.push(\n `bunfig.toml is missing registry-backed first-party quarantine excludes: ${missing.join(\", \")}`,\n );\n } catch (error) {\n errors.push(error instanceof Error ? error.message : String(error));\n }\n return { errors, warnings };\n};\n\ntype PruneOptions = { bunfig: string; parseToml: ParseToml; now?: Date };\nexport const pruneExpiredExcludes = ({\n bunfig,\n parseToml,\n now = new Date(),\n}: PruneOptions): { bunfig: string; pruned: string[] } => {\n const nowMs = validNow(now);\n const { entries, close } = readSourceArray(bunfig, parseToml);\n const removals: { start: number; end: number }[] = [];\n const pruned: string[] = [];\n for (const entry of entries) {\n if (ownPackage(entry.name)) continue;\n const annotation = annotationOf(entry);\n if (annotation.type !== \"expires\" || !exactTimestamp(annotation.timestamp))\n return fail(\n `bunfig.toml third-party quarantine exclude \"${entry.name}\" must have an exact UTC quarantine-expires: annotation`,\n );\n if (nowMs < Date.parse(annotation.timestamp)) continue;\n const lineStart = bunfig.lastIndexOf(\"\\n\", entry.token.start - 1) + 1;\n const nextNewline = bunfig.indexOf(\"\\n\", entry.token.end);\n const lineEnd = nextNewline < 0 ? bunfig.length : nextNewline;\n const commentInside =\n entry.comment !== undefined && entry.comment.start < close.start;\n const end = commentInside\n ? (entry.comment?.end ?? entry.token.end)\n : (entry.comma?.end ?? entry.token.end);\n if (\n bunfig.slice(lineStart, entry.token.start).trim() === \"\" &&\n bunfig.slice(end, lineEnd).trim() === \"\"\n )\n removals.push({\n start: lineStart,\n end: nextNewline < 0 ? lineEnd : lineEnd + 1,\n });\n else removals.push({ start: entry.token.start, end });\n if (entry.comment !== undefined && !commentInside)\n removals.push({ start: entry.comment.start, end: entry.comment.end });\n pruned.push(entry.name);\n }\n let result = bunfig;\n for (const removal of removals.toReversed())\n result = result.slice(0, removal.start) + result.slice(removal.end);\n // Never return edited TOML without confirming the resulting source is valid.\n readSourceArray(result, parseToml);\n return { bunfig: result, pruned };\n};\n\ntype SynchronizeOptions = {\n bunfig: string;\n firstPartyPackages: FirstPartyPackages;\n parseToml: ParseToml;\n now?: Date;\n};\nexport const synchronizeFirstPartyExcludes = ({\n bunfig,\n firstPartyPackages,\n parseToml,\n now = new Date(),\n}: SynchronizeOptions): string => {\n validNow(now);\n const required = ownNames(firstPartyPackages);\n const { open, close, entries, comments } = readSourceArray(bunfig, parseToml);\n const attachedComments = new Set(\n entries.flatMap(({ comment }) => (comment === undefined ? [] : [comment])),\n );\n const lines = comments\n .filter((comment) => !attachedComments.has(comment))\n .map(({ text }) => ` ${text}`);\n const seen = new Set<string>();\n for (const entry of entries) {\n if (!ownPackage(entry.name)) {\n const annotation = annotationOf(entry);\n if (\n annotation.type !== \"expires\" ||\n !exactTimestamp(annotation.timestamp)\n )\n return fail(\n `bunfig.toml third-party quarantine exclude \"${entry.name}\" must have an exact UTC quarantine-expires: annotation`,\n );\n lines.push(\n ` ${entry.token.text},${entry.comment === undefined ? \"\" : ` ${entry.comment.text}`}`,\n );\n continue;\n }\n if (!required.has(entry.name)) continue;\n seen.add(entry.name);\n const annotation = annotationOf(entry);\n const timestamp =\n annotation.type === \"excluded-since\" &&\n exactTimestamp(annotation.timestamp)\n ? annotation.timestamp\n : now.toISOString();\n lines.push(\n ` ${JSON.stringify(entry.name)}, # quarantine-excluded-since: ${timestamp}`,\n );\n }\n for (const name of [...required]\n .filter((requiredPackage) => !seen.has(requiredPackage))\n .sort())\n lines.push(\n ` ${JSON.stringify(name)}, # quarantine-excluded-since: ${now.toISOString()}`,\n );\n const newline = bunfig.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const trailingComment = entries.at(-1)?.comment;\n const end =\n trailingComment !== undefined && trailingComment.start > close.end\n ? trailingComment.end\n : close.end;\n const result =\n bunfig.slice(0, open.start) +\n `[${newline}${lines.join(newline)}${lines.length === 0 ? \"\" : newline}]` +\n bunfig.slice(end);\n readSourceArray(result, parseToml);\n return result;\n};\n","import { parse } from \"smol-toml\";\n\nimport {\n REQUIRED_RELEASE_AGE_SECONDS,\n checkQuarantinePolicy,\n isFirstPartyPackageName,\n pruneExpiredExcludes,\n readRegistryFirstPartyPackages,\n synchronizeFirstPartyExcludes,\n} from \"./quarantine-policy-core\";\n\nexport {\n EXACT_UTC_TIMESTAMP,\n NPM_REGISTRY,\n REQUIRED_RELEASE_AGE_SECONDS,\n exactTimestamp,\n} from \"./quarantine-policy-core\";\n\nconst record = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\n/** Derive exact registry identities before install, including catalog references. */\nexport const declaredFirstPartyPackages = (files: Record<string, string>) => {\n const names = new Set<string>();\n for (const [file, text] of Object.entries(files)) {\n if (!/(?:^|\\/)package\\.json$/.test(file)) continue;\n const manifest: unknown = JSON.parse(text);\n if (!record(manifest)) throw new Error(`${file} must contain an object`);\n for (const field of [\n \"dependencies\",\n \"devDependencies\",\n \"optionalDependencies\",\n \"peerDependencies\",\n ]) {\n const dependencies = manifest[field];\n if (!record(dependencies)) continue;\n for (const [name, specifier] of Object.entries(dependencies)) {\n if (typeof specifier !== \"string\") continue;\n if (\n /^(?:workspace:|file:|link:|git(?:\\+|:)|https?:|github:|\\.\\.?\\/|\\/)/.test(\n specifier,\n )\n )\n continue;\n if (specifier.startsWith(\"npm:\")) {\n const alias = /^npm:(@[^/]+\\/[^@]+|[^@]+)@/.exec(specifier)?.at(1);\n if (alias !== undefined && isFirstPartyPackageName(alias))\n names.add(alias);\n continue;\n }\n if (isFirstPartyPackageName(name)) names.add(name);\n }\n }\n }\n return names;\n};\n\ntype RepositoryQuarantineOptions = {\n files: Record<string, string>;\n now?: Date | undefined;\n npmrcPresent?: boolean | undefined;\n};\n\nexport const checkRepositoryQuarantine = ({\n files,\n now,\n npmrcPresent,\n}: RepositoryQuarantineOptions) =>\n checkQuarantinePolicy({\n bunfig: files[\"bunfig.toml\"] ?? \"\",\n lockfile: files[\"bun.lock\"],\n firstPartyPackages: declaredFirstPartyPackages(files),\n parseToml: parse,\n ...(now === undefined ? {} : { now }),\n ...(npmrcPresent === undefined ? {} : { npmrcPresent }),\n });\n\nexport const synchronizeRepositoryQuarantine = ({\n files,\n now,\n}: RepositoryQuarantineOptions) => {\n const firstPartyPackages = new Set([\n ...declaredFirstPartyPackages(files),\n ...readRegistryFirstPartyPackages(files[\"bun.lock\"]),\n ]);\n return synchronizeFirstPartyExcludes({\n bunfig:\n files[\"bunfig.toml\"] ??\n `[install]\\nminimumReleaseAge = ${REQUIRED_RELEASE_AGE_SECONDS}\\nminimumReleaseAgeExcludes = []\\n`,\n firstPartyPackages,\n parseToml: parse,\n ...(now === undefined ? {} : { now }),\n });\n};\n\nexport const pruneRepositoryQuarantine = ({\n files,\n now,\n}: RepositoryQuarantineOptions) =>\n pruneExpiredExcludes({\n bunfig: files[\"bunfig.toml\"] ?? \"\",\n parseToml: parse,\n ...(now === undefined ? {} : { now }),\n });\n"],"mappings":"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"}
@@ -1,11 +1,12 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime.cjs");
2
+ const require_jsonc = require("./jsonc.cjs");
2
3
  const require_toolchain_inputs = require("./toolchain-inputs.cjs");
3
4
  const require_compiler_packages = require("./compiler-packages.cjs");
4
- let node_child_process = require("node:child_process");
5
5
  let node_path = require("node:path");
6
6
  node_path = require_rolldown_runtime.__toESM(node_path, 1);
7
- let semver = require("semver");
8
7
  let smol_toml = require("smol-toml");
8
+ let node_child_process = require("node:child_process");
9
+ let semver = require("semver");
9
10
  let node_util = require("node:util");
10
11
  let yaml = require("yaml");
11
12
  //#region src/toolchain-changed-locks.ts
@@ -58,62 +59,6 @@ const changedCompilerPatches = ({ value, stringsArePaths, compilerNames }) => {
58
59
  }
59
60
  return patches;
60
61
  };
61
- /** JSONC permits comments and trailing commas, never alterations inside strings. */
62
- const parseChangedJson = (text) => {
63
- let clean = "";
64
- let quote = false;
65
- for (let index = 0; index < text.length; index++) {
66
- const char = text[index];
67
- if (quote) {
68
- clean += char;
69
- if (char === "\\") {
70
- index++;
71
- clean += text[index] ?? "";
72
- } else if (char === "\"") quote = false;
73
- continue;
74
- }
75
- if (char === "\"") {
76
- quote = true;
77
- clean += char;
78
- continue;
79
- }
80
- if (char === "/" && text[index + 1] === "/") {
81
- while (index < text.length && text[index] !== "\n") index++;
82
- clean += "\n";
83
- continue;
84
- }
85
- if (char === "/" && text[index + 1] === "*") {
86
- index += 2;
87
- while (index < text.length && !(text[index] === "*" && text[index + 1] === "/")) index++;
88
- if (index >= text.length) throw new Error("Unterminated JSONC comment");
89
- index++;
90
- clean += " ";
91
- continue;
92
- }
93
- clean += char;
94
- }
95
- let result = "";
96
- quote = false;
97
- for (let index = 0; index < clean.length; index++) {
98
- const char = clean[index];
99
- if (quote) {
100
- result += char;
101
- if (char === "\\") {
102
- index++;
103
- result += clean[index] ?? "";
104
- } else if (char === "\"") quote = false;
105
- continue;
106
- }
107
- if (char === "\"") quote = true;
108
- if (char === ",") {
109
- let next = index + 1;
110
- while (/\s/.test(clean[next] ?? "") && next < clean.length) next++;
111
- if (clean[next] === "}" || clean[next] === "]") continue;
112
- }
113
- result += char;
114
- }
115
- return JSON.parse(result);
116
- };
117
62
  const changedYarnSelectors = (location) => location.replace(/"/g, "").split(/,\s*/).map((selector) => selector.trim());
118
63
  const packageDescriptor = (descriptor) => {
119
64
  const match = /^(@[^/]+\/[^@]+|[^@]+)@(.+)$/.exec(descriptor.replace(/^\//, ""));
@@ -287,7 +232,7 @@ const parseChangedLock = ({ file, text }) => {
287
232
  const resolutions = [];
288
233
  const importers = {};
289
234
  if (file.endsWith("bun.lock")) {
290
- const parsed = parseChangedJson(text);
235
+ const parsed = require_jsonc.parseJsonc(text);
291
236
  if (!changedRecord(parsed) || !BUN_TEXT_LOCKFILE_VERSIONS.has(Number(parsed["lockfileVersion"])) || !changedRecord(parsed["packages"]) || !changedRecord(parsed["workspaces"])) throw new Error("Unsupported Bun lockfile shape");
292
237
  for (const [directory, workspace] of Object.entries(parsed["workspaces"])) importers[directory || "."] = importerDependencies(workspace);
293
238
  for (const [location, value] of Object.entries(parsed["packages"])) {
@@ -385,7 +330,7 @@ const parseChangedLock = ({ file, text }) => {
385
330
  }
386
331
  }
387
332
  } else {
388
- const parsed = parseChangedJson(text);
333
+ const parsed = require_jsonc.parseJsonc(text);
389
334
  if (!changedRecord(parsed) || ![
390
335
  1,
391
336
  2,
@@ -711,7 +656,7 @@ const compilerInstallationNames = (snapshot) => {
711
656
  for (const file of snapshot.entries.keys()) {
712
657
  const basename = node_path.default.posix.basename(file);
713
658
  if (basename === "package.json") {
714
- const manifest = parseChangedJson(snapshotText({
659
+ const manifest = require_jsonc.parseJsonc(snapshotText({
715
660
  snapshot,
716
661
  file
717
662
  }));
@@ -771,7 +716,7 @@ const effectiveCatalogSpecifier = ({ snapshot, file, dependency, specifier }) =>
771
716
  const document = (0, yaml.parseDocument)(text);
772
717
  if (document.errors.length > 0) throw new Error(`Invalid catalog YAML: ${owner}`);
773
718
  value = document.toJS({ maxAliasCount: 100 });
774
- } else value = parseChangedJson(text);
719
+ } else value = require_jsonc.parseJsonc(text);
775
720
  if (!changedRecord(value)) continue;
776
721
  const sources = [value];
777
722
  if (changedRecord(value["workspaces"])) sources.push(value["workspaces"]);
@@ -808,7 +753,7 @@ const compilerPatches = (snapshot) => {
808
753
  const document = (0, yaml.parseDocument)(text);
809
754
  if (document.errors.length > 0) throw new Error(`Invalid compiler patch YAML: ${file}`);
810
755
  value = document.toJS({ maxAliasCount: 100 });
811
- } else value = parseChangedJson(text);
756
+ } else value = require_jsonc.parseJsonc(text);
812
757
  const sources = [value];
813
758
  if (name === "package.json" && changedRecord(value)) sources.push(value["pnpm"]);
814
759
  for (const source of sources) for (const patch of changedCompilerPatches({
@@ -1000,7 +945,7 @@ const setupRuntimeFileVersion = ({ snapshot, file, runtime }) => {
1000
945
  file
1001
946
  }).trim();
1002
947
  if (runtime === "bun" && file.endsWith(".json")) {
1003
- const manifest = parseChangedJson(text);
948
+ const manifest = require_jsonc.parseJsonc(text);
1004
949
  const manager = changedRecord(manifest) ? manifest["packageManager"] : void 0;
1005
950
  if (typeof manager !== "string" || !manager.startsWith("bun@")) throw new Error("Bun selector manifest lacks an exact Bun packageManager");
1006
951
  return stableVersion(manager.slice(4));
@@ -1196,7 +1141,7 @@ const parseSnapshot = (snapshot) => {
1196
1141
  if (compilerPatchPackageFile(file, compilerNames)) tools.typescript.add(`patch-package:${file}:${text}`);
1197
1142
  for (const tool of selectedFiles.get(file) ?? []) tools[tool].add(`selector-file:${file}:${text}`);
1198
1143
  if (name === "package.json") {
1199
- const manifest = parseChangedJson(text);
1144
+ const manifest = require_jsonc.parseJsonc(text);
1200
1145
  if (!changedRecord(manifest)) throw new Error(`Invalid tracked manifest: ${file}`);
1201
1146
  if (typeof manifest["name"] === "string" && changedPackageTool(manifest["name"]) === "typescript") throw new Error(`Tracked compiler source has no immutable artifact identity: ${file}`);
1202
1147
  manifests.set(file, manifest);
@@ -1232,7 +1177,7 @@ const parseSnapshot = (snapshot) => {
1232
1177
  else if (otherRuntimeFiles.has(name)) tools.shared.add(`${file}:${text}`);
1233
1178
  else if (name === ".node-version" || name === ".nvmrc") tools.node.add(`${file}:${stableVersion(text)}`);
1234
1179
  else if (name === "toolchain.json") {
1235
- const policy = parseChangedJson(text);
1180
+ const policy = require_jsonc.parseJsonc(text);
1236
1181
  if (!changedRecord(policy)) throw new Error("Invalid shared toolchain policy");
1237
1182
  tools.shared.add(`${file}:${stableJson(policy)}`);
1238
1183
  if (typeof policy["bun"] === "string") addBun(policy["bun"]);