wingfoil 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +334 -0
- package/dist/cli/error.d.ts +11 -0
- package/dist/cli/error.d.ts.map +1 -0
- package/dist/cli/error.js +27 -0
- package/dist/cli/error.js.map +1 -0
- package/dist/cli/exit.d.ts +19 -0
- package/dist/cli/exit.d.ts.map +1 -0
- package/dist/cli/exit.js +14 -0
- package/dist/cli/exit.js.map +1 -0
- package/dist/cli/index.d.ts +28 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +36 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-command.d.ts +34 -0
- package/dist/cli/init-command.d.ts.map +1 -0
- package/dist/cli/init-command.js +100 -0
- package/dist/cli/init-command.js.map +1 -0
- package/dist/cli/mcp-command.d.ts +24 -0
- package/dist/cli/mcp-command.d.ts.map +1 -0
- package/dist/cli/mcp-command.js +42 -0
- package/dist/cli/mcp-command.js.map +1 -0
- package/dist/cli/output.d.ts +13 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +28 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/program.d.ts +12 -0
- package/dist/cli/program.d.ts.map +1 -0
- package/dist/cli/program.js +279 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/registrar.d.ts +69 -0
- package/dist/cli/registrar.d.ts.map +1 -0
- package/dist/cli/registrar.js +82 -0
- package/dist/cli/registrar.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +45 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/approval-authority.d.ts +83 -0
- package/dist/core/approval-authority.d.ts.map +1 -0
- package/dist/core/approval-authority.js +112 -0
- package/dist/core/approval-authority.js.map +1 -0
- package/dist/core/builtin-asset.d.ts +71 -0
- package/dist/core/builtin-asset.d.ts.map +1 -0
- package/dist/core/builtin-asset.js +137 -0
- package/dist/core/builtin-asset.js.map +1 -0
- package/dist/core/builtin-integrity.d.ts +32 -0
- package/dist/core/builtin-integrity.d.ts.map +1 -0
- package/dist/core/builtin-integrity.js +148 -0
- package/dist/core/builtin-integrity.js.map +1 -0
- package/dist/core/confinement.d.ts +57 -0
- package/dist/core/confinement.d.ts.map +1 -0
- package/dist/core/confinement.js +108 -0
- package/dist/core/confinement.js.map +1 -0
- package/dist/core/context.d.ts +187 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +192 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/directive-assign.d.ts +131 -0
- package/dist/core/directive-assign.d.ts.map +1 -0
- package/dist/core/directive-assign.js +352 -0
- package/dist/core/directive-assign.js.map +1 -0
- package/dist/core/directives-list.d.ts +80 -0
- package/dist/core/directives-list.d.ts.map +1 -0
- package/dist/core/directives-list.js +148 -0
- package/dist/core/directives-list.js.map +1 -0
- package/dist/core/exit-code.d.ts +85 -0
- package/dist/core/exit-code.d.ts.map +1 -0
- package/dist/core/exit-code.js +163 -0
- package/dist/core/exit-code.js.map +1 -0
- package/dist/core/git-identity.d.ts +32 -0
- package/dist/core/git-identity.d.ts.map +1 -0
- package/dist/core/git-identity.js +72 -0
- package/dist/core/git-identity.js.map +1 -0
- package/dist/core/index.d.ts +388 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +1331 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/init.d.ts +78 -0
- package/dist/core/init.d.ts.map +1 -0
- package/dist/core/init.js +167 -0
- package/dist/core/init.js.map +1 -0
- package/dist/core/loaders.d.ts +174 -0
- package/dist/core/loaders.d.ts.map +1 -0
- package/dist/core/loaders.js +364 -0
- package/dist/core/loaders.js.map +1 -0
- package/dist/core/memory-add-type.d.ts +43 -0
- package/dist/core/memory-add-type.d.ts.map +1 -0
- package/dist/core/memory-add-type.js +151 -0
- package/dist/core/memory-add-type.js.map +1 -0
- package/dist/core/memory-transition.d.ts +111 -0
- package/dist/core/memory-transition.d.ts.map +1 -0
- package/dist/core/memory-transition.js +269 -0
- package/dist/core/memory-transition.js.map +1 -0
- package/dist/core/registry.d.ts +189 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +66 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/relevance.d.ts +86 -0
- package/dist/core/relevance.d.ts.map +1 -0
- package/dist/core/relevance.js +258 -0
- package/dist/core/relevance.js.map +1 -0
- package/dist/core/require-reason.d.ts +27 -0
- package/dist/core/require-reason.d.ts.map +1 -0
- package/dist/core/require-reason.js +95 -0
- package/dist/core/require-reason.js.map +1 -0
- package/dist/core/types.d.ts +45 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +22 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/usage-error.d.ts +20 -0
- package/dist/core/usage-error.d.ts.map +1 -0
- package/dist/core/usage-error.js +29 -0
- package/dist/core/usage-error.js.map +1 -0
- package/dist/core/write-guard.d.ts +99 -0
- package/dist/core/write-guard.d.ts.map +1 -0
- package/dist/core/write-guard.js +247 -0
- package/dist/core/write-guard.js.map +1 -0
- package/dist/directives/create.d.ts +47 -0
- package/dist/directives/create.d.ts.map +1 -0
- package/dist/directives/create.js +82 -0
- package/dist/directives/create.js.map +1 -0
- package/dist/directives/index.d.ts +20 -0
- package/dist/directives/index.d.ts.map +1 -0
- package/dist/directives/index.js +32 -0
- package/dist/directives/index.js.map +1 -0
- package/dist/directives/roles-edit.d.ts +53 -0
- package/dist/directives/roles-edit.d.ts.map +1 -0
- package/dist/directives/roles-edit.js +286 -0
- package/dist/directives/roles-edit.js.map +1 -0
- package/dist/directives/schema.d.ts +65 -0
- package/dist/directives/schema.d.ts.map +1 -0
- package/dist/directives/schema.js +68 -0
- package/dist/directives/schema.js.map +1 -0
- package/dist/dna/edit.d.ts +61 -0
- package/dist/dna/edit.d.ts.map +1 -0
- package/dist/dna/edit.js +429 -0
- package/dist/dna/edit.js.map +1 -0
- package/dist/dna/index.d.ts +24 -0
- package/dist/dna/index.d.ts.map +1 -0
- package/dist/dna/index.js +59 -0
- package/dist/dna/index.js.map +1 -0
- package/dist/dna/mutate.d.ts +74 -0
- package/dist/dna/mutate.d.ts.map +1 -0
- package/dist/dna/mutate.js +318 -0
- package/dist/dna/mutate.js.map +1 -0
- package/dist/dna/path.d.ts +175 -0
- package/dist/dna/path.d.ts.map +1 -0
- package/dist/dna/path.js +289 -0
- package/dist/dna/path.js.map +1 -0
- package/dist/dna/roles.d.ts +57 -0
- package/dist/dna/roles.d.ts.map +1 -0
- package/dist/dna/roles.js +50 -0
- package/dist/dna/roles.js.map +1 -0
- package/dist/dna/schema.d.ts +172 -0
- package/dist/dna/schema.d.ts.map +1 -0
- package/dist/dna/schema.js +182 -0
- package/dist/dna/schema.js.map +1 -0
- package/dist/dna/set.d.ts +145 -0
- package/dist/dna/set.d.ts.map +1 -0
- package/dist/dna/set.js +428 -0
- package/dist/dna/set.js.map +1 -0
- package/dist/mcp/dna-resource.d.ts +16 -0
- package/dist/mcp/dna-resource.d.ts.map +1 -0
- package/dist/mcp/dna-resource.js +56 -0
- package/dist/mcp/dna-resource.js.map +1 -0
- package/dist/mcp/index.d.ts +49 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +60 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/memory-resource.d.ts +17 -0
- package/dist/mcp/memory-resource.d.ts.map +1 -0
- package/dist/mcp/memory-resource.js +133 -0
- package/dist/mcp/memory-resource.js.map +1 -0
- package/dist/mcp/prompt.d.ts +48 -0
- package/dist/mcp/prompt.d.ts.map +1 -0
- package/dist/mcp/prompt.js +176 -0
- package/dist/mcp/prompt.js.map +1 -0
- package/dist/mcp/read-only.d.ts +42 -0
- package/dist/mcp/read-only.d.ts.map +1 -0
- package/dist/mcp/read-only.js +93 -0
- package/dist/mcp/read-only.js.map +1 -0
- package/dist/mcp/registrar.d.ts +54 -0
- package/dist/mcp/registrar.d.ts.map +1 -0
- package/dist/mcp/registrar.js +72 -0
- package/dist/mcp/registrar.js.map +1 -0
- package/dist/mcp/server.d.ts +58 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +64 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/workflow-resource.d.ts +17 -0
- package/dist/mcp/workflow-resource.d.ts.map +1 -0
- package/dist/mcp/workflow-resource.js +63 -0
- package/dist/mcp/workflow-resource.js.map +1 -0
- package/dist/memory/add.d.ts +50 -0
- package/dist/memory/add.d.ts.map +1 -0
- package/dist/memory/add.js +131 -0
- package/dist/memory/add.js.map +1 -0
- package/dist/memory/audit.d.ts +177 -0
- package/dist/memory/audit.d.ts.map +1 -0
- package/dist/memory/audit.js +287 -0
- package/dist/memory/audit.js.map +1 -0
- package/dist/memory/commit-message.d.ts +146 -0
- package/dist/memory/commit-message.d.ts.map +1 -0
- package/dist/memory/commit-message.js +203 -0
- package/dist/memory/commit-message.js.map +1 -0
- package/dist/memory/entry.d.ts +56 -0
- package/dist/memory/entry.d.ts.map +1 -0
- package/dist/memory/entry.js +28 -0
- package/dist/memory/entry.js.map +1 -0
- package/dist/memory/frontmatter-edit.d.ts +68 -0
- package/dist/memory/frontmatter-edit.d.ts.map +1 -0
- package/dist/memory/frontmatter-edit.js +333 -0
- package/dist/memory/frontmatter-edit.js.map +1 -0
- package/dist/memory/git-log.d.ts +32 -0
- package/dist/memory/git-log.d.ts.map +1 -0
- package/dist/memory/git-log.js +100 -0
- package/dist/memory/git-log.js.map +1 -0
- package/dist/memory/history.d.ts +142 -0
- package/dist/memory/history.d.ts.map +1 -0
- package/dist/memory/history.js +250 -0
- package/dist/memory/history.js.map +1 -0
- package/dist/memory/index.d.ts +58 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +107 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/query.d.ts +150 -0
- package/dist/memory/query.d.ts.map +1 -0
- package/dist/memory/query.js +307 -0
- package/dist/memory/query.js.map +1 -0
- package/dist/memory/reject.d.ts +11 -0
- package/dist/memory/reject.d.ts.map +1 -0
- package/dist/memory/reject.js +32 -0
- package/dist/memory/reject.js.map +1 -0
- package/dist/memory/schema.d.ts +104 -0
- package/dist/memory/schema.d.ts.map +1 -0
- package/dist/memory/schema.js +161 -0
- package/dist/memory/schema.js.map +1 -0
- package/dist/memory/state-machine.d.ts +166 -0
- package/dist/memory/state-machine.d.ts.map +1 -0
- package/dist/memory/state-machine.js +431 -0
- package/dist/memory/state-machine.js.map +1 -0
- package/dist/memory/submit.d.ts +11 -0
- package/dist/memory/submit.d.ts.map +1 -0
- package/dist/memory/submit.js +44 -0
- package/dist/memory/submit.js.map +1 -0
- package/dist/storage/builtin-directives.d.ts +54 -0
- package/dist/storage/builtin-directives.d.ts.map +1 -0
- package/dist/storage/builtin-directives.js +152 -0
- package/dist/storage/builtin-directives.js.map +1 -0
- package/dist/storage/commit.d.ts +92 -0
- package/dist/storage/commit.d.ts.map +1 -0
- package/dist/storage/commit.js +201 -0
- package/dist/storage/commit.js.map +1 -0
- package/dist/storage/confinement.d.ts +93 -0
- package/dist/storage/confinement.d.ts.map +1 -0
- package/dist/storage/confinement.js +164 -0
- package/dist/storage/confinement.js.map +1 -0
- package/dist/storage/document.d.ts +27 -0
- package/dist/storage/document.d.ts.map +1 -0
- package/dist/storage/document.js +52 -0
- package/dist/storage/document.js.map +1 -0
- package/dist/storage/errors.d.ts +36 -0
- package/dist/storage/errors.d.ts.map +1 -0
- package/dist/storage/errors.js +46 -0
- package/dist/storage/errors.js.map +1 -0
- package/dist/storage/frontmatter.d.ts +27 -0
- package/dist/storage/frontmatter.d.ts.map +1 -0
- package/dist/storage/frontmatter.js +37 -0
- package/dist/storage/frontmatter.js.map +1 -0
- package/dist/storage/git-root.d.ts +17 -0
- package/dist/storage/git-root.d.ts.map +1 -0
- package/dist/storage/git-root.js +49 -0
- package/dist/storage/git-root.js.map +1 -0
- package/dist/storage/index.d.ts +29 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +66 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/init-state.d.ts +9 -0
- package/dist/storage/init-state.d.ts.map +1 -0
- package/dist/storage/init-state.js +24 -0
- package/dist/storage/init-state.js.map +1 -0
- package/dist/storage/layout.d.ts +51 -0
- package/dist/storage/layout.d.ts.map +1 -0
- package/dist/storage/layout.js +88 -0
- package/dist/storage/layout.js.map +1 -0
- package/dist/storage/memory-path.d.ts +72 -0
- package/dist/storage/memory-path.d.ts.map +1 -0
- package/dist/storage/memory-path.js +127 -0
- package/dist/storage/memory-path.js.map +1 -0
- package/dist/storage/snapshot.d.ts +16 -0
- package/dist/storage/snapshot.d.ts.map +1 -0
- package/dist/storage/snapshot.js +72 -0
- package/dist/storage/snapshot.js.map +1 -0
- package/dist/storage/templates.d.ts +88 -0
- package/dist/storage/templates.d.ts.map +1 -0
- package/dist/storage/templates.js +422 -0
- package/dist/storage/templates.js.map +1 -0
- package/dist/validation/error-mapper.d.ts +16 -0
- package/dist/validation/error-mapper.d.ts.map +1 -0
- package/dist/validation/error-mapper.js +18 -0
- package/dist/validation/error-mapper.js.map +1 -0
- package/dist/validation/errors.d.ts +69 -0
- package/dist/validation/errors.d.ts.map +1 -0
- package/dist/validation/errors.js +69 -0
- package/dist/validation/errors.js.map +1 -0
- package/dist/validation/id.d.ts +16 -0
- package/dist/validation/id.d.ts.map +1 -0
- package/dist/validation/id.js +177 -0
- package/dist/validation/id.js.map +1 -0
- package/dist/validation/index.d.ts +18 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +37 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/secret-scan.d.ts +129 -0
- package/dist/validation/secret-scan.d.ts.map +1 -0
- package/dist/validation/secret-scan.js +367 -0
- package/dist/validation/secret-scan.js.map +1 -0
- package/dist/validation/two-pass.d.ts +24 -0
- package/dist/validation/two-pass.d.ts.map +1 -0
- package/dist/validation/two-pass.js +24 -0
- package/dist/validation/two-pass.js.map +1 -0
- package/dist/validation/warning.d.ts +31 -0
- package/dist/validation/warning.d.ts.map +1 -0
- package/dist/validation/warning.js +81 -0
- package/dist/validation/warning.js.map +1 -0
- package/dist/validation/yaml.d.ts +9 -0
- package/dist/validation/yaml.d.ts.map +1 -0
- package/dist/validation/yaml.js +30 -0
- package/dist/validation/yaml.js.map +1 -0
- package/dist/workflow/index.d.ts +10 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +16 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/schema.d.ts +89 -0
- package/dist/workflow/schema.d.ts.map +1 -0
- package/dist/workflow/schema.js +73 -0
- package/dist/workflow/schema.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyDnaMutation = applyDnaMutation;
|
|
4
|
+
const path_1 = require("./path");
|
|
5
|
+
/** A refusal, in the one shape every branch below returns. */
|
|
6
|
+
function refuse(message) {
|
|
7
|
+
return { ok: false, message };
|
|
8
|
+
}
|
|
9
|
+
/** Deep-clone the document so no branch can leave a half-applied mutation behind on a refusal. */
|
|
10
|
+
function clone(dna) {
|
|
11
|
+
return structuredClone(dna);
|
|
12
|
+
}
|
|
13
|
+
/** Coerce one `--entry-<field>` option string into the shape the entry schema declares for it. */
|
|
14
|
+
function coerce(raw, kind) {
|
|
15
|
+
if (kind === 'string-list')
|
|
16
|
+
return splitList(raw);
|
|
17
|
+
if (kind === 'number') {
|
|
18
|
+
const parsed = Number(raw);
|
|
19
|
+
return Number.isFinite(parsed) ? parsed : raw;
|
|
20
|
+
}
|
|
21
|
+
if (kind === 'boolean') {
|
|
22
|
+
if (raw === 'true')
|
|
23
|
+
return true;
|
|
24
|
+
if (raw === 'false')
|
|
25
|
+
return false;
|
|
26
|
+
return raw;
|
|
27
|
+
}
|
|
28
|
+
return raw;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Split a comma-separated option value — the shape used **only** where the schema declares
|
|
32
|
+
* `z.array(z.string())` (`paths.*`, `team.members[].roles`, `team.agents[].executes_as`). The precedent
|
|
33
|
+
* is `directive assign --directive testing,code-quality` (`task-056-role-based-directive-assignment`),
|
|
34
|
+
* so the CLI has one comma convention rather than two.
|
|
35
|
+
*/
|
|
36
|
+
function splitList(raw) {
|
|
37
|
+
return raw
|
|
38
|
+
.split(',')
|
|
39
|
+
.map((part) => part.trim())
|
|
40
|
+
.filter((part) => part.length > 0);
|
|
41
|
+
}
|
|
42
|
+
/** The text-edit path for a target, with every collection segment replaced by the entry's resolved index. */
|
|
43
|
+
function textPath(dna, target) {
|
|
44
|
+
const steps = [];
|
|
45
|
+
let node = dna;
|
|
46
|
+
for (const segment of target.segments) {
|
|
47
|
+
if (Array.isArray(node)) {
|
|
48
|
+
const index = node.findIndex((entry) => isRecord(entry) && entry.name === segment);
|
|
49
|
+
steps.push({ index });
|
|
50
|
+
node = node[index];
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
steps.push({ key: segment });
|
|
54
|
+
node = isRecord(node) ? node[segment] : undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return steps;
|
|
58
|
+
}
|
|
59
|
+
/** Whether `value` is a plain object (not null, not an array). */
|
|
60
|
+
function isRecord(value) {
|
|
61
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The container a path's last segment lives in.
|
|
65
|
+
*
|
|
66
|
+
* A **declared but absent** object on the way is created — that is what lets
|
|
67
|
+
* `dna set project.license --value MIT` fill an optional section the document omits — and this is deliberately
|
|
68
|
+
* NOT the creation `bug-084` filed: every segment here has already been resolved against the schema by
|
|
69
|
+
* `resolveDnaPath`, so nothing the schema does not declare can reach this function. An existing array is
|
|
70
|
+
* descended into by entry name rather than replaced, which is exactly what the old traversal got wrong.
|
|
71
|
+
*/
|
|
72
|
+
function containerFor(dna, segments) {
|
|
73
|
+
let node = dna;
|
|
74
|
+
for (let i = 0; i < segments.length - 1; i += 1) {
|
|
75
|
+
const segment = segments[i];
|
|
76
|
+
if (Array.isArray(node)) {
|
|
77
|
+
const index = node.findIndex((entry) => isRecord(entry) && entry.name === segment);
|
|
78
|
+
node = node[index];
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const child = node[segment];
|
|
82
|
+
if (Array.isArray(child) || isRecord(child)) {
|
|
83
|
+
node = child;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const created = {};
|
|
87
|
+
node[segment] = created;
|
|
88
|
+
node = created;
|
|
89
|
+
}
|
|
90
|
+
return node;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Read the list at `segments`, or `[]` when the schema declares it and the document omits it — which
|
|
94
|
+
* is how `dna add paths.tests --value test/` fills a category the file leaves out.
|
|
95
|
+
*
|
|
96
|
+
* The container is always a MAPPING: a list is reached through a mapping key, either a section's
|
|
97
|
+
* (`paths.sources`) or an entry's (`team.members.<name>.roles`), never as an element of another list,
|
|
98
|
+
* because the schema declares no list of lists and `resolveDnaPath` refuses one if it ever does.
|
|
99
|
+
*/
|
|
100
|
+
function listAt(dna, target) {
|
|
101
|
+
const container = containerFor(dna, target.segments);
|
|
102
|
+
const key = target.segments[target.segments.length - 1];
|
|
103
|
+
const current = container[key];
|
|
104
|
+
const items = Array.isArray(current) ? current : [];
|
|
105
|
+
container[key] = items;
|
|
106
|
+
return { key, items };
|
|
107
|
+
}
|
|
108
|
+
/** Apply `fields` to `entry`, refusing an option the collection's entry schema does not declare. */
|
|
109
|
+
function applyFields(entry, fields, declared, collectionPath) {
|
|
110
|
+
for (const name of Object.keys(fields)) {
|
|
111
|
+
if (name === 'name') {
|
|
112
|
+
return `'name' is an entry's identity, not a field to update: it is what the path '${collectionPath}.<name>' addresses. Remove the entry and add it under the new name.`;
|
|
113
|
+
}
|
|
114
|
+
const field = declared.find((candidate) => candidate.name === name);
|
|
115
|
+
if (field === undefined) {
|
|
116
|
+
const known = declared.filter((candidate) => candidate.name !== 'name').map((candidate) => `--${(0, path_1.dnaEntryOptionName)(candidate.name)}`);
|
|
117
|
+
return `'--${(0, path_1.dnaEntryOptionName)(name)}' is not a field of '${collectionPath}' entries; they carry ${known.join(', ')}`;
|
|
118
|
+
}
|
|
119
|
+
entry[name] = coerce(fields[name], field.kind);
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Apply one `add`/`remove`/`update` to `dna`, returning the new document and the minimal text edit that
|
|
125
|
+
* expresses it — or a refusal message the caller reports at exit `1` (`spec-005` §1, as ruled on
|
|
126
|
+
* `bug-076`: a well-formed invocation that fails on the content is a logic error, not a usage error).
|
|
127
|
+
*
|
|
128
|
+
* Every refusal names what failed and, where there is one, the verb that would have worked — the whole
|
|
129
|
+
* point of `bug-083`'s repair is that `dna set team.members '[…]'` used to fail with
|
|
130
|
+
* `expected array, received string` from a schema re-validation, which says nothing about how to reach
|
|
131
|
+
* the field.
|
|
132
|
+
*
|
|
133
|
+
* `schemaRoot` is passed straight to `resolveDnaPath` and defaults to `DnaYaml` there — the only schema
|
|
134
|
+
* any caller uses. It is a parameter for the same reason: the semantics below are a function of *a*
|
|
135
|
+
* schema (which field kinds exist, which are required), so they stay exercisable against shapes
|
|
136
|
+
* `spec-002` does not declare today rather than resting on an untested claim.
|
|
137
|
+
*/
|
|
138
|
+
function applyDnaMutation(dna, request, schemaRoot) {
|
|
139
|
+
const resolved = (0, path_1.resolveDnaPath)(dna, request.field, schemaRoot);
|
|
140
|
+
if (!resolved.ok)
|
|
141
|
+
return refuse(resolved.message);
|
|
142
|
+
const target = resolved.target;
|
|
143
|
+
const fields = request.fields ?? {};
|
|
144
|
+
const next = clone(dna);
|
|
145
|
+
switch (target.kind) {
|
|
146
|
+
case 'section':
|
|
147
|
+
return refuse(`'${request.field}' is a section of dna.yaml, not a field: name a field inside it (for example '${request.field}.<field>')`);
|
|
148
|
+
case 'collection':
|
|
149
|
+
return mutateCollection(next, target, request, fields);
|
|
150
|
+
case 'entry':
|
|
151
|
+
return mutateEntry(next, target, request, fields);
|
|
152
|
+
case 'string-list':
|
|
153
|
+
return mutateStringList(next, target, request);
|
|
154
|
+
case 'scalar':
|
|
155
|
+
return mutateScalar(next, target, request);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/** The path ends at an array of objects: `add` creates an entry, `remove` drops one, `update` amends one. */
|
|
159
|
+
function mutateCollection(next, target, request, fields) {
|
|
160
|
+
const name = request.value;
|
|
161
|
+
if (name === undefined || name.length === 0) {
|
|
162
|
+
return refuse(`--value is required at '${target.path}': it names the entry (dl-081: --value is the entry's identity at a collection)`);
|
|
163
|
+
}
|
|
164
|
+
const { items } = listAt(next, target);
|
|
165
|
+
const index = items.findIndex((entry) => isRecord(entry) && entry.name === name);
|
|
166
|
+
const declared = target.entryFields ?? [];
|
|
167
|
+
if (request.verb === 'add') {
|
|
168
|
+
if (index >= 0) {
|
|
169
|
+
return refuse(`'${target.path}' already carries an entry named '${name}' — entry names are unique (dl-081); use \`dna update\` to change it`);
|
|
170
|
+
}
|
|
171
|
+
const entry = { name };
|
|
172
|
+
const failure = applyFields(entry, fields, declared, target.path);
|
|
173
|
+
if (failure !== undefined)
|
|
174
|
+
return refuse(failure);
|
|
175
|
+
const missing = declared
|
|
176
|
+
.filter((field) => field.required && field.name !== 'name' && entry[field.name] === undefined)
|
|
177
|
+
.map((field) => `--${(0, path_1.dnaEntryOptionName)(field.name)}`);
|
|
178
|
+
if (missing.length > 0) {
|
|
179
|
+
return refuse(`an entry of '${target.path}' requires ${missing.join(', ')}`);
|
|
180
|
+
}
|
|
181
|
+
const ordered = orderBySchema(entry, declared);
|
|
182
|
+
items.push(ordered);
|
|
183
|
+
return { ok: true, dna: next, edit: { kind: 'append-items', path: textPath(next, target), items: [ordered] } };
|
|
184
|
+
}
|
|
185
|
+
if (index < 0) {
|
|
186
|
+
return refuse(`no entry named '${name}' in '${target.path}'`);
|
|
187
|
+
}
|
|
188
|
+
if (request.verb === 'remove') {
|
|
189
|
+
items.splice(index, 1);
|
|
190
|
+
return { ok: true, dna: next, edit: { kind: 'remove-items', path: textPath(next, target), indexes: [index] } };
|
|
191
|
+
}
|
|
192
|
+
if (Object.keys(fields).length === 0) {
|
|
193
|
+
const known = declared.filter((field) => field.name !== 'name').map((field) => `--${(0, path_1.dnaEntryOptionName)(field.name)}`);
|
|
194
|
+
return refuse(`\`dna update ${target.path} --value ${name}\` carries no change: pass one of ${known.join(', ')}`);
|
|
195
|
+
}
|
|
196
|
+
const entry = items[index];
|
|
197
|
+
const failure = applyFields(entry, fields, declared, target.path);
|
|
198
|
+
if (failure !== undefined)
|
|
199
|
+
return refuse(failure);
|
|
200
|
+
return { ok: true, dna: next, edit: entryFieldEdit(next, target, index, fields, declared) };
|
|
201
|
+
}
|
|
202
|
+
/** The path ends at one entry (`modules.core`): the path already says which, so `--value` would repeat it. */
|
|
203
|
+
function mutateEntry(next, target, request, fields) {
|
|
204
|
+
const collectionPath = target.collectionPath;
|
|
205
|
+
const name = target.segments[target.segments.length - 1];
|
|
206
|
+
if (request.verb === 'add') {
|
|
207
|
+
return refuse(`'${target.path}' already exists: \`dna add ${collectionPath} --value <name>\` creates a new entry, \`dna update\` changes this one`);
|
|
208
|
+
}
|
|
209
|
+
if (request.value !== undefined) {
|
|
210
|
+
return refuse(`--value says nothing the path '${target.path}' has not already said: drop it, or address the collection with \`${collectionPath} --value ${name}\``);
|
|
211
|
+
}
|
|
212
|
+
// The collection resolved on the way to the entry, so this re-resolution against the clone cannot
|
|
213
|
+
// fail; it is done rather than threaded through because the clone's array is a different object.
|
|
214
|
+
const collection = (0, path_1.resolveDnaPath)(next, collectionPath);
|
|
215
|
+
if (!collection.ok)
|
|
216
|
+
return refuse(collection.message);
|
|
217
|
+
const { items } = listAt(next, collection.target);
|
|
218
|
+
const index = target.entryIndex;
|
|
219
|
+
if (request.verb === 'remove') {
|
|
220
|
+
items.splice(index, 1);
|
|
221
|
+
return { ok: true, dna: next, edit: { kind: 'remove-items', path: textPath(next, collection.target), indexes: [index] } };
|
|
222
|
+
}
|
|
223
|
+
const declared = target.entryFields ?? [];
|
|
224
|
+
if (Object.keys(fields).length === 0) {
|
|
225
|
+
const known = declared.filter((field) => field.name !== 'name').map((field) => `--${(0, path_1.dnaEntryOptionName)(field.name)}`);
|
|
226
|
+
return refuse(`\`dna update ${target.path}\` carries no change: pass one of ${known.join(', ')}`);
|
|
227
|
+
}
|
|
228
|
+
const entry = items[index];
|
|
229
|
+
const failure = applyFields(entry, fields, declared, collectionPath);
|
|
230
|
+
if (failure !== undefined)
|
|
231
|
+
return refuse(failure);
|
|
232
|
+
return { ok: true, dna: next, edit: entryFieldEdit(next, collection.target, index, fields, declared) };
|
|
233
|
+
}
|
|
234
|
+
/** The path ends at an array of strings: `add` appends, `remove` drops, `update` replaces the list. */
|
|
235
|
+
function mutateStringList(next, target, request) {
|
|
236
|
+
if (request.value === undefined) {
|
|
237
|
+
return refuse(`--value is required at '${target.path}'`);
|
|
238
|
+
}
|
|
239
|
+
const values = splitList(request.value);
|
|
240
|
+
if (values.length === 0) {
|
|
241
|
+
return refuse(`--value is required at '${target.path}'`);
|
|
242
|
+
}
|
|
243
|
+
const { items } = listAt(next, target);
|
|
244
|
+
const path = textPath(next, target);
|
|
245
|
+
if (request.verb === 'update') {
|
|
246
|
+
items.splice(0, items.length, ...values);
|
|
247
|
+
return { ok: true, dna: next, edit: { kind: 'replace-list', path, items: values } };
|
|
248
|
+
}
|
|
249
|
+
if (request.verb === 'add') {
|
|
250
|
+
for (const value of values) {
|
|
251
|
+
if (items.includes(value))
|
|
252
|
+
return refuse(`'${target.path}' already contains '${value}'`);
|
|
253
|
+
}
|
|
254
|
+
items.push(...values);
|
|
255
|
+
return { ok: true, dna: next, edit: { kind: 'append-items', path, items: values } };
|
|
256
|
+
}
|
|
257
|
+
const indexes = [];
|
|
258
|
+
for (const value of values) {
|
|
259
|
+
const index = items.indexOf(value);
|
|
260
|
+
if (index < 0)
|
|
261
|
+
return refuse(`'${target.path}' does not contain '${value}'`);
|
|
262
|
+
indexes.push(index);
|
|
263
|
+
}
|
|
264
|
+
const removed = new Set(indexes);
|
|
265
|
+
const kept = items.filter((_item, index) => !removed.has(index));
|
|
266
|
+
items.splice(0, items.length, ...kept);
|
|
267
|
+
return { ok: true, dna: next, edit: { kind: 'remove-items', path, indexes: [...indexes].sort((a, b) => a - b) } };
|
|
268
|
+
}
|
|
269
|
+
/** The path ends at a single value: `update` writes it, `remove` drops it when the schema allows, `add` does not apply. */
|
|
270
|
+
function mutateScalar(next, target, request) {
|
|
271
|
+
const key = target.segments[target.segments.length - 1];
|
|
272
|
+
const container = containerFor(next, target.segments);
|
|
273
|
+
if (request.verb === 'add') {
|
|
274
|
+
return refuse(`'${target.path}' holds a single value: use \`dna update ${target.path} --value <v>\` (or \`dna set ${target.path} --value <v>\`)`);
|
|
275
|
+
}
|
|
276
|
+
if (request.verb === 'remove') {
|
|
277
|
+
if (target.required) {
|
|
278
|
+
return refuse(`'${target.path}' is required by the dna.yaml schema and cannot be removed`);
|
|
279
|
+
}
|
|
280
|
+
if (!(key in container)) {
|
|
281
|
+
return refuse(`'${target.path}' is not set, so there is nothing to remove`);
|
|
282
|
+
}
|
|
283
|
+
delete container[key];
|
|
284
|
+
return { ok: true, dna: next, edit: { kind: 'delete-key', path: textPath(next, target) } };
|
|
285
|
+
}
|
|
286
|
+
if (request.value === undefined) {
|
|
287
|
+
return refuse(`--value is required at '${target.path}'`);
|
|
288
|
+
}
|
|
289
|
+
container[key] = request.value;
|
|
290
|
+
return { ok: true, dna: next, edit: { kind: 'set-scalar', path: textPath(next, target), value: request.value } };
|
|
291
|
+
}
|
|
292
|
+
/** Rewrite an entry's keys into schema order, so the same call always renders the same bytes (REQ-SYS-07). */
|
|
293
|
+
function orderBySchema(entry, declared) {
|
|
294
|
+
const ordered = {};
|
|
295
|
+
for (const field of declared) {
|
|
296
|
+
if (entry[field.name] !== undefined)
|
|
297
|
+
ordered[field.name] = entry[field.name];
|
|
298
|
+
}
|
|
299
|
+
for (const key of Object.keys(entry)) {
|
|
300
|
+
if (ordered[key] === undefined)
|
|
301
|
+
ordered[key] = entry[key];
|
|
302
|
+
}
|
|
303
|
+
return ordered;
|
|
304
|
+
}
|
|
305
|
+
/** One `set-scalar` per changed entry field, batched — the text editor applies them in order. */
|
|
306
|
+
function entryFieldEdit(dna, collection, index, fields, declared) {
|
|
307
|
+
const base = [...textPath(dna, collection), { index }];
|
|
308
|
+
const edits = Object.keys(fields).map((name) => {
|
|
309
|
+
const field = declared.find((candidate) => candidate.name === name);
|
|
310
|
+
return {
|
|
311
|
+
kind: 'set-scalar',
|
|
312
|
+
path: [...base, { key: name }],
|
|
313
|
+
value: coerce(fields[name], field?.kind ?? 'string'),
|
|
314
|
+
};
|
|
315
|
+
});
|
|
316
|
+
return edits.length === 1 ? edits[0] : { kind: 'batch', edits };
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=mutate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutate.js","sourceRoot":"","sources":["../../src/dna/mutate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema-driven DNA path resolution — the single traversal every DNA **write** goes through
|
|
3
|
+
* (`dna set`, and `dna add|remove|update` since task-093-dna-mutation-surface-add-remove-update).
|
|
4
|
+
*
|
|
5
|
+
* It exists because the previous traversal had no notion of the schema at all: `setDnaValue` walked a
|
|
6
|
+
* dotted path treating every segment as an object key and **created** an object for any segment it
|
|
7
|
+
* could not descend into, so `dna set tech_stack.cli.framework Commander` (the then-current spelling,
|
|
8
|
+
* before `dl-082` moved the value into `--value`) wrote `stacks.cli.framework`
|
|
9
|
+
* — a key no schema declares — and committed it at exit `0`
|
|
10
|
+
* (`bug-084-dna-key-alias-writes-unschemad-keys`). `dl-081-dna-mutation-surface-shape`'s ratification
|
|
11
|
+
* makes the repair a **precondition** of the mutation surface rather than a follow-up to it: under
|
|
12
|
+
* add/remove/update semantics one cannot add to a collection that does not exist, so the traversal
|
|
13
|
+
* must be structure-aware and non-creating.
|
|
14
|
+
*
|
|
15
|
+
* The rule it implements, in the ratification's own words: **the DNA pillar accepts unknown keys when
|
|
16
|
+
* reading a document and refuses to write one.** Pass-through on read stays exactly as
|
|
17
|
+
* `spec-002-dna-yaml-schema` declares it (every node is `.passthrough()`, so a file written by a newer
|
|
18
|
+
* WingFoil still loads); it is the write side that is closed.
|
|
19
|
+
*
|
|
20
|
+
* Two further properties this module owns:
|
|
21
|
+
*
|
|
22
|
+
* - **Entries are addressed by `name`, never by index** (`dl-081`, settled in its approve commit).
|
|
23
|
+
* `team.members.roberto.roles` reaches one member's role list; `team.members.2.roles` does not
|
|
24
|
+
* resolve at all, because an index shifts the moment an entry is removed and a path written today
|
|
25
|
+
* would address a different entry tomorrow.
|
|
26
|
+
* - **A path segment may be quoted, and a quoted segment is taken verbatim, dots included**
|
|
27
|
+
* (`dl-083-dotted-entry-names-in-paths`, task-099). `stacks.technologies."Node.js".version`
|
|
28
|
+
* addresses the entry named `Node.js` — a name this repository's own `dna.yaml` carries, along with
|
|
29
|
+
* `Commander.js` and `AI agent (Claude/Cursor/etc.)`, which is why the alternative of forbidding
|
|
30
|
+
* dots in `name` was declined. The grammar lives in `splitDnaPath` (`./set.ts`); this module is one
|
|
31
|
+
* of its three callers and adds nothing to it.
|
|
32
|
+
* - **The schema is the only source of truth.** The traversal reads `DnaYaml` itself (Zod v4 exposes
|
|
33
|
+
* `def.shape` / `def.element` / `def.innerType`, and does so through `.passthrough()` and
|
|
34
|
+
* `.superRefine()` alike), never a hand-written field table, so the write surface cannot drift from
|
|
35
|
+
* the schema it writes as `spec-002` evolves.
|
|
36
|
+
*
|
|
37
|
+
* Pure and deterministic (REQ-SYS-07): no wall-clock, no randomness, no filesystem, and the document
|
|
38
|
+
* it is handed is never mutated — on a refusal as much as on a success.
|
|
39
|
+
*/
|
|
40
|
+
import type { z } from 'zod';
|
|
41
|
+
/**
|
|
42
|
+
* The prefix every schema-derived entry-field option carries: `--entry-<field>`, spelled with the
|
|
43
|
+
* schema's own field name (`--entry-executes_as`, not `--entry-executes-as`).
|
|
44
|
+
*
|
|
45
|
+
* It exists because the option set is **derived** — `dnaEntryOptionNames()` reads `spec-002`'s entry
|
|
46
|
+
* schemas — while the global flags are **declared** (`spec-008` §2), and the two namespaces had no
|
|
47
|
+
* reason to stay disjoint. They did not: `TechEntry` declares `version`, so
|
|
48
|
+
* `dna add stacks.technologies --value Zod --category validation --version 4.0` reached Commander's
|
|
49
|
+
* program-level `-V, --version`, printed the CLI version, exited `0` and wrote nothing, while
|
|
50
|
+
* `--help` advertised the option as working. Measured on a real `wingfoil init` project.
|
|
51
|
+
*
|
|
52
|
+
* **It is not a `version` problem.** Driving a synthetic Commander tree with one subcommand option per
|
|
53
|
+
* global flag shows three distinct outcomes, two of them silent: `--version` fires the program's own
|
|
54
|
+
* action and exits; `--format` and `--verbose` are swallowed by the program-level option and simply
|
|
55
|
+
* do not appear in the subcommand's parsed options; `--color` and a non-colliding name survive. So
|
|
56
|
+
* the failure mode is "the value vanishes", and any future entry field named after any current or
|
|
57
|
+
* future global flag inherits it.
|
|
58
|
+
*
|
|
59
|
+
* **What an unprefixed spelling therefore does, which is two different things.** A name §2 does not
|
|
60
|
+
* declare (`--category`, `--email`) is refused by Commander as an unknown option, exit `1`. A name §2
|
|
61
|
+
* DOES declare — today exactly one, `version`, which is the whole overlap between the derived set and
|
|
62
|
+
* the global set — is consumed by the global instead and is never reported: that is the silent no-op
|
|
63
|
+
* above. `spec-008` §9's option row states both halves, because stating only the first is a claim
|
|
64
|
+
* that is false for the very field the section uses as its example.
|
|
65
|
+
*
|
|
66
|
+
* **Why a prefix rather than refusing to register a shadowing name.** Refusal trades a silent failure
|
|
67
|
+
* for a loud hole: `version` is a field `spec-002` declares on `TechEntry`, so refusing it would make
|
|
68
|
+
* a schema-declared field permanently unwritable, and `dl-081` ratified a surface that reaches every
|
|
69
|
+
* collection. Refusal is also unstable in the wrong direction — the global set can grow (`spec-008`
|
|
70
|
+
* §2 is amendable), and a new global flag would then retroactively disable an entry field that had
|
|
71
|
+
* been writable, breaking scripts with no code change nearby. A prefix removes the collision **by
|
|
72
|
+
* construction**, for every present and future name on both sides, and it is uniform rather than
|
|
73
|
+
* conditional: a rule that prefixed only the colliding names would make an option's spelling depend
|
|
74
|
+
* on a table declared elsewhere, so adding a global flag later would silently RENAME an existing
|
|
75
|
+
* option. `test/cli/derived-option-namespace.test.ts` holds the invariant that keeps this true,
|
|
76
|
+
* derived from the built program rather than from a hand-listed copy of `spec-008` §2.
|
|
77
|
+
*/
|
|
78
|
+
export declare const DNA_ENTRY_OPTION_PREFIX: "entry-";
|
|
79
|
+
/** The CLI/MCP option name carrying one entry field — the single place the prefix is applied. */
|
|
80
|
+
export declare function dnaEntryOptionName(field: string): string;
|
|
81
|
+
/** The entry field an option name carries, or `undefined` when it is not an entry-field option. */
|
|
82
|
+
export declare function dnaEntryFieldOfOption(option: string): string | undefined;
|
|
83
|
+
/** The kind of node a resolved path lands on — what a verb is allowed to do there. */
|
|
84
|
+
export type DnaTargetKind =
|
|
85
|
+
/** An object node (`project`, `team`, `paths`): a section, not a writable field. */
|
|
86
|
+
'section'
|
|
87
|
+
/** A single value (`project.license`, `modules.core.path`, `version`). */
|
|
88
|
+
| 'scalar'
|
|
89
|
+
/** An array of strings (`paths.sources`, `team.members.<name>.roles`). */
|
|
90
|
+
| 'string-list'
|
|
91
|
+
/** An array of objects (`modules`, `team.members`, `stacks.technologies`). */
|
|
92
|
+
| 'collection'
|
|
93
|
+
/** One element of a collection, addressed by its `name`. */
|
|
94
|
+
| 'entry';
|
|
95
|
+
/** The value shape of one field declared on a collection's entry object. */
|
|
96
|
+
export type DnaFieldKind = 'string' | 'number' | 'boolean' | 'string-list' | 'other';
|
|
97
|
+
/** One field a collection's entries may carry, as the schema declares it (used to build the CLI options). */
|
|
98
|
+
export interface DnaEntryField {
|
|
99
|
+
readonly name: string;
|
|
100
|
+
readonly kind: DnaFieldKind;
|
|
101
|
+
readonly required: boolean;
|
|
102
|
+
}
|
|
103
|
+
/** Where a dotted path landed: what kind of node, what is there today, and what may be written into it. */
|
|
104
|
+
export interface DnaPathTarget {
|
|
105
|
+
readonly kind: DnaTargetKind;
|
|
106
|
+
/** The path as given (paths are never rewritten — see {@link DNA_KEY_ALIASES}'s note in `./set.ts`). */
|
|
107
|
+
readonly path: string;
|
|
108
|
+
/**
|
|
109
|
+
* `path` parsed by `splitDnaPath`; for an `entry`, the last segment is the entry's `name`. A quoted
|
|
110
|
+
* segment contributes its name **without** the delimiters and with its dots intact, so
|
|
111
|
+
* `stacks.technologies."Node.js".version` yields four segments, not five (`dl-083`, task-099).
|
|
112
|
+
*/
|
|
113
|
+
readonly segments: readonly string[];
|
|
114
|
+
/** The value in the document at this path, or `undefined` when the node is declared but absent. */
|
|
115
|
+
readonly value: unknown;
|
|
116
|
+
/** Whether the node is actually present in the document (a declared-but-absent node resolves with `false`). */
|
|
117
|
+
readonly exists: boolean;
|
|
118
|
+
/** Whether the schema requires this node (`kind: 'scalar'`/`'string-list'`) — i.e. whether it may be removed. */
|
|
119
|
+
readonly required?: boolean;
|
|
120
|
+
/** The entry's index inside its collection (`kind: 'entry'`). */
|
|
121
|
+
readonly entryIndex?: number;
|
|
122
|
+
/** The fields the entries of this collection may carry, in schema order (`kind: 'collection'` or `'entry'`). */
|
|
123
|
+
readonly entryFields?: readonly DnaEntryField[];
|
|
124
|
+
/** The path of the collection an `entry` belongs to (`kind: 'entry'`). */
|
|
125
|
+
readonly collectionPath?: string;
|
|
126
|
+
}
|
|
127
|
+
/** A resolved target, or the refusal message the caller reports at exit `1` (`spec-005` §1). */
|
|
128
|
+
export type DnaPathResolution = {
|
|
129
|
+
readonly ok: true;
|
|
130
|
+
readonly target: DnaPathTarget;
|
|
131
|
+
} | {
|
|
132
|
+
readonly ok: false;
|
|
133
|
+
readonly message: string;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Resolve `keyPath` against `DnaYaml` and `dna`, reporting what a verb may do at the end of it.
|
|
137
|
+
*
|
|
138
|
+
* Every refusal names the **full** path (so an error message is greppable against the invocation) and
|
|
139
|
+
* the part of it that failed. The four refusal families:
|
|
140
|
+
*
|
|
141
|
+
* - a segment the schema does not declare — `bug-084`, the reason this module exists;
|
|
142
|
+
* - a path that tries to descend through a value or through a list of values;
|
|
143
|
+
* - an index where an entry `name` is expected (`dl-081`: indices are not the addressing form);
|
|
144
|
+
* - an entry `name` the collection does not carry, or carries more than once. The second is
|
|
145
|
+
* unreachable through any CLI/MCP path once `DnaYaml`'s per-collection uniqueness refinement is in
|
|
146
|
+
* force (a duplicate-bearing document no longer loads), and is kept because this function is a pure
|
|
147
|
+
* helper that can be handed any object — including, in a test, one that never went through the
|
|
148
|
+
* loader.
|
|
149
|
+
*
|
|
150
|
+
* A **declared but absent** node is not a refusal: it resolves with `exists: false`, which is what lets
|
|
151
|
+
* `dna set project.license --value MIT` fill an optional section the document happens to omit. That is the
|
|
152
|
+
* precise line `bug-084` draws — creating a node the schema declares is legitimate; inventing one it
|
|
153
|
+
* does not declare is the defect.
|
|
154
|
+
*
|
|
155
|
+
* `schemaRoot` defaults to `DnaYaml` — the only schema any caller passes — and is a parameter because
|
|
156
|
+
* the traversal is a function of *a* schema and a document, not of this one: it keeps the
|
|
157
|
+
* "addressable shape" rules (which node kinds a path may end on, which it may descend through)
|
|
158
|
+
* testable against shapes `spec-002` does not declare today, rather than leaving them as assertions
|
|
159
|
+
* nothing exercises.
|
|
160
|
+
*/
|
|
161
|
+
export declare function resolveDnaPath(dna: unknown, keyPath: string, schemaRoot?: z.ZodType): DnaPathResolution;
|
|
162
|
+
/**
|
|
163
|
+
* Every collection `DnaYaml` declares, as a dotted path — derived from the schema, in a fixed order
|
|
164
|
+
* (REQ-SYS-07). Used to build the union of `--<entry-field>` options the mutation verbs accept and to
|
|
165
|
+
* document the surface in `--help`; nothing here is hand-listed, so a collection added to `spec-002`
|
|
166
|
+
* becomes addressable without touching this module.
|
|
167
|
+
*/
|
|
168
|
+
export declare function dnaCollectionPaths(): readonly string[];
|
|
169
|
+
/**
|
|
170
|
+
* The union of every field name the entries of every collection may carry, minus `name` (which travels
|
|
171
|
+
* in `--value`, per `dl-081`'s `--value`-is-the-identity convention), in a fixed order. This is the
|
|
172
|
+
* `--entry-<field>` option set `dna add`/`dna update` register on both surfaces (see {@link dnaEntryOptionName}).
|
|
173
|
+
*/
|
|
174
|
+
export declare function dnaEntryOptionNames(): readonly string[];
|
|
175
|
+
//# sourceMappingURL=path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/dna/path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAK7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,uBAAuB,EAAG,QAAiB,CAAC;AAEzD,iGAAiG;AACjG,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,mGAAmG;AACnG,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAExE;AAED,sFAAsF;AACtF,MAAM,MAAM,aAAa;AACvB,oFAAoF;AAClF,SAAS;AACX,0EAA0E;GACxE,QAAQ;AACV,0EAA0E;GACxE,aAAa;AACf,8EAA8E;GAC5E,YAAY;AACd,4DAA4D;GAC1D,OAAO,CAAC;AAEZ,4EAA4E;AAC5E,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,aAAa,GAAG,OAAO,CAAC;AAErF,6GAA6G;AAC7G,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,2GAA2G;AAC3G,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,wGAAwG;IACxG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,mGAAmG;IACnG,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,+GAA+G;IAC/G,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,iHAAiH;IACjH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,gHAAgH;IAChH,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAChD,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,gGAAgG;AAChG,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAsFzI;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,GAAE,CAAC,CAAC,OAAiB,GAAG,iBAAiB,CA2FhH;AAOD;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,SAAS,MAAM,EAAE,CActD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,SAAS,MAAM,EAAE,CAavD"}
|