@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.js CHANGED
@@ -4463,6 +4463,40 @@ function parseTakeCommand(ctx, identifierNode) {
4463
4463
  .endingAt(ctx.getPosition())
4464
4464
  .build();
4465
4465
  }
4466
+ function consumeViewTransitionTail(ctx, args) {
4467
+ if (!ctx.check('using')) {
4468
+ return false;
4469
+ }
4470
+ ctx.advance();
4471
+ if (!ctx.match('view')) {
4472
+ throw new Error("expected 'view transition' after 'using'");
4473
+ }
4474
+ if (!ctx.match('transition')) {
4475
+ throw new Error("expected 'transition' after 'using view'");
4476
+ }
4477
+ args.push(ctx.createIdentifier('using'));
4478
+ args.push(ctx.createIdentifier('view'));
4479
+ args.push(ctx.createIdentifier('transition'));
4480
+ return true;
4481
+ }
4482
+ function parseProcessCommand(ctx, identifierNode) {
4483
+ if (!ctx.check('partials')) {
4484
+ return null;
4485
+ }
4486
+ const args = [];
4487
+ consumeKeywordToArgs(ctx, 'partials', args);
4488
+ if (consumeKeywordToArgs(ctx, KEYWORDS$1.IN, args)) {
4489
+ const contentArg = parseOneArgument(ctx, ['using']);
4490
+ if (contentArg) {
4491
+ args.push(contentArg);
4492
+ }
4493
+ }
4494
+ consumeViewTransitionTail(ctx, args);
4495
+ return CommandNodeBuilder.fromIdentifier(identifierNode)
4496
+ .withArgs(...args)
4497
+ .endingAt(ctx.getPosition())
4498
+ .build();
4499
+ }
4466
4500
  function parseAddCommand(ctx, commandToken) {
4467
4501
  const args = [];
4468
4502
  if (ctx.match('{')) {
@@ -4584,6 +4618,7 @@ function parseSwapCommand(ctx, identifierNode) {
4584
4618
  args.push(contentExpr);
4585
4619
  }
4586
4620
  }
4621
+ consumeViewTransitionTail(ctx, args);
4587
4622
  return CommandNodeBuilder.fromIdentifier(identifierNode)
4588
4623
  .withArgs(...args)
4589
4624
  .endingAt(ctx.getPosition())
@@ -5097,6 +5132,9 @@ function parseCompoundCommand(ctx, identifierNode) {
5097
5132
  case 'swap':
5098
5133
  case 'morph':
5099
5134
  return parseSwapCommand(ctx, identifierNode);
5135
+ case 'process':
5136
+ return (parseProcessCommand(ctx, identifierNode) ??
5137
+ parseRegularCommand(ctx, identifierNode));
5100
5138
  default:
5101
5139
  return parseRegularCommand(ctx, identifierNode);
5102
5140
  }
@@ -5428,6 +5466,9 @@ function parseTellCommand(ctx, identifierNode) {
5428
5466
  if (!target) {
5429
5467
  throw new Error('tell command requires a target expression');
5430
5468
  }
5469
+ if (ctx.check(KEYWORDS$1.TO)) {
5470
+ ctx.advance();
5471
+ }
5431
5472
  const commands = [];
5432
5473
  while (!ctx.isAtEnd()) {
5433
5474
  if (ctx.checkIsCommand()) {
@@ -5447,7 +5488,11 @@ function parseTellCommand(ctx, identifierNode) {
5447
5488
  if (ctx.match(KEYWORDS$1.AND) || ctx.match(KEYWORDS$1.THEN)) {
5448
5489
  continue;
5449
5490
  }
5450
- if (ctx.check(KEYWORDS$1.ELSE) || ctx.check(KEYWORDS$1.END)) {
5491
+ if (ctx.check(KEYWORDS$1.ELSE)) {
5492
+ break;
5493
+ }
5494
+ if (ctx.check(KEYWORDS$1.END)) {
5495
+ ctx.advance();
5451
5496
  break;
5452
5497
  }
5453
5498
  if (ctx.checkIsCommand()) {
@@ -7785,6 +7830,7 @@ class Parser {
7785
7830
  'js',
7786
7831
  'tell',
7787
7832
  'fetch',
7833
+ 'process',
7788
7834
  ];
7789
7835
  if (this.semanticAdapter && !skipSemanticParsing.includes(commandName.toLowerCase())) {
7790
7836
  const remainingInput = this.getRemainingInput();
@@ -8739,6 +8785,12 @@ function isHTMLElement$2(value) {
8739
8785
  typeof value.tagName === 'string' &&
8740
8786
  'classList' in value);
8741
8787
  }
8788
+ function isInsertableNode(value) {
8789
+ if (value === null || typeof value !== 'object')
8790
+ return false;
8791
+ const nodeType = value.nodeType;
8792
+ return nodeType === 1 || nodeType === 3 || nodeType === 11;
8793
+ }
8742
8794
  function isNodeList(value) {
8743
8795
  return (value !== null &&
8744
8796
  typeof value === 'object' &&
@@ -10611,6 +10663,12 @@ function evaluateLiteral(node) {
10611
10663
  }
10612
10664
  async function evaluateIdentifier(node, context) {
10613
10665
  const name = node.name;
10666
+ if (name.startsWith('$')) {
10667
+ notifyGlobalRead(name.slice(1), context);
10668
+ }
10669
+ else if (node.scope === 'global') {
10670
+ notifyGlobalRead(name, context);
10671
+ }
10614
10672
  if (name === 'me' || name === 'my' || name === 'I') {
10615
10673
  return getExpr(context, 'me').evaluate(context);
10616
10674
  }
@@ -10630,7 +10688,6 @@ async function evaluateIdentifier(node, context) {
10630
10688
  return getExpr(context, 'document').evaluate(context);
10631
10689
  }
10632
10690
  if (node.scope === 'global' && context.globals?.has(name)) {
10633
- notifyGlobalRead(name, context);
10634
10691
  return context.globals.get(name);
10635
10692
  }
10636
10693
  if (node.scope === 'element') {
@@ -10641,12 +10698,9 @@ async function evaluateIdentifier(node, context) {
10641
10698
  return context.locals.get(name);
10642
10699
  }
10643
10700
  if (context.globals && context.globals.has(name)) {
10644
- if (name.startsWith('$'))
10645
- notifyGlobalRead(name.slice(1), context);
10646
10701
  return context.globals.get(name);
10647
10702
  }
10648
10703
  if (name.startsWith('$') && context.globals && context.globals.has(name.slice(1))) {
10649
- notifyGlobalRead(name.slice(1), context);
10650
10704
  return context.globals.get(name.slice(1));
10651
10705
  }
10652
10706
  if (context[name] !== undefined) {
@@ -11941,7 +11995,7 @@ class CommandAdapterV2 {
11941
11995
  return {
11942
11996
  description: this.impl.metadata?.description || '',
11943
11997
  examples: this.impl.metadata?.examples || [],
11944
- syntax: Array.isArray(syntax) ? syntax.join(' | ') : syntax || '',
11998
+ syntax: typeof syntax === 'string' ? syntax : syntax ? syntax.join(' | ') : '',
11945
11999
  };
11946
12000
  }
11947
12001
  async execute(context, ...args) {
@@ -12017,10 +12071,8 @@ class CommandAdapterV2 {
12017
12071
  }
12018
12072
  }
12019
12073
  validate(input) {
12020
- if (this.impl.validate) {
12021
- return this.impl.validate(input);
12022
- }
12023
- return { isValid: true, errors: [], suggestions: [] };
12074
+ const isValid = this.impl.validate ? this.impl.validate(input) : true;
12075
+ return { isValid, errors: [], suggestions: [] };
12024
12076
  }
12025
12077
  }
12026
12078
  class CommandRegistryV2 {
@@ -16875,7 +16927,7 @@ function command(config) {
16875
16927
  };
16876
16928
  }
16877
16929
  function commandMeta(metadata) {
16878
- return { isBlocking: false, hasBody: false, version: '1.0.0', ...metadata };
16930
+ return { ...metadata };
16879
16931
  }
16880
16932
  function createFactory(CommandClass) {
16881
16933
  return () => new CommandClass();
@@ -17778,7 +17830,7 @@ function insertContent(target, content, position) {
17778
17830
  insertReplace(target, content);
17779
17831
  return;
17780
17832
  }
17781
- if (isHTMLElement$2(content)) {
17833
+ if (isInsertableNode(content)) {
17782
17834
  insertElement(target, content, position);
17783
17835
  }
17784
17836
  else {
@@ -17789,7 +17841,7 @@ function insertContentSemantic(target, content, position) {
17789
17841
  insertContent(target, content, toInsertPosition(position));
17790
17842
  }
17791
17843
  function insertReplace(target, content) {
17792
- if (isHTMLElement$2(content)) {
17844
+ if (isInsertableNode(content)) {
17793
17845
  target.innerHTML = '';
17794
17846
  target.appendChild(content);
17795
17847
  }
@@ -17836,6 +17888,53 @@ function insertText(target, content, position) {
17836
17888
  target.insertAdjacentText(domPosition, content);
17837
17889
  }
17838
17890
  }
17891
+ function moveOrInsert(parent, element, ref) {
17892
+ const p = parent;
17893
+ if (typeof p.moveBefore === 'function' && element.isConnected && parent.isConnected) {
17894
+ try {
17895
+ p.moveBefore(element, ref);
17896
+ return;
17897
+ }
17898
+ catch {
17899
+ }
17900
+ }
17901
+ parent.insertBefore(element, ref);
17902
+ }
17903
+ function insertElementsInOrder(target, elements, position) {
17904
+ switch (position) {
17905
+ case 'beforeend':
17906
+ for (const el of elements)
17907
+ moveOrInsert(target, el, null);
17908
+ break;
17909
+ case 'afterbegin':
17910
+ for (let i = elements.length - 1; i >= 0; i--) {
17911
+ moveOrInsert(target, elements[i], target.firstChild);
17912
+ }
17913
+ break;
17914
+ case 'beforebegin': {
17915
+ const parent = target.parentElement;
17916
+ if (!parent)
17917
+ return;
17918
+ for (const el of elements)
17919
+ moveOrInsert(parent, el, target);
17920
+ break;
17921
+ }
17922
+ case 'afterend': {
17923
+ const parent = target.parentElement;
17924
+ if (!parent)
17925
+ return;
17926
+ for (let i = elements.length - 1; i >= 0; i--) {
17927
+ moveOrInsert(parent, elements[i], target.nextSibling);
17928
+ }
17929
+ break;
17930
+ }
17931
+ case 'replace':
17932
+ target.innerHTML = '';
17933
+ for (const el of elements)
17934
+ moveOrInsert(target, el, null);
17935
+ break;
17936
+ }
17937
+ }
17839
17938
  function removeElement(element) {
17840
17939
  if (element.parentNode) {
17841
17940
  element.remove();
@@ -18926,7 +19025,12 @@ let PutCommand = (() => {
18926
19025
  else {
18927
19026
  for (const t of targets) {
18928
19027
  const content = this.parseValue(value);
18929
- insertContentSemantic(t, content, position);
19028
+ if (Array.isArray(content)) {
19029
+ insertElementsInOrder(t, content, toInsertPosition(position));
19030
+ }
19031
+ else {
19032
+ insertContentSemantic(t, content, position);
19033
+ }
18930
19034
  }
18931
19035
  }
18932
19036
  return targets;
@@ -18958,6 +19062,11 @@ let PutCommand = (() => {
18958
19062
  parseValue(v) {
18959
19063
  if (isHTMLElement$2(v))
18960
19064
  return v;
19065
+ if (Array.isArray(v) && v.length > 0 && v.every(isHTMLElement$2)) {
19066
+ return v;
19067
+ }
19068
+ if (isInsertableNode(v))
19069
+ return v;
18961
19070
  return v == null ? '' : String(v);
18962
19071
  }
18963
19072
  looksLikeCss(s) {
@@ -20179,8 +20288,9 @@ const morphAdapter = {
20179
20288
  function getStartViewTransition() {
20180
20289
  if (typeof document === 'undefined')
20181
20290
  return undefined;
20182
- return document
20291
+ const fn = document
20183
20292
  .startViewTransition;
20293
+ return typeof fn === 'function' ? fn.bind(document) : undefined;
20184
20294
  }
20185
20295
  function isViewTransitionsSupported() {
20186
20296
  return typeof getStartViewTransition() === 'function';
@@ -20442,7 +20552,7 @@ let SwapCommand = (() => {
20442
20552
  };
20443
20553
  }
20444
20554
  }
20445
- let useViewTransition = false;
20555
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
20446
20556
  if (usingIndex !== -1) {
20447
20557
  const afterUsing = argKeywords.slice(usingIndex + 1);
20448
20558
  if (afterUsing.includes('view') && afterUsing.includes('transition')) {
@@ -20652,7 +20762,7 @@ let MorphCommand = (() => {
20652
20762
  const withIndex = argKeywords.findIndex(k => k === 'with');
20653
20763
  const overIndex = argKeywords.findIndex(k => k === 'over');
20654
20764
  const usingIndex = argKeywords.findIndex(k => k === 'using');
20655
- let useViewTransition = false;
20765
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
20656
20766
  if (usingIndex !== -1) {
20657
20767
  const afterUsing = argKeywords.slice(usingIndex + 1);
20658
20768
  if (afterUsing.includes('view') && afterUsing.includes('transition')) {
@@ -20733,7 +20843,11 @@ let MorphCommand = (() => {
20733
20843
  })();
20734
20844
  _classThis.metadata = commandMeta({
20735
20845
  description: 'Morph content into target elements (intelligent diffing, preserves state)',
20736
- syntax: ['morph <target> with <content>', 'morph over <target> with <content>'],
20846
+ syntax: [
20847
+ 'morph <target> with <content>',
20848
+ 'morph over <target> with <content>',
20849
+ 'morph <target> with <content> using view transition',
20850
+ ],
20737
20851
  examples: ['morph #target with it', 'morph over #modal with fetchedContent'],
20738
20852
  sideEffects: ['dom-mutation'],
20739
20853
  category: 'dom',
@@ -21365,24 +21479,33 @@ let ProcessPartialsCommand = (() => {
21365
21479
  if (!args || args.length === 0) {
21366
21480
  throw new Error('process partials command requires content argument');
21367
21481
  }
21368
- const evaluatedArgs = [];
21369
- const argStrings = [];
21370
- for (const arg of args) {
21371
- const evaluated = await evaluator.evaluate(arg, context);
21372
- evaluatedArgs.push(evaluated);
21373
- if (typeof evaluated === 'string') {
21374
- argStrings.push(evaluated.toLowerCase());
21375
- }
21376
- }
21377
- const partialsIndex = argStrings.findIndex(s => s === 'partials');
21482
+ const keywordOf = (node) => {
21483
+ const n = node;
21484
+ if (!n || typeof n !== 'object')
21485
+ return null;
21486
+ if (n.type === 'identifier' && typeof n.name === 'string')
21487
+ return n.name.toLowerCase();
21488
+ if (n.type === 'literal' && typeof n.value === 'string')
21489
+ return n.value.toLowerCase();
21490
+ return null;
21491
+ };
21492
+ const keywords = args.map(keywordOf);
21493
+ const partialsIndex = keywords.indexOf('partials');
21494
+ const inIndex = keywords.indexOf('in');
21495
+ let contentNode;
21378
21496
  if (partialsIndex === -1) {
21379
- throw new Error('process command expects "partials" keyword: process partials in <content>');
21497
+ if (inIndex !== -1) {
21498
+ throw new Error('process command expects "partials" keyword: process partials in <content>');
21499
+ }
21500
+ contentNode = args[0];
21380
21501
  }
21381
- const inIndex = argStrings.findIndex(s => s === 'in');
21382
- if (inIndex === -1 || inIndex <= partialsIndex) {
21383
- throw new Error('process partials command expects "in" keyword: process partials in <content>');
21502
+ else {
21503
+ if (inIndex === -1 || inIndex <= partialsIndex) {
21504
+ throw new Error('process partials command expects "in" keyword: process partials in <content>');
21505
+ }
21506
+ contentNode = args[inIndex + 1];
21384
21507
  }
21385
- const contentArg = evaluatedArgs[inIndex + 1];
21508
+ const contentArg = contentNode ? await evaluator.evaluate(contentNode, context) : undefined;
21386
21509
  let html;
21387
21510
  if (typeof contentArg === 'string') {
21388
21511
  html = contentArg;
@@ -21396,10 +21519,10 @@ let ProcessPartialsCommand = (() => {
21396
21519
  else {
21397
21520
  throw new Error('process partials: content must be an HTML string or element');
21398
21521
  }
21399
- const usingIndex = argStrings.findIndex(s => s === 'using');
21400
- let useViewTransition = false;
21522
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
21523
+ const usingIndex = keywords.indexOf('using');
21401
21524
  if (usingIndex !== -1) {
21402
- const remaining = argStrings.slice(usingIndex + 1).join(' ');
21525
+ const remaining = keywords.slice(usingIndex + 1);
21403
21526
  if (remaining.includes('view') && remaining.includes('transition')) {
21404
21527
  useViewTransition = true;
21405
21528
  }
@@ -27266,6 +27389,8 @@ class Runtime extends RuntimeBase {
27266
27389
  }
27267
27390
  }
27268
27391
 
27392
+ const VERSION$1 = '2.10.0';
27393
+
27269
27394
  // src/types.ts
27270
27395
  function createLiteral$1(value, dataType) {
27271
27396
  return dataType ? { type: "literal", value, dataType } : { type: "literal", value };
@@ -31607,14 +31732,26 @@ var MultilingualDSLImpl = class {
31607
31732
  }
31608
31733
  translate(input, fromLanguage, toLanguage) {
31609
31734
  if (isExplicitSyntax$1(input)) return input;
31610
- for (const language of [fromLanguage, toLanguage]) {
31611
- if (!this.profileProvider.getProfile(language)) {
31612
- throw new Error(
31613
- `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'.`
31614
- );
31735
+ let node;
31736
+ try {
31737
+ node = this.parseWithConfidence(input, fromLanguage).node;
31738
+ } catch (parseError) {
31739
+ if (this.hasGrammarProfile(fromLanguage) && this.hasGrammarProfile(toLanguage)) {
31740
+ return this.transformer.transform(input, fromLanguage, toLanguage);
31615
31741
  }
31742
+ throw parseError;
31743
+ }
31744
+ const rendered = this.registry.getSupportedLanguages().includes(toLanguage) ? this.render(node, toLanguage) : null;
31745
+ if (rendered != null) return rendered;
31746
+ if (this.hasGrammarProfile(fromLanguage) && this.hasGrammarProfile(toLanguage)) {
31747
+ return this.transformer.transform(input, fromLanguage, toLanguage);
31616
31748
  }
31617
- return this.transformer.transform(input, fromLanguage, toLanguage);
31749
+ throw new Error(
31750
+ `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).`
31751
+ );
31752
+ }
31753
+ hasGrammarProfile(language) {
31754
+ return this.profileProvider.getProfile(language) != null;
31618
31755
  }
31619
31756
  compile(input, language) {
31620
31757
  if (!this.codeGenerator) {
@@ -35888,7 +36025,7 @@ function getSchemasByCategory(category) {
35888
36025
  function getDefinedSchemas() {
35889
36026
  return Object.values(commandSchemas).filter((s) => s.roles.length > 0 || s.bareKeyword === true);
35890
36027
  }
35891
- 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;
36028
+ 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;
35892
36029
  var init_command_schemas = __esm({
35893
36030
  "src/generators/command-schemas.ts"() {
35894
36031
  toggleSchema = {
@@ -35897,7 +36034,6 @@ var init_command_schemas = __esm({
35897
36034
  category: "dom-class",
35898
36035
  primaryRole: "patient",
35899
36036
  // `toggle .active on #btn for 2s` \u2192 args ['.active'], modifiers { on, for }.
35900
- // NOTE: `duration` is read here but not declared in `roles` below.
35901
36037
  ast: { args: ["patient"], modifiers: { on: "destination", for: "duration" } },
35902
36038
  roles: [
35903
36039
  {
@@ -35907,7 +36043,13 @@ var init_command_schemas = __esm({
35907
36043
  expectedTypes: ["selector"],
35908
36044
  selectorKinds: ["class", "attribute"],
35909
36045
  svoPosition: 1,
35910
- sovPosition: 2
36046
+ sovPosition: 2,
36047
+ // zh: the transformer emits `\u5207\u6362 \u628a .active` (the profile's \u628a patient
36048
+ // marker), but natural zh writes `\u5207\u6362 .active` bare \u2014 the handcrafted
36049
+ // patterns' form. Optional accepts both; without it the generated
36050
+ // pattern REQUIRED \u628a and the slim bundles could not parse the bare
36051
+ // form at all. Same treatment as go's destination.
36052
+ markerOptional: { zh: true }
35911
36053
  },
35912
36054
  {
35913
36055
  role: "destination",
@@ -36245,6 +36387,8 @@ var init_command_schemas = __esm({
36245
36387
  markerOverride: {
36246
36388
  en: "",
36247
36389
  // No marker before destination in English: "set :x to 5"
36390
+ es: "",
36391
+ // "establecer x a 5" - no marker before variable (profile default `en` matched nothing)
36248
36392
  ja: "\u3092",
36249
36393
  // "x \u3092 10 \u306b \u8a2d\u5b9a" - variable gets object marker
36250
36394
  ko: "\uB97C",
@@ -36267,9 +36411,19 @@ var init_command_schemas = __esm({
36267
36411
  // generated hi set patterns carried the swapped markers and matched no
36268
36412
  // corpus, so the whole hi set-family (set-text/inner-html/style/attribute)
36269
36413
  // fell to the bare-event fallback (S6 set-trio).
36270
- hi: "\u0915\u094B"
36414
+ hi: "\u0915\u094B",
36271
36415
  // target (destination) gets \u0915\u094b
36272
- }
36416
+ // zh: the transformer emits the verb-first BA form `\u8bbe\u7f6e \u628a X \u5230 V`
36417
+ // (\u628a before the variable), while natural zh writes `\u8bbe\u7f6e X \u4e3a V`
36418
+ // (unmarked). \u628a as the marker, optional below, accepts both. The
36419
+ // profile default \u5728 matched neither form, so the generated zh set
36420
+ // patterns were dead weight and the slim bundles (schema-generated
36421
+ // patterns only) could not parse set at all.
36422
+ zh: "\u628A"
36423
+ },
36424
+ // Accept the unmarked natural form alongside the transformer's \u628a form
36425
+ // (same treatment as go's destination).
36426
+ markerOptional: { zh: true }
36273
36427
  },
36274
36428
  {
36275
36429
  role: "patient",
@@ -36312,8 +36466,14 @@ var init_command_schemas = __esm({
36312
36466
  // "x \u0995\u09c7 10 \u09a4\u09c7 \u09b8\u09c7\u099f" - destination marker on value
36313
36467
  qu: "man",
36314
36468
  // "x ta 10 man churay" - destination marker on value
36315
- hi: "\u092E\u0947\u0902"
36469
+ hi: "\u092E\u0947\u0902",
36316
36470
  // value (patient) gets \u092e\u0947\u0902 \u2014 see the destination note above
36471
+ // zh: the transformer/corpus form marks the value with \u5230 (`\u8bbe\u7f6e \u628a X
36472
+ // \u5230 V`); natural zh uses \u4e3a (`\u8bbe\u7f6e X \u4e3a V`). \u5230 is the override,
36473
+ // the \u4e3a-family rides along as variants (all merged as alternatives
36474
+ // by schemaMarkerAlternatives). Profile default \u628a was the PATIENT
36475
+ // marker, which never precedes set's value in either form.
36476
+ zh: "\u5230"
36317
36477
  },
36318
36478
  // Turkish dative is allomorphic under vowel harmony: the i18n transformer
36319
36479
  // emits `e` for quoted-string values (`"red" e`) but `-ya` for a value
@@ -36326,7 +36486,11 @@ var init_command_schemas = __esm({
36326
36486
  // not parse as a bare command while `t\u0131klama da @disabled i do\u011fru ya
36327
36487
  // ayarla` did. See STRUCTURAL_ARCS_ROADMAP.md (tr set-attribute).
36328
36488
  markerVariants: {
36329
- tr: ["e", "a", "ye", "ya"]
36489
+ tr: ["e", "a", "ye", "ya"],
36490
+ // Natural zh value markers (`\u8bbe\u7f6e X \u4e3a V`), simplified + traditional +
36491
+ // resultative \u2014 the handcrafted set-zh-full alternatives, kept parseable
36492
+ // alongside the transformer's \u5230 override above.
36493
+ zh: ["\u4E3A", "\u70BA", "\u6210"]
36330
36494
  }
36331
36495
  },
36332
36496
  {
@@ -36988,8 +37152,8 @@ var init_command_schemas = __esm({
36988
37152
  description: "Take content from a source element",
36989
37153
  category: "dom-content",
36990
37154
  primaryRole: "patient",
36991
- // `take .active from #parent` \u2192 args ['.active'], modifiers { from: '#parent' }.
36992
- ast: { args: ["patient"], modifiers: { from: "source" } },
37155
+ // `take .active from #parent for me` \u2192 args ['.active'], modifiers { from, for }.
37156
+ ast: { args: ["patient"], modifiers: { from: "source", for: "recipient" } },
36993
37157
  roles: [
36994
37158
  {
36995
37159
  role: "patient",
@@ -37012,6 +37176,38 @@ var init_command_schemas = __esm({
37012
37176
  expectedTypes: ["selector", "reference"],
37013
37177
  svoPosition: 2,
37014
37178
  sovPosition: 1
37179
+ },
37180
+ {
37181
+ role: "recipient",
37182
+ description: "The element the class moves ONTO (`take .active from .tab for me`)",
37183
+ required: false,
37184
+ // References only, deliberately. Upstream accepts an element expression,
37185
+ // but the 23 non-en corpus surfaces carry the recipient as a BARE
37186
+ // trailing pronoun (i18n renders `\u2026 von .tab-button ich`), so this slot
37187
+ // is marker-less almost everywhere and a selector-typed slot would
37188
+ // swallow the second selector of `take .active from .a .b`. English is
37189
+ // unaffected: `take` is on the core parser's skipSemanticParsing list,
37190
+ // so the traditional parser owns `for <anything>` there.
37191
+ expectedTypes: ["reference"],
37192
+ svoPosition: 3,
37193
+ sovPosition: 3,
37194
+ // NO default. The runtime already defaults the recipient to `me`
37195
+ // (commands/animation/take.ts), and a schema default would emit an
37196
+ // explicit `for me` modifier on every take \u2014 re-smuggling the exact
37197
+ // "absent means absent" semantics #859 removed from `source`.
37198
+ //
37199
+ // Shape-anchored on `reference`: without it this optional slot weighs
37200
+ // into every take pattern's denominator in `scoreRoleCoverage`, dropping
37201
+ // plain `take .active from .tab-button` from 1.0 to ~0.69 \u2014 the toggle-es
37202
+ // regression class the R1 role-set flip ratchet exists to catch.
37203
+ valueShape: "reference",
37204
+ // en only. The other 23 languages render the recipient unmarked, so a
37205
+ // marker there would never match their corpus rows; where the marker-less
37206
+ // slot proves inert they stay uncaptured and the pattern lands in the
37207
+ // baseline's `roleLossyPatterns` as named R1 burn-down tail. A language
37208
+ // gets a real particle here ONLY if the empty slot perturbs its other
37209
+ // parses (toggle's ja \u9593 / ko \ub3d9\uc548 case).
37210
+ markerOverride: { en: "for" }
37015
37211
  }
37016
37212
  ]
37017
37213
  };
@@ -38076,6 +38272,47 @@ var init_command_schemas = __esm({
38076
38272
  }
38077
38273
  ]
38078
38274
  };
38275
+ USING_VIEW_MARKER_ALL_LANGS = {
38276
+ en: "using view",
38277
+ es: "using view",
38278
+ pt: "using view",
38279
+ fr: "using view",
38280
+ de: "using view",
38281
+ it: "using view",
38282
+ ja: "using view",
38283
+ ko: "using view",
38284
+ zh: "using view",
38285
+ ar: "using view",
38286
+ he: "using view",
38287
+ hi: "using view",
38288
+ bn: "using view",
38289
+ tr: "using view",
38290
+ ru: "using view",
38291
+ uk: "using view",
38292
+ pl: "using view",
38293
+ id: "using view",
38294
+ vi: "using view",
38295
+ th: "using view",
38296
+ ms: "using view",
38297
+ tl: "using view",
38298
+ sw: "using view",
38299
+ qu: "using view"
38300
+ };
38301
+ VIEW_TRANSITION_MANNER_ROLE = {
38302
+ role: "manner",
38303
+ description: "Run the swap inside a `document.startViewTransition()` (`using view transition`)",
38304
+ required: false,
38305
+ // Both types, because the SAME word tokenizes differently per language and
38306
+ // the difference is an accident of vocabulary: `transition` is a command
38307
+ // keyword in en/fr (it is also their verb) and a bare identifier everywhere
38308
+ // else, which types it `literal` in the first group and `expression` in the
38309
+ // second. Measured: with `['literal']` alone only en and fr captured the
38310
+ // tail. Widening is safe precisely because the slot is marker-guarded \u2014
38311
+ // nothing reaches it until `using view` has matched.
38312
+ expectedTypes: ["literal", "expression"],
38313
+ valueShape: "keyword",
38314
+ markerOverride: USING_VIEW_MARKER_ALL_LANGS
38315
+ };
38079
38316
  swapSchema = {
38080
38317
  action: "swap",
38081
38318
  description: "Swap DOM content using various strategies (innerHTML, outerHTML, delete, etc.)",
@@ -38096,7 +38333,11 @@ var init_command_schemas = __esm({
38096
38333
  // work. Preserved verbatim by the Arc F migration (a faithful migration must
38097
38334
  // not change output) and pinned as two `drift` exemptions; this is the
38098
38335
  // behavior fix those entries were waiting for.
38099
- ast: { args: ["method", "destination", "patient"] },
38336
+ //
38337
+ // `manner` is the exception to "keyword-positional args": it rides as
38338
+ // `modifiers.viewTransition`, which SwapCommand.parseInput reads for presence
38339
+ // alongside its existing flat-args `using`/`view`/`transition` scan.
38340
+ ast: { args: ["method", "destination", "patient"], modifiers: { viewTransition: "manner" } },
38100
38341
  roles: [
38101
38342
  {
38102
38343
  role: "method",
@@ -38191,6 +38432,11 @@ var init_command_schemas = __esm({
38191
38432
  ar: "\u0628\u0640",
38192
38433
  tl: "nang"
38193
38434
  }
38435
+ },
38436
+ {
38437
+ ...VIEW_TRANSITION_MANNER_ROLE,
38438
+ svoPosition: 4,
38439
+ sovPosition: 4
38194
38440
  }
38195
38441
  ]
38196
38442
  };
@@ -38201,7 +38447,15 @@ var init_command_schemas = __esm({
38201
38447
  primaryRole: "patient",
38202
38448
  // `morph #list to it` \u2192 args [content], modifiers { on: element }.
38203
38449
  // Content is source or destination; the element being morphed is the patient.
38204
- ast: { args: [["source", "destination"]], modifiers: { on: "patient" } },
38450
+ //
38451
+ // `manner` rides as `modifiers.viewTransition`, same as swap/process \u2014
38452
+ // MorphCommand.parseInput reads it for presence alongside its existing
38453
+ // flat-args `using`/`view`/`transition` scan (the traditional-parser path,
38454
+ // which owns English because morph sits on SKIP_SEMANTIC_COMMANDS).
38455
+ ast: {
38456
+ args: [["source", "destination"]],
38457
+ modifiers: { on: "patient", viewTransition: "manner" }
38458
+ },
38205
38459
  roles: [
38206
38460
  {
38207
38461
  role: "patient",
@@ -38222,6 +38476,18 @@ var init_command_schemas = __esm({
38222
38476
  sovPosition: 2,
38223
38477
  markerOverride: { en: "to" }
38224
38478
  // "morph #target to it"
38479
+ },
38480
+ {
38481
+ // `morph #target to it using view transition` \u2014 the same tail as swap and
38482
+ // process, closed here for the same reason (#870's third-schema filing):
38483
+ // without the role the semantic parser matched morph at confidence 1.0
38484
+ // and stranded the tail, so every semantic-only consumer (multilingual
38485
+ // bundles, the bridge, `translate()`) silently dropped the animation
38486
+ // request in all 24 languages. Morph has NO hand-written patterns in any
38487
+ // language, so this schema role is the whole fix on the pattern side.
38488
+ ...VIEW_TRANSITION_MANNER_ROLE,
38489
+ svoPosition: 3,
38490
+ sovPosition: 3
38225
38491
  }
38226
38492
  ]
38227
38493
  };
@@ -38408,6 +38674,13 @@ var init_command_schemas = __esm({
38408
38674
  description: "Process hx-partial markup in HTML content",
38409
38675
  category: "dom-content",
38410
38676
  primaryRole: "patient",
38677
+ // `process partials in it` \u2192 args ['it']; the optional tail rides as
38678
+ // `modifiers.viewTransition`, which ProcessPartialsCommand.parseInput has
38679
+ // read since #861 (`raw.modifiers?.viewTransition !== undefined`). Without a
38680
+ // descriptor this schema fell through to `buildGenericCommand`, whose
38681
+ // modifier list is fixed (destination/duration/method/style) and would have
38682
+ // dropped a captured `manner` on the floor.
38683
+ ast: { args: ["patient"], modifiers: { viewTransition: "manner" } },
38411
38684
  roles: [
38412
38685
  {
38413
38686
  role: "patient",
@@ -38417,6 +38690,11 @@ var init_command_schemas = __esm({
38417
38690
  svoPosition: 1,
38418
38691
  sovPosition: 1,
38419
38692
  markerOverride: PARTIALS_IN_MARKER_ALL_LANGS
38693
+ },
38694
+ {
38695
+ ...VIEW_TRANSITION_MANNER_ROLE,
38696
+ svoPosition: 2,
38697
+ sovPosition: 2
38420
38698
  }
38421
38699
  ]
38422
38700
  };
@@ -40011,7 +40289,9 @@ var init_french = __esm({
40011
40289
  trigger: { primary: "d\xE9clencher", normalized: "trigger" },
40012
40290
  send: { primary: "envoyer", alternatives: ["envoie"], normalized: "send" },
40013
40291
  focus: { primary: "focaliser", alternatives: ["concentrer"], normalized: "focus" },
40014
- blur: { primary: "d\xE9focaliser", normalized: "blur" },
40292
+ // `d\u00e9focaliser` is an unattested infinitive; French pedagogy writes
40293
+ // `perte de focus` for the event (2026-07 terminology review).
40294
+ blur: { primary: "perte de focus", alternatives: ["d\xE9focaliser"], normalized: "blur" },
40015
40295
  // Phase 1 (v0.9.90): DOM / form state / debug
40016
40296
  // `vide` (adjective, "empty") is the i18n transformer's `is empty` predicate
40017
40297
  // form; `vider` is the verb ("to empty"). Accept both so the emptiness check
@@ -40024,7 +40304,13 @@ var init_french = __esm({
40024
40304
  reset: { primary: "r\xE9initialiser", alternatives: ["reinitialiser"], normalized: "reset" },
40025
40305
  breakpoint: { primary: "point-arr\xEAt", alternatives: ["point-arret"], normalized: "breakpoint" },
40026
40306
  go: { primary: "aller", alternatives: ["naviguer", "va"], normalized: "go" },
40027
- scroll: { primary: "d\xE9filer", alternatives: ["faire-d\xE9filer"], normalized: "scroll" },
40307
+ // MDN fr and the OQLF standardize the noun `d\u00e9filement` for the event; the
40308
+ // infinitive stays as an alternative.
40309
+ scroll: {
40310
+ primary: "d\xE9filement",
40311
+ alternatives: ["defilement", "d\xE9filer", "faire-d\xE9filer"],
40312
+ normalized: "scroll"
40313
+ },
40028
40314
  push: { primary: "pousser", normalized: "push" },
40029
40315
  replace: { primary: "remplacer", normalized: "replace" },
40030
40316
  process: { primary: "traiter", normalized: "process" },
@@ -40090,9 +40376,15 @@ var init_french = __esm({
40090
40376
  after: { primary: "apr\xE8s", normalized: "after" },
40091
40377
  // Common event names (for event handler patterns)
40092
40378
  click: { primary: "clic", alternatives: ["clique"], normalized: "click" },
40093
- // `resize` event (window-resize): dict emits redimensionner; register it so the
40094
- // event types as literal="resize" (matching en) instead of expression.
40095
- resize: { primary: "redimensionner", normalized: "resize" },
40379
+ // `resize` event (window-resize): the noun `redimensionnement` is the
40380
+ // attested event form ("lors du redimensionnement de la fen\u00eatre"). The dict
40381
+ // still emits redimensionner, kept as an alternative so the event keeps
40382
+ // typing as literal="resize" (matching en) instead of expression.
40383
+ resize: {
40384
+ primary: "redimensionnement",
40385
+ alternatives: ["redimensionner"],
40386
+ normalized: "resize"
40387
+ },
40096
40388
  hover: { primary: "survol", alternatives: ["survoler"], normalized: "hover" },
40097
40389
  submit: { primary: "soumission", alternatives: ["soumettre"], normalized: "submit" },
40098
40390
  input: { primary: "saisie", alternatives: ["entr\xE9e"], normalized: "input" },
@@ -43875,9 +44167,17 @@ var init_turkish = __esm({
43875
44167
  on: { primary: "\xFCzerinde", alternatives: ["zaman"], normalized: "on" },
43876
44168
  trigger: { primary: "tetikle", normalized: "trigger" },
43877
44169
  send: { primary: "g\xF6nder", normalized: "send" },
43878
- // DOM focus
43879
- focus: { primary: "odak", alternatives: ["odaklanma"], normalized: "focus" },
43880
- blur: { primary: "bulan\u0131k", alternatives: ["bulan\u0131kl\u0131k", "bulanik"], normalized: "blur" },
44170
+ // DOM focus. `odaklanma` (the act of focusing) leads over the static state
44171
+ // noun `odak` \u2014 Turkish event prose says "odaklanma olay\u0131". `bulan\u0131k` was
44172
+ // the optical blur (CSS filters, image processing), never the DOM event;
44173
+ // native usage is `odak kayb\u0131` (loss of focus). 2026-07 terminology-review
44174
+ // corrections; old forms stay as parse alternatives.
44175
+ focus: { primary: "odaklanma", alternatives: ["odak"], normalized: "focus" },
44176
+ blur: {
44177
+ primary: "odak kayb\u0131",
44178
+ alternatives: ["odak kaybi", "bulan\u0131k", "bulan\u0131kl\u0131k", "bulanik"],
44179
+ normalized: "blur"
44180
+ },
43881
44181
  // Phase 1 (v0.9.90): DOM / form state / debug
43882
44182
  empty: { primary: "bo\u015Falt", alternatives: ["bosalt", "bo\u015F"], normalized: "empty" },
43883
44183
  open: { primary: "a\xE7", alternatives: ["ac"], normalized: "open" },
@@ -43898,7 +44198,9 @@ var init_turkish = __esm({
43898
44198
  },
43899
44199
  hover: { primary: "\xFCzerine gelme", alternatives: ["\xFCzerinde gezinme"], normalized: "hover" },
43900
44200
  submit: { primary: "g\xF6nderme", normalized: "submit" },
43901
- input: { primary: "giri\u015F", alternatives: ["girdi", "giris"], normalized: "input" },
44201
+ // `giri\u015f` reads as entry/login (giri\u015f yapma) and can imply an auth event;
44202
+ // the data-input term is `girdi` ("Girdi (Input) Eventleri").
44203
+ input: { primary: "girdi", alternatives: ["giri\u015F", "giris"], normalized: "input" },
43902
44204
  change: { primary: "de\u011Fi\u015Fiklik", alternatives: ["de\u011Fi\u015Fim", "degisim"], normalized: "change" },
43903
44205
  // `load` event: the i18n dict emits y\u00fckle for `load`. Without this keyword the
43904
44206
  // SOV reorder's mid-stream `y\u00fckle de` (on load) tokenized as the `install`
@@ -43908,7 +44210,13 @@ var init_turkish = __esm({
43908
44210
  load: { primary: "y\xFCkle", normalized: "load" },
43909
44211
  // Navigation
43910
44212
  go: { primary: "git", normalized: "go" },
43911
- scroll: { primary: "kayd\u0131r", alternatives: ["kaydir"], normalized: "scroll" },
44213
+ // `kayd\u0131r` is the bare imperative; the attested event noun is `kayd\u0131rma`
44214
+ // ("kayd\u0131rma olay\u0131"). The imperative stays as an alternative.
44215
+ scroll: {
44216
+ primary: "kayd\u0131rma",
44217
+ alternatives: ["kaydirma", "kayd\u0131r", "kaydir"],
44218
+ normalized: "scroll"
44219
+ },
43912
44220
  push: { primary: "itele", alternatives: ["push"], normalized: "push" },
43913
44221
  replace: { primary: "de\u011Fi\u015Ftir_url", alternatives: ["degistir_url"], normalized: "replace" },
43914
44222
  process: { primary: "i\u015Fle", alternatives: ["isle"], normalized: "process" },
@@ -44861,6 +45169,60 @@ var init_chinese = __esm({
44861
45169
  }
44862
45170
  });
44863
45171
 
45172
+ // src/parser/utils/marker-resolution.ts
45173
+ function resolveMarkerForRole(roleSpec, profile) {
45174
+ const overrideMarker = roleSpec.markerOverride?.[profile.code];
45175
+ const defaultMarker = profile.roleMarkers[roleSpec.role];
45176
+ if (overrideMarker !== void 0) {
45177
+ const alternatives = legacyMarkerAlternatives(roleSpec, profile.code, overrideMarker);
45178
+ return {
45179
+ primary: overrideMarker,
45180
+ ...alternatives && { alternatives },
45181
+ position: defaultMarker?.position ?? "before",
45182
+ isOverride: true
45183
+ };
45184
+ }
45185
+ if (defaultMarker && defaultMarker.primary) {
45186
+ const result = {
45187
+ primary: defaultMarker.primary,
45188
+ position: defaultMarker.position,
45189
+ isOverride: false
45190
+ };
45191
+ if (defaultMarker.alternatives) {
45192
+ result.alternatives = defaultMarker.alternatives;
45193
+ }
45194
+ return result;
45195
+ }
45196
+ return null;
45197
+ }
45198
+ function legacyMarkerAlternatives(roleSpec, languageCode, overrideMarker) {
45199
+ const legacy = roleSpec.markerLegacy?.[languageCode];
45200
+ if (!legacy?.length) return void 0;
45201
+ const alternatives = [...new Set(legacy)].filter((a) => a && a !== overrideMarker);
45202
+ return alternatives.length ? alternatives : void 0;
45203
+ }
45204
+ function schemaMarkerAlternatives(roleSpec, languageCode, marker) {
45205
+ const legacy = roleSpec.markerLegacy?.[languageCode] ?? [];
45206
+ const variants = roleSpec.methodCarrier ? [] : roleSpec.markerVariants?.[languageCode] ?? [];
45207
+ const alternatives = [.../* @__PURE__ */ new Set([...legacy, ...variants])].filter((a) => a && a !== marker);
45208
+ return alternatives.length ? alternatives : void 0;
45209
+ }
45210
+ var ROLE_MARKER_CONCEPTS;
45211
+ var init_marker_resolution = __esm({
45212
+ "src/parser/utils/marker-resolution.ts"() {
45213
+ ROLE_MARKER_CONCEPTS = /* @__PURE__ */ new Set([
45214
+ "destination",
45215
+ "source",
45216
+ "patient",
45217
+ "object",
45218
+ "event",
45219
+ "eventmarker",
45220
+ "manner",
45221
+ "instrument"
45222
+ ]);
45223
+ }
45224
+ });
45225
+
44864
45226
  // src/patterns/put.ts
44865
45227
  function getPutPatternsBn() {
44866
45228
  return [
@@ -59721,49 +60083,6 @@ var init_role_positioning = __esm({
59721
60083
  }
59722
60084
  });
59723
60085
 
59724
- // src/parser/utils/marker-resolution.ts
59725
- function resolveMarkerForRole(roleSpec, profile) {
59726
- const overrideMarker = roleSpec.markerOverride?.[profile.code];
59727
- const defaultMarker = profile.roleMarkers[roleSpec.role];
59728
- if (overrideMarker !== void 0) {
59729
- const alternatives = legacyMarkerAlternatives(roleSpec, profile.code, overrideMarker);
59730
- return {
59731
- primary: overrideMarker,
59732
- ...alternatives && { alternatives },
59733
- position: defaultMarker?.position ?? "before",
59734
- isOverride: true
59735
- };
59736
- }
59737
- if (defaultMarker && defaultMarker.primary) {
59738
- const result = {
59739
- primary: defaultMarker.primary,
59740
- position: defaultMarker.position,
59741
- isOverride: false
59742
- };
59743
- if (defaultMarker.alternatives) {
59744
- result.alternatives = defaultMarker.alternatives;
59745
- }
59746
- return result;
59747
- }
59748
- return null;
59749
- }
59750
- function legacyMarkerAlternatives(roleSpec, languageCode, overrideMarker) {
59751
- const legacy = roleSpec.markerLegacy?.[languageCode];
59752
- if (!legacy?.length) return void 0;
59753
- const alternatives = [...new Set(legacy)].filter((a) => a && a !== overrideMarker);
59754
- return alternatives.length ? alternatives : void 0;
59755
- }
59756
- function schemaMarkerAlternatives(roleSpec, languageCode, marker) {
59757
- const legacy = roleSpec.markerLegacy?.[languageCode] ?? [];
59758
- const variants = roleSpec.methodCarrier ? [] : roleSpec.markerVariants?.[languageCode] ?? [];
59759
- const alternatives = [.../* @__PURE__ */ new Set([...legacy, ...variants])].filter((a) => a && a !== marker);
59760
- return alternatives.length ? alternatives : void 0;
59761
- }
59762
- var init_marker_resolution = __esm({
59763
- "src/parser/utils/marker-resolution.ts"() {
59764
- }
59765
- });
59766
-
59767
60086
  // src/generators/event-handlers-sov.ts
59768
60087
  function resolveRoleMarker(roleSpec, profile) {
59769
60088
  let marker;
@@ -59797,6 +60116,44 @@ function appendOptionalScope(tokens, extraction, commandSchema) {
59797
60116
  });
59798
60117
  extraction.scope = { fromRole: "scope" };
59799
60118
  }
60119
+ function appendOptionalViewTransition(tokens, extraction, commandSchema, languageCode) {
60120
+ appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, "manner", {
60121
+ requireMarker: true
60122
+ });
60123
+ }
60124
+ function appendOptionalRecipient(tokens, extraction, commandSchema, languageCode) {
60125
+ appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, "recipient", {
60126
+ requireMarker: false
60127
+ });
60128
+ }
60129
+ function appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, role, opts) {
60130
+ const spec = commandSchema.roles.find((r) => r.role === role && !r.required);
60131
+ if (!spec) return;
60132
+ const marker = spec.markerOverride?.[languageCode];
60133
+ if (opts.requireMarker && !marker) return;
60134
+ tokens.push({
60135
+ type: "group",
60136
+ optional: true,
60137
+ tokens: [
60138
+ ...(marker ? marker.split(/\s+/) : []).map((word) => ({
60139
+ type: "literal",
60140
+ value: word
60141
+ })),
60142
+ {
60143
+ type: "role",
60144
+ role,
60145
+ optional: true,
60146
+ expectedTypes: spec.expectedTypes,
60147
+ // Load-bearing, same as on the generated command patterns: it exempts
60148
+ // the trailing slot from the matcher's verb guard, keeps the uncaptured
60149
+ // slot out of `scoreRoleCoverage`'s denominator, and (for `keyword`)
60150
+ // normalizes the captured value type to the EN reference's `literal`.
60151
+ ...spec.valueShape !== void 0 ? { valueShape: spec.valueShape } : {}
60152
+ }
60153
+ ]
60154
+ });
60155
+ extraction[role] = { fromRole: role };
60156
+ }
59800
60157
  function generateSOVEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
59801
60158
  const tokens = [];
59802
60159
  tokens.push({ type: "role", role: "event", optional: false });
@@ -59891,6 +60248,15 @@ function generateSOVPatientFirstEventHandlerPattern(commandSchema, profile, keyw
59891
60248
  tokens.push(
59892
60249
  ...swapsOperands ? eventHandlerPatientGroup(commandSchema, trailingMarker) : eventHandlerDestinationGroup(commandSchema, trailingMarker)
59893
60250
  );
60251
+ const extraction = {
60252
+ action: { value: commandSchema.action },
60253
+ event: { fromRole: "event" },
60254
+ [frontedRole]: { fromRole: frontedRole },
60255
+ ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
60256
+ ...eventHandlerSourceExtraction(commandSchema)
60257
+ };
60258
+ appendOptionalRecipient(tokens, extraction, commandSchema, profile.code);
60259
+ appendOptionalViewTransition(tokens, extraction, commandSchema, profile.code);
59894
60260
  return {
59895
60261
  id: `${commandSchema.action}-event-${profile.code}-sov-patient-first`,
59896
60262
  language: profile.code,
@@ -59900,13 +60266,71 @@ function generateSOVPatientFirstEventHandlerPattern(commandSchema, profile, keyw
59900
60266
  format: `{patient} ${patientMarker?.primary || ""} {event} ${eventMarker.primary} ${keyword.primary}`,
59901
60267
  tokens
59902
60268
  },
59903
- extraction: {
59904
- action: { value: commandSchema.action },
59905
- event: { fromRole: "event" },
59906
- [frontedRole]: { fromRole: frontedRole },
59907
- ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
59908
- ...eventHandlerSourceExtraction(commandSchema)
60269
+ extraction
60270
+ };
60271
+ }
60272
+ function generateSOVPatientFirstSourceFrontedEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
60273
+ const sourceSpec = commandSchema.roles.find((r) => r.role === "source");
60274
+ if (!sourceSpec) return null;
60275
+ const { marker: sourceMarker, alternatives: sourceAlts } = resolveRoleMarker(sourceSpec, profile);
60276
+ const patientMarker = profile.roleMarkers.patient;
60277
+ if (!sourceMarker) return null;
60278
+ if (sourceMarker === eventMarker.primary || sourceMarker === patientMarker?.primary) return null;
60279
+ const tokens = [];
60280
+ tokens.push({ type: "role", role: "patient", optional: false });
60281
+ if (patientMarker) {
60282
+ tokens.push(
60283
+ patientMarker.alternatives ? {
60284
+ type: "literal",
60285
+ value: patientMarker.primary,
60286
+ alternatives: patientMarker.alternatives
60287
+ } : { type: "literal", value: patientMarker.primary }
60288
+ );
60289
+ }
60290
+ tokens.push({
60291
+ type: "role",
60292
+ role: "source",
60293
+ optional: false,
60294
+ ...sourceSpec.expectedTypes ? { expectedTypes: sourceSpec.expectedTypes } : {},
60295
+ ...sourceSpec.valueShape !== void 0 ? { valueShape: sourceSpec.valueShape } : {}
60296
+ });
60297
+ for (const word of sourceMarker.split(/\s+/)) {
60298
+ tokens.push(
60299
+ sourceAlts && sourceMarker.split(/\s+/).length === 1 ? { type: "literal", value: word, alternatives: sourceAlts } : { type: "literal", value: word }
60300
+ );
60301
+ }
60302
+ tokens.push({ type: "role", role: "event", optional: false });
60303
+ if (eventMarker.position === "after") {
60304
+ const markerWords = eventMarker.primary.split(/\s+/);
60305
+ if (markerWords.length > 1) {
60306
+ for (const word of markerWords) tokens.push({ type: "literal", value: word });
60307
+ } else {
60308
+ tokens.push(
60309
+ eventMarker.alternatives ? { type: "literal", value: eventMarker.primary, alternatives: eventMarker.alternatives } : { type: "literal", value: eventMarker.primary }
60310
+ );
59909
60311
  }
60312
+ }
60313
+ tokens.push(
60314
+ keyword.alternatives ? { type: "literal", value: keyword.primary, alternatives: keyword.alternatives } : { type: "literal", value: keyword.primary }
60315
+ );
60316
+ const extraction = {
60317
+ action: { value: commandSchema.action },
60318
+ event: { fromRole: "event" },
60319
+ patient: { fromRole: "patient" },
60320
+ source: { fromRole: "source" }
60321
+ };
60322
+ appendOptionalRecipient(tokens, extraction, commandSchema, profile.code);
60323
+ appendOptionalViewTransition(tokens, extraction, commandSchema, profile.code);
60324
+ return {
60325
+ id: `${commandSchema.action}-event-${profile.code}-sov-source-fronted`,
60326
+ language: profile.code,
60327
+ command: "on",
60328
+ priority: (config.basePriority ?? 100) + 48,
60329
+ template: {
60330
+ format: `{patient} ${patientMarker?.primary || ""} {source} ${sourceMarker} {event} ${eventMarker.primary} ${keyword.primary}`,
60331
+ tokens
60332
+ },
60333
+ extraction
59910
60334
  };
59911
60335
  }
59912
60336
  function generateSOVPatientFirstWithDestEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
@@ -60348,6 +60772,16 @@ function generateVSOVerbFirstEventHandlerPattern(commandSchema, profile, keyword
60348
60772
  });
60349
60773
  }
60350
60774
  }
60775
+ const extraction = {
60776
+ action: { value: commandSchema.action },
60777
+ event: { fromRole: "event" },
60778
+ [swapsOperands ? "destination" : "patient"]: {
60779
+ fromRole: swapsOperands ? "destination" : "patient"
60780
+ },
60781
+ ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
60782
+ ...eventHandlerSourceExtraction(commandSchema)
60783
+ };
60784
+ appendOptionalViewTransition(tokens, extraction, commandSchema, profile.code);
60351
60785
  return {
60352
60786
  id: `${commandSchema.action}-event-${profile.code}-vso-verb-first`,
60353
60787
  language: profile.code,
@@ -60358,15 +60792,7 @@ function generateVSOVerbFirstEventHandlerPattern(commandSchema, profile, keyword
60358
60792
  format: `${keyword.primary} {patient} ${destMarker?.primary || ""} {destination?} ${eventMarker.primary} {event}`,
60359
60793
  tokens
60360
60794
  },
60361
- extraction: {
60362
- action: { value: commandSchema.action },
60363
- event: { fromRole: "event" },
60364
- [swapsOperands ? "destination" : "patient"]: {
60365
- fromRole: swapsOperands ? "destination" : "patient"
60366
- },
60367
- ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
60368
- ...eventHandlerSourceExtraction(commandSchema)
60369
- }
60795
+ extraction
60370
60796
  };
60371
60797
  }
60372
60798
  function generateVSOVerbFirstTwoRoleEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
@@ -60809,6 +61235,14 @@ function generateEventHandlerPatterns(commandSchema, profile, config = defaultCo
60809
61235
  config
60810
61236
  )
60811
61237
  );
61238
+ const sourceFronted = generateSOVPatientFirstSourceFrontedEventHandlerPattern(
61239
+ commandSchema,
61240
+ profile,
61241
+ keyword,
61242
+ eventMarker,
61243
+ config
61244
+ );
61245
+ if (sourceFronted) patterns.push(sourceFronted);
60812
61246
  const destMarkerCheck = profile.roleMarkers.destination;
60813
61247
  if (destMarkerCheck && destMarkerCheck.primary !== eventMarker.primary) {
60814
61248
  patterns.push(
@@ -60968,7 +61402,11 @@ function buildRoleToken(roleSpec, profile) {
60968
61402
  type: "role",
60969
61403
  role: roleSpec.role,
60970
61404
  optional: !roleSpec.required,
60971
- expectedTypes: roleSpec.expectedTypes
61405
+ expectedTypes: roleSpec.expectedTypes,
61406
+ // The matcher reads this too \u2014 a `'keyword'`-shaped slot holds a fixed
61407
+ // keyword phrase (`using view transition`) and must not be skipped by the
61408
+ // trailing-slot verb guard.
61409
+ ...roleSpec.valueShape !== void 0 ? { valueShape: roleSpec.valueShape } : {}
60972
61410
  };
60973
61411
  const prefixLiteral = roleSpec.valuePrefixLiteral?.[profile.code];
60974
61412
  const pushPrefixed = () => {
@@ -61277,9 +61715,24 @@ var init_pick = __esm({
61277
61715
  });
61278
61716
 
61279
61717
  // src/patterns/languages/en/swap.ts
61280
- var swapSimpleEnglish, swapElementEnglish, swapStrategyOfEnglish, swapStrategyEnglish, swapPatternsEn;
61718
+ var VIEW_TRANSITION_TAIL, swapSimpleEnglish, swapElementEnglish, swapStrategyOfEnglish, swapStrategyEnglish, swapPatternsEn;
61281
61719
  var init_swap = __esm({
61282
61720
  "src/patterns/languages/en/swap.ts"() {
61721
+ VIEW_TRANSITION_TAIL = {
61722
+ type: "group",
61723
+ optional: true,
61724
+ tokens: [
61725
+ { type: "literal", value: "using" },
61726
+ { type: "literal", value: "view" },
61727
+ {
61728
+ type: "role",
61729
+ role: "manner",
61730
+ optional: true,
61731
+ expectedTypes: ["literal", "expression"],
61732
+ valueShape: "keyword"
61733
+ }
61734
+ ]
61735
+ };
61283
61736
  swapSimpleEnglish = {
61284
61737
  id: "swap-en-handcrafted",
61285
61738
  language: "en",
@@ -61287,11 +61740,12 @@ var init_swap = __esm({
61287
61740
  priority: 110,
61288
61741
  // Higher than generated patterns
61289
61742
  template: {
61290
- format: "swap {method} {destination}",
61743
+ format: "swap {method} {destination} [using view {manner}]",
61291
61744
  tokens: [
61292
61745
  { type: "literal", value: "swap" },
61293
61746
  { type: "role", role: "method" },
61294
- { type: "role", role: "destination" }
61747
+ { type: "role", role: "destination" },
61748
+ VIEW_TRANSITION_TAIL
61295
61749
  ]
61296
61750
  },
61297
61751
  extraction: {
@@ -61305,12 +61759,13 @@ var init_swap = __esm({
61305
61759
  command: "swap",
61306
61760
  priority: 120,
61307
61761
  template: {
61308
- format: "swap {destination} with {patient}",
61762
+ format: "swap {destination} with {patient} [using view {manner}]",
61309
61763
  tokens: [
61310
61764
  { type: "literal", value: "swap" },
61311
61765
  { type: "role", role: "destination" },
61312
61766
  { type: "literal", value: "with" },
61313
- { type: "role", role: "patient" }
61767
+ { type: "role", role: "patient" },
61768
+ VIEW_TRANSITION_TAIL
61314
61769
  ]
61315
61770
  },
61316
61771
  extraction: {}
@@ -61321,14 +61776,15 @@ var init_swap = __esm({
61321
61776
  command: "swap",
61322
61777
  priority: 140,
61323
61778
  template: {
61324
- format: "swap {method} of {destination} with {patient}",
61779
+ format: "swap {method} of {destination} with {patient} [using view {manner}]",
61325
61780
  tokens: [
61326
61781
  { type: "literal", value: "swap" },
61327
61782
  { type: "role", role: "method" },
61328
61783
  { type: "literal", value: "of" },
61329
61784
  { type: "role", role: "destination" },
61330
61785
  { type: "literal", value: "with" },
61331
- { type: "role", role: "patient" }
61786
+ { type: "role", role: "patient" },
61787
+ VIEW_TRANSITION_TAIL
61332
61788
  ]
61333
61789
  },
61334
61790
  extraction: {}
@@ -61339,13 +61795,14 @@ var init_swap = __esm({
61339
61795
  command: "swap",
61340
61796
  priority: 130,
61341
61797
  template: {
61342
- format: "swap {method} {destination} with {patient}",
61798
+ format: "swap {method} {destination} with {patient} [using view {manner}]",
61343
61799
  tokens: [
61344
61800
  { type: "literal", value: "swap" },
61345
61801
  { type: "role", role: "method" },
61346
61802
  { type: "role", role: "destination" },
61347
61803
  { type: "literal", value: "with" },
61348
- { type: "role", role: "patient" }
61804
+ { type: "role", role: "patient" },
61805
+ VIEW_TRANSITION_TAIL
61349
61806
  ]
61350
61807
  },
61351
61808
  extraction: {}
@@ -64715,6 +65172,7 @@ function isTypeCompatible(actualType, expectedTypes) {
64715
65172
  }
64716
65173
 
64717
65174
  // src/parser/pattern-matcher.ts
65175
+ init_marker_resolution();
64718
65176
  init_command_schemas();
64719
65177
 
64720
65178
  // src/parser/utils/possessive-keywords.ts
@@ -65279,7 +65737,8 @@ var DefaultConfidenceModel = class {
65279
65737
  const hasDefault = (role) => {
65280
65738
  return pattern.extraction?.[role]?.default !== void 0;
65281
65739
  };
65282
- const schemaRoles = commandSchemas[pattern.command]?.roles;
65740
+ const wrappedAction = pattern.command === "on" ? pattern.extraction?.action?.value : void 0;
65741
+ const schemaRoles = commandSchemas[wrappedAction ?? pattern.command]?.roles;
65283
65742
  const isShapeAnchored = (role) => schemaRoles?.find((r) => r.role === role)?.valueShape !== void 0;
65284
65743
  for (const token of pattern.template.tokens) {
65285
65744
  if (token.type === "role") {
@@ -65683,7 +66142,7 @@ var _PatternMatcher = class _PatternMatcher {
65683
66142
  return patternToken.optional || false;
65684
66143
  }
65685
66144
  }
65686
- if (patternToken.optional && nextPatternToken === void 0 && patternToken.role !== "event" && patternToken.role !== "action" && token.kind === "keyword") {
66145
+ if (patternToken.optional && nextPatternToken === void 0 && patternToken.role !== "event" && patternToken.role !== "action" && patternToken.valueShape !== "keyword" && token.kind === "keyword") {
65687
66146
  const verbNorm = (token.normalized ?? token.value).toLowerCase();
65688
66147
  if (verbNorm in commandSchemas) {
65689
66148
  return true;
@@ -65838,7 +66297,14 @@ var _PatternMatcher = class _PatternMatcher {
65838
66297
  }
65839
66298
  }
65840
66299
  }
65841
- captured.set(patternToken.role, value);
66300
+ if (patternToken.valueShape === "keyword" && value.type === "expression") {
66301
+ captured.set(
66302
+ patternToken.role,
66303
+ createLiteral(String(value.raw ?? ""))
66304
+ );
66305
+ } else {
66306
+ captured.set(patternToken.role, value);
66307
+ }
65842
66308
  tokens.advance();
65843
66309
  if (patternToken.role === "event") {
65844
66310
  const filterTok = tokens.peek();
@@ -66427,17 +66893,7 @@ var _PatternMatcher = class _PatternMatcher {
66427
66893
  * so this never blocks a genuine `my value` / `its style` possessive.
66428
66894
  */
66429
66895
  isRoleMarkerConcept(normalized2) {
66430
- const markerConcepts = /* @__PURE__ */ new Set([
66431
- "destination",
66432
- "source",
66433
- "patient",
66434
- "object",
66435
- "event",
66436
- "eventmarker",
66437
- "manner",
66438
- "instrument"
66439
- ]);
66440
- return markerConcepts.has(normalized2.toLowerCase());
66896
+ return ROLE_MARKER_CONCEPTS.has(normalized2.toLowerCase());
66441
66897
  }
66442
66898
  /**
66443
66899
  * Does `token` look like an EVENT name for the `event` role? Events are bare
@@ -66823,7 +67279,7 @@ var _PatternMatcher = class _PatternMatcher {
66823
67279
  */
66824
67280
  matchGroupToken(tokens, patternToken, captured, nextPatternToken) {
66825
67281
  const mark = tokens.mark();
66826
- const capturedBefore = new Set(captured.keys());
67282
+ const capturedBefore = new Map(captured);
66827
67283
  const success = this.matchTokenSequence(
66828
67284
  tokens,
66829
67285
  patternToken.tokens,
@@ -66837,6 +67293,11 @@ var _PatternMatcher = class _PatternMatcher {
66837
67293
  captured.delete(role);
66838
67294
  }
66839
67295
  }
67296
+ for (const [role, value] of capturedBefore) {
67297
+ if (captured.get(role) !== value) {
67298
+ captured.set(role, value);
67299
+ }
67300
+ }
66840
67301
  return patternToken.optional || false;
66841
67302
  }
66842
67303
  return true;
@@ -66938,7 +67399,7 @@ var _PatternMatcher = class _PatternMatcher {
66938
67399
  } else if (rule.value !== void 0) {
66939
67400
  captured.set(role, { type: "literal", value: rule.value });
66940
67401
  } else if (rule.default) {
66941
- captured.set(role, rule.default);
67402
+ captured.set(role, { ...rule.default, implicit: true });
66942
67403
  }
66943
67404
  }
66944
67405
  }
@@ -67226,6 +67687,7 @@ function registerTokenizer2(tokenizer) {
67226
67687
  // src/parser/semantic-parser.ts
67227
67688
  init_registry();
67228
67689
  init_command_schemas();
67690
+ init_marker_resolution();
67229
67691
 
67230
67692
  // src/parser/block-parser.ts
67231
67693
  init_registry();
@@ -67891,14 +68353,20 @@ var SemanticRendererImpl = class {
67891
68353
  return parts.join(" ");
67892
68354
  }
67893
68355
  /**
67894
- * Join a statement list the way a block body reads: ` then ` between siblings,
67895
- * but a single space immediately after a loop/tell block header (whose body
67896
- * follows directly). Shared by renderConditional's branches; renderCompound
67897
- * keeps its own copy because it also handles the multi-handler and bind-feature
67898
- * cases.
68356
+ * Join a statement list the way a block body reads: the target language's `then`
68357
+ * between siblings, but a single space immediately after a loop/tell block header
68358
+ * (whose body follows directly). Used by renderConditional's branches;
68359
+ * renderCompound keeps its own copy because it also handles the multi-handler
68360
+ * and bind-feature cases.
68361
+ *
68362
+ * The chain word is localized (`this.keyword(language, 'then')`) for the same
68363
+ * reason renderCompound localizes it: a hardcoded English `then` leaks into every
68364
+ * non-en block body (`\u3082\u3057 \u2026 \u524a\u9664 then \u8ffd\u52a0`), which no target-language tokenizer
68365
+ * recognizes as a connector.
67899
68366
  */
67900
68367
  joinStatements(statements, language) {
67901
68368
  const rendered = statements.map((s) => this.render(s, language));
68369
+ const thenKw = this.keyword(language, "then");
67902
68370
  let out = rendered[0] ?? "";
67903
68371
  for (let i = 1; i < rendered.length; i++) {
67904
68372
  const prev = statements[i - 1];
@@ -67906,7 +68374,7 @@ var SemanticRendererImpl = class {
67906
68374
  if (prev.kind === "command" && BLOCK_NEEDS_TRAILING_END.has(prev.action)) {
67907
68375
  out += ` ${this.keyword(language, "end")}`;
67908
68376
  }
67909
- out += (afterBlockHeader ? " " : " then ") + rendered[i];
68377
+ out += (afterBlockHeader ? " " : ` ${thenKw} `) + rendered[i];
67910
68378
  }
67911
68379
  return out;
67912
68380
  }
@@ -68079,6 +68547,7 @@ var SemanticRendererImpl = class {
68079
68547
  if (!roleToken) continue;
68080
68548
  const roleValue = node.roles.get(roleName);
68081
68549
  if (roleValue?.type !== "reference" || roleValue.value !== "me") continue;
68550
+ if (!roleValue.implicit) continue;
68082
68551
  if (roleName === "destination") {
68083
68552
  const patient = node.roles.get("patient");
68084
68553
  if (patient?.type === "literal" && patient.dataType === "string") continue;
@@ -68520,7 +68989,7 @@ function fillSchemaDefaults(node) {
68520
68989
  const roles = node.roles;
68521
68990
  for (const spec of schema.roles) {
68522
68991
  if (spec.default !== void 0 && !roles.has(spec.role)) {
68523
- roles.set(spec.role, { ...spec.default });
68992
+ roles.set(spec.role, { ...spec.default, implicit: true });
68524
68993
  }
68525
68994
  }
68526
68995
  }
@@ -69125,7 +69594,7 @@ var _SemanticParserImpl = class _SemanticParserImpl {
69125
69594
  }
69126
69595
  let eventModifiers = patternMatcher.extractEventModifiers(tokens);
69127
69596
  const sourceValue = match.captured.get("source");
69128
- if (sourceValue && match.pattern.id.includes("source") && !(sourceValue.type === "reference" && sourceValue.value === "me")) {
69597
+ if (sourceValue && match.pattern.id.endsWith("source") && !(sourceValue.type === "reference" && sourceValue.value === "me")) {
69129
69598
  eventModifiers = { ...eventModifiers ?? {}, from: sourceValue };
69130
69599
  }
69131
69600
  const additionalEvents = this.extractOrConjunctionEvents(tokens, language);
@@ -69275,13 +69744,18 @@ var _SemanticParserImpl = class _SemanticParserImpl {
69275
69744
  if (!spec) return true;
69276
69745
  return spec.expectedTypes.length > 0 && !spec.expectedTypes.includes(valType(val));
69277
69746
  };
69747
+ const isMarkerConceptJunk = (role, val) => role === "patient" && !!schema && !schema.roles.some((r) => r.role === "patient") && valType(val) === "literal" && ROLE_MARKER_CONCEPTS.has(
69748
+ String(val.value ?? "").toLowerCase()
69749
+ );
69278
69750
  const preservesFused = !!first && first.kind === "command" && Object.entries(roles).every(([role, val]) => {
69279
- if (isIgnorableFusedRole(role, val)) return true;
69751
+ if (isIgnorableFusedRole(role, val) || isMarkerConceptJunk(role, val)) return true;
69280
69752
  const rv = first.roles.get(mapRole(role));
69281
69753
  if (rv !== void 0 && valType(rv) === valType(val)) return true;
69282
69754
  if (role === "patient" && actionName === "pick" && valType(val) === "literal") {
69283
69755
  const mv = first.roles.get("method");
69284
- return mv !== void 0 && valType(mv) === "literal" && String(mv.value) === String(val.value);
69756
+ const mvType = valType(mv);
69757
+ const mvSurface = mvType === "literal" ? String(mv.value) : mvType === "expression" ? String(mv.raw) : void 0;
69758
+ return mvSurface !== void 0 && mvSurface === String(val.value);
69285
69759
  }
69286
69760
  return false;
69287
69761
  });
@@ -69291,7 +69765,12 @@ var _SemanticParserImpl = class _SemanticParserImpl {
69291
69765
  // the swap can never swallow a body command. The body-swallowing
69292
69766
  // generated repeat matches none of these ids.
69293
69767
  /^repeat-.*-(times|for-in|while-head|until-head)$/.test(reparsePid);
69294
- if (reparsed.length === 1 && first && first.kind === "command" && first.action === actionName && preservesFused && headOnlyOk && first.roles.size > Object.keys(roles).length) {
69768
+ if (reparsed.length === 1 && first && first.kind === "command" && first.action === actionName && preservesFused && headOnlyOk && // Strictly-more: the re-parse must recover something the fused
69769
+ // capture lacked. Junk marker captures are excluded from the
69770
+ // count \u2014 a fused shape whose ONLY role is a swallowed marker
69771
+ // (scroll: `destination:literal="destination"`) would otherwise
69772
+ // tie 1 > 1 and veto its own repair.
69773
+ first.roles.size > Object.entries(roles).filter(([r, v]) => !isMarkerConceptJunk(r, v)).length) {
69295
69774
  commandNode = first;
69296
69775
  while (tokens.position() < clauseEnd) tokens.advance();
69297
69776
  } else {
@@ -76090,7 +76569,7 @@ function getGetPatternsBn() {
76090
76569
  tokens: [
76091
76570
  { type: "role", role: "source" },
76092
76571
  { type: "literal", value: "\u09A5\u09C7\u0995\u09C7" },
76093
- { type: "literal", value: "\u09AA\u09BE\u09A8", alternatives: ["\u09A8\u09BF\u09A8"] }
76572
+ { type: "literal", value: "\u09AA\u09BE\u09A8" }
76094
76573
  ]
76095
76574
  },
76096
76575
  extraction: {
@@ -76106,7 +76585,7 @@ function getGetPatternsBn() {
76106
76585
  template: {
76107
76586
  format: "\u09AA\u09BE\u09A8 {source}",
76108
76587
  tokens: [
76109
- { type: "literal", value: "\u09AA\u09BE\u09A8", alternatives: ["\u09A8\u09BF\u09A8"] },
76588
+ { type: "literal", value: "\u09AA\u09BE\u09A8" },
76110
76589
  { type: "role", role: "source" }
76111
76590
  ]
76112
76591
  },
@@ -76190,7 +76669,7 @@ function getGetPatternsIt() {
76190
76669
  template: {
76191
76670
  format: "ottenere {patient} da {source}",
76192
76671
  tokens: [
76193
- { type: "literal", value: "ottenere", alternatives: ["ottieni", "get", "prendere"] },
76672
+ { type: "literal", value: "ottenere", alternatives: ["ottieni", "get"] },
76194
76673
  { type: "role", role: "patient" },
76195
76674
  {
76196
76675
  type: "group",
@@ -76280,7 +76759,7 @@ function getGetPatternsRu() {
76280
76759
  template: {
76281
76760
  format: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C {patient} \u0438\u0437 {source}",
76282
76761
  tokens: [
76283
- { 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"] },
76762
+ { type: "literal", value: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C", alternatives: ["\u043F\u043E\u043B\u0443\u0447\u0438"] },
76284
76763
  { type: "role", role: "patient" },
76285
76764
  {
76286
76765
  type: "group",
@@ -76305,7 +76784,7 @@ function getGetPatternsRu() {
76305
76784
  template: {
76306
76785
  format: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C {patient}",
76307
76786
  tokens: [
76308
- { 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"] },
76787
+ { type: "literal", value: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C", alternatives: ["\u043F\u043E\u043B\u0443\u0447\u0438"] },
76309
76788
  { type: "role", role: "patient" }
76310
76789
  ]
76311
76790
  },
@@ -76346,7 +76825,7 @@ function getGetPatternsUk() {
76346
76825
  template: {
76347
76826
  format: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438 {patient} \u0437 {source}",
76348
76827
  tokens: [
76349
- { 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"] },
76828
+ { type: "literal", value: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438", alternatives: ["\u043E\u0442\u0440\u0438\u043C\u0430\u0439"] },
76350
76829
  { type: "role", role: "patient" },
76351
76830
  {
76352
76831
  type: "group",
@@ -76371,7 +76850,7 @@ function getGetPatternsUk() {
76371
76850
  template: {
76372
76851
  format: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438 {patient}",
76373
76852
  tokens: [
76374
- { 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"] },
76853
+ { type: "literal", value: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438", alternatives: ["\u043E\u0442\u0440\u0438\u043C\u0430\u0439"] },
76375
76854
  { type: "role", role: "patient" }
76376
76855
  ]
76377
76856
  },
@@ -76391,7 +76870,7 @@ function getGetPatternsVi() {
76391
76870
  template: {
76392
76871
  format: "l\u1EA5y gi\xE1 tr\u1ECB c\u1EE7a {target}",
76393
76872
  tokens: [
76394
- { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn", "l\u1EA5y"] },
76873
+ { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn"] },
76395
76874
  { type: "group", optional: true, tokens: [{ type: "literal", value: "c\u1EE7a" }] },
76396
76875
  { type: "role", role: "patient" }
76397
76876
  ]
@@ -76402,13 +76881,17 @@ function getGetPatternsVi() {
76402
76881
  },
76403
76882
  {
76404
76883
  id: "get-vi-simple",
76884
+ // Head was `l\u1ea5y` (alt `l\u1ea5y gi\u00e1 tr\u1ecb`) \u2014 but bare `l\u1ea5y` is vi's TAKE verb,
76885
+ // so this pattern claimed every `l\u1ea5y .active t\u1eeb \u2026`. vi's get verb is the
76886
+ // three-word `l\u1ea5y gi\u00e1 tr\u1ecb` ("take the value of"), which is what the i18n
76887
+ // transformer renders; the bare form has no valid `get` surface.
76405
76888
  language: "vi",
76406
76889
  command: "get",
76407
76890
  priority: 90,
76408
76891
  template: {
76409
- format: "l\u1EA5y {target}",
76892
+ format: "l\u1EA5y gi\xE1 tr\u1ECB {target}",
76410
76893
  tokens: [
76411
- { type: "literal", value: "l\u1EA5y", alternatives: ["nh\u1EADn", "l\u1EA5y gi\xE1 tr\u1ECB"] },
76894
+ { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn"] },
76412
76895
  { type: "role", role: "patient" }
76413
76896
  ]
76414
76897
  },
@@ -78167,6 +78650,12 @@ function getSendPatternsForLanguage(language) {
78167
78650
  }
78168
78651
 
78169
78652
  // src/patterns/pick.ts
78653
+ var PICK_UNIT_WORDS = /* @__PURE__ */ new Set(["character", "characters", "item", "items"]);
78654
+ var retypePickUnitWord = (raw) => {
78655
+ if (PICK_UNIT_WORDS.has(raw)) return { type: "expression", raw };
78656
+ const n = Number(raw);
78657
+ return createLiteral(raw !== "" && !Number.isNaN(n) ? n : raw);
78658
+ };
78170
78659
  function makePickVariantPattern(language, spec) {
78171
78660
  const tokens = [{ type: "literal", value: "pick" }];
78172
78661
  if (spec.objectMarkers?.length) {
@@ -78206,7 +78695,7 @@ function makePickVariantPattern(language, spec) {
78206
78695
  tokens
78207
78696
  },
78208
78697
  extraction: {
78209
- method: { position: 1 },
78698
+ method: { position: 1, transform: retypePickUnitWord },
78210
78699
  patient: { position: 2 },
78211
78700
  source: {
78212
78701
  marker: spec.srcMarker,
@@ -78257,7 +78746,7 @@ function makePickVerbFinalPattern(language, spec) {
78257
78746
  },
78258
78747
  extraction: {
78259
78748
  source: { position: 0 },
78260
- method: { position: 2 },
78749
+ method: { position: 2, transform: retypePickUnitWord },
78261
78750
  patient: { position: 3 }
78262
78751
  }
78263
78752
  };
@@ -80688,7 +81177,7 @@ function createRuntimeInstance(options) {
80688
81177
  return new Runtime(options);
80689
81178
  }
80690
81179
  function getVersion() {
80691
- return '2.0.0';
81180
+ return VERSION$1;
80692
81181
  }
80693
81182
  function toCompileError(error) {
80694
81183
  return {