@absolutejs/changelog 0.6.0 → 0.7.1

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/entries.d.ts CHANGED
@@ -8,6 +8,18 @@ export type LoadedEntries = {
8
8
  entries: LoadedEntry[];
9
9
  problems: string[];
10
10
  };
11
+ /**
12
+ * Whether the build is older than the source it was built from.
13
+ *
14
+ * The gate compares what is on disk against what was published, so a `dist`
15
+ * from yesterday reports yesterday's package. It cost an afternoon once: six
16
+ * exports reported as withdrawn from a package that had withdrawn nothing,
17
+ * because the build predated the source by a day.
18
+ *
19
+ * A warning rather than a failure -- a fresh checkout has every file at the
20
+ * same moment, and the publish path builds first anyway.
21
+ */
22
+ export declare const buildIsStale: (packageRoot: string) => Promise<boolean>;
11
23
  /**
12
24
  * The public surface a build produced, read the way a consumer would.
13
25
  *
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { applyMigration, applyMigrations, type MigrationResult } from "./apply";
2
2
  export { change, manual, moved, renamed } from "./authoring";
3
- export { builtSurface, changelogPaths, loadUnreleased, readJsonFile, type LoadedEntries, type LoadedEntry, } from "./entries";
3
+ export { buildIsStale, builtSurface, changelogPaths, loadUnreleased, readJsonFile, type LoadedEntries, type LoadedEntry, } from "./entries";
4
4
  export { changesBetween, disruptiveBetween, mechanicalMigrations, migrationsBetween, parseChangelog, releasesBetween, symbolsDisturbedBetween, validateChange, type ChangeAt, type ChangelogRead, type MigrationAt, } from "./read";
5
5
  export { describeReconciliation, reconcile, type Reconciliation, type Unannounced, } from "./reconcile";
6
6
  export { forgetRegistry, isPackageName, packageArchive, packageVersions, publishedChangelog, publishedSurface, type PackageVersions, type RegistryOptions, } from "./registry";
package/dist/index.js CHANGED
@@ -324,7 +324,7 @@ var renamed = (input) => change({
324
324
  symbols: [input.from]
325
325
  });
326
326
  // src/entries.ts
327
- import { readdir, readFile } from "fs/promises";
327
+ import { readdir, readFile, stat } from "fs/promises";
328
328
  import { join } from "path";
329
329
  import { pathToFileURL } from "url";
330
330
 
@@ -430,11 +430,11 @@ var readMigration = (value, where, problems) => {
430
430
  instruction,
431
431
  rename: { from: rename.from, to: rename.to }
432
432
  };
433
- const { moved: moved2 } = value;
434
- if (isRecord(moved2) && isText(moved2.symbol) && isText(moved2.from) && isText(moved2.to))
433
+ const { moved } = value;
434
+ if (isRecord(moved) && isText(moved.symbol) && isText(moved.from) && isText(moved.to))
435
435
  return {
436
436
  instruction,
437
- moved: { from: moved2.from, symbol: moved2.symbol, to: moved2.to }
437
+ moved: { from: moved.from, symbol: moved.symbol, to: moved.to }
438
438
  };
439
439
  const { resubpath } = value;
440
440
  if (isRecord(resubpath) && isText(resubpath.from) && isText(resubpath.to))
@@ -527,12 +527,12 @@ var readRelease = (value, where, problems) => {
527
527
  };
528
528
  var validateChange = (value, where = "entry") => {
529
529
  const problems = [];
530
- const change2 = readChange(value, where, problems);
531
- if (change2 === undefined) {
530
+ const change = readChange(value, where, problems);
531
+ if (change === undefined) {
532
532
  const failed = { problems };
533
533
  return failed;
534
534
  }
535
- const read = { change: change2 };
535
+ const read = { change };
536
536
  return read;
537
537
  };
538
538
  var parseChangelog = (value) => {
@@ -558,22 +558,22 @@ var parseChangelog = (value) => {
558
558
  };
559
559
  };
560
560
  var releasesBetween = (changelog, from, upto) => [...changelog.releases].filter((release) => compareVersions(release.version, from) > 0 && compareVersions(release.version, upto) <= 0).sort((left, right) => compareVersions(left.version, right.version));
561
- var changesBetween = (changelog, from, upto) => releasesBetween(changelog, from, upto).flatMap((release) => release.changes.map((change2) => {
562
- const found = { change: change2, version: release.version };
561
+ var changesBetween = (changelog, from, upto) => releasesBetween(changelog, from, upto).flatMap((release) => release.changes.map((change) => {
562
+ const found = { change, version: release.version };
563
563
  return found;
564
564
  }));
565
565
  var isDisruptiveAt = (found) => isDisruptive(found.change);
566
566
  var disruptiveBetween = (changelog, from, upto) => changesBetween(changelog, from, upto).filter(isDisruptiveAt);
567
567
  var mechanicalMigrations = (migrations) => migrations.filter((found) => isMechanical(found.migration));
568
- var migrationsBetween = (changelog, from, upto) => disruptiveBetween(changelog, from, upto).map(({ change: change2, version }) => {
568
+ var migrationsBetween = (changelog, from, upto) => disruptiveBetween(changelog, from, upto).map(({ change, version }) => {
569
569
  const found = {
570
- migration: change2.migration,
571
- symbols: change2.symbols,
570
+ migration: change.migration,
571
+ symbols: change.symbols,
572
572
  version
573
573
  };
574
574
  return found;
575
575
  });
576
- var symbolsDisturbedBetween = (changelog, from, upto) => new Set(disruptiveBetween(changelog, from, upto).flatMap(({ change: change2 }) => change2.symbols));
576
+ var symbolsDisturbedBetween = (changelog, from, upto) => new Set(disruptiveBetween(changelog, from, upto).flatMap(({ change }) => change.symbols));
577
577
 
578
578
  // src/surface.ts
579
579
  import path from "path";
@@ -634,6 +634,38 @@ var readTar = (archive, keep, limits = {}) => {
634
634
  var DECLARATION = /\.d\.[cm]?ts$/u;
635
635
  var parse2 = (source, name) => ts2.createSourceFile(name, source, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS);
636
636
  var normalize = (text) => text.replace(/\s+/gu, " ").trim();
637
+ var CLOSERS = new Set(["}", ")", "]", ">"]);
638
+ var wordy = (token) => /^[\w$#@]/u.test(token) || /[\w$]$/u.test(token);
639
+ var LAST2 = -1;
640
+ var tokenText = (scanner, scanned, state) => {
641
+ const closesTemplate = scanned === ts2.SyntaxKind.CloseBraceToken && state.templates.at(LAST2) === state.depth;
642
+ const token = closesTemplate ? scanner.reScanTemplateToken(false) : scanned;
643
+ if (closesTemplate && token === ts2.SyntaxKind.TemplateTail)
644
+ state.templates.pop();
645
+ if (closesTemplate)
646
+ return scanner.getTokenText();
647
+ if (token === ts2.SyntaxKind.StringLiteral)
648
+ return JSON.stringify(scanner.getTokenValue());
649
+ if (token === ts2.SyntaxKind.TemplateHead)
650
+ state.templates.push(state.depth);
651
+ if (token === ts2.SyntaxKind.OpenBraceToken)
652
+ state.depth += 1;
653
+ if (token === ts2.SyntaxKind.CloseBraceToken)
654
+ state.depth -= 1;
655
+ return scanner.getTokenText();
656
+ };
657
+ var canonical = (text) => {
658
+ const scanner = ts2.createScanner(ts2.ScriptTarget.Latest, true, ts2.LanguageVariant.Standard, text);
659
+ const state = { depth: 0, templates: [] };
660
+ const tokens = [];
661
+ for (let token = scanner.scan();token !== ts2.SyntaxKind.EndOfFileToken; token = scanner.scan()) {
662
+ const value = tokenText(scanner, token, state);
663
+ if (CLOSERS.has(value) && tokens.at(LAST2) === ",")
664
+ tokens.pop();
665
+ tokens.push(value);
666
+ }
667
+ return tokens.reduce((joined, token, index) => index > 0 && wordy(tokens[index - 1] ?? "") && wordy(token) ? `${joined} ${token}` : `${joined}${token}`, "");
668
+ };
637
669
  var resolveFrom = (files, from, specifier) => {
638
670
  if (!specifier.startsWith("."))
639
671
  return;
@@ -799,7 +831,7 @@ var SHAPE = {
799
831
  types: "types",
800
832
  unknown: "unknown"
801
833
  };
802
- var isStub = (declaration) => declaration.startsWith("export {");
834
+ var isStub = (declaration) => /^export\s*\{/u.test(declaration);
803
835
  var signatureOf = (declaration) => {
804
836
  const file = parse2(`${declaration}
805
837
  `, "declaration.d.ts");
@@ -815,7 +847,7 @@ var parametersOf = (declaration) => {
815
847
  const found = [];
816
848
  const visit = (node) => {
817
849
  if (ts2.isFunctionTypeNode(node) || ts2.isFunctionDeclaration(node) || ts2.isMethodSignature(node) || ts2.isMethodDeclaration(node) || ts2.isConstructSignatureDeclaration(node) || ts2.isConstructorDeclaration(node))
818
- found.push(node.parameters.map((parameter) => normalize(parameter.getText())).join(", "));
850
+ found.push(node.parameters.map((parameter) => canonical(parameter.getText())).join(", "));
819
851
  ts2.forEachChild(node, visit);
820
852
  };
821
853
  visit(statement);
@@ -835,12 +867,12 @@ var membersOf = (declaration) => {
835
867
  return members;
836
868
  };
837
869
  var sameNames = (left, right) => left.size === right.size && [...left].every((name) => right.has(name));
838
- var changeShape = (change2) => {
839
- if (isStub(change2.before) !== isStub(change2.after))
870
+ var changeShape = (change) => {
871
+ if (isStub(change.before) !== isStub(change.after))
840
872
  return SHAPE.unknown;
841
- if (parametersOf(change2.before) !== parametersOf(change2.after))
873
+ if (parametersOf(change.before) !== parametersOf(change.after))
842
874
  return SHAPE.parameters;
843
- if (!sameNames(membersOf(change2.before), membersOf(change2.after)))
875
+ if (!sameNames(membersOf(change.before), membersOf(change.after)))
844
876
  return SHAPE.members;
845
877
  return SHAPE.types;
846
878
  };
@@ -857,7 +889,7 @@ var diffSurface = (before, after) => {
857
889
  const lost = was.entries.filter((entry) => !now.entries.includes(entry));
858
890
  if (lost.length > 0)
859
891
  withdrawn.push({ from: lost, name });
860
- if (now.declaration !== was.declaration)
892
+ if (canonical(now.declaration) !== canonical(was.declaration))
861
893
  changed.push({
862
894
  after: now.declaration,
863
895
  before: was.declaration,
@@ -875,12 +907,12 @@ var diffSurface = (before, after) => {
875
907
  withdrawn
876
908
  };
877
909
  };
878
- var notable = (diff) => diff.changed.filter((change2) => change2.shape === "parameters" || change2.shape === "members");
910
+ var notable = (diff) => diff.changed.filter((change) => change.shape === "parameters" || change.shape === "members");
879
911
 
880
912
  // src/entries.ts
881
- var loadEntry = async (path2) => {
913
+ var loadEntry = async (path) => {
882
914
  try {
883
- const module = await import(pathToFileURL(path2).href);
915
+ const module = await import(pathToFileURL(path).href);
884
916
  const named = typeof module === "object" && module !== null && "change" in module ? module.change : undefined;
885
917
  const exported = named ?? (typeof module === "object" && module !== null && "default" in module ? module.default : undefined);
886
918
  const read = { exported };
@@ -895,6 +927,23 @@ var loadEntry = async (path2) => {
895
927
  var ENTRY = /\.[cm]?ts$/u;
896
928
  var DECLARATION2 = /\.d\.[cm]?ts$/u;
897
929
  var OUTPUT_DIRECTORIES = ["dist", "build", "lib", "types", "out"];
930
+ var newestUnder = async (root) => {
931
+ const found = await readdir(root, { withFileTypes: true }).catch(() => []);
932
+ const times = await Promise.all(found.map(async (entry) => {
933
+ const path = join(root, entry.name);
934
+ if (entry.isDirectory())
935
+ return newestUnder(path);
936
+ return stat(path).then((stats) => stats.mtimeMs, () => 0);
937
+ }));
938
+ return Math.max(0, ...times);
939
+ };
940
+ var buildIsStale = async (packageRoot) => {
941
+ const [source, built] = await Promise.all([
942
+ newestUnder(join(packageRoot, "src")),
943
+ Promise.all(OUTPUT_DIRECTORIES.map((directory) => newestUnder(join(packageRoot, directory)))).then((times) => Math.max(0, ...times))
944
+ ]);
945
+ return source > 0 && built > 0 && source > built;
946
+ };
898
947
  var builtSurface = async (packageRoot) => {
899
948
  const manifest = await readJsonFile(join(packageRoot, "package.json"));
900
949
  const files = new Map;
@@ -940,8 +989,8 @@ var loadUnreleased = async (packageRoot) => {
940
989
  }
941
990
  return { entries, problems };
942
991
  };
943
- var readJsonFile = async (path2) => {
944
- const source = await readFile(path2, "utf8").catch(() => {
992
+ var readJsonFile = async (path) => {
993
+ const source = await readFile(path, "utf8").catch(() => {
945
994
  return;
946
995
  });
947
996
  if (source === undefined)
@@ -959,39 +1008,39 @@ var strayEntries = async (packageRoot) => {
959
1008
  };
960
1009
  // src/reconcile.ts
961
1010
  var migrationHolds = (input) => {
962
- const { after, change: change2, subpaths } = input;
1011
+ const { after, change, subpaths } = input;
963
1012
  const wrong = [];
964
- const { migration } = change2;
1013
+ const { migration } = change;
965
1014
  if ("rename" in migration) {
966
1015
  const { from } = migration.rename;
967
1016
  const into = migration.rename.to;
968
1017
  if (!after.has(into))
969
- wrong.push(`\`${change2.summary}\` renames to \`${into}\`, which this version does not export`);
1018
+ wrong.push(`\`${change.summary}\` renames to \`${into}\`, which this version does not export`);
970
1019
  if (after.has(from))
971
- wrong.push(`\`${change2.summary}\` renames \`${from}\` away, but this version still exports it`);
972
- if (!change2.symbols.includes(from))
973
- wrong.push(`\`${change2.summary}\` renames \`${from}\`, which is not in its own symbols`);
1020
+ wrong.push(`\`${change.summary}\` renames \`${from}\` away, but this version still exports it`);
1021
+ if (!change.symbols.includes(from))
1022
+ wrong.push(`\`${change.summary}\` renames \`${from}\`, which is not in its own symbols`);
974
1023
  }
975
1024
  if ("moved" in migration) {
976
1025
  const { symbol } = migration.moved;
977
1026
  const into = migration.moved.to;
978
1027
  if (!after.has(symbol))
979
- wrong.push(`\`${change2.summary}\` moves \`${symbol}\`, which this version does not export`);
1028
+ wrong.push(`\`${change.summary}\` moves \`${symbol}\`, which this version does not export`);
980
1029
  if (subpaths.size > 0 && !subpaths.has(into))
981
- wrong.push(`\`${change2.summary}\` moves \`${symbol}\` to \`${into}\`, which is not an entry point of this package`);
1030
+ wrong.push(`\`${change.summary}\` moves \`${symbol}\` to \`${into}\`, which is not an entry point of this package`);
982
1031
  }
983
1032
  if ("resubpath" in migration && subpaths.size > 0 && !subpaths.has(migration.resubpath.to))
984
- wrong.push(`\`${change2.summary}\` points at \`${migration.resubpath.to}\`, which is not an entry point of this package`);
985
- if (change2.kind === "removed") {
986
- for (const symbol of change2.symbols)
1033
+ wrong.push(`\`${change.summary}\` points at \`${migration.resubpath.to}\`, which is not an entry point of this package`);
1034
+ if (change.kind === "removed") {
1035
+ for (const symbol of change.symbols)
987
1036
  if (after.has(symbol))
988
- wrong.push(`\`${change2.summary}\` says \`${symbol}\` was removed, but this version still exports it`);
1037
+ wrong.push(`\`${change.summary}\` says \`${symbol}\` was removed, but this version still exports it`);
989
1038
  }
990
1039
  return wrong;
991
1040
  };
992
1041
  var describeReconciliation = (found) => {
993
1042
  const lines = [];
994
- const moved2 = {
1043
+ const moved = {
995
1044
  members: "changed the members of its type",
996
1045
  parameters: "changed what it is called with",
997
1046
  removed: "is no longer exported",
@@ -999,27 +1048,27 @@ var describeReconciliation = (found) => {
999
1048
  withdrawn: "is no longer exported from"
1000
1049
  };
1001
1050
  for (const entry of found.unannounced)
1002
- lines.push(entry.kind === "withdrawn" ? `\`${entry.name}\` ${moved2.withdrawn} ${(entry.from ?? []).join(", ")} and no entry says so` : `\`${entry.name}\` ${moved2[entry.kind]} and no entry says so`);
1051
+ lines.push(entry.kind === "withdrawn" ? `\`${entry.name}\` ${moved.withdrawn} ${(entry.from ?? []).join(", ")} and no entry says so` : `\`${entry.name}\` ${moved[entry.kind]} and no entry says so`);
1003
1052
  for (const name of found.unknownSymbols)
1004
1053
  lines.push(`an entry names \`${name}\`, which this package does not export`);
1005
1054
  lines.push(...found.wrongMigrations);
1006
1055
  return lines;
1007
1056
  };
1008
1057
  var reconcile = (input) => {
1009
- const disruptive = new Set(input.changes.filter(isDisruptive).flatMap((change2) => [...change2.symbols]));
1010
- const mentioned = new Set(input.changes.flatMap((change2) => [...change2.symbols ?? []]));
1058
+ const disruptive = new Set(input.changes.filter(isDisruptive).flatMap((change) => [...change.symbols]));
1059
+ const mentioned = new Set(input.changes.flatMap((change) => [...change.symbols ?? []]));
1011
1060
  const unannounced = [
1012
1061
  ...input.diff.removed.filter((name) => !disruptive.has(name)).map((name) => ({ kind: "removed", name })),
1013
1062
  ...input.diff.withdrawn.filter((entry) => !disruptive.has(entry.name)).map((entry) => ({ from: entry.from, kind: "withdrawn", name: entry.name })),
1014
- ...input.diff.changed.filter((change2) => !mentioned.has(change2.name) && change2.shape !== "unknown").map((change2) => ({ kind: change2.shape, name: change2.name }))
1063
+ ...input.diff.changed.filter((change) => !mentioned.has(change.name) && change.shape !== "unknown").map((change) => ({ kind: change.shape, name: change.name }))
1015
1064
  ];
1016
1065
  const unknownSymbols = [
1017
- ...new Set(input.changes.flatMap((change2) => [...change2.symbols ?? []]).filter((name) => !input.known.has(name)))
1066
+ ...new Set(input.changes.flatMap((change) => [...change.symbols ?? []]).filter((name) => !input.known.has(name)))
1018
1067
  ];
1019
1068
  const { after } = input;
1020
- const wrongMigrations = after === undefined ? [] : input.changes.filter(isDisruptive).flatMap((change2) => migrationHolds({
1069
+ const wrongMigrations = after === undefined ? [] : input.changes.filter(isDisruptive).flatMap((change) => migrationHolds({
1021
1070
  after,
1022
- change: change2,
1071
+ change,
1023
1072
  subpaths: input.subpaths ?? new Set
1024
1073
  }));
1025
1074
  return { unannounced, unknownSymbols, wrongMigrations };
@@ -1118,7 +1167,7 @@ var publishedChangelog = async (name, version, options = {}) => {
1118
1167
  const archive = await packageArchive(name, version, options);
1119
1168
  if (!archive)
1120
1169
  return;
1121
- const file = readTar(archive, (path2) => path2 === CHANGELOG_FILE).get(CHANGELOG_FILE);
1170
+ const file = readTar(archive, (path) => path === CHANGELOG_FILE).get(CHANGELOG_FILE);
1122
1171
  if (!file)
1123
1172
  return;
1124
1173
  try {
@@ -1161,19 +1210,19 @@ var migrationLine = (migration) => {
1161
1210
  return `Import from \`${migration.resubpath.to}\` instead of \`${migration.resubpath.from}\`.`;
1162
1211
  return migration.instruction;
1163
1212
  };
1164
- var renderChange = (change2) => {
1165
- const symbols = change2.symbols && change2.symbols.length > 0 ? ` (${change2.symbols.map((name) => `\`${name}\``).join(", ")})` : "";
1166
- const lines = [`- **${change2.summary}**${symbols}`];
1167
- if (change2.detail !== undefined)
1168
- lines.push(` ${change2.detail}`);
1169
- if (isDisruptive(change2)) {
1170
- lines.push(` _Migration:_ ${change2.migration.instruction}`);
1171
- const mechanical = migrationLine(change2.migration);
1172
- if (mechanical !== change2.migration.instruction)
1213
+ var renderChange = (change) => {
1214
+ const symbols = change.symbols && change.symbols.length > 0 ? ` (${change.symbols.map((name) => `\`${name}\``).join(", ")})` : "";
1215
+ const lines = [`- **${change.summary}**${symbols}`];
1216
+ if (change.detail !== undefined)
1217
+ lines.push(` ${change.detail}`);
1218
+ if (isDisruptive(change)) {
1219
+ lines.push(` _Migration:_ ${change.migration.instruction}`);
1220
+ const mechanical = migrationLine(change.migration);
1221
+ if (mechanical !== change.migration.instruction)
1173
1222
  lines.push(` _Applied automatically:_ ${mechanical}`);
1174
1223
  }
1175
- if (change2.reference !== undefined)
1176
- lines.push(` See ${change2.reference}.`);
1224
+ if (change.reference !== undefined)
1225
+ lines.push(` See ${change.reference}.`);
1177
1226
  return lines.join(`
1178
1227
  `);
1179
1228
  };
@@ -1200,13 +1249,13 @@ var renderChangelogJson = (changelog) => `${JSON.stringify({
1200
1249
  contract: CHANGELOG_CONTRACT,
1201
1250
  name: changelog.name,
1202
1251
  releases: [...changelog.releases].sort((left, right) => compareVersions(right.version, left.version)).map((release) => ({
1203
- changes: release.changes.map((change2) => ({
1204
- ...change2.detail === undefined ? {} : { detail: change2.detail },
1205
- kind: change2.kind,
1206
- ...isDisruptive(change2) ? { migration: change2.migration } : {},
1207
- ...change2.reference === undefined ? {} : { reference: change2.reference },
1208
- summary: change2.summary,
1209
- ...change2.symbols && change2.symbols.length > 0 ? { symbols: change2.symbols } : {}
1252
+ changes: release.changes.map((change) => ({
1253
+ ...change.detail === undefined ? {} : { detail: change.detail },
1254
+ kind: change.kind,
1255
+ ...isDisruptive(change) ? { migration: change.migration } : {},
1256
+ ...change.reference === undefined ? {} : { reference: change.reference },
1257
+ summary: change.summary,
1258
+ ...change.symbols && change.symbols.length > 0 ? { symbols: change.symbols } : {}
1210
1259
  })),
1211
1260
  date: release.date,
1212
1261
  ...release.note === undefined ? {} : { note: release.note },
@@ -1246,6 +1295,7 @@ export {
1246
1295
  applyMigration,
1247
1296
  applyMigrations,
1248
1297
  asText,
1298
+ buildIsStale,
1249
1299
  builtSurface,
1250
1300
  change,
1251
1301
  changeShape,
@@ -1289,5 +1339,5 @@ export {
1289
1339
  validateChange
1290
1340
  };
1291
1341
 
1292
- //# debugId=C07818292D22AD6164756E2164756E21
1342
+ //# debugId=00D829A9B9D35BB264756E2164756E21
1293
1343
  //# sourceMappingURL=index.js.map