@hyperfixi/core 2.9.4 → 2.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.
Files changed (102) hide show
  1. package/dist/ast-utils/index.js +400 -89
  2. package/dist/ast-utils/index.mjs +400 -89
  3. package/dist/behaviors/index.js +2 -1
  4. package/dist/behaviors/index.mjs +2 -1
  5. package/dist/chunks/{bridge-DhmZ3Khh.js → bridge-De7lnU_9.js} +2 -2
  6. package/dist/chunks/browser-modular-DpHHlmJ0.js +2 -0
  7. package/dist/chunks/{index-DKrx4rv2.js → index-D6-8bcsy.js} +2 -2
  8. package/dist/commands/advanced/async.d.ts +0 -8
  9. package/dist/commands/advanced/js.d.ts +0 -8
  10. package/dist/commands/animation/measure.d.ts +0 -8
  11. package/dist/commands/animation/settle.d.ts +0 -8
  12. package/dist/commands/animation/start-view-transition.d.ts +0 -8
  13. package/dist/commands/animation/take.d.ts +0 -8
  14. package/dist/commands/animation/transition.d.ts +0 -8
  15. package/dist/commands/async/fetch.d.ts +0 -8
  16. package/dist/commands/async/wait.d.ts +0 -8
  17. package/dist/commands/behaviors/install.d.ts +0 -8
  18. package/dist/commands/content/append.d.ts +0 -8
  19. package/dist/commands/content/prepend.d.ts +0 -8
  20. package/dist/commands/control-flow/break.d.ts +0 -8
  21. package/dist/commands/control-flow/continue.d.ts +0 -8
  22. package/dist/commands/control-flow/exit.d.ts +0 -8
  23. package/dist/commands/control-flow/halt.d.ts +0 -8
  24. package/dist/commands/control-flow/if.d.ts +0 -8
  25. package/dist/commands/control-flow/repeat.d.ts +0 -8
  26. package/dist/commands/control-flow/return.d.ts +0 -8
  27. package/dist/commands/control-flow/throw.d.ts +0 -8
  28. package/dist/commands/data/clear.d.ts +0 -8
  29. package/dist/commands/data/default.d.ts +0 -8
  30. package/dist/commands/data/get.d.ts +0 -8
  31. package/dist/commands/data/increment.d.ts +0 -8
  32. package/dist/commands/data/set.d.ts +0 -8
  33. package/dist/commands/decorators/index.d.ts +2 -8
  34. package/dist/commands/dom/add.d.ts +0 -8
  35. package/dist/commands/dom/close.d.ts +0 -8
  36. package/dist/commands/dom/empty.d.ts +0 -8
  37. package/dist/commands/dom/hide.d.ts +0 -8
  38. package/dist/commands/dom/make.d.ts +0 -8
  39. package/dist/commands/dom/open.d.ts +0 -8
  40. package/dist/commands/dom/process-partials.d.ts +0 -8
  41. package/dist/commands/dom/put.d.ts +0 -8
  42. package/dist/commands/dom/remove.d.ts +0 -8
  43. package/dist/commands/dom/reset.d.ts +0 -8
  44. package/dist/commands/dom/select.d.ts +0 -8
  45. package/dist/commands/dom/show.d.ts +0 -8
  46. package/dist/commands/dom/swap.d.ts +2 -18
  47. package/dist/commands/dom/toggle.d.ts +0 -8
  48. package/dist/commands/events/trigger.d.ts +0 -8
  49. package/dist/commands/execution/blur.d.ts +0 -8
  50. package/dist/commands/execution/call.d.ts +0 -8
  51. package/dist/commands/execution/focus.d.ts +0 -8
  52. package/dist/commands/execution/pseudo-command.d.ts +0 -8
  53. package/dist/commands/helpers/dom-mutation.d.ts +3 -2
  54. package/dist/commands/helpers/index.d.ts +1 -1
  55. package/dist/commands/index.js +156 -31
  56. package/dist/commands/index.mjs +156 -31
  57. package/dist/commands/navigation/go.d.ts +0 -8
  58. package/dist/commands/navigation/push-url.d.ts +0 -8
  59. package/dist/commands/navigation/scroll-to.d.ts +0 -8
  60. package/dist/commands/templates/render.d.ts +0 -8
  61. package/dist/commands/utility/beep.d.ts +0 -8
  62. package/dist/commands/utility/breakpoint.d.ts +0 -8
  63. package/dist/commands/utility/copy.d.ts +0 -8
  64. package/dist/commands/utility/log.d.ts +0 -8
  65. package/dist/commands/utility/pick.d.ts +0 -8
  66. package/dist/commands/utility/tell.d.ts +0 -8
  67. package/dist/hyperfixi-browser-classic-i18n.js +1 -1
  68. package/dist/hyperfixi-browser-minimal.js +1 -1
  69. package/dist/hyperfixi-browser-standard.js +1 -1
  70. package/dist/hyperfixi-browser.js +1 -1
  71. package/dist/hyperfixi-classic-i18n.js +1 -1
  72. package/dist/hyperfixi-hx-v4.js +1 -1
  73. package/dist/hyperfixi-minimal.js +1 -1
  74. package/dist/hyperfixi-multilingual.js +1 -1
  75. package/dist/hyperfixi-standard.js +1 -1
  76. package/dist/hyperfixi.js +1 -1
  77. package/dist/hyperfixi.mjs +1 -1
  78. package/dist/index.js +660 -171
  79. package/dist/index.min.js +1 -1
  80. package/dist/index.mjs +660 -171
  81. package/dist/lokascript-browser-classic-i18n.js +1 -1
  82. package/dist/lokascript-browser-minimal.js +1 -1
  83. package/dist/lokascript-browser-standard.js +1 -1
  84. package/dist/lokascript-browser.js +1 -1
  85. package/dist/lokascript-multilingual.js +1 -1
  86. package/dist/lsp-metadata.js +2 -2
  87. package/dist/lsp-metadata.mjs +2 -2
  88. package/dist/metadata.d.ts +1 -1
  89. package/dist/metadata.js +13 -11
  90. package/dist/metadata.mjs +13 -11
  91. package/dist/parser/command-parsers/dom-commands.d.ts +1 -0
  92. package/dist/parser/full-parser.js +47 -1
  93. package/dist/parser/full-parser.mjs +47 -1
  94. package/dist/reference/index.js +13 -7
  95. package/dist/reference/index.mjs +13 -7
  96. package/dist/registry/index.js +56 -10
  97. package/dist/registry/index.mjs +56 -10
  98. package/dist/runtime/command-adapter.d.ts +8 -8
  99. package/dist/utils/element-check.d.ts +1 -0
  100. package/dist/version.d.ts +2 -0
  101. package/package.json +5 -5
  102. package/dist/chunks/browser-modular-BllAMlht.js +0 -2
package/dist/index.mjs CHANGED
@@ -4461,6 +4461,40 @@ function parseTakeCommand(ctx, identifierNode) {
4461
4461
  .endingAt(ctx.getPosition())
4462
4462
  .build();
4463
4463
  }
4464
+ function consumeViewTransitionTail(ctx, args) {
4465
+ if (!ctx.check('using')) {
4466
+ return false;
4467
+ }
4468
+ ctx.advance();
4469
+ if (!ctx.match('view')) {
4470
+ throw new Error("expected 'view transition' after 'using'");
4471
+ }
4472
+ if (!ctx.match('transition')) {
4473
+ throw new Error("expected 'transition' after 'using view'");
4474
+ }
4475
+ args.push(ctx.createIdentifier('using'));
4476
+ args.push(ctx.createIdentifier('view'));
4477
+ args.push(ctx.createIdentifier('transition'));
4478
+ return true;
4479
+ }
4480
+ function parseProcessCommand(ctx, identifierNode) {
4481
+ if (!ctx.check('partials')) {
4482
+ return null;
4483
+ }
4484
+ const args = [];
4485
+ consumeKeywordToArgs(ctx, 'partials', args);
4486
+ if (consumeKeywordToArgs(ctx, KEYWORDS$1.IN, args)) {
4487
+ const contentArg = parseOneArgument(ctx, ['using']);
4488
+ if (contentArg) {
4489
+ args.push(contentArg);
4490
+ }
4491
+ }
4492
+ consumeViewTransitionTail(ctx, args);
4493
+ return CommandNodeBuilder.fromIdentifier(identifierNode)
4494
+ .withArgs(...args)
4495
+ .endingAt(ctx.getPosition())
4496
+ .build();
4497
+ }
4464
4498
  function parseAddCommand(ctx, commandToken) {
4465
4499
  const args = [];
4466
4500
  if (ctx.match('{')) {
@@ -4582,6 +4616,7 @@ function parseSwapCommand(ctx, identifierNode) {
4582
4616
  args.push(contentExpr);
4583
4617
  }
4584
4618
  }
4619
+ consumeViewTransitionTail(ctx, args);
4585
4620
  return CommandNodeBuilder.fromIdentifier(identifierNode)
4586
4621
  .withArgs(...args)
4587
4622
  .endingAt(ctx.getPosition())
@@ -5095,6 +5130,9 @@ function parseCompoundCommand(ctx, identifierNode) {
5095
5130
  case 'swap':
5096
5131
  case 'morph':
5097
5132
  return parseSwapCommand(ctx, identifierNode);
5133
+ case 'process':
5134
+ return (parseProcessCommand(ctx, identifierNode) ??
5135
+ parseRegularCommand(ctx, identifierNode));
5098
5136
  default:
5099
5137
  return parseRegularCommand(ctx, identifierNode);
5100
5138
  }
@@ -5426,6 +5464,9 @@ function parseTellCommand(ctx, identifierNode) {
5426
5464
  if (!target) {
5427
5465
  throw new Error('tell command requires a target expression');
5428
5466
  }
5467
+ if (ctx.check(KEYWORDS$1.TO)) {
5468
+ ctx.advance();
5469
+ }
5429
5470
  const commands = [];
5430
5471
  while (!ctx.isAtEnd()) {
5431
5472
  if (ctx.checkIsCommand()) {
@@ -5445,7 +5486,11 @@ function parseTellCommand(ctx, identifierNode) {
5445
5486
  if (ctx.match(KEYWORDS$1.AND) || ctx.match(KEYWORDS$1.THEN)) {
5446
5487
  continue;
5447
5488
  }
5448
- if (ctx.check(KEYWORDS$1.ELSE) || ctx.check(KEYWORDS$1.END)) {
5489
+ if (ctx.check(KEYWORDS$1.ELSE)) {
5490
+ break;
5491
+ }
5492
+ if (ctx.check(KEYWORDS$1.END)) {
5493
+ ctx.advance();
5449
5494
  break;
5450
5495
  }
5451
5496
  if (ctx.checkIsCommand()) {
@@ -7783,6 +7828,7 @@ class Parser {
7783
7828
  'js',
7784
7829
  'tell',
7785
7830
  'fetch',
7831
+ 'process',
7786
7832
  ];
7787
7833
  if (this.semanticAdapter && !skipSemanticParsing.includes(commandName.toLowerCase())) {
7788
7834
  const remainingInput = this.getRemainingInput();
@@ -8737,6 +8783,12 @@ function isHTMLElement$2(value) {
8737
8783
  typeof value.tagName === 'string' &&
8738
8784
  'classList' in value);
8739
8785
  }
8786
+ function isInsertableNode(value) {
8787
+ if (value === null || typeof value !== 'object')
8788
+ return false;
8789
+ const nodeType = value.nodeType;
8790
+ return nodeType === 1 || nodeType === 3 || nodeType === 11;
8791
+ }
8740
8792
  function isNodeList(value) {
8741
8793
  return (value !== null &&
8742
8794
  typeof value === 'object' &&
@@ -10609,6 +10661,12 @@ function evaluateLiteral(node) {
10609
10661
  }
10610
10662
  async function evaluateIdentifier(node, context) {
10611
10663
  const name = node.name;
10664
+ if (name.startsWith('$')) {
10665
+ notifyGlobalRead(name.slice(1), context);
10666
+ }
10667
+ else if (node.scope === 'global') {
10668
+ notifyGlobalRead(name, context);
10669
+ }
10612
10670
  if (name === 'me' || name === 'my' || name === 'I') {
10613
10671
  return getExpr(context, 'me').evaluate(context);
10614
10672
  }
@@ -10628,7 +10686,6 @@ async function evaluateIdentifier(node, context) {
10628
10686
  return getExpr(context, 'document').evaluate(context);
10629
10687
  }
10630
10688
  if (node.scope === 'global' && context.globals?.has(name)) {
10631
- notifyGlobalRead(name, context);
10632
10689
  return context.globals.get(name);
10633
10690
  }
10634
10691
  if (node.scope === 'element') {
@@ -10639,12 +10696,9 @@ async function evaluateIdentifier(node, context) {
10639
10696
  return context.locals.get(name);
10640
10697
  }
10641
10698
  if (context.globals && context.globals.has(name)) {
10642
- if (name.startsWith('$'))
10643
- notifyGlobalRead(name.slice(1), context);
10644
10699
  return context.globals.get(name);
10645
10700
  }
10646
10701
  if (name.startsWith('$') && context.globals && context.globals.has(name.slice(1))) {
10647
- notifyGlobalRead(name.slice(1), context);
10648
10702
  return context.globals.get(name.slice(1));
10649
10703
  }
10650
10704
  if (context[name] !== undefined) {
@@ -11939,7 +11993,7 @@ class CommandAdapterV2 {
11939
11993
  return {
11940
11994
  description: this.impl.metadata?.description || '',
11941
11995
  examples: this.impl.metadata?.examples || [],
11942
- syntax: Array.isArray(syntax) ? syntax.join(' | ') : syntax || '',
11996
+ syntax: typeof syntax === 'string' ? syntax : syntax ? syntax.join(' | ') : '',
11943
11997
  };
11944
11998
  }
11945
11999
  async execute(context, ...args) {
@@ -12015,10 +12069,8 @@ class CommandAdapterV2 {
12015
12069
  }
12016
12070
  }
12017
12071
  validate(input) {
12018
- if (this.impl.validate) {
12019
- return this.impl.validate(input);
12020
- }
12021
- return { isValid: true, errors: [], suggestions: [] };
12072
+ const isValid = this.impl.validate ? this.impl.validate(input) : true;
12073
+ return { isValid, errors: [], suggestions: [] };
12022
12074
  }
12023
12075
  }
12024
12076
  class CommandRegistryV2 {
@@ -16873,7 +16925,7 @@ function command(config) {
16873
16925
  };
16874
16926
  }
16875
16927
  function commandMeta(metadata) {
16876
- return { isBlocking: false, hasBody: false, version: '1.0.0', ...metadata };
16928
+ return { ...metadata };
16877
16929
  }
16878
16930
  function createFactory(CommandClass) {
16879
16931
  return () => new CommandClass();
@@ -17776,7 +17828,7 @@ function insertContent(target, content, position) {
17776
17828
  insertReplace(target, content);
17777
17829
  return;
17778
17830
  }
17779
- if (isHTMLElement$2(content)) {
17831
+ if (isInsertableNode(content)) {
17780
17832
  insertElement(target, content, position);
17781
17833
  }
17782
17834
  else {
@@ -17787,7 +17839,7 @@ function insertContentSemantic(target, content, position) {
17787
17839
  insertContent(target, content, toInsertPosition(position));
17788
17840
  }
17789
17841
  function insertReplace(target, content) {
17790
- if (isHTMLElement$2(content)) {
17842
+ if (isInsertableNode(content)) {
17791
17843
  target.innerHTML = '';
17792
17844
  target.appendChild(content);
17793
17845
  }
@@ -17834,6 +17886,53 @@ function insertText(target, content, position) {
17834
17886
  target.insertAdjacentText(domPosition, content);
17835
17887
  }
17836
17888
  }
17889
+ function moveOrInsert(parent, element, ref) {
17890
+ const p = parent;
17891
+ if (typeof p.moveBefore === 'function' && element.isConnected && parent.isConnected) {
17892
+ try {
17893
+ p.moveBefore(element, ref);
17894
+ return;
17895
+ }
17896
+ catch {
17897
+ }
17898
+ }
17899
+ parent.insertBefore(element, ref);
17900
+ }
17901
+ function insertElementsInOrder(target, elements, position) {
17902
+ switch (position) {
17903
+ case 'beforeend':
17904
+ for (const el of elements)
17905
+ moveOrInsert(target, el, null);
17906
+ break;
17907
+ case 'afterbegin':
17908
+ for (let i = elements.length - 1; i >= 0; i--) {
17909
+ moveOrInsert(target, elements[i], target.firstChild);
17910
+ }
17911
+ break;
17912
+ case 'beforebegin': {
17913
+ const parent = target.parentElement;
17914
+ if (!parent)
17915
+ return;
17916
+ for (const el of elements)
17917
+ moveOrInsert(parent, el, target);
17918
+ break;
17919
+ }
17920
+ case 'afterend': {
17921
+ const parent = target.parentElement;
17922
+ if (!parent)
17923
+ return;
17924
+ for (let i = elements.length - 1; i >= 0; i--) {
17925
+ moveOrInsert(parent, elements[i], target.nextSibling);
17926
+ }
17927
+ break;
17928
+ }
17929
+ case 'replace':
17930
+ target.innerHTML = '';
17931
+ for (const el of elements)
17932
+ moveOrInsert(target, el, null);
17933
+ break;
17934
+ }
17935
+ }
17837
17936
  function removeElement(element) {
17838
17937
  if (element.parentNode) {
17839
17938
  element.remove();
@@ -18924,7 +19023,12 @@ let PutCommand = (() => {
18924
19023
  else {
18925
19024
  for (const t of targets) {
18926
19025
  const content = this.parseValue(value);
18927
- insertContentSemantic(t, content, position);
19026
+ if (Array.isArray(content)) {
19027
+ insertElementsInOrder(t, content, toInsertPosition(position));
19028
+ }
19029
+ else {
19030
+ insertContentSemantic(t, content, position);
19031
+ }
18928
19032
  }
18929
19033
  }
18930
19034
  return targets;
@@ -18956,6 +19060,11 @@ let PutCommand = (() => {
18956
19060
  parseValue(v) {
18957
19061
  if (isHTMLElement$2(v))
18958
19062
  return v;
19063
+ if (Array.isArray(v) && v.length > 0 && v.every(isHTMLElement$2)) {
19064
+ return v;
19065
+ }
19066
+ if (isInsertableNode(v))
19067
+ return v;
18959
19068
  return v == null ? '' : String(v);
18960
19069
  }
18961
19070
  looksLikeCss(s) {
@@ -20177,8 +20286,9 @@ const morphAdapter = {
20177
20286
  function getStartViewTransition() {
20178
20287
  if (typeof document === 'undefined')
20179
20288
  return undefined;
20180
- return document
20289
+ const fn = document
20181
20290
  .startViewTransition;
20291
+ return typeof fn === 'function' ? fn.bind(document) : undefined;
20182
20292
  }
20183
20293
  function isViewTransitionsSupported() {
20184
20294
  return typeof getStartViewTransition() === 'function';
@@ -20440,7 +20550,7 @@ let SwapCommand = (() => {
20440
20550
  };
20441
20551
  }
20442
20552
  }
20443
- let useViewTransition = false;
20553
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
20444
20554
  if (usingIndex !== -1) {
20445
20555
  const afterUsing = argKeywords.slice(usingIndex + 1);
20446
20556
  if (afterUsing.includes('view') && afterUsing.includes('transition')) {
@@ -20650,7 +20760,7 @@ let MorphCommand = (() => {
20650
20760
  const withIndex = argKeywords.findIndex(k => k === 'with');
20651
20761
  const overIndex = argKeywords.findIndex(k => k === 'over');
20652
20762
  const usingIndex = argKeywords.findIndex(k => k === 'using');
20653
- let useViewTransition = false;
20763
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
20654
20764
  if (usingIndex !== -1) {
20655
20765
  const afterUsing = argKeywords.slice(usingIndex + 1);
20656
20766
  if (afterUsing.includes('view') && afterUsing.includes('transition')) {
@@ -20731,7 +20841,11 @@ let MorphCommand = (() => {
20731
20841
  })();
20732
20842
  _classThis.metadata = commandMeta({
20733
20843
  description: 'Morph content into target elements (intelligent diffing, preserves state)',
20734
- syntax: ['morph <target> with <content>', 'morph over <target> with <content>'],
20844
+ syntax: [
20845
+ 'morph <target> with <content>',
20846
+ 'morph over <target> with <content>',
20847
+ 'morph <target> with <content> using view transition',
20848
+ ],
20735
20849
  examples: ['morph #target with it', 'morph over #modal with fetchedContent'],
20736
20850
  sideEffects: ['dom-mutation'],
20737
20851
  category: 'dom',
@@ -21363,24 +21477,33 @@ let ProcessPartialsCommand = (() => {
21363
21477
  if (!args || args.length === 0) {
21364
21478
  throw new Error('process partials command requires content argument');
21365
21479
  }
21366
- const evaluatedArgs = [];
21367
- const argStrings = [];
21368
- for (const arg of args) {
21369
- const evaluated = await evaluator.evaluate(arg, context);
21370
- evaluatedArgs.push(evaluated);
21371
- if (typeof evaluated === 'string') {
21372
- argStrings.push(evaluated.toLowerCase());
21373
- }
21374
- }
21375
- const partialsIndex = argStrings.findIndex(s => s === 'partials');
21480
+ const keywordOf = (node) => {
21481
+ const n = node;
21482
+ if (!n || typeof n !== 'object')
21483
+ return null;
21484
+ if (n.type === 'identifier' && typeof n.name === 'string')
21485
+ return n.name.toLowerCase();
21486
+ if (n.type === 'literal' && typeof n.value === 'string')
21487
+ return n.value.toLowerCase();
21488
+ return null;
21489
+ };
21490
+ const keywords = args.map(keywordOf);
21491
+ const partialsIndex = keywords.indexOf('partials');
21492
+ const inIndex = keywords.indexOf('in');
21493
+ let contentNode;
21376
21494
  if (partialsIndex === -1) {
21377
- throw new Error('process command expects "partials" keyword: process partials in <content>');
21495
+ if (inIndex !== -1) {
21496
+ throw new Error('process command expects "partials" keyword: process partials in <content>');
21497
+ }
21498
+ contentNode = args[0];
21378
21499
  }
21379
- const inIndex = argStrings.findIndex(s => s === 'in');
21380
- if (inIndex === -1 || inIndex <= partialsIndex) {
21381
- throw new Error('process partials command expects "in" keyword: process partials in <content>');
21500
+ else {
21501
+ if (inIndex === -1 || inIndex <= partialsIndex) {
21502
+ throw new Error('process partials command expects "in" keyword: process partials in <content>');
21503
+ }
21504
+ contentNode = args[inIndex + 1];
21382
21505
  }
21383
- const contentArg = evaluatedArgs[inIndex + 1];
21506
+ const contentArg = contentNode ? await evaluator.evaluate(contentNode, context) : undefined;
21384
21507
  let html;
21385
21508
  if (typeof contentArg === 'string') {
21386
21509
  html = contentArg;
@@ -21394,10 +21517,10 @@ let ProcessPartialsCommand = (() => {
21394
21517
  else {
21395
21518
  throw new Error('process partials: content must be an HTML string or element');
21396
21519
  }
21397
- const usingIndex = argStrings.findIndex(s => s === 'using');
21398
- let useViewTransition = false;
21520
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
21521
+ const usingIndex = keywords.indexOf('using');
21399
21522
  if (usingIndex !== -1) {
21400
- const remaining = argStrings.slice(usingIndex + 1).join(' ');
21523
+ const remaining = keywords.slice(usingIndex + 1);
21401
21524
  if (remaining.includes('view') && remaining.includes('transition')) {
21402
21525
  useViewTransition = true;
21403
21526
  }
@@ -27264,6 +27387,8 @@ class Runtime extends RuntimeBase {
27264
27387
  }
27265
27388
  }
27266
27389
 
27390
+ const VERSION$1 = '2.10.0';
27391
+
27267
27392
  // src/types.ts
27268
27393
  function createLiteral$1(value, dataType) {
27269
27394
  return dataType ? { type: "literal", value, dataType } : { type: "literal", value };
@@ -31605,14 +31730,26 @@ var MultilingualDSLImpl = class {
31605
31730
  }
31606
31731
  translate(input, fromLanguage, toLanguage) {
31607
31732
  if (isExplicitSyntax$1(input)) return input;
31608
- for (const language of [fromLanguage, toLanguage]) {
31609
- if (!this.profileProvider.getProfile(language)) {
31610
- throw new Error(
31611
- `translate() requires a grammar profile for language "${language}", but none is configured. Set 'grammarProfile' on the LanguageConfig for "${language}" in createMultilingualDSL() (parse/validate/compile do not need it), or inject a custom 'profileProvider'.`
31612
- );
31733
+ let node;
31734
+ try {
31735
+ node = this.parseWithConfidence(input, fromLanguage).node;
31736
+ } catch (parseError) {
31737
+ if (this.hasGrammarProfile(fromLanguage) && this.hasGrammarProfile(toLanguage)) {
31738
+ return this.transformer.transform(input, fromLanguage, toLanguage);
31613
31739
  }
31740
+ throw parseError;
31741
+ }
31742
+ const rendered = this.registry.getSupportedLanguages().includes(toLanguage) ? this.render(node, toLanguage) : null;
31743
+ if (rendered != null) return rendered;
31744
+ if (this.hasGrammarProfile(fromLanguage) && this.hasGrammarProfile(toLanguage)) {
31745
+ return this.transformer.transform(input, fromLanguage, toLanguage);
31614
31746
  }
31615
- return this.transformer.transform(input, fromLanguage, toLanguage);
31747
+ throw new Error(
31748
+ `translate() could not render action "${node.action}" in language "${toLanguage}": no custom renderer, domain renderer, or schema pattern covers it, and no grammar profile is configured for the transformer fallback. Either add "${toLanguage}" to the DSL's languages/renderer, or set 'grammarProfile' on its LanguageConfig in createMultilingualDSL() (parse/validate/compile do not need it).`
31749
+ );
31750
+ }
31751
+ hasGrammarProfile(language) {
31752
+ return this.profileProvider.getProfile(language) != null;
31616
31753
  }
31617
31754
  compile(input, language) {
31618
31755
  if (!this.codeGenerator) {
@@ -35886,7 +36023,7 @@ function getSchemasByCategory(category) {
35886
36023
  function getDefinedSchemas() {
35887
36024
  return Object.values(commandSchemas).filter((s) => s.roles.length > 0 || s.bareKeyword === true);
35888
36025
  }
35889
- var toggleSchema, addSchema, removeSchema, putSchema, setSchema, bindSchema, liveSchema, eventsourceSchema, socketSchema, workerSchema, interceptSchema, showSchema, hideSchema, onSchema, triggerSchema, waitSchema, fetchSchema, incrementSchema, decrementSchema, appendSchema, prependSchema, logSchema, getCommandSchema, takeSchema, makeSchema, haltSchema, settleSchema, throwSchema, sendSchema, ifSchema, unlessSchema, elseSchema, repeatSchema, forSchema, whileSchema, continueSchema, URL_MARKER_ALL_LANGS, goSchema, transitionSchema, cloneSchema, focusSchema, blurSchema, emptySchema, openSchema, closeSchema, selectSchema, clearSchema, resetSchema, breakpointSchema, callSchema, returnSchema, jsSchema, asyncSchema, tellSchema, defaultSchema, initSchema, behaviorSchema, installSchema, measureSchema, swapSchema, morphSchema, beepSchema, breakSchema, copySchema, exitSchema, pickSchema, scrollSchema, PARTIALS_IN_MARKER_ALL_LANGS, pushSchema, replaceSchema, processSchema, renderSchema, commandSchemas;
36026
+ var toggleSchema, addSchema, removeSchema, putSchema, setSchema, bindSchema, liveSchema, eventsourceSchema, socketSchema, workerSchema, interceptSchema, showSchema, hideSchema, onSchema, triggerSchema, waitSchema, fetchSchema, incrementSchema, decrementSchema, appendSchema, prependSchema, logSchema, getCommandSchema, takeSchema, makeSchema, haltSchema, settleSchema, throwSchema, sendSchema, ifSchema, unlessSchema, elseSchema, repeatSchema, forSchema, whileSchema, continueSchema, URL_MARKER_ALL_LANGS, goSchema, transitionSchema, cloneSchema, focusSchema, blurSchema, emptySchema, openSchema, closeSchema, selectSchema, clearSchema, resetSchema, breakpointSchema, callSchema, returnSchema, jsSchema, asyncSchema, tellSchema, defaultSchema, initSchema, behaviorSchema, installSchema, measureSchema, USING_VIEW_MARKER_ALL_LANGS, VIEW_TRANSITION_MANNER_ROLE, swapSchema, morphSchema, beepSchema, breakSchema, copySchema, exitSchema, pickSchema, scrollSchema, PARTIALS_IN_MARKER_ALL_LANGS, pushSchema, replaceSchema, processSchema, renderSchema, commandSchemas;
35890
36027
  var init_command_schemas = __esm({
35891
36028
  "src/generators/command-schemas.ts"() {
35892
36029
  toggleSchema = {
@@ -35895,7 +36032,6 @@ var init_command_schemas = __esm({
35895
36032
  category: "dom-class",
35896
36033
  primaryRole: "patient",
35897
36034
  // `toggle .active on #btn for 2s` \u2192 args ['.active'], modifiers { on, for }.
35898
- // NOTE: `duration` is read here but not declared in `roles` below.
35899
36035
  ast: { args: ["patient"], modifiers: { on: "destination", for: "duration" } },
35900
36036
  roles: [
35901
36037
  {
@@ -35905,7 +36041,13 @@ var init_command_schemas = __esm({
35905
36041
  expectedTypes: ["selector"],
35906
36042
  selectorKinds: ["class", "attribute"],
35907
36043
  svoPosition: 1,
35908
- sovPosition: 2
36044
+ sovPosition: 2,
36045
+ // zh: the transformer emits `\u5207\u6362 \u628a .active` (the profile's \u628a patient
36046
+ // marker), but natural zh writes `\u5207\u6362 .active` bare \u2014 the handcrafted
36047
+ // patterns' form. Optional accepts both; without it the generated
36048
+ // pattern REQUIRED \u628a and the slim bundles could not parse the bare
36049
+ // form at all. Same treatment as go's destination.
36050
+ markerOptional: { zh: true }
35909
36051
  },
35910
36052
  {
35911
36053
  role: "destination",
@@ -36243,6 +36385,8 @@ var init_command_schemas = __esm({
36243
36385
  markerOverride: {
36244
36386
  en: "",
36245
36387
  // No marker before destination in English: "set :x to 5"
36388
+ es: "",
36389
+ // "establecer x a 5" - no marker before variable (profile default `en` matched nothing)
36246
36390
  ja: "\u3092",
36247
36391
  // "x \u3092 10 \u306b \u8a2d\u5b9a" - variable gets object marker
36248
36392
  ko: "\uB97C",
@@ -36265,9 +36409,19 @@ var init_command_schemas = __esm({
36265
36409
  // generated hi set patterns carried the swapped markers and matched no
36266
36410
  // corpus, so the whole hi set-family (set-text/inner-html/style/attribute)
36267
36411
  // fell to the bare-event fallback (S6 set-trio).
36268
- hi: "\u0915\u094B"
36412
+ hi: "\u0915\u094B",
36269
36413
  // target (destination) gets \u0915\u094b
36270
- }
36414
+ // zh: the transformer emits the verb-first BA form `\u8bbe\u7f6e \u628a X \u5230 V`
36415
+ // (\u628a before the variable), while natural zh writes `\u8bbe\u7f6e X \u4e3a V`
36416
+ // (unmarked). \u628a as the marker, optional below, accepts both. The
36417
+ // profile default \u5728 matched neither form, so the generated zh set
36418
+ // patterns were dead weight and the slim bundles (schema-generated
36419
+ // patterns only) could not parse set at all.
36420
+ zh: "\u628A"
36421
+ },
36422
+ // Accept the unmarked natural form alongside the transformer's \u628a form
36423
+ // (same treatment as go's destination).
36424
+ markerOptional: { zh: true }
36271
36425
  },
36272
36426
  {
36273
36427
  role: "patient",
@@ -36310,8 +36464,14 @@ var init_command_schemas = __esm({
36310
36464
  // "x \u0995\u09c7 10 \u09a4\u09c7 \u09b8\u09c7\u099f" - destination marker on value
36311
36465
  qu: "man",
36312
36466
  // "x ta 10 man churay" - destination marker on value
36313
- hi: "\u092E\u0947\u0902"
36467
+ hi: "\u092E\u0947\u0902",
36314
36468
  // value (patient) gets \u092e\u0947\u0902 \u2014 see the destination note above
36469
+ // zh: the transformer/corpus form marks the value with \u5230 (`\u8bbe\u7f6e \u628a X
36470
+ // \u5230 V`); natural zh uses \u4e3a (`\u8bbe\u7f6e X \u4e3a V`). \u5230 is the override,
36471
+ // the \u4e3a-family rides along as variants (all merged as alternatives
36472
+ // by schemaMarkerAlternatives). Profile default \u628a was the PATIENT
36473
+ // marker, which never precedes set's value in either form.
36474
+ zh: "\u5230"
36315
36475
  },
36316
36476
  // Turkish dative is allomorphic under vowel harmony: the i18n transformer
36317
36477
  // emits `e` for quoted-string values (`"red" e`) but `-ya` for a value
@@ -36324,7 +36484,11 @@ var init_command_schemas = __esm({
36324
36484
  // not parse as a bare command while `t\u0131klama da @disabled i do\u011fru ya
36325
36485
  // ayarla` did. See STRUCTURAL_ARCS_ROADMAP.md (tr set-attribute).
36326
36486
  markerVariants: {
36327
- tr: ["e", "a", "ye", "ya"]
36487
+ tr: ["e", "a", "ye", "ya"],
36488
+ // Natural zh value markers (`\u8bbe\u7f6e X \u4e3a V`), simplified + traditional +
36489
+ // resultative \u2014 the handcrafted set-zh-full alternatives, kept parseable
36490
+ // alongside the transformer's \u5230 override above.
36491
+ zh: ["\u4E3A", "\u70BA", "\u6210"]
36328
36492
  }
36329
36493
  },
36330
36494
  {
@@ -36986,8 +37150,8 @@ var init_command_schemas = __esm({
36986
37150
  description: "Take content from a source element",
36987
37151
  category: "dom-content",
36988
37152
  primaryRole: "patient",
36989
- // `take .active from #parent` \u2192 args ['.active'], modifiers { from: '#parent' }.
36990
- ast: { args: ["patient"], modifiers: { from: "source" } },
37153
+ // `take .active from #parent for me` \u2192 args ['.active'], modifiers { from, for }.
37154
+ ast: { args: ["patient"], modifiers: { from: "source", for: "recipient" } },
36991
37155
  roles: [
36992
37156
  {
36993
37157
  role: "patient",
@@ -37010,6 +37174,38 @@ var init_command_schemas = __esm({
37010
37174
  expectedTypes: ["selector", "reference"],
37011
37175
  svoPosition: 2,
37012
37176
  sovPosition: 1
37177
+ },
37178
+ {
37179
+ role: "recipient",
37180
+ description: "The element the class moves ONTO (`take .active from .tab for me`)",
37181
+ required: false,
37182
+ // References only, deliberately. Upstream accepts an element expression,
37183
+ // but the 23 non-en corpus surfaces carry the recipient as a BARE
37184
+ // trailing pronoun (i18n renders `\u2026 von .tab-button ich`), so this slot
37185
+ // is marker-less almost everywhere and a selector-typed slot would
37186
+ // swallow the second selector of `take .active from .a .b`. English is
37187
+ // unaffected: `take` is on the core parser's skipSemanticParsing list,
37188
+ // so the traditional parser owns `for <anything>` there.
37189
+ expectedTypes: ["reference"],
37190
+ svoPosition: 3,
37191
+ sovPosition: 3,
37192
+ // NO default. The runtime already defaults the recipient to `me`
37193
+ // (commands/animation/take.ts), and a schema default would emit an
37194
+ // explicit `for me` modifier on every take \u2014 re-smuggling the exact
37195
+ // "absent means absent" semantics #859 removed from `source`.
37196
+ //
37197
+ // Shape-anchored on `reference`: without it this optional slot weighs
37198
+ // into every take pattern's denominator in `scoreRoleCoverage`, dropping
37199
+ // plain `take .active from .tab-button` from 1.0 to ~0.69 \u2014 the toggle-es
37200
+ // regression class the R1 role-set flip ratchet exists to catch.
37201
+ valueShape: "reference",
37202
+ // en only. The other 23 languages render the recipient unmarked, so a
37203
+ // marker there would never match their corpus rows; where the marker-less
37204
+ // slot proves inert they stay uncaptured and the pattern lands in the
37205
+ // baseline's `roleLossyPatterns` as named R1 burn-down tail. A language
37206
+ // gets a real particle here ONLY if the empty slot perturbs its other
37207
+ // parses (toggle's ja \u9593 / ko \ub3d9\uc548 case).
37208
+ markerOverride: { en: "for" }
37013
37209
  }
37014
37210
  ]
37015
37211
  };
@@ -38074,6 +38270,47 @@ var init_command_schemas = __esm({
38074
38270
  }
38075
38271
  ]
38076
38272
  };
38273
+ USING_VIEW_MARKER_ALL_LANGS = {
38274
+ en: "using view",
38275
+ es: "using view",
38276
+ pt: "using view",
38277
+ fr: "using view",
38278
+ de: "using view",
38279
+ it: "using view",
38280
+ ja: "using view",
38281
+ ko: "using view",
38282
+ zh: "using view",
38283
+ ar: "using view",
38284
+ he: "using view",
38285
+ hi: "using view",
38286
+ bn: "using view",
38287
+ tr: "using view",
38288
+ ru: "using view",
38289
+ uk: "using view",
38290
+ pl: "using view",
38291
+ id: "using view",
38292
+ vi: "using view",
38293
+ th: "using view",
38294
+ ms: "using view",
38295
+ tl: "using view",
38296
+ sw: "using view",
38297
+ qu: "using view"
38298
+ };
38299
+ VIEW_TRANSITION_MANNER_ROLE = {
38300
+ role: "manner",
38301
+ description: "Run the swap inside a `document.startViewTransition()` (`using view transition`)",
38302
+ required: false,
38303
+ // Both types, because the SAME word tokenizes differently per language and
38304
+ // the difference is an accident of vocabulary: `transition` is a command
38305
+ // keyword in en/fr (it is also their verb) and a bare identifier everywhere
38306
+ // else, which types it `literal` in the first group and `expression` in the
38307
+ // second. Measured: with `['literal']` alone only en and fr captured the
38308
+ // tail. Widening is safe precisely because the slot is marker-guarded \u2014
38309
+ // nothing reaches it until `using view` has matched.
38310
+ expectedTypes: ["literal", "expression"],
38311
+ valueShape: "keyword",
38312
+ markerOverride: USING_VIEW_MARKER_ALL_LANGS
38313
+ };
38077
38314
  swapSchema = {
38078
38315
  action: "swap",
38079
38316
  description: "Swap DOM content using various strategies (innerHTML, outerHTML, delete, etc.)",
@@ -38094,7 +38331,11 @@ var init_command_schemas = __esm({
38094
38331
  // work. Preserved verbatim by the Arc F migration (a faithful migration must
38095
38332
  // not change output) and pinned as two `drift` exemptions; this is the
38096
38333
  // behavior fix those entries were waiting for.
38097
- ast: { args: ["method", "destination", "patient"] },
38334
+ //
38335
+ // `manner` is the exception to "keyword-positional args": it rides as
38336
+ // `modifiers.viewTransition`, which SwapCommand.parseInput reads for presence
38337
+ // alongside its existing flat-args `using`/`view`/`transition` scan.
38338
+ ast: { args: ["method", "destination", "patient"], modifiers: { viewTransition: "manner" } },
38098
38339
  roles: [
38099
38340
  {
38100
38341
  role: "method",
@@ -38189,6 +38430,11 @@ var init_command_schemas = __esm({
38189
38430
  ar: "\u0628\u0640",
38190
38431
  tl: "nang"
38191
38432
  }
38433
+ },
38434
+ {
38435
+ ...VIEW_TRANSITION_MANNER_ROLE,
38436
+ svoPosition: 4,
38437
+ sovPosition: 4
38192
38438
  }
38193
38439
  ]
38194
38440
  };
@@ -38199,7 +38445,15 @@ var init_command_schemas = __esm({
38199
38445
  primaryRole: "patient",
38200
38446
  // `morph #list to it` \u2192 args [content], modifiers { on: element }.
38201
38447
  // Content is source or destination; the element being morphed is the patient.
38202
- ast: { args: [["source", "destination"]], modifiers: { on: "patient" } },
38448
+ //
38449
+ // `manner` rides as `modifiers.viewTransition`, same as swap/process \u2014
38450
+ // MorphCommand.parseInput reads it for presence alongside its existing
38451
+ // flat-args `using`/`view`/`transition` scan (the traditional-parser path,
38452
+ // which owns English because morph sits on SKIP_SEMANTIC_COMMANDS).
38453
+ ast: {
38454
+ args: [["source", "destination"]],
38455
+ modifiers: { on: "patient", viewTransition: "manner" }
38456
+ },
38203
38457
  roles: [
38204
38458
  {
38205
38459
  role: "patient",
@@ -38220,6 +38474,18 @@ var init_command_schemas = __esm({
38220
38474
  sovPosition: 2,
38221
38475
  markerOverride: { en: "to" }
38222
38476
  // "morph #target to it"
38477
+ },
38478
+ {
38479
+ // `morph #target to it using view transition` \u2014 the same tail as swap and
38480
+ // process, closed here for the same reason (#870's third-schema filing):
38481
+ // without the role the semantic parser matched morph at confidence 1.0
38482
+ // and stranded the tail, so every semantic-only consumer (multilingual
38483
+ // bundles, the bridge, `translate()`) silently dropped the animation
38484
+ // request in all 24 languages. Morph has NO hand-written patterns in any
38485
+ // language, so this schema role is the whole fix on the pattern side.
38486
+ ...VIEW_TRANSITION_MANNER_ROLE,
38487
+ svoPosition: 3,
38488
+ sovPosition: 3
38223
38489
  }
38224
38490
  ]
38225
38491
  };
@@ -38406,6 +38672,13 @@ var init_command_schemas = __esm({
38406
38672
  description: "Process hx-partial markup in HTML content",
38407
38673
  category: "dom-content",
38408
38674
  primaryRole: "patient",
38675
+ // `process partials in it` \u2192 args ['it']; the optional tail rides as
38676
+ // `modifiers.viewTransition`, which ProcessPartialsCommand.parseInput has
38677
+ // read since #861 (`raw.modifiers?.viewTransition !== undefined`). Without a
38678
+ // descriptor this schema fell through to `buildGenericCommand`, whose
38679
+ // modifier list is fixed (destination/duration/method/style) and would have
38680
+ // dropped a captured `manner` on the floor.
38681
+ ast: { args: ["patient"], modifiers: { viewTransition: "manner" } },
38409
38682
  roles: [
38410
38683
  {
38411
38684
  role: "patient",
@@ -38415,6 +38688,11 @@ var init_command_schemas = __esm({
38415
38688
  svoPosition: 1,
38416
38689
  sovPosition: 1,
38417
38690
  markerOverride: PARTIALS_IN_MARKER_ALL_LANGS
38691
+ },
38692
+ {
38693
+ ...VIEW_TRANSITION_MANNER_ROLE,
38694
+ svoPosition: 2,
38695
+ sovPosition: 2
38418
38696
  }
38419
38697
  ]
38420
38698
  };
@@ -40009,7 +40287,9 @@ var init_french = __esm({
40009
40287
  trigger: { primary: "d\xE9clencher", normalized: "trigger" },
40010
40288
  send: { primary: "envoyer", alternatives: ["envoie"], normalized: "send" },
40011
40289
  focus: { primary: "focaliser", alternatives: ["concentrer"], normalized: "focus" },
40012
- blur: { primary: "d\xE9focaliser", normalized: "blur" },
40290
+ // `d\u00e9focaliser` is an unattested infinitive; French pedagogy writes
40291
+ // `perte de focus` for the event (2026-07 terminology review).
40292
+ blur: { primary: "perte de focus", alternatives: ["d\xE9focaliser"], normalized: "blur" },
40013
40293
  // Phase 1 (v0.9.90): DOM / form state / debug
40014
40294
  // `vide` (adjective, "empty") is the i18n transformer's `is empty` predicate
40015
40295
  // form; `vider` is the verb ("to empty"). Accept both so the emptiness check
@@ -40022,7 +40302,13 @@ var init_french = __esm({
40022
40302
  reset: { primary: "r\xE9initialiser", alternatives: ["reinitialiser"], normalized: "reset" },
40023
40303
  breakpoint: { primary: "point-arr\xEAt", alternatives: ["point-arret"], normalized: "breakpoint" },
40024
40304
  go: { primary: "aller", alternatives: ["naviguer", "va"], normalized: "go" },
40025
- scroll: { primary: "d\xE9filer", alternatives: ["faire-d\xE9filer"], normalized: "scroll" },
40305
+ // MDN fr and the OQLF standardize the noun `d\u00e9filement` for the event; the
40306
+ // infinitive stays as an alternative.
40307
+ scroll: {
40308
+ primary: "d\xE9filement",
40309
+ alternatives: ["defilement", "d\xE9filer", "faire-d\xE9filer"],
40310
+ normalized: "scroll"
40311
+ },
40026
40312
  push: { primary: "pousser", normalized: "push" },
40027
40313
  replace: { primary: "remplacer", normalized: "replace" },
40028
40314
  process: { primary: "traiter", normalized: "process" },
@@ -40088,9 +40374,15 @@ var init_french = __esm({
40088
40374
  after: { primary: "apr\xE8s", normalized: "after" },
40089
40375
  // Common event names (for event handler patterns)
40090
40376
  click: { primary: "clic", alternatives: ["clique"], normalized: "click" },
40091
- // `resize` event (window-resize): dict emits redimensionner; register it so the
40092
- // event types as literal="resize" (matching en) instead of expression.
40093
- resize: { primary: "redimensionner", normalized: "resize" },
40377
+ // `resize` event (window-resize): the noun `redimensionnement` is the
40378
+ // attested event form ("lors du redimensionnement de la fen\u00eatre"). The dict
40379
+ // still emits redimensionner, kept as an alternative so the event keeps
40380
+ // typing as literal="resize" (matching en) instead of expression.
40381
+ resize: {
40382
+ primary: "redimensionnement",
40383
+ alternatives: ["redimensionner"],
40384
+ normalized: "resize"
40385
+ },
40094
40386
  hover: { primary: "survol", alternatives: ["survoler"], normalized: "hover" },
40095
40387
  submit: { primary: "soumission", alternatives: ["soumettre"], normalized: "submit" },
40096
40388
  input: { primary: "saisie", alternatives: ["entr\xE9e"], normalized: "input" },
@@ -43873,9 +44165,17 @@ var init_turkish = __esm({
43873
44165
  on: { primary: "\xFCzerinde", alternatives: ["zaman"], normalized: "on" },
43874
44166
  trigger: { primary: "tetikle", normalized: "trigger" },
43875
44167
  send: { primary: "g\xF6nder", normalized: "send" },
43876
- // DOM focus
43877
- focus: { primary: "odak", alternatives: ["odaklanma"], normalized: "focus" },
43878
- blur: { primary: "bulan\u0131k", alternatives: ["bulan\u0131kl\u0131k", "bulanik"], normalized: "blur" },
44168
+ // DOM focus. `odaklanma` (the act of focusing) leads over the static state
44169
+ // noun `odak` \u2014 Turkish event prose says "odaklanma olay\u0131". `bulan\u0131k` was
44170
+ // the optical blur (CSS filters, image processing), never the DOM event;
44171
+ // native usage is `odak kayb\u0131` (loss of focus). 2026-07 terminology-review
44172
+ // corrections; old forms stay as parse alternatives.
44173
+ focus: { primary: "odaklanma", alternatives: ["odak"], normalized: "focus" },
44174
+ blur: {
44175
+ primary: "odak kayb\u0131",
44176
+ alternatives: ["odak kaybi", "bulan\u0131k", "bulan\u0131kl\u0131k", "bulanik"],
44177
+ normalized: "blur"
44178
+ },
43879
44179
  // Phase 1 (v0.9.90): DOM / form state / debug
43880
44180
  empty: { primary: "bo\u015Falt", alternatives: ["bosalt", "bo\u015F"], normalized: "empty" },
43881
44181
  open: { primary: "a\xE7", alternatives: ["ac"], normalized: "open" },
@@ -43896,7 +44196,9 @@ var init_turkish = __esm({
43896
44196
  },
43897
44197
  hover: { primary: "\xFCzerine gelme", alternatives: ["\xFCzerinde gezinme"], normalized: "hover" },
43898
44198
  submit: { primary: "g\xF6nderme", normalized: "submit" },
43899
- input: { primary: "giri\u015F", alternatives: ["girdi", "giris"], normalized: "input" },
44199
+ // `giri\u015f` reads as entry/login (giri\u015f yapma) and can imply an auth event;
44200
+ // the data-input term is `girdi` ("Girdi (Input) Eventleri").
44201
+ input: { primary: "girdi", alternatives: ["giri\u015F", "giris"], normalized: "input" },
43900
44202
  change: { primary: "de\u011Fi\u015Fiklik", alternatives: ["de\u011Fi\u015Fim", "degisim"], normalized: "change" },
43901
44203
  // `load` event: the i18n dict emits y\u00fckle for `load`. Without this keyword the
43902
44204
  // SOV reorder's mid-stream `y\u00fckle de` (on load) tokenized as the `install`
@@ -43906,7 +44208,13 @@ var init_turkish = __esm({
43906
44208
  load: { primary: "y\xFCkle", normalized: "load" },
43907
44209
  // Navigation
43908
44210
  go: { primary: "git", normalized: "go" },
43909
- scroll: { primary: "kayd\u0131r", alternatives: ["kaydir"], normalized: "scroll" },
44211
+ // `kayd\u0131r` is the bare imperative; the attested event noun is `kayd\u0131rma`
44212
+ // ("kayd\u0131rma olay\u0131"). The imperative stays as an alternative.
44213
+ scroll: {
44214
+ primary: "kayd\u0131rma",
44215
+ alternatives: ["kaydirma", "kayd\u0131r", "kaydir"],
44216
+ normalized: "scroll"
44217
+ },
43910
44218
  push: { primary: "itele", alternatives: ["push"], normalized: "push" },
43911
44219
  replace: { primary: "de\u011Fi\u015Ftir_url", alternatives: ["degistir_url"], normalized: "replace" },
43912
44220
  process: { primary: "i\u015Fle", alternatives: ["isle"], normalized: "process" },
@@ -44859,6 +45167,60 @@ var init_chinese = __esm({
44859
45167
  }
44860
45168
  });
44861
45169
 
45170
+ // src/parser/utils/marker-resolution.ts
45171
+ function resolveMarkerForRole(roleSpec, profile) {
45172
+ const overrideMarker = roleSpec.markerOverride?.[profile.code];
45173
+ const defaultMarker = profile.roleMarkers[roleSpec.role];
45174
+ if (overrideMarker !== void 0) {
45175
+ const alternatives = legacyMarkerAlternatives(roleSpec, profile.code, overrideMarker);
45176
+ return {
45177
+ primary: overrideMarker,
45178
+ ...alternatives && { alternatives },
45179
+ position: defaultMarker?.position ?? "before",
45180
+ isOverride: true
45181
+ };
45182
+ }
45183
+ if (defaultMarker && defaultMarker.primary) {
45184
+ const result = {
45185
+ primary: defaultMarker.primary,
45186
+ position: defaultMarker.position,
45187
+ isOverride: false
45188
+ };
45189
+ if (defaultMarker.alternatives) {
45190
+ result.alternatives = defaultMarker.alternatives;
45191
+ }
45192
+ return result;
45193
+ }
45194
+ return null;
45195
+ }
45196
+ function legacyMarkerAlternatives(roleSpec, languageCode, overrideMarker) {
45197
+ const legacy = roleSpec.markerLegacy?.[languageCode];
45198
+ if (!legacy?.length) return void 0;
45199
+ const alternatives = [...new Set(legacy)].filter((a) => a && a !== overrideMarker);
45200
+ return alternatives.length ? alternatives : void 0;
45201
+ }
45202
+ function schemaMarkerAlternatives(roleSpec, languageCode, marker) {
45203
+ const legacy = roleSpec.markerLegacy?.[languageCode] ?? [];
45204
+ const variants = roleSpec.methodCarrier ? [] : roleSpec.markerVariants?.[languageCode] ?? [];
45205
+ const alternatives = [.../* @__PURE__ */ new Set([...legacy, ...variants])].filter((a) => a && a !== marker);
45206
+ return alternatives.length ? alternatives : void 0;
45207
+ }
45208
+ var ROLE_MARKER_CONCEPTS;
45209
+ var init_marker_resolution = __esm({
45210
+ "src/parser/utils/marker-resolution.ts"() {
45211
+ ROLE_MARKER_CONCEPTS = /* @__PURE__ */ new Set([
45212
+ "destination",
45213
+ "source",
45214
+ "patient",
45215
+ "object",
45216
+ "event",
45217
+ "eventmarker",
45218
+ "manner",
45219
+ "instrument"
45220
+ ]);
45221
+ }
45222
+ });
45223
+
44862
45224
  // src/patterns/put.ts
44863
45225
  function getPutPatternsBn() {
44864
45226
  return [
@@ -59719,49 +60081,6 @@ var init_role_positioning = __esm({
59719
60081
  }
59720
60082
  });
59721
60083
 
59722
- // src/parser/utils/marker-resolution.ts
59723
- function resolveMarkerForRole(roleSpec, profile) {
59724
- const overrideMarker = roleSpec.markerOverride?.[profile.code];
59725
- const defaultMarker = profile.roleMarkers[roleSpec.role];
59726
- if (overrideMarker !== void 0) {
59727
- const alternatives = legacyMarkerAlternatives(roleSpec, profile.code, overrideMarker);
59728
- return {
59729
- primary: overrideMarker,
59730
- ...alternatives && { alternatives },
59731
- position: defaultMarker?.position ?? "before",
59732
- isOverride: true
59733
- };
59734
- }
59735
- if (defaultMarker && defaultMarker.primary) {
59736
- const result = {
59737
- primary: defaultMarker.primary,
59738
- position: defaultMarker.position,
59739
- isOverride: false
59740
- };
59741
- if (defaultMarker.alternatives) {
59742
- result.alternatives = defaultMarker.alternatives;
59743
- }
59744
- return result;
59745
- }
59746
- return null;
59747
- }
59748
- function legacyMarkerAlternatives(roleSpec, languageCode, overrideMarker) {
59749
- const legacy = roleSpec.markerLegacy?.[languageCode];
59750
- if (!legacy?.length) return void 0;
59751
- const alternatives = [...new Set(legacy)].filter((a) => a && a !== overrideMarker);
59752
- return alternatives.length ? alternatives : void 0;
59753
- }
59754
- function schemaMarkerAlternatives(roleSpec, languageCode, marker) {
59755
- const legacy = roleSpec.markerLegacy?.[languageCode] ?? [];
59756
- const variants = roleSpec.methodCarrier ? [] : roleSpec.markerVariants?.[languageCode] ?? [];
59757
- const alternatives = [.../* @__PURE__ */ new Set([...legacy, ...variants])].filter((a) => a && a !== marker);
59758
- return alternatives.length ? alternatives : void 0;
59759
- }
59760
- var init_marker_resolution = __esm({
59761
- "src/parser/utils/marker-resolution.ts"() {
59762
- }
59763
- });
59764
-
59765
60084
  // src/generators/event-handlers-sov.ts
59766
60085
  function resolveRoleMarker(roleSpec, profile) {
59767
60086
  let marker;
@@ -59795,6 +60114,44 @@ function appendOptionalScope(tokens, extraction, commandSchema) {
59795
60114
  });
59796
60115
  extraction.scope = { fromRole: "scope" };
59797
60116
  }
60117
+ function appendOptionalViewTransition(tokens, extraction, commandSchema, languageCode) {
60118
+ appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, "manner", {
60119
+ requireMarker: true
60120
+ });
60121
+ }
60122
+ function appendOptionalRecipient(tokens, extraction, commandSchema, languageCode) {
60123
+ appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, "recipient", {
60124
+ requireMarker: false
60125
+ });
60126
+ }
60127
+ function appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, role, opts) {
60128
+ const spec = commandSchema.roles.find((r) => r.role === role && !r.required);
60129
+ if (!spec) return;
60130
+ const marker = spec.markerOverride?.[languageCode];
60131
+ if (opts.requireMarker && !marker) return;
60132
+ tokens.push({
60133
+ type: "group",
60134
+ optional: true,
60135
+ tokens: [
60136
+ ...(marker ? marker.split(/\s+/) : []).map((word) => ({
60137
+ type: "literal",
60138
+ value: word
60139
+ })),
60140
+ {
60141
+ type: "role",
60142
+ role,
60143
+ optional: true,
60144
+ expectedTypes: spec.expectedTypes,
60145
+ // Load-bearing, same as on the generated command patterns: it exempts
60146
+ // the trailing slot from the matcher's verb guard, keeps the uncaptured
60147
+ // slot out of `scoreRoleCoverage`'s denominator, and (for `keyword`)
60148
+ // normalizes the captured value type to the EN reference's `literal`.
60149
+ ...spec.valueShape !== void 0 ? { valueShape: spec.valueShape } : {}
60150
+ }
60151
+ ]
60152
+ });
60153
+ extraction[role] = { fromRole: role };
60154
+ }
59798
60155
  function generateSOVEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
59799
60156
  const tokens = [];
59800
60157
  tokens.push({ type: "role", role: "event", optional: false });
@@ -59889,6 +60246,15 @@ function generateSOVPatientFirstEventHandlerPattern(commandSchema, profile, keyw
59889
60246
  tokens.push(
59890
60247
  ...swapsOperands ? eventHandlerPatientGroup(commandSchema, trailingMarker) : eventHandlerDestinationGroup(commandSchema, trailingMarker)
59891
60248
  );
60249
+ const extraction = {
60250
+ action: { value: commandSchema.action },
60251
+ event: { fromRole: "event" },
60252
+ [frontedRole]: { fromRole: frontedRole },
60253
+ ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
60254
+ ...eventHandlerSourceExtraction(commandSchema)
60255
+ };
60256
+ appendOptionalRecipient(tokens, extraction, commandSchema, profile.code);
60257
+ appendOptionalViewTransition(tokens, extraction, commandSchema, profile.code);
59892
60258
  return {
59893
60259
  id: `${commandSchema.action}-event-${profile.code}-sov-patient-first`,
59894
60260
  language: profile.code,
@@ -59898,13 +60264,71 @@ function generateSOVPatientFirstEventHandlerPattern(commandSchema, profile, keyw
59898
60264
  format: `{patient} ${patientMarker?.primary || ""} {event} ${eventMarker.primary} ${keyword.primary}`,
59899
60265
  tokens
59900
60266
  },
59901
- extraction: {
59902
- action: { value: commandSchema.action },
59903
- event: { fromRole: "event" },
59904
- [frontedRole]: { fromRole: frontedRole },
59905
- ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
59906
- ...eventHandlerSourceExtraction(commandSchema)
60267
+ extraction
60268
+ };
60269
+ }
60270
+ function generateSOVPatientFirstSourceFrontedEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
60271
+ const sourceSpec = commandSchema.roles.find((r) => r.role === "source");
60272
+ if (!sourceSpec) return null;
60273
+ const { marker: sourceMarker, alternatives: sourceAlts } = resolveRoleMarker(sourceSpec, profile);
60274
+ const patientMarker = profile.roleMarkers.patient;
60275
+ if (!sourceMarker) return null;
60276
+ if (sourceMarker === eventMarker.primary || sourceMarker === patientMarker?.primary) return null;
60277
+ const tokens = [];
60278
+ tokens.push({ type: "role", role: "patient", optional: false });
60279
+ if (patientMarker) {
60280
+ tokens.push(
60281
+ patientMarker.alternatives ? {
60282
+ type: "literal",
60283
+ value: patientMarker.primary,
60284
+ alternatives: patientMarker.alternatives
60285
+ } : { type: "literal", value: patientMarker.primary }
60286
+ );
60287
+ }
60288
+ tokens.push({
60289
+ type: "role",
60290
+ role: "source",
60291
+ optional: false,
60292
+ ...sourceSpec.expectedTypes ? { expectedTypes: sourceSpec.expectedTypes } : {},
60293
+ ...sourceSpec.valueShape !== void 0 ? { valueShape: sourceSpec.valueShape } : {}
60294
+ });
60295
+ for (const word of sourceMarker.split(/\s+/)) {
60296
+ tokens.push(
60297
+ sourceAlts && sourceMarker.split(/\s+/).length === 1 ? { type: "literal", value: word, alternatives: sourceAlts } : { type: "literal", value: word }
60298
+ );
60299
+ }
60300
+ tokens.push({ type: "role", role: "event", optional: false });
60301
+ if (eventMarker.position === "after") {
60302
+ const markerWords = eventMarker.primary.split(/\s+/);
60303
+ if (markerWords.length > 1) {
60304
+ for (const word of markerWords) tokens.push({ type: "literal", value: word });
60305
+ } else {
60306
+ tokens.push(
60307
+ eventMarker.alternatives ? { type: "literal", value: eventMarker.primary, alternatives: eventMarker.alternatives } : { type: "literal", value: eventMarker.primary }
60308
+ );
59907
60309
  }
60310
+ }
60311
+ tokens.push(
60312
+ keyword.alternatives ? { type: "literal", value: keyword.primary, alternatives: keyword.alternatives } : { type: "literal", value: keyword.primary }
60313
+ );
60314
+ const extraction = {
60315
+ action: { value: commandSchema.action },
60316
+ event: { fromRole: "event" },
60317
+ patient: { fromRole: "patient" },
60318
+ source: { fromRole: "source" }
60319
+ };
60320
+ appendOptionalRecipient(tokens, extraction, commandSchema, profile.code);
60321
+ appendOptionalViewTransition(tokens, extraction, commandSchema, profile.code);
60322
+ return {
60323
+ id: `${commandSchema.action}-event-${profile.code}-sov-source-fronted`,
60324
+ language: profile.code,
60325
+ command: "on",
60326
+ priority: (config.basePriority ?? 100) + 48,
60327
+ template: {
60328
+ format: `{patient} ${patientMarker?.primary || ""} {source} ${sourceMarker} {event} ${eventMarker.primary} ${keyword.primary}`,
60329
+ tokens
60330
+ },
60331
+ extraction
59908
60332
  };
59909
60333
  }
59910
60334
  function generateSOVPatientFirstWithDestEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
@@ -60346,6 +60770,16 @@ function generateVSOVerbFirstEventHandlerPattern(commandSchema, profile, keyword
60346
60770
  });
60347
60771
  }
60348
60772
  }
60773
+ const extraction = {
60774
+ action: { value: commandSchema.action },
60775
+ event: { fromRole: "event" },
60776
+ [swapsOperands ? "destination" : "patient"]: {
60777
+ fromRole: swapsOperands ? "destination" : "patient"
60778
+ },
60779
+ ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
60780
+ ...eventHandlerSourceExtraction(commandSchema)
60781
+ };
60782
+ appendOptionalViewTransition(tokens, extraction, commandSchema, profile.code);
60349
60783
  return {
60350
60784
  id: `${commandSchema.action}-event-${profile.code}-vso-verb-first`,
60351
60785
  language: profile.code,
@@ -60356,15 +60790,7 @@ function generateVSOVerbFirstEventHandlerPattern(commandSchema, profile, keyword
60356
60790
  format: `${keyword.primary} {patient} ${destMarker?.primary || ""} {destination?} ${eventMarker.primary} {event}`,
60357
60791
  tokens
60358
60792
  },
60359
- extraction: {
60360
- action: { value: commandSchema.action },
60361
- event: { fromRole: "event" },
60362
- [swapsOperands ? "destination" : "patient"]: {
60363
- fromRole: swapsOperands ? "destination" : "patient"
60364
- },
60365
- ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
60366
- ...eventHandlerSourceExtraction(commandSchema)
60367
- }
60793
+ extraction
60368
60794
  };
60369
60795
  }
60370
60796
  function generateVSOVerbFirstTwoRoleEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
@@ -60807,6 +61233,14 @@ function generateEventHandlerPatterns(commandSchema, profile, config = defaultCo
60807
61233
  config
60808
61234
  )
60809
61235
  );
61236
+ const sourceFronted = generateSOVPatientFirstSourceFrontedEventHandlerPattern(
61237
+ commandSchema,
61238
+ profile,
61239
+ keyword,
61240
+ eventMarker,
61241
+ config
61242
+ );
61243
+ if (sourceFronted) patterns.push(sourceFronted);
60810
61244
  const destMarkerCheck = profile.roleMarkers.destination;
60811
61245
  if (destMarkerCheck && destMarkerCheck.primary !== eventMarker.primary) {
60812
61246
  patterns.push(
@@ -60966,7 +61400,11 @@ function buildRoleToken(roleSpec, profile) {
60966
61400
  type: "role",
60967
61401
  role: roleSpec.role,
60968
61402
  optional: !roleSpec.required,
60969
- expectedTypes: roleSpec.expectedTypes
61403
+ expectedTypes: roleSpec.expectedTypes,
61404
+ // The matcher reads this too \u2014 a `'keyword'`-shaped slot holds a fixed
61405
+ // keyword phrase (`using view transition`) and must not be skipped by the
61406
+ // trailing-slot verb guard.
61407
+ ...roleSpec.valueShape !== void 0 ? { valueShape: roleSpec.valueShape } : {}
60970
61408
  };
60971
61409
  const prefixLiteral = roleSpec.valuePrefixLiteral?.[profile.code];
60972
61410
  const pushPrefixed = () => {
@@ -61275,9 +61713,24 @@ var init_pick = __esm({
61275
61713
  });
61276
61714
 
61277
61715
  // src/patterns/languages/en/swap.ts
61278
- var swapSimpleEnglish, swapElementEnglish, swapStrategyOfEnglish, swapStrategyEnglish, swapPatternsEn;
61716
+ var VIEW_TRANSITION_TAIL, swapSimpleEnglish, swapElementEnglish, swapStrategyOfEnglish, swapStrategyEnglish, swapPatternsEn;
61279
61717
  var init_swap = __esm({
61280
61718
  "src/patterns/languages/en/swap.ts"() {
61719
+ VIEW_TRANSITION_TAIL = {
61720
+ type: "group",
61721
+ optional: true,
61722
+ tokens: [
61723
+ { type: "literal", value: "using" },
61724
+ { type: "literal", value: "view" },
61725
+ {
61726
+ type: "role",
61727
+ role: "manner",
61728
+ optional: true,
61729
+ expectedTypes: ["literal", "expression"],
61730
+ valueShape: "keyword"
61731
+ }
61732
+ ]
61733
+ };
61281
61734
  swapSimpleEnglish = {
61282
61735
  id: "swap-en-handcrafted",
61283
61736
  language: "en",
@@ -61285,11 +61738,12 @@ var init_swap = __esm({
61285
61738
  priority: 110,
61286
61739
  // Higher than generated patterns
61287
61740
  template: {
61288
- format: "swap {method} {destination}",
61741
+ format: "swap {method} {destination} [using view {manner}]",
61289
61742
  tokens: [
61290
61743
  { type: "literal", value: "swap" },
61291
61744
  { type: "role", role: "method" },
61292
- { type: "role", role: "destination" }
61745
+ { type: "role", role: "destination" },
61746
+ VIEW_TRANSITION_TAIL
61293
61747
  ]
61294
61748
  },
61295
61749
  extraction: {
@@ -61303,12 +61757,13 @@ var init_swap = __esm({
61303
61757
  command: "swap",
61304
61758
  priority: 120,
61305
61759
  template: {
61306
- format: "swap {destination} with {patient}",
61760
+ format: "swap {destination} with {patient} [using view {manner}]",
61307
61761
  tokens: [
61308
61762
  { type: "literal", value: "swap" },
61309
61763
  { type: "role", role: "destination" },
61310
61764
  { type: "literal", value: "with" },
61311
- { type: "role", role: "patient" }
61765
+ { type: "role", role: "patient" },
61766
+ VIEW_TRANSITION_TAIL
61312
61767
  ]
61313
61768
  },
61314
61769
  extraction: {}
@@ -61319,14 +61774,15 @@ var init_swap = __esm({
61319
61774
  command: "swap",
61320
61775
  priority: 140,
61321
61776
  template: {
61322
- format: "swap {method} of {destination} with {patient}",
61777
+ format: "swap {method} of {destination} with {patient} [using view {manner}]",
61323
61778
  tokens: [
61324
61779
  { type: "literal", value: "swap" },
61325
61780
  { type: "role", role: "method" },
61326
61781
  { type: "literal", value: "of" },
61327
61782
  { type: "role", role: "destination" },
61328
61783
  { type: "literal", value: "with" },
61329
- { type: "role", role: "patient" }
61784
+ { type: "role", role: "patient" },
61785
+ VIEW_TRANSITION_TAIL
61330
61786
  ]
61331
61787
  },
61332
61788
  extraction: {}
@@ -61337,13 +61793,14 @@ var init_swap = __esm({
61337
61793
  command: "swap",
61338
61794
  priority: 130,
61339
61795
  template: {
61340
- format: "swap {method} {destination} with {patient}",
61796
+ format: "swap {method} {destination} with {patient} [using view {manner}]",
61341
61797
  tokens: [
61342
61798
  { type: "literal", value: "swap" },
61343
61799
  { type: "role", role: "method" },
61344
61800
  { type: "role", role: "destination" },
61345
61801
  { type: "literal", value: "with" },
61346
- { type: "role", role: "patient" }
61802
+ { type: "role", role: "patient" },
61803
+ VIEW_TRANSITION_TAIL
61347
61804
  ]
61348
61805
  },
61349
61806
  extraction: {}
@@ -64713,6 +65170,7 @@ function isTypeCompatible(actualType, expectedTypes) {
64713
65170
  }
64714
65171
 
64715
65172
  // src/parser/pattern-matcher.ts
65173
+ init_marker_resolution();
64716
65174
  init_command_schemas();
64717
65175
 
64718
65176
  // src/parser/utils/possessive-keywords.ts
@@ -65277,7 +65735,8 @@ var DefaultConfidenceModel = class {
65277
65735
  const hasDefault = (role) => {
65278
65736
  return pattern.extraction?.[role]?.default !== void 0;
65279
65737
  };
65280
- const schemaRoles = commandSchemas[pattern.command]?.roles;
65738
+ const wrappedAction = pattern.command === "on" ? pattern.extraction?.action?.value : void 0;
65739
+ const schemaRoles = commandSchemas[wrappedAction ?? pattern.command]?.roles;
65281
65740
  const isShapeAnchored = (role) => schemaRoles?.find((r) => r.role === role)?.valueShape !== void 0;
65282
65741
  for (const token of pattern.template.tokens) {
65283
65742
  if (token.type === "role") {
@@ -65681,7 +66140,7 @@ var _PatternMatcher = class _PatternMatcher {
65681
66140
  return patternToken.optional || false;
65682
66141
  }
65683
66142
  }
65684
- if (patternToken.optional && nextPatternToken === void 0 && patternToken.role !== "event" && patternToken.role !== "action" && token.kind === "keyword") {
66143
+ if (patternToken.optional && nextPatternToken === void 0 && patternToken.role !== "event" && patternToken.role !== "action" && patternToken.valueShape !== "keyword" && token.kind === "keyword") {
65685
66144
  const verbNorm = (token.normalized ?? token.value).toLowerCase();
65686
66145
  if (verbNorm in commandSchemas) {
65687
66146
  return true;
@@ -65836,7 +66295,14 @@ var _PatternMatcher = class _PatternMatcher {
65836
66295
  }
65837
66296
  }
65838
66297
  }
65839
- captured.set(patternToken.role, value);
66298
+ if (patternToken.valueShape === "keyword" && value.type === "expression") {
66299
+ captured.set(
66300
+ patternToken.role,
66301
+ createLiteral(String(value.raw ?? ""))
66302
+ );
66303
+ } else {
66304
+ captured.set(patternToken.role, value);
66305
+ }
65840
66306
  tokens.advance();
65841
66307
  if (patternToken.role === "event") {
65842
66308
  const filterTok = tokens.peek();
@@ -66425,17 +66891,7 @@ var _PatternMatcher = class _PatternMatcher {
66425
66891
  * so this never blocks a genuine `my value` / `its style` possessive.
66426
66892
  */
66427
66893
  isRoleMarkerConcept(normalized2) {
66428
- const markerConcepts = /* @__PURE__ */ new Set([
66429
- "destination",
66430
- "source",
66431
- "patient",
66432
- "object",
66433
- "event",
66434
- "eventmarker",
66435
- "manner",
66436
- "instrument"
66437
- ]);
66438
- return markerConcepts.has(normalized2.toLowerCase());
66894
+ return ROLE_MARKER_CONCEPTS.has(normalized2.toLowerCase());
66439
66895
  }
66440
66896
  /**
66441
66897
  * Does `token` look like an EVENT name for the `event` role? Events are bare
@@ -66821,7 +67277,7 @@ var _PatternMatcher = class _PatternMatcher {
66821
67277
  */
66822
67278
  matchGroupToken(tokens, patternToken, captured, nextPatternToken) {
66823
67279
  const mark = tokens.mark();
66824
- const capturedBefore = new Set(captured.keys());
67280
+ const capturedBefore = new Map(captured);
66825
67281
  const success = this.matchTokenSequence(
66826
67282
  tokens,
66827
67283
  patternToken.tokens,
@@ -66835,6 +67291,11 @@ var _PatternMatcher = class _PatternMatcher {
66835
67291
  captured.delete(role);
66836
67292
  }
66837
67293
  }
67294
+ for (const [role, value] of capturedBefore) {
67295
+ if (captured.get(role) !== value) {
67296
+ captured.set(role, value);
67297
+ }
67298
+ }
66838
67299
  return patternToken.optional || false;
66839
67300
  }
66840
67301
  return true;
@@ -66936,7 +67397,7 @@ var _PatternMatcher = class _PatternMatcher {
66936
67397
  } else if (rule.value !== void 0) {
66937
67398
  captured.set(role, { type: "literal", value: rule.value });
66938
67399
  } else if (rule.default) {
66939
- captured.set(role, rule.default);
67400
+ captured.set(role, { ...rule.default, implicit: true });
66940
67401
  }
66941
67402
  }
66942
67403
  }
@@ -67224,6 +67685,7 @@ function registerTokenizer2(tokenizer) {
67224
67685
  // src/parser/semantic-parser.ts
67225
67686
  init_registry();
67226
67687
  init_command_schemas();
67688
+ init_marker_resolution();
67227
67689
 
67228
67690
  // src/parser/block-parser.ts
67229
67691
  init_registry();
@@ -67889,14 +68351,20 @@ var SemanticRendererImpl = class {
67889
68351
  return parts.join(" ");
67890
68352
  }
67891
68353
  /**
67892
- * Join a statement list the way a block body reads: ` then ` between siblings,
67893
- * but a single space immediately after a loop/tell block header (whose body
67894
- * follows directly). Shared by renderConditional's branches; renderCompound
67895
- * keeps its own copy because it also handles the multi-handler and bind-feature
67896
- * cases.
68354
+ * Join a statement list the way a block body reads: the target language's `then`
68355
+ * between siblings, but a single space immediately after a loop/tell block header
68356
+ * (whose body follows directly). Used by renderConditional's branches;
68357
+ * renderCompound keeps its own copy because it also handles the multi-handler
68358
+ * and bind-feature cases.
68359
+ *
68360
+ * The chain word is localized (`this.keyword(language, 'then')`) for the same
68361
+ * reason renderCompound localizes it: a hardcoded English `then` leaks into every
68362
+ * non-en block body (`\u3082\u3057 \u2026 \u524a\u9664 then \u8ffd\u52a0`), which no target-language tokenizer
68363
+ * recognizes as a connector.
67897
68364
  */
67898
68365
  joinStatements(statements, language) {
67899
68366
  const rendered = statements.map((s) => this.render(s, language));
68367
+ const thenKw = this.keyword(language, "then");
67900
68368
  let out = rendered[0] ?? "";
67901
68369
  for (let i = 1; i < rendered.length; i++) {
67902
68370
  const prev = statements[i - 1];
@@ -67904,7 +68372,7 @@ var SemanticRendererImpl = class {
67904
68372
  if (prev.kind === "command" && BLOCK_NEEDS_TRAILING_END.has(prev.action)) {
67905
68373
  out += ` ${this.keyword(language, "end")}`;
67906
68374
  }
67907
- out += (afterBlockHeader ? " " : " then ") + rendered[i];
68375
+ out += (afterBlockHeader ? " " : ` ${thenKw} `) + rendered[i];
67908
68376
  }
67909
68377
  return out;
67910
68378
  }
@@ -68077,6 +68545,7 @@ var SemanticRendererImpl = class {
68077
68545
  if (!roleToken) continue;
68078
68546
  const roleValue = node.roles.get(roleName);
68079
68547
  if (roleValue?.type !== "reference" || roleValue.value !== "me") continue;
68548
+ if (!roleValue.implicit) continue;
68080
68549
  if (roleName === "destination") {
68081
68550
  const patient = node.roles.get("patient");
68082
68551
  if (patient?.type === "literal" && patient.dataType === "string") continue;
@@ -68518,7 +68987,7 @@ function fillSchemaDefaults(node) {
68518
68987
  const roles = node.roles;
68519
68988
  for (const spec of schema.roles) {
68520
68989
  if (spec.default !== void 0 && !roles.has(spec.role)) {
68521
- roles.set(spec.role, { ...spec.default });
68990
+ roles.set(spec.role, { ...spec.default, implicit: true });
68522
68991
  }
68523
68992
  }
68524
68993
  }
@@ -69123,7 +69592,7 @@ var _SemanticParserImpl = class _SemanticParserImpl {
69123
69592
  }
69124
69593
  let eventModifiers = patternMatcher.extractEventModifiers(tokens);
69125
69594
  const sourceValue = match.captured.get("source");
69126
- if (sourceValue && match.pattern.id.includes("source") && !(sourceValue.type === "reference" && sourceValue.value === "me")) {
69595
+ if (sourceValue && match.pattern.id.endsWith("source") && !(sourceValue.type === "reference" && sourceValue.value === "me")) {
69127
69596
  eventModifiers = { ...eventModifiers ?? {}, from: sourceValue };
69128
69597
  }
69129
69598
  const additionalEvents = this.extractOrConjunctionEvents(tokens, language);
@@ -69273,13 +69742,18 @@ var _SemanticParserImpl = class _SemanticParserImpl {
69273
69742
  if (!spec) return true;
69274
69743
  return spec.expectedTypes.length > 0 && !spec.expectedTypes.includes(valType(val));
69275
69744
  };
69745
+ const isMarkerConceptJunk = (role, val) => role === "patient" && !!schema && !schema.roles.some((r) => r.role === "patient") && valType(val) === "literal" && ROLE_MARKER_CONCEPTS.has(
69746
+ String(val.value ?? "").toLowerCase()
69747
+ );
69276
69748
  const preservesFused = !!first && first.kind === "command" && Object.entries(roles).every(([role, val]) => {
69277
- if (isIgnorableFusedRole(role, val)) return true;
69749
+ if (isIgnorableFusedRole(role, val) || isMarkerConceptJunk(role, val)) return true;
69278
69750
  const rv = first.roles.get(mapRole(role));
69279
69751
  if (rv !== void 0 && valType(rv) === valType(val)) return true;
69280
69752
  if (role === "patient" && actionName === "pick" && valType(val) === "literal") {
69281
69753
  const mv = first.roles.get("method");
69282
- return mv !== void 0 && valType(mv) === "literal" && String(mv.value) === String(val.value);
69754
+ const mvType = valType(mv);
69755
+ const mvSurface = mvType === "literal" ? String(mv.value) : mvType === "expression" ? String(mv.raw) : void 0;
69756
+ return mvSurface !== void 0 && mvSurface === String(val.value);
69283
69757
  }
69284
69758
  return false;
69285
69759
  });
@@ -69289,7 +69763,12 @@ var _SemanticParserImpl = class _SemanticParserImpl {
69289
69763
  // the swap can never swallow a body command. The body-swallowing
69290
69764
  // generated repeat matches none of these ids.
69291
69765
  /^repeat-.*-(times|for-in|while-head|until-head)$/.test(reparsePid);
69292
- if (reparsed.length === 1 && first && first.kind === "command" && first.action === actionName && preservesFused && headOnlyOk && first.roles.size > Object.keys(roles).length) {
69766
+ if (reparsed.length === 1 && first && first.kind === "command" && first.action === actionName && preservesFused && headOnlyOk && // Strictly-more: the re-parse must recover something the fused
69767
+ // capture lacked. Junk marker captures are excluded from the
69768
+ // count \u2014 a fused shape whose ONLY role is a swallowed marker
69769
+ // (scroll: `destination:literal="destination"`) would otherwise
69770
+ // tie 1 > 1 and veto its own repair.
69771
+ first.roles.size > Object.entries(roles).filter(([r, v]) => !isMarkerConceptJunk(r, v)).length) {
69293
69772
  commandNode = first;
69294
69773
  while (tokens.position() < clauseEnd) tokens.advance();
69295
69774
  } else {
@@ -76088,7 +76567,7 @@ function getGetPatternsBn() {
76088
76567
  tokens: [
76089
76568
  { type: "role", role: "source" },
76090
76569
  { type: "literal", value: "\u09A5\u09C7\u0995\u09C7" },
76091
- { type: "literal", value: "\u09AA\u09BE\u09A8", alternatives: ["\u09A8\u09BF\u09A8"] }
76570
+ { type: "literal", value: "\u09AA\u09BE\u09A8" }
76092
76571
  ]
76093
76572
  },
76094
76573
  extraction: {
@@ -76104,7 +76583,7 @@ function getGetPatternsBn() {
76104
76583
  template: {
76105
76584
  format: "\u09AA\u09BE\u09A8 {source}",
76106
76585
  tokens: [
76107
- { type: "literal", value: "\u09AA\u09BE\u09A8", alternatives: ["\u09A8\u09BF\u09A8"] },
76586
+ { type: "literal", value: "\u09AA\u09BE\u09A8" },
76108
76587
  { type: "role", role: "source" }
76109
76588
  ]
76110
76589
  },
@@ -76188,7 +76667,7 @@ function getGetPatternsIt() {
76188
76667
  template: {
76189
76668
  format: "ottenere {patient} da {source}",
76190
76669
  tokens: [
76191
- { type: "literal", value: "ottenere", alternatives: ["ottieni", "get", "prendere"] },
76670
+ { type: "literal", value: "ottenere", alternatives: ["ottieni", "get"] },
76192
76671
  { type: "role", role: "patient" },
76193
76672
  {
76194
76673
  type: "group",
@@ -76278,7 +76757,7 @@ function getGetPatternsRu() {
76278
76757
  template: {
76279
76758
  format: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C {patient} \u0438\u0437 {source}",
76280
76759
  tokens: [
76281
- { type: "literal", value: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C", alternatives: ["\u043F\u043E\u043B\u0443\u0447\u0438", "\u0432\u0437\u044F\u0442\u044C", "\u0432\u043E\u0437\u044C\u043C\u0438"] },
76760
+ { type: "literal", value: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C", alternatives: ["\u043F\u043E\u043B\u0443\u0447\u0438"] },
76282
76761
  { type: "role", role: "patient" },
76283
76762
  {
76284
76763
  type: "group",
@@ -76303,7 +76782,7 @@ function getGetPatternsRu() {
76303
76782
  template: {
76304
76783
  format: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C {patient}",
76305
76784
  tokens: [
76306
- { type: "literal", value: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C", alternatives: ["\u043F\u043E\u043B\u0443\u0447\u0438", "\u0432\u0437\u044F\u0442\u044C", "\u0432\u043E\u0437\u044C\u043C\u0438"] },
76785
+ { type: "literal", value: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C", alternatives: ["\u043F\u043E\u043B\u0443\u0447\u0438"] },
76307
76786
  { type: "role", role: "patient" }
76308
76787
  ]
76309
76788
  },
@@ -76344,7 +76823,7 @@ function getGetPatternsUk() {
76344
76823
  template: {
76345
76824
  format: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438 {patient} \u0437 {source}",
76346
76825
  tokens: [
76347
- { type: "literal", value: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438", alternatives: ["\u043E\u0442\u0440\u0438\u043C\u0430\u0439", "\u0432\u0437\u044F\u0442\u0438", "\u0432\u0456\u0437\u044C\u043C\u0438"] },
76826
+ { type: "literal", value: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438", alternatives: ["\u043E\u0442\u0440\u0438\u043C\u0430\u0439"] },
76348
76827
  { type: "role", role: "patient" },
76349
76828
  {
76350
76829
  type: "group",
@@ -76369,7 +76848,7 @@ function getGetPatternsUk() {
76369
76848
  template: {
76370
76849
  format: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438 {patient}",
76371
76850
  tokens: [
76372
- { type: "literal", value: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438", alternatives: ["\u043E\u0442\u0440\u0438\u043C\u0430\u0439", "\u0432\u0437\u044F\u0442\u0438", "\u0432\u0456\u0437\u044C\u043C\u0438"] },
76851
+ { type: "literal", value: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438", alternatives: ["\u043E\u0442\u0440\u0438\u043C\u0430\u0439"] },
76373
76852
  { type: "role", role: "patient" }
76374
76853
  ]
76375
76854
  },
@@ -76389,7 +76868,7 @@ function getGetPatternsVi() {
76389
76868
  template: {
76390
76869
  format: "l\u1EA5y gi\xE1 tr\u1ECB c\u1EE7a {target}",
76391
76870
  tokens: [
76392
- { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn", "l\u1EA5y"] },
76871
+ { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn"] },
76393
76872
  { type: "group", optional: true, tokens: [{ type: "literal", value: "c\u1EE7a" }] },
76394
76873
  { type: "role", role: "patient" }
76395
76874
  ]
@@ -76400,13 +76879,17 @@ function getGetPatternsVi() {
76400
76879
  },
76401
76880
  {
76402
76881
  id: "get-vi-simple",
76882
+ // Head was `l\u1ea5y` (alt `l\u1ea5y gi\u00e1 tr\u1ecb`) \u2014 but bare `l\u1ea5y` is vi's TAKE verb,
76883
+ // so this pattern claimed every `l\u1ea5y .active t\u1eeb \u2026`. vi's get verb is the
76884
+ // three-word `l\u1ea5y gi\u00e1 tr\u1ecb` ("take the value of"), which is what the i18n
76885
+ // transformer renders; the bare form has no valid `get` surface.
76403
76886
  language: "vi",
76404
76887
  command: "get",
76405
76888
  priority: 90,
76406
76889
  template: {
76407
- format: "l\u1EA5y {target}",
76890
+ format: "l\u1EA5y gi\xE1 tr\u1ECB {target}",
76408
76891
  tokens: [
76409
- { type: "literal", value: "l\u1EA5y", alternatives: ["nh\u1EADn", "l\u1EA5y gi\xE1 tr\u1ECB"] },
76892
+ { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn"] },
76410
76893
  { type: "role", role: "patient" }
76411
76894
  ]
76412
76895
  },
@@ -78165,6 +78648,12 @@ function getSendPatternsForLanguage(language) {
78165
78648
  }
78166
78649
 
78167
78650
  // src/patterns/pick.ts
78651
+ var PICK_UNIT_WORDS = /* @__PURE__ */ new Set(["character", "characters", "item", "items"]);
78652
+ var retypePickUnitWord = (raw) => {
78653
+ if (PICK_UNIT_WORDS.has(raw)) return { type: "expression", raw };
78654
+ const n = Number(raw);
78655
+ return createLiteral(raw !== "" && !Number.isNaN(n) ? n : raw);
78656
+ };
78168
78657
  function makePickVariantPattern(language, spec) {
78169
78658
  const tokens = [{ type: "literal", value: "pick" }];
78170
78659
  if (spec.objectMarkers?.length) {
@@ -78204,7 +78693,7 @@ function makePickVariantPattern(language, spec) {
78204
78693
  tokens
78205
78694
  },
78206
78695
  extraction: {
78207
- method: { position: 1 },
78696
+ method: { position: 1, transform: retypePickUnitWord },
78208
78697
  patient: { position: 2 },
78209
78698
  source: {
78210
78699
  marker: spec.srcMarker,
@@ -78255,7 +78744,7 @@ function makePickVerbFinalPattern(language, spec) {
78255
78744
  },
78256
78745
  extraction: {
78257
78746
  source: { position: 0 },
78258
- method: { position: 2 },
78747
+ method: { position: 2, transform: retypePickUnitWord },
78259
78748
  patient: { position: 3 }
78260
78749
  }
78261
78750
  };
@@ -80686,7 +81175,7 @@ function createRuntimeInstance(options) {
80686
81175
  return new Runtime(options);
80687
81176
  }
80688
81177
  function getVersion() {
80689
- return '2.0.0';
81178
+ return VERSION$1;
80690
81179
  }
80691
81180
  function toCompileError(error) {
80692
81181
  return {