@patterkit/core 0.10.0 → 0.11.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/index.cjs +90 -8
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +90 -8
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -141,10 +141,73 @@ function walkContainer(children, selector, out) {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
// src/validate.ts
|
|
144
|
-
function
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
|
|
144
|
+
function jumpGraph(scenes, start) {
|
|
145
|
+
const firstBlock = /* @__PURE__ */ new Map();
|
|
146
|
+
const blocks = /* @__PURE__ */ new Set();
|
|
147
|
+
const wellFormed = scenes.filter((sc) => typeof sc?.id === "string" && Array.isArray(sc.blocks));
|
|
148
|
+
for (const scene of wellFormed) {
|
|
149
|
+
const first = scene.blocks[0];
|
|
150
|
+
if (typeof first?.id === "string") firstBlock.set(scene.id, first.id);
|
|
151
|
+
for (const b of scene.blocks) if (typeof b?.id === "string") blocks.add(b.id);
|
|
152
|
+
}
|
|
153
|
+
const resolve = (to) => blocks.has(to) ? to : firstBlock.get(to);
|
|
154
|
+
const next = /* @__PURE__ */ new Map();
|
|
155
|
+
const jumpedInto = /* @__PURE__ */ new Set();
|
|
156
|
+
const calledInto = /* @__PURE__ */ new Set();
|
|
157
|
+
for (const scene of wellFormed) {
|
|
158
|
+
for (const block of scene.blocks) {
|
|
159
|
+
if (typeof block?.id !== "string" || !Array.isArray(block.children)) continue;
|
|
160
|
+
const out = /* @__PURE__ */ new Set();
|
|
161
|
+
for (const to of jumpTargets(block.children, resolve)) {
|
|
162
|
+
out.add(to.block);
|
|
163
|
+
(to.call ? calledInto : jumpedInto).add(to.block);
|
|
164
|
+
}
|
|
165
|
+
next.set(block.id, out);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const begin = start ? start.block !== void 0 && blocks.has(start.block) ? start.block : firstBlock.get(start.scene) : void 0;
|
|
169
|
+
const fallbackBegin = wellFormed[0] ? firstBlock.get(wellFormed[0].id) : void 0;
|
|
170
|
+
if (begin ?? fallbackBegin) jumpedInto.add(begin ?? fallbackBegin);
|
|
171
|
+
return { next, jumpedInto, calledInto, resolve };
|
|
172
|
+
}
|
|
173
|
+
function jumpTargets(nodes, resolve) {
|
|
174
|
+
const out = [];
|
|
175
|
+
(0, import_model.walkNodes)(nodes.filter((n) => n && typeof n === "object"), (n) => {
|
|
176
|
+
if (n.type !== "snippet" || !n.jump || typeof n.jump.to !== "string" || n.jump.to === "END") return;
|
|
177
|
+
const block = resolve(n.jump.to);
|
|
178
|
+
if (block !== void 0) out.push({ block, call: n.jump.mode === "call" });
|
|
179
|
+
});
|
|
180
|
+
return out;
|
|
181
|
+
}
|
|
182
|
+
function leadsBack(graph, nodes, home) {
|
|
183
|
+
const queue = jumpTargets(nodes, graph.resolve).map((t) => t.block);
|
|
184
|
+
const seen = /* @__PURE__ */ new Set();
|
|
185
|
+
while (queue.length > 0) {
|
|
186
|
+
const b = queue.shift();
|
|
187
|
+
if (b === home) return true;
|
|
188
|
+
if (seen.has(b)) continue;
|
|
189
|
+
seen.add(b);
|
|
190
|
+
for (const n of graph.next.get(b) ?? []) queue.push(n);
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
function whatFollowsChoices(children) {
|
|
195
|
+
const out = /* @__PURE__ */ new Map();
|
|
196
|
+
const visit = (nodes, inOrder, after, once, options) => {
|
|
197
|
+
nodes.forEach((n, i) => {
|
|
198
|
+
if (!n || typeof n !== "object") return;
|
|
199
|
+
const inOnce = once || options && n.sticky !== true;
|
|
200
|
+
if (n.type !== "group") return;
|
|
201
|
+
const follows = inOrder ? [...nodes.slice(i + 1), ...after] : after;
|
|
202
|
+
if (n.selector === "choice") out.set(n.id, { follows, once });
|
|
203
|
+
if (Array.isArray(n.children)) visit(n.children, (n.selector ?? "run") === "run", follows, inOnce, n.selector === "choice");
|
|
204
|
+
});
|
|
205
|
+
};
|
|
206
|
+
visit(children, true, [], false, false);
|
|
207
|
+
return out;
|
|
208
|
+
}
|
|
209
|
+
function carriesOn(nodes) {
|
|
210
|
+
return nodes.some((n) => !isContentlessNode(n) && !(n.type === "snippet" && (n.beats?.length ?? 0) === 0 && n.jump?.to === "END"));
|
|
148
211
|
}
|
|
149
212
|
function isContentlessNode(node) {
|
|
150
213
|
if (node.type === "snippet") return (node.beats?.length ?? 0) === 0 && !node.jump;
|
|
@@ -211,6 +274,7 @@ function validateProject(input) {
|
|
|
211
274
|
const addressable = /* @__PURE__ */ new Set();
|
|
212
275
|
const sceneGameIds = /* @__PURE__ */ new Map();
|
|
213
276
|
const jumps = [];
|
|
277
|
+
const graph = jumpGraph(Array.isArray(scenes) ? scenes : [], project.start);
|
|
214
278
|
const castNames = new Set((project.cast ?? []).map((c) => c.name));
|
|
215
279
|
const qualifierIds = project.qualifiers === void 0 || Array.isArray(project.qualifiers) ? new Set((0, import_model.projectQualifiers)(project).flatMap((q) => isQualifierEntry(q) && typeof q.gameId === "string" ? [q.gameId] : [])) : null;
|
|
216
280
|
const checkPad = (value, what, id) => {
|
|
@@ -361,6 +425,7 @@ function validateProject(input) {
|
|
|
361
425
|
message: `${n.type} '${n.id}' in block '${block.id}' never runs: snippet '${n.jumper}' before it always jumps ${where2}`
|
|
362
426
|
});
|
|
363
427
|
}
|
|
428
|
+
const afterChoice = whatFollowsChoices(block.children);
|
|
364
429
|
(0, import_model.walkNodes)(block.children, (node) => {
|
|
365
430
|
const inBlock = `block '${block.id}'`;
|
|
366
431
|
checkTags(node.tags, `${node.type} '${node.id}'`, node.id);
|
|
@@ -402,10 +467,27 @@ function validateProject(input) {
|
|
|
402
467
|
issues.push({ code: "multiple-fallbacks", message: `choice '${node.id}' in ${inBlock} has ${fallbacks} fallback options (at most one allowed)`, id: node.id });
|
|
403
468
|
}
|
|
404
469
|
const hasUnconditionalEscape = (node.children ?? []).some((opt) => !opt.condition);
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
470
|
+
const { follows, once } = afterChoice.get(node.id) ?? { follows: [], once: false };
|
|
471
|
+
const noGuaranteedPath = (node.children?.length ?? 0) > 0 && !hasUnconditionalEscape;
|
|
472
|
+
const exhausts = !noGuaranteedPath && !once && !hasSticky && fallbacks === 0 && leadsBack(graph, [...node.children ?? [], ...follows], block.id);
|
|
473
|
+
if (noGuaranteedPath || exhausts) {
|
|
474
|
+
const why = noGuaranteedPath ? "has no unconditional option or fallback, so it runs dry if every condition fails" : "can be played again but every option is once-only with no fallback, so it runs dry once they're used";
|
|
475
|
+
const returns = graph.calledInto.has(block.id) && !graph.jumpedInto.has(block.id);
|
|
476
|
+
if (carriesOn(follows) || returns) {
|
|
477
|
+
issues.push({
|
|
478
|
+
code: "choice-can-empty",
|
|
479
|
+
severity: "info",
|
|
480
|
+
id: node.id,
|
|
481
|
+
message: `choice '${node.id}' in ${inBlock} ${why}; play then carries on ${returns && !carriesOn(follows) ? "where the block was called from" : "after it"}`
|
|
482
|
+
});
|
|
483
|
+
} else {
|
|
484
|
+
issues.push({
|
|
485
|
+
code: "choice-ends-dry",
|
|
486
|
+
severity: "warning",
|
|
487
|
+
id: node.id,
|
|
488
|
+
message: `choice '${node.id}' in ${inBlock} ${why}, and nothing follows it, so the dialogue would end there; add a fallback to say what happens then`
|
|
489
|
+
});
|
|
490
|
+
}
|
|
409
491
|
}
|
|
410
492
|
}
|
|
411
493
|
return;
|
package/dist/index.d.cts
CHANGED
|
@@ -26,13 +26,14 @@ interface StringifyOptions {
|
|
|
26
26
|
declare function canonicalStringify(value: unknown, opts?: StringifyOptions): string;
|
|
27
27
|
|
|
28
28
|
interface ValidationIssue {
|
|
29
|
-
code: "duplicate-id" | "missing-id" | "malformed-node" | "missing-name" | "empty-scene" | "empty-snippet" | "empty-container" | "dangling-jump" | "jump-into-non-addressable" | "invalid-gameid" | "duplicate-gameid" | "unknown-character" | "unknown-qualifier" | "invalid-qualifier" | "invalid-pad" | "pad-overlaps-seam" | "prompt-pad-without-beat" | "qualifier-without-speaker" | "invalid-speaker-label" | "unused-speaker-label" | "invalid-temporary" | "invalid-declaration" | "invalid-status-ladder" | "invalid-locales" | "invalid-captions" | "missing-prompt" | "invalid-prompt" | "multiple-fallbacks" | "choice-can-empty" | "invalid-status-value" | "unknown-doc-class" | "invalid-tag" | "invalid-gamedata-field" | "invalid-gamedata-value" | "jump-cycle" | "unreachable-after-jump" | "no-start" | "dangling-start";
|
|
29
|
+
code: "duplicate-id" | "missing-id" | "malformed-node" | "missing-name" | "empty-scene" | "empty-snippet" | "empty-container" | "dangling-jump" | "jump-into-non-addressable" | "invalid-gameid" | "duplicate-gameid" | "unknown-character" | "unknown-qualifier" | "invalid-qualifier" | "invalid-pad" | "pad-overlaps-seam" | "prompt-pad-without-beat" | "qualifier-without-speaker" | "invalid-speaker-label" | "unused-speaker-label" | "invalid-temporary" | "invalid-declaration" | "invalid-status-ladder" | "invalid-locales" | "invalid-captions" | "missing-prompt" | "invalid-prompt" | "multiple-fallbacks" | "choice-can-empty" | "choice-ends-dry" | "invalid-status-value" | "unknown-doc-class" | "invalid-tag" | "invalid-gamedata-field" | "invalid-gamedata-value" | "jump-cycle" | "unreachable-after-jump" | "no-start" | "dangling-start";
|
|
30
30
|
message: string;
|
|
31
31
|
/** Id of the offending node/beat, where applicable. */
|
|
32
32
|
id?: string;
|
|
33
33
|
/** Absent means an error: the project should not be built. A warning still compiles and plays (a choice
|
|
34
|
-
* that can run dry
|
|
35
|
-
|
|
34
|
+
* that can run dry and end the dialogue), and every front end shows it as one. An `info` is a note, not a
|
|
35
|
+
* problem (a choice that can run dry and then carry on, which is often meant): shown, never counted. */
|
|
36
|
+
severity?: "warning" | "info";
|
|
36
37
|
/** A quality gameData value off its field's ladder (a deleted or renamed stage, most often): the field, the
|
|
37
38
|
* value, and the stages to offer in its place, in ladder order. An editor's quick fix reads it. */
|
|
38
39
|
offLadder?: {
|
package/dist/index.d.ts
CHANGED
|
@@ -26,13 +26,14 @@ interface StringifyOptions {
|
|
|
26
26
|
declare function canonicalStringify(value: unknown, opts?: StringifyOptions): string;
|
|
27
27
|
|
|
28
28
|
interface ValidationIssue {
|
|
29
|
-
code: "duplicate-id" | "missing-id" | "malformed-node" | "missing-name" | "empty-scene" | "empty-snippet" | "empty-container" | "dangling-jump" | "jump-into-non-addressable" | "invalid-gameid" | "duplicate-gameid" | "unknown-character" | "unknown-qualifier" | "invalid-qualifier" | "invalid-pad" | "pad-overlaps-seam" | "prompt-pad-without-beat" | "qualifier-without-speaker" | "invalid-speaker-label" | "unused-speaker-label" | "invalid-temporary" | "invalid-declaration" | "invalid-status-ladder" | "invalid-locales" | "invalid-captions" | "missing-prompt" | "invalid-prompt" | "multiple-fallbacks" | "choice-can-empty" | "invalid-status-value" | "unknown-doc-class" | "invalid-tag" | "invalid-gamedata-field" | "invalid-gamedata-value" | "jump-cycle" | "unreachable-after-jump" | "no-start" | "dangling-start";
|
|
29
|
+
code: "duplicate-id" | "missing-id" | "malformed-node" | "missing-name" | "empty-scene" | "empty-snippet" | "empty-container" | "dangling-jump" | "jump-into-non-addressable" | "invalid-gameid" | "duplicate-gameid" | "unknown-character" | "unknown-qualifier" | "invalid-qualifier" | "invalid-pad" | "pad-overlaps-seam" | "prompt-pad-without-beat" | "qualifier-without-speaker" | "invalid-speaker-label" | "unused-speaker-label" | "invalid-temporary" | "invalid-declaration" | "invalid-status-ladder" | "invalid-locales" | "invalid-captions" | "missing-prompt" | "invalid-prompt" | "multiple-fallbacks" | "choice-can-empty" | "choice-ends-dry" | "invalid-status-value" | "unknown-doc-class" | "invalid-tag" | "invalid-gamedata-field" | "invalid-gamedata-value" | "jump-cycle" | "unreachable-after-jump" | "no-start" | "dangling-start";
|
|
30
30
|
message: string;
|
|
31
31
|
/** Id of the offending node/beat, where applicable. */
|
|
32
32
|
id?: string;
|
|
33
33
|
/** Absent means an error: the project should not be built. A warning still compiles and plays (a choice
|
|
34
|
-
* that can run dry
|
|
35
|
-
|
|
34
|
+
* that can run dry and end the dialogue), and every front end shows it as one. An `info` is a note, not a
|
|
35
|
+
* problem (a choice that can run dry and then carry on, which is often meant): shown, never counted. */
|
|
36
|
+
severity?: "warning" | "info";
|
|
36
37
|
/** A quality gameData value off its field's ladder (a deleted or renamed stage, most often): the field, the
|
|
37
38
|
* value, and the stages to offer in its place, in ladder order. An editor's quick fix reads it. */
|
|
38
39
|
offLadder?: {
|
package/dist/index.js
CHANGED
|
@@ -102,10 +102,73 @@ function walkContainer(children, selector, out) {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
// src/validate.ts
|
|
105
|
-
function
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
|
|
105
|
+
function jumpGraph(scenes, start) {
|
|
106
|
+
const firstBlock = /* @__PURE__ */ new Map();
|
|
107
|
+
const blocks = /* @__PURE__ */ new Set();
|
|
108
|
+
const wellFormed = scenes.filter((sc) => typeof sc?.id === "string" && Array.isArray(sc.blocks));
|
|
109
|
+
for (const scene of wellFormed) {
|
|
110
|
+
const first = scene.blocks[0];
|
|
111
|
+
if (typeof first?.id === "string") firstBlock.set(scene.id, first.id);
|
|
112
|
+
for (const b of scene.blocks) if (typeof b?.id === "string") blocks.add(b.id);
|
|
113
|
+
}
|
|
114
|
+
const resolve = (to) => blocks.has(to) ? to : firstBlock.get(to);
|
|
115
|
+
const next = /* @__PURE__ */ new Map();
|
|
116
|
+
const jumpedInto = /* @__PURE__ */ new Set();
|
|
117
|
+
const calledInto = /* @__PURE__ */ new Set();
|
|
118
|
+
for (const scene of wellFormed) {
|
|
119
|
+
for (const block of scene.blocks) {
|
|
120
|
+
if (typeof block?.id !== "string" || !Array.isArray(block.children)) continue;
|
|
121
|
+
const out = /* @__PURE__ */ new Set();
|
|
122
|
+
for (const to of jumpTargets(block.children, resolve)) {
|
|
123
|
+
out.add(to.block);
|
|
124
|
+
(to.call ? calledInto : jumpedInto).add(to.block);
|
|
125
|
+
}
|
|
126
|
+
next.set(block.id, out);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const begin = start ? start.block !== void 0 && blocks.has(start.block) ? start.block : firstBlock.get(start.scene) : void 0;
|
|
130
|
+
const fallbackBegin = wellFormed[0] ? firstBlock.get(wellFormed[0].id) : void 0;
|
|
131
|
+
if (begin ?? fallbackBegin) jumpedInto.add(begin ?? fallbackBegin);
|
|
132
|
+
return { next, jumpedInto, calledInto, resolve };
|
|
133
|
+
}
|
|
134
|
+
function jumpTargets(nodes, resolve) {
|
|
135
|
+
const out = [];
|
|
136
|
+
walkNodes(nodes.filter((n) => n && typeof n === "object"), (n) => {
|
|
137
|
+
if (n.type !== "snippet" || !n.jump || typeof n.jump.to !== "string" || n.jump.to === "END") return;
|
|
138
|
+
const block = resolve(n.jump.to);
|
|
139
|
+
if (block !== void 0) out.push({ block, call: n.jump.mode === "call" });
|
|
140
|
+
});
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
function leadsBack(graph, nodes, home) {
|
|
144
|
+
const queue = jumpTargets(nodes, graph.resolve).map((t) => t.block);
|
|
145
|
+
const seen = /* @__PURE__ */ new Set();
|
|
146
|
+
while (queue.length > 0) {
|
|
147
|
+
const b = queue.shift();
|
|
148
|
+
if (b === home) return true;
|
|
149
|
+
if (seen.has(b)) continue;
|
|
150
|
+
seen.add(b);
|
|
151
|
+
for (const n of graph.next.get(b) ?? []) queue.push(n);
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
function whatFollowsChoices(children) {
|
|
156
|
+
const out = /* @__PURE__ */ new Map();
|
|
157
|
+
const visit = (nodes, inOrder, after, once, options) => {
|
|
158
|
+
nodes.forEach((n, i) => {
|
|
159
|
+
if (!n || typeof n !== "object") return;
|
|
160
|
+
const inOnce = once || options && n.sticky !== true;
|
|
161
|
+
if (n.type !== "group") return;
|
|
162
|
+
const follows = inOrder ? [...nodes.slice(i + 1), ...after] : after;
|
|
163
|
+
if (n.selector === "choice") out.set(n.id, { follows, once });
|
|
164
|
+
if (Array.isArray(n.children)) visit(n.children, (n.selector ?? "run") === "run", follows, inOnce, n.selector === "choice");
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
visit(children, true, [], false, false);
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
170
|
+
function carriesOn(nodes) {
|
|
171
|
+
return nodes.some((n) => !isContentlessNode(n) && !(n.type === "snippet" && (n.beats?.length ?? 0) === 0 && n.jump?.to === "END"));
|
|
109
172
|
}
|
|
110
173
|
function isContentlessNode(node) {
|
|
111
174
|
if (node.type === "snippet") return (node.beats?.length ?? 0) === 0 && !node.jump;
|
|
@@ -172,6 +235,7 @@ function validateProject(input) {
|
|
|
172
235
|
const addressable = /* @__PURE__ */ new Set();
|
|
173
236
|
const sceneGameIds = /* @__PURE__ */ new Map();
|
|
174
237
|
const jumps = [];
|
|
238
|
+
const graph = jumpGraph(Array.isArray(scenes) ? scenes : [], project.start);
|
|
175
239
|
const castNames = new Set((project.cast ?? []).map((c) => c.name));
|
|
176
240
|
const qualifierIds = project.qualifiers === void 0 || Array.isArray(project.qualifiers) ? new Set(projectQualifiers(project).flatMap((q) => isQualifierEntry(q) && typeof q.gameId === "string" ? [q.gameId] : [])) : null;
|
|
177
241
|
const checkPad = (value, what, id) => {
|
|
@@ -322,6 +386,7 @@ function validateProject(input) {
|
|
|
322
386
|
message: `${n.type} '${n.id}' in block '${block.id}' never runs: snippet '${n.jumper}' before it always jumps ${where2}`
|
|
323
387
|
});
|
|
324
388
|
}
|
|
389
|
+
const afterChoice = whatFollowsChoices(block.children);
|
|
325
390
|
walkNodes(block.children, (node) => {
|
|
326
391
|
const inBlock = `block '${block.id}'`;
|
|
327
392
|
checkTags(node.tags, `${node.type} '${node.id}'`, node.id);
|
|
@@ -363,10 +428,27 @@ function validateProject(input) {
|
|
|
363
428
|
issues.push({ code: "multiple-fallbacks", message: `choice '${node.id}' in ${inBlock} has ${fallbacks} fallback options (at most one allowed)`, id: node.id });
|
|
364
429
|
}
|
|
365
430
|
const hasUnconditionalEscape = (node.children ?? []).some((opt) => !opt.condition);
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
431
|
+
const { follows, once } = afterChoice.get(node.id) ?? { follows: [], once: false };
|
|
432
|
+
const noGuaranteedPath = (node.children?.length ?? 0) > 0 && !hasUnconditionalEscape;
|
|
433
|
+
const exhausts = !noGuaranteedPath && !once && !hasSticky && fallbacks === 0 && leadsBack(graph, [...node.children ?? [], ...follows], block.id);
|
|
434
|
+
if (noGuaranteedPath || exhausts) {
|
|
435
|
+
const why = noGuaranteedPath ? "has no unconditional option or fallback, so it runs dry if every condition fails" : "can be played again but every option is once-only with no fallback, so it runs dry once they're used";
|
|
436
|
+
const returns = graph.calledInto.has(block.id) && !graph.jumpedInto.has(block.id);
|
|
437
|
+
if (carriesOn(follows) || returns) {
|
|
438
|
+
issues.push({
|
|
439
|
+
code: "choice-can-empty",
|
|
440
|
+
severity: "info",
|
|
441
|
+
id: node.id,
|
|
442
|
+
message: `choice '${node.id}' in ${inBlock} ${why}; play then carries on ${returns && !carriesOn(follows) ? "where the block was called from" : "after it"}`
|
|
443
|
+
});
|
|
444
|
+
} else {
|
|
445
|
+
issues.push({
|
|
446
|
+
code: "choice-ends-dry",
|
|
447
|
+
severity: "warning",
|
|
448
|
+
id: node.id,
|
|
449
|
+
message: `choice '${node.id}' in ${inBlock} ${why}, and nothing follows it, so the dialogue would end there; add a fallback to say what happens then`
|
|
450
|
+
});
|
|
451
|
+
}
|
|
370
452
|
}
|
|
371
453
|
}
|
|
372
454
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patterkit/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Patter core: stable id generation, readable-handle computation, canonical (de)serialisation, and the structural validator.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"build": "tsup src/index.ts --format esm,cjs --dts --clean"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@patterkit/model": "0.
|
|
37
|
+
"@patterkit/model": "0.23.0",
|
|
38
38
|
"@wildwinter/expr": "^0.6.0",
|
|
39
39
|
"@wildwinter/toolkit": "^0.4.0",
|
|
40
40
|
"json5": "^2.2.3"
|