@patterkit/compiler 0.2.8 → 0.4.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 +161 -19
- package/dist/index.d.cts +55 -10
- package/dist/index.d.ts +55 -10
- package/dist/index.js +152 -14
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -20,9 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
EXTERNAL_SCOPES: () => import_dialect4.EXTERNAL_SCOPES,
|
|
24
|
+
PATTER_SCOPE: () => PATTER_SCOPE,
|
|
23
25
|
compileExpression: () => compileExpression,
|
|
24
26
|
exportBundle: () => exportBundle,
|
|
25
|
-
|
|
27
|
+
externalGameScopes: () => externalGameScopes,
|
|
28
|
+
hostScopesToSpec: () => import_dialect4.hostScopesToSpec,
|
|
29
|
+
projectScopes: () => projectScopes,
|
|
26
30
|
validateConditions: () => validateConditions,
|
|
27
31
|
validateInterpolation: () => validateInterpolation
|
|
28
32
|
});
|
|
@@ -30,15 +34,103 @@ module.exports = __toCommonJS(index_exports);
|
|
|
30
34
|
|
|
31
35
|
// src/expressions.ts
|
|
32
36
|
var import_expr = require("@wildwinter/expr");
|
|
37
|
+
var import_dialect2 = require("@patterkit/dialect");
|
|
38
|
+
var import_scopes2 = require("@wildwinter/scoperegistry/scopes");
|
|
39
|
+
|
|
40
|
+
// src/game-scopes.ts
|
|
41
|
+
var import_scopes = require("@wildwinter/scoperegistry/scopes");
|
|
33
42
|
var import_dialect = require("@patterkit/dialect");
|
|
43
|
+
var PATTER_SCOPE = "patter";
|
|
44
|
+
function asHostScope(s) {
|
|
45
|
+
return {
|
|
46
|
+
token: s.token,
|
|
47
|
+
...s.writable !== void 0 ? { writable: s.writable } : {},
|
|
48
|
+
...s.declarations ? { declarations: s.declarations.map((d) => ({ ...d })) } : {}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function sameScope(a, b) {
|
|
52
|
+
const norm = (s) => JSON.stringify((0, import_dialect.hostScopesToSpec)({ version: 1, scopes: [s] }));
|
|
53
|
+
return norm(a) === norm(b);
|
|
54
|
+
}
|
|
55
|
+
function projectScopes(project, merged) {
|
|
56
|
+
const own = project.scopeRegistry;
|
|
57
|
+
if (!merged) return { host: own, external: [], notes: [] };
|
|
58
|
+
const notes = [];
|
|
59
|
+
const hosted = [];
|
|
60
|
+
const bundled = /* @__PURE__ */ new Set();
|
|
61
|
+
let changed = false;
|
|
62
|
+
const shared = (token) => token === PATTER_SCOPE ? void 0 : merged.spec.scopes.find((s) => s.token === token);
|
|
63
|
+
for (const h of own?.scopes ?? []) {
|
|
64
|
+
const s = shared(h.token);
|
|
65
|
+
const who = merged.owners.get(h.token);
|
|
66
|
+
if (!s || !who) {
|
|
67
|
+
hosted.push(h);
|
|
68
|
+
bundled.add(h.token);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (who.fileName === import_scopes.GAME_SCOPES_FILE) {
|
|
72
|
+
const fromFile = asHostScope(s);
|
|
73
|
+
hosted.push(fromFile);
|
|
74
|
+
bundled.add(h.token);
|
|
75
|
+
changed = true;
|
|
76
|
+
if (!sameScope(h, fromFile)) {
|
|
77
|
+
notes.push({
|
|
78
|
+
token: h.token,
|
|
79
|
+
file: who.fileName,
|
|
80
|
+
message: `@${h.token} in World properties differs from ${import_scopes.GAME_SCOPES_DIR}/${who.fileName}, and the shared file wins: saving Project Settings in Patterpad brings the project's copy up to date`
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
changed = true;
|
|
85
|
+
notes.push({
|
|
86
|
+
token: h.token,
|
|
87
|
+
file: who.fileName,
|
|
88
|
+
message: `@${h.token} is declared in ${import_scopes.GAME_SCOPES_DIR}/${who.fileName}; remove it from World properties`
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const world = shared("world");
|
|
93
|
+
if (world && merged.owners.get("world")?.fileName === import_scopes.GAME_SCOPES_FILE && !bundled.has("world")) {
|
|
94
|
+
hosted.push(asHostScope(world));
|
|
95
|
+
bundled.add("world");
|
|
96
|
+
changed = true;
|
|
97
|
+
}
|
|
98
|
+
const external = merged.spec.scopes.filter((s) => s.token !== PATTER_SCOPE && !bundled.has(s.token));
|
|
99
|
+
const host = !changed ? own : hosted.length ? { version: own?.version ?? 1, scopes: hosted } : void 0;
|
|
100
|
+
return { host, external, notes };
|
|
101
|
+
}
|
|
102
|
+
function externalGameScopes(strict, merged) {
|
|
103
|
+
if (!merged) return [];
|
|
104
|
+
const hostTokens = new Set((strict?.scopes ?? []).map((s) => s.token));
|
|
105
|
+
return merged.spec.scopes.filter((s) => s.token !== PATTER_SCOPE && !hostTokens.has(s.token));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/expressions.ts
|
|
34
109
|
var import_model = require("@patterkit/model");
|
|
35
110
|
function compileExpression(src, foreign) {
|
|
36
|
-
return (0, import_expr.compile)(src, (0,
|
|
111
|
+
return (0, import_expr.compile)(src, (0, import_dialect2.dialectWithForeignScopes)(foreign));
|
|
112
|
+
}
|
|
113
|
+
function validationScopes(project, options) {
|
|
114
|
+
const merged = options.gameScopes;
|
|
115
|
+
const strict = options.foreignScopes ?? (merged ? (0, import_dialect2.hostScopesToSpec)(projectScopes(project, merged).host) : void 0);
|
|
116
|
+
const external = externalGameScopes(strict, merged);
|
|
117
|
+
const base = strict?.scopes ?? [];
|
|
118
|
+
const foreign = (0, import_dialect2.withEngineScopes)({ version: strict?.version ?? 1, scopes: [...base, ...external.map((s) => ({ token: s.token }))] });
|
|
119
|
+
const checked = external.some((s) => s.declarations?.length) ? (0, import_dialect2.withEngineScopes)({ version: strict?.version ?? 1, scopes: [...base, ...external] }) : void 0;
|
|
120
|
+
return { foreign, checked, external: new Set(external.map((s) => s.token)), merged };
|
|
121
|
+
}
|
|
122
|
+
var issueKey = (i) => `${i.kind}|${JSON.stringify(i.path)}|${i.message}`;
|
|
123
|
+
function externalMessage(i, merged) {
|
|
124
|
+
if (merged && i.kind === "unresolved-scoped-property" && i.reference) {
|
|
125
|
+
const [token, name] = i.reference.split(".");
|
|
126
|
+
if (token && name) return (0, import_scopes2.referenceNote)(merged, token, name) ?? i.message;
|
|
127
|
+
}
|
|
128
|
+
return i.message;
|
|
37
129
|
}
|
|
38
130
|
function validateConditions(input, options = {}) {
|
|
39
131
|
const issues = [];
|
|
40
|
-
const foreign = options
|
|
41
|
-
const dialect = (0,
|
|
132
|
+
const { foreign, checked, external, merged } = validationScopes(input.project, options);
|
|
133
|
+
const dialect = (0, import_dialect2.dialectWithForeignScopes)(foreign);
|
|
42
134
|
const readOnly = readOnlyForeignTargets(foreign);
|
|
43
135
|
const opaqueForeign = opaqueForeignTokens(foreign);
|
|
44
136
|
const isScopeToken = scopeTokenTest(foreign);
|
|
@@ -60,7 +152,8 @@ function validateConditions(input, options = {}) {
|
|
|
60
152
|
}
|
|
61
153
|
};
|
|
62
154
|
const validateElement = (blocks, sceneProps, onEntry, elementId) => {
|
|
63
|
-
const schema = (0,
|
|
155
|
+
const schema = (0, import_dialect2.buildSchema)(input.project, sceneProps, foreign);
|
|
156
|
+
const checkedSchema = checked ? (0, import_dialect2.buildSchema)(input.project, sceneProps, checked) : void 0;
|
|
64
157
|
const check = (nodeId, field, src) => {
|
|
65
158
|
let ast;
|
|
66
159
|
try {
|
|
@@ -69,9 +162,16 @@ function validateConditions(input, options = {}) {
|
|
|
69
162
|
issues.push({ nodeId, field, src, severity: "error", message: e instanceof Error ? e.message : String(e) });
|
|
70
163
|
return;
|
|
71
164
|
}
|
|
72
|
-
|
|
165
|
+
const strict = (0, import_expr.validateExpr)(ast, schema, dialect);
|
|
166
|
+
for (const iss of strict) {
|
|
73
167
|
issues.push({ nodeId, field, src, severity: iss.severity, message: iss.message });
|
|
74
168
|
}
|
|
169
|
+
if (checkedSchema) {
|
|
170
|
+
const seen = new Set(strict.map(issueKey));
|
|
171
|
+
for (const iss of (0, import_expr.validateExpr)(ast, checkedSchema, dialect)) {
|
|
172
|
+
if (!seen.has(issueKey(iss))) issues.push({ nodeId, field, src, severity: "warning", message: externalMessage(iss, merged) });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
75
175
|
checkVisitIds(ast, nodeId, field, src);
|
|
76
176
|
};
|
|
77
177
|
const checkTarget = (nodeId, field, target) => {
|
|
@@ -95,7 +195,12 @@ function validateConditions(input, options = {}) {
|
|
|
95
195
|
});
|
|
96
196
|
return;
|
|
97
197
|
}
|
|
98
|
-
const { scope, name } = (0,
|
|
198
|
+
const { scope, name } = (0, import_dialect2.splitRef)(target, isScopeToken);
|
|
199
|
+
if (external.has(scope)) {
|
|
200
|
+
const note = merged ? (0, import_scopes2.referenceNote)(merged, scope, name, { write: true }) : void 0;
|
|
201
|
+
if (note) issues.push({ nodeId, field, src: target, severity: "warning", message: note });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
99
204
|
if (opaqueForeign.has(scope)) return;
|
|
100
205
|
if (!schema.properties.get(scope)?.has(name)) {
|
|
101
206
|
issues.push({
|
|
@@ -132,12 +237,14 @@ function validateInterpolation(input, options = {}) {
|
|
|
132
237
|
const voiced = input.project.voiced ?? false;
|
|
133
238
|
const tables = (input.locales ?? []).map((l) => ({ locale: l.locale, strings: l.strings }));
|
|
134
239
|
const defaultLocale = input.project.locales.default;
|
|
135
|
-
const
|
|
136
|
-
const
|
|
240
|
+
const { foreign, external, merged } = validationScopes(input.project, options);
|
|
241
|
+
const opaqueForeign = opaqueForeignTokens(foreign);
|
|
242
|
+
const isScopeToken = scopeTokenTest(foreign);
|
|
137
243
|
for (const scene of input.scenes) {
|
|
138
|
-
const schema = (0,
|
|
244
|
+
const schema = (0, import_dialect2.buildSchema)(input.project, scene.sceneProps, foreign);
|
|
139
245
|
const known = (ref) => {
|
|
140
|
-
const { scope, name } = (0,
|
|
246
|
+
const { scope, name } = (0, import_dialect2.splitRef)(ref, isScopeToken);
|
|
247
|
+
if (external.has(scope)) return (merged ? (0, import_scopes2.referenceNote)(merged, scope, name) : void 0) ?? true;
|
|
141
248
|
if (opaqueForeign.has(scope)) return true;
|
|
142
249
|
return schema.properties.get(scope)?.has(name) ?? false;
|
|
143
250
|
};
|
|
@@ -146,7 +253,7 @@ function validateInterpolation(input, options = {}) {
|
|
|
146
253
|
const text = t.strings[id];
|
|
147
254
|
if (text === void 0) continue;
|
|
148
255
|
const field = `text[${t.locale}]`;
|
|
149
|
-
for (const slot of (0,
|
|
256
|
+
for (const slot of (0, import_dialect2.extractSlots)(text)) {
|
|
150
257
|
if (voicedLine) {
|
|
151
258
|
issues.push({
|
|
152
259
|
nodeId,
|
|
@@ -167,7 +274,10 @@ function validateInterpolation(input, options = {}) {
|
|
|
167
274
|
});
|
|
168
275
|
continue;
|
|
169
276
|
}
|
|
170
|
-
|
|
277
|
+
const ok = known(slot.ref);
|
|
278
|
+
if (typeof ok === "string") {
|
|
279
|
+
issues.push({ nodeId, field, src: slot.raw, severity: "warning", message: ok });
|
|
280
|
+
} else if (!ok) {
|
|
171
281
|
issues.push({
|
|
172
282
|
nodeId,
|
|
173
283
|
field,
|
|
@@ -231,11 +341,11 @@ function readOnlyForeignTargets(spec) {
|
|
|
231
341
|
}
|
|
232
342
|
|
|
233
343
|
// src/index.ts
|
|
234
|
-
var
|
|
344
|
+
var import_dialect4 = require("@patterkit/dialect");
|
|
235
345
|
|
|
236
346
|
// src/export.ts
|
|
237
347
|
var import_core = require("@patterkit/core");
|
|
238
|
-
var
|
|
348
|
+
var import_dialect3 = require("@patterkit/dialect");
|
|
239
349
|
function compileEffect(e, foreign) {
|
|
240
350
|
return { kind: "set", target: e.target, value: compileExpression(e.value, foreign) };
|
|
241
351
|
}
|
|
@@ -303,11 +413,37 @@ function compileScene(scene, foreign) {
|
|
|
303
413
|
blocks: scene.blocks.map((b) => compileBlock(b, foreign))
|
|
304
414
|
};
|
|
305
415
|
}
|
|
416
|
+
function externalScopesIn(scenes, external) {
|
|
417
|
+
const found = /* @__PURE__ */ new Set();
|
|
418
|
+
const walk = (node) => {
|
|
419
|
+
if (!Array.isArray(node) && (node === null || typeof node !== "object")) return;
|
|
420
|
+
if (Array.isArray(node)) {
|
|
421
|
+
if (node[0] === "sv" && typeof node[1] === "string" && external.has(node[1])) found.add(node[1]);
|
|
422
|
+
for (const n of node) walk(n);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const o = node;
|
|
426
|
+
if (o["kind"] === "set" && typeof o["target"] === "string") {
|
|
427
|
+
const head = o["target"].replace(/^@/, "").split(".")[0];
|
|
428
|
+
if (o["target"].includes(".") && external.has(head)) found.add(head);
|
|
429
|
+
}
|
|
430
|
+
for (const v of Object.values(o)) walk(v);
|
|
431
|
+
};
|
|
432
|
+
walk(scenes);
|
|
433
|
+
return [...found].sort();
|
|
434
|
+
}
|
|
306
435
|
function exportBundle(input) {
|
|
307
436
|
const { project, scenes, locales = [], includeLocales } = input;
|
|
308
|
-
const
|
|
437
|
+
const hostScopes = projectScopes(project, input.gameScopes).host;
|
|
438
|
+
const foreignScopes = input.foreignScopes ?? (0, import_dialect3.hostScopesToSpec)(hostScopes);
|
|
439
|
+
const gameExternal = externalGameScopes(foreignScopes, input.gameScopes);
|
|
440
|
+
const compileScopes = (0, import_dialect3.withEngineScopes)({
|
|
441
|
+
version: foreignScopes?.version ?? 1,
|
|
442
|
+
scopes: [...foreignScopes?.scopes ?? [], ...gameExternal.map((s) => ({ token: s.token }))]
|
|
443
|
+
});
|
|
309
444
|
const scenesOut = {};
|
|
310
|
-
for (const scene of scenes) scenesOut[scene.id] = compileScene(scene,
|
|
445
|
+
for (const scene of scenes) scenesOut[scene.id] = compileScene(scene, compileScopes);
|
|
446
|
+
const externalScopes = externalScopesIn(scenesOut, /* @__PURE__ */ new Set([...import_dialect3.EXTERNAL_SCOPES, ...gameExternal.map((s) => s.token)]));
|
|
311
447
|
const strings = {};
|
|
312
448
|
for (const loc of locales) {
|
|
313
449
|
if (includeLocales && !includeLocales.includes(loc.locale)) continue;
|
|
@@ -357,20 +493,26 @@ function exportBundle(input) {
|
|
|
357
493
|
return m;
|
|
358
494
|
}),
|
|
359
495
|
properties: project.properties,
|
|
360
|
-
scopeRegistry:
|
|
496
|
+
scopeRegistry: hostScopes,
|
|
361
497
|
gameDataFields: project.gameDataFields,
|
|
362
498
|
// Closed-caption delimiters ride along only when the project pins a non-default pair (#214); the
|
|
363
499
|
// runtime falls back to `[` / `]` when absent, so default projects keep their exact prior bundle.
|
|
364
500
|
...project.closedCaptions ? { closedCaptions: project.closedCaptions } : {},
|
|
365
501
|
scenes: scenesOut,
|
|
366
|
-
strings
|
|
502
|
+
strings,
|
|
503
|
+
// Other engines' scopes the content names, so the engine can say when the game has not registered one.
|
|
504
|
+
...externalScopes.length > 0 ? { externalScopes } : {}
|
|
367
505
|
};
|
|
368
506
|
}
|
|
369
507
|
// Annotate the CommonJS export names for ESM import in node:
|
|
370
508
|
0 && (module.exports = {
|
|
509
|
+
EXTERNAL_SCOPES,
|
|
510
|
+
PATTER_SCOPE,
|
|
371
511
|
compileExpression,
|
|
372
512
|
exportBundle,
|
|
513
|
+
externalGameScopes,
|
|
373
514
|
hostScopesToSpec,
|
|
515
|
+
projectScopes,
|
|
374
516
|
validateConditions,
|
|
375
517
|
validateInterpolation
|
|
376
518
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { ScopeRegistrySpec } from '@wildwinter/scoperegistry';
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { ScopeRegistrySpec, ScopeSpec } from '@wildwinter/scoperegistry';
|
|
2
|
+
import { MergedScopes } from '@wildwinter/scoperegistry/scopes';
|
|
3
|
+
import { Expression, ProjectFile, Scene, LocaleFile, Bundle, HostScopeRegistry } from '@patterkit/model';
|
|
4
|
+
export { EXTERNAL_SCOPES, hostScopesToSpec } from '@patterkit/dialect';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Compile a condition/effect `src` string to the bundle `{ src, ast }` envelope.
|
|
@@ -8,6 +9,17 @@ export { hostScopesToSpec } from '@patterkit/dialect';
|
|
|
8
9
|
* a storylet's `@world`); the parser needs every referenced scope registered.
|
|
9
10
|
*/
|
|
10
11
|
declare function compileExpression(src: string, foreign?: ScopeRegistrySpec): Expression;
|
|
12
|
+
/**
|
|
13
|
+
* What the validators take besides the project. `foreignScopes` is the host spec, checked strictly (a
|
|
14
|
+
* project's own `@world`, or another owner's spec). `gameScopes` is the game's merged `game-scopes/`
|
|
15
|
+
* folder: every scope in it the host spec doesn't hold is checked too, but only ever with WARNINGS
|
|
16
|
+
* (patterkit/design/shared-scopes.md decision 3). Given `gameScopes` and no `foreignScopes`, the host
|
|
17
|
+
* spec is the project's host scopes as the folder leaves them (`projectScopes`).
|
|
18
|
+
*/
|
|
19
|
+
interface ValidateOptions {
|
|
20
|
+
foreignScopes?: ScopeRegistrySpec;
|
|
21
|
+
gameScopes?: MergedScopes;
|
|
22
|
+
}
|
|
11
23
|
interface ConditionIssue {
|
|
12
24
|
/** Id of the node whose expression has the issue. */
|
|
13
25
|
nodeId: string;
|
|
@@ -31,9 +43,7 @@ interface ConditionIssue {
|
|
|
31
43
|
declare function validateConditions(input: {
|
|
32
44
|
project: ProjectFile;
|
|
33
45
|
scenes: Scene[];
|
|
34
|
-
}, options?:
|
|
35
|
-
foreignScopes?: ScopeRegistrySpec;
|
|
36
|
-
}): ConditionIssue[];
|
|
46
|
+
}, options?: ValidateOptions): ConditionIssue[];
|
|
37
47
|
/**
|
|
38
48
|
* Validate inline `{@ref}` interpolation slots in a project's localised strings
|
|
39
49
|
* (spec §16). Enforces the VO-safety guarantee - **a voiced project rejects any
|
|
@@ -50,9 +60,7 @@ declare function validateInterpolation(input: {
|
|
|
50
60
|
project: ProjectFile;
|
|
51
61
|
scenes: Scene[];
|
|
52
62
|
locales?: LocaleFile[];
|
|
53
|
-
}, options?:
|
|
54
|
-
foreignScopes?: ScopeRegistrySpec;
|
|
55
|
-
}): ConditionIssue[];
|
|
63
|
+
}, options?: ValidateOptions): ConditionIssue[];
|
|
56
64
|
|
|
57
65
|
interface ExportInput {
|
|
58
66
|
project: ProjectFile;
|
|
@@ -67,8 +75,45 @@ interface ExportInput {
|
|
|
67
75
|
* unregistered scope token, so cross-engine refs need this.
|
|
68
76
|
*/
|
|
69
77
|
foreignScopes?: ScopeRegistrySpec;
|
|
78
|
+
/**
|
|
79
|
+
* The game's merged `game-scopes/` folder, when the project has one (patterkit/design/shared-scopes.md).
|
|
80
|
+
* Its `game.scopes.json` wins over the project's copy of a host scope, and its `@world` is baked in
|
|
81
|
+
* even when the project doesn't declare it; every other scope in it compiles as another engine's
|
|
82
|
+
* does: named in `externalScopes`, never baked in.
|
|
83
|
+
*/
|
|
84
|
+
gameScopes?: MergedScopes;
|
|
70
85
|
}
|
|
71
86
|
/** Compile a project's source into the runtime bundle. */
|
|
72
87
|
declare function exportBundle(input: ExportInput): Bundle;
|
|
73
88
|
|
|
74
|
-
|
|
89
|
+
/** Patter's own game-wide token: the one scope Patter writes to the folder and never reads back. */
|
|
90
|
+
declare const PATTER_SCOPE = "patter";
|
|
91
|
+
/** Something the folder says about the project's host scopes: a warning, anchored to a scopes file. */
|
|
92
|
+
interface HostScopeNote {
|
|
93
|
+
token: string;
|
|
94
|
+
/** The scopes file it concerns, by name (`game.scopes.json`). */
|
|
95
|
+
file: string;
|
|
96
|
+
message: string;
|
|
97
|
+
}
|
|
98
|
+
/** A project's scopes once its game's folder is taken into account. */
|
|
99
|
+
interface ProjectScopes {
|
|
100
|
+
/** The host scopes the compile treats as the project's: validated strictly, baked into the bundle. */
|
|
101
|
+
host?: HostScopeRegistry;
|
|
102
|
+
/** Every other scope the folder declares, checked with warnings and never bundled. */
|
|
103
|
+
external: ScopeSpec[];
|
|
104
|
+
/** Where the project's host scopes and the folder disagree. */
|
|
105
|
+
notes: HostScopeNote[];
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The project's host scopes and the folder's other scopes, from a project and its game's merged
|
|
109
|
+
* scopes. With no folder the host scopes are the project's own, untouched (the same object, so a
|
|
110
|
+
* bundle's hash doesn't move), and there is nothing external.
|
|
111
|
+
*/
|
|
112
|
+
declare function projectScopes(project: ProjectFile, merged?: MergedScopes): ProjectScopes;
|
|
113
|
+
/**
|
|
114
|
+
* The folder's scopes that a compile treats as external, given the host spec it is using: every merged
|
|
115
|
+
* scope except Patter's own and the host spec's tokens. Empty with no folder.
|
|
116
|
+
*/
|
|
117
|
+
declare function externalGameScopes(strict: ScopeRegistrySpec | undefined, merged?: MergedScopes): ScopeSpec[];
|
|
118
|
+
|
|
119
|
+
export { type ConditionIssue, type ExportInput, type HostScopeNote, PATTER_SCOPE, type ProjectScopes, type ValidateOptions, compileExpression, exportBundle, externalGameScopes, projectScopes, validateConditions, validateInterpolation };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { ScopeRegistrySpec } from '@wildwinter/scoperegistry';
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { ScopeRegistrySpec, ScopeSpec } from '@wildwinter/scoperegistry';
|
|
2
|
+
import { MergedScopes } from '@wildwinter/scoperegistry/scopes';
|
|
3
|
+
import { Expression, ProjectFile, Scene, LocaleFile, Bundle, HostScopeRegistry } from '@patterkit/model';
|
|
4
|
+
export { EXTERNAL_SCOPES, hostScopesToSpec } from '@patterkit/dialect';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Compile a condition/effect `src` string to the bundle `{ src, ast }` envelope.
|
|
@@ -8,6 +9,17 @@ export { hostScopesToSpec } from '@patterkit/dialect';
|
|
|
8
9
|
* a storylet's `@world`); the parser needs every referenced scope registered.
|
|
9
10
|
*/
|
|
10
11
|
declare function compileExpression(src: string, foreign?: ScopeRegistrySpec): Expression;
|
|
12
|
+
/**
|
|
13
|
+
* What the validators take besides the project. `foreignScopes` is the host spec, checked strictly (a
|
|
14
|
+
* project's own `@world`, or another owner's spec). `gameScopes` is the game's merged `game-scopes/`
|
|
15
|
+
* folder: every scope in it the host spec doesn't hold is checked too, but only ever with WARNINGS
|
|
16
|
+
* (patterkit/design/shared-scopes.md decision 3). Given `gameScopes` and no `foreignScopes`, the host
|
|
17
|
+
* spec is the project's host scopes as the folder leaves them (`projectScopes`).
|
|
18
|
+
*/
|
|
19
|
+
interface ValidateOptions {
|
|
20
|
+
foreignScopes?: ScopeRegistrySpec;
|
|
21
|
+
gameScopes?: MergedScopes;
|
|
22
|
+
}
|
|
11
23
|
interface ConditionIssue {
|
|
12
24
|
/** Id of the node whose expression has the issue. */
|
|
13
25
|
nodeId: string;
|
|
@@ -31,9 +43,7 @@ interface ConditionIssue {
|
|
|
31
43
|
declare function validateConditions(input: {
|
|
32
44
|
project: ProjectFile;
|
|
33
45
|
scenes: Scene[];
|
|
34
|
-
}, options?:
|
|
35
|
-
foreignScopes?: ScopeRegistrySpec;
|
|
36
|
-
}): ConditionIssue[];
|
|
46
|
+
}, options?: ValidateOptions): ConditionIssue[];
|
|
37
47
|
/**
|
|
38
48
|
* Validate inline `{@ref}` interpolation slots in a project's localised strings
|
|
39
49
|
* (spec §16). Enforces the VO-safety guarantee - **a voiced project rejects any
|
|
@@ -50,9 +60,7 @@ declare function validateInterpolation(input: {
|
|
|
50
60
|
project: ProjectFile;
|
|
51
61
|
scenes: Scene[];
|
|
52
62
|
locales?: LocaleFile[];
|
|
53
|
-
}, options?:
|
|
54
|
-
foreignScopes?: ScopeRegistrySpec;
|
|
55
|
-
}): ConditionIssue[];
|
|
63
|
+
}, options?: ValidateOptions): ConditionIssue[];
|
|
56
64
|
|
|
57
65
|
interface ExportInput {
|
|
58
66
|
project: ProjectFile;
|
|
@@ -67,8 +75,45 @@ interface ExportInput {
|
|
|
67
75
|
* unregistered scope token, so cross-engine refs need this.
|
|
68
76
|
*/
|
|
69
77
|
foreignScopes?: ScopeRegistrySpec;
|
|
78
|
+
/**
|
|
79
|
+
* The game's merged `game-scopes/` folder, when the project has one (patterkit/design/shared-scopes.md).
|
|
80
|
+
* Its `game.scopes.json` wins over the project's copy of a host scope, and its `@world` is baked in
|
|
81
|
+
* even when the project doesn't declare it; every other scope in it compiles as another engine's
|
|
82
|
+
* does: named in `externalScopes`, never baked in.
|
|
83
|
+
*/
|
|
84
|
+
gameScopes?: MergedScopes;
|
|
70
85
|
}
|
|
71
86
|
/** Compile a project's source into the runtime bundle. */
|
|
72
87
|
declare function exportBundle(input: ExportInput): Bundle;
|
|
73
88
|
|
|
74
|
-
|
|
89
|
+
/** Patter's own game-wide token: the one scope Patter writes to the folder and never reads back. */
|
|
90
|
+
declare const PATTER_SCOPE = "patter";
|
|
91
|
+
/** Something the folder says about the project's host scopes: a warning, anchored to a scopes file. */
|
|
92
|
+
interface HostScopeNote {
|
|
93
|
+
token: string;
|
|
94
|
+
/** The scopes file it concerns, by name (`game.scopes.json`). */
|
|
95
|
+
file: string;
|
|
96
|
+
message: string;
|
|
97
|
+
}
|
|
98
|
+
/** A project's scopes once its game's folder is taken into account. */
|
|
99
|
+
interface ProjectScopes {
|
|
100
|
+
/** The host scopes the compile treats as the project's: validated strictly, baked into the bundle. */
|
|
101
|
+
host?: HostScopeRegistry;
|
|
102
|
+
/** Every other scope the folder declares, checked with warnings and never bundled. */
|
|
103
|
+
external: ScopeSpec[];
|
|
104
|
+
/** Where the project's host scopes and the folder disagree. */
|
|
105
|
+
notes: HostScopeNote[];
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The project's host scopes and the folder's other scopes, from a project and its game's merged
|
|
109
|
+
* scopes. With no folder the host scopes are the project's own, untouched (the same object, so a
|
|
110
|
+
* bundle's hash doesn't move), and there is nothing external.
|
|
111
|
+
*/
|
|
112
|
+
declare function projectScopes(project: ProjectFile, merged?: MergedScopes): ProjectScopes;
|
|
113
|
+
/**
|
|
114
|
+
* The folder's scopes that a compile treats as external, given the host spec it is using: every merged
|
|
115
|
+
* scope except Patter's own and the host spec's tokens. Empty with no folder.
|
|
116
|
+
*/
|
|
117
|
+
declare function externalGameScopes(strict: ScopeRegistrySpec | undefined, merged?: MergedScopes): ScopeSpec[];
|
|
118
|
+
|
|
119
|
+
export { type ConditionIssue, type ExportInput, type HostScopeNote, PATTER_SCOPE, type ProjectScopes, type ValidateOptions, compileExpression, exportBundle, externalGameScopes, projectScopes, validateConditions, validateInterpolation };
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,101 @@
|
|
|
1
1
|
// src/expressions.ts
|
|
2
2
|
import { compile, parse, validateExpr } from "@wildwinter/expr";
|
|
3
|
-
import { dialectWithForeignScopes, buildSchema, extractSlots, splitRef } from "@patterkit/dialect";
|
|
3
|
+
import { dialectWithForeignScopes, buildSchema, extractSlots, splitRef, withEngineScopes, hostScopesToSpec as hostScopesToSpec2 } from "@patterkit/dialect";
|
|
4
|
+
import { referenceNote } from "@wildwinter/scoperegistry/scopes";
|
|
5
|
+
|
|
6
|
+
// src/game-scopes.ts
|
|
7
|
+
import { GAME_SCOPES_DIR, GAME_SCOPES_FILE } from "@wildwinter/scoperegistry/scopes";
|
|
8
|
+
import { hostScopesToSpec } from "@patterkit/dialect";
|
|
9
|
+
var PATTER_SCOPE = "patter";
|
|
10
|
+
function asHostScope(s) {
|
|
11
|
+
return {
|
|
12
|
+
token: s.token,
|
|
13
|
+
...s.writable !== void 0 ? { writable: s.writable } : {},
|
|
14
|
+
...s.declarations ? { declarations: s.declarations.map((d) => ({ ...d })) } : {}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function sameScope(a, b) {
|
|
18
|
+
const norm = (s) => JSON.stringify(hostScopesToSpec({ version: 1, scopes: [s] }));
|
|
19
|
+
return norm(a) === norm(b);
|
|
20
|
+
}
|
|
21
|
+
function projectScopes(project, merged) {
|
|
22
|
+
const own = project.scopeRegistry;
|
|
23
|
+
if (!merged) return { host: own, external: [], notes: [] };
|
|
24
|
+
const notes = [];
|
|
25
|
+
const hosted = [];
|
|
26
|
+
const bundled = /* @__PURE__ */ new Set();
|
|
27
|
+
let changed = false;
|
|
28
|
+
const shared = (token) => token === PATTER_SCOPE ? void 0 : merged.spec.scopes.find((s) => s.token === token);
|
|
29
|
+
for (const h of own?.scopes ?? []) {
|
|
30
|
+
const s = shared(h.token);
|
|
31
|
+
const who = merged.owners.get(h.token);
|
|
32
|
+
if (!s || !who) {
|
|
33
|
+
hosted.push(h);
|
|
34
|
+
bundled.add(h.token);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (who.fileName === GAME_SCOPES_FILE) {
|
|
38
|
+
const fromFile = asHostScope(s);
|
|
39
|
+
hosted.push(fromFile);
|
|
40
|
+
bundled.add(h.token);
|
|
41
|
+
changed = true;
|
|
42
|
+
if (!sameScope(h, fromFile)) {
|
|
43
|
+
notes.push({
|
|
44
|
+
token: h.token,
|
|
45
|
+
file: who.fileName,
|
|
46
|
+
message: `@${h.token} in World properties differs from ${GAME_SCOPES_DIR}/${who.fileName}, and the shared file wins: saving Project Settings in Patterpad brings the project's copy up to date`
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
changed = true;
|
|
51
|
+
notes.push({
|
|
52
|
+
token: h.token,
|
|
53
|
+
file: who.fileName,
|
|
54
|
+
message: `@${h.token} is declared in ${GAME_SCOPES_DIR}/${who.fileName}; remove it from World properties`
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const world = shared("world");
|
|
59
|
+
if (world && merged.owners.get("world")?.fileName === GAME_SCOPES_FILE && !bundled.has("world")) {
|
|
60
|
+
hosted.push(asHostScope(world));
|
|
61
|
+
bundled.add("world");
|
|
62
|
+
changed = true;
|
|
63
|
+
}
|
|
64
|
+
const external = merged.spec.scopes.filter((s) => s.token !== PATTER_SCOPE && !bundled.has(s.token));
|
|
65
|
+
const host = !changed ? own : hosted.length ? { version: own?.version ?? 1, scopes: hosted } : void 0;
|
|
66
|
+
return { host, external, notes };
|
|
67
|
+
}
|
|
68
|
+
function externalGameScopes(strict, merged) {
|
|
69
|
+
if (!merged) return [];
|
|
70
|
+
const hostTokens = new Set((strict?.scopes ?? []).map((s) => s.token));
|
|
71
|
+
return merged.spec.scopes.filter((s) => s.token !== PATTER_SCOPE && !hostTokens.has(s.token));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/expressions.ts
|
|
4
75
|
import { walkNodes } from "@patterkit/model";
|
|
5
76
|
function compileExpression(src, foreign) {
|
|
6
77
|
return compile(src, dialectWithForeignScopes(foreign));
|
|
7
78
|
}
|
|
79
|
+
function validationScopes(project, options) {
|
|
80
|
+
const merged = options.gameScopes;
|
|
81
|
+
const strict = options.foreignScopes ?? (merged ? hostScopesToSpec2(projectScopes(project, merged).host) : void 0);
|
|
82
|
+
const external = externalGameScopes(strict, merged);
|
|
83
|
+
const base = strict?.scopes ?? [];
|
|
84
|
+
const foreign = withEngineScopes({ version: strict?.version ?? 1, scopes: [...base, ...external.map((s) => ({ token: s.token }))] });
|
|
85
|
+
const checked = external.some((s) => s.declarations?.length) ? withEngineScopes({ version: strict?.version ?? 1, scopes: [...base, ...external] }) : void 0;
|
|
86
|
+
return { foreign, checked, external: new Set(external.map((s) => s.token)), merged };
|
|
87
|
+
}
|
|
88
|
+
var issueKey = (i) => `${i.kind}|${JSON.stringify(i.path)}|${i.message}`;
|
|
89
|
+
function externalMessage(i, merged) {
|
|
90
|
+
if (merged && i.kind === "unresolved-scoped-property" && i.reference) {
|
|
91
|
+
const [token, name] = i.reference.split(".");
|
|
92
|
+
if (token && name) return referenceNote(merged, token, name) ?? i.message;
|
|
93
|
+
}
|
|
94
|
+
return i.message;
|
|
95
|
+
}
|
|
8
96
|
function validateConditions(input, options = {}) {
|
|
9
97
|
const issues = [];
|
|
10
|
-
const foreign = options
|
|
98
|
+
const { foreign, checked, external, merged } = validationScopes(input.project, options);
|
|
11
99
|
const dialect = dialectWithForeignScopes(foreign);
|
|
12
100
|
const readOnly = readOnlyForeignTargets(foreign);
|
|
13
101
|
const opaqueForeign = opaqueForeignTokens(foreign);
|
|
@@ -31,6 +119,7 @@ function validateConditions(input, options = {}) {
|
|
|
31
119
|
};
|
|
32
120
|
const validateElement = (blocks, sceneProps, onEntry, elementId) => {
|
|
33
121
|
const schema = buildSchema(input.project, sceneProps, foreign);
|
|
122
|
+
const checkedSchema = checked ? buildSchema(input.project, sceneProps, checked) : void 0;
|
|
34
123
|
const check = (nodeId, field, src) => {
|
|
35
124
|
let ast;
|
|
36
125
|
try {
|
|
@@ -39,9 +128,16 @@ function validateConditions(input, options = {}) {
|
|
|
39
128
|
issues.push({ nodeId, field, src, severity: "error", message: e instanceof Error ? e.message : String(e) });
|
|
40
129
|
return;
|
|
41
130
|
}
|
|
42
|
-
|
|
131
|
+
const strict = validateExpr(ast, schema, dialect);
|
|
132
|
+
for (const iss of strict) {
|
|
43
133
|
issues.push({ nodeId, field, src, severity: iss.severity, message: iss.message });
|
|
44
134
|
}
|
|
135
|
+
if (checkedSchema) {
|
|
136
|
+
const seen = new Set(strict.map(issueKey));
|
|
137
|
+
for (const iss of validateExpr(ast, checkedSchema, dialect)) {
|
|
138
|
+
if (!seen.has(issueKey(iss))) issues.push({ nodeId, field, src, severity: "warning", message: externalMessage(iss, merged) });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
45
141
|
checkVisitIds(ast, nodeId, field, src);
|
|
46
142
|
};
|
|
47
143
|
const checkTarget = (nodeId, field, target) => {
|
|
@@ -66,6 +162,11 @@ function validateConditions(input, options = {}) {
|
|
|
66
162
|
return;
|
|
67
163
|
}
|
|
68
164
|
const { scope, name } = splitRef(target, isScopeToken);
|
|
165
|
+
if (external.has(scope)) {
|
|
166
|
+
const note = merged ? referenceNote(merged, scope, name, { write: true }) : void 0;
|
|
167
|
+
if (note) issues.push({ nodeId, field, src: target, severity: "warning", message: note });
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
69
170
|
if (opaqueForeign.has(scope)) return;
|
|
70
171
|
if (!schema.properties.get(scope)?.has(name)) {
|
|
71
172
|
issues.push({
|
|
@@ -102,12 +203,14 @@ function validateInterpolation(input, options = {}) {
|
|
|
102
203
|
const voiced = input.project.voiced ?? false;
|
|
103
204
|
const tables = (input.locales ?? []).map((l) => ({ locale: l.locale, strings: l.strings }));
|
|
104
205
|
const defaultLocale = input.project.locales.default;
|
|
105
|
-
const
|
|
106
|
-
const
|
|
206
|
+
const { foreign, external, merged } = validationScopes(input.project, options);
|
|
207
|
+
const opaqueForeign = opaqueForeignTokens(foreign);
|
|
208
|
+
const isScopeToken = scopeTokenTest(foreign);
|
|
107
209
|
for (const scene of input.scenes) {
|
|
108
|
-
const schema = buildSchema(input.project, scene.sceneProps,
|
|
210
|
+
const schema = buildSchema(input.project, scene.sceneProps, foreign);
|
|
109
211
|
const known = (ref) => {
|
|
110
212
|
const { scope, name } = splitRef(ref, isScopeToken);
|
|
213
|
+
if (external.has(scope)) return (merged ? referenceNote(merged, scope, name) : void 0) ?? true;
|
|
111
214
|
if (opaqueForeign.has(scope)) return true;
|
|
112
215
|
return schema.properties.get(scope)?.has(name) ?? false;
|
|
113
216
|
};
|
|
@@ -137,7 +240,10 @@ function validateInterpolation(input, options = {}) {
|
|
|
137
240
|
});
|
|
138
241
|
continue;
|
|
139
242
|
}
|
|
140
|
-
|
|
243
|
+
const ok = known(slot.ref);
|
|
244
|
+
if (typeof ok === "string") {
|
|
245
|
+
issues.push({ nodeId, field, src: slot.raw, severity: "warning", message: ok });
|
|
246
|
+
} else if (!ok) {
|
|
141
247
|
issues.push({
|
|
142
248
|
nodeId,
|
|
143
249
|
field,
|
|
@@ -201,11 +307,11 @@ function readOnlyForeignTargets(spec) {
|
|
|
201
307
|
}
|
|
202
308
|
|
|
203
309
|
// src/index.ts
|
|
204
|
-
import { hostScopesToSpec as
|
|
310
|
+
import { hostScopesToSpec as hostScopesToSpec4, EXTERNAL_SCOPES as EXTERNAL_SCOPES2 } from "@patterkit/dialect";
|
|
205
311
|
|
|
206
312
|
// src/export.ts
|
|
207
313
|
import { canonicalStringify, hash32 } from "@patterkit/core";
|
|
208
|
-
import { hostScopesToSpec } from "@patterkit/dialect";
|
|
314
|
+
import { hostScopesToSpec as hostScopesToSpec3, withEngineScopes as withEngineScopes2, EXTERNAL_SCOPES } from "@patterkit/dialect";
|
|
209
315
|
function compileEffect(e, foreign) {
|
|
210
316
|
return { kind: "set", target: e.target, value: compileExpression(e.value, foreign) };
|
|
211
317
|
}
|
|
@@ -273,11 +379,37 @@ function compileScene(scene, foreign) {
|
|
|
273
379
|
blocks: scene.blocks.map((b) => compileBlock(b, foreign))
|
|
274
380
|
};
|
|
275
381
|
}
|
|
382
|
+
function externalScopesIn(scenes, external) {
|
|
383
|
+
const found = /* @__PURE__ */ new Set();
|
|
384
|
+
const walk = (node) => {
|
|
385
|
+
if (!Array.isArray(node) && (node === null || typeof node !== "object")) return;
|
|
386
|
+
if (Array.isArray(node)) {
|
|
387
|
+
if (node[0] === "sv" && typeof node[1] === "string" && external.has(node[1])) found.add(node[1]);
|
|
388
|
+
for (const n of node) walk(n);
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
const o = node;
|
|
392
|
+
if (o["kind"] === "set" && typeof o["target"] === "string") {
|
|
393
|
+
const head = o["target"].replace(/^@/, "").split(".")[0];
|
|
394
|
+
if (o["target"].includes(".") && external.has(head)) found.add(head);
|
|
395
|
+
}
|
|
396
|
+
for (const v of Object.values(o)) walk(v);
|
|
397
|
+
};
|
|
398
|
+
walk(scenes);
|
|
399
|
+
return [...found].sort();
|
|
400
|
+
}
|
|
276
401
|
function exportBundle(input) {
|
|
277
402
|
const { project, scenes, locales = [], includeLocales } = input;
|
|
278
|
-
const
|
|
403
|
+
const hostScopes = projectScopes(project, input.gameScopes).host;
|
|
404
|
+
const foreignScopes = input.foreignScopes ?? hostScopesToSpec3(hostScopes);
|
|
405
|
+
const gameExternal = externalGameScopes(foreignScopes, input.gameScopes);
|
|
406
|
+
const compileScopes = withEngineScopes2({
|
|
407
|
+
version: foreignScopes?.version ?? 1,
|
|
408
|
+
scopes: [...foreignScopes?.scopes ?? [], ...gameExternal.map((s) => ({ token: s.token }))]
|
|
409
|
+
});
|
|
279
410
|
const scenesOut = {};
|
|
280
|
-
for (const scene of scenes) scenesOut[scene.id] = compileScene(scene,
|
|
411
|
+
for (const scene of scenes) scenesOut[scene.id] = compileScene(scene, compileScopes);
|
|
412
|
+
const externalScopes = externalScopesIn(scenesOut, /* @__PURE__ */ new Set([...EXTERNAL_SCOPES, ...gameExternal.map((s) => s.token)]));
|
|
281
413
|
const strings = {};
|
|
282
414
|
for (const loc of locales) {
|
|
283
415
|
if (includeLocales && !includeLocales.includes(loc.locale)) continue;
|
|
@@ -327,19 +459,25 @@ function exportBundle(input) {
|
|
|
327
459
|
return m;
|
|
328
460
|
}),
|
|
329
461
|
properties: project.properties,
|
|
330
|
-
scopeRegistry:
|
|
462
|
+
scopeRegistry: hostScopes,
|
|
331
463
|
gameDataFields: project.gameDataFields,
|
|
332
464
|
// Closed-caption delimiters ride along only when the project pins a non-default pair (#214); the
|
|
333
465
|
// runtime falls back to `[` / `]` when absent, so default projects keep their exact prior bundle.
|
|
334
466
|
...project.closedCaptions ? { closedCaptions: project.closedCaptions } : {},
|
|
335
467
|
scenes: scenesOut,
|
|
336
|
-
strings
|
|
468
|
+
strings,
|
|
469
|
+
// Other engines' scopes the content names, so the engine can say when the game has not registered one.
|
|
470
|
+
...externalScopes.length > 0 ? { externalScopes } : {}
|
|
337
471
|
};
|
|
338
472
|
}
|
|
339
473
|
export {
|
|
474
|
+
EXTERNAL_SCOPES2 as EXTERNAL_SCOPES,
|
|
475
|
+
PATTER_SCOPE,
|
|
340
476
|
compileExpression,
|
|
341
477
|
exportBundle,
|
|
342
|
-
|
|
478
|
+
externalGameScopes,
|
|
479
|
+
hostScopesToSpec4 as hostScopesToSpec,
|
|
480
|
+
projectScopes,
|
|
343
481
|
validateConditions,
|
|
344
482
|
validateInterpolation
|
|
345
483
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patterkit/compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Patter compiler: compile condition/effect expressions, validate them, and export source to the runtime bundle.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"build": "tsup src/index.ts --format esm,cjs --dts --clean"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@patterkit/model": "0.
|
|
38
|
-
"@patterkit/core": "0.2.
|
|
39
|
-
"@patterkit/dialect": "0.1
|
|
37
|
+
"@patterkit/model": "0.7.0",
|
|
38
|
+
"@patterkit/core": "0.2.6",
|
|
39
|
+
"@patterkit/dialect": "0.2.1",
|
|
40
40
|
"@wildwinter/expr": "^0.5.0",
|
|
41
|
-
"@wildwinter/scoperegistry": "^0.
|
|
41
|
+
"@wildwinter/scoperegistry": "^0.8.0"
|
|
42
42
|
}
|
|
43
43
|
}
|