@telorun/analyzer 0.58.0 → 0.60.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/analyzer.d.ts +9 -2
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +38 -10
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +16 -42
- package/dist/cel-environment.d.ts.map +1 -1
- package/dist/cel-environment.js +35 -0
- package/dist/flatten-for-analyzer.d.ts +4 -0
- package/dist/flatten-for-analyzer.d.ts.map +1 -1
- package/dist/flatten-for-analyzer.js +8 -0
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -2
- package/dist/invocation-contract.d.ts +37 -0
- package/dist/invocation-contract.d.ts.map +1 -1
- package/dist/invocation-contract.js +81 -1
- package/dist/kernel-globals.d.ts +1 -1
- package/dist/kernel-globals.d.ts.map +1 -1
- package/dist/kernel-globals.js +15 -1
- package/dist/manifest-schemas.d.ts +407 -0
- package/dist/manifest-schemas.d.ts.map +1 -0
- package/dist/manifest-schemas.js +396 -0
- package/dist/module-file-claims.d.ts +6 -0
- package/dist/module-file-claims.d.ts.map +1 -1
- package/dist/module-file-claims.js +4 -0
- package/dist/module-metadata-scope.d.ts +44 -0
- package/dist/module-metadata-scope.d.ts.map +1 -0
- package/dist/module-metadata-scope.js +82 -0
- package/dist/parse-loaded-file.d.ts.map +1 -1
- package/dist/parse-loaded-file.js +16 -0
- package/dist/release/bump-level.d.ts +46 -0
- package/dist/release/bump-level.d.ts.map +1 -0
- package/dist/release/bump-level.js +80 -0
- package/dist/release/changelog.d.ts +36 -0
- package/dist/release/changelog.d.ts.map +1 -0
- package/dist/release/changelog.js +53 -0
- package/dist/release/fragment.d.ts +48 -0
- package/dist/release/fragment.d.ts.map +1 -0
- package/dist/release/fragment.js +84 -0
- package/dist/release/index.d.ts +26 -0
- package/dist/release/index.d.ts.map +1 -0
- package/dist/release/index.js +18 -0
- package/dist/release/ledger.d.ts +53 -0
- package/dist/release/ledger.d.ts.map +1 -0
- package/dist/release/ledger.js +109 -0
- package/dist/release/payload-digest.d.ts +63 -0
- package/dist/release/payload-digest.d.ts.map +1 -0
- package/dist/release/payload-digest.js +65 -0
- package/dist/release/release-plan.d.ts +128 -0
- package/dist/release/release-plan.d.ts.map +1 -0
- package/dist/release/release-plan.js +277 -0
- package/dist/release/version-stamp.d.ts +50 -0
- package/dist/release/version-stamp.d.ts.map +1 -0
- package/dist/release/version-stamp.js +119 -0
- package/dist/release/workspace-config.d.ts +41 -0
- package/dist/release/workspace-config.d.ts.map +1 -0
- package/dist/release/workspace-config.js +60 -0
- package/dist/schema-compat.d.ts +18 -0
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +71 -7
- package/dist/validate-cel-context.d.ts.map +1 -1
- package/dist/validate-cel-context.js +69 -13
- package/dist/validate-step-inputs.d.ts +1 -1
- package/dist/validate-step-inputs.d.ts.map +1 -1
- package/dist/validate-step-inputs.js +99 -8
- package/package.json +3 -3
- package/src/analyzer.ts +41 -10
- package/src/builtins.ts +16 -42
- package/src/cel-environment.ts +37 -0
- package/src/flatten-for-analyzer.ts +12 -0
- package/src/index.ts +18 -3
- package/src/invocation-contract.ts +92 -1
- package/src/kernel-globals.ts +23 -1
- package/src/manifest-schemas.ts +408 -0
- package/src/module-file-claims.ts +10 -0
- package/src/module-metadata-scope.ts +88 -0
- package/src/parse-loaded-file.ts +16 -0
- package/src/release/bump-level.ts +95 -0
- package/src/release/changelog.ts +62 -0
- package/src/release/fragment.ts +130 -0
- package/src/release/index.ts +66 -0
- package/src/release/ledger.ts +142 -0
- package/src/release/payload-digest.ts +83 -0
- package/src/release/release-plan.ts +392 -0
- package/src/release/version-stamp.ts +142 -0
- package/src/release/workspace-config.ts +81 -0
- package/src/schema-compat.ts +69 -5
- package/src/validate-cel-context.ts +82 -13
- package/src/validate-step-inputs.ts +109 -9
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two vocabularies a release speaks, and the arithmetic between them.
|
|
3
|
+
*
|
|
4
|
+
* A **kind** is what an author writes in a fragment (`Added`, `Fixed`, …). It is
|
|
5
|
+
* changie's vocabulary, kept because it drives two things at once: the semantic
|
|
6
|
+
* level of the bump, and the heading the entry lands under in the changelog. A
|
|
7
|
+
* **level** is what the version arithmetic consumes.
|
|
8
|
+
*
|
|
9
|
+
* The mapping is the only place the two meet, and it is deliberately total: an
|
|
10
|
+
* unrecognized kind is refused rather than defaulted, because a typo that
|
|
11
|
+
* degraded to `patch` would silently under-release a breaking change.
|
|
12
|
+
*/
|
|
13
|
+
/** Ordering used whenever several levels reach one module — the maximum wins,
|
|
14
|
+
* because a module that inlines a breaking change is breaking for its own
|
|
15
|
+
* consumers. */
|
|
16
|
+
const LEVEL_RANK = { patch: 0, minor: 1, major: 2 };
|
|
17
|
+
export function maxLevel(a, b) {
|
|
18
|
+
return LEVEL_RANK[a] >= LEVEL_RANK[b] ? a : b;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Fragment kinds, in changelog section order, each with the level it induces.
|
|
22
|
+
*
|
|
23
|
+
* `Changed` / `Removed` induce `major`, which the pre-1.0 guard then rejects —
|
|
24
|
+
* they are kept in the vocabulary rather than dropped so the rejection can name
|
|
25
|
+
* what was written and say why, instead of reporting an unknown kind.
|
|
26
|
+
*/
|
|
27
|
+
export const FRAGMENT_KINDS = {
|
|
28
|
+
Added: "minor",
|
|
29
|
+
Changed: "major",
|
|
30
|
+
Deprecated: "minor",
|
|
31
|
+
Removed: "major",
|
|
32
|
+
Fixed: "patch",
|
|
33
|
+
Security: "patch",
|
|
34
|
+
};
|
|
35
|
+
/** Declaration order, which is also the order sections appear in a changelog
|
|
36
|
+
* release block. */
|
|
37
|
+
export const FRAGMENT_KIND_ORDER = Object.keys(FRAGMENT_KINDS);
|
|
38
|
+
export function isFragmentKind(value) {
|
|
39
|
+
return typeof value === "string" && value in FRAGMENT_KINDS;
|
|
40
|
+
}
|
|
41
|
+
export function levelOfKind(kind) {
|
|
42
|
+
return FRAGMENT_KINDS[kind];
|
|
43
|
+
}
|
|
44
|
+
/** A `major.minor.patch` triple. Pre-release and build metadata are not accepted:
|
|
45
|
+
* a module version is the tag an artifact publishes under and the value a pin
|
|
46
|
+
* resolves, and neither has a meaning for a suffix today. */
|
|
47
|
+
const VERSION = /^(\d+)\.(\d+)\.(\d+)$/;
|
|
48
|
+
export function isReleaseVersion(value) {
|
|
49
|
+
return typeof value === "string" && VERSION.test(value);
|
|
50
|
+
}
|
|
51
|
+
/** Apply `level` to `version`. Throws on a version this system cannot represent,
|
|
52
|
+
* rather than returning something plausible — every caller has already read the
|
|
53
|
+
* value out of a manifest it is about to rewrite. */
|
|
54
|
+
export function applyBump(version, level) {
|
|
55
|
+
const match = VERSION.exec(version);
|
|
56
|
+
if (!match) {
|
|
57
|
+
throw new Error(`'${version}' is not a major.minor.patch version, so no ${level} bump can be derived from it.`);
|
|
58
|
+
}
|
|
59
|
+
const [major, minor, patch] = match.slice(1, 4).map(Number);
|
|
60
|
+
if (level === "major")
|
|
61
|
+
return `${major + 1}.0.0`;
|
|
62
|
+
if (level === "minor")
|
|
63
|
+
return `${major}.${minor + 1}.0`;
|
|
64
|
+
return `${major}.${minor}.${patch + 1}`;
|
|
65
|
+
}
|
|
66
|
+
/** Numeric comparison, so `0.10.0` sorts after `0.9.0`. Returns a negative
|
|
67
|
+
* number when `a` precedes `b`. An unparseable version sorts last rather than
|
|
68
|
+
* throwing — this is used for display ordering, not for decisions. */
|
|
69
|
+
export function compareVersions(a, b) {
|
|
70
|
+
const pa = VERSION.exec(a);
|
|
71
|
+
const pb = VERSION.exec(b);
|
|
72
|
+
if (!pa || !pb)
|
|
73
|
+
return pa ? -1 : pb ? 1 : a.localeCompare(b);
|
|
74
|
+
for (let i = 1; i <= 3; i++) {
|
|
75
|
+
const diff = Number(pa[i]) - Number(pb[i]);
|
|
76
|
+
if (diff !== 0)
|
|
77
|
+
return diff;
|
|
78
|
+
}
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rendering a module's `CHANGELOG.md` entry, and splicing it into the file.
|
|
3
|
+
*
|
|
4
|
+
* The output shape is the one changie was configured to emit — `## <version> -
|
|
5
|
+
* <date>`, `### <Kind>`, `* <body>` — so a module's history stays one document
|
|
6
|
+
* across the handover rather than changing format mid-file.
|
|
7
|
+
*
|
|
8
|
+
* Prepending rather than rewriting: a changelog is append-only history, and the
|
|
9
|
+
* only edit ever made to it is inserting the newest release above the previous
|
|
10
|
+
* one. Everything already written is untouched bytes.
|
|
11
|
+
*/
|
|
12
|
+
import { type FragmentKind } from "./bump-level.js";
|
|
13
|
+
export declare const CHANGELOG_HEADER = "# Changelog";
|
|
14
|
+
export interface ChangelogRelease {
|
|
15
|
+
readonly version: string;
|
|
16
|
+
/** `YYYY-MM-DD`. Passed in rather than read from a clock, so a plan renders
|
|
17
|
+
* identically whenever it is rendered and a test needs no clock control. */
|
|
18
|
+
readonly date: string;
|
|
19
|
+
readonly entries: readonly {
|
|
20
|
+
readonly kind: FragmentKind;
|
|
21
|
+
readonly body: string;
|
|
22
|
+
}[];
|
|
23
|
+
}
|
|
24
|
+
/** One release block. Entries group under their kind, in the vocabulary's own
|
|
25
|
+
* order, so two releases never disagree about where `Fixed` sits. */
|
|
26
|
+
export declare function renderChangelogRelease(release: ChangelogRelease): string;
|
|
27
|
+
/**
|
|
28
|
+
* Insert a release block below the file's `# Changelog` header, creating the
|
|
29
|
+
* file's skeleton when it has none.
|
|
30
|
+
*
|
|
31
|
+
* A module with no changelog yet is the ordinary case for a new module, so this
|
|
32
|
+
* writes the header rather than failing — the alternative is a release that
|
|
33
|
+
* stops to ask for an empty file to be created by hand.
|
|
34
|
+
*/
|
|
35
|
+
export declare function prependChangelogRelease(existing: string | undefined, block: string): string;
|
|
36
|
+
//# sourceMappingURL=changelog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../../src/release/changelog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEzE,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;iFAC6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACrF;AAED;sEACsE;AACtE,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAgBxE;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAS3F"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rendering a module's `CHANGELOG.md` entry, and splicing it into the file.
|
|
3
|
+
*
|
|
4
|
+
* The output shape is the one changie was configured to emit — `## <version> -
|
|
5
|
+
* <date>`, `### <Kind>`, `* <body>` — so a module's history stays one document
|
|
6
|
+
* across the handover rather than changing format mid-file.
|
|
7
|
+
*
|
|
8
|
+
* Prepending rather than rewriting: a changelog is append-only history, and the
|
|
9
|
+
* only edit ever made to it is inserting the newest release above the previous
|
|
10
|
+
* one. Everything already written is untouched bytes.
|
|
11
|
+
*/
|
|
12
|
+
import { FRAGMENT_KIND_ORDER } from "./bump-level.js";
|
|
13
|
+
export const CHANGELOG_HEADER = "# Changelog";
|
|
14
|
+
/** One release block. Entries group under their kind, in the vocabulary's own
|
|
15
|
+
* order, so two releases never disagree about where `Fixed` sits. */
|
|
16
|
+
export function renderChangelogRelease(release) {
|
|
17
|
+
const byKind = new Map();
|
|
18
|
+
for (const entry of release.entries) {
|
|
19
|
+
const list = byKind.get(entry.kind);
|
|
20
|
+
if (list)
|
|
21
|
+
list.push(entry.body);
|
|
22
|
+
else
|
|
23
|
+
byKind.set(entry.kind, [entry.body]);
|
|
24
|
+
}
|
|
25
|
+
const lines = [`## ${release.version} - ${release.date}`];
|
|
26
|
+
for (const kind of FRAGMENT_KIND_ORDER) {
|
|
27
|
+
const bodies = byKind.get(kind);
|
|
28
|
+
if (!bodies)
|
|
29
|
+
continue;
|
|
30
|
+
lines.push(`### ${kind}`);
|
|
31
|
+
for (const body of bodies)
|
|
32
|
+
lines.push(`* ${body}`);
|
|
33
|
+
}
|
|
34
|
+
return lines.join("\n") + "\n";
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Insert a release block below the file's `# Changelog` header, creating the
|
|
38
|
+
* file's skeleton when it has none.
|
|
39
|
+
*
|
|
40
|
+
* A module with no changelog yet is the ordinary case for a new module, so this
|
|
41
|
+
* writes the header rather than failing — the alternative is a release that
|
|
42
|
+
* stops to ask for an empty file to be created by hand.
|
|
43
|
+
*/
|
|
44
|
+
export function prependChangelogRelease(existing, block) {
|
|
45
|
+
const text = existing ?? "";
|
|
46
|
+
const header = text.match(/^#\s+Changelog[^\n]*\n/);
|
|
47
|
+
if (!header) {
|
|
48
|
+
const rest = text.trim();
|
|
49
|
+
return `${CHANGELOG_HEADER}\n\n${block}${rest ? `\n${rest}\n` : ""}`;
|
|
50
|
+
}
|
|
51
|
+
const after = text.slice(header[0].length).replace(/^\n+/, "");
|
|
52
|
+
return `${header[0]}\n${block}${after ? `\n${after}` : ""}`;
|
|
53
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A release fragment — one pending change, written by an author.
|
|
3
|
+
*
|
|
4
|
+
* The shape is changesets' (one file, several modules, one body) carrying
|
|
5
|
+
* changie's kind vocabulary, which is what lets one cross-cutting change be one
|
|
6
|
+
* file while the kind still drives both the level and the changelog section a
|
|
7
|
+
* line lands under. Changie's own file is the other arrangement — one module per
|
|
8
|
+
* file — so a change touching five modules meant five files repeating one
|
|
9
|
+
* sentence, and its key was the module's bare directory NAME, which two
|
|
10
|
+
* directories in different subtrees can share.
|
|
11
|
+
*
|
|
12
|
+
* A fragment names modules by **workspace-relative path**, the same key the
|
|
13
|
+
* ledger and every diagnostic use.
|
|
14
|
+
*
|
|
15
|
+
* They are plain YAML validated here, not a `Telo.*` kind: build-time repo state
|
|
16
|
+
* with no controller and no capability, which the runtime never loads.
|
|
17
|
+
*/
|
|
18
|
+
import { type FragmentKind } from "./bump-level.js";
|
|
19
|
+
/** A module's workspace-relative directory path — `modules/sql`, `apps/hub`. */
|
|
20
|
+
export type ModuleKey = string;
|
|
21
|
+
export interface ReleaseFragment {
|
|
22
|
+
/**
|
|
23
|
+
* Where this fragment was read from, workspace-relative. Carried so a
|
|
24
|
+
* diagnostic can name the file to fix and `apply` can delete the file it
|
|
25
|
+
* consumed.
|
|
26
|
+
*/
|
|
27
|
+
readonly source: string;
|
|
28
|
+
/** The directly-changed modules this fragment declares, each with its kind. */
|
|
29
|
+
readonly modules: ReadonlyMap<ModuleKey, FragmentKind>;
|
|
30
|
+
/** The changelog line. */
|
|
31
|
+
readonly body: string;
|
|
32
|
+
}
|
|
33
|
+
export declare class FragmentError extends Error {
|
|
34
|
+
readonly source: string;
|
|
35
|
+
constructor(source: string, message: string);
|
|
36
|
+
}
|
|
37
|
+
export declare function parseFragment(text: string, source: string): ReleaseFragment;
|
|
38
|
+
/**
|
|
39
|
+
* Render a fragment, for `telo release add`.
|
|
40
|
+
*
|
|
41
|
+
* Serialized rather than templated so a long body folds the way the YAML writer
|
|
42
|
+
* folds it, and so a module path needing quotes gets them.
|
|
43
|
+
*/
|
|
44
|
+
export declare function serializeFragment(modules: ReadonlyMap<ModuleKey, FragmentKind>, body: string): string;
|
|
45
|
+
/** Module keys are POSIX-separated and carry no leading `./` or trailing slash,
|
|
46
|
+
* so the same directory written three ways is one key. */
|
|
47
|
+
export declare function normalizeModuleKey(key: string): ModuleKey;
|
|
48
|
+
//# sourceMappingURL=fragment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fragment.d.ts","sourceRoot":"","sources":["../../src/release/fragment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpE,gFAAgF;AAChF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IACvD,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,aAAc,SAAQ,KAAK;IAEpC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM;CAIlB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,CA4D3E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,WAAW,CAAC,SAAS,EAAE,YAAY,CAAC,EAC7C,IAAI,EAAE,MAAM,GACX,MAAM,CAMR;AAED;2DAC2D;AAC3D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAEzD"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A release fragment — one pending change, written by an author.
|
|
3
|
+
*
|
|
4
|
+
* The shape is changesets' (one file, several modules, one body) carrying
|
|
5
|
+
* changie's kind vocabulary, which is what lets one cross-cutting change be one
|
|
6
|
+
* file while the kind still drives both the level and the changelog section a
|
|
7
|
+
* line lands under. Changie's own file is the other arrangement — one module per
|
|
8
|
+
* file — so a change touching five modules meant five files repeating one
|
|
9
|
+
* sentence, and its key was the module's bare directory NAME, which two
|
|
10
|
+
* directories in different subtrees can share.
|
|
11
|
+
*
|
|
12
|
+
* A fragment names modules by **workspace-relative path**, the same key the
|
|
13
|
+
* ledger and every diagnostic use.
|
|
14
|
+
*
|
|
15
|
+
* They are plain YAML validated here, not a `Telo.*` kind: build-time repo state
|
|
16
|
+
* with no controller and no capability, which the runtime never loads.
|
|
17
|
+
*/
|
|
18
|
+
import { Document, parseDocument } from "yaml";
|
|
19
|
+
import { isFragmentKind } from "./bump-level.js";
|
|
20
|
+
export class FragmentError extends Error {
|
|
21
|
+
source;
|
|
22
|
+
constructor(source, message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.source = source;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function parseFragment(text, source) {
|
|
28
|
+
let value;
|
|
29
|
+
try {
|
|
30
|
+
value = parseDocument(text).toJSON();
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
throw new FragmentError(source, `${source} is not valid YAML: ${err instanceof Error ? err.message : String(err)}`);
|
|
34
|
+
}
|
|
35
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
36
|
+
throw new FragmentError(source, `${source} must be a YAML mapping.`);
|
|
37
|
+
}
|
|
38
|
+
const record = value;
|
|
39
|
+
for (const key of Object.keys(record)) {
|
|
40
|
+
if (key !== "modules" && key !== "body") {
|
|
41
|
+
throw new FragmentError(source, `${source}: unknown field '${key}'. A fragment carries 'modules:' and 'body:'.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const rawModules = record.modules;
|
|
45
|
+
if (rawModules === null || typeof rawModules !== "object" || Array.isArray(rawModules)) {
|
|
46
|
+
throw new FragmentError(source, `${source}: 'modules' must be a mapping of module path to kind, ` +
|
|
47
|
+
`e.g. { modules/sql: Fixed }.`);
|
|
48
|
+
}
|
|
49
|
+
const modules = new Map();
|
|
50
|
+
for (const [key, kind] of Object.entries(rawModules)) {
|
|
51
|
+
if (!isFragmentKind(kind)) {
|
|
52
|
+
throw new FragmentError(source, `${source}: '${key}' declares kind '${String(kind)}', which is not a release kind. ` +
|
|
53
|
+
`Use Added, Changed, Deprecated, Removed, Fixed or Security.`);
|
|
54
|
+
}
|
|
55
|
+
modules.set(normalizeModuleKey(key), kind);
|
|
56
|
+
}
|
|
57
|
+
if (modules.size === 0) {
|
|
58
|
+
throw new FragmentError(source, `${source}: 'modules' is empty, so this fragment releases nothing. ` +
|
|
59
|
+
`Name at least one module by its workspace-relative path.`);
|
|
60
|
+
}
|
|
61
|
+
const body = record.body;
|
|
62
|
+
if (typeof body !== "string" || body.trim() === "") {
|
|
63
|
+
throw new FragmentError(source, `${source}: 'body' must be the changelog line for this change.`);
|
|
64
|
+
}
|
|
65
|
+
return { source, modules, body: body.trim() };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Render a fragment, for `telo release add`.
|
|
69
|
+
*
|
|
70
|
+
* Serialized rather than templated so a long body folds the way the YAML writer
|
|
71
|
+
* folds it, and so a module path needing quotes gets them.
|
|
72
|
+
*/
|
|
73
|
+
export function serializeFragment(modules, body) {
|
|
74
|
+
const doc = new Document({
|
|
75
|
+
modules: Object.fromEntries([...modules].map(([key, kind]) => [key, kind])),
|
|
76
|
+
body,
|
|
77
|
+
});
|
|
78
|
+
return doc.toString({ lineWidth: 88 });
|
|
79
|
+
}
|
|
80
|
+
/** Module keys are POSIX-separated and carry no leading `./` or trailing slash,
|
|
81
|
+
* so the same directory written three ways is one key. */
|
|
82
|
+
export function normalizeModuleKey(key) {
|
|
83
|
+
return key.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+$/, "");
|
|
84
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The release model: module identity, fragments, the ledger, the edge graph,
|
|
3
|
+
* level propagation and version planning.
|
|
4
|
+
*
|
|
5
|
+
* Browser-safe by construction — pure data in, plan out — so the telo editor can
|
|
6
|
+
* answer "what does changing this library bump?" from the same model the CLI
|
|
7
|
+
* releases from. Everything Node-shaped (finding the workspace, running the
|
|
8
|
+
* controller builder, building payloads, reading git, writing files) is
|
|
9
|
+
* `cli/nodejs/src/release/`.
|
|
10
|
+
*/
|
|
11
|
+
export { FRAGMENT_KINDS, FRAGMENT_KIND_ORDER, applyBump, compareVersions, isFragmentKind, isReleaseVersion, levelOfKind, maxLevel, } from "./bump-level.js";
|
|
12
|
+
export type { BumpLevel, FragmentKind } from "./bump-level.js";
|
|
13
|
+
export { CHANGELOG_HEADER, prependChangelogRelease, renderChangelogRelease, } from "./changelog.js";
|
|
14
|
+
export type { ChangelogRelease } from "./changelog.js";
|
|
15
|
+
export { FragmentError, normalizeModuleKey, parseFragment, serializeFragment } from "./fragment.js";
|
|
16
|
+
export type { ModuleKey, ReleaseFragment } from "./fragment.js";
|
|
17
|
+
export { EMPTY_LEDGER, LEDGER_PATH, LedgerError, parseLedger, serializeLedger } from "./ledger.js";
|
|
18
|
+
export type { Ledger, LedgerEntry } from "./ledger.js";
|
|
19
|
+
export { LOCALLY_DERIVED_LAYERS, MANIFEST_LAYER, diffLayerDigests, layerDigestKey, } from "./payload-digest.js";
|
|
20
|
+
export type { LayerChange, LayerDigests } from "./payload-digest.js";
|
|
21
|
+
export { orderByImports, planRelease } from "./release-plan.js";
|
|
22
|
+
export type { ArtifactKind, BumpReason, ChangelogEntry, ModuleEvidence, PlannedModule, ReleaseDiagnostic, ReleaseEvidence, ReleasePlan, } from "./release-plan.js";
|
|
23
|
+
export { VersionStampError, readManifestVersion, stampCrateVersion, stampManifestVersion, stampPackageVersion, } from "./version-stamp.js";
|
|
24
|
+
export { WORKSPACE_FILENAME, WorkspaceConfigError, parseWorkspaceConfig } from "./workspace-config.js";
|
|
25
|
+
export type { WorkspaceConfig } from "./workspace-config.js";
|
|
26
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/release/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,SAAS,EACT,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,QAAQ,GACT,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/D,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpG,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnG,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,gBAAgB,EAChB,cAAc,GACf,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChE,YAAY,EACV,YAAY,EACZ,UAAU,EACV,cAAc,EACd,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACvG,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The release model: module identity, fragments, the ledger, the edge graph,
|
|
3
|
+
* level propagation and version planning.
|
|
4
|
+
*
|
|
5
|
+
* Browser-safe by construction — pure data in, plan out — so the telo editor can
|
|
6
|
+
* answer "what does changing this library bump?" from the same model the CLI
|
|
7
|
+
* releases from. Everything Node-shaped (finding the workspace, running the
|
|
8
|
+
* controller builder, building payloads, reading git, writing files) is
|
|
9
|
+
* `cli/nodejs/src/release/`.
|
|
10
|
+
*/
|
|
11
|
+
export { FRAGMENT_KINDS, FRAGMENT_KIND_ORDER, applyBump, compareVersions, isFragmentKind, isReleaseVersion, levelOfKind, maxLevel, } from "./bump-level.js";
|
|
12
|
+
export { CHANGELOG_HEADER, prependChangelogRelease, renderChangelogRelease, } from "./changelog.js";
|
|
13
|
+
export { FragmentError, normalizeModuleKey, parseFragment, serializeFragment } from "./fragment.js";
|
|
14
|
+
export { EMPTY_LEDGER, LEDGER_PATH, LedgerError, parseLedger, serializeLedger } from "./ledger.js";
|
|
15
|
+
export { LOCALLY_DERIVED_LAYERS, MANIFEST_LAYER, diffLayerDigests, layerDigestKey, } from "./payload-digest.js";
|
|
16
|
+
export { orderByImports, planRelease } from "./release-plan.js";
|
|
17
|
+
export { VersionStampError, readManifestVersion, stampCrateVersion, stampManifestVersion, stampPackageVersion, } from "./version-stamp.js";
|
|
18
|
+
export { WORKSPACE_FILENAME, WorkspaceConfigError, parseWorkspaceConfig } from "./workspace-config.js";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.changes/ledger.yaml` — what each module looks like **as published**.
|
|
3
|
+
*
|
|
4
|
+
* It exists so a gate can answer "does my payload differ from what is published
|
|
5
|
+
* at my current version?" with no network call, no merge base and no
|
|
6
|
+
* credentials: a fork's PR runs the identical computation the release job runs.
|
|
7
|
+
* That is the load-bearing property — the PR gate and the publish gate compute
|
|
8
|
+
* the same number.
|
|
9
|
+
*
|
|
10
|
+
* **It is a cache, never the authority.** A committed digest can disagree with
|
|
11
|
+
* the registry — a hand edit, an `apply` whose publish then failed, a push made
|
|
12
|
+
* outside the pipeline — so `telo publish` still reads the registry, and
|
|
13
|
+
* `telo release verify` reconciles the two on demand. A *missing* entry is not
|
|
14
|
+
* drift: it means nothing is published, which is the correct reading for a
|
|
15
|
+
* module that has never shipped.
|
|
16
|
+
*
|
|
17
|
+
* **It records the registry base**, because canonicalizing a relative `imports:`
|
|
18
|
+
* source writes the destination into the manifest layer — so the digests below
|
|
19
|
+
* are digests *against that base*, and comparing them to digests taken against
|
|
20
|
+
* another one would be comparing two different artifacts.
|
|
21
|
+
*/
|
|
22
|
+
import { type ModuleKey } from "./fragment.js";
|
|
23
|
+
import type { LayerDigests } from "./payload-digest.js";
|
|
24
|
+
export declare const LEDGER_PATH = ".changes/ledger.yaml";
|
|
25
|
+
export interface LedgerEntry {
|
|
26
|
+
/** The version these digests were taken at — the tag the artifact published
|
|
27
|
+
* under. */
|
|
28
|
+
readonly version: string;
|
|
29
|
+
readonly layers: LayerDigests;
|
|
30
|
+
}
|
|
31
|
+
export interface Ledger {
|
|
32
|
+
/**
|
|
33
|
+
* The publish destination base the digests were taken against
|
|
34
|
+
* (`oci://ghcr.io/telorun`). Absent in a workspace that has published nothing
|
|
35
|
+
* yet, which is why it is optional rather than required — but a `check` that
|
|
36
|
+
* has entries and no base cannot reproduce them, and says so.
|
|
37
|
+
*/
|
|
38
|
+
readonly registry?: string;
|
|
39
|
+
readonly modules: ReadonlyMap<ModuleKey, LedgerEntry>;
|
|
40
|
+
}
|
|
41
|
+
export declare class LedgerError extends Error {
|
|
42
|
+
}
|
|
43
|
+
export declare const EMPTY_LEDGER: Ledger;
|
|
44
|
+
export declare function parseLedger(text: string, where: string): Ledger;
|
|
45
|
+
/**
|
|
46
|
+
* Render the ledger.
|
|
47
|
+
*
|
|
48
|
+
* Keys are sorted so a release's ledger diff shows only the modules that moved
|
|
49
|
+
* — the file is committed and reviewed, and a map whose order followed insertion
|
|
50
|
+
* would reorder wholesale on every run.
|
|
51
|
+
*/
|
|
52
|
+
export declare function serializeLedger(ledger: Ledger): string;
|
|
53
|
+
//# sourceMappingURL=ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/release/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,eAAO,MAAM,WAAW,yBAAyB,CAAC;AAElD,MAAM,WAAW,WAAW;IAC1B;iBACa;IACb,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CAC/B;AAED,MAAM,WAAW,MAAM;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;CACvD;AAED,qBAAa,WAAY,SAAQ,KAAK;CAAG;AAEzC,eAAO,MAAM,YAAY,EAAE,MAA+B,CAAC;AAE3D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA+D/D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAkBtD"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.changes/ledger.yaml` — what each module looks like **as published**.
|
|
3
|
+
*
|
|
4
|
+
* It exists so a gate can answer "does my payload differ from what is published
|
|
5
|
+
* at my current version?" with no network call, no merge base and no
|
|
6
|
+
* credentials: a fork's PR runs the identical computation the release job runs.
|
|
7
|
+
* That is the load-bearing property — the PR gate and the publish gate compute
|
|
8
|
+
* the same number.
|
|
9
|
+
*
|
|
10
|
+
* **It is a cache, never the authority.** A committed digest can disagree with
|
|
11
|
+
* the registry — a hand edit, an `apply` whose publish then failed, a push made
|
|
12
|
+
* outside the pipeline — so `telo publish` still reads the registry, and
|
|
13
|
+
* `telo release verify` reconciles the two on demand. A *missing* entry is not
|
|
14
|
+
* drift: it means nothing is published, which is the correct reading for a
|
|
15
|
+
* module that has never shipped.
|
|
16
|
+
*
|
|
17
|
+
* **It records the registry base**, because canonicalizing a relative `imports:`
|
|
18
|
+
* source writes the destination into the manifest layer — so the digests below
|
|
19
|
+
* are digests *against that base*, and comparing them to digests taken against
|
|
20
|
+
* another one would be comparing two different artifacts.
|
|
21
|
+
*/
|
|
22
|
+
import { Document, parseDocument } from "yaml";
|
|
23
|
+
import { isReleaseVersion } from "./bump-level.js";
|
|
24
|
+
import { normalizeModuleKey } from "./fragment.js";
|
|
25
|
+
export const LEDGER_PATH = ".changes/ledger.yaml";
|
|
26
|
+
export class LedgerError extends Error {
|
|
27
|
+
}
|
|
28
|
+
export const EMPTY_LEDGER = { modules: new Map() };
|
|
29
|
+
export function parseLedger(text, where) {
|
|
30
|
+
let value;
|
|
31
|
+
try {
|
|
32
|
+
value = parseDocument(text).toJSON();
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
throw new LedgerError(`${where} is not valid YAML: ${err instanceof Error ? err.message : String(err)}`);
|
|
36
|
+
}
|
|
37
|
+
if (value === null)
|
|
38
|
+
return EMPTY_LEDGER;
|
|
39
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
40
|
+
throw new LedgerError(`${where} must be a YAML mapping.`);
|
|
41
|
+
}
|
|
42
|
+
const record = value;
|
|
43
|
+
for (const key of Object.keys(record)) {
|
|
44
|
+
if (key !== "registry" && key !== "modules") {
|
|
45
|
+
throw new LedgerError(`${where}: unknown field '${key}'. The ledger carries 'registry:' and 'modules:'.`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const registry = record.registry;
|
|
49
|
+
if (registry !== undefined && typeof registry !== "string") {
|
|
50
|
+
throw new LedgerError(`${where}: 'registry' must be the publish destination base, as a string.`);
|
|
51
|
+
}
|
|
52
|
+
const rawModules = record.modules;
|
|
53
|
+
if (rawModules === undefined || rawModules === null)
|
|
54
|
+
return { ...(registry ? { registry } : {}), modules: new Map() };
|
|
55
|
+
if (typeof rawModules !== "object" || Array.isArray(rawModules)) {
|
|
56
|
+
throw new LedgerError(`${where}: 'modules' must be a mapping of module path to entry.`);
|
|
57
|
+
}
|
|
58
|
+
const modules = new Map();
|
|
59
|
+
for (const [key, raw] of Object.entries(rawModules)) {
|
|
60
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
61
|
+
throw new LedgerError(`${where}: entry '${key}' must be a mapping.`);
|
|
62
|
+
}
|
|
63
|
+
const entry = raw;
|
|
64
|
+
if (!isReleaseVersion(entry.version)) {
|
|
65
|
+
throw new LedgerError(`${where}: entry '${key}' has no major.minor.patch 'version'. The ledger records the ` +
|
|
66
|
+
`version each digest was taken at; without it the digest says nothing.`);
|
|
67
|
+
}
|
|
68
|
+
const layers = {};
|
|
69
|
+
const rawLayers = entry.layers;
|
|
70
|
+
if (rawLayers !== undefined && rawLayers !== null) {
|
|
71
|
+
if (typeof rawLayers !== "object" || Array.isArray(rawLayers)) {
|
|
72
|
+
throw new LedgerError(`${where}: entry '${key}' has a non-mapping 'layers'.`);
|
|
73
|
+
}
|
|
74
|
+
for (const [layer, digest] of Object.entries(rawLayers)) {
|
|
75
|
+
if (typeof digest !== "string") {
|
|
76
|
+
throw new LedgerError(`${where}: entry '${key}' layer '${layer}' is not a digest string.`);
|
|
77
|
+
}
|
|
78
|
+
layers[layer] = digest;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
modules.set(normalizeModuleKey(key), { version: entry.version, layers });
|
|
82
|
+
}
|
|
83
|
+
return { ...(registry ? { registry } : {}), modules };
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Render the ledger.
|
|
87
|
+
*
|
|
88
|
+
* Keys are sorted so a release's ledger diff shows only the modules that moved
|
|
89
|
+
* — the file is committed and reviewed, and a map whose order followed insertion
|
|
90
|
+
* would reorder wholesale on every run.
|
|
91
|
+
*/
|
|
92
|
+
export function serializeLedger(ledger) {
|
|
93
|
+
const modules = {};
|
|
94
|
+
for (const key of [...ledger.modules.keys()].sort()) {
|
|
95
|
+
const entry = ledger.modules.get(key);
|
|
96
|
+
const layers = {};
|
|
97
|
+
for (const layer of Object.keys(entry.layers).sort())
|
|
98
|
+
layers[layer] = entry.layers[layer];
|
|
99
|
+
modules[key] = { version: entry.version, layers };
|
|
100
|
+
}
|
|
101
|
+
const doc = new Document({
|
|
102
|
+
...(ledger.registry ? { registry: ledger.registry } : {}),
|
|
103
|
+
modules,
|
|
104
|
+
});
|
|
105
|
+
return ("# Generated by `telo release apply` — what each module looks like as published.\n" +
|
|
106
|
+
"# A cache of the registry's answer, so a PR gate needs no credentials.\n" +
|
|
107
|
+
"# `telo release verify` reconciles it against the registry.\n" +
|
|
108
|
+
doc.toString({ lineWidth: 0 }));
|
|
109
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A module's payload, reduced to one digest per layer — the exact answer to
|
|
3
|
+
* "did this module's artifact change?".
|
|
4
|
+
*
|
|
5
|
+
* It is exact because it is taken from the bytes: it fires for an inlined
|
|
6
|
+
* sibling's edit, for a shared-library fix, and for a transitive bump the
|
|
7
|
+
* lockfile alone moved, none of which touch a file under the module's own
|
|
8
|
+
* directory. No path-scoped rule and no declared-dependency graph can see any of
|
|
9
|
+
* them.
|
|
10
|
+
*
|
|
11
|
+
* The digest itself is `computeFilesIntegrity`, the same framing-independent
|
|
12
|
+
* content digest the published `layers:` index carries — which is what makes the
|
|
13
|
+
* ledger's recorded number and the registry's the same number, comparable
|
|
14
|
+
* without fetching a blob.
|
|
15
|
+
*/
|
|
16
|
+
import { type ArtifactSelector, type LayerRole } from "../artifact-selector.js";
|
|
17
|
+
/** Per-layer integrity, keyed by `layerDigestKey`. */
|
|
18
|
+
export type LayerDigests = Readonly<Record<string, string>>;
|
|
19
|
+
/** The ledger key for the module's `telo.yaml` layer. */
|
|
20
|
+
export declare const MANIFEST_LAYER = "manifest";
|
|
21
|
+
/**
|
|
22
|
+
* Ledger keys the registry cannot answer for, and so the ones `telo release
|
|
23
|
+
* verify` reconciles nothing about and must preserve.
|
|
24
|
+
*
|
|
25
|
+
* Exactly one today, and for a structural reason rather than an omission: the
|
|
26
|
+
* published `layers:` index lives *inside* `telo.yaml`, so it cannot carry that
|
|
27
|
+
* file's own digest — the entry would have to be computed over bytes containing
|
|
28
|
+
* it. Nor can the digest be recovered by hashing what the registry serves, since
|
|
29
|
+
* the transport injects the index at push time and the published text is
|
|
30
|
+
* therefore not the text the payload builder produced.
|
|
31
|
+
*
|
|
32
|
+
* It stays in the ledger regardless, because it is the only thing that sees a
|
|
33
|
+
* **manifest-only change**: a schema edit, a new kind, a description, a
|
|
34
|
+
* dependency's version moving into a pin. None of those touch a controller byte,
|
|
35
|
+
* so without this key such a module would report no drift and its fix would ship
|
|
36
|
+
* to nobody — the exact failure the digest exists to prevent.
|
|
37
|
+
*/
|
|
38
|
+
export declare const LOCALLY_DERIVED_LAYERS: ReadonlySet<string>;
|
|
39
|
+
/**
|
|
40
|
+
* A layer's identity within an artifact, as a stable, readable, YAML-plain key.
|
|
41
|
+
*
|
|
42
|
+
* A role alone is not the identity — there is one controller layer per selector
|
|
43
|
+
* — so a selector's axes join the key. Rendered as `controller/js` and
|
|
44
|
+
* `controller/napi+linux+amd64+gnu` rather than through `selectorKey`'s
|
|
45
|
+
* `axis=value;…` form, because this string is read by a human in a ledger diff
|
|
46
|
+
* and written into a plain YAML key; the axis order is `PLATFORM_AXES`, so the
|
|
47
|
+
* rendering is deterministic rather than dependent on how the selector was
|
|
48
|
+
* built.
|
|
49
|
+
*/
|
|
50
|
+
export declare function layerDigestKey(role: LayerRole | string, selector?: ArtifactSelector): string;
|
|
51
|
+
/** A layer whose digest differs between two readings, or that exists in only
|
|
52
|
+
* one of them. `before` / `after` are absent when the layer is absent there —
|
|
53
|
+
* a payload that gained or lost a layer changed just as much as one whose
|
|
54
|
+
* bytes moved. */
|
|
55
|
+
export interface LayerChange {
|
|
56
|
+
readonly layer: string;
|
|
57
|
+
readonly before?: string;
|
|
58
|
+
readonly after?: string;
|
|
59
|
+
}
|
|
60
|
+
/** Every layer on which two readings disagree, in key order. Empty means the
|
|
61
|
+
* payloads are byte-identical. */
|
|
62
|
+
export declare function diffLayerDigests(before: LayerDigests, after: LayerDigests): LayerChange[];
|
|
63
|
+
//# sourceMappingURL=payload-digest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payload-digest.d.ts","sourceRoot":"","sources":["../../src/release/payload-digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAiB,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAE/F,sDAAsD;AACtD,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE5D,yDAAyD;AACzD,eAAO,MAAM,cAAc,aAAa,CAAC;AAEzC;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAA6B,CAAC;AAErF;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,EAAE,QAAQ,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAM5F;AAED;;;mBAGmB;AACnB,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;mCACmC;AACnC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,WAAW,EAAE,CAQzF"}
|