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