@absolutejs/changelog 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +158 -0
- package/changelog.json +16 -0
- package/dist/apply.d.ts +34 -0
- package/dist/authoring.d.ts +79 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1007 -0
- package/dist/cli.js.map +19 -0
- package/dist/entries.d.ts +23 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +946 -0
- package/dist/index.js.map +20 -0
- package/dist/read.d.ts +63 -0
- package/dist/reconcile.d.ts +23 -0
- package/dist/registry.d.ts +32 -0
- package/dist/surface.d.ts +55 -0
- package/dist/tarball.d.ts +17 -0
- package/dist/types.d.ts +117 -0
- package/dist/versioning.d.ts +25 -0
- package/dist/write.d.ts +10 -0
- package/package.json +72 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,946 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/types.ts
|
|
3
|
+
var CHANGE_KINDS = [
|
|
4
|
+
"breaking",
|
|
5
|
+
"removed",
|
|
6
|
+
"added",
|
|
7
|
+
"changed",
|
|
8
|
+
"deprecated",
|
|
9
|
+
"fixed",
|
|
10
|
+
"security",
|
|
11
|
+
"internal"
|
|
12
|
+
];
|
|
13
|
+
var DISRUPTIVE_KINDS = ["breaking", "removed"];
|
|
14
|
+
var CHANGELOG_CONTRACT = 1;
|
|
15
|
+
var CHANGELOG_FILE = "changelog.json";
|
|
16
|
+
var CHANGELOG_MARKDOWN = "CHANGELOG.md";
|
|
17
|
+
var UNRELEASED_DIRECTORY = "changelog/unreleased";
|
|
18
|
+
var isDisruptive = (change) => change.kind === "breaking" || change.kind === "removed";
|
|
19
|
+
var isMechanical = (migration) => !("manual" in migration);
|
|
20
|
+
|
|
21
|
+
// src/apply.ts
|
|
22
|
+
var IS_CODE = -1;
|
|
23
|
+
var IMPORT = /(?:import|export)\s+(?:type\s+)?(?<clause>[\s\S]*?)\s*from\s*(?<quote>['"])(?<module>[^'"]+)\k<quote>/gu;
|
|
24
|
+
var importsOf = (source) => {
|
|
25
|
+
const found = [];
|
|
26
|
+
for (const match of source.matchAll(IMPORT)) {
|
|
27
|
+
const { clause, module } = match.groups ?? {};
|
|
28
|
+
if (module === undefined || match.index === undefined)
|
|
29
|
+
continue;
|
|
30
|
+
const braced = clause === undefined ? undefined : /\{([\s\S]*)\}/u.exec(clause);
|
|
31
|
+
found.push({
|
|
32
|
+
clause: braced?.[1],
|
|
33
|
+
end: match.index + match[0].length,
|
|
34
|
+
full: match[0],
|
|
35
|
+
module,
|
|
36
|
+
start: match.index
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return found;
|
|
40
|
+
};
|
|
41
|
+
var belongsTo = (specifier, name) => specifier === name || specifier.startsWith(`${name}/`);
|
|
42
|
+
var skipEnd = (source, index) => {
|
|
43
|
+
const character = source[index];
|
|
44
|
+
const next = source[index + 1];
|
|
45
|
+
if (character === "/" && next === "/") {
|
|
46
|
+
const line = source.indexOf(`
|
|
47
|
+
`, index);
|
|
48
|
+
return line < 0 ? source.length : line;
|
|
49
|
+
}
|
|
50
|
+
if (character === "/" && next === "*") {
|
|
51
|
+
const close = source.indexOf("*/", index + 2);
|
|
52
|
+
return close < 0 ? source.length : close + 2;
|
|
53
|
+
}
|
|
54
|
+
if (character !== "'" && character !== '"' && character !== "`")
|
|
55
|
+
return IS_CODE;
|
|
56
|
+
let cursor = index + 1;
|
|
57
|
+
while (cursor < source.length && source[cursor] !== character)
|
|
58
|
+
cursor += source[cursor] === "\\" ? 2 : 1;
|
|
59
|
+
return Math.min(cursor + 1, source.length);
|
|
60
|
+
};
|
|
61
|
+
var codeSpans = (source) => {
|
|
62
|
+
const spans = [];
|
|
63
|
+
let start = 0;
|
|
64
|
+
let index = 0;
|
|
65
|
+
const closeSpan = (ends, resumes) => {
|
|
66
|
+
spans.push([start, ends]);
|
|
67
|
+
start = resumes;
|
|
68
|
+
};
|
|
69
|
+
while (index < source.length) {
|
|
70
|
+
const skipped = skipEnd(source, index);
|
|
71
|
+
if (skipped > IS_CODE)
|
|
72
|
+
closeSpan(index, skipped);
|
|
73
|
+
index = skipped === IS_CODE ? index + 1 : skipped;
|
|
74
|
+
}
|
|
75
|
+
spans.push([start, source.length]);
|
|
76
|
+
return spans;
|
|
77
|
+
};
|
|
78
|
+
var renameInCode = (source, from, into) => {
|
|
79
|
+
const pattern = new RegExp(`(?<![.\\w$])${from.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}(?![\\w$])`, "gu");
|
|
80
|
+
let out = "";
|
|
81
|
+
let cursor = 0;
|
|
82
|
+
for (const [start, end] of codeSpans(source)) {
|
|
83
|
+
out += source.slice(cursor, start);
|
|
84
|
+
out += source.slice(start, end).replace(pattern, into);
|
|
85
|
+
cursor = end;
|
|
86
|
+
}
|
|
87
|
+
return out + source.slice(cursor);
|
|
88
|
+
};
|
|
89
|
+
var declaresLocally = (source, name) => new RegExp(`\\b(?:const|let|var|function|class|interface|type|enum)\\s+${name.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}\\b`, "u").test(source);
|
|
90
|
+
var applyRename = (source, packageName, rename) => {
|
|
91
|
+
const statements = importsOf(source).filter((statement) => belongsTo(statement.module, packageName) && statement.clause !== undefined && new RegExp(`(?<![\\w$])${rename.from}(?![\\w$])`, "u").test(statement.clause));
|
|
92
|
+
if (statements.length === 0)
|
|
93
|
+
return { changed: false, notes: [], source };
|
|
94
|
+
const aliased = statements.some((statement) => new RegExp(`(?<![\\w$])${rename.from}\\s+as\\s`, "u").test(statement.clause ?? ""));
|
|
95
|
+
if (aliased) {
|
|
96
|
+
let out = source;
|
|
97
|
+
for (const statement of statements)
|
|
98
|
+
out = out.replace(statement.full, statement.full.replace(new RegExp(`(?<![\\w$])${rename.from}(\\s+as\\s)`, "u"), `${rename.to}$1`));
|
|
99
|
+
return { changed: true, notes: [], source: out };
|
|
100
|
+
}
|
|
101
|
+
if (declaresLocally(source, rename.from)) {
|
|
102
|
+
let out = source;
|
|
103
|
+
for (const statement of statements)
|
|
104
|
+
out = out.replace(statement.full, statement.full.replace(new RegExp(`(?<![\\w$])${rename.from}(?![\\w$])`, "u"), `${rename.to} as ${rename.from}`));
|
|
105
|
+
return {
|
|
106
|
+
changed: true,
|
|
107
|
+
notes: [
|
|
108
|
+
`\`${rename.from}\` is also declared in this file, so the import was aliased instead of the uses being renamed`
|
|
109
|
+
],
|
|
110
|
+
source: out
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
changed: true,
|
|
115
|
+
notes: [],
|
|
116
|
+
source: renameInCode(source, rename.from, rename.to)
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
var applyResubpath = (source, resubpath) => {
|
|
120
|
+
const statements = importsOf(source).filter((statement) => statement.module === resubpath.from);
|
|
121
|
+
if (statements.length === 0)
|
|
122
|
+
return { changed: false, notes: [], source };
|
|
123
|
+
let out = source;
|
|
124
|
+
for (const statement of statements)
|
|
125
|
+
out = out.replace(statement.full, statement.full.replace(resubpath.from, resubpath.to));
|
|
126
|
+
return { changed: true, notes: [], source: out };
|
|
127
|
+
};
|
|
128
|
+
var applyMoved = (source, moved) => {
|
|
129
|
+
const pattern = new RegExp(`(?<![\\w$])${moved.symbol}(?![\\w$])`, "u");
|
|
130
|
+
const statements = importsOf(source).filter((statement) => statement.module === moved.from && statement.clause !== undefined && pattern.test(statement.clause));
|
|
131
|
+
if (statements.length === 0)
|
|
132
|
+
return { changed: false, notes: [], source };
|
|
133
|
+
let out = source;
|
|
134
|
+
for (const statement of statements) {
|
|
135
|
+
const clause = statement.clause ?? "";
|
|
136
|
+
const kept = clause.split(",").map((part) => part.trim()).filter((part) => part !== "" && !pattern.test(part));
|
|
137
|
+
const replacement = kept.length === 0 ? statement.full.replace(moved.from, moved.to) : `${statement.full.replace(clause, ` ${kept.join(", ")} `).replace(/\s+/gu, " ")}
|
|
138
|
+
import { ${moved.symbol} } from '${moved.to}';`;
|
|
139
|
+
out = out.replace(statement.full, replacement);
|
|
140
|
+
}
|
|
141
|
+
return { changed: true, notes: [], source: out };
|
|
142
|
+
};
|
|
143
|
+
var applyMigration = (source, input) => {
|
|
144
|
+
const { migration, packageName } = input;
|
|
145
|
+
if (!isMechanical(migration))
|
|
146
|
+
return { changed: false, notes: [migration.instruction], source };
|
|
147
|
+
if ("rename" in migration)
|
|
148
|
+
return applyRename(source, packageName, migration.rename);
|
|
149
|
+
if ("resubpath" in migration)
|
|
150
|
+
return applyResubpath(source, migration.resubpath);
|
|
151
|
+
return applyMoved(source, migration.moved);
|
|
152
|
+
};
|
|
153
|
+
var applyMigrations = (source, input) => input.migrations.reduce((carried, migration) => {
|
|
154
|
+
const result = applyMigration(carried.source, {
|
|
155
|
+
migration,
|
|
156
|
+
packageName: input.packageName
|
|
157
|
+
});
|
|
158
|
+
return {
|
|
159
|
+
changed: carried.changed || result.changed,
|
|
160
|
+
notes: [...carried.notes, ...result.notes],
|
|
161
|
+
source: result.source
|
|
162
|
+
};
|
|
163
|
+
}, { changed: false, notes: [], source });
|
|
164
|
+
// src/authoring.ts
|
|
165
|
+
var change = (entry) => entry;
|
|
166
|
+
var manual = (instruction) => ({
|
|
167
|
+
instruction,
|
|
168
|
+
manual: true
|
|
169
|
+
});
|
|
170
|
+
var moved = (input) => change({
|
|
171
|
+
...input.detail === undefined ? {} : { detail: input.detail },
|
|
172
|
+
kind: "breaking",
|
|
173
|
+
migration: {
|
|
174
|
+
instruction: `Import \`${input.symbol}\` from \`${input.to}\`.`,
|
|
175
|
+
moved: { from: input.from, symbol: input.symbol, to: input.to }
|
|
176
|
+
},
|
|
177
|
+
...input.reference === undefined ? {} : { reference: input.reference },
|
|
178
|
+
summary: `\`${input.symbol}\` moved to \`${input.to}\``,
|
|
179
|
+
symbols: [input.symbol]
|
|
180
|
+
});
|
|
181
|
+
var renamed = (input) => change({
|
|
182
|
+
...input.detail === undefined ? {} : { detail: input.detail },
|
|
183
|
+
kind: "breaking",
|
|
184
|
+
migration: {
|
|
185
|
+
instruction: `Import \`${input.to}\` instead of \`${input.from}\`.`,
|
|
186
|
+
rename: { from: input.from, to: input.to }
|
|
187
|
+
},
|
|
188
|
+
...input.reference === undefined ? {} : { reference: input.reference },
|
|
189
|
+
summary: `\`${input.from}\` is now \`${input.to}\``,
|
|
190
|
+
symbols: [input.from]
|
|
191
|
+
});
|
|
192
|
+
// src/entries.ts
|
|
193
|
+
import { readdir, readFile } from "fs/promises";
|
|
194
|
+
import { join } from "path";
|
|
195
|
+
import { pathToFileURL } from "url";
|
|
196
|
+
|
|
197
|
+
// src/versioning.ts
|
|
198
|
+
var OLDER = -1;
|
|
199
|
+
var LAST = -1;
|
|
200
|
+
var NEWER = 1;
|
|
201
|
+
var VERSION = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/u;
|
|
202
|
+
var parseVersion = (version) => {
|
|
203
|
+
const found = VERSION.exec(version.trim());
|
|
204
|
+
if (!found)
|
|
205
|
+
return;
|
|
206
|
+
const [, major, minor, patch, prerelease] = found;
|
|
207
|
+
return {
|
|
208
|
+
prerelease: prerelease === undefined ? [] : prerelease.split("."),
|
|
209
|
+
release: [Number(major), Number(minor), Number(patch)]
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
var isNumeric = (value) => /^\d+$/u.test(value);
|
|
213
|
+
var comparePrerelease = (left, right) => {
|
|
214
|
+
if (left.length === 0 || right.length === 0)
|
|
215
|
+
return right.length - left.length;
|
|
216
|
+
for (const [index, mine] of left.entries()) {
|
|
217
|
+
const theirs = right[index];
|
|
218
|
+
if (theirs === undefined)
|
|
219
|
+
return NEWER;
|
|
220
|
+
if (mine === theirs)
|
|
221
|
+
continue;
|
|
222
|
+
if (isNumeric(mine) && isNumeric(theirs))
|
|
223
|
+
return Number(mine) - Number(theirs);
|
|
224
|
+
if (isNumeric(mine))
|
|
225
|
+
return OLDER;
|
|
226
|
+
if (isNumeric(theirs))
|
|
227
|
+
return NEWER;
|
|
228
|
+
return mine < theirs ? OLDER : NEWER;
|
|
229
|
+
}
|
|
230
|
+
return left.length - right.length;
|
|
231
|
+
};
|
|
232
|
+
var compareVersions = (left, right) => {
|
|
233
|
+
const mine = parseVersion(left);
|
|
234
|
+
const theirs = parseVersion(right);
|
|
235
|
+
if (!mine || !theirs)
|
|
236
|
+
return 0;
|
|
237
|
+
for (const [index, part] of mine.release.entries()) {
|
|
238
|
+
const other = theirs.release[index] ?? 0;
|
|
239
|
+
if (part !== other)
|
|
240
|
+
return part - other;
|
|
241
|
+
}
|
|
242
|
+
return comparePrerelease(mine.prerelease, theirs.prerelease);
|
|
243
|
+
};
|
|
244
|
+
var isPrerelease = (version) => (parseVersion(version)?.prerelease.length ?? 0) > 0;
|
|
245
|
+
var releaseKindFor = (changes) => {
|
|
246
|
+
if (changes.some(isDisruptive)) {
|
|
247
|
+
const major = "major";
|
|
248
|
+
return major;
|
|
249
|
+
}
|
|
250
|
+
const asked = changes.some((entry) => entry.kind === "added") ? "minor" : "patch";
|
|
251
|
+
return asked;
|
|
252
|
+
};
|
|
253
|
+
var bumpPrerelease = (parsed) => {
|
|
254
|
+
const { prerelease, release } = parsed;
|
|
255
|
+
const last = prerelease.at(LAST);
|
|
256
|
+
const counted = last !== undefined && isNumeric(last) ? [...prerelease.slice(0, LAST), String(Number(last) + 1)] : [...prerelease, "1"];
|
|
257
|
+
return `${release.join(".")}-${counted.join(".")}`;
|
|
258
|
+
};
|
|
259
|
+
var nextVersion = (input) => {
|
|
260
|
+
const parsed = parseVersion(input.current);
|
|
261
|
+
if (!parsed)
|
|
262
|
+
return;
|
|
263
|
+
const [major, minor, patch] = parsed.release;
|
|
264
|
+
const kind = input.asked ?? (parsed.prerelease.length > 0 ? "prerelease" : releaseKindFor(input.changes));
|
|
265
|
+
if (kind === "prerelease")
|
|
266
|
+
return parsed.prerelease.length > 0 ? bumpPrerelease(parsed) : `${major}.${minor}.${patch + 1}-${input.prereleaseIdentifier ?? "beta"}.1`;
|
|
267
|
+
if (parsed.prerelease.length > 0 && kind === "patch")
|
|
268
|
+
return `${major}.${minor}.${patch}`;
|
|
269
|
+
if (kind === "major")
|
|
270
|
+
return major === 0 ? `${major}.${minor + 1}.0` : `${major + 1}.0.0`;
|
|
271
|
+
return kind === "minor" ? `${major}.${minor + 1}.0` : `${major}.${minor}.${patch + 1}`;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// src/read.ts
|
|
275
|
+
var isKind = (value) => typeof value === "string" && CHANGE_KINDS.some((known) => known === value);
|
|
276
|
+
var isDisruptiveKind = (kind) => kind === "breaking" || kind === "removed";
|
|
277
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
278
|
+
var isText = (value) => typeof value === "string" && value.trim().length > 0;
|
|
279
|
+
var textList = (value) => Array.isArray(value) && value.length > 0 && value.every(isText) ? value : undefined;
|
|
280
|
+
var readMigration = (value, where, problems) => {
|
|
281
|
+
if (!isRecord(value) || !isText(value.instruction)) {
|
|
282
|
+
problems.push(`${where}: migration needs an instruction`);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const { instruction } = value;
|
|
286
|
+
const { rename } = value;
|
|
287
|
+
if (isRecord(rename) && isText(rename.from) && isText(rename.to))
|
|
288
|
+
return {
|
|
289
|
+
instruction,
|
|
290
|
+
rename: { from: rename.from, to: rename.to }
|
|
291
|
+
};
|
|
292
|
+
const { moved: moved2 } = value;
|
|
293
|
+
if (isRecord(moved2) && isText(moved2.symbol) && isText(moved2.from) && isText(moved2.to))
|
|
294
|
+
return {
|
|
295
|
+
instruction,
|
|
296
|
+
moved: { from: moved2.from, symbol: moved2.symbol, to: moved2.to }
|
|
297
|
+
};
|
|
298
|
+
const { resubpath } = value;
|
|
299
|
+
if (isRecord(resubpath) && isText(resubpath.from) && isText(resubpath.to))
|
|
300
|
+
return {
|
|
301
|
+
instruction,
|
|
302
|
+
resubpath: { from: resubpath.from, to: resubpath.to }
|
|
303
|
+
};
|
|
304
|
+
if (value.manual === true)
|
|
305
|
+
return { instruction, manual: true };
|
|
306
|
+
problems.push(`${where}: migration says neither rename, moved, resubpath nor manual`);
|
|
307
|
+
return;
|
|
308
|
+
};
|
|
309
|
+
var readChange = (value, where, problems) => {
|
|
310
|
+
if (!isRecord(value)) {
|
|
311
|
+
problems.push(`${where}: not an object`);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const { kind } = value;
|
|
315
|
+
if (!isKind(kind)) {
|
|
316
|
+
problems.push(`${where}: unknown kind ${JSON.stringify(kind)}`);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (!isText(value.summary)) {
|
|
320
|
+
problems.push(`${where}: needs a summary`);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
const shared = {
|
|
324
|
+
...isText(value.detail) ? { detail: value.detail } : {},
|
|
325
|
+
...isText(value.reference) ? { reference: value.reference } : {},
|
|
326
|
+
summary: value.summary
|
|
327
|
+
};
|
|
328
|
+
const symbols = textList(value.symbols);
|
|
329
|
+
const [first, ...rest] = symbols ?? [];
|
|
330
|
+
if (kind === "breaking" || kind === "removed") {
|
|
331
|
+
const migration = readMigration(value.migration, where, problems);
|
|
332
|
+
if (first === undefined)
|
|
333
|
+
problems.push(`${where}: a ${kind} change must name symbols`);
|
|
334
|
+
if (!migration || first === undefined)
|
|
335
|
+
return;
|
|
336
|
+
const named = [first, ...rest];
|
|
337
|
+
const disruptive = {
|
|
338
|
+
...shared,
|
|
339
|
+
kind,
|
|
340
|
+
migration,
|
|
341
|
+
symbols: named
|
|
342
|
+
};
|
|
343
|
+
return disruptive;
|
|
344
|
+
}
|
|
345
|
+
if (isDisruptiveKind(kind))
|
|
346
|
+
return;
|
|
347
|
+
const ordinary = {
|
|
348
|
+
...shared,
|
|
349
|
+
kind,
|
|
350
|
+
...symbols ? { symbols } : {}
|
|
351
|
+
};
|
|
352
|
+
return ordinary;
|
|
353
|
+
};
|
|
354
|
+
var readRelease = (value, where, problems) => {
|
|
355
|
+
if (!isRecord(value)) {
|
|
356
|
+
problems.push(`${where}: not an object`);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (!isText(value.version) || parseVersion(value.version) === undefined) {
|
|
360
|
+
problems.push(`${where}: version is not a version`);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (!isText(value.date)) {
|
|
364
|
+
problems.push(`${where}: needs a date`);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const raw = value.changes;
|
|
368
|
+
if (!Array.isArray(raw) || raw.length === 0) {
|
|
369
|
+
problems.push(`${where}: a release with no changes is not a release`);
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const changes = raw.map((entry, index) => readChange(entry, `${where}.changes[${index}]`, problems)).filter((entry) => entry !== undefined);
|
|
373
|
+
if (changes.length !== raw.length)
|
|
374
|
+
return;
|
|
375
|
+
const [head, ...tail] = changes;
|
|
376
|
+
if (head === undefined)
|
|
377
|
+
return;
|
|
378
|
+
const release = {
|
|
379
|
+
changes: [head, ...tail],
|
|
380
|
+
date: value.date,
|
|
381
|
+
...isText(value.note) ? { note: value.note } : {},
|
|
382
|
+
version: value.version
|
|
383
|
+
};
|
|
384
|
+
return release;
|
|
385
|
+
};
|
|
386
|
+
var validateChange = (value, where = "entry") => {
|
|
387
|
+
const problems = [];
|
|
388
|
+
const change2 = readChange(value, where, problems);
|
|
389
|
+
if (change2 === undefined) {
|
|
390
|
+
const failed = { problems };
|
|
391
|
+
return failed;
|
|
392
|
+
}
|
|
393
|
+
const read = { change: change2 };
|
|
394
|
+
return read;
|
|
395
|
+
};
|
|
396
|
+
var parseChangelog = (value) => {
|
|
397
|
+
const problems = [];
|
|
398
|
+
if (!isRecord(value))
|
|
399
|
+
return { problems: ["not an object"] };
|
|
400
|
+
if (!isText(value.name))
|
|
401
|
+
problems.push("needs a package name");
|
|
402
|
+
if (value.contract !== CHANGELOG_CONTRACT)
|
|
403
|
+
problems.push(`contract ${JSON.stringify(value.contract)} is not ${CHANGELOG_CONTRACT}`);
|
|
404
|
+
const raw = value.releases;
|
|
405
|
+
if (!Array.isArray(raw))
|
|
406
|
+
problems.push("releases is not a list");
|
|
407
|
+
const releases = (Array.isArray(raw) ? raw : []).map((entry, index) => readRelease(entry, `releases[${index}]`, problems)).filter((entry) => entry !== undefined);
|
|
408
|
+
if (problems.length > 0)
|
|
409
|
+
return { problems };
|
|
410
|
+
return {
|
|
411
|
+
changelog: {
|
|
412
|
+
contract: CHANGELOG_CONTRACT,
|
|
413
|
+
name: String(value.name),
|
|
414
|
+
releases: [...releases].sort((left, right) => compareVersions(right.version, left.version))
|
|
415
|
+
}
|
|
416
|
+
};
|
|
417
|
+
};
|
|
418
|
+
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));
|
|
419
|
+
var changesBetween = (changelog, from, upto) => releasesBetween(changelog, from, upto).flatMap((release) => release.changes.map((change2) => {
|
|
420
|
+
const found = { change: change2, version: release.version };
|
|
421
|
+
return found;
|
|
422
|
+
}));
|
|
423
|
+
var isDisruptiveAt = (found) => isDisruptive(found.change);
|
|
424
|
+
var disruptiveBetween = (changelog, from, upto) => changesBetween(changelog, from, upto).filter(isDisruptiveAt);
|
|
425
|
+
var mechanicalMigrations = (migrations) => migrations.filter((found) => isMechanical(found.migration));
|
|
426
|
+
var migrationsBetween = (changelog, from, upto) => disruptiveBetween(changelog, from, upto).map(({ change: change2, version }) => {
|
|
427
|
+
const found = {
|
|
428
|
+
migration: change2.migration,
|
|
429
|
+
symbols: change2.symbols,
|
|
430
|
+
version
|
|
431
|
+
};
|
|
432
|
+
return found;
|
|
433
|
+
});
|
|
434
|
+
var symbolsDisturbedBetween = (changelog, from, upto) => new Set(disruptiveBetween(changelog, from, upto).flatMap(({ change: change2 }) => change2.symbols));
|
|
435
|
+
|
|
436
|
+
// src/tarball.ts
|
|
437
|
+
var TAR_BLOCK = 512;
|
|
438
|
+
var NAME_LENGTH = 100;
|
|
439
|
+
var SIZE_OFFSET = 124;
|
|
440
|
+
var SIZE_LENGTH = 12;
|
|
441
|
+
var TYPE_OFFSET = 156;
|
|
442
|
+
var PREFIX_OFFSET = 345;
|
|
443
|
+
var PREFIX_LENGTH = 155;
|
|
444
|
+
var OCTAL = 8;
|
|
445
|
+
var KIBIBYTE = 1024;
|
|
446
|
+
var MEBIBYTE = KIBIBYTE * KIBIBYTE;
|
|
447
|
+
var DEFAULT_FILE_MEBIBYTES = 4;
|
|
448
|
+
var DEFAULT_TOTAL_MEBIBYTES = 64;
|
|
449
|
+
var DEFAULT_FILE_BYTES = DEFAULT_FILE_MEBIBYTES * MEBIBYTE;
|
|
450
|
+
var DEFAULT_TOTAL_BYTES = DEFAULT_TOTAL_MEBIBYTES * MEBIBYTE;
|
|
451
|
+
var decoder = new TextDecoder;
|
|
452
|
+
var cString = (bytes) => {
|
|
453
|
+
const end = bytes.indexOf(0);
|
|
454
|
+
return decoder.decode(end < 0 ? bytes : bytes.subarray(0, end)).trim();
|
|
455
|
+
};
|
|
456
|
+
var asText = (bytes) => decoder.decode(bytes);
|
|
457
|
+
var readTar = (archive, keep, limits = {}) => {
|
|
458
|
+
const maxFile = limits.maxFileBytes ?? DEFAULT_FILE_BYTES;
|
|
459
|
+
const maxTotal = limits.maxTotalBytes ?? DEFAULT_TOTAL_BYTES;
|
|
460
|
+
const files = new Map;
|
|
461
|
+
let offset = 0;
|
|
462
|
+
let total = 0;
|
|
463
|
+
while (offset + TAR_BLOCK <= archive.length) {
|
|
464
|
+
const header = archive.subarray(offset, offset + TAR_BLOCK);
|
|
465
|
+
const name = cString(header.subarray(0, NAME_LENGTH));
|
|
466
|
+
if (name === "")
|
|
467
|
+
break;
|
|
468
|
+
const prefix = cString(header.subarray(PREFIX_OFFSET, PREFIX_OFFSET + PREFIX_LENGTH));
|
|
469
|
+
const size = Number.parseInt(cString(header.subarray(SIZE_OFFSET, SIZE_OFFSET + SIZE_LENGTH)), OCTAL);
|
|
470
|
+
if (!Number.isSafeInteger(size) || size < 0)
|
|
471
|
+
break;
|
|
472
|
+
const kind = String.fromCharCode(header[TYPE_OFFSET] ?? 0);
|
|
473
|
+
const start = offset + TAR_BLOCK;
|
|
474
|
+
const path = (prefix === "" ? name : `${prefix}/${name}`).replace(/^package\//u, "");
|
|
475
|
+
const plain = kind === "0" || kind === "\x00";
|
|
476
|
+
const wanted = plain && size <= maxFile && keep(path);
|
|
477
|
+
total += wanted ? size : 0;
|
|
478
|
+
if (total > maxTotal)
|
|
479
|
+
break;
|
|
480
|
+
if (wanted)
|
|
481
|
+
files.set(path, archive.subarray(start, start + size));
|
|
482
|
+
offset = start + Math.ceil(size / TAR_BLOCK) * TAR_BLOCK;
|
|
483
|
+
}
|
|
484
|
+
return files;
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
// src/surface.ts
|
|
488
|
+
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;
|
|
489
|
+
var NAMED_EXPORT = /\bexport\s*\{([^}]*)\}/gu;
|
|
490
|
+
var BODIED = new Set(["class", "interface", "enum", "namespace"]);
|
|
491
|
+
var OPENS = new Set(["{", "(", "["]);
|
|
492
|
+
var CLOSES = new Set(["}", ")", "]"]);
|
|
493
|
+
var IDENTIFIER = /^[A-Za-z_$][\w$]*$/u;
|
|
494
|
+
var LAST2 = -1;
|
|
495
|
+
var NOWHERE = -1;
|
|
496
|
+
var MEMBER = /([A-Za-z_$][\w$]*)\s*[?!]?\s*[:(<]/u;
|
|
497
|
+
var isStub = (declaration) => declaration.startsWith("export {");
|
|
498
|
+
var declarationEnd = (source, from, bodied) => {
|
|
499
|
+
let depth = 0;
|
|
500
|
+
for (let index = from;index < source.length; index += 1) {
|
|
501
|
+
const character = source[index] ?? "";
|
|
502
|
+
if (OPENS.has(character))
|
|
503
|
+
depth += 1;
|
|
504
|
+
else if (CLOSES.has(character))
|
|
505
|
+
depth -= 1;
|
|
506
|
+
else if (character === ";" && depth <= 0)
|
|
507
|
+
return index + 1;
|
|
508
|
+
if (CLOSES.has(character) && depth <= 0 && bodied)
|
|
509
|
+
return index + 1;
|
|
510
|
+
}
|
|
511
|
+
return source.length;
|
|
512
|
+
};
|
|
513
|
+
var normalize = (declaration) => declaration.replace(/\s+/gu, " ").trim();
|
|
514
|
+
var reExported = (body) => body.split(",").map((part) => part.trim().replace(/^type\s+/u, "")).filter((clause) => clause !== "").map((clause) => [
|
|
515
|
+
clause.split(/\s+as\s+/u).at(LAST2)?.trim(),
|
|
516
|
+
clause
|
|
517
|
+
]).filter((pair) => pair[0] !== undefined && IDENTIFIER.test(pair[0]));
|
|
518
|
+
var exportedDeclarations = (source) => {
|
|
519
|
+
const found = new Map;
|
|
520
|
+
const add = (name, declaration) => {
|
|
521
|
+
const existing = found.get(name);
|
|
522
|
+
found.set(name, existing === undefined ? declaration : `${existing}
|
|
523
|
+
${declaration}`);
|
|
524
|
+
};
|
|
525
|
+
for (const match of source.matchAll(DECLARATION)) {
|
|
526
|
+
const [, keyword, name] = match;
|
|
527
|
+
if (name === undefined || match.index === undefined)
|
|
528
|
+
continue;
|
|
529
|
+
add(name, normalize(source.slice(match.index, declarationEnd(source, match.index + match[0].length, BODIED.has(keyword ?? "")))));
|
|
530
|
+
}
|
|
531
|
+
for (const match of source.matchAll(NAMED_EXPORT))
|
|
532
|
+
for (const [exported, clause] of reExported(match[1] ?? ""))
|
|
533
|
+
add(exported, `export { ${clause} }`);
|
|
534
|
+
return found;
|
|
535
|
+
};
|
|
536
|
+
var surfaceOfArchive = (archive) => surfaceOfFiles([...readTar(archive, (path) => path.endsWith(".d.ts")).values()].map(asText));
|
|
537
|
+
var surfaceOfFiles = (files) => {
|
|
538
|
+
const surface = new Map;
|
|
539
|
+
for (const source of files)
|
|
540
|
+
for (const [name, declaration] of exportedDeclarations(source)) {
|
|
541
|
+
const known = surface.get(name);
|
|
542
|
+
if (known === undefined || isStub(known) && !isStub(declaration))
|
|
543
|
+
surface.set(name, declaration);
|
|
544
|
+
}
|
|
545
|
+
return surface;
|
|
546
|
+
};
|
|
547
|
+
var SHAPE = {
|
|
548
|
+
members: "members",
|
|
549
|
+
parameters: "parameters",
|
|
550
|
+
types: "types",
|
|
551
|
+
unknown: "unknown"
|
|
552
|
+
};
|
|
553
|
+
var parametersOf = (declaration) => {
|
|
554
|
+
let depth = 0;
|
|
555
|
+
let start = NOWHERE;
|
|
556
|
+
for (const [index, character] of [...declaration].entries()) {
|
|
557
|
+
if (character === "{" && depth === 0)
|
|
558
|
+
return "";
|
|
559
|
+
depth += character === "(" ? 1 : 0;
|
|
560
|
+
if (character === "(" && depth === 1)
|
|
561
|
+
start = index;
|
|
562
|
+
depth -= character === ")" ? 1 : 0;
|
|
563
|
+
if (character === ")" && depth === 0 && start > NOWHERE)
|
|
564
|
+
return declaration.slice(start, index + 1);
|
|
565
|
+
}
|
|
566
|
+
return "";
|
|
567
|
+
};
|
|
568
|
+
var membersOf = (declaration) => {
|
|
569
|
+
const opened = declaration.indexOf("{");
|
|
570
|
+
if (opened < 0)
|
|
571
|
+
return new Set;
|
|
572
|
+
const members = new Set;
|
|
573
|
+
let depth = 0;
|
|
574
|
+
let segment = "";
|
|
575
|
+
const take = () => {
|
|
576
|
+
const [, name] = MEMBER.exec(segment.trim()) ?? [];
|
|
577
|
+
if (name !== undefined)
|
|
578
|
+
members.add(name);
|
|
579
|
+
segment = "";
|
|
580
|
+
};
|
|
581
|
+
for (const character of declaration.slice(opened)) {
|
|
582
|
+
const opening = OPENS.has(character);
|
|
583
|
+
const closing = CLOSES.has(character);
|
|
584
|
+
depth += opening ? 1 : 0;
|
|
585
|
+
if (opening && depth === 1)
|
|
586
|
+
segment = "";
|
|
587
|
+
depth -= closing ? 1 : 0;
|
|
588
|
+
if (opening || closing || depth !== 1)
|
|
589
|
+
continue;
|
|
590
|
+
if (character === ";" || character === ",")
|
|
591
|
+
take();
|
|
592
|
+
else
|
|
593
|
+
segment += character;
|
|
594
|
+
}
|
|
595
|
+
take();
|
|
596
|
+
return members;
|
|
597
|
+
};
|
|
598
|
+
var sameNames = (left, right) => left.size === right.size && [...left].every((name) => right.has(name));
|
|
599
|
+
var changeShape = (change2) => {
|
|
600
|
+
if (isStub(change2.before) !== isStub(change2.after))
|
|
601
|
+
return SHAPE.unknown;
|
|
602
|
+
if (parametersOf(change2.before) !== parametersOf(change2.after))
|
|
603
|
+
return SHAPE.parameters;
|
|
604
|
+
if (!sameNames(membersOf(change2.before), membersOf(change2.after)))
|
|
605
|
+
return SHAPE.members;
|
|
606
|
+
return SHAPE.types;
|
|
607
|
+
};
|
|
608
|
+
var diffSurface = (before, after) => {
|
|
609
|
+
const removed = [];
|
|
610
|
+
const changed = [];
|
|
611
|
+
for (const [name, declaration] of before) {
|
|
612
|
+
const now = after.get(name);
|
|
613
|
+
if (now === undefined)
|
|
614
|
+
removed.push(name);
|
|
615
|
+
else if (now !== declaration)
|
|
616
|
+
changed.push({
|
|
617
|
+
after: now,
|
|
618
|
+
before: declaration,
|
|
619
|
+
name,
|
|
620
|
+
shape: changeShape({ after: now, before: declaration })
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
return {
|
|
624
|
+
added: [...after.keys()].filter((name) => !before.has(name)),
|
|
625
|
+
changed,
|
|
626
|
+
removed
|
|
627
|
+
};
|
|
628
|
+
};
|
|
629
|
+
var notable = (diff) => diff.changed.filter((change2) => change2.shape === "parameters" || change2.shape === "members");
|
|
630
|
+
|
|
631
|
+
// src/entries.ts
|
|
632
|
+
var loadEntry = async (path) => {
|
|
633
|
+
try {
|
|
634
|
+
const module = await import(pathToFileURL(path).href);
|
|
635
|
+
const exported = typeof module === "object" && module !== null && "default" in module ? module.default : undefined;
|
|
636
|
+
const read = { exported };
|
|
637
|
+
return read;
|
|
638
|
+
} catch (error) {
|
|
639
|
+
const failed = {
|
|
640
|
+
failure: error instanceof Error ? error.message : String(error)
|
|
641
|
+
};
|
|
642
|
+
return failed;
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
var ENTRY = /\.[cm]?ts$/u;
|
|
646
|
+
var builtSurface = async (packageRoot, out = "dist") => {
|
|
647
|
+
const root = join(packageRoot, out);
|
|
648
|
+
const sources = [];
|
|
649
|
+
const walk = async (directory) => {
|
|
650
|
+
const found = await readdir(directory, { withFileTypes: true }).catch(() => []);
|
|
651
|
+
await Promise.all(found.map(async (entry) => {
|
|
652
|
+
const path = join(directory, entry.name);
|
|
653
|
+
if (entry.isDirectory())
|
|
654
|
+
return walk(path);
|
|
655
|
+
if (!entry.name.endsWith(".d.ts"))
|
|
656
|
+
return;
|
|
657
|
+
sources.push(await readFile(path, "utf8").catch(() => ""));
|
|
658
|
+
return;
|
|
659
|
+
}));
|
|
660
|
+
};
|
|
661
|
+
await walk(root);
|
|
662
|
+
return sources.length === 0 ? undefined : surfaceOfFiles(sources);
|
|
663
|
+
};
|
|
664
|
+
var changelogPaths = (packageRoot) => ({
|
|
665
|
+
history: join(packageRoot, "changelog", "history.md"),
|
|
666
|
+
json: join(packageRoot, CHANGELOG_FILE),
|
|
667
|
+
markdown: join(packageRoot, CHANGELOG_MARKDOWN),
|
|
668
|
+
unreleased: join(packageRoot, UNRELEASED_DIRECTORY)
|
|
669
|
+
});
|
|
670
|
+
var loadUnreleased = async (packageRoot) => {
|
|
671
|
+
const directory = join(packageRoot, UNRELEASED_DIRECTORY);
|
|
672
|
+
const names = await readdir(directory).catch(() => []);
|
|
673
|
+
const entries = [];
|
|
674
|
+
const problems = [];
|
|
675
|
+
for (const name of names.filter((file) => ENTRY.test(file)).sort()) {
|
|
676
|
+
const file = join(UNRELEASED_DIRECTORY, name);
|
|
677
|
+
const loaded = await loadEntry(join(directory, name));
|
|
678
|
+
if (loaded.failure !== undefined)
|
|
679
|
+
problems.push(`${file}: ${loaded.failure}`);
|
|
680
|
+
const checked = loaded.failure === undefined ? validateChange(loaded.exported, file) : undefined;
|
|
681
|
+
if (checked?.problems)
|
|
682
|
+
problems.push(...checked.problems);
|
|
683
|
+
if (checked?.change !== undefined)
|
|
684
|
+
entries.push({ change: checked.change, file });
|
|
685
|
+
}
|
|
686
|
+
return { entries, problems };
|
|
687
|
+
};
|
|
688
|
+
var readJsonFile = async (path) => {
|
|
689
|
+
const source = await readFile(path, "utf8").catch(() => {
|
|
690
|
+
return;
|
|
691
|
+
});
|
|
692
|
+
if (source === undefined)
|
|
693
|
+
return;
|
|
694
|
+
try {
|
|
695
|
+
const document = JSON.parse(source);
|
|
696
|
+
return document;
|
|
697
|
+
} catch {
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
// src/reconcile.ts
|
|
702
|
+
var describeReconciliation = (found) => {
|
|
703
|
+
const lines = [];
|
|
704
|
+
for (const entry of found.unannounced)
|
|
705
|
+
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`);
|
|
706
|
+
for (const name of found.unknownSymbols)
|
|
707
|
+
lines.push(`an entry names \`${name}\`, which this package does not export`);
|
|
708
|
+
return lines;
|
|
709
|
+
};
|
|
710
|
+
var reconcile = (input) => {
|
|
711
|
+
const announced = new Set(input.changes.filter(isDisruptive).flatMap((change2) => [...change2.symbols]));
|
|
712
|
+
const unannounced = [
|
|
713
|
+
...input.diff.removed.map((name) => ({ kind: "removed", name })),
|
|
714
|
+
...notable(input.diff).map((change2) => ({
|
|
715
|
+
kind: change2.shape === "parameters" ? "parameters" : "members",
|
|
716
|
+
name: change2.name
|
|
717
|
+
}))
|
|
718
|
+
].filter((entry) => !announced.has(entry.name));
|
|
719
|
+
const unknownSymbols = [
|
|
720
|
+
...new Set(input.changes.flatMap((change2) => [...change2.symbols ?? []]).filter((name) => !input.known.has(name)))
|
|
721
|
+
];
|
|
722
|
+
return { unannounced, unknownSymbols };
|
|
723
|
+
};
|
|
724
|
+
// src/registry.ts
|
|
725
|
+
import { gunzipSync } from "zlib";
|
|
726
|
+
var ABBREVIATED = "application/vnd.npm.install-v1+json";
|
|
727
|
+
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
728
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null;
|
|
729
|
+
var readPackument = (body) => {
|
|
730
|
+
if (!isRecord2(body) || !isRecord2(body.versions))
|
|
731
|
+
return;
|
|
732
|
+
const tarballs = {};
|
|
733
|
+
for (const [version, entry] of Object.entries(body.versions)) {
|
|
734
|
+
if (!isRecord2(entry) || !isRecord2(entry.dist))
|
|
735
|
+
continue;
|
|
736
|
+
const { tarball } = entry.dist;
|
|
737
|
+
if (typeof tarball === "string")
|
|
738
|
+
tarballs[version] = tarball;
|
|
739
|
+
}
|
|
740
|
+
const tags = body["dist-tags"];
|
|
741
|
+
const latest = isRecord2(tags) ? tags.latest : undefined;
|
|
742
|
+
return {
|
|
743
|
+
...typeof latest === "string" ? { latest } : {},
|
|
744
|
+
published: Object.keys(body.versions),
|
|
745
|
+
tarballs
|
|
746
|
+
};
|
|
747
|
+
};
|
|
748
|
+
var packageArchive = async (name, version, options = {}) => {
|
|
749
|
+
const call = options.fetch ?? fetch;
|
|
750
|
+
const versions = await packageVersions(name, options);
|
|
751
|
+
const url = versions?.tarballs[version];
|
|
752
|
+
if (url === undefined)
|
|
753
|
+
return;
|
|
754
|
+
try {
|
|
755
|
+
const response = await call(url);
|
|
756
|
+
if (!response.ok)
|
|
757
|
+
return;
|
|
758
|
+
return new Uint8Array(gunzipSync(new Uint8Array(await response.arrayBuffer())));
|
|
759
|
+
} catch {
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
var packageVersions = async (name, options = {}) => {
|
|
764
|
+
const call = options.fetch ?? fetch;
|
|
765
|
+
try {
|
|
766
|
+
const response = await call(`${options.registry ?? DEFAULT_REGISTRY}/${name.replace("/", "%2f")}`, { headers: { accept: ABBREVIATED } });
|
|
767
|
+
if (!response.ok)
|
|
768
|
+
return;
|
|
769
|
+
return readPackument(await response.json());
|
|
770
|
+
} catch {
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
};
|
|
774
|
+
var publishedChangelog = async (name, version, options = {}) => {
|
|
775
|
+
const archive = await packageArchive(name, version, options);
|
|
776
|
+
if (!archive)
|
|
777
|
+
return;
|
|
778
|
+
const file = readTar(archive, (path) => path === CHANGELOG_FILE).get(CHANGELOG_FILE);
|
|
779
|
+
if (!file)
|
|
780
|
+
return;
|
|
781
|
+
try {
|
|
782
|
+
return parseChangelog(JSON.parse(asText(file))).changelog;
|
|
783
|
+
} catch {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
var publishedSurface = async (name, version, options = {}) => {
|
|
788
|
+
const archive = await packageArchive(name, version, options);
|
|
789
|
+
return archive === undefined ? undefined : surfaceOfArchive(archive);
|
|
790
|
+
};
|
|
791
|
+
// src/write.ts
|
|
792
|
+
var HEADING = {
|
|
793
|
+
added: "Added",
|
|
794
|
+
breaking: "Breaking",
|
|
795
|
+
changed: "Changed",
|
|
796
|
+
deprecated: "Deprecated",
|
|
797
|
+
fixed: "Fixed",
|
|
798
|
+
internal: "Internal",
|
|
799
|
+
removed: "Removed",
|
|
800
|
+
security: "Security"
|
|
801
|
+
};
|
|
802
|
+
var ORDER = [
|
|
803
|
+
"breaking",
|
|
804
|
+
"removed",
|
|
805
|
+
"deprecated",
|
|
806
|
+
"security",
|
|
807
|
+
"added",
|
|
808
|
+
"changed",
|
|
809
|
+
"fixed",
|
|
810
|
+
"internal"
|
|
811
|
+
];
|
|
812
|
+
var migrationLine = (migration) => {
|
|
813
|
+
if ("rename" in migration)
|
|
814
|
+
return `Rename \`${migration.rename.from}\` to \`${migration.rename.to}\`.`;
|
|
815
|
+
if ("moved" in migration)
|
|
816
|
+
return `Import \`${migration.moved.symbol}\` from \`${migration.moved.to}\` instead of \`${migration.moved.from}\`.`;
|
|
817
|
+
if ("resubpath" in migration)
|
|
818
|
+
return `Import from \`${migration.resubpath.to}\` instead of \`${migration.resubpath.from}\`.`;
|
|
819
|
+
return migration.instruction;
|
|
820
|
+
};
|
|
821
|
+
var renderChange = (change2) => {
|
|
822
|
+
const symbols = change2.symbols && change2.symbols.length > 0 ? ` (${change2.symbols.map((name) => `\`${name}\``).join(", ")})` : "";
|
|
823
|
+
const lines = [`- **${change2.summary}**${symbols}`];
|
|
824
|
+
if (change2.detail !== undefined)
|
|
825
|
+
lines.push(` ${change2.detail}`);
|
|
826
|
+
if (isDisruptive(change2)) {
|
|
827
|
+
lines.push(` _Migration:_ ${change2.migration.instruction}`);
|
|
828
|
+
const mechanical = migrationLine(change2.migration);
|
|
829
|
+
if (mechanical !== change2.migration.instruction)
|
|
830
|
+
lines.push(` _Applied automatically:_ ${mechanical}`);
|
|
831
|
+
}
|
|
832
|
+
if (change2.reference !== undefined)
|
|
833
|
+
lines.push(` See ${change2.reference}.`);
|
|
834
|
+
return lines.join(`
|
|
835
|
+
`);
|
|
836
|
+
};
|
|
837
|
+
var renderRelease = (release) => {
|
|
838
|
+
const sections = ORDER.map((kind) => {
|
|
839
|
+
const changes = release.changes.filter((entry) => entry.kind === kind);
|
|
840
|
+
if (changes.length === 0)
|
|
841
|
+
return null;
|
|
842
|
+
return [`### ${HEADING[kind]}`, "", ...changes.map(renderChange)].join(`
|
|
843
|
+
`);
|
|
844
|
+
}).filter((section) => section !== null);
|
|
845
|
+
return [
|
|
846
|
+
`## ${release.version} \u2014 ${release.date}`,
|
|
847
|
+
...release.note === undefined ? [] : ["", release.note],
|
|
848
|
+
"",
|
|
849
|
+
sections.join(`
|
|
850
|
+
|
|
851
|
+
`)
|
|
852
|
+
].join(`
|
|
853
|
+
`);
|
|
854
|
+
};
|
|
855
|
+
var renderChangelogJson = (changelog) => `${JSON.stringify({
|
|
856
|
+
contract: CHANGELOG_CONTRACT,
|
|
857
|
+
name: changelog.name,
|
|
858
|
+
releases: [...changelog.releases].sort((left, right) => compareVersions(right.version, left.version)).map((release) => ({
|
|
859
|
+
changes: release.changes.map((change2) => ({
|
|
860
|
+
...change2.detail === undefined ? {} : { detail: change2.detail },
|
|
861
|
+
kind: change2.kind,
|
|
862
|
+
...isDisruptive(change2) ? { migration: change2.migration } : {},
|
|
863
|
+
...change2.reference === undefined ? {} : { reference: change2.reference },
|
|
864
|
+
summary: change2.summary,
|
|
865
|
+
...change2.symbols && change2.symbols.length > 0 ? { symbols: change2.symbols } : {}
|
|
866
|
+
})),
|
|
867
|
+
date: release.date,
|
|
868
|
+
...release.note === undefined ? {} : { note: release.note },
|
|
869
|
+
version: release.version
|
|
870
|
+
}))
|
|
871
|
+
}, null, "\t")}
|
|
872
|
+
`;
|
|
873
|
+
var renderMarkdown = (changelog, options = {}) => {
|
|
874
|
+
const releases = [...changelog.releases].sort((left, right) => compareVersions(right.version, left.version));
|
|
875
|
+
const head = [
|
|
876
|
+
"# Changelog",
|
|
877
|
+
"",
|
|
878
|
+
`All notable changes to \`${changelog.name}\`.`,
|
|
879
|
+
"",
|
|
880
|
+
"This file is generated by `absolute-changelog` from the entries in",
|
|
881
|
+
"`changelog/`. Edit an entry, not this file \u2014 and add new ones under",
|
|
882
|
+
"`changelog/unreleased/`."
|
|
883
|
+
].join(`
|
|
884
|
+
`);
|
|
885
|
+
const body = releases.map(renderRelease).join(`
|
|
886
|
+
|
|
887
|
+
`);
|
|
888
|
+
const tail = options.history === undefined || options.history.trim() === "" ? "" : ["---", "", "## Earlier releases", "", options.history.trim()].join(`
|
|
889
|
+
`);
|
|
890
|
+
return `${[head, body, tail].filter((part) => part !== "").join(`
|
|
891
|
+
|
|
892
|
+
`)}
|
|
893
|
+
`;
|
|
894
|
+
};
|
|
895
|
+
export {
|
|
896
|
+
CHANGELOG_CONTRACT,
|
|
897
|
+
CHANGELOG_FILE,
|
|
898
|
+
CHANGELOG_MARKDOWN,
|
|
899
|
+
CHANGE_KINDS,
|
|
900
|
+
DISRUPTIVE_KINDS,
|
|
901
|
+
UNRELEASED_DIRECTORY,
|
|
902
|
+
applyMigration,
|
|
903
|
+
applyMigrations,
|
|
904
|
+
asText,
|
|
905
|
+
builtSurface,
|
|
906
|
+
change,
|
|
907
|
+
changeShape,
|
|
908
|
+
changelogPaths,
|
|
909
|
+
changesBetween,
|
|
910
|
+
compareVersions,
|
|
911
|
+
describeReconciliation,
|
|
912
|
+
diffSurface,
|
|
913
|
+
disruptiveBetween,
|
|
914
|
+
exportedDeclarations,
|
|
915
|
+
isDisruptive,
|
|
916
|
+
isMechanical,
|
|
917
|
+
isPrerelease,
|
|
918
|
+
loadUnreleased,
|
|
919
|
+
manual,
|
|
920
|
+
mechanicalMigrations,
|
|
921
|
+
migrationsBetween,
|
|
922
|
+
moved,
|
|
923
|
+
nextVersion,
|
|
924
|
+
notable,
|
|
925
|
+
packageArchive,
|
|
926
|
+
packageVersions,
|
|
927
|
+
parseChangelog,
|
|
928
|
+
parseVersion,
|
|
929
|
+
publishedChangelog,
|
|
930
|
+
publishedSurface,
|
|
931
|
+
readJsonFile,
|
|
932
|
+
readTar,
|
|
933
|
+
reconcile,
|
|
934
|
+
releaseKindFor,
|
|
935
|
+
releasesBetween,
|
|
936
|
+
renamed,
|
|
937
|
+
renderChangelogJson,
|
|
938
|
+
renderMarkdown,
|
|
939
|
+
surfaceOfArchive,
|
|
940
|
+
surfaceOfFiles,
|
|
941
|
+
symbolsDisturbedBetween,
|
|
942
|
+
validateChange
|
|
943
|
+
};
|
|
944
|
+
|
|
945
|
+
//# debugId=24AC404EA4C9D1DD64756E2164756E21
|
|
946
|
+
//# sourceMappingURL=index.js.map
|