@hyperfixi/core 2.9.4 → 2.10.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 (91) hide show
  1. package/dist/ast-utils/index.js +295 -85
  2. package/dist/ast-utils/index.mjs +295 -85
  3. package/dist/chunks/{bridge-DhmZ3Khh.js → bridge-CPNAPYAo.js} +2 -2
  4. package/dist/chunks/browser-modular-B0lGdcoP.js +2 -0
  5. package/dist/chunks/{index-DKrx4rv2.js → index-BQkkNlzO.js} +2 -2
  6. package/dist/commands/advanced/async.d.ts +0 -8
  7. package/dist/commands/advanced/js.d.ts +0 -8
  8. package/dist/commands/animation/measure.d.ts +0 -8
  9. package/dist/commands/animation/settle.d.ts +0 -8
  10. package/dist/commands/animation/start-view-transition.d.ts +0 -8
  11. package/dist/commands/animation/take.d.ts +0 -8
  12. package/dist/commands/animation/transition.d.ts +0 -8
  13. package/dist/commands/async/fetch.d.ts +0 -8
  14. package/dist/commands/async/wait.d.ts +0 -8
  15. package/dist/commands/behaviors/install.d.ts +0 -8
  16. package/dist/commands/content/append.d.ts +0 -8
  17. package/dist/commands/content/prepend.d.ts +0 -8
  18. package/dist/commands/control-flow/break.d.ts +0 -8
  19. package/dist/commands/control-flow/continue.d.ts +0 -8
  20. package/dist/commands/control-flow/exit.d.ts +0 -8
  21. package/dist/commands/control-flow/halt.d.ts +0 -8
  22. package/dist/commands/control-flow/if.d.ts +0 -8
  23. package/dist/commands/control-flow/repeat.d.ts +0 -8
  24. package/dist/commands/control-flow/return.d.ts +0 -8
  25. package/dist/commands/control-flow/throw.d.ts +0 -8
  26. package/dist/commands/data/clear.d.ts +0 -8
  27. package/dist/commands/data/default.d.ts +0 -8
  28. package/dist/commands/data/get.d.ts +0 -8
  29. package/dist/commands/data/increment.d.ts +0 -8
  30. package/dist/commands/data/set.d.ts +0 -8
  31. package/dist/commands/decorators/index.d.ts +2 -8
  32. package/dist/commands/dom/add.d.ts +0 -8
  33. package/dist/commands/dom/close.d.ts +0 -8
  34. package/dist/commands/dom/empty.d.ts +0 -8
  35. package/dist/commands/dom/hide.d.ts +0 -8
  36. package/dist/commands/dom/make.d.ts +0 -8
  37. package/dist/commands/dom/open.d.ts +0 -8
  38. package/dist/commands/dom/process-partials.d.ts +0 -8
  39. package/dist/commands/dom/put.d.ts +0 -8
  40. package/dist/commands/dom/remove.d.ts +0 -8
  41. package/dist/commands/dom/reset.d.ts +0 -8
  42. package/dist/commands/dom/select.d.ts +0 -8
  43. package/dist/commands/dom/show.d.ts +0 -8
  44. package/dist/commands/dom/swap.d.ts +2 -18
  45. package/dist/commands/dom/toggle.d.ts +0 -8
  46. package/dist/commands/events/trigger.d.ts +0 -8
  47. package/dist/commands/execution/blur.d.ts +0 -8
  48. package/dist/commands/execution/call.d.ts +0 -8
  49. package/dist/commands/execution/focus.d.ts +0 -8
  50. package/dist/commands/execution/pseudo-command.d.ts +0 -8
  51. package/dist/commands/index.js +82 -23
  52. package/dist/commands/index.mjs +82 -23
  53. package/dist/commands/navigation/go.d.ts +0 -8
  54. package/dist/commands/navigation/push-url.d.ts +0 -8
  55. package/dist/commands/navigation/scroll-to.d.ts +0 -8
  56. package/dist/commands/templates/render.d.ts +0 -8
  57. package/dist/commands/utility/beep.d.ts +0 -8
  58. package/dist/commands/utility/breakpoint.d.ts +0 -8
  59. package/dist/commands/utility/copy.d.ts +0 -8
  60. package/dist/commands/utility/log.d.ts +0 -8
  61. package/dist/commands/utility/pick.d.ts +0 -8
  62. package/dist/commands/utility/tell.d.ts +0 -8
  63. package/dist/hyperfixi-browser-classic-i18n.js +1 -1
  64. package/dist/hyperfixi-browser-minimal.js +1 -1
  65. package/dist/hyperfixi-browser-standard.js +1 -1
  66. package/dist/hyperfixi-browser.js +1 -1
  67. package/dist/hyperfixi-classic-i18n.js +1 -1
  68. package/dist/hyperfixi-hx-v4.js +1 -1
  69. package/dist/hyperfixi-minimal.js +1 -1
  70. package/dist/hyperfixi-multilingual.js +1 -1
  71. package/dist/hyperfixi-standard.js +1 -1
  72. package/dist/hyperfixi.js +1 -1
  73. package/dist/hyperfixi.mjs +1 -1
  74. package/dist/index.js +441 -143
  75. package/dist/index.min.js +1 -1
  76. package/dist/index.mjs +441 -143
  77. package/dist/lokascript-browser-classic-i18n.js +1 -1
  78. package/dist/lokascript-browser-minimal.js +1 -1
  79. package/dist/lokascript-browser-standard.js +1 -1
  80. package/dist/lokascript-browser.js +1 -1
  81. package/dist/lokascript-multilingual.js +1 -1
  82. package/dist/parser/command-parsers/dom-commands.d.ts +1 -0
  83. package/dist/parser/full-parser.js +47 -1
  84. package/dist/parser/full-parser.mjs +47 -1
  85. package/dist/reference/index.js +6 -5
  86. package/dist/reference/index.mjs +6 -5
  87. package/dist/registry/index.js +50 -6
  88. package/dist/registry/index.mjs +50 -6
  89. package/dist/runtime/command-adapter.d.ts +8 -8
  90. package/package.json +5 -5
  91. 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();
@@ -11939,7 +11985,7 @@ class CommandAdapterV2 {
11939
11985
  return {
11940
11986
  description: this.impl.metadata?.description || '',
11941
11987
  examples: this.impl.metadata?.examples || [],
11942
- syntax: Array.isArray(syntax) ? syntax.join(' | ') : syntax || '',
11988
+ syntax: typeof syntax === 'string' ? syntax : syntax ? syntax.join(' | ') : '',
11943
11989
  };
11944
11990
  }
11945
11991
  async execute(context, ...args) {
@@ -12015,10 +12061,8 @@ class CommandAdapterV2 {
12015
12061
  }
12016
12062
  }
12017
12063
  validate(input) {
12018
- if (this.impl.validate) {
12019
- return this.impl.validate(input);
12020
- }
12021
- return { isValid: true, errors: [], suggestions: [] };
12064
+ const isValid = this.impl.validate ? this.impl.validate(input) : true;
12065
+ return { isValid, errors: [], suggestions: [] };
12022
12066
  }
12023
12067
  }
12024
12068
  class CommandRegistryV2 {
@@ -16873,7 +16917,7 @@ function command(config) {
16873
16917
  };
16874
16918
  }
16875
16919
  function commandMeta(metadata) {
16876
- return { isBlocking: false, hasBody: false, version: '1.0.0', ...metadata };
16920
+ return { ...metadata };
16877
16921
  }
16878
16922
  function createFactory(CommandClass) {
16879
16923
  return () => new CommandClass();
@@ -20440,7 +20484,7 @@ let SwapCommand = (() => {
20440
20484
  };
20441
20485
  }
20442
20486
  }
20443
- let useViewTransition = false;
20487
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
20444
20488
  if (usingIndex !== -1) {
20445
20489
  const afterUsing = argKeywords.slice(usingIndex + 1);
20446
20490
  if (afterUsing.includes('view') && afterUsing.includes('transition')) {
@@ -20650,7 +20694,7 @@ let MorphCommand = (() => {
20650
20694
  const withIndex = argKeywords.findIndex(k => k === 'with');
20651
20695
  const overIndex = argKeywords.findIndex(k => k === 'over');
20652
20696
  const usingIndex = argKeywords.findIndex(k => k === 'using');
20653
- let useViewTransition = false;
20697
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
20654
20698
  if (usingIndex !== -1) {
20655
20699
  const afterUsing = argKeywords.slice(usingIndex + 1);
20656
20700
  if (afterUsing.includes('view') && afterUsing.includes('transition')) {
@@ -20731,7 +20775,11 @@ let MorphCommand = (() => {
20731
20775
  })();
20732
20776
  _classThis.metadata = commandMeta({
20733
20777
  description: 'Morph content into target elements (intelligent diffing, preserves state)',
20734
- syntax: ['morph <target> with <content>', 'morph over <target> with <content>'],
20778
+ syntax: [
20779
+ 'morph <target> with <content>',
20780
+ 'morph over <target> with <content>',
20781
+ 'morph <target> with <content> using view transition',
20782
+ ],
20735
20783
  examples: ['morph #target with it', 'morph over #modal with fetchedContent'],
20736
20784
  sideEffects: ['dom-mutation'],
20737
20785
  category: 'dom',
@@ -21363,24 +21411,33 @@ let ProcessPartialsCommand = (() => {
21363
21411
  if (!args || args.length === 0) {
21364
21412
  throw new Error('process partials command requires content argument');
21365
21413
  }
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');
21414
+ const keywordOf = (node) => {
21415
+ const n = node;
21416
+ if (!n || typeof n !== 'object')
21417
+ return null;
21418
+ if (n.type === 'identifier' && typeof n.name === 'string')
21419
+ return n.name.toLowerCase();
21420
+ if (n.type === 'literal' && typeof n.value === 'string')
21421
+ return n.value.toLowerCase();
21422
+ return null;
21423
+ };
21424
+ const keywords = args.map(keywordOf);
21425
+ const partialsIndex = keywords.indexOf('partials');
21426
+ const inIndex = keywords.indexOf('in');
21427
+ let contentNode;
21376
21428
  if (partialsIndex === -1) {
21377
- throw new Error('process command expects "partials" keyword: process partials in <content>');
21429
+ if (inIndex !== -1) {
21430
+ throw new Error('process command expects "partials" keyword: process partials in <content>');
21431
+ }
21432
+ contentNode = args[0];
21378
21433
  }
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>');
21434
+ else {
21435
+ if (inIndex === -1 || inIndex <= partialsIndex) {
21436
+ throw new Error('process partials command expects "in" keyword: process partials in <content>');
21437
+ }
21438
+ contentNode = args[inIndex + 1];
21382
21439
  }
21383
- const contentArg = evaluatedArgs[inIndex + 1];
21440
+ const contentArg = contentNode ? await evaluator.evaluate(contentNode, context) : undefined;
21384
21441
  let html;
21385
21442
  if (typeof contentArg === 'string') {
21386
21443
  html = contentArg;
@@ -21394,10 +21451,10 @@ let ProcessPartialsCommand = (() => {
21394
21451
  else {
21395
21452
  throw new Error('process partials: content must be an HTML string or element');
21396
21453
  }
21397
- const usingIndex = argStrings.findIndex(s => s === 'using');
21398
- let useViewTransition = false;
21454
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
21455
+ const usingIndex = keywords.indexOf('using');
21399
21456
  if (usingIndex !== -1) {
21400
- const remaining = argStrings.slice(usingIndex + 1).join(' ');
21457
+ const remaining = keywords.slice(usingIndex + 1);
21401
21458
  if (remaining.includes('view') && remaining.includes('transition')) {
21402
21459
  useViewTransition = true;
21403
21460
  }
@@ -35886,7 +35943,7 @@ function getSchemasByCategory(category) {
35886
35943
  function getDefinedSchemas() {
35887
35944
  return Object.values(commandSchemas).filter((s) => s.roles.length > 0 || s.bareKeyword === true);
35888
35945
  }
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;
35946
+ 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
35947
  var init_command_schemas = __esm({
35891
35948
  "src/generators/command-schemas.ts"() {
35892
35949
  toggleSchema = {
@@ -35895,7 +35952,6 @@ var init_command_schemas = __esm({
35895
35952
  category: "dom-class",
35896
35953
  primaryRole: "patient",
35897
35954
  // `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
35955
  ast: { args: ["patient"], modifiers: { on: "destination", for: "duration" } },
35900
35956
  roles: [
35901
35957
  {
@@ -36986,8 +37042,8 @@ var init_command_schemas = __esm({
36986
37042
  description: "Take content from a source element",
36987
37043
  category: "dom-content",
36988
37044
  primaryRole: "patient",
36989
- // `take .active from #parent` \u2192 args ['.active'], modifiers { from: '#parent' }.
36990
- ast: { args: ["patient"], modifiers: { from: "source" } },
37045
+ // `take .active from #parent for me` \u2192 args ['.active'], modifiers { from, for }.
37046
+ ast: { args: ["patient"], modifiers: { from: "source", for: "recipient" } },
36991
37047
  roles: [
36992
37048
  {
36993
37049
  role: "patient",
@@ -37010,6 +37066,38 @@ var init_command_schemas = __esm({
37010
37066
  expectedTypes: ["selector", "reference"],
37011
37067
  svoPosition: 2,
37012
37068
  sovPosition: 1
37069
+ },
37070
+ {
37071
+ role: "recipient",
37072
+ description: "The element the class moves ONTO (`take .active from .tab for me`)",
37073
+ required: false,
37074
+ // References only, deliberately. Upstream accepts an element expression,
37075
+ // but the 23 non-en corpus surfaces carry the recipient as a BARE
37076
+ // trailing pronoun (i18n renders `\u2026 von .tab-button ich`), so this slot
37077
+ // is marker-less almost everywhere and a selector-typed slot would
37078
+ // swallow the second selector of `take .active from .a .b`. English is
37079
+ // unaffected: `take` is on the core parser's skipSemanticParsing list,
37080
+ // so the traditional parser owns `for <anything>` there.
37081
+ expectedTypes: ["reference"],
37082
+ svoPosition: 3,
37083
+ sovPosition: 3,
37084
+ // NO default. The runtime already defaults the recipient to `me`
37085
+ // (commands/animation/take.ts), and a schema default would emit an
37086
+ // explicit `for me` modifier on every take \u2014 re-smuggling the exact
37087
+ // "absent means absent" semantics #859 removed from `source`.
37088
+ //
37089
+ // Shape-anchored on `reference`: without it this optional slot weighs
37090
+ // into every take pattern's denominator in `scoreRoleCoverage`, dropping
37091
+ // plain `take .active from .tab-button` from 1.0 to ~0.69 \u2014 the toggle-es
37092
+ // regression class the R1 role-set flip ratchet exists to catch.
37093
+ valueShape: "reference",
37094
+ // en only. The other 23 languages render the recipient unmarked, so a
37095
+ // marker there would never match their corpus rows; where the marker-less
37096
+ // slot proves inert they stay uncaptured and the pattern lands in the
37097
+ // baseline's `roleLossyPatterns` as named R1 burn-down tail. A language
37098
+ // gets a real particle here ONLY if the empty slot perturbs its other
37099
+ // parses (toggle's ja \u9593 / ko \ub3d9\uc548 case).
37100
+ markerOverride: { en: "for" }
37013
37101
  }
37014
37102
  ]
37015
37103
  };
@@ -38074,6 +38162,47 @@ var init_command_schemas = __esm({
38074
38162
  }
38075
38163
  ]
38076
38164
  };
38165
+ USING_VIEW_MARKER_ALL_LANGS = {
38166
+ en: "using view",
38167
+ es: "using view",
38168
+ pt: "using view",
38169
+ fr: "using view",
38170
+ de: "using view",
38171
+ it: "using view",
38172
+ ja: "using view",
38173
+ ko: "using view",
38174
+ zh: "using view",
38175
+ ar: "using view",
38176
+ he: "using view",
38177
+ hi: "using view",
38178
+ bn: "using view",
38179
+ tr: "using view",
38180
+ ru: "using view",
38181
+ uk: "using view",
38182
+ pl: "using view",
38183
+ id: "using view",
38184
+ vi: "using view",
38185
+ th: "using view",
38186
+ ms: "using view",
38187
+ tl: "using view",
38188
+ sw: "using view",
38189
+ qu: "using view"
38190
+ };
38191
+ VIEW_TRANSITION_MANNER_ROLE = {
38192
+ role: "manner",
38193
+ description: "Run the swap inside a `document.startViewTransition()` (`using view transition`)",
38194
+ required: false,
38195
+ // Both types, because the SAME word tokenizes differently per language and
38196
+ // the difference is an accident of vocabulary: `transition` is a command
38197
+ // keyword in en/fr (it is also their verb) and a bare identifier everywhere
38198
+ // else, which types it `literal` in the first group and `expression` in the
38199
+ // second. Measured: with `['literal']` alone only en and fr captured the
38200
+ // tail. Widening is safe precisely because the slot is marker-guarded \u2014
38201
+ // nothing reaches it until `using view` has matched.
38202
+ expectedTypes: ["literal", "expression"],
38203
+ valueShape: "keyword",
38204
+ markerOverride: USING_VIEW_MARKER_ALL_LANGS
38205
+ };
38077
38206
  swapSchema = {
38078
38207
  action: "swap",
38079
38208
  description: "Swap DOM content using various strategies (innerHTML, outerHTML, delete, etc.)",
@@ -38094,7 +38223,11 @@ var init_command_schemas = __esm({
38094
38223
  // work. Preserved verbatim by the Arc F migration (a faithful migration must
38095
38224
  // not change output) and pinned as two `drift` exemptions; this is the
38096
38225
  // behavior fix those entries were waiting for.
38097
- ast: { args: ["method", "destination", "patient"] },
38226
+ //
38227
+ // `manner` is the exception to "keyword-positional args": it rides as
38228
+ // `modifiers.viewTransition`, which SwapCommand.parseInput reads for presence
38229
+ // alongside its existing flat-args `using`/`view`/`transition` scan.
38230
+ ast: { args: ["method", "destination", "patient"], modifiers: { viewTransition: "manner" } },
38098
38231
  roles: [
38099
38232
  {
38100
38233
  role: "method",
@@ -38189,6 +38322,11 @@ var init_command_schemas = __esm({
38189
38322
  ar: "\u0628\u0640",
38190
38323
  tl: "nang"
38191
38324
  }
38325
+ },
38326
+ {
38327
+ ...VIEW_TRANSITION_MANNER_ROLE,
38328
+ svoPosition: 4,
38329
+ sovPosition: 4
38192
38330
  }
38193
38331
  ]
38194
38332
  };
@@ -38199,7 +38337,15 @@ var init_command_schemas = __esm({
38199
38337
  primaryRole: "patient",
38200
38338
  // `morph #list to it` \u2192 args [content], modifiers { on: element }.
38201
38339
  // Content is source or destination; the element being morphed is the patient.
38202
- ast: { args: [["source", "destination"]], modifiers: { on: "patient" } },
38340
+ //
38341
+ // `manner` rides as `modifiers.viewTransition`, same as swap/process \u2014
38342
+ // MorphCommand.parseInput reads it for presence alongside its existing
38343
+ // flat-args `using`/`view`/`transition` scan (the traditional-parser path,
38344
+ // which owns English because morph sits on SKIP_SEMANTIC_COMMANDS).
38345
+ ast: {
38346
+ args: [["source", "destination"]],
38347
+ modifiers: { on: "patient", viewTransition: "manner" }
38348
+ },
38203
38349
  roles: [
38204
38350
  {
38205
38351
  role: "patient",
@@ -38220,6 +38366,18 @@ var init_command_schemas = __esm({
38220
38366
  sovPosition: 2,
38221
38367
  markerOverride: { en: "to" }
38222
38368
  // "morph #target to it"
38369
+ },
38370
+ {
38371
+ // `morph #target to it using view transition` \u2014 the same tail as swap and
38372
+ // process, closed here for the same reason (#870's third-schema filing):
38373
+ // without the role the semantic parser matched morph at confidence 1.0
38374
+ // and stranded the tail, so every semantic-only consumer (multilingual
38375
+ // bundles, the bridge, `translate()`) silently dropped the animation
38376
+ // request in all 24 languages. Morph has NO hand-written patterns in any
38377
+ // language, so this schema role is the whole fix on the pattern side.
38378
+ ...VIEW_TRANSITION_MANNER_ROLE,
38379
+ svoPosition: 3,
38380
+ sovPosition: 3
38223
38381
  }
38224
38382
  ]
38225
38383
  };
@@ -38406,6 +38564,13 @@ var init_command_schemas = __esm({
38406
38564
  description: "Process hx-partial markup in HTML content",
38407
38565
  category: "dom-content",
38408
38566
  primaryRole: "patient",
38567
+ // `process partials in it` \u2192 args ['it']; the optional tail rides as
38568
+ // `modifiers.viewTransition`, which ProcessPartialsCommand.parseInput has
38569
+ // read since #861 (`raw.modifiers?.viewTransition !== undefined`). Without a
38570
+ // descriptor this schema fell through to `buildGenericCommand`, whose
38571
+ // modifier list is fixed (destination/duration/method/style) and would have
38572
+ // dropped a captured `manner` on the floor.
38573
+ ast: { args: ["patient"], modifiers: { viewTransition: "manner" } },
38409
38574
  roles: [
38410
38575
  {
38411
38576
  role: "patient",
@@ -38415,6 +38580,11 @@ var init_command_schemas = __esm({
38415
38580
  svoPosition: 1,
38416
38581
  sovPosition: 1,
38417
38582
  markerOverride: PARTIALS_IN_MARKER_ALL_LANGS
38583
+ },
38584
+ {
38585
+ ...VIEW_TRANSITION_MANNER_ROLE,
38586
+ svoPosition: 2,
38587
+ sovPosition: 2
38418
38588
  }
38419
38589
  ]
38420
38590
  };
@@ -40009,7 +40179,9 @@ var init_french = __esm({
40009
40179
  trigger: { primary: "d\xE9clencher", normalized: "trigger" },
40010
40180
  send: { primary: "envoyer", alternatives: ["envoie"], normalized: "send" },
40011
40181
  focus: { primary: "focaliser", alternatives: ["concentrer"], normalized: "focus" },
40012
- blur: { primary: "d\xE9focaliser", normalized: "blur" },
40182
+ // `d\u00e9focaliser` is an unattested infinitive; French pedagogy writes
40183
+ // `perte de focus` for the event (2026-07 terminology review).
40184
+ blur: { primary: "perte de focus", alternatives: ["d\xE9focaliser"], normalized: "blur" },
40013
40185
  // Phase 1 (v0.9.90): DOM / form state / debug
40014
40186
  // `vide` (adjective, "empty") is the i18n transformer's `is empty` predicate
40015
40187
  // form; `vider` is the verb ("to empty"). Accept both so the emptiness check
@@ -40022,7 +40194,13 @@ var init_french = __esm({
40022
40194
  reset: { primary: "r\xE9initialiser", alternatives: ["reinitialiser"], normalized: "reset" },
40023
40195
  breakpoint: { primary: "point-arr\xEAt", alternatives: ["point-arret"], normalized: "breakpoint" },
40024
40196
  go: { primary: "aller", alternatives: ["naviguer", "va"], normalized: "go" },
40025
- scroll: { primary: "d\xE9filer", alternatives: ["faire-d\xE9filer"], normalized: "scroll" },
40197
+ // MDN fr and the OQLF standardize the noun `d\u00e9filement` for the event; the
40198
+ // infinitive stays as an alternative.
40199
+ scroll: {
40200
+ primary: "d\xE9filement",
40201
+ alternatives: ["defilement", "d\xE9filer", "faire-d\xE9filer"],
40202
+ normalized: "scroll"
40203
+ },
40026
40204
  push: { primary: "pousser", normalized: "push" },
40027
40205
  replace: { primary: "remplacer", normalized: "replace" },
40028
40206
  process: { primary: "traiter", normalized: "process" },
@@ -40088,9 +40266,15 @@ var init_french = __esm({
40088
40266
  after: { primary: "apr\xE8s", normalized: "after" },
40089
40267
  // Common event names (for event handler patterns)
40090
40268
  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" },
40269
+ // `resize` event (window-resize): the noun `redimensionnement` is the
40270
+ // attested event form ("lors du redimensionnement de la fen\u00eatre"). The dict
40271
+ // still emits redimensionner, kept as an alternative so the event keeps
40272
+ // typing as literal="resize" (matching en) instead of expression.
40273
+ resize: {
40274
+ primary: "redimensionnement",
40275
+ alternatives: ["redimensionner"],
40276
+ normalized: "resize"
40277
+ },
40094
40278
  hover: { primary: "survol", alternatives: ["survoler"], normalized: "hover" },
40095
40279
  submit: { primary: "soumission", alternatives: ["soumettre"], normalized: "submit" },
40096
40280
  input: { primary: "saisie", alternatives: ["entr\xE9e"], normalized: "input" },
@@ -43873,9 +44057,17 @@ var init_turkish = __esm({
43873
44057
  on: { primary: "\xFCzerinde", alternatives: ["zaman"], normalized: "on" },
43874
44058
  trigger: { primary: "tetikle", normalized: "trigger" },
43875
44059
  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" },
44060
+ // DOM focus. `odaklanma` (the act of focusing) leads over the static state
44061
+ // noun `odak` \u2014 Turkish event prose says "odaklanma olay\u0131". `bulan\u0131k` was
44062
+ // the optical blur (CSS filters, image processing), never the DOM event;
44063
+ // native usage is `odak kayb\u0131` (loss of focus). 2026-07 terminology-review
44064
+ // corrections; old forms stay as parse alternatives.
44065
+ focus: { primary: "odaklanma", alternatives: ["odak"], normalized: "focus" },
44066
+ blur: {
44067
+ primary: "odak kayb\u0131",
44068
+ alternatives: ["odak kaybi", "bulan\u0131k", "bulan\u0131kl\u0131k", "bulanik"],
44069
+ normalized: "blur"
44070
+ },
43879
44071
  // Phase 1 (v0.9.90): DOM / form state / debug
43880
44072
  empty: { primary: "bo\u015Falt", alternatives: ["bosalt", "bo\u015F"], normalized: "empty" },
43881
44073
  open: { primary: "a\xE7", alternatives: ["ac"], normalized: "open" },
@@ -43896,7 +44088,9 @@ var init_turkish = __esm({
43896
44088
  },
43897
44089
  hover: { primary: "\xFCzerine gelme", alternatives: ["\xFCzerinde gezinme"], normalized: "hover" },
43898
44090
  submit: { primary: "g\xF6nderme", normalized: "submit" },
43899
- input: { primary: "giri\u015F", alternatives: ["girdi", "giris"], normalized: "input" },
44091
+ // `giri\u015f` reads as entry/login (giri\u015f yapma) and can imply an auth event;
44092
+ // the data-input term is `girdi` ("Girdi (Input) Eventleri").
44093
+ input: { primary: "girdi", alternatives: ["giri\u015F", "giris"], normalized: "input" },
43900
44094
  change: { primary: "de\u011Fi\u015Fiklik", alternatives: ["de\u011Fi\u015Fim", "degisim"], normalized: "change" },
43901
44095
  // `load` event: the i18n dict emits y\u00fckle for `load`. Without this keyword the
43902
44096
  // SOV reorder's mid-stream `y\u00fckle de` (on load) tokenized as the `install`
@@ -43906,7 +44100,13 @@ var init_turkish = __esm({
43906
44100
  load: { primary: "y\xFCkle", normalized: "load" },
43907
44101
  // Navigation
43908
44102
  go: { primary: "git", normalized: "go" },
43909
- scroll: { primary: "kayd\u0131r", alternatives: ["kaydir"], normalized: "scroll" },
44103
+ // `kayd\u0131r` is the bare imperative; the attested event noun is `kayd\u0131rma`
44104
+ // ("kayd\u0131rma olay\u0131"). The imperative stays as an alternative.
44105
+ scroll: {
44106
+ primary: "kayd\u0131rma",
44107
+ alternatives: ["kaydirma", "kayd\u0131r", "kaydir"],
44108
+ normalized: "scroll"
44109
+ },
43910
44110
  push: { primary: "itele", alternatives: ["push"], normalized: "push" },
43911
44111
  replace: { primary: "de\u011Fi\u015Ftir_url", alternatives: ["degistir_url"], normalized: "replace" },
43912
44112
  process: { primary: "i\u015Fle", alternatives: ["isle"], normalized: "process" },
@@ -44859,6 +45059,60 @@ var init_chinese = __esm({
44859
45059
  }
44860
45060
  });
44861
45061
 
45062
+ // src/parser/utils/marker-resolution.ts
45063
+ function resolveMarkerForRole(roleSpec, profile) {
45064
+ const overrideMarker = roleSpec.markerOverride?.[profile.code];
45065
+ const defaultMarker = profile.roleMarkers[roleSpec.role];
45066
+ if (overrideMarker !== void 0) {
45067
+ const alternatives = legacyMarkerAlternatives(roleSpec, profile.code, overrideMarker);
45068
+ return {
45069
+ primary: overrideMarker,
45070
+ ...alternatives && { alternatives },
45071
+ position: defaultMarker?.position ?? "before",
45072
+ isOverride: true
45073
+ };
45074
+ }
45075
+ if (defaultMarker && defaultMarker.primary) {
45076
+ const result = {
45077
+ primary: defaultMarker.primary,
45078
+ position: defaultMarker.position,
45079
+ isOverride: false
45080
+ };
45081
+ if (defaultMarker.alternatives) {
45082
+ result.alternatives = defaultMarker.alternatives;
45083
+ }
45084
+ return result;
45085
+ }
45086
+ return null;
45087
+ }
45088
+ function legacyMarkerAlternatives(roleSpec, languageCode, overrideMarker) {
45089
+ const legacy = roleSpec.markerLegacy?.[languageCode];
45090
+ if (!legacy?.length) return void 0;
45091
+ const alternatives = [...new Set(legacy)].filter((a) => a && a !== overrideMarker);
45092
+ return alternatives.length ? alternatives : void 0;
45093
+ }
45094
+ function schemaMarkerAlternatives(roleSpec, languageCode, marker) {
45095
+ const legacy = roleSpec.markerLegacy?.[languageCode] ?? [];
45096
+ const variants = roleSpec.methodCarrier ? [] : roleSpec.markerVariants?.[languageCode] ?? [];
45097
+ const alternatives = [.../* @__PURE__ */ new Set([...legacy, ...variants])].filter((a) => a && a !== marker);
45098
+ return alternatives.length ? alternatives : void 0;
45099
+ }
45100
+ var ROLE_MARKER_CONCEPTS;
45101
+ var init_marker_resolution = __esm({
45102
+ "src/parser/utils/marker-resolution.ts"() {
45103
+ ROLE_MARKER_CONCEPTS = /* @__PURE__ */ new Set([
45104
+ "destination",
45105
+ "source",
45106
+ "patient",
45107
+ "object",
45108
+ "event",
45109
+ "eventmarker",
45110
+ "manner",
45111
+ "instrument"
45112
+ ]);
45113
+ }
45114
+ });
45115
+
44862
45116
  // src/patterns/put.ts
44863
45117
  function getPutPatternsBn() {
44864
45118
  return [
@@ -59719,49 +59973,6 @@ var init_role_positioning = __esm({
59719
59973
  }
59720
59974
  });
59721
59975
 
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
59976
  // src/generators/event-handlers-sov.ts
59766
59977
  function resolveRoleMarker(roleSpec, profile) {
59767
59978
  let marker;
@@ -59795,6 +60006,43 @@ function appendOptionalScope(tokens, extraction, commandSchema) {
59795
60006
  });
59796
60007
  extraction.scope = { fromRole: "scope" };
59797
60008
  }
60009
+ function appendOptionalViewTransition(tokens, extraction, commandSchema, languageCode) {
60010
+ appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, "manner", {
60011
+ requireMarker: true
60012
+ });
60013
+ }
60014
+ function appendOptionalRecipient(tokens, extraction, commandSchema, languageCode) {
60015
+ appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, "recipient", {
60016
+ requireMarker: false
60017
+ });
60018
+ }
60019
+ function appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, role, opts) {
60020
+ const spec = commandSchema.roles.find((r) => r.role === role && !r.required);
60021
+ if (!spec) return;
60022
+ const marker = spec.markerOverride?.[languageCode];
60023
+ if (opts.requireMarker && !marker) return;
60024
+ tokens.push({
60025
+ type: "group",
60026
+ optional: true,
60027
+ tokens: [
60028
+ ...(marker ? marker.split(/\s+/) : []).map(
60029
+ (word) => ({ type: "literal", value: word })
60030
+ ),
60031
+ {
60032
+ type: "role",
60033
+ role,
60034
+ optional: true,
60035
+ expectedTypes: spec.expectedTypes,
60036
+ // Load-bearing, same as on the generated command patterns: it exempts
60037
+ // the trailing slot from the matcher's verb guard, keeps the uncaptured
60038
+ // slot out of `scoreRoleCoverage`'s denominator, and (for `keyword`)
60039
+ // normalizes the captured value type to the EN reference's `literal`.
60040
+ ...spec.valueShape !== void 0 ? { valueShape: spec.valueShape } : {}
60041
+ }
60042
+ ]
60043
+ });
60044
+ extraction[role] = { fromRole: role };
60045
+ }
59798
60046
  function generateSOVEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
59799
60047
  const tokens = [];
59800
60048
  tokens.push({ type: "role", role: "event", optional: false });
@@ -59889,6 +60137,15 @@ function generateSOVPatientFirstEventHandlerPattern(commandSchema, profile, keyw
59889
60137
  tokens.push(
59890
60138
  ...swapsOperands ? eventHandlerPatientGroup(commandSchema, trailingMarker) : eventHandlerDestinationGroup(commandSchema, trailingMarker)
59891
60139
  );
60140
+ const extraction = {
60141
+ action: { value: commandSchema.action },
60142
+ event: { fromRole: "event" },
60143
+ [frontedRole]: { fromRole: frontedRole },
60144
+ ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
60145
+ ...eventHandlerSourceExtraction(commandSchema)
60146
+ };
60147
+ appendOptionalRecipient(tokens, extraction, commandSchema, profile.code);
60148
+ appendOptionalViewTransition(tokens, extraction, commandSchema, profile.code);
59892
60149
  return {
59893
60150
  id: `${commandSchema.action}-event-${profile.code}-sov-patient-first`,
59894
60151
  language: profile.code,
@@ -59898,13 +60155,7 @@ function generateSOVPatientFirstEventHandlerPattern(commandSchema, profile, keyw
59898
60155
  format: `{patient} ${patientMarker?.primary || ""} {event} ${eventMarker.primary} ${keyword.primary}`,
59899
60156
  tokens
59900
60157
  },
59901
- extraction: {
59902
- action: { value: commandSchema.action },
59903
- event: { fromRole: "event" },
59904
- [frontedRole]: { fromRole: frontedRole },
59905
- ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
59906
- ...eventHandlerSourceExtraction(commandSchema)
59907
- }
60158
+ extraction
59908
60159
  };
59909
60160
  }
59910
60161
  function generateSOVPatientFirstWithDestEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
@@ -60346,6 +60597,16 @@ function generateVSOVerbFirstEventHandlerPattern(commandSchema, profile, keyword
60346
60597
  });
60347
60598
  }
60348
60599
  }
60600
+ const extraction = {
60601
+ action: { value: commandSchema.action },
60602
+ event: { fromRole: "event" },
60603
+ [swapsOperands ? "destination" : "patient"]: {
60604
+ fromRole: swapsOperands ? "destination" : "patient"
60605
+ },
60606
+ ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
60607
+ ...eventHandlerSourceExtraction(commandSchema)
60608
+ };
60609
+ appendOptionalViewTransition(tokens, extraction, commandSchema, profile.code);
60349
60610
  return {
60350
60611
  id: `${commandSchema.action}-event-${profile.code}-vso-verb-first`,
60351
60612
  language: profile.code,
@@ -60356,15 +60617,7 @@ function generateVSOVerbFirstEventHandlerPattern(commandSchema, profile, keyword
60356
60617
  format: `${keyword.primary} {patient} ${destMarker?.primary || ""} {destination?} ${eventMarker.primary} {event}`,
60357
60618
  tokens
60358
60619
  },
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
- }
60620
+ extraction
60368
60621
  };
60369
60622
  }
60370
60623
  function generateVSOVerbFirstTwoRoleEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
@@ -60966,7 +61219,11 @@ function buildRoleToken(roleSpec, profile) {
60966
61219
  type: "role",
60967
61220
  role: roleSpec.role,
60968
61221
  optional: !roleSpec.required,
60969
- expectedTypes: roleSpec.expectedTypes
61222
+ expectedTypes: roleSpec.expectedTypes,
61223
+ // The matcher reads this too \u2014 a `'keyword'`-shaped slot holds a fixed
61224
+ // keyword phrase (`using view transition`) and must not be skipped by the
61225
+ // trailing-slot verb guard.
61226
+ ...roleSpec.valueShape !== void 0 ? { valueShape: roleSpec.valueShape } : {}
60970
61227
  };
60971
61228
  const prefixLiteral = roleSpec.valuePrefixLiteral?.[profile.code];
60972
61229
  const pushPrefixed = () => {
@@ -61275,9 +61532,24 @@ var init_pick = __esm({
61275
61532
  });
61276
61533
 
61277
61534
  // src/patterns/languages/en/swap.ts
61278
- var swapSimpleEnglish, swapElementEnglish, swapStrategyOfEnglish, swapStrategyEnglish, swapPatternsEn;
61535
+ var VIEW_TRANSITION_TAIL, swapSimpleEnglish, swapElementEnglish, swapStrategyOfEnglish, swapStrategyEnglish, swapPatternsEn;
61279
61536
  var init_swap = __esm({
61280
61537
  "src/patterns/languages/en/swap.ts"() {
61538
+ VIEW_TRANSITION_TAIL = {
61539
+ type: "group",
61540
+ optional: true,
61541
+ tokens: [
61542
+ { type: "literal", value: "using" },
61543
+ { type: "literal", value: "view" },
61544
+ {
61545
+ type: "role",
61546
+ role: "manner",
61547
+ optional: true,
61548
+ expectedTypes: ["literal", "expression"],
61549
+ valueShape: "keyword"
61550
+ }
61551
+ ]
61552
+ };
61281
61553
  swapSimpleEnglish = {
61282
61554
  id: "swap-en-handcrafted",
61283
61555
  language: "en",
@@ -61285,11 +61557,12 @@ var init_swap = __esm({
61285
61557
  priority: 110,
61286
61558
  // Higher than generated patterns
61287
61559
  template: {
61288
- format: "swap {method} {destination}",
61560
+ format: "swap {method} {destination} [using view {manner}]",
61289
61561
  tokens: [
61290
61562
  { type: "literal", value: "swap" },
61291
61563
  { type: "role", role: "method" },
61292
- { type: "role", role: "destination" }
61564
+ { type: "role", role: "destination" },
61565
+ VIEW_TRANSITION_TAIL
61293
61566
  ]
61294
61567
  },
61295
61568
  extraction: {
@@ -61303,12 +61576,13 @@ var init_swap = __esm({
61303
61576
  command: "swap",
61304
61577
  priority: 120,
61305
61578
  template: {
61306
- format: "swap {destination} with {patient}",
61579
+ format: "swap {destination} with {patient} [using view {manner}]",
61307
61580
  tokens: [
61308
61581
  { type: "literal", value: "swap" },
61309
61582
  { type: "role", role: "destination" },
61310
61583
  { type: "literal", value: "with" },
61311
- { type: "role", role: "patient" }
61584
+ { type: "role", role: "patient" },
61585
+ VIEW_TRANSITION_TAIL
61312
61586
  ]
61313
61587
  },
61314
61588
  extraction: {}
@@ -61319,14 +61593,15 @@ var init_swap = __esm({
61319
61593
  command: "swap",
61320
61594
  priority: 140,
61321
61595
  template: {
61322
- format: "swap {method} of {destination} with {patient}",
61596
+ format: "swap {method} of {destination} with {patient} [using view {manner}]",
61323
61597
  tokens: [
61324
61598
  { type: "literal", value: "swap" },
61325
61599
  { type: "role", role: "method" },
61326
61600
  { type: "literal", value: "of" },
61327
61601
  { type: "role", role: "destination" },
61328
61602
  { type: "literal", value: "with" },
61329
- { type: "role", role: "patient" }
61603
+ { type: "role", role: "patient" },
61604
+ VIEW_TRANSITION_TAIL
61330
61605
  ]
61331
61606
  },
61332
61607
  extraction: {}
@@ -61337,13 +61612,14 @@ var init_swap = __esm({
61337
61612
  command: "swap",
61338
61613
  priority: 130,
61339
61614
  template: {
61340
- format: "swap {method} {destination} with {patient}",
61615
+ format: "swap {method} {destination} with {patient} [using view {manner}]",
61341
61616
  tokens: [
61342
61617
  { type: "literal", value: "swap" },
61343
61618
  { type: "role", role: "method" },
61344
61619
  { type: "role", role: "destination" },
61345
61620
  { type: "literal", value: "with" },
61346
- { type: "role", role: "patient" }
61621
+ { type: "role", role: "patient" },
61622
+ VIEW_TRANSITION_TAIL
61347
61623
  ]
61348
61624
  },
61349
61625
  extraction: {}
@@ -64713,6 +64989,7 @@ function isTypeCompatible(actualType, expectedTypes) {
64713
64989
  }
64714
64990
 
64715
64991
  // src/parser/pattern-matcher.ts
64992
+ init_marker_resolution();
64716
64993
  init_command_schemas();
64717
64994
 
64718
64995
  // src/parser/utils/possessive-keywords.ts
@@ -65277,7 +65554,8 @@ var DefaultConfidenceModel = class {
65277
65554
  const hasDefault = (role) => {
65278
65555
  return pattern.extraction?.[role]?.default !== void 0;
65279
65556
  };
65280
- const schemaRoles = commandSchemas[pattern.command]?.roles;
65557
+ const wrappedAction = pattern.command === "on" ? pattern.extraction?.action?.value : void 0;
65558
+ const schemaRoles = commandSchemas[wrappedAction ?? pattern.command]?.roles;
65281
65559
  const isShapeAnchored = (role) => schemaRoles?.find((r) => r.role === role)?.valueShape !== void 0;
65282
65560
  for (const token of pattern.template.tokens) {
65283
65561
  if (token.type === "role") {
@@ -65681,7 +65959,7 @@ var _PatternMatcher = class _PatternMatcher {
65681
65959
  return patternToken.optional || false;
65682
65960
  }
65683
65961
  }
65684
- if (patternToken.optional && nextPatternToken === void 0 && patternToken.role !== "event" && patternToken.role !== "action" && token.kind === "keyword") {
65962
+ if (patternToken.optional && nextPatternToken === void 0 && patternToken.role !== "event" && patternToken.role !== "action" && patternToken.valueShape !== "keyword" && token.kind === "keyword") {
65685
65963
  const verbNorm = (token.normalized ?? token.value).toLowerCase();
65686
65964
  if (verbNorm in commandSchemas) {
65687
65965
  return true;
@@ -65836,7 +66114,11 @@ var _PatternMatcher = class _PatternMatcher {
65836
66114
  }
65837
66115
  }
65838
66116
  }
65839
- captured.set(patternToken.role, value);
66117
+ if (patternToken.valueShape === "keyword" && value.type === "expression") {
66118
+ captured.set(patternToken.role, createLiteral(String(value.raw ?? "")));
66119
+ } else {
66120
+ captured.set(patternToken.role, value);
66121
+ }
65840
66122
  tokens.advance();
65841
66123
  if (patternToken.role === "event") {
65842
66124
  const filterTok = tokens.peek();
@@ -66425,17 +66707,7 @@ var _PatternMatcher = class _PatternMatcher {
66425
66707
  * so this never blocks a genuine `my value` / `its style` possessive.
66426
66708
  */
66427
66709
  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());
66710
+ return ROLE_MARKER_CONCEPTS.has(normalized2.toLowerCase());
66439
66711
  }
66440
66712
  /**
66441
66713
  * Does `token` look like an EVENT name for the `event` role? Events are bare
@@ -66821,7 +67093,7 @@ var _PatternMatcher = class _PatternMatcher {
66821
67093
  */
66822
67094
  matchGroupToken(tokens, patternToken, captured, nextPatternToken) {
66823
67095
  const mark = tokens.mark();
66824
- const capturedBefore = new Set(captured.keys());
67096
+ const capturedBefore = new Map(captured);
66825
67097
  const success = this.matchTokenSequence(
66826
67098
  tokens,
66827
67099
  patternToken.tokens,
@@ -66835,6 +67107,11 @@ var _PatternMatcher = class _PatternMatcher {
66835
67107
  captured.delete(role);
66836
67108
  }
66837
67109
  }
67110
+ for (const [role, value] of capturedBefore) {
67111
+ if (captured.get(role) !== value) {
67112
+ captured.set(role, value);
67113
+ }
67114
+ }
66838
67115
  return patternToken.optional || false;
66839
67116
  }
66840
67117
  return true;
@@ -67224,6 +67501,7 @@ function registerTokenizer2(tokenizer) {
67224
67501
  // src/parser/semantic-parser.ts
67225
67502
  init_registry();
67226
67503
  init_command_schemas();
67504
+ init_marker_resolution();
67227
67505
 
67228
67506
  // src/parser/block-parser.ts
67229
67507
  init_registry();
@@ -69273,13 +69551,18 @@ var _SemanticParserImpl = class _SemanticParserImpl {
69273
69551
  if (!spec) return true;
69274
69552
  return spec.expectedTypes.length > 0 && !spec.expectedTypes.includes(valType(val));
69275
69553
  };
69554
+ const isMarkerConceptJunk = (role, val) => role === "patient" && !!schema && !schema.roles.some((r) => r.role === "patient") && valType(val) === "literal" && ROLE_MARKER_CONCEPTS.has(
69555
+ String(val.value ?? "").toLowerCase()
69556
+ );
69276
69557
  const preservesFused = !!first && first.kind === "command" && Object.entries(roles).every(([role, val]) => {
69277
- if (isIgnorableFusedRole(role, val)) return true;
69558
+ if (isIgnorableFusedRole(role, val) || isMarkerConceptJunk(role, val)) return true;
69278
69559
  const rv = first.roles.get(mapRole(role));
69279
69560
  if (rv !== void 0 && valType(rv) === valType(val)) return true;
69280
69561
  if (role === "patient" && actionName === "pick" && valType(val) === "literal") {
69281
69562
  const mv = first.roles.get("method");
69282
- return mv !== void 0 && valType(mv) === "literal" && String(mv.value) === String(val.value);
69563
+ const mvType = valType(mv);
69564
+ const mvSurface = mvType === "literal" ? String(mv.value) : mvType === "expression" ? String(mv.raw) : void 0;
69565
+ return mvSurface !== void 0 && mvSurface === String(val.value);
69283
69566
  }
69284
69567
  return false;
69285
69568
  });
@@ -69289,7 +69572,12 @@ var _SemanticParserImpl = class _SemanticParserImpl {
69289
69572
  // the swap can never swallow a body command. The body-swallowing
69290
69573
  // generated repeat matches none of these ids.
69291
69574
  /^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) {
69575
+ if (reparsed.length === 1 && first && first.kind === "command" && first.action === actionName && preservesFused && headOnlyOk && // Strictly-more: the re-parse must recover something the fused
69576
+ // capture lacked. Junk marker captures are excluded from the
69577
+ // count \u2014 a fused shape whose ONLY role is a swallowed marker
69578
+ // (scroll: `destination:literal="destination"`) would otherwise
69579
+ // tie 1 > 1 and veto its own repair.
69580
+ first.roles.size > Object.entries(roles).filter(([r, v]) => !isMarkerConceptJunk(r, v)).length) {
69293
69581
  commandNode = first;
69294
69582
  while (tokens.position() < clauseEnd) tokens.advance();
69295
69583
  } else {
@@ -76088,7 +76376,7 @@ function getGetPatternsBn() {
76088
76376
  tokens: [
76089
76377
  { type: "role", role: "source" },
76090
76378
  { type: "literal", value: "\u09A5\u09C7\u0995\u09C7" },
76091
- { type: "literal", value: "\u09AA\u09BE\u09A8", alternatives: ["\u09A8\u09BF\u09A8"] }
76379
+ { type: "literal", value: "\u09AA\u09BE\u09A8" }
76092
76380
  ]
76093
76381
  },
76094
76382
  extraction: {
@@ -76104,7 +76392,7 @@ function getGetPatternsBn() {
76104
76392
  template: {
76105
76393
  format: "\u09AA\u09BE\u09A8 {source}",
76106
76394
  tokens: [
76107
- { type: "literal", value: "\u09AA\u09BE\u09A8", alternatives: ["\u09A8\u09BF\u09A8"] },
76395
+ { type: "literal", value: "\u09AA\u09BE\u09A8" },
76108
76396
  { type: "role", role: "source" }
76109
76397
  ]
76110
76398
  },
@@ -76188,7 +76476,7 @@ function getGetPatternsIt() {
76188
76476
  template: {
76189
76477
  format: "ottenere {patient} da {source}",
76190
76478
  tokens: [
76191
- { type: "literal", value: "ottenere", alternatives: ["ottieni", "get", "prendere"] },
76479
+ { type: "literal", value: "ottenere", alternatives: ["ottieni", "get"] },
76192
76480
  { type: "role", role: "patient" },
76193
76481
  {
76194
76482
  type: "group",
@@ -76278,7 +76566,7 @@ function getGetPatternsRu() {
76278
76566
  template: {
76279
76567
  format: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C {patient} \u0438\u0437 {source}",
76280
76568
  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"] },
76569
+ { type: "literal", value: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C", alternatives: ["\u043F\u043E\u043B\u0443\u0447\u0438"] },
76282
76570
  { type: "role", role: "patient" },
76283
76571
  {
76284
76572
  type: "group",
@@ -76303,7 +76591,7 @@ function getGetPatternsRu() {
76303
76591
  template: {
76304
76592
  format: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C {patient}",
76305
76593
  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"] },
76594
+ { type: "literal", value: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C", alternatives: ["\u043F\u043E\u043B\u0443\u0447\u0438"] },
76307
76595
  { type: "role", role: "patient" }
76308
76596
  ]
76309
76597
  },
@@ -76344,7 +76632,7 @@ function getGetPatternsUk() {
76344
76632
  template: {
76345
76633
  format: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438 {patient} \u0437 {source}",
76346
76634
  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"] },
76635
+ { type: "literal", value: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438", alternatives: ["\u043E\u0442\u0440\u0438\u043C\u0430\u0439"] },
76348
76636
  { type: "role", role: "patient" },
76349
76637
  {
76350
76638
  type: "group",
@@ -76369,7 +76657,7 @@ function getGetPatternsUk() {
76369
76657
  template: {
76370
76658
  format: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438 {patient}",
76371
76659
  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"] },
76660
+ { type: "literal", value: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438", alternatives: ["\u043E\u0442\u0440\u0438\u043C\u0430\u0439"] },
76373
76661
  { type: "role", role: "patient" }
76374
76662
  ]
76375
76663
  },
@@ -76389,7 +76677,7 @@ function getGetPatternsVi() {
76389
76677
  template: {
76390
76678
  format: "l\u1EA5y gi\xE1 tr\u1ECB c\u1EE7a {target}",
76391
76679
  tokens: [
76392
- { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn", "l\u1EA5y"] },
76680
+ { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn"] },
76393
76681
  { type: "group", optional: true, tokens: [{ type: "literal", value: "c\u1EE7a" }] },
76394
76682
  { type: "role", role: "patient" }
76395
76683
  ]
@@ -76400,13 +76688,17 @@ function getGetPatternsVi() {
76400
76688
  },
76401
76689
  {
76402
76690
  id: "get-vi-simple",
76691
+ // Head was `l\u1ea5y` (alt `l\u1ea5y gi\u00e1 tr\u1ecb`) \u2014 but bare `l\u1ea5y` is vi's TAKE verb,
76692
+ // so this pattern claimed every `l\u1ea5y .active t\u1eeb \u2026`. vi's get verb is the
76693
+ // three-word `l\u1ea5y gi\u00e1 tr\u1ecb` ("take the value of"), which is what the i18n
76694
+ // transformer renders; the bare form has no valid `get` surface.
76403
76695
  language: "vi",
76404
76696
  command: "get",
76405
76697
  priority: 90,
76406
76698
  template: {
76407
- format: "l\u1EA5y {target}",
76699
+ format: "l\u1EA5y gi\xE1 tr\u1ECB {target}",
76408
76700
  tokens: [
76409
- { type: "literal", value: "l\u1EA5y", alternatives: ["nh\u1EADn", "l\u1EA5y gi\xE1 tr\u1ECB"] },
76701
+ { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn"] },
76410
76702
  { type: "role", role: "patient" }
76411
76703
  ]
76412
76704
  },
@@ -78165,6 +78457,12 @@ function getSendPatternsForLanguage(language) {
78165
78457
  }
78166
78458
 
78167
78459
  // src/patterns/pick.ts
78460
+ var PICK_UNIT_WORDS = /* @__PURE__ */ new Set(["character", "characters", "item", "items"]);
78461
+ var retypePickUnitWord = (raw) => {
78462
+ if (PICK_UNIT_WORDS.has(raw)) return { type: "expression", raw };
78463
+ const n = Number(raw);
78464
+ return createLiteral(raw !== "" && !Number.isNaN(n) ? n : raw);
78465
+ };
78168
78466
  function makePickVariantPattern(language, spec) {
78169
78467
  const tokens = [{ type: "literal", value: "pick" }];
78170
78468
  if (spec.objectMarkers?.length) {
@@ -78204,7 +78502,7 @@ function makePickVariantPattern(language, spec) {
78204
78502
  tokens
78205
78503
  },
78206
78504
  extraction: {
78207
- method: { position: 1 },
78505
+ method: { position: 1, transform: retypePickUnitWord },
78208
78506
  patient: { position: 2 },
78209
78507
  source: {
78210
78508
  marker: spec.srcMarker,
@@ -78255,7 +78553,7 @@ function makePickVerbFinalPattern(language, spec) {
78255
78553
  },
78256
78554
  extraction: {
78257
78555
  source: { position: 0 },
78258
- method: { position: 2 },
78556
+ method: { position: 2, transform: retypePickUnitWord },
78259
78557
  patient: { position: 3 }
78260
78558
  }
78261
78559
  };