@absolutejs/changelog 0.2.0 → 0.4.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.
- package/CHANGELOG.md +41 -0
- package/README.md +41 -4
- package/changelog.json +111 -0
- package/dist/apply.d.ts +3 -5
- package/dist/cli.js +269 -140
- package/dist/cli.js.map +9 -9
- package/dist/entries.d.ts +16 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +464 -224
- package/dist/index.js.map +9 -9
- package/dist/reconcile.d.ts +3 -3
- package/dist/registry.d.ts +1 -0
- package/dist/surface.d.ts +21 -22
- package/dist/write.d.ts +9 -0
- package/package.json +74 -71
package/dist/cli.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
// src/cli.ts
|
|
5
5
|
import { existsSync } from "fs";
|
|
6
|
+
import ts2 from "typescript";
|
|
6
7
|
import { mkdir, readFile as readFile3, rm, writeFile as writeFile2 } from "fs/promises";
|
|
7
8
|
import { join as join2 } from "path";
|
|
8
9
|
|
|
@@ -269,6 +270,10 @@ var migrationsBetween = (changelog, from, upto) => disruptiveBetween(changelog,
|
|
|
269
270
|
});
|
|
270
271
|
var symbolsDisturbedBetween = (changelog, from, upto) => new Set(disruptiveBetween(changelog, from, upto).flatMap(({ change }) => change.symbols));
|
|
271
272
|
|
|
273
|
+
// src/surface.ts
|
|
274
|
+
import path from "path";
|
|
275
|
+
import ts from "typescript";
|
|
276
|
+
|
|
272
277
|
// src/tarball.ts
|
|
273
278
|
var TAR_BLOCK = 512;
|
|
274
279
|
var NAME_LENGTH = 100;
|
|
@@ -321,114 +326,185 @@ var readTar = (archive, keep, limits = {}) => {
|
|
|
321
326
|
};
|
|
322
327
|
|
|
323
328
|
// src/surface.ts
|
|
324
|
-
var DECLARATION =
|
|
325
|
-
var
|
|
326
|
-
var
|
|
327
|
-
var
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
var
|
|
350
|
-
var reExported = (body) => body.split(",").map((part) => part.trim().replace(/^type\s+/u, "")).filter((clause) => clause !== "").map((clause) => [
|
|
351
|
-
clause.split(/\s+as\s+/u).at(LAST2)?.trim(),
|
|
352
|
-
clause
|
|
353
|
-
]).filter((pair) => pair[0] !== undefined && IDENTIFIER.test(pair[0]));
|
|
354
|
-
var exportedDeclarations = (source) => {
|
|
329
|
+
var DECLARATION = /\.d\.[cm]?ts$/u;
|
|
330
|
+
var parse = (source, name) => ts.createSourceFile(name, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
331
|
+
var normalize = (text) => text.replace(/\s+/gu, " ").trim();
|
|
332
|
+
var resolveFrom = (files, from, specifier) => {
|
|
333
|
+
if (!specifier.startsWith("."))
|
|
334
|
+
return;
|
|
335
|
+
const base = path.posix.join(path.posix.dirname(from), specifier);
|
|
336
|
+
const candidates = [
|
|
337
|
+
base,
|
|
338
|
+
`${base.replace(/\.js$/u, "")}.d.ts`,
|
|
339
|
+
`${base.replace(/\.js$/u, "")}.d.mts`,
|
|
340
|
+
`${base.replace(/\.js$/u, "")}.d.cts`,
|
|
341
|
+
`${base}/index.d.ts`,
|
|
342
|
+
`${base}/index.d.mts`,
|
|
343
|
+
`${base}/index.d.cts`
|
|
344
|
+
];
|
|
345
|
+
return candidates.find((candidate) => files.has(candidate));
|
|
346
|
+
};
|
|
347
|
+
var declaredNameOf = (statement) => {
|
|
348
|
+
if (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement) || ts.isInterfaceDeclaration(statement) || ts.isTypeAliasDeclaration(statement) || ts.isEnumDeclaration(statement) || ts.isModuleDeclaration(statement))
|
|
349
|
+
return statement.name !== undefined && ts.isIdentifier(statement.name) ? statement.name.text : undefined;
|
|
350
|
+
return;
|
|
351
|
+
};
|
|
352
|
+
var isExported = (statement) => ts.canHaveModifiers(statement) && ts.getModifiers(statement)?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword) === true;
|
|
353
|
+
var variableNamesOf = (statement) => statement.declarationList.declarations.map((declaration) => declaration.name).filter((name) => ts.isIdentifier(name)).map((name) => name.text);
|
|
354
|
+
var declarationsIn = (file) => {
|
|
355
355
|
const found = new Map;
|
|
356
|
-
const
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
const [, keyword, name] = match;
|
|
363
|
-
if (name === undefined || match.index === undefined)
|
|
356
|
+
for (const statement of file.statements) {
|
|
357
|
+
const text = normalize(statement.getText(file));
|
|
358
|
+
const named = declaredNameOf(statement);
|
|
359
|
+
if (named !== undefined)
|
|
360
|
+
found.set(named, text);
|
|
361
|
+
if (!ts.isVariableStatement(statement))
|
|
364
362
|
continue;
|
|
365
|
-
|
|
363
|
+
for (const name of variableNamesOf(statement))
|
|
364
|
+
found.set(name, text);
|
|
366
365
|
}
|
|
367
|
-
for (const match of source.matchAll(NAMED_EXPORT))
|
|
368
|
-
for (const [exported, clause] of reExported(match[1] ?? ""))
|
|
369
|
-
add(exported, `export { ${clause} }`);
|
|
370
366
|
return found;
|
|
371
367
|
};
|
|
372
|
-
var
|
|
373
|
-
|
|
368
|
+
var declaresTypes = (manifest) => {
|
|
369
|
+
if (typeof manifest !== "object" || manifest === null)
|
|
370
|
+
return false;
|
|
371
|
+
const record = new Map(Object.entries(manifest));
|
|
372
|
+
if (typeof record.get("types") === "string")
|
|
373
|
+
return true;
|
|
374
|
+
if (typeof record.get("typings") === "string")
|
|
375
|
+
return true;
|
|
376
|
+
return JSON.stringify(record.get("exports") ?? {}).includes('"types"');
|
|
377
|
+
};
|
|
378
|
+
var contributionOf = (input) => {
|
|
379
|
+
const { file, files, from, local, seen, statement } = input;
|
|
380
|
+
const nothing = [];
|
|
381
|
+
if (ts.isExportAssignment(statement))
|
|
382
|
+
return [
|
|
383
|
+
[
|
|
384
|
+
statement.isExportEquals === true ? "export=" : "default",
|
|
385
|
+
normalize(statement.getText(file))
|
|
386
|
+
]
|
|
387
|
+
];
|
|
388
|
+
const named = declaredNameOf(statement);
|
|
389
|
+
if (named !== undefined && isExported(statement))
|
|
390
|
+
return [
|
|
391
|
+
[named, local.get(named) ?? normalize(statement.getText(file))]
|
|
392
|
+
];
|
|
393
|
+
if (ts.isVariableStatement(statement) && isExported(statement)) {
|
|
394
|
+
const text = normalize(statement.getText(file));
|
|
395
|
+
return variableNamesOf(statement).map((name) => [name, text]);
|
|
396
|
+
}
|
|
397
|
+
if (!ts.isExportDeclaration(statement))
|
|
398
|
+
return nothing;
|
|
399
|
+
const specifier = statement.moduleSpecifier !== undefined && ts.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : undefined;
|
|
400
|
+
const target = specifier === undefined ? undefined : resolveFrom(files, from, specifier);
|
|
401
|
+
const theirs = target === undefined ? new Map : exportsOf(files, target, new Set(seen));
|
|
402
|
+
const clause = statement.exportClause;
|
|
403
|
+
if (clause === undefined)
|
|
404
|
+
return [...theirs].filter(([name]) => name !== "default" && name !== "export=");
|
|
405
|
+
if (ts.isNamespaceExport(clause))
|
|
406
|
+
return [[clause.name.text, `export * as ${clause.name.text}`]];
|
|
407
|
+
return clause.elements.map((element) => {
|
|
408
|
+
const sourceName = (element.propertyName ?? element.name).text;
|
|
409
|
+
const text = (specifier === undefined ? local.get(sourceName) : theirs.get(sourceName)) ?? `export { ${sourceName} }`;
|
|
410
|
+
return [element.name.text, text];
|
|
411
|
+
});
|
|
412
|
+
};
|
|
413
|
+
var exportsOf = (files, from, seen) => {
|
|
374
414
|
const surface = new Map;
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
415
|
+
const source = files.get(from);
|
|
416
|
+
if (source === undefined || seen.has(from))
|
|
417
|
+
return surface;
|
|
418
|
+
seen.add(from);
|
|
419
|
+
const file = parse(source, from);
|
|
420
|
+
const local = declarationsIn(file);
|
|
421
|
+
const contributed = file.statements.flatMap((statement) => contributionOf({ file, files, from, local, seen, statement }));
|
|
422
|
+
for (const [name, text] of contributed)
|
|
423
|
+
surface.set(name, text);
|
|
381
424
|
return surface;
|
|
382
425
|
};
|
|
426
|
+
var surfaceOfArchive = (archive) => {
|
|
427
|
+
const held = readTar(archive, (name) => DECLARATION.test(name) || name === "package.json");
|
|
428
|
+
const files = new Map([...held].map(([name, bytes]) => [name, asText(bytes)]));
|
|
429
|
+
const manifest = files.get("package.json");
|
|
430
|
+
let parsed;
|
|
431
|
+
try {
|
|
432
|
+
parsed = manifest === undefined ? undefined : JSON.parse(manifest);
|
|
433
|
+
} catch {
|
|
434
|
+
parsed = undefined;
|
|
435
|
+
}
|
|
436
|
+
const entries = typeEntriesOf(parsed, files);
|
|
437
|
+
return entries.length === 0 ? undefined : surfaceOfFiles(files, entries);
|
|
438
|
+
};
|
|
439
|
+
var surfaceOfFiles = (files, entries) => {
|
|
440
|
+
const surface = new Map;
|
|
441
|
+
for (const entry of entries)
|
|
442
|
+
for (const [name, text] of exportsOf(files, entry, new Set))
|
|
443
|
+
if (!surface.has(name))
|
|
444
|
+
surface.set(name, text);
|
|
445
|
+
return surface;
|
|
446
|
+
};
|
|
447
|
+
var typeCandidatesIn = (value) => {
|
|
448
|
+
if (typeof value === "string")
|
|
449
|
+
return [value];
|
|
450
|
+
if (typeof value !== "object" || value === null)
|
|
451
|
+
return [];
|
|
452
|
+
return Object.entries(value).flatMap(([key, nested]) => key === "types" || key === "typings" ? typeCandidatesIn(nested) : typeCandidatesIn(nested));
|
|
453
|
+
};
|
|
454
|
+
var typeEntriesOf = (manifest, files) => {
|
|
455
|
+
const record = typeof manifest === "object" && manifest !== null ? new Map(Object.entries(manifest)) : new Map;
|
|
456
|
+
const claimed = [
|
|
457
|
+
record.get("types"),
|
|
458
|
+
record.get("typings"),
|
|
459
|
+
...typeCandidatesIn(record.get("exports"))
|
|
460
|
+
];
|
|
461
|
+
const entries = claimed.filter((value) => typeof value === "string").map((value) => value.replace(/^\.\//u, "")).flatMap((cleaned) => DECLARATION.test(cleaned) ? [cleaned] : [
|
|
462
|
+
cleaned.replace(/\.[cm]?js$/u, ".d.ts"),
|
|
463
|
+
cleaned.replace(/\.[cm]?js$/u, ".d.mts"),
|
|
464
|
+
cleaned.replace(/\.[cm]?js$/u, ".d.cts")
|
|
465
|
+
]).filter((candidate) => files.has(candidate));
|
|
466
|
+
const fallback = entries.length === 0 && files.has("dist/index.d.ts") ? ["dist/index.d.ts"] : [];
|
|
467
|
+
return [...new Set([...entries, ...fallback])];
|
|
468
|
+
};
|
|
383
469
|
var SHAPE = {
|
|
384
470
|
members: "members",
|
|
385
471
|
parameters: "parameters",
|
|
386
472
|
types: "types",
|
|
387
473
|
unknown: "unknown"
|
|
388
474
|
};
|
|
475
|
+
var isStub = (declaration) => declaration.startsWith("export {");
|
|
476
|
+
var signatureOf = (declaration) => {
|
|
477
|
+
const file = parse(`${declaration}
|
|
478
|
+
`, "declaration.d.ts");
|
|
479
|
+
const [statement] = file.statements;
|
|
480
|
+
if (statement === undefined)
|
|
481
|
+
return;
|
|
482
|
+
return statement;
|
|
483
|
+
};
|
|
389
484
|
var parametersOf = (declaration) => {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
return "";
|
|
485
|
+
const statement = signatureOf(declaration);
|
|
486
|
+
if (statement === undefined)
|
|
487
|
+
return "";
|
|
488
|
+
const found = [];
|
|
489
|
+
const visit = (node) => {
|
|
490
|
+
if (ts.isFunctionTypeNode(node) || ts.isFunctionDeclaration(node) || ts.isMethodSignature(node) || ts.isMethodDeclaration(node) || ts.isConstructSignatureDeclaration(node) || ts.isConstructorDeclaration(node))
|
|
491
|
+
found.push(node.parameters.map((parameter) => normalize(parameter.getText())).join(", "));
|
|
492
|
+
ts.forEachChild(node, visit);
|
|
493
|
+
};
|
|
494
|
+
visit(statement);
|
|
495
|
+
return found.join(" | ");
|
|
403
496
|
};
|
|
404
497
|
var membersOf = (declaration) => {
|
|
405
|
-
const
|
|
406
|
-
if (opened < 0)
|
|
407
|
-
return new Set;
|
|
498
|
+
const statement = signatureOf(declaration);
|
|
408
499
|
const members = new Set;
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
segment = "";
|
|
500
|
+
if (statement === undefined)
|
|
501
|
+
return members;
|
|
502
|
+
const visit = (node) => {
|
|
503
|
+
if ((ts.isPropertySignature(node) || ts.isMethodSignature(node) || ts.isPropertyDeclaration(node) || ts.isMethodDeclaration(node) || ts.isEnumMember(node)) && node.name !== undefined && (ts.isIdentifier(node.name) || ts.isStringLiteral(node.name)))
|
|
504
|
+
members.add(node.name.text);
|
|
505
|
+
ts.forEachChild(node, visit);
|
|
416
506
|
};
|
|
417
|
-
|
|
418
|
-
const opening = OPENS.has(character);
|
|
419
|
-
const closing = CLOSES.has(character);
|
|
420
|
-
depth += opening ? 1 : 0;
|
|
421
|
-
if (opening && depth === 1)
|
|
422
|
-
segment = "";
|
|
423
|
-
depth -= closing ? 1 : 0;
|
|
424
|
-
if (opening || closing || depth !== 1)
|
|
425
|
-
continue;
|
|
426
|
-
if (character === ";" || character === ",")
|
|
427
|
-
take();
|
|
428
|
-
else
|
|
429
|
-
segment += character;
|
|
430
|
-
}
|
|
431
|
-
take();
|
|
507
|
+
visit(statement);
|
|
432
508
|
return members;
|
|
433
509
|
};
|
|
434
510
|
var sameNames = (left, right) => left.size === right.size && [...left].every((name) => right.has(name));
|
|
@@ -465,9 +541,9 @@ var diffSurface = (before, after) => {
|
|
|
465
541
|
var notable = (diff) => diff.changed.filter((change) => change.shape === "parameters" || change.shape === "members");
|
|
466
542
|
|
|
467
543
|
// src/entries.ts
|
|
468
|
-
var loadEntry = async (
|
|
544
|
+
var loadEntry = async (path2) => {
|
|
469
545
|
try {
|
|
470
|
-
const module = await import(pathToFileURL(
|
|
546
|
+
const module = await import(pathToFileURL(path2).href);
|
|
471
547
|
const named = typeof module === "object" && module !== null && "change" in module ? module.change : undefined;
|
|
472
548
|
const exported = named ?? (typeof module === "object" && module !== null && "default" in module ? module.default : undefined);
|
|
473
549
|
const read = { exported };
|
|
@@ -480,23 +556,28 @@ var loadEntry = async (path) => {
|
|
|
480
556
|
}
|
|
481
557
|
};
|
|
482
558
|
var ENTRY = /\.[cm]?ts$/u;
|
|
483
|
-
var
|
|
484
|
-
|
|
485
|
-
|
|
559
|
+
var DECLARATION2 = /\.d\.[cm]?ts$/u;
|
|
560
|
+
var OUTPUT_DIRECTORIES = ["dist", "build", "lib", "types", "out"];
|
|
561
|
+
var builtSurface = async (packageRoot) => {
|
|
562
|
+
const manifest = await readJsonFile(join(packageRoot, "package.json"));
|
|
563
|
+
const files = new Map;
|
|
486
564
|
const walk = async (directory) => {
|
|
487
|
-
const found = await readdir(directory, {
|
|
565
|
+
const found = await readdir(join(packageRoot, directory), {
|
|
566
|
+
withFileTypes: true
|
|
567
|
+
}).catch(() => []);
|
|
488
568
|
await Promise.all(found.map(async (entry) => {
|
|
489
|
-
const
|
|
569
|
+
const relative = `${directory}/${entry.name}`;
|
|
490
570
|
if (entry.isDirectory())
|
|
491
|
-
return walk(
|
|
492
|
-
if (!entry.name
|
|
571
|
+
return walk(relative);
|
|
572
|
+
if (!DECLARATION2.test(entry.name))
|
|
493
573
|
return;
|
|
494
|
-
|
|
574
|
+
files.set(relative, await readFile(join(packageRoot, relative), "utf8").catch(() => ""));
|
|
495
575
|
return;
|
|
496
576
|
}));
|
|
497
577
|
};
|
|
498
|
-
await walk(
|
|
499
|
-
|
|
578
|
+
await Promise.all(OUTPUT_DIRECTORIES.map((directory) => walk(directory)));
|
|
579
|
+
const entries = typeEntriesOf(manifest, files);
|
|
580
|
+
return entries.length === 0 ? undefined : surfaceOfFiles(files, entries);
|
|
500
581
|
};
|
|
501
582
|
var changelogPaths = (packageRoot) => ({
|
|
502
583
|
history: join(packageRoot, "changelog", "history.md"),
|
|
@@ -522,8 +603,8 @@ var loadUnreleased = async (packageRoot) => {
|
|
|
522
603
|
}
|
|
523
604
|
return { entries, problems };
|
|
524
605
|
};
|
|
525
|
-
var readJsonFile = async (
|
|
526
|
-
const source = await readFile(
|
|
606
|
+
var readJsonFile = async (path2) => {
|
|
607
|
+
const source = await readFile(path2, "utf8").catch(() => {
|
|
527
608
|
return;
|
|
528
609
|
});
|
|
529
610
|
if (source === undefined)
|
|
@@ -546,9 +627,9 @@ var indentOf = (source) => {
|
|
|
546
627
|
const found = /\n([\t ]+)\S/u.exec(source)?.[1];
|
|
547
628
|
return found === undefined || found === "" ? "\t" : found;
|
|
548
629
|
};
|
|
549
|
-
var writeJsonLike = async (
|
|
550
|
-
const source = await readFile2(
|
|
551
|
-
await writeFile(
|
|
630
|
+
var writeJsonLike = async (path2, document) => {
|
|
631
|
+
const source = await readFile2(path2, "utf8").catch(() => "");
|
|
632
|
+
await writeFile(path2, `${JSON.stringify(document, null, indentOf(source))}
|
|
552
633
|
`);
|
|
553
634
|
};
|
|
554
635
|
|
|
@@ -586,8 +667,14 @@ var migrationHolds = (input) => {
|
|
|
586
667
|
};
|
|
587
668
|
var describeReconciliation = (found) => {
|
|
588
669
|
const lines = [];
|
|
670
|
+
const moved = {
|
|
671
|
+
members: "changed the members of its type",
|
|
672
|
+
parameters: "changed what it is called with",
|
|
673
|
+
removed: "is no longer exported",
|
|
674
|
+
types: "changed its declaration"
|
|
675
|
+
};
|
|
589
676
|
for (const entry of found.unannounced)
|
|
590
|
-
lines.push(
|
|
677
|
+
lines.push(`\`${entry.name}\` ${moved[entry.kind]} and no entry says so`);
|
|
591
678
|
for (const name of found.unknownSymbols)
|
|
592
679
|
lines.push(`an entry names \`${name}\`, which this package does not export`);
|
|
593
680
|
lines.push(...found.wrongMigrations);
|
|
@@ -598,10 +685,7 @@ var reconcile = (input) => {
|
|
|
598
685
|
const mentioned = new Set(input.changes.flatMap((change) => [...change.symbols ?? []]));
|
|
599
686
|
const unannounced = [
|
|
600
687
|
...input.diff.removed.filter((name) => !disruptive.has(name)).map((name) => ({ kind: "removed", name })),
|
|
601
|
-
...
|
|
602
|
-
kind: change.shape === "parameters" ? "parameters" : "members",
|
|
603
|
-
name: change.name
|
|
604
|
-
}))
|
|
688
|
+
...input.diff.changed.filter((change) => !mentioned.has(change.name) && change.shape !== "unknown").map((change) => ({ kind: change.shape, name: change.name }))
|
|
605
689
|
];
|
|
606
690
|
const unknownSymbols = [
|
|
607
691
|
...new Set(input.changes.flatMap((change) => [...change.symbols ?? []]).filter((name) => !input.known.has(name)))
|
|
@@ -619,6 +703,16 @@ var reconcile = (input) => {
|
|
|
619
703
|
import { gunzipSync } from "zlib";
|
|
620
704
|
var ABBREVIATED = "application/vnd.npm.install-v1+json";
|
|
621
705
|
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
706
|
+
var KIBIBYTE2 = 1024;
|
|
707
|
+
var MEBIBYTE2 = KIBIBYTE2 * KIBIBYTE2;
|
|
708
|
+
var MAX_ARCHIVE_MEBIBYTES = 96;
|
|
709
|
+
var MAX_ARCHIVE_BYTES = MAX_ARCHIVE_MEBIBYTES * MEBIBYTE2;
|
|
710
|
+
var MAX_DOWNLOAD_MEBIBYTES = 32;
|
|
711
|
+
var MAX_DOWNLOAD_BYTES = MAX_DOWNLOAD_MEBIBYTES * MEBIBYTE2;
|
|
712
|
+
var TIMEOUT_MS = 20000;
|
|
713
|
+
var PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u;
|
|
714
|
+
var MAX_NAME_LENGTH = 214;
|
|
715
|
+
var isPackageName = (name) => name.length <= MAX_NAME_LENGTH && PACKAGE_NAME.test(name);
|
|
622
716
|
var isRecord2 = (value) => typeof value === "object" && value !== null;
|
|
623
717
|
var readPackument = (body) => {
|
|
624
718
|
if (!isRecord2(body) || !isRecord2(body.versions))
|
|
@@ -646,20 +740,30 @@ var packageArchive = async (name, version, options = {}) => {
|
|
|
646
740
|
if (url === undefined)
|
|
647
741
|
return;
|
|
648
742
|
try {
|
|
649
|
-
const response = await call(url
|
|
743
|
+
const response = await call(url, {
|
|
744
|
+
signal: AbortSignal.timeout(TIMEOUT_MS)
|
|
745
|
+
});
|
|
650
746
|
if (!response.ok)
|
|
651
747
|
return;
|
|
652
|
-
|
|
748
|
+
const compressed = new Uint8Array(await response.arrayBuffer());
|
|
749
|
+
if (compressed.byteLength > MAX_DOWNLOAD_BYTES)
|
|
750
|
+
return;
|
|
751
|
+
return new Uint8Array(gunzipSync(compressed, { maxOutputLength: MAX_ARCHIVE_BYTES }));
|
|
653
752
|
} catch {
|
|
654
753
|
return;
|
|
655
754
|
}
|
|
656
755
|
};
|
|
657
756
|
var packageVersions = async (name, options = {}) => {
|
|
757
|
+
if (!isPackageName(name))
|
|
758
|
+
return;
|
|
658
759
|
const call = options.fetch ?? fetch;
|
|
659
760
|
const url = `${options.registry ?? DEFAULT_REGISTRY}/${name.replace("/", "%2f")}`;
|
|
660
761
|
try {
|
|
661
|
-
const abbreviated = await call(url, {
|
|
662
|
-
|
|
762
|
+
const abbreviated = await call(url, {
|
|
763
|
+
headers: { accept: ABBREVIATED },
|
|
764
|
+
signal: AbortSignal.timeout(TIMEOUT_MS)
|
|
765
|
+
});
|
|
766
|
+
const response = abbreviated.ok ? abbreviated : await call(url, { signal: AbortSignal.timeout(TIMEOUT_MS) });
|
|
663
767
|
if (!response.ok)
|
|
664
768
|
return;
|
|
665
769
|
return readPackument(await response.json());
|
|
@@ -671,7 +775,7 @@ var publishedChangelog = async (name, version, options = {}) => {
|
|
|
671
775
|
const archive = await packageArchive(name, version, options);
|
|
672
776
|
if (!archive)
|
|
673
777
|
return;
|
|
674
|
-
const file = readTar(archive, (
|
|
778
|
+
const file = readTar(archive, (path2) => path2 === CHANGELOG_FILE).get(CHANGELOG_FILE);
|
|
675
779
|
if (!file)
|
|
676
780
|
return;
|
|
677
781
|
try {
|
|
@@ -749,6 +853,7 @@ var renderRelease = (release) => {
|
|
|
749
853
|
].join(`
|
|
750
854
|
`);
|
|
751
855
|
};
|
|
856
|
+
var GENERATED_MARKER = "This file is generated by `absolute-changelog`";
|
|
752
857
|
var renderChangelogJson = (changelog) => `${JSON.stringify({
|
|
753
858
|
contract: CHANGELOG_CONTRACT,
|
|
754
859
|
name: changelog.name,
|
|
@@ -774,7 +879,7 @@ var renderMarkdown = (changelog, options = {}) => {
|
|
|
774
879
|
"",
|
|
775
880
|
`All notable changes to \`${changelog.name}\`.`,
|
|
776
881
|
"",
|
|
777
|
-
|
|
882
|
+
`${GENERATED_MARKER} from the entries in`,
|
|
778
883
|
"`changelog/`. Edit an entry, not this file \u2014 and add new ones under",
|
|
779
884
|
"`changelog/unreleased/`."
|
|
780
885
|
].join(`
|
|
@@ -984,10 +1089,10 @@ var check = async (root, flags) => {
|
|
|
984
1089
|
const actual = await readFile3(changelogPaths(root).markdown, "utf8").catch(() => {
|
|
985
1090
|
return;
|
|
986
1091
|
});
|
|
987
|
-
if (
|
|
1092
|
+
if (actual !== expected)
|
|
988
1093
|
failures.push(`${CHANGELOG_MARKDOWN} is not what the entries say it should be \u2014 it is generated; run \`absolute-changelog release\` or restore it`);
|
|
989
|
-
const tsconfig = await
|
|
990
|
-
const include =
|
|
1094
|
+
const tsconfig = await readTsconfig(join2(root, "tsconfig.json"));
|
|
1095
|
+
const include = includeOf(tsconfig?.config);
|
|
991
1096
|
if (Array.isArray(include) && !coversEntries(include))
|
|
992
1097
|
failures.push('tsconfig.json does not compile changelog/, so nothing is checking the entries \u2014 add "changelog/**/*" to its include list');
|
|
993
1098
|
for (const stray of await strayEntries(root))
|
|
@@ -998,12 +1103,21 @@ var check = async (root, flags) => {
|
|
|
998
1103
|
failures.push(`package.json does not ship ${file}`);
|
|
999
1104
|
const offline = flags.offline === true;
|
|
1000
1105
|
const built = await builtSurface(root);
|
|
1106
|
+
const shipsTypes = declaresTypes(await readJsonFile(join2(root, "package.json")));
|
|
1107
|
+
if (built === undefined && shipsTypes)
|
|
1108
|
+
failures.push("there are no declaration files where package.json says its types are \u2014 build before the gate, or nothing compares them");
|
|
1109
|
+
if (!shipsTypes)
|
|
1110
|
+
console.warn(" (this package ships no types, so none were compared)");
|
|
1001
1111
|
const versions = offline ? undefined : await packageVersions(manifest.name ?? "");
|
|
1002
|
-
|
|
1003
|
-
|
|
1112
|
+
if (!offline && versions === undefined)
|
|
1113
|
+
failures.push(`the registry did not answer for ${manifest.name}, so nothing was compared \u2014 pass --offline to skip the comparison deliberately`);
|
|
1114
|
+
const baseline = (versions?.published ?? []).filter((version) => compareVersions(version, manifest.version) <= 0).sort(compareVersions).at(LAST2);
|
|
1115
|
+
if (versions !== undefined && baseline === undefined && !offline)
|
|
1116
|
+
console.warn(` (nothing published at or below ${manifest.version}; this looks like a first release)`);
|
|
1117
|
+
if (built !== undefined && baseline !== undefined) {
|
|
1004
1118
|
const published = await publishedSurface(manifest.name ?? "", baseline);
|
|
1005
1119
|
if (published === undefined)
|
|
1006
|
-
|
|
1120
|
+
failures.push(`could not read the published types of ${manifest.name}@${baseline}, so nothing was compared`);
|
|
1007
1121
|
const speaking = [
|
|
1008
1122
|
...entries.map((entry) => entry.change),
|
|
1009
1123
|
...current.releases.filter((entry) => compareVersions(entry.version, baseline) > 0).flatMap((entry) => [...entry.changes])
|
|
@@ -1016,14 +1130,12 @@ var check = async (root, flags) => {
|
|
|
1016
1130
|
subpaths: subpathsOf(manifest)
|
|
1017
1131
|
})));
|
|
1018
1132
|
}
|
|
1019
|
-
if (!offline && built === undefined)
|
|
1020
|
-
console.warn(" (no dist to read, so the types were not checked \u2014 run the build before the gate)");
|
|
1021
1133
|
if (failures.length > 0)
|
|
1022
1134
|
throw new CliError(["This package\u2019s changelog does not hold:", ...failures].join(`
|
|
1023
1135
|
`));
|
|
1024
1136
|
console.log(`${manifest.name}@${manifest.version}: changelog holds (${entries.length} pending, ${current.releases.length} released)`);
|
|
1025
1137
|
};
|
|
1026
|
-
var
|
|
1138
|
+
var LAST2 = -1;
|
|
1027
1139
|
var subpathsOf = (manifest) => {
|
|
1028
1140
|
const { exports } = manifest;
|
|
1029
1141
|
if (typeof exports !== "object" || exports === null)
|
|
@@ -1031,18 +1143,35 @@ var subpathsOf = (manifest) => {
|
|
|
1031
1143
|
return new Set(Object.keys(exports).map((key) => key === "." ? manifest.name ?? "" : `${manifest.name}${key.slice(1)}`));
|
|
1032
1144
|
};
|
|
1033
1145
|
var CHECKING_CONFIGS = ["tsconfig.json", "tsconfig.eslint.json"];
|
|
1146
|
+
var readTsconfig = async (path2) => {
|
|
1147
|
+
const source = await readFile3(path2, "utf8").catch(() => {
|
|
1148
|
+
return;
|
|
1149
|
+
});
|
|
1150
|
+
if (source === undefined)
|
|
1151
|
+
return;
|
|
1152
|
+
const read = ts2.parseConfigFileTextToJson(path2, source);
|
|
1153
|
+
if (read.error !== undefined)
|
|
1154
|
+
return;
|
|
1155
|
+
const { config } = read;
|
|
1156
|
+
const parsed = config;
|
|
1157
|
+
return { config: parsed, source };
|
|
1158
|
+
};
|
|
1034
1159
|
var coversEntries = (include) => Array.isArray(include) && include.some((entry) => typeof entry === "string" && entry.startsWith("changelog"));
|
|
1160
|
+
var includeOf = (config) => typeof config === "object" && config !== null ? new Map(Object.entries(config)).get("include") : undefined;
|
|
1035
1161
|
var includeEntriesIn = async (root, file) => {
|
|
1036
|
-
const
|
|
1037
|
-
const
|
|
1038
|
-
if (
|
|
1162
|
+
const path2 = join2(root, file);
|
|
1163
|
+
const read = await readTsconfig(path2);
|
|
1164
|
+
if (read === undefined)
|
|
1039
1165
|
return false;
|
|
1040
|
-
|
|
1166
|
+
const include = includeOf(read.config);
|
|
1167
|
+
if (!Array.isArray(include) || coversEntries(include))
|
|
1041
1168
|
return false;
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1169
|
+
const opened = /"include"\s*:\s*\[/u.exec(read.source);
|
|
1170
|
+
if (opened === null)
|
|
1171
|
+
return false;
|
|
1172
|
+
const opens = opened.index + opened[0].length;
|
|
1173
|
+
await writeFile2(path2, `${read.source.slice(0, opens)}
|
|
1174
|
+
"changelog/**/*",${read.source.slice(opens)}`);
|
|
1046
1175
|
return true;
|
|
1047
1176
|
};
|
|
1048
1177
|
var includeEntries = async (root) => {
|
|
@@ -1050,8 +1179,8 @@ var includeEntries = async (root) => {
|
|
|
1050
1179
|
return wired.some(Boolean) ? undefined : "no tsconfig include list to wire \u2014 make sure changelog/ is compiled by something";
|
|
1051
1180
|
};
|
|
1052
1181
|
var ignoreGenerated = async (root) => {
|
|
1053
|
-
const
|
|
1054
|
-
const existing = await readFile3(
|
|
1182
|
+
const path2 = join2(root, ".prettierignore");
|
|
1183
|
+
const existing = await readFile3(path2, "utf8").catch(() => "");
|
|
1055
1184
|
const wanted = [CHANGELOG_FILE, CHANGELOG_MARKDOWN].filter((name) => !existing.split(`
|
|
1056
1185
|
`).includes(name));
|
|
1057
1186
|
if (wanted.length === 0)
|
|
@@ -1059,7 +1188,7 @@ var ignoreGenerated = async (root) => {
|
|
|
1059
1188
|
const head = existing.trim() === "" ? `# Generated by absolute-changelog. Edit the entries, not these.
|
|
1060
1189
|
` : `${existing.trimEnd()}
|
|
1061
1190
|
`;
|
|
1062
|
-
await writeFile2(
|
|
1191
|
+
await writeFile2(path2, `${head}${wanted.join(`
|
|
1063
1192
|
`)}
|
|
1064
1193
|
`);
|
|
1065
1194
|
};
|
|
@@ -1078,8 +1207,8 @@ var adopt = async (root) => {
|
|
|
1078
1207
|
const paths = changelogPaths(root);
|
|
1079
1208
|
await mkdir(paths.unreleased, { recursive: true });
|
|
1080
1209
|
await writeFile2(join2(paths.unreleased, ".gitkeep"), "# Entries wait here. One file per change; `absolute-changelog release` consumes them.\n");
|
|
1081
|
-
|
|
1082
|
-
|
|
1210
|
+
const previous = existsSync(paths.markdown) ? await readFile3(paths.markdown, "utf8") : undefined;
|
|
1211
|
+
if (previous !== undefined && !previous.includes(GENERATED_MARKER) && !existsSync(paths.history)) {
|
|
1083
1212
|
await mkdir(join2(root, "changelog"), { recursive: true });
|
|
1084
1213
|
await writeFile2(paths.history, previous.replace(/^#\s+Changelog\s*/u, "").trimStart());
|
|
1085
1214
|
await rm(paths.markdown, { force: true });
|
|
@@ -1120,5 +1249,5 @@ await main().catch((error) => {
|
|
|
1120
1249
|
process.exit(1);
|
|
1121
1250
|
});
|
|
1122
1251
|
|
|
1123
|
-
//# debugId=
|
|
1252
|
+
//# debugId=4CD69EF0E551B35864756E2164756E21
|
|
1124
1253
|
//# sourceMappingURL=cli.js.map
|