@patterkit/compiler 0.13.0 → 0.14.1

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 CHANGED
@@ -430,18 +430,17 @@ function extensionPass(input) {
430
430
  for (const [id, entry] of Object.entries(taken)) {
431
431
  const m = manifests.get(id);
432
432
  const version = typeof entry?.version === "string" ? entry.version : "";
433
- const settings = entry?.settings ?? {};
434
433
  if (m === void 0) {
435
434
  issues.push({
436
435
  severity: "warning",
437
436
  file: projectPath,
438
437
  message: `the project takes the Patter extension "${id}", but has no manifest for it at ${import_model2.EXTENSIONS_DIR}/${id}${import_model2.MANIFEST_EXTENSION}; its data is left as it is, and not compiled`
439
438
  });
440
- takenList.push({ id, settings });
439
+ takenList.push({ id });
441
440
  continue;
442
441
  }
443
442
  if (!m.sound) {
444
- takenList.push({ id, settings });
443
+ takenList.push({ id });
445
444
  continue;
446
445
  }
447
446
  const manifest = m.manifest;
@@ -452,25 +451,20 @@ function extensionPass(input) {
452
451
  message: `the project takes "${id}" ${version === "" ? "with no version" : `at version ${version}`}, but its manifest is version ${manifest.version}; run \`patter format\` to take it (renamed stages are renamed in the data as it does)`
453
452
  });
454
453
  }
455
- const known = new Set((manifest.settings ?? []).map((s) => s.name));
456
- for (const [name, value] of Object.entries(settings)) {
457
- if (!known.has(name)) {
458
- issues.push({ severity: "warning", file: projectPath, message: `"${id}" has no setting "${name}"; it's ignored` });
459
- } else if (typeof value !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
460
- issues.push({
461
- severity: "error",
462
- file: projectPath,
463
- message: `"${id}"'s setting "${name}" names a gameData field, so it's a field name, not ${JSON.stringify(value)}`
464
- });
465
- }
466
- }
467
- takenList.push({ id, settings, manifest });
454
+ takenList.push({ id, manifest });
468
455
  }
469
456
  const sound = new Map(takenList.filter((t) => t.manifest !== void 0).map((t) => [t.id, t.manifest]));
457
+ for (const [id, manifest] of sound) {
458
+ for (const req of (0, import_extensions.missingRequirements)(manifest, Object.keys(taken))) {
459
+ issues.push({
460
+ severity: "warning",
461
+ file: projectPath,
462
+ code: "requires-missing",
463
+ message: `the project takes "${id}", which requires the extension "${req}", but doesn't take it; add "${req}" to the project, or ${manifest.name} won't work in the game`
464
+ });
465
+ }
466
+ }
470
467
  const nodes = extensionNodes(project, scenes);
471
- const claims = takenList.flatMap((t) => t.manifest ? (0, import_extensions.resolvedClaims)(t.manifest, "patter", t.settings) : []);
472
- for (const p of (0, import_extensions.claimClashes)(claims)) issues.push({ severity: p.severity, file: projectPath, code: p.code, message: p.message });
473
- issues.push(...claimIssues(input, nodes, claims));
474
468
  const exists = (kind, id) => kind === "cast" ? (project.cast ?? []).some((c) => c.name === id) : nodes.get(id)?.kind === kind;
475
469
  const projectId = project.project.id;
476
470
  const projectEntries = /* @__PURE__ */ new Map();
@@ -578,7 +572,6 @@ function extensionPass(input) {
578
572
  }
579
573
  }
580
574
  const bundle = {};
581
- const chosen = new Map(takenList.map((t) => [t.id, t.settings]));
582
575
  for (const [id, manifest] of [...sound.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) {
583
576
  const fields = {};
584
577
  for (const kind of Object.keys(manifest.targets.patter ?? {}).sort()) {
@@ -586,13 +579,7 @@ function extensionPass(input) {
586
579
  if (target !== void 0) fields[kind] = (0, import_extensions.compiledTarget)(target);
587
580
  }
588
581
  const projectEntry = projectValues.get(id);
589
- const settings = (manifest.settings ?? []).length > 0 ? sortRecord((0, import_extensions.settingValues)(manifest, chosen.get(id))) : void 0;
590
- bundle[id] = {
591
- version: manifest.version,
592
- fields,
593
- ...projectEntry !== void 0 ? { project: projectEntry } : {},
594
- ...settings !== void 0 ? { settings } : {}
595
- };
582
+ bundle[id] = { version: manifest.version, fields, ...projectEntry !== void 0 ? { project: projectEntry } : {} };
596
583
  }
597
584
  const sortedNodes = new Map([...values.entries()].map(([id, v]) => [id, sortRecord(v)]));
598
585
  return { issues, compiled: { bundle, nodes: sortedNodes } };
@@ -610,45 +597,6 @@ function pickDecls(manifest) {
610
597
  function sortRecord(r) {
611
598
  return Object.fromEntries(Object.keys(r).sort().map((k) => [k, r[k]]));
612
599
  }
613
- function claimIssues(input, nodes, claims) {
614
- const issues = [];
615
- const projectPath = input.projectPath ?? "";
616
- const declared = input.project.gameDataFields ?? {};
617
- for (const claim of claims) {
618
- const decl = (declared[claim.kind] ?? []).find((d) => d.name === claim.field);
619
- if (decl === void 0) {
620
- issues.push({
621
- severity: "warning",
622
- file: projectPath,
623
- message: `the Patter extension "${claim.extension}" claims the ${claim.kind} gameData field "${claim.field}", which the project doesn't declare`
624
- });
625
- continue;
626
- }
627
- if (decl.type !== claim.claim.type) {
628
- issues.push({
629
- severity: "error",
630
- file: projectPath,
631
- message: `the Patter extension "${claim.extension}" claims the ${claim.kind} gameData field "${claim.field}" as ${claim.claim.type}, but the project declares it as ${decl.type}`
632
- });
633
- continue;
634
- }
635
- const effective = (0, import_extensions.effectiveClaim)(claim.claim, decl);
636
- for (const [id, node] of nodes) {
637
- if (node.kind !== claim.kind || node.gameData === void 0 || !own(node.gameData, claim.field)) continue;
638
- const file = (node.scene !== void 0 ? input.sceneFiles?.[node.scene] : void 0) ?? projectPath;
639
- for (const p of (0, import_extensions.valueProblems)(effective, node.gameData[claim.field])) {
640
- issues.push({
641
- severity: p.severity,
642
- file,
643
- node: id,
644
- code: p.code,
645
- message: `${claim.kind} '${id}' gameData "${claim.field}", as the Patter extension "${claim.extension}" claims it: ${p.message}`
646
- });
647
- }
648
- }
649
- }
650
- return issues;
651
- }
652
600
 
653
601
  // src/export.ts
654
602
  function compileBeat(beat, ctx, asAction = false) {
@@ -877,8 +825,7 @@ function exportBundle(input) {
877
825
  Object.entries(project.gameDataFields).map(([kind, fields]) => [kind, resolved(fields)])
878
826
  ),
879
827
  // The extensions the project takes: each one's version, its compiled declarations by node kind (every
880
- // default resolved, editor-only fields and the editor's words left out), the project node's values, and
881
- // its settings, each the project's value or else the default.
828
+ // default resolved, editor-only fields and the editor's words left out), and the project node's values.
882
829
  ...extensionSection !== void 0 ? { extensions: extensionSection } : {},
883
830
  // Closed-caption delimiters ride along only when the project pins a non-default pair (#214); the
884
831
  // runtime falls back to `[` / `]` when absent, so default projects keep their exact prior bundle.
package/dist/index.js CHANGED
@@ -321,19 +321,15 @@ import { textIsAction, usedQualifiers, usedSpeakerPairs, walkNodes as walkNodes2
321
321
  import { EXTENSIONS_DIR, MANIFEST_EXTENSION, PROJECT_LOCALE_SCENE } from "@patterkit/model";
322
322
  import {
323
323
  HOSTS,
324
- claimClashes,
325
324
  compileEntry,
326
325
  compiledTarget,
327
- effectiveClaim,
328
326
  entryProblems,
329
327
  manifestProblems,
328
+ missingRequirements,
330
329
  orphanedEntries,
331
330
  pickClashes,
332
331
  pickLists,
333
- resolvedClaims,
334
- settingValues,
335
- targetOf,
336
- valueProblems
332
+ targetOf
337
333
  } from "@wildwinter/toolkit/extensions";
338
334
  function extensionNodes(project, scenes) {
339
335
  const nodes = /* @__PURE__ */ new Map();
@@ -409,18 +405,17 @@ function extensionPass(input) {
409
405
  for (const [id, entry] of Object.entries(taken)) {
410
406
  const m = manifests.get(id);
411
407
  const version = typeof entry?.version === "string" ? entry.version : "";
412
- const settings = entry?.settings ?? {};
413
408
  if (m === void 0) {
414
409
  issues.push({
415
410
  severity: "warning",
416
411
  file: projectPath,
417
412
  message: `the project takes the Patter extension "${id}", but has no manifest for it at ${EXTENSIONS_DIR}/${id}${MANIFEST_EXTENSION}; its data is left as it is, and not compiled`
418
413
  });
419
- takenList.push({ id, settings });
414
+ takenList.push({ id });
420
415
  continue;
421
416
  }
422
417
  if (!m.sound) {
423
- takenList.push({ id, settings });
418
+ takenList.push({ id });
424
419
  continue;
425
420
  }
426
421
  const manifest = m.manifest;
@@ -431,25 +426,20 @@ function extensionPass(input) {
431
426
  message: `the project takes "${id}" ${version === "" ? "with no version" : `at version ${version}`}, but its manifest is version ${manifest.version}; run \`patter format\` to take it (renamed stages are renamed in the data as it does)`
432
427
  });
433
428
  }
434
- const known = new Set((manifest.settings ?? []).map((s) => s.name));
435
- for (const [name, value] of Object.entries(settings)) {
436
- if (!known.has(name)) {
437
- issues.push({ severity: "warning", file: projectPath, message: `"${id}" has no setting "${name}"; it's ignored` });
438
- } else if (typeof value !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
439
- issues.push({
440
- severity: "error",
441
- file: projectPath,
442
- message: `"${id}"'s setting "${name}" names a gameData field, so it's a field name, not ${JSON.stringify(value)}`
443
- });
444
- }
445
- }
446
- takenList.push({ id, settings, manifest });
429
+ takenList.push({ id, manifest });
447
430
  }
448
431
  const sound = new Map(takenList.filter((t) => t.manifest !== void 0).map((t) => [t.id, t.manifest]));
432
+ for (const [id, manifest] of sound) {
433
+ for (const req of missingRequirements(manifest, Object.keys(taken))) {
434
+ issues.push({
435
+ severity: "warning",
436
+ file: projectPath,
437
+ code: "requires-missing",
438
+ message: `the project takes "${id}", which requires the extension "${req}", but doesn't take it; add "${req}" to the project, or ${manifest.name} won't work in the game`
439
+ });
440
+ }
441
+ }
449
442
  const nodes = extensionNodes(project, scenes);
450
- const claims = takenList.flatMap((t) => t.manifest ? resolvedClaims(t.manifest, "patter", t.settings) : []);
451
- for (const p of claimClashes(claims)) issues.push({ severity: p.severity, file: projectPath, code: p.code, message: p.message });
452
- issues.push(...claimIssues(input, nodes, claims));
453
443
  const exists = (kind, id) => kind === "cast" ? (project.cast ?? []).some((c) => c.name === id) : nodes.get(id)?.kind === kind;
454
444
  const projectId = project.project.id;
455
445
  const projectEntries = /* @__PURE__ */ new Map();
@@ -557,7 +547,6 @@ function extensionPass(input) {
557
547
  }
558
548
  }
559
549
  const bundle = {};
560
- const chosen = new Map(takenList.map((t) => [t.id, t.settings]));
561
550
  for (const [id, manifest] of [...sound.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) {
562
551
  const fields = {};
563
552
  for (const kind of Object.keys(manifest.targets.patter ?? {}).sort()) {
@@ -565,13 +554,7 @@ function extensionPass(input) {
565
554
  if (target !== void 0) fields[kind] = compiledTarget(target);
566
555
  }
567
556
  const projectEntry = projectValues.get(id);
568
- const settings = (manifest.settings ?? []).length > 0 ? sortRecord(settingValues(manifest, chosen.get(id))) : void 0;
569
- bundle[id] = {
570
- version: manifest.version,
571
- fields,
572
- ...projectEntry !== void 0 ? { project: projectEntry } : {},
573
- ...settings !== void 0 ? { settings } : {}
574
- };
557
+ bundle[id] = { version: manifest.version, fields, ...projectEntry !== void 0 ? { project: projectEntry } : {} };
575
558
  }
576
559
  const sortedNodes = new Map([...values.entries()].map(([id, v]) => [id, sortRecord(v)]));
577
560
  return { issues, compiled: { bundle, nodes: sortedNodes } };
@@ -589,45 +572,6 @@ function pickDecls(manifest) {
589
572
  function sortRecord(r) {
590
573
  return Object.fromEntries(Object.keys(r).sort().map((k) => [k, r[k]]));
591
574
  }
592
- function claimIssues(input, nodes, claims) {
593
- const issues = [];
594
- const projectPath = input.projectPath ?? "";
595
- const declared = input.project.gameDataFields ?? {};
596
- for (const claim of claims) {
597
- const decl = (declared[claim.kind] ?? []).find((d) => d.name === claim.field);
598
- if (decl === void 0) {
599
- issues.push({
600
- severity: "warning",
601
- file: projectPath,
602
- message: `the Patter extension "${claim.extension}" claims the ${claim.kind} gameData field "${claim.field}", which the project doesn't declare`
603
- });
604
- continue;
605
- }
606
- if (decl.type !== claim.claim.type) {
607
- issues.push({
608
- severity: "error",
609
- file: projectPath,
610
- message: `the Patter extension "${claim.extension}" claims the ${claim.kind} gameData field "${claim.field}" as ${claim.claim.type}, but the project declares it as ${decl.type}`
611
- });
612
- continue;
613
- }
614
- const effective = effectiveClaim(claim.claim, decl);
615
- for (const [id, node] of nodes) {
616
- if (node.kind !== claim.kind || node.gameData === void 0 || !own(node.gameData, claim.field)) continue;
617
- const file = (node.scene !== void 0 ? input.sceneFiles?.[node.scene] : void 0) ?? projectPath;
618
- for (const p of valueProblems(effective, node.gameData[claim.field])) {
619
- issues.push({
620
- severity: p.severity,
621
- file,
622
- node: id,
623
- code: p.code,
624
- message: `${claim.kind} '${id}' gameData "${claim.field}", as the Patter extension "${claim.extension}" claims it: ${p.message}`
625
- });
626
- }
627
- }
628
- }
629
- return issues;
630
- }
631
575
 
632
576
  // src/export.ts
633
577
  function compileBeat(beat, ctx, asAction = false) {
@@ -856,8 +800,7 @@ function exportBundle(input) {
856
800
  Object.entries(project.gameDataFields).map(([kind, fields]) => [kind, resolved(fields)])
857
801
  ),
858
802
  // The extensions the project takes: each one's version, its compiled declarations by node kind (every
859
- // default resolved, editor-only fields and the editor's words left out), the project node's values, and
860
- // its settings, each the project's value or else the default.
803
+ // default resolved, editor-only fields and the editor's words left out), and the project node's values.
861
804
  ...extensionSection !== void 0 ? { extensions: extensionSection } : {},
862
805
  // Closed-caption delimiters ride along only when the project pins a non-default pair (#214); the
863
806
  // runtime falls back to `[` / `]` when absent, so default projects keep their exact prior bundle.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patterkit/compiler",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
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,11 +34,11 @@
34
34
  "build": "tsup src/index.ts --format esm,cjs --dts --clean"
35
35
  },
36
36
  "dependencies": {
37
- "@patterkit/model": "0.19.0",
38
- "@patterkit/core": "0.9.4",
39
- "@patterkit/dialect": "0.2.16",
37
+ "@patterkit/model": "0.20.0",
38
+ "@patterkit/core": "0.9.6",
39
+ "@patterkit/dialect": "0.2.17",
40
40
  "@wildwinter/expr": "^0.6.0",
41
- "@wildwinter/toolkit": "^0.2.5"
41
+ "@wildwinter/toolkit": "^0.3.1"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@wildwinter/scoperegistry": ">=0.9.0 <1.0.0"