@ldclabs/kip-lang 2.1.0 → 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,36 +141,44 @@ 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
183
  // Spec §52.7 names seven statements whose WHERE can select an unbounded
162
184
  // set and which SHOULD therefore carry a LIMIT. Warning on the read and on
@@ -377,12 +399,15 @@ function collectHandleRefs(
377
399
  }
378
400
  break
379
401
 
380
- case 'SupersedeAssertionStatement':
381
- case 'CorrectEvidenceStatement':
382
- for (const ref of [clause.target, clause.by]) {
383
- if (ref.kind === 'VariableRef') {
384
- out.push({ name: ref.name.slice(1), range: ref.range })
385
- }
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)
386
411
  }
387
412
  break
388
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,15 +55,10 @@ 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',
68
63
  Payload = 'PAYLOAD',
69
64
  Confirm = 'CONFIRM',
@@ -82,7 +77,6 @@ export enum TokenType {
82
77
  Facet = 'FACET',
83
78
  Expect = 'EXPECT',
84
79
  Version = 'VERSION',
85
- State = 'STATE',
86
80
 
87
81
  // ── Keywords — META ───────────────────────────────────────────────
88
82
  Describe = 'DESCRIBE',
@@ -98,10 +92,7 @@ export enum TokenType {
98
92
  Primer = 'PRIMER',
99
93
  Mode = 'MODE',
100
94
  Protocol = 'PROTOCOL',
101
- Execution = 'EXECUTION',
102
- Context = 'CONTEXT',
103
95
  Capabilities = 'CAPABILITIES',
104
- Capability = 'CAPABILITY',
105
96
  Space = 'SPACE',
106
97
  Spaces = 'SPACES',
107
98
  Schema = 'SCHEMA',
@@ -122,7 +113,6 @@ export enum TokenType {
122
113
  Transaction = 'TRANSACTION',
123
114
  Idempotency = 'IDEMPOTENCY',
124
115
  Capsule = 'CAPSULE',
125
- Projection = 'PROJECTION',
126
116
  Trust = 'TRUST',
127
117
  Access = 'ACCESS',
128
118
  With = 'WITH',
@@ -216,8 +206,8 @@ export const KEYWORDS: ReadonlyMap<string, TokenType> = new Map([
216
206
  ['DISTINCT', TokenType.Distinct],
217
207
  ['AS', TokenType.As],
218
208
  ['OF', TokenType.Of],
209
+ ['AT', TokenType.At],
219
210
  ['SEQ', TokenType.Seq],
220
- ['TX', TokenType.Tx],
221
211
  ['TIME', TokenType.Time],
222
212
  ['FOR', TokenType.For],
223
213
  ['EPISTEMIC', TokenType.Epistemic],
@@ -238,15 +228,10 @@ export const KEYWORDS: ReadonlyMap<string, TokenType> = new Map([
238
228
  ['ASSERT', TokenType.Assert],
239
229
  ['SUPERSEDING', TokenType.Superseding],
240
230
  ['UPDATE', TokenType.Update],
241
- ['RETRACT', TokenType.Retract],
242
- ['SUPERSEDE', TokenType.Supersede],
243
- ['CORRECT', TokenType.Correct],
244
231
  ['TRANSITION', TokenType.Transition],
245
232
  ['SET', TokenType.Set],
246
233
  ['UNSET', TokenType.Unset],
247
234
  ['RETENTION', TokenType.Retention],
248
- ['ARCHIVE', TokenType.Archive],
249
- ['TOMBSTONE', TokenType.Tombstone],
250
235
  ['PURGE', TokenType.Purge],
251
236
  ['PAYLOAD', TokenType.Payload],
252
237
  ['CONFIRM', TokenType.Confirm],
@@ -265,7 +250,6 @@ export const KEYWORDS: ReadonlyMap<string, TokenType> = new Map([
265
250
  ['FACET', TokenType.Facet],
266
251
  ['EXPECT', TokenType.Expect],
267
252
  ['VERSION', TokenType.Version],
268
- ['STATE', TokenType.State],
269
253
 
270
254
  // META
271
255
  ['DESCRIBE', TokenType.Describe],
@@ -281,10 +265,7 @@ export const KEYWORDS: ReadonlyMap<string, TokenType> = new Map([
281
265
  ['PRIMER', TokenType.Primer],
282
266
  ['MODE', TokenType.Mode],
283
267
  ['PROTOCOL', TokenType.Protocol],
284
- ['EXECUTION', TokenType.Execution],
285
- ['CONTEXT', TokenType.Context],
286
268
  ['CAPABILITIES', TokenType.Capabilities],
287
- ['CAPABILITY', TokenType.Capability],
288
269
  ['SPACE', TokenType.Space],
289
270
  ['SPACES', TokenType.Spaces],
290
271
  ['SCHEMA', TokenType.Schema],
@@ -305,7 +286,6 @@ export const KEYWORDS: ReadonlyMap<string, TokenType> = new Map([
305
286
  ['TRANSACTION', TokenType.Transaction],
306
287
  ['IDEMPOTENCY', TokenType.Idempotency],
307
288
  ['CAPSULE', TokenType.Capsule],
308
- ['PROJECTION', TokenType.Projection],
309
289
  ['TRUST', TokenType.Trust],
310
290
  ['ACCESS', TokenType.Access],
311
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.1.0'
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'