@milaboratories/pl-model-common 1.47.3 → 1.48.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/bmodel/block_kind_ref.cjs +45 -0
- package/dist/bmodel/block_kind_ref.cjs.map +1 -0
- package/dist/bmodel/block_kind_ref.d.ts +57 -0
- package/dist/bmodel/block_kind_ref.d.ts.map +1 -0
- package/dist/bmodel/block_kind_ref.js +43 -0
- package/dist/bmodel/block_kind_ref.js.map +1 -0
- package/dist/bmodel/container.d.ts +8 -0
- package/dist/bmodel/container.d.ts.map +1 -1
- package/dist/bmodel/index.cjs +4 -0
- package/dist/bmodel/index.d.ts +2 -1
- package/dist/bmodel/index.js +2 -1
- package/dist/columns/dedup.cjs +1 -1
- package/dist/columns/dedup.cjs.map +1 -1
- package/dist/columns/dedup.d.ts +1 -1
- package/dist/columns/dedup.js +1 -1
- package/dist/columns/dedup.js.map +1 -1
- package/dist/columns/providers.cjs +1 -1
- package/dist/columns/providers.cjs.map +1 -1
- package/dist/columns/providers.d.ts +1 -1
- package/dist/columns/providers.js +1 -1
- package/dist/columns/providers.js.map +1 -1
- package/dist/drivers/index.cjs +4 -0
- package/dist/drivers/index.d.ts +2 -2
- package/dist/drivers/index.js +2 -2
- package/dist/drivers/pframe/index.cjs +4 -0
- package/dist/drivers/pframe/index.d.ts +2 -2
- package/dist/drivers/pframe/index.js +2 -2
- package/dist/drivers/pframe/spec/ids.cjs +151 -0
- package/dist/drivers/pframe/spec/ids.cjs.map +1 -1
- package/dist/drivers/pframe/spec/ids.d.ts +53 -1
- package/dist/drivers/pframe/spec/ids.d.ts.map +1 -1
- package/dist/drivers/pframe/spec/ids.js +150 -3
- package/dist/drivers/pframe/spec/ids.js.map +1 -1
- package/dist/drivers/pframe/spec/index.cjs +4 -0
- package/dist/drivers/pframe/spec/index.d.ts +2 -2
- package/dist/drivers/pframe/spec/index.js +2 -2
- package/dist/index.cjs +29 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +8 -2
- package/dist/plid.cjs +1 -1
- package/dist/plid.cjs.map +1 -1
- package/dist/plid.d.ts +3 -2
- package/dist/plid.d.ts.map +1 -1
- package/dist/plid.js +1 -1
- package/dist/plid.js.map +1 -1
- package/dist/template/index.cjs +20 -0
- package/dist/template/index.d.ts +5 -0
- package/dist/template/index.js +5 -0
- package/dist/template/kind_selector.cjs +92 -0
- package/dist/template/kind_selector.cjs.map +1 -0
- package/dist/template/kind_selector.d.ts +80 -0
- package/dist/template/kind_selector.d.ts.map +1 -0
- package/dist/template/kind_selector.js +87 -0
- package/dist/template/kind_selector.js.map +1 -0
- package/dist/template/project_template_v1.cjs +231 -0
- package/dist/template/project_template_v1.cjs.map +1 -0
- package/dist/template/project_template_v1.d.ts +215 -0
- package/dist/template/project_template_v1.d.ts.map +1 -0
- package/dist/template/project_template_v1.js +225 -0
- package/dist/template/project_template_v1.js.map +1 -0
- package/dist/template/template_ref_form.cjs +73 -0
- package/dist/template/template_ref_form.cjs.map +1 -0
- package/dist/template/template_ref_form.d.ts +74 -0
- package/dist/template/template_ref_form.d.ts.map +1 -0
- package/dist/template/template_ref_form.js +72 -0
- package/dist/template/template_ref_form.js.map +1 -0
- package/dist/template/template_relocate.cjs +46 -0
- package/dist/template/template_relocate.cjs.map +1 -0
- package/dist/template/template_relocate.d.ts +32 -0
- package/dist/template/template_relocate.d.ts.map +1 -0
- package/dist/template/template_relocate.js +46 -0
- package/dist/template/template_relocate.js.map +1 -0
- package/package.json +5 -5
- package/src/bmodel/block_kind_ref.ts +59 -0
- package/src/bmodel/container.ts +9 -0
- package/src/bmodel/index.ts +1 -0
- package/src/columns/dedup.ts +1 -1
- package/src/columns/providers.ts +1 -1
- package/src/drivers/pframe/spec/ids.test.ts +90 -0
- package/src/drivers/pframe/spec/ids.ts +191 -1
- package/src/index.ts +1 -0
- package/src/plid.ts +5 -5
- package/src/template/index.ts +4 -0
- package/src/template/kind_selector.ts +126 -0
- package/src/template/project_template_v1.test.ts +315 -0
- package/src/template/project_template_v1.ts +444 -0
- package/src/template/template_ref_form.test.ts +86 -0
- package/src/template/template_ref_form.ts +108 -0
- package/src/template/template_relocate.test.ts +182 -0
- package/src/template/template_relocate.ts +61 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { parseKindRef, splitVersionedName } from "../bmodel/block_kind_ref.js";
|
|
2
|
+
//#region src/template/kind_selector.ts
|
|
3
|
+
/** `X.Y.Z` with optional semver prerelease and build metadata. */
|
|
4
|
+
const semVerRegex = /^\d+\.\d+\.\d+(?:-[\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*)?(?:\+[\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*)?$/;
|
|
5
|
+
/**
|
|
6
|
+
* Split a raw selector string (`1.2.0`, `~1.2.0`, `^1.2.0`) into its parts.
|
|
7
|
+
*
|
|
8
|
+
* The version is validated as `X.Y.Z`, so a range that is legal npm but not part
|
|
9
|
+
* of the kind grammar (`>=1.0.0`, `1.x`, `latest`) is rejected here rather than
|
|
10
|
+
* reaching resolution. Note the deliberate divergence from
|
|
11
|
+
* `tools/block-tools`'s `parseSelector`, which additionally tolerates a leading
|
|
12
|
+
* `@` as `exact`: after the `{name}@{selector}` split a leading `@` can only
|
|
13
|
+
* come from a doubled separator, which is malformed.
|
|
14
|
+
*
|
|
15
|
+
* Mapping a selector onto a concrete version is resolution, not parsing, and
|
|
16
|
+
* lives with the resolver (`kind_resolver.selectorToRange`).
|
|
17
|
+
*
|
|
18
|
+
* @throws if the version part is not `X.Y.Z`
|
|
19
|
+
*/
|
|
20
|
+
function parseKindSelector(raw) {
|
|
21
|
+
const s = raw.trim();
|
|
22
|
+
const op = s.startsWith("~") ? "patch" : s.startsWith("^") ? "minor" : "exact";
|
|
23
|
+
const version = op === "exact" ? s : s.slice(1);
|
|
24
|
+
if (!semVerRegex.test(version)) throw new Error(`Malformed kind version selector (expected 'X.Y.Z', '~X.Y.Z' or '^X.Y.Z'): ${raw}`);
|
|
25
|
+
return {
|
|
26
|
+
op,
|
|
27
|
+
version
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Render a {@link KindSelector} back to its on-wire string. */
|
|
31
|
+
function formatKindSelector(sel) {
|
|
32
|
+
switch (sel.op) {
|
|
33
|
+
case "exact": return sel.version;
|
|
34
|
+
case "patch": return `~${sel.version}`;
|
|
35
|
+
case "minor": return `^${sel.version}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Split a {@link BlockKindSelectorReference} into `{ name, selector }`.
|
|
40
|
+
*
|
|
41
|
+
* @throws if the reference carries no version segment, or the selector is
|
|
42
|
+
* outside the `X.Y.Z` / `~X.Y.Z` / `^X.Y.Z` grammar
|
|
43
|
+
*/
|
|
44
|
+
function parseKindSelectorReference(ref) {
|
|
45
|
+
const { name, version } = splitVersionedName(ref, "kind selector reference", "{name}@{selector}");
|
|
46
|
+
return {
|
|
47
|
+
name,
|
|
48
|
+
selector: parseKindSelector(version)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Compose a {@link BlockKindSelectorReference} from a name and selector.
|
|
53
|
+
*
|
|
54
|
+
* A formatter, not a validator — pass a selector that came from
|
|
55
|
+
* {@link parseKindSelector} or that you constructed from a known-good version.
|
|
56
|
+
*/
|
|
57
|
+
function formatKindSelectorReference(k) {
|
|
58
|
+
return `${k.name}@${formatKindSelector(k.selector)}`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Widen a resolved {@link BlockKindReference} to its `exact`-tier selector form.
|
|
62
|
+
*
|
|
63
|
+
* The export direction: a block implements exactly one kind version, so export
|
|
64
|
+
* always emits `{name}@X.Y.Z`. Validates on the way through, so a
|
|
65
|
+
* malformed stored reference fails at the boundary rather than in the file.
|
|
66
|
+
*/
|
|
67
|
+
function kindReferenceToSelectorReference(ref) {
|
|
68
|
+
const { name, version } = parseKindRef(ref);
|
|
69
|
+
return formatKindSelectorReference({
|
|
70
|
+
name,
|
|
71
|
+
selector: parseKindSelector(version)
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/** Whether `value` is a well-formed `{name}@{selector}` string. */
|
|
75
|
+
function isBlockKindSelectorReference(value) {
|
|
76
|
+
if (typeof value !== "string") return false;
|
|
77
|
+
try {
|
|
78
|
+
parseKindSelectorReference(value);
|
|
79
|
+
return true;
|
|
80
|
+
} catch {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
export { formatKindSelector, formatKindSelectorReference, isBlockKindSelectorReference, kindReferenceToSelectorReference, parseKindSelector, parseKindSelectorReference };
|
|
86
|
+
|
|
87
|
+
//# sourceMappingURL=kind_selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kind_selector.js","names":[],"sources":["../../src/template/kind_selector.ts"],"sourcesContent":["import type { Branded } from \"@milaboratories/helpers\";\nimport type { BlockKindReference } from \"../bmodel/block_kind_ref\";\nimport { parseKindRef, splitVersionedName } from \"../bmodel/block_kind_ref\";\n\n/**\n * Version-selection tier of a template entry's `kind` field.\n *\n * - `exact` — `X.Y.Z`: this version and no other.\n * - `patch` — `~X.Y.Z`: patch floor, behavior frozen.\n * - `minor` — `^X.Y.Z`: minor floor, behavior floats.\n */\nexport type KindSelectorOp = \"exact\" | \"patch\" | \"minor\";\n\n/** The version half of a `{name}@{selector}` kind reference, split into parts. */\nexport type KindSelector = {\n readonly op: KindSelectorOp;\n readonly version: string;\n};\n\n/**\n * On-wire reference to a *set* of block kind versions: `{name}@{selector}`, e.g.\n * `@platforma-open/milaboratories.mixcr-clonotyping.kind@~1.2.0`.\n *\n * The template-file form of a kind reference, and the only form the\n * `template-v1` schema accepts in an entry's `kind` field. It is the same string\n * shape as {@link BlockKindReference} widened by the `~`/`^` tiers, but branded\n * separately so a *resolved* kind reference is never silently passed where a\n * selector is expected, or vice versa. Widen an exact reference explicitly with\n * {@link kindReferenceToSelectorReference}.\n */\nexport type BlockKindSelectorReference = Branded<string, \"BlockKindSelectorReference\">;\n\n/** `X.Y.Z` with optional semver prerelease and build metadata. */\nconst semVerRegex =\n /^\\d+\\.\\d+\\.\\d+(?:-[\\dA-Za-z-]+(?:\\.[\\dA-Za-z-]+)*)?(?:\\+[\\dA-Za-z-]+(?:\\.[\\dA-Za-z-]+)*)?$/;\n\n/**\n * Split a raw selector string (`1.2.0`, `~1.2.0`, `^1.2.0`) into its parts.\n *\n * The version is validated as `X.Y.Z`, so a range that is legal npm but not part\n * of the kind grammar (`>=1.0.0`, `1.x`, `latest`) is rejected here rather than\n * reaching resolution. Note the deliberate divergence from\n * `tools/block-tools`'s `parseSelector`, which additionally tolerates a leading\n * `@` as `exact`: after the `{name}@{selector}` split a leading `@` can only\n * come from a doubled separator, which is malformed.\n *\n * Mapping a selector onto a concrete version is resolution, not parsing, and\n * lives with the resolver (`kind_resolver.selectorToRange`).\n *\n * @throws if the version part is not `X.Y.Z`\n */\nexport function parseKindSelector(raw: string): KindSelector {\n const s = raw.trim();\n const op: KindSelectorOp = s.startsWith(\"~\") ? \"patch\" : s.startsWith(\"^\") ? \"minor\" : \"exact\";\n const version = op === \"exact\" ? s : s.slice(1);\n if (!semVerRegex.test(version)) {\n throw new Error(\n `Malformed kind version selector (expected 'X.Y.Z', '~X.Y.Z' or '^X.Y.Z'): ${raw}`,\n );\n }\n return { op, version };\n}\n\n/** Render a {@link KindSelector} back to its on-wire string. */\nexport function formatKindSelector(sel: KindSelector): string {\n switch (sel.op) {\n case \"exact\":\n return sel.version;\n case \"patch\":\n return `~${sel.version}`;\n case \"minor\":\n return `^${sel.version}`;\n }\n}\n\n/**\n * Split a {@link BlockKindSelectorReference} into `{ name, selector }`.\n *\n * @throws if the reference carries no version segment, or the selector is\n * outside the `X.Y.Z` / `~X.Y.Z` / `^X.Y.Z` grammar\n */\nexport function parseKindSelectorReference(ref: BlockKindSelectorReference): {\n name: string;\n selector: KindSelector;\n} {\n const { name, version } = splitVersionedName(ref, \"kind selector reference\", \"{name}@{selector}\");\n return { name, selector: parseKindSelector(version) };\n}\n\n/**\n * Compose a {@link BlockKindSelectorReference} from a name and selector.\n *\n * A formatter, not a validator — pass a selector that came from\n * {@link parseKindSelector} or that you constructed from a known-good version.\n */\nexport function formatKindSelectorReference(k: {\n name: string;\n selector: KindSelector;\n}): BlockKindSelectorReference {\n return `${k.name}@${formatKindSelector(k.selector)}` as BlockKindSelectorReference;\n}\n\n/**\n * Widen a resolved {@link BlockKindReference} to its `exact`-tier selector form.\n *\n * The export direction: a block implements exactly one kind version, so export\n * always emits `{name}@X.Y.Z`. Validates on the way through, so a\n * malformed stored reference fails at the boundary rather than in the file.\n */\nexport function kindReferenceToSelectorReference(\n ref: BlockKindReference,\n): BlockKindSelectorReference {\n const { name, version } = parseKindRef(ref);\n return formatKindSelectorReference({ name, selector: parseKindSelector(version) });\n}\n\n/** Whether `value` is a well-formed `{name}@{selector}` string. */\nexport function isBlockKindSelectorReference(value: unknown): value is BlockKindSelectorReference {\n if (typeof value !== \"string\") return false;\n try {\n parseKindSelectorReference(value as BlockKindSelectorReference);\n return true;\n } catch {\n return false;\n }\n}\n"],"mappings":";;;AAiCA,MAAM,cACJ;;;;;;;;;;;;;;;;AAiBF,SAAgB,kBAAkB,KAA2B;CAC3D,MAAM,IAAI,IAAI,KAAK;CACnB,MAAM,KAAqB,EAAE,WAAW,GAAG,IAAI,UAAU,EAAE,WAAW,GAAG,IAAI,UAAU;CACvF,MAAM,UAAU,OAAO,UAAU,IAAI,EAAE,MAAM,CAAC;CAC9C,IAAI,CAAC,YAAY,KAAK,OAAO,GAC3B,MAAM,IAAI,MACR,6EAA6E,KAC/E;CAEF,OAAO;EAAE;EAAI;CAAQ;AACvB;;AAGA,SAAgB,mBAAmB,KAA2B;CAC5D,QAAQ,IAAI,IAAZ;EACE,KAAK,SACH,OAAO,IAAI;EACb,KAAK,SACH,OAAO,IAAI,IAAI;EACjB,KAAK,SACH,OAAO,IAAI,IAAI;CACnB;AACF;;;;;;;AAQA,SAAgB,2BAA2B,KAGzC;CACA,MAAM,EAAE,MAAM,YAAY,mBAAmB,KAAK,2BAA2B,mBAAmB;CAChG,OAAO;EAAE;EAAM,UAAU,kBAAkB,OAAO;CAAE;AACtD;;;;;;;AAQA,SAAgB,4BAA4B,GAGb;CAC7B,OAAO,GAAG,EAAE,KAAK,GAAG,mBAAmB,EAAE,QAAQ;AACnD;;;;;;;;AASA,SAAgB,iCACd,KAC4B;CAC5B,MAAM,EAAE,MAAM,YAAY,aAAa,GAAG;CAC1C,OAAO,4BAA4B;EAAE;EAAM,UAAU,kBAAkB,OAAO;CAAE,CAAC;AACnF;;AAGA,SAAgB,6BAA6B,OAAqD;CAChG,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI;EACF,2BAA2B,KAAmC;EAC9D,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF"}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
const require_block_kind_ref = require("../bmodel/block_kind_ref.cjs");
|
|
2
|
+
const require_kind_selector = require("./kind_selector.cjs");
|
|
3
|
+
//#region src/template/project_template_v1.ts
|
|
4
|
+
/**
|
|
5
|
+
* Value of a template file's `schema` field — the format marker every
|
|
6
|
+
* `template-v1` document opens with.
|
|
7
|
+
*/
|
|
8
|
+
const PROJECT_TEMPLATE_SCHEMA_V1 = "template-v1";
|
|
9
|
+
/**
|
|
10
|
+
* Split a {@link BlockPackReference} into `{ name, version }`.
|
|
11
|
+
*
|
|
12
|
+
* @throws if the reference carries no version segment or the version is not
|
|
13
|
+
* exactly `X.Y.Z`
|
|
14
|
+
*/
|
|
15
|
+
function parseBlockPackReference(ref) {
|
|
16
|
+
const { name, version } = require_block_kind_ref.splitVersionedName(ref, "block package reference", "{name}@X.Y.Z");
|
|
17
|
+
const selector = require_kind_selector.parseKindSelector(version);
|
|
18
|
+
if (selector.op !== "exact") throw new Error(`A 'block' override must pin an exact version (expected '{name}@X.Y.Z'): ${ref}`);
|
|
19
|
+
return {
|
|
20
|
+
name,
|
|
21
|
+
version: selector.version
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Read the scheme off a {@link BlockPackLocationReference}, which is all the
|
|
26
|
+
* document layer knows about it — resolving the rest belongs to whoever can reach
|
|
27
|
+
* the scheme.
|
|
28
|
+
*
|
|
29
|
+
* A scheme is required. Accepting a bare path would mean reading it relative to
|
|
30
|
+
* whatever directory the application happens to have been started from, which is
|
|
31
|
+
* exactly the ambiguity a locator exists to remove.
|
|
32
|
+
*
|
|
33
|
+
* @throws if the value carries no scheme
|
|
34
|
+
*/
|
|
35
|
+
function parseBlockPackLocation(ref) {
|
|
36
|
+
const match = LocationSchemePattern.exec(ref);
|
|
37
|
+
if (!match) throw new Error(`A 'location' must be an absolute URI with a scheme (expected e.g. 'file:///path/to/block'), got: ${ref}`);
|
|
38
|
+
return { scheme: match.groups.scheme.toLowerCase() };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Scheme grammar, with one deliberate narrowing: a scheme is at least TWO
|
|
42
|
+
* characters, while the URI grammar allows one.
|
|
43
|
+
*
|
|
44
|
+
* `C:\blocks\my-block` is a valid single-letter-scheme URI, so a Windows path
|
|
45
|
+
* pasted into the field would otherwise be accepted with scheme `c` and then fail
|
|
46
|
+
* far away from the mistake. Rejecting it here means the error names the actual
|
|
47
|
+
* problem, and the fix — `file:///C:/blocks/my-block` — is spelled out.
|
|
48
|
+
*/
|
|
49
|
+
const LocationSchemePattern = /^(?<scheme>[A-Za-z][A-Za-z0-9+.-]+):/;
|
|
50
|
+
/**
|
|
51
|
+
* One issue as a line: `blocks[2].kind: Expected a kind reference, got nothing.`
|
|
52
|
+
*
|
|
53
|
+
* Indexes read as they are written in the file — `blocks[2]`, not `blocks.2` — so the place
|
|
54
|
+
* can be found by reading rather than by counting.
|
|
55
|
+
*/
|
|
56
|
+
function formatTemplateParseIssue(issue) {
|
|
57
|
+
const path = issue.path.reduce((acc, segment) => typeof segment === "number" ? `${acc}[${segment}]` : acc === "" ? segment : `${acc}.${segment}`, "");
|
|
58
|
+
return path === "" ? issue.message : `${path}: ${issue.message}`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Every problem a document has, thrown once so a caller fixes the file in one pass.
|
|
62
|
+
*
|
|
63
|
+
* The issues are in `message` as well as on `issues`, because a throw that escapes to a log is
|
|
64
|
+
* read as its message and nothing else.
|
|
65
|
+
*/
|
|
66
|
+
var ProjectTemplateV1ParseError = class extends Error {
|
|
67
|
+
issues;
|
|
68
|
+
constructor(issues) {
|
|
69
|
+
super([`The template document could not be read (${issues.length} problem(s)):`, ...issues.map((issue) => `- ${formatTemplateParseIssue(issue)}`)].join("\n"));
|
|
70
|
+
this.issues = issues;
|
|
71
|
+
this.name = "ProjectTemplateV1ParseError";
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const isMapping = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
75
|
+
/** Keys an entry may carry. Anything else is a mistake, not an extension point. */
|
|
76
|
+
const ENTRY_KEYS = [
|
|
77
|
+
"id",
|
|
78
|
+
"kind",
|
|
79
|
+
"block",
|
|
80
|
+
"location",
|
|
81
|
+
"params"
|
|
82
|
+
];
|
|
83
|
+
/**
|
|
84
|
+
* Read an already-decoded template document — the value a YAML or JSON reader returns.
|
|
85
|
+
*
|
|
86
|
+
* Checks the format marker, every entry's shape, the reference grammars and id uniqueness,
|
|
87
|
+
* and settles an omitted `params` to `{}`. Unknown keys are refused rather than ignored: a
|
|
88
|
+
* misspelled key that was silently dropped would apply a file that does not say what its
|
|
89
|
+
* author meant.
|
|
90
|
+
*
|
|
91
|
+
* It does NOT check what an entry's params point at, and nothing downstream of it does
|
|
92
|
+
* either. Which values in there carry block ids is knowable only to the block, in its own
|
|
93
|
+
* bundle, where the params are relocated onto the project being built — so a reference to an
|
|
94
|
+
* entry listed later, or to the entry holding it, is not refused here. It survives into the
|
|
95
|
+
* applied project as a block whose references name nothing, which is how a reference to a
|
|
96
|
+
* deleted block already behaves.
|
|
97
|
+
*
|
|
98
|
+
* Collects rather than stops: a file with three mistakes should take one pass to fix.
|
|
99
|
+
*/
|
|
100
|
+
function readProjectTemplateV1(value) {
|
|
101
|
+
const issues = [];
|
|
102
|
+
const fail = (path, message) => issues.push({
|
|
103
|
+
path,
|
|
104
|
+
message
|
|
105
|
+
});
|
|
106
|
+
if (!isMapping(value)) return {
|
|
107
|
+
ok: false,
|
|
108
|
+
issues: [{
|
|
109
|
+
path: [],
|
|
110
|
+
message: "A template must be a mapping with 'schema' and 'blocks'."
|
|
111
|
+
}]
|
|
112
|
+
};
|
|
113
|
+
for (const key of Object.keys(value)) if (key !== "schema" && key !== "blocks") fail([], `Unrecognized key: '${key}'`);
|
|
114
|
+
if (value.schema !== "template-v1") fail(["schema"], `Expected '${PROJECT_TEMPLATE_SCHEMA_V1}', got ${describe(value.schema)}. This is the format marker every template opens with.`);
|
|
115
|
+
if (!Array.isArray(value.blocks)) {
|
|
116
|
+
fail(["blocks"], `Expected a list of entries, got ${describe(value.blocks)}.`);
|
|
117
|
+
return {
|
|
118
|
+
ok: false,
|
|
119
|
+
issues
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const blocks = [];
|
|
123
|
+
const seen = /* @__PURE__ */ new Set();
|
|
124
|
+
value.blocks.forEach((raw, i) => {
|
|
125
|
+
const entry = readEntry(raw, ["blocks", i], fail);
|
|
126
|
+
if (entry === void 0) return;
|
|
127
|
+
if (seen.has(entry.id)) fail([
|
|
128
|
+
"blocks",
|
|
129
|
+
i,
|
|
130
|
+
"id"
|
|
131
|
+
], `Duplicate template-local id: ${entry.id}`);
|
|
132
|
+
seen.add(entry.id);
|
|
133
|
+
blocks.push(entry);
|
|
134
|
+
});
|
|
135
|
+
if (issues.length > 0) return {
|
|
136
|
+
ok: false,
|
|
137
|
+
issues
|
|
138
|
+
};
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
document: {
|
|
142
|
+
schema: PROJECT_TEMPLATE_SCHEMA_V1,
|
|
143
|
+
blocks
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* One entry, or `undefined` when it is not even a mapping — in which case its own fields are
|
|
149
|
+
* not reported on top, since a reader given "this entry is not a mapping" does not also need
|
|
150
|
+
* to hear that its `id` is missing.
|
|
151
|
+
*/
|
|
152
|
+
function readEntry(raw, at, fail) {
|
|
153
|
+
if (!isMapping(raw)) {
|
|
154
|
+
fail(at, `Expected an entry mapping, got ${describe(raw)}.`);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
for (const key of Object.keys(raw)) if (!ENTRY_KEYS.includes(key)) fail(at, `Unrecognized key: '${key}'`);
|
|
158
|
+
let ok = true;
|
|
159
|
+
if (typeof raw.id !== "string" || raw.id.length === 0) {
|
|
160
|
+
fail([...at, "id"], `Expected a non-empty id, got ${describe(raw.id)}.`);
|
|
161
|
+
ok = false;
|
|
162
|
+
}
|
|
163
|
+
if (typeof raw.kind !== "string") {
|
|
164
|
+
fail([...at, "kind"], `Expected a kind reference, got ${describe(raw.kind)}.`);
|
|
165
|
+
ok = false;
|
|
166
|
+
} else ok = check([...at, "kind"], () => require_kind_selector.parseKindSelectorReference(raw.kind), fail) && ok;
|
|
167
|
+
if (raw.block !== void 0) if (typeof raw.block !== "string") {
|
|
168
|
+
fail([...at, "block"], `Expected a block package reference, got ${describe(raw.block)}.`);
|
|
169
|
+
ok = false;
|
|
170
|
+
} else ok = check([...at, "block"], () => parseBlockPackReference(raw.block), fail) && ok;
|
|
171
|
+
if (raw.location !== void 0) if (typeof raw.location !== "string") {
|
|
172
|
+
fail([...at, "location"], `Expected a locator URI, got ${describe(raw.location)}.`);
|
|
173
|
+
ok = false;
|
|
174
|
+
} else ok = check([...at, "location"], () => parseBlockPackLocation(raw.location), fail) && ok;
|
|
175
|
+
if (raw.block !== void 0 && raw.location !== void 0) {
|
|
176
|
+
fail([...at, "location"], "An entry cannot carry both 'block' and 'location': the first pins which version to install, the second pins where to install it from. Keep the one that is actually meant.");
|
|
177
|
+
ok = false;
|
|
178
|
+
}
|
|
179
|
+
if (raw.params !== void 0 && !isMapping(raw.params)) {
|
|
180
|
+
fail([...at, "params"], `Expected a mapping of params, got ${describe(raw.params)}.`);
|
|
181
|
+
ok = false;
|
|
182
|
+
}
|
|
183
|
+
if (!ok) return void 0;
|
|
184
|
+
return {
|
|
185
|
+
id: raw.id,
|
|
186
|
+
kind: raw.kind,
|
|
187
|
+
...raw.block !== void 0 ? { block: raw.block } : {},
|
|
188
|
+
...raw.location !== void 0 ? { location: raw.location } : {},
|
|
189
|
+
params: raw.params ?? {}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/** Run a grammar check, turning its throw into an issue at `path`. */
|
|
193
|
+
function check(path, grammar, fail) {
|
|
194
|
+
try {
|
|
195
|
+
grammar();
|
|
196
|
+
return true;
|
|
197
|
+
} catch (e) {
|
|
198
|
+
fail(path, e instanceof Error ? e.message : String(e));
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/** A value named the way an error message should name it, without printing its contents. */
|
|
203
|
+
function describe(value) {
|
|
204
|
+
if (value === void 0) return "nothing";
|
|
205
|
+
if (value === null) return "null";
|
|
206
|
+
if (Array.isArray(value)) return "a list";
|
|
207
|
+
if (typeof value === "string") return `'${value}'`;
|
|
208
|
+
if (typeof value === "object") return "a mapping";
|
|
209
|
+
return String(value);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* {@link readProjectTemplateV1} for a caller that treats an unreadable document as
|
|
213
|
+
* exceptional — export, which asserts on every run that what it wrote can be read back.
|
|
214
|
+
*
|
|
215
|
+
* @throws {ProjectTemplateV1ParseError} carrying every problem found
|
|
216
|
+
*/
|
|
217
|
+
function parseProjectTemplateV1(value) {
|
|
218
|
+
const outcome = readProjectTemplateV1(value);
|
|
219
|
+
if (!outcome.ok) throw new ProjectTemplateV1ParseError(outcome.issues);
|
|
220
|
+
return outcome.document;
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
exports.PROJECT_TEMPLATE_SCHEMA_V1 = PROJECT_TEMPLATE_SCHEMA_V1;
|
|
224
|
+
exports.ProjectTemplateV1ParseError = ProjectTemplateV1ParseError;
|
|
225
|
+
exports.formatTemplateParseIssue = formatTemplateParseIssue;
|
|
226
|
+
exports.parseBlockPackLocation = parseBlockPackLocation;
|
|
227
|
+
exports.parseBlockPackReference = parseBlockPackReference;
|
|
228
|
+
exports.parseProjectTemplateV1 = parseProjectTemplateV1;
|
|
229
|
+
exports.readProjectTemplateV1 = readProjectTemplateV1;
|
|
230
|
+
|
|
231
|
+
//# sourceMappingURL=project_template_v1.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project_template_v1.cjs","names":["splitVersionedName","parseKindSelector","parseKindSelectorReference"],"sources":["../../src/template/project_template_v1.ts"],"sourcesContent":["import type { Branded } from \"@milaboratories/helpers\";\nimport { splitVersionedName } from \"../bmodel/block_kind_ref\";\nimport type { BlockKindSelectorReference } from \"./kind_selector\";\nimport { parseKindSelector, parseKindSelectorReference } from \"./kind_selector\";\n\n/**\n * Value of a template file's `schema` field — the format marker every\n * `template-v1` document opens with.\n */\nexport const PROJECT_TEMPLATE_SCHEMA_V1 = \"template-v1\";\nexport type ProjectTemplateSchemaV1 = typeof PROJECT_TEMPLATE_SCHEMA_V1;\n\n/**\n * On-wire reference to one exact block package version, `{name}@X.Y.Z`.\n *\n * The `block` override's value type. Exact only — the override exists to pin an\n * implementation, so a range would defeat it. Mapping this to the structured\n * `BlockPackId` (`{ organization, name, version }`) is import-side work; the\n * organization lives inside the npm scope here, as it does for kind names.\n */\nexport type BlockPackReference = Branded<string, \"BlockPackReference\">;\n\n/**\n * Split a {@link BlockPackReference} into `{ name, version }`.\n *\n * @throws if the reference carries no version segment or the version is not\n * exactly `X.Y.Z`\n */\nexport function parseBlockPackReference(ref: BlockPackReference): {\n name: string;\n version: string;\n} {\n const { name, version } = splitVersionedName(ref, \"block package reference\", \"{name}@X.Y.Z\");\n const selector = parseKindSelector(version);\n if (selector.op !== \"exact\") {\n throw new Error(\n `A 'block' override must pin an exact version (expected '{name}@X.Y.Z'): ${ref}`,\n );\n }\n return { name, version: selector.version };\n}\n\n/**\n * On-wire locator naming WHERE one entry's block implementation comes from, as an\n * absolute URI: `file:///abs/path/to/block`.\n *\n * The third way an entry can reach an implementation, and the only one that names a\n * place rather than a name. It exists for a block that is built but not published —\n * the implementation lives in a folder and no registry knows it, so neither `kind`\n * resolution nor a `block` version pin can find it.\n *\n * A URI rather than a bare path because the question \"where\" is not limited to the\n * filesystem, and because scheme dispatch is how the rest of the toolchain already\n * answers it. Which schemes an environment can actually serve is that environment's\n * business: this type fixes only the grammar, so a document remains readable by a\n * consumer that cannot fetch every scheme.\n */\nexport type BlockPackLocationReference = Branded<string, \"BlockPackLocationReference\">;\n\n/**\n * Read the scheme off a {@link BlockPackLocationReference}, which is all the\n * document layer knows about it — resolving the rest belongs to whoever can reach\n * the scheme.\n *\n * A scheme is required. Accepting a bare path would mean reading it relative to\n * whatever directory the application happens to have been started from, which is\n * exactly the ambiguity a locator exists to remove.\n *\n * @throws if the value carries no scheme\n */\nexport function parseBlockPackLocation(ref: BlockPackLocationReference): { scheme: string } {\n const match = LocationSchemePattern.exec(ref);\n if (!match) {\n throw new Error(\n `A 'location' must be an absolute URI with a scheme (expected e.g. ` +\n `'file:///path/to/block'), got: ${ref}`,\n );\n }\n return { scheme: match.groups!.scheme.toLowerCase() };\n}\n\n/**\n * Scheme grammar, with one deliberate narrowing: a scheme is at least TWO\n * characters, while the URI grammar allows one.\n *\n * `C:\\blocks\\my-block` is a valid single-letter-scheme URI, so a Windows path\n * pasted into the field would otherwise be accepted with scheme `c` and then fail\n * far away from the mistake. Rejecting it here means the error names the actual\n * problem, and the fix — `file:///C:/blocks/my-block` — is spelled out.\n */\nconst LocationSchemePattern = /^(?<scheme>[A-Za-z][A-Za-z0-9+.-]+):/;\n\n/**\n * One block in a template file.\n *\n * `kind` is always required: it carries the params contract the entry is typed against, and\n * whichever of the three routes finds the block, what that block declares is checked against\n * it — so params written for one contract cannot reach an implementation of another.\n *\n * A file may omit `params`, which is terseness and not an escape from the contract: the parser\n * reads the omission as `{}`, so an entry that leaves it out still fails for a kind whose\n * contract has required fields. Past the parser there is only one spelling, and no reader has\n * to normalize. There is no `label` field: a template\n * does not name block instances for display.\n *\n * An entry may also carry one locator override — see {@link BlockPackLocatorOverride} for\n * what each answers. Either one is resolved on its own and kind resolution is skipped\n * entirely; carrying both would state two different things with no way to reconcile them, so\n * the type admits at most one.\n */\nexport type ProjectTemplateV1Entry = {\n /**\n * Template-local identifier, unique within the file. Names the entry for\n * inter-block references; on export it is the block's project-local UUID,\n * reused verbatim.\n */\n readonly id: string;\n readonly kind: BlockKindSelectorReference;\n /**\n * The block's `BlockParams` instance, exactly as the block projected it — opaque here\n * and typed by the kind. Always present: an entry whose file omitted it parses as `{}`.\n *\n * **Nothing here looks inside.** Not for a reference, not for a marker: values travel from\n * the block that projected them to the block that receives them verbatim, and which of them\n * carry block ids is recognized in the receiving block's own bundle. A document layer that\n * recognized a reference would have to model the whole reference system to do it.\n *\n * That is also what lets a hand-written file spell a reference readably. A block stores\n * `{ __isRef: true, blockId, name }` and an export writes that, but a person may write\n * `{ block: <entry id>, name: … }` instead — see `TemplatePlRef`. Both arrive at the block as\n * the same reference; neither is understood here.\n */\n readonly params: Record<string, unknown>;\n} & BlockPackLocatorOverride;\n\n/**\n * The locator override an entry may carry: a version pin, a place, or neither.\n *\n * Two arms rather than two optional fields, so \"not both\" is a property of the type and not\n * only of the parser. Each arm forbids the other's field by typing it `never`, which is what\n * makes `{ block, location }` match neither — and both arms leave their own field optional, so\n * an entry that pins nothing satisfies either.\n *\n * Readers are unaffected: every arm declares both keys, so `entry.block` and `entry.location`\n * stay directly readable without narrowing.\n */\nexport type BlockPackLocatorOverride =\n | {\n /**\n * WHICH VERSION to install, leaving it to the environment to decide which registry\n * serves it — so an entry pinned this way stays portable.\n *\n * Exact only, `{name}@X.Y.Z` (see {@link BlockPackReference}): the override exists to\n * pin one implementation, and a range would defeat that. Export never writes it, because\n * it already records the exact version the block implements, leaving a pin nothing to\n * add — so this is a hand-written field.\n */\n readonly block?: BlockPackReference;\n /** Excluded: this arm is the version pin. */\n readonly location?: never;\n }\n | {\n /** Excluded: this arm is the place. */\n readonly block?: never;\n /**\n * WHICH PLACE to install from, as an absolute URI (see\n * {@link BlockPackLocationReference}).\n *\n * Names a concrete, possibly unpublished implementation, and is therefore only\n * meaningful where that place exists: a `file:` locator written on one machine says\n * nothing on another. That is the trade it makes — it is the only answer for a block\n * that is built but not published, which no registry can find and no kind can resolve\n * to. Export writes it for every block installed from the filesystem, since omitting it\n * would describe a project that cannot be recreated at all.\n */\n readonly location?: BlockPackLocationReference;\n };\n\n/**\n * A `template-v1` document — the primitive form of a template.\n *\n * `blocks` order is the instantiation order, so every entry must appear after\n * the entries it references. This type is the shared contract for both\n * directions of the round trip: export emits exactly this, import parses\n * exactly this.\n *\n * Scope note: this package owns the *document*, i.e. the shape of the value a\n * YAML (or JSON) reader hands back. The text layer stays out on purpose —\n * pl-model-common is in every block-model and UI bundle and takes no `yaml`\n * dependency; serializing to YAML bytes belongs with the caller that already\n * has one (pl-middle-layer).\n */\nexport type ProjectTemplateV1 = {\n readonly schema: ProjectTemplateSchemaV1;\n readonly blocks: readonly ProjectTemplateV1Entry[];\n};\n\n//\n// Reading a decoded document.\n//\n// Hand-written rather than schema-driven, for what a reader of a hand-written file gets out\n// of it. A template is a file a person edits, so the parser's output is a bug report: every\n// problem at once, each located the way the file is written, worded as the edit to make. That\n// means owning the wording, which a schema library gives away — and the values here need\n// checks a schema cannot express anyway (the reference grammars are functions, and the locator\n// exclusion is a rule about two fields), so the schema was carrying the trivial half while the\n// interesting half sat in refinements beside it.\n//\n\n/** One thing wrong with a document, and where in it. */\nexport type TemplateParseIssue = {\n /** Location in the decoded value: `[\"blocks\", 2, \"kind\"]`. */\n readonly path: readonly (string | number)[];\n /** What is wrong, worded for whoever is editing the file. */\n readonly message: string;\n};\n\n/**\n * One issue as a line: `blocks[2].kind: Expected a kind reference, got nothing.`\n *\n * Indexes read as they are written in the file — `blocks[2]`, not `blocks.2` — so the place\n * can be found by reading rather than by counting.\n */\nexport function formatTemplateParseIssue(issue: TemplateParseIssue): string {\n const path = issue.path.reduce<string>(\n (acc, segment) =>\n typeof segment === \"number\"\n ? `${acc}[${segment}]`\n : acc === \"\"\n ? segment\n : `${acc}.${segment}`,\n \"\",\n );\n return path === \"\" ? issue.message : `${path}: ${issue.message}`;\n}\n\n/**\n * Every problem a document has, thrown once so a caller fixes the file in one pass.\n *\n * The issues are in `message` as well as on `issues`, because a throw that escapes to a log is\n * read as its message and nothing else.\n */\nexport class ProjectTemplateV1ParseError extends Error {\n constructor(readonly issues: readonly TemplateParseIssue[]) {\n super(\n [\n `The template document could not be read (${issues.length} problem(s)):`,\n ...issues.map((issue) => `- ${formatTemplateParseIssue(issue)}`),\n ].join(\"\\n\"),\n );\n this.name = \"ProjectTemplateV1ParseError\";\n }\n}\n\n/** A document, or everything wrong with the value that was supposed to be one. */\nexport type ProjectTemplateV1ReadResult =\n | { readonly ok: true; readonly document: ProjectTemplateV1 }\n | { readonly ok: false; readonly issues: readonly TemplateParseIssue[] };\n\nconst isMapping = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\n/** Keys an entry may carry. Anything else is a mistake, not an extension point. */\nconst ENTRY_KEYS = [\"id\", \"kind\", \"block\", \"location\", \"params\"] as const;\n\n/**\n * Read an already-decoded template document — the value a YAML or JSON reader returns.\n *\n * Checks the format marker, every entry's shape, the reference grammars and id uniqueness,\n * and settles an omitted `params` to `{}`. Unknown keys are refused rather than ignored: a\n * misspelled key that was silently dropped would apply a file that does not say what its\n * author meant.\n *\n * It does NOT check what an entry's params point at, and nothing downstream of it does\n * either. Which values in there carry block ids is knowable only to the block, in its own\n * bundle, where the params are relocated onto the project being built — so a reference to an\n * entry listed later, or to the entry holding it, is not refused here. It survives into the\n * applied project as a block whose references name nothing, which is how a reference to a\n * deleted block already behaves.\n *\n * Collects rather than stops: a file with three mistakes should take one pass to fix.\n */\nexport function readProjectTemplateV1(value: unknown): ProjectTemplateV1ReadResult {\n const issues: TemplateParseIssue[] = [];\n const fail = (path: readonly (string | number)[], message: string) =>\n issues.push({ path, message });\n\n if (!isMapping(value)) {\n return {\n ok: false,\n issues: [{ path: [], message: \"A template must be a mapping with 'schema' and 'blocks'.\" }],\n };\n }\n\n for (const key of Object.keys(value)) {\n if (key !== \"schema\" && key !== \"blocks\") fail([], `Unrecognized key: '${key}'`);\n }\n\n if (value.schema !== PROJECT_TEMPLATE_SCHEMA_V1) {\n fail(\n [\"schema\"],\n `Expected '${PROJECT_TEMPLATE_SCHEMA_V1}', got ${describe(value.schema)}. This is the ` +\n `format marker every template opens with.`,\n );\n }\n\n if (!Array.isArray(value.blocks)) {\n fail([\"blocks\"], `Expected a list of entries, got ${describe(value.blocks)}.`);\n return { ok: false, issues };\n }\n\n const blocks: ProjectTemplateV1Entry[] = [];\n const seen = new Set<string>();\n\n value.blocks.forEach((raw, i) => {\n const entry = readEntry(raw, [\"blocks\", i], fail);\n if (entry === undefined) return;\n if (seen.has(entry.id)) fail([\"blocks\", i, \"id\"], `Duplicate template-local id: ${entry.id}`);\n seen.add(entry.id);\n blocks.push(entry);\n });\n\n if (issues.length > 0) return { ok: false, issues };\n return { ok: true, document: { schema: PROJECT_TEMPLATE_SCHEMA_V1, blocks } };\n}\n\n/**\n * One entry, or `undefined` when it is not even a mapping — in which case its own fields are\n * not reported on top, since a reader given \"this entry is not a mapping\" does not also need\n * to hear that its `id` is missing.\n */\nfunction readEntry(\n raw: unknown,\n at: readonly (string | number)[],\n fail: (path: readonly (string | number)[], message: string) => void,\n): ProjectTemplateV1Entry | undefined {\n if (!isMapping(raw)) {\n fail(at, `Expected an entry mapping, got ${describe(raw)}.`);\n return undefined;\n }\n\n for (const key of Object.keys(raw)) {\n if (!(ENTRY_KEYS as readonly string[]).includes(key)) {\n fail(at, `Unrecognized key: '${key}'`);\n }\n }\n\n let ok = true;\n\n if (typeof raw.id !== \"string\" || raw.id.length === 0) {\n fail([...at, \"id\"], `Expected a non-empty id, got ${describe(raw.id)}.`);\n ok = false;\n }\n\n if (typeof raw.kind !== \"string\") {\n fail([...at, \"kind\"], `Expected a kind reference, got ${describe(raw.kind)}.`);\n ok = false;\n } else {\n // The grammars are functions, and their messages already name the fix, so they are\n // reported as they come rather than restated.\n ok = check([...at, \"kind\"], () => parseKindSelectorReference(raw.kind as never), fail) && ok;\n }\n\n if (raw.block !== undefined) {\n if (typeof raw.block !== \"string\") {\n fail([...at, \"block\"], `Expected a block package reference, got ${describe(raw.block)}.`);\n ok = false;\n } else {\n ok = check([...at, \"block\"], () => parseBlockPackReference(raw.block as never), fail) && ok;\n }\n }\n\n if (raw.location !== undefined) {\n if (typeof raw.location !== \"string\") {\n fail([...at, \"location\"], `Expected a locator URI, got ${describe(raw.location)}.`);\n ok = false;\n } else {\n ok =\n check([...at, \"location\"], () => parseBlockPackLocation(raw.location as never), fail) && ok;\n }\n }\n\n if (raw.block !== undefined && raw.location !== undefined) {\n fail(\n [...at, \"location\"],\n `An entry cannot carry both 'block' and 'location': the first pins which version to ` +\n `install, the second pins where to install it from. Keep the one that is actually meant.`,\n );\n ok = false;\n }\n\n if (raw.params !== undefined && !isMapping(raw.params)) {\n fail([...at, \"params\"], `Expected a mapping of params, got ${describe(raw.params)}.`);\n ok = false;\n }\n\n if (!ok) return undefined;\n\n return {\n id: raw.id as string,\n kind: raw.kind as BlockKindSelectorReference,\n ...(raw.block !== undefined ? { block: raw.block as BlockPackReference } : {}),\n ...(raw.location !== undefined ? { location: raw.location as BlockPackLocationReference } : {}),\n // Omissible in the file, settled here: every reader downstream gets a mapping.\n params: (raw.params ?? {}) as Record<string, unknown>,\n } as ProjectTemplateV1Entry;\n}\n\n/** Run a grammar check, turning its throw into an issue at `path`. */\nfunction check(\n path: readonly (string | number)[],\n grammar: () => unknown,\n fail: (path: readonly (string | number)[], message: string) => void,\n): boolean {\n try {\n grammar();\n return true;\n } catch (e) {\n fail(path, e instanceof Error ? e.message : String(e));\n return false;\n }\n}\n\n/** A value named the way an error message should name it, without printing its contents. */\nfunction describe(value: unknown): string {\n if (value === undefined) return \"nothing\";\n if (value === null) return \"null\";\n if (Array.isArray(value)) return \"a list\";\n if (typeof value === \"string\") return `'${value}'`;\n if (typeof value === \"object\") return \"a mapping\";\n return String(value);\n}\n\n/**\n * {@link readProjectTemplateV1} for a caller that treats an unreadable document as\n * exceptional — export, which asserts on every run that what it wrote can be read back.\n *\n * @throws {ProjectTemplateV1ParseError} carrying every problem found\n */\nexport function parseProjectTemplateV1(value: unknown): ProjectTemplateV1 {\n const outcome = readProjectTemplateV1(value);\n if (!outcome.ok) throw new ProjectTemplateV1ParseError(outcome.issues);\n return outcome.document;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { BlockKindSelectorReference } from "./kind_selector.js";
|
|
2
|
+
import { Branded } from "@milaboratories/helpers";
|
|
3
|
+
|
|
4
|
+
//#region src/template/project_template_v1.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Value of a template file's `schema` field — the format marker every
|
|
7
|
+
* `template-v1` document opens with.
|
|
8
|
+
*/
|
|
9
|
+
declare const PROJECT_TEMPLATE_SCHEMA_V1 = "template-v1";
|
|
10
|
+
type ProjectTemplateSchemaV1 = typeof PROJECT_TEMPLATE_SCHEMA_V1;
|
|
11
|
+
/**
|
|
12
|
+
* On-wire reference to one exact block package version, `{name}@X.Y.Z`.
|
|
13
|
+
*
|
|
14
|
+
* The `block` override's value type. Exact only — the override exists to pin an
|
|
15
|
+
* implementation, so a range would defeat it. Mapping this to the structured
|
|
16
|
+
* `BlockPackId` (`{ organization, name, version }`) is import-side work; the
|
|
17
|
+
* organization lives inside the npm scope here, as it does for kind names.
|
|
18
|
+
*/
|
|
19
|
+
type BlockPackReference = Branded<string, "BlockPackReference">;
|
|
20
|
+
/**
|
|
21
|
+
* Split a {@link BlockPackReference} into `{ name, version }`.
|
|
22
|
+
*
|
|
23
|
+
* @throws if the reference carries no version segment or the version is not
|
|
24
|
+
* exactly `X.Y.Z`
|
|
25
|
+
*/
|
|
26
|
+
declare function parseBlockPackReference(ref: BlockPackReference): {
|
|
27
|
+
name: string;
|
|
28
|
+
version: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* On-wire locator naming WHERE one entry's block implementation comes from, as an
|
|
32
|
+
* absolute URI: `file:///abs/path/to/block`.
|
|
33
|
+
*
|
|
34
|
+
* The third way an entry can reach an implementation, and the only one that names a
|
|
35
|
+
* place rather than a name. It exists for a block that is built but not published —
|
|
36
|
+
* the implementation lives in a folder and no registry knows it, so neither `kind`
|
|
37
|
+
* resolution nor a `block` version pin can find it.
|
|
38
|
+
*
|
|
39
|
+
* A URI rather than a bare path because the question "where" is not limited to the
|
|
40
|
+
* filesystem, and because scheme dispatch is how the rest of the toolchain already
|
|
41
|
+
* answers it. Which schemes an environment can actually serve is that environment's
|
|
42
|
+
* business: this type fixes only the grammar, so a document remains readable by a
|
|
43
|
+
* consumer that cannot fetch every scheme.
|
|
44
|
+
*/
|
|
45
|
+
type BlockPackLocationReference = Branded<string, "BlockPackLocationReference">;
|
|
46
|
+
/**
|
|
47
|
+
* Read the scheme off a {@link BlockPackLocationReference}, which is all the
|
|
48
|
+
* document layer knows about it — resolving the rest belongs to whoever can reach
|
|
49
|
+
* the scheme.
|
|
50
|
+
*
|
|
51
|
+
* A scheme is required. Accepting a bare path would mean reading it relative to
|
|
52
|
+
* whatever directory the application happens to have been started from, which is
|
|
53
|
+
* exactly the ambiguity a locator exists to remove.
|
|
54
|
+
*
|
|
55
|
+
* @throws if the value carries no scheme
|
|
56
|
+
*/
|
|
57
|
+
declare function parseBlockPackLocation(ref: BlockPackLocationReference): {
|
|
58
|
+
scheme: string;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* One block in a template file.
|
|
62
|
+
*
|
|
63
|
+
* `kind` is always required: it carries the params contract the entry is typed against, and
|
|
64
|
+
* whichever of the three routes finds the block, what that block declares is checked against
|
|
65
|
+
* it — so params written for one contract cannot reach an implementation of another.
|
|
66
|
+
*
|
|
67
|
+
* A file may omit `params`, which is terseness and not an escape from the contract: the parser
|
|
68
|
+
* reads the omission as `{}`, so an entry that leaves it out still fails for a kind whose
|
|
69
|
+
* contract has required fields. Past the parser there is only one spelling, and no reader has
|
|
70
|
+
* to normalize. There is no `label` field: a template
|
|
71
|
+
* does not name block instances for display.
|
|
72
|
+
*
|
|
73
|
+
* An entry may also carry one locator override — see {@link BlockPackLocatorOverride} for
|
|
74
|
+
* what each answers. Either one is resolved on its own and kind resolution is skipped
|
|
75
|
+
* entirely; carrying both would state two different things with no way to reconcile them, so
|
|
76
|
+
* the type admits at most one.
|
|
77
|
+
*/
|
|
78
|
+
type ProjectTemplateV1Entry = {
|
|
79
|
+
/**
|
|
80
|
+
* Template-local identifier, unique within the file. Names the entry for
|
|
81
|
+
* inter-block references; on export it is the block's project-local UUID,
|
|
82
|
+
* reused verbatim.
|
|
83
|
+
*/
|
|
84
|
+
readonly id: string;
|
|
85
|
+
readonly kind: BlockKindSelectorReference;
|
|
86
|
+
/**
|
|
87
|
+
* The block's `BlockParams` instance, exactly as the block projected it — opaque here
|
|
88
|
+
* and typed by the kind. Always present: an entry whose file omitted it parses as `{}`.
|
|
89
|
+
*
|
|
90
|
+
* **Nothing here looks inside.** Not for a reference, not for a marker: values travel from
|
|
91
|
+
* the block that projected them to the block that receives them verbatim, and which of them
|
|
92
|
+
* carry block ids is recognized in the receiving block's own bundle. A document layer that
|
|
93
|
+
* recognized a reference would have to model the whole reference system to do it.
|
|
94
|
+
*
|
|
95
|
+
* That is also what lets a hand-written file spell a reference readably. A block stores
|
|
96
|
+
* `{ __isRef: true, blockId, name }` and an export writes that, but a person may write
|
|
97
|
+
* `{ block: <entry id>, name: … }` instead — see `TemplatePlRef`. Both arrive at the block as
|
|
98
|
+
* the same reference; neither is understood here.
|
|
99
|
+
*/
|
|
100
|
+
readonly params: Record<string, unknown>;
|
|
101
|
+
} & BlockPackLocatorOverride;
|
|
102
|
+
/**
|
|
103
|
+
* The locator override an entry may carry: a version pin, a place, or neither.
|
|
104
|
+
*
|
|
105
|
+
* Two arms rather than two optional fields, so "not both" is a property of the type and not
|
|
106
|
+
* only of the parser. Each arm forbids the other's field by typing it `never`, which is what
|
|
107
|
+
* makes `{ block, location }` match neither — and both arms leave their own field optional, so
|
|
108
|
+
* an entry that pins nothing satisfies either.
|
|
109
|
+
*
|
|
110
|
+
* Readers are unaffected: every arm declares both keys, so `entry.block` and `entry.location`
|
|
111
|
+
* stay directly readable without narrowing.
|
|
112
|
+
*/
|
|
113
|
+
type BlockPackLocatorOverride = {
|
|
114
|
+
/**
|
|
115
|
+
* WHICH VERSION to install, leaving it to the environment to decide which registry
|
|
116
|
+
* serves it — so an entry pinned this way stays portable.
|
|
117
|
+
*
|
|
118
|
+
* Exact only, `{name}@X.Y.Z` (see {@link BlockPackReference}): the override exists to
|
|
119
|
+
* pin one implementation, and a range would defeat that. Export never writes it, because
|
|
120
|
+
* it already records the exact version the block implements, leaving a pin nothing to
|
|
121
|
+
* add — so this is a hand-written field.
|
|
122
|
+
*/
|
|
123
|
+
readonly block?: BlockPackReference; /** Excluded: this arm is the version pin. */
|
|
124
|
+
readonly location?: never;
|
|
125
|
+
} | {
|
|
126
|
+
/** Excluded: this arm is the place. */readonly block?: never;
|
|
127
|
+
/**
|
|
128
|
+
* WHICH PLACE to install from, as an absolute URI (see
|
|
129
|
+
* {@link BlockPackLocationReference}).
|
|
130
|
+
*
|
|
131
|
+
* Names a concrete, possibly unpublished implementation, and is therefore only
|
|
132
|
+
* meaningful where that place exists: a `file:` locator written on one machine says
|
|
133
|
+
* nothing on another. That is the trade it makes — it is the only answer for a block
|
|
134
|
+
* that is built but not published, which no registry can find and no kind can resolve
|
|
135
|
+
* to. Export writes it for every block installed from the filesystem, since omitting it
|
|
136
|
+
* would describe a project that cannot be recreated at all.
|
|
137
|
+
*/
|
|
138
|
+
readonly location?: BlockPackLocationReference;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* A `template-v1` document — the primitive form of a template.
|
|
142
|
+
*
|
|
143
|
+
* `blocks` order is the instantiation order, so every entry must appear after
|
|
144
|
+
* the entries it references. This type is the shared contract for both
|
|
145
|
+
* directions of the round trip: export emits exactly this, import parses
|
|
146
|
+
* exactly this.
|
|
147
|
+
*
|
|
148
|
+
* Scope note: this package owns the *document*, i.e. the shape of the value a
|
|
149
|
+
* YAML (or JSON) reader hands back. The text layer stays out on purpose —
|
|
150
|
+
* pl-model-common is in every block-model and UI bundle and takes no `yaml`
|
|
151
|
+
* dependency; serializing to YAML bytes belongs with the caller that already
|
|
152
|
+
* has one (pl-middle-layer).
|
|
153
|
+
*/
|
|
154
|
+
type ProjectTemplateV1 = {
|
|
155
|
+
readonly schema: ProjectTemplateSchemaV1;
|
|
156
|
+
readonly blocks: readonly ProjectTemplateV1Entry[];
|
|
157
|
+
};
|
|
158
|
+
/** One thing wrong with a document, and where in it. */
|
|
159
|
+
type TemplateParseIssue = {
|
|
160
|
+
/** Location in the decoded value: `["blocks", 2, "kind"]`. */readonly path: readonly (string | number)[]; /** What is wrong, worded for whoever is editing the file. */
|
|
161
|
+
readonly message: string;
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* One issue as a line: `blocks[2].kind: Expected a kind reference, got nothing.`
|
|
165
|
+
*
|
|
166
|
+
* Indexes read as they are written in the file — `blocks[2]`, not `blocks.2` — so the place
|
|
167
|
+
* can be found by reading rather than by counting.
|
|
168
|
+
*/
|
|
169
|
+
declare function formatTemplateParseIssue(issue: TemplateParseIssue): string;
|
|
170
|
+
/**
|
|
171
|
+
* Every problem a document has, thrown once so a caller fixes the file in one pass.
|
|
172
|
+
*
|
|
173
|
+
* The issues are in `message` as well as on `issues`, because a throw that escapes to a log is
|
|
174
|
+
* read as its message and nothing else.
|
|
175
|
+
*/
|
|
176
|
+
declare class ProjectTemplateV1ParseError extends Error {
|
|
177
|
+
readonly issues: readonly TemplateParseIssue[];
|
|
178
|
+
constructor(issues: readonly TemplateParseIssue[]);
|
|
179
|
+
}
|
|
180
|
+
/** A document, or everything wrong with the value that was supposed to be one. */
|
|
181
|
+
type ProjectTemplateV1ReadResult = {
|
|
182
|
+
readonly ok: true;
|
|
183
|
+
readonly document: ProjectTemplateV1;
|
|
184
|
+
} | {
|
|
185
|
+
readonly ok: false;
|
|
186
|
+
readonly issues: readonly TemplateParseIssue[];
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* Read an already-decoded template document — the value a YAML or JSON reader returns.
|
|
190
|
+
*
|
|
191
|
+
* Checks the format marker, every entry's shape, the reference grammars and id uniqueness,
|
|
192
|
+
* and settles an omitted `params` to `{}`. Unknown keys are refused rather than ignored: a
|
|
193
|
+
* misspelled key that was silently dropped would apply a file that does not say what its
|
|
194
|
+
* author meant.
|
|
195
|
+
*
|
|
196
|
+
* It does NOT check what an entry's params point at, and nothing downstream of it does
|
|
197
|
+
* either. Which values in there carry block ids is knowable only to the block, in its own
|
|
198
|
+
* bundle, where the params are relocated onto the project being built — so a reference to an
|
|
199
|
+
* entry listed later, or to the entry holding it, is not refused here. It survives into the
|
|
200
|
+
* applied project as a block whose references name nothing, which is how a reference to a
|
|
201
|
+
* deleted block already behaves.
|
|
202
|
+
*
|
|
203
|
+
* Collects rather than stops: a file with three mistakes should take one pass to fix.
|
|
204
|
+
*/
|
|
205
|
+
declare function readProjectTemplateV1(value: unknown): ProjectTemplateV1ReadResult;
|
|
206
|
+
/**
|
|
207
|
+
* {@link readProjectTemplateV1} for a caller that treats an unreadable document as
|
|
208
|
+
* exceptional — export, which asserts on every run that what it wrote can be read back.
|
|
209
|
+
*
|
|
210
|
+
* @throws {ProjectTemplateV1ParseError} carrying every problem found
|
|
211
|
+
*/
|
|
212
|
+
declare function parseProjectTemplateV1(value: unknown): ProjectTemplateV1;
|
|
213
|
+
//#endregion
|
|
214
|
+
export { BlockPackLocationReference, BlockPackLocatorOverride, BlockPackReference, PROJECT_TEMPLATE_SCHEMA_V1, ProjectTemplateSchemaV1, ProjectTemplateV1, ProjectTemplateV1Entry, ProjectTemplateV1ParseError, ProjectTemplateV1ReadResult, TemplateParseIssue, formatTemplateParseIssue, parseBlockPackLocation, parseBlockPackReference, parseProjectTemplateV1, readProjectTemplateV1 };
|
|
215
|
+
//# sourceMappingURL=project_template_v1.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project_template_v1.d.ts","names":[],"sources":["../../src/template/project_template_v1.ts"],"mappings":";;;;;;AASA;;cAAa,0BAAA;AAAA,KACD,uBAAA,UAAiC,0BAA0B;AADhC;AACvC;;;;AAAuE;AAUvE;;AAXuC,KAW3B,kBAAA,GAAqB,OAAO;;AAAA;AAQxC;;;;iBAAgB,uBAAA,CAAwB,GAAA,EAAK,kBAAkB;EAC7D,IAAA;EACA,OAAA;AAAA;;AAAO;AA2BT;;;;AAAgD;AAahD;;;;;;;;KAbY,0BAAA,GAA6B,OAAO;AAqDhD;;;;;;;;;;;AAAA,iBAxCgB,sBAAA,CAAuB,GAAA,EAAK,0BAA0B;EAAK,MAAA;AAAA;;AA+D/C;AAa5B;;;;;;;;;;;AA6BoD;AAiBpD;;;;KAlFY,sBAAA;EAmFO;;;;AAC+B;EAD/B,SA7ER,EAAA;EAAA,SACA,IAAA,EAAM,0BAAA;;;AAiGC;AASlB;;;;AAAkE;AAmBlE;;;;;;WA9GW,MAAA,EAAQ,MAAA;AAAA,IACf,wBAAA;;;;;;;;AA8GwD;AAY5D;;;KA7GY,wBAAA;EA8GG;;;;;;;AACuD;AAyBtE;EA1Be,SAnGA,KAAA,GAAQ,kBAAA;WAER,QAAA;AAAA;EAwRC,gDApRD,KAAA;;;AAoR0D;;;;;;;;;WAxQ1D,QAAA,GAAW,0BAA0B;AAAA;;;;;;;;;;;;;;;KAiBxC,iBAAA;EAAA,SACD,MAAA,EAAQ,uBAAA;EAAA,SACR,MAAA,WAAiB,sBAAsB;AAAA;;KAgBtC,kBAAA;yEAED,IAAA;WAEA,OAAO;AAAA;;;;;;;iBASF,wBAAA,CAAyB,KAAyB,EAAlB,kBAAkB;;;;;;;cAmBrD,2BAAA,SAAoC,KAAA;EAAA,SAC1B,MAAA,WAAiB,kBAAA;cAAjB,MAAA,WAAiB,kBAAA;AAAA;;KAY5B,2BAAA;EAAA,SACG,EAAA;EAAA,SAAmB,QAAA,EAAU,iBAAA;AAAA;EAAA,SAC7B,EAAA;EAAA,SAAoB,MAAA,WAAiB,kBAAkB;AAAA;;;;;;;;;;;;;;;;;;iBAyBtD,qBAAA,CAAsB,KAAA,YAAiB,2BAA2B;;;;;;;iBA6JlE,sBAAA,CAAuB,KAAA,YAAiB,iBAAiB"}
|