@ldclabs/kip-lang 2.0.2 → 2.2.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/src/semantics.ts CHANGED
@@ -48,13 +48,27 @@ const MODES = new Set([
48
48
  'imported'
49
49
  ])
50
50
  const SEARCH_MODES = new Set(['keyword', 'semantic', 'hybrid'])
51
- const ASSERTION_STATES = new Set([
52
- 'active',
51
+ /**
52
+ * Everything `TRANSITION ... TO` may name (Spec §52.5): Assertion revision,
53
+ * Evidence correction, Activity status, and the storage lifecycle any element
54
+ * has. The engine matches the state to the target's kind; the toolkit can only
55
+ * reject a word that belongs to none of them.
56
+ */
57
+ const TRANSITION_STATES = new Set([
53
58
  'retracted',
54
59
  'superseded',
55
- 'expired'
60
+ 'corrected',
61
+ 'running',
62
+ 'completed',
63
+ 'failed',
64
+ 'cancelled',
65
+ 'archived',
66
+ 'tombstoned'
56
67
  ])
57
- const ACTIVITY_TERMINAL = new Set(['completed', 'failed', 'cancelled'])
68
+ /** Moves that name the replacing element with `BY`. */
69
+ const TRANSITION_WITH_BY = new Set(['superseded', 'corrected'])
70
+ /** Moves that may finalize an Activity's fields and topology. */
71
+ const ACTIVITY_STATES = new Set(['running', 'completed', 'failed', 'cancelled'])
58
72
  const EVIDENCE_ROLES = new Set(['support', 'challenge', 'context'])
59
73
 
60
74
  /** Signals the Profile fixes to `[0,1]`; none of them is truth. */
@@ -127,42 +141,51 @@ function analyzeMutationClause(stmt: Statement, diags: Diagnostic[]): void {
127
141
  if (stmt.where) checkWhere(stmt.where, !!stmt.limit, diags)
128
142
  break
129
143
 
130
- // `EXPECT STATE` is checkable only where the target's kind is fixed by the
131
- // statement itself. RETRACT and SUPERSEDE always name an Assertion, so the
132
- // Assertion lifecycle registry applies. ARCHIVE and TOMBSTONE take any
133
- // element — a Concept is not `retracted` and may well be `archived` — and
134
- // Core registers no element-lifecycle vocabulary, so checking them here
135
- // rejected commands the Specification admits.
136
- case 'RetractAssertionStatement':
137
- if (stmt.expectState) {
138
- checkEnum(stmt.expectState.value, ASSERTION_STATES, 'EXPECT STATE', diags)
139
- }
140
- if (stmt.where) checkWhere(stmt.where, !!stmt.limit, diags)
141
- break
142
-
143
- case 'SupersedeAssertionStatement':
144
- if (stmt.expectState) {
145
- checkEnum(stmt.expectState.value, ASSERTION_STATES, 'EXPECT STATE', diags)
144
+ // The target's kind is not known statically, so only the vocabulary is
145
+ // checkable: a state no kind has, a `BY` on a move that takes none, a
146
+ // finalize clause on a move that is not an Activity's.
147
+ case 'TransitionStatement': {
148
+ checkEnum(stmt.to, TRANSITION_STATES, 'TRANSITION TO', diags)
149
+ if (stmt.to.kind === 'StringLiteral') {
150
+ const to = stmt.to.parsed
151
+ if (TRANSITION_WITH_BY.has(to) && !stmt.by) {
152
+ diags.push({
153
+ range: stmt.to.range,
154
+ severity: 'error',
155
+ message: `TRANSITION TO "${to}" names the replacing element with BY`,
156
+ code: 'KIP_2001'
157
+ })
158
+ }
159
+ if (!TRANSITION_WITH_BY.has(to) && stmt.by && TRANSITION_STATES.has(to)) {
160
+ diags.push({
161
+ range: stmt.by.range,
162
+ severity: 'error',
163
+ message: `TRANSITION TO "${to}" takes no BY`,
164
+ code: 'KIP_2001'
165
+ })
166
+ }
167
+ if (stmt.finalize.length > 0 && !ACTIVITY_STATES.has(to) && TRANSITION_STATES.has(to)) {
168
+ diags.push({
169
+ range: stmt.finalize[0].range,
170
+ severity: 'error',
171
+ message: `TRANSITION TO "${to}" cannot finalize fields or topology; only a pending Activity does`,
172
+ code: 'KIP_2001'
173
+ })
174
+ }
146
175
  }
147
- break
148
-
149
- case 'ArchiveStatement':
150
- case 'TombstoneStatement':
151
- if (stmt.where) checkWhere(stmt.where, !!stmt.limit, diags)
152
- break
153
-
154
- case 'TransitionActivityStatement':
155
- checkEnum(stmt.to, ACTIVITY_TERMINAL, 'TRANSITION ACTIVITY TO', diags)
156
176
  checkStructural(stmt.finalize.find(
157
177
  (c): c is SetStructuralClause => c.kind === 'SetStructuralClause'
158
178
  ), diags)
179
+ if (stmt.where) checkWhere(stmt.where, !!stmt.limit, diags)
159
180
  break
181
+ }
160
182
 
161
- // Spec §52.7 names six statements whose WHERE can select an unbounded set
162
- // and which SHOULD therefore carry a LIMIT. Warning on the read and on
183
+ // Spec §52.7 names seven statements whose WHERE can select an unbounded
184
+ // set and which SHOULD therefore carry a LIMIT. Warning on the read and on
163
185
  // UPDATE while staying silent on the removal ladder had it backwards: an
164
186
  // over-broad PURGE is the one that cannot be undone.
165
187
  case 'PurgeStatement':
188
+ case 'PurgePayloadStatement':
166
189
  case 'SetRetentionStatement':
167
190
  if (stmt.where) checkWhere(stmt.where, !!stmt.limit, diags)
168
191
  break
@@ -376,12 +399,15 @@ function collectHandleRefs(
376
399
  }
377
400
  break
378
401
 
379
- case 'SupersedeAssertionStatement':
380
- case 'CorrectEvidenceStatement':
381
- for (const ref of [clause.target, clause.by]) {
382
- if (ref.kind === 'VariableRef') {
383
- out.push({ name: ref.name.slice(1), range: ref.range })
384
- }
402
+ case 'TransitionStatement':
403
+ // `BY ?new` resolves inside the plan; a `?target` is bound by WHERE or
404
+ // by a handle, so only the replacing element is a plan reference.
405
+ if (clause.by && clause.by.kind === 'VariableRef') {
406
+ out.push({ name: clause.by.name.slice(1), range: clause.by.range })
407
+ }
408
+ for (const fin of clause.finalize) {
409
+ if (fin.kind === 'SetFieldsClause') fromObject(fin.assignments)
410
+ else for (const edge of fin.assignments) fromExpression(edge.value)
385
411
  }
386
412
  break
387
413
  }
package/src/token.ts CHANGED
@@ -33,8 +33,8 @@ export enum TokenType {
33
33
  Distinct = 'DISTINCT',
34
34
  As = 'AS',
35
35
  Of = 'OF',
36
+ At = 'AT',
36
37
  Seq = 'SEQ',
37
- Tx = 'TX',
38
38
  Time = 'TIME',
39
39
  For = 'FOR',
40
40
  Epistemic = 'EPISTEMIC',
@@ -55,16 +55,12 @@ export enum TokenType {
55
55
  Assert = 'ASSERT',
56
56
  Superseding = 'SUPERSEDING',
57
57
  Update = 'UPDATE',
58
- Retract = 'RETRACT',
59
- Supersede = 'SUPERSEDE',
60
- Correct = 'CORRECT',
61
58
  Transition = 'TRANSITION',
62
59
  Set = 'SET',
63
60
  Unset = 'UNSET',
64
61
  Retention = 'RETENTION',
65
- Archive = 'ARCHIVE',
66
- Tombstone = 'TOMBSTONE',
67
62
  Purge = 'PURGE',
63
+ Payload = 'PAYLOAD',
68
64
  Confirm = 'CONFIRM',
69
65
  Reference = 'REFERENCE',
70
66
  Policy = 'POLICY',
@@ -81,7 +77,6 @@ export enum TokenType {
81
77
  Facet = 'FACET',
82
78
  Expect = 'EXPECT',
83
79
  Version = 'VERSION',
84
- State = 'STATE',
85
80
 
86
81
  // ── Keywords — META ───────────────────────────────────────────────
87
82
  Describe = 'DESCRIBE',
@@ -97,10 +92,7 @@ export enum TokenType {
97
92
  Primer = 'PRIMER',
98
93
  Mode = 'MODE',
99
94
  Protocol = 'PROTOCOL',
100
- Execution = 'EXECUTION',
101
- Context = 'CONTEXT',
102
95
  Capabilities = 'CAPABILITIES',
103
- Capability = 'CAPABILITY',
104
96
  Space = 'SPACE',
105
97
  Spaces = 'SPACES',
106
98
  Schema = 'SCHEMA',
@@ -113,13 +105,14 @@ export enum TokenType {
113
105
  Facets = 'FACETS',
114
106
  Types = 'TYPES',
115
107
  Policies = 'POLICIES',
108
+ Dependents = 'DEPENDENTS',
109
+ Depth = 'DEPTH',
116
110
  Compatibility = 'COMPATIBILITY',
117
111
  From = 'FROM',
118
112
  Error = 'ERROR',
119
113
  Transaction = 'TRANSACTION',
120
114
  Idempotency = 'IDEMPOTENCY',
121
115
  Capsule = 'CAPSULE',
122
- Projection = 'PROJECTION',
123
116
  Trust = 'TRUST',
124
117
  Access = 'ACCESS',
125
118
  With = 'WITH',
@@ -213,8 +206,8 @@ export const KEYWORDS: ReadonlyMap<string, TokenType> = new Map([
213
206
  ['DISTINCT', TokenType.Distinct],
214
207
  ['AS', TokenType.As],
215
208
  ['OF', TokenType.Of],
209
+ ['AT', TokenType.At],
216
210
  ['SEQ', TokenType.Seq],
217
- ['TX', TokenType.Tx],
218
211
  ['TIME', TokenType.Time],
219
212
  ['FOR', TokenType.For],
220
213
  ['EPISTEMIC', TokenType.Epistemic],
@@ -235,16 +228,12 @@ export const KEYWORDS: ReadonlyMap<string, TokenType> = new Map([
235
228
  ['ASSERT', TokenType.Assert],
236
229
  ['SUPERSEDING', TokenType.Superseding],
237
230
  ['UPDATE', TokenType.Update],
238
- ['RETRACT', TokenType.Retract],
239
- ['SUPERSEDE', TokenType.Supersede],
240
- ['CORRECT', TokenType.Correct],
241
231
  ['TRANSITION', TokenType.Transition],
242
232
  ['SET', TokenType.Set],
243
233
  ['UNSET', TokenType.Unset],
244
234
  ['RETENTION', TokenType.Retention],
245
- ['ARCHIVE', TokenType.Archive],
246
- ['TOMBSTONE', TokenType.Tombstone],
247
235
  ['PURGE', TokenType.Purge],
236
+ ['PAYLOAD', TokenType.Payload],
248
237
  ['CONFIRM', TokenType.Confirm],
249
238
  ['REFERENCE', TokenType.Reference],
250
239
  ['POLICY', TokenType.Policy],
@@ -261,7 +250,6 @@ export const KEYWORDS: ReadonlyMap<string, TokenType> = new Map([
261
250
  ['FACET', TokenType.Facet],
262
251
  ['EXPECT', TokenType.Expect],
263
252
  ['VERSION', TokenType.Version],
264
- ['STATE', TokenType.State],
265
253
 
266
254
  // META
267
255
  ['DESCRIBE', TokenType.Describe],
@@ -277,10 +265,7 @@ export const KEYWORDS: ReadonlyMap<string, TokenType> = new Map([
277
265
  ['PRIMER', TokenType.Primer],
278
266
  ['MODE', TokenType.Mode],
279
267
  ['PROTOCOL', TokenType.Protocol],
280
- ['EXECUTION', TokenType.Execution],
281
- ['CONTEXT', TokenType.Context],
282
268
  ['CAPABILITIES', TokenType.Capabilities],
283
- ['CAPABILITY', TokenType.Capability],
284
269
  ['SPACE', TokenType.Space],
285
270
  ['SPACES', TokenType.Spaces],
286
271
  ['SCHEMA', TokenType.Schema],
@@ -293,13 +278,14 @@ export const KEYWORDS: ReadonlyMap<string, TokenType> = new Map([
293
278
  ['FACETS', TokenType.Facets],
294
279
  ['TYPES', TokenType.Types],
295
280
  ['POLICIES', TokenType.Policies],
281
+ ['DEPENDENTS', TokenType.Dependents],
282
+ ['DEPTH', TokenType.Depth],
296
283
  ['COMPATIBILITY', TokenType.Compatibility],
297
284
  ['FROM', TokenType.From],
298
285
  ['ERROR', TokenType.Error],
299
286
  ['TRANSACTION', TokenType.Transaction],
300
287
  ['IDEMPOTENCY', TokenType.Idempotency],
301
288
  ['CAPSULE', TokenType.Capsule],
302
- ['PROJECTION', TokenType.Projection],
303
289
  ['TRUST', TokenType.Trust],
304
290
  ['ACCESS', TokenType.Access],
305
291
  ['WITH', TokenType.With],
package/src/version.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  * has to load in runtimes with no filesystem; `test/lower.test.mjs` asserts the
8
8
  * two stay in step.
9
9
  */
10
- export const PARSER_VERSION = '2.0.2'
10
+ export const PARSER_VERSION = '2.2.0'
11
11
 
12
12
  /** The KIP specification revision this grammar targets. */
13
13
  export const KIP_SPEC_REVISION = '2.0-draft'