@dtmd/temper 0.0.7 → 0.0.8

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.
Files changed (44) hide show
  1. package/README.md +84 -53
  2. package/bin/temper.js +0 -0
  3. package/dist/src/assembly.d.ts +15 -1
  4. package/dist/src/assembly.js +2 -1
  5. package/dist/src/builtins.d.ts +682 -66
  6. package/dist/src/builtins.js +664 -92
  7. package/dist/src/claude-code.d.ts +2 -2
  8. package/dist/src/claude-code.js +1 -1
  9. package/dist/src/contract.d.ts +180 -29
  10. package/dist/src/contract.js +128 -15
  11. package/dist/src/declarations.d.ts +72 -5
  12. package/dist/src/declarations.js +389 -107
  13. package/dist/src/dial.d.ts +75 -0
  14. package/dist/src/dial.js +82 -0
  15. package/dist/src/emit.d.ts +35 -1
  16. package/dist/src/emit.js +369 -63
  17. package/dist/src/generated/AssemblyFactRow.d.ts +2 -2
  18. package/dist/src/generated/BoundRow.d.ts +2 -2
  19. package/dist/src/generated/ClauseRow.d.ts +73 -3
  20. package/dist/src/generated/CollectionAddressRow.d.ts +4 -0
  21. package/dist/src/generated/EmbeddedMember.d.ts +3 -3
  22. package/dist/src/generated/FeatureValue.d.ts +2 -2
  23. package/dist/src/generated/Features.d.ts +52 -3
  24. package/dist/src/generated/KindFactRow.d.ts +24 -7
  25. package/dist/src/generated/MentionRow.d.ts +5 -3
  26. package/dist/src/generated/NestedMemberRow.d.ts +32 -0
  27. package/dist/src/generated/PayloadMember.d.ts +6 -0
  28. package/dist/src/generated/RequirementRow.d.ts +4 -2
  29. package/dist/src/generated/SatisfiesRow.d.ts +2 -1
  30. package/dist/src/generated/Shape.d.ts +15 -0
  31. package/dist/src/generated/Shape.js +2 -0
  32. package/dist/src/generated/TemplateRow.d.ts +24 -0
  33. package/dist/src/generated/TemplateRow.js +2 -0
  34. package/dist/src/generated/ValueType.d.ts +11 -2
  35. package/dist/src/generated/Verifier.d.ts +20 -0
  36. package/dist/src/generated/Verifier.js +2 -0
  37. package/dist/src/generated/index.d.ts +3 -0
  38. package/dist/src/index.d.ts +8 -8
  39. package/dist/src/index.js +3 -3
  40. package/dist/src/kind.d.ts +135 -29
  41. package/dist/src/kind.js +35 -8
  42. package/dist/src/prose.d.ts +81 -25
  43. package/dist/src/prose.js +91 -21
  44. package/package.json +2 -2
package/dist/src/prose.js CHANGED
@@ -1,14 +1,54 @@
1
1
  /**
2
2
  * Prose — three constructors, one field type. A member's words are data the
3
3
  * member declares: `file()` for a document that keeps its medium, `` text`…` ``
4
- * for short inline prose, `blocks()` for fully composed embedded-member values. Whatever
5
- * the constructor, the words land byte-identical to their authored text (law 5).
4
+ * for short inline prose, `blocks()` for a composed body that interleaves verbatim
5
+ * prose spans with embedded-member values in authored order. Whatever
6
+ * the constructor, the words land byte-identical to their authored text.
6
7
  * Interpolations in `` text`…` `` are references, two intents apart: a **mention**
7
8
  * (a {@link Mentionable}) is a declared one-way edge that moves no content, and an
8
9
  * **include** (an {@link Include}) pulls the target file's bytes into the host's emitted
9
- * projection. Both are authored per word and resolution-checked at emit, never mined
10
- * (law 8).
10
+ * projection. Both are authored per word and resolution-checked at emit, never mined.
11
11
  */
12
+ /**
13
+ * Spell a top-level member as the {@link Mentionable} a mention carries: its
14
+ * `kind:name` address, its bare name the display text — the convention every
15
+ * corpus repeats to cite a member from prose, captured once here.
16
+ */
17
+ export function mentionOf(member) {
18
+ return { address: `${member.kind}:${member.name}`, display: member.name };
19
+ }
20
+ /**
21
+ * Whether a mention's unresolved address **defers to the gate** rather than refusing at
22
+ * emit: a top-level `kind:name` address whose kind is one the program declares at a
23
+ * discovery locus (an `at`-locus kind) may name a member discovered on disk, so `check`
24
+ * owns the verdict. An embedded leaf address (a `<host>/<kind>/<key>` form, carrying a
25
+ * `/`), a bare requirement name (no `:`), or a kind the program does not declare has no
26
+ * discovery locus and stays a dangling refusal.
27
+ */
28
+ export function defersToGate(address, deferrableKinds) {
29
+ if (address.includes("/"))
30
+ return false;
31
+ const colon = address.indexOf(":");
32
+ return colon > 0 && deferrableKinds.has(address.slice(0, colon));
33
+ }
34
+ /**
35
+ * Refuse a mention whose address neither resolves against the scope's `mentionable`
36
+ * set nor defers to the gate ({@link defersToGate}) — the one dangling-mention refusal,
37
+ * shared by a member-level `Text` body, a composed body's prose span, and an embedded
38
+ * `Text` leaf. `context` prefixes the error so it names the host.
39
+ *
40
+ * # Throws
41
+ * If a mention names no declared value and its address has no discovery locus.
42
+ */
43
+ export function checkMentions(mentions, scope, context) {
44
+ for (const mention of mentions) {
45
+ const { address } = mention.target;
46
+ if (!scope.mentionable.has(address) && !defersToGate(address, scope.deferrableKinds)) {
47
+ throw new Error(`${context}: mention of \`${address}\` resolves to no declared value — ` +
48
+ `a mention cannot dangle (specs/model/contract.md).`);
49
+ }
50
+ }
51
+ }
12
52
  /** Whether an interpolation target is an include rather than a mention. */
13
53
  function isInclude(reference) {
14
54
  return reference.kind === "include";
@@ -40,8 +80,8 @@ function dedent(text) {
40
80
  .replace(/\n[ \t]*$/, "\n");
41
81
  }
42
82
  /**
43
- * Declare a document whose medium is preserved — read in whole at emit
44
- * (posture 1). `moduleUrl` is the declaring module's own `import.meta.url`,
83
+ * Declare a document whose medium is preserved — read in whole at emit.
84
+ * `moduleUrl` is the declaring module's own `import.meta.url`,
45
85
  * so `path` resolves relative to that module, never the process cwd:
46
86
  * `file(import.meta.url, "./long.md")`.
47
87
  */
@@ -52,7 +92,7 @@ export function file(moduleUrl, path) {
52
92
  * The inline dedenting prose constructor. Interpolate {@link Reference} values — a
53
93
  * {@link Mentionable} is a mention (moves no content), an {@link Include} pulls the
54
94
  * target's bytes in; either is opt-in per word, and plain prose with zero references is
55
- * fully legal forever (the opt-in Decision, `20-surface.md`).
95
+ * fully legal forever.
56
96
  *
57
97
  * # Throws
58
98
  * If an authored chunk carries {@link MENTION_SLOT} or {@link INCLUDE_SLOT} — the markers
@@ -89,14 +129,48 @@ export function text(strings, ...targets) {
89
129
  export function include(moduleUrl, path) {
90
130
  return { kind: "include", path, moduleUrl };
91
131
  }
92
- /** Compose fully-typed embedded-member values into a member's body (posture 3). */
132
+ /**
133
+ * Compose a member's body from ordered children: verbatim prose spans
134
+ * ({@link text}) and embedded-member values interleaved in authored order. A prose
135
+ * span rides as prose — no wrapper member is minted to carry a narrative.
136
+ *
137
+ * # Throws
138
+ * If a child is a {@link File} — the parameter type excludes one, so only a JS or
139
+ * cast caller arrives here, and the alternative is a raw crash downstream on the
140
+ * `leaves` a `File` has no reason to carry.
141
+ */
93
142
  export function blocks(...values) {
143
+ values.forEach((value, index) => {
144
+ if (isFileValue(value)) {
145
+ throw new Error(`blocks(): block ${index} is a \`file()\` value — a composed body admits a ` +
146
+ `\`text\` span or an embedded member value. A document is a member's whole ` +
147
+ `\`prose\` body (\`prose: file(…)\`); to pull its bytes into a composed body, ` +
148
+ `interpolate \`include()\` into a \`text\` span (specs/model/pipeline.md, "The SDK").`);
149
+ }
150
+ });
94
151
  return { kind: "blocks", values };
95
152
  }
153
+ /**
154
+ * Whether a composed-body child is a {@link File}. A child kind may itself be named
155
+ * `file`, so the kind tag alone is ambiguous — an embedded value always carries
156
+ * `leaves`, and only a `File` anchors a `moduleUrl`.
157
+ */
158
+ function isFileValue(value) {
159
+ const candidate = value;
160
+ return candidate.kind === "file" && typeof candidate.moduleUrl === "string";
161
+ }
162
+ /**
163
+ * Whether a composed-body child is a verbatim prose span rather than an embedded
164
+ * member value — the discriminant emit and the row builders branch on to render a
165
+ * span as prose and count its refs at host level, never as a nested member.
166
+ */
167
+ export function isTextSpan(value) {
168
+ return value.kind === "text";
169
+ }
96
170
  /**
97
171
  * Render an inline body to its final text — the display rule applied: each
98
172
  * mention slot becomes its target's display form, the surrounding words
99
- * untouched (law 5). The chunk count is `mentions.length + 1` by {@link text}'s
173
+ * untouched. The chunk count is `mentions.length + 1` by {@link text}'s
100
174
  * construction, so the walk consumes every slot.
101
175
  */
102
176
  export function renderText(prose) {
@@ -109,26 +183,22 @@ export function renderText(prose) {
109
183
  }
110
184
  /**
111
185
  * Resolve a leaf's authored value to its stored/rendered string: a bare string
112
- * is unchanged; a `Text` leaf is mention-resolution-checked against
113
- * `mentionable` (loud on a dangling address) and rendered by {@link renderText}
114
- * — the same rule a member-level `Text` body resolves by. `context` prefixes
115
- * the dangling-mention error so it names the leaf, not just the mention.
186
+ * is unchanged; a `Text` leaf is mention-resolution-checked against `scope`
187
+ * ({@link checkMentions}: loud on a dangling address, a discovery-locus one
188
+ * deferred) and rendered by {@link renderText} — the same rule a member-level
189
+ * `Text` body resolves by. `context` prefixes the dangling-mention error so it
190
+ * names the leaf, not just the mention.
116
191
  *
117
192
  * # Throws
118
- * If a mention names no declared value.
193
+ * If a mention names no declared value and has no discovery locus.
119
194
  */
120
- export function resolveLeaf(value, mentionable, context) {
195
+ export function resolveLeaf(value, scope, context) {
121
196
  if (typeof value === "string")
122
197
  return value;
123
198
  if (value.includes.length > 0) {
124
199
  throw new Error(`${context}: an embedded-member leaf cannot carry an include — a content pull is a ` +
125
200
  `member-body intent, not a fenced-value one (specs/model/pipeline.md, "The SDK").`);
126
201
  }
127
- for (const mention of value.mentions) {
128
- if (!mentionable.has(mention.target.address)) {
129
- throw new Error(`${context}: mention of \`${mention.target.address}\` resolves to no declared value — ` +
130
- `a mention cannot dangle (specs/model/contract.md).`);
131
- }
132
- }
202
+ checkMentions(value.mentions, scope, context);
133
203
  return renderText(value);
134
204
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dtmd/temper",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "The temper authoring face — the six-noun model as typed modules: harness(), kind<T>(), clause values, needs, and file()/text/blocks(). Emit compiles to the declaration rows the engine reads, a byte-faithful projection, and the lock.",
5
5
  "license": "(MIT OR Apache-2.0)",
6
6
  "repository": {
@@ -45,7 +45,7 @@
45
45
  "prepublishOnly": "npm run test"
46
46
  },
47
47
  "devDependencies": {
48
- "@types/node": "^22.0.0",
48
+ "@types/node": "^22.20.1",
49
49
  "typescript": "^5.6.0"
50
50
  },
51
51
  "bin": {