@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.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();
@@ -11941,7 +11987,7 @@ class CommandAdapterV2 {
11941
11987
  return {
11942
11988
  description: this.impl.metadata?.description || '',
11943
11989
  examples: this.impl.metadata?.examples || [],
11944
- syntax: Array.isArray(syntax) ? syntax.join(' | ') : syntax || '',
11990
+ syntax: typeof syntax === 'string' ? syntax : syntax ? syntax.join(' | ') : '',
11945
11991
  };
11946
11992
  }
11947
11993
  async execute(context, ...args) {
@@ -12017,10 +12063,8 @@ class CommandAdapterV2 {
12017
12063
  }
12018
12064
  }
12019
12065
  validate(input) {
12020
- if (this.impl.validate) {
12021
- return this.impl.validate(input);
12022
- }
12023
- return { isValid: true, errors: [], suggestions: [] };
12066
+ const isValid = this.impl.validate ? this.impl.validate(input) : true;
12067
+ return { isValid, errors: [], suggestions: [] };
12024
12068
  }
12025
12069
  }
12026
12070
  class CommandRegistryV2 {
@@ -16875,7 +16919,7 @@ function command(config) {
16875
16919
  };
16876
16920
  }
16877
16921
  function commandMeta(metadata) {
16878
- return { isBlocking: false, hasBody: false, version: '1.0.0', ...metadata };
16922
+ return { ...metadata };
16879
16923
  }
16880
16924
  function createFactory(CommandClass) {
16881
16925
  return () => new CommandClass();
@@ -20442,7 +20486,7 @@ let SwapCommand = (() => {
20442
20486
  };
20443
20487
  }
20444
20488
  }
20445
- let useViewTransition = false;
20489
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
20446
20490
  if (usingIndex !== -1) {
20447
20491
  const afterUsing = argKeywords.slice(usingIndex + 1);
20448
20492
  if (afterUsing.includes('view') && afterUsing.includes('transition')) {
@@ -20652,7 +20696,7 @@ let MorphCommand = (() => {
20652
20696
  const withIndex = argKeywords.findIndex(k => k === 'with');
20653
20697
  const overIndex = argKeywords.findIndex(k => k === 'over');
20654
20698
  const usingIndex = argKeywords.findIndex(k => k === 'using');
20655
- let useViewTransition = false;
20699
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
20656
20700
  if (usingIndex !== -1) {
20657
20701
  const afterUsing = argKeywords.slice(usingIndex + 1);
20658
20702
  if (afterUsing.includes('view') && afterUsing.includes('transition')) {
@@ -20733,7 +20777,11 @@ let MorphCommand = (() => {
20733
20777
  })();
20734
20778
  _classThis.metadata = commandMeta({
20735
20779
  description: 'Morph content into target elements (intelligent diffing, preserves state)',
20736
- syntax: ['morph <target> with <content>', 'morph over <target> with <content>'],
20780
+ syntax: [
20781
+ 'morph <target> with <content>',
20782
+ 'morph over <target> with <content>',
20783
+ 'morph <target> with <content> using view transition',
20784
+ ],
20737
20785
  examples: ['morph #target with it', 'morph over #modal with fetchedContent'],
20738
20786
  sideEffects: ['dom-mutation'],
20739
20787
  category: 'dom',
@@ -21365,24 +21413,33 @@ let ProcessPartialsCommand = (() => {
21365
21413
  if (!args || args.length === 0) {
21366
21414
  throw new Error('process partials command requires content argument');
21367
21415
  }
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');
21416
+ const keywordOf = (node) => {
21417
+ const n = node;
21418
+ if (!n || typeof n !== 'object')
21419
+ return null;
21420
+ if (n.type === 'identifier' && typeof n.name === 'string')
21421
+ return n.name.toLowerCase();
21422
+ if (n.type === 'literal' && typeof n.value === 'string')
21423
+ return n.value.toLowerCase();
21424
+ return null;
21425
+ };
21426
+ const keywords = args.map(keywordOf);
21427
+ const partialsIndex = keywords.indexOf('partials');
21428
+ const inIndex = keywords.indexOf('in');
21429
+ let contentNode;
21378
21430
  if (partialsIndex === -1) {
21379
- throw new Error('process command expects "partials" keyword: process partials in <content>');
21431
+ if (inIndex !== -1) {
21432
+ throw new Error('process command expects "partials" keyword: process partials in <content>');
21433
+ }
21434
+ contentNode = args[0];
21380
21435
  }
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>');
21436
+ else {
21437
+ if (inIndex === -1 || inIndex <= partialsIndex) {
21438
+ throw new Error('process partials command expects "in" keyword: process partials in <content>');
21439
+ }
21440
+ contentNode = args[inIndex + 1];
21384
21441
  }
21385
- const contentArg = evaluatedArgs[inIndex + 1];
21442
+ const contentArg = contentNode ? await evaluator.evaluate(contentNode, context) : undefined;
21386
21443
  let html;
21387
21444
  if (typeof contentArg === 'string') {
21388
21445
  html = contentArg;
@@ -21396,10 +21453,10 @@ let ProcessPartialsCommand = (() => {
21396
21453
  else {
21397
21454
  throw new Error('process partials: content must be an HTML string or element');
21398
21455
  }
21399
- const usingIndex = argStrings.findIndex(s => s === 'using');
21400
- let useViewTransition = false;
21456
+ let useViewTransition = raw.modifiers?.viewTransition !== undefined;
21457
+ const usingIndex = keywords.indexOf('using');
21401
21458
  if (usingIndex !== -1) {
21402
- const remaining = argStrings.slice(usingIndex + 1).join(' ');
21459
+ const remaining = keywords.slice(usingIndex + 1);
21403
21460
  if (remaining.includes('view') && remaining.includes('transition')) {
21404
21461
  useViewTransition = true;
21405
21462
  }
@@ -35888,7 +35945,7 @@ function getSchemasByCategory(category) {
35888
35945
  function getDefinedSchemas() {
35889
35946
  return Object.values(commandSchemas).filter((s) => s.roles.length > 0 || s.bareKeyword === true);
35890
35947
  }
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;
35948
+ 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
35949
  var init_command_schemas = __esm({
35893
35950
  "src/generators/command-schemas.ts"() {
35894
35951
  toggleSchema = {
@@ -35897,7 +35954,6 @@ var init_command_schemas = __esm({
35897
35954
  category: "dom-class",
35898
35955
  primaryRole: "patient",
35899
35956
  // `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
35957
  ast: { args: ["patient"], modifiers: { on: "destination", for: "duration" } },
35902
35958
  roles: [
35903
35959
  {
@@ -36988,8 +37044,8 @@ var init_command_schemas = __esm({
36988
37044
  description: "Take content from a source element",
36989
37045
  category: "dom-content",
36990
37046
  primaryRole: "patient",
36991
- // `take .active from #parent` \u2192 args ['.active'], modifiers { from: '#parent' }.
36992
- ast: { args: ["patient"], modifiers: { from: "source" } },
37047
+ // `take .active from #parent for me` \u2192 args ['.active'], modifiers { from, for }.
37048
+ ast: { args: ["patient"], modifiers: { from: "source", for: "recipient" } },
36993
37049
  roles: [
36994
37050
  {
36995
37051
  role: "patient",
@@ -37012,6 +37068,38 @@ var init_command_schemas = __esm({
37012
37068
  expectedTypes: ["selector", "reference"],
37013
37069
  svoPosition: 2,
37014
37070
  sovPosition: 1
37071
+ },
37072
+ {
37073
+ role: "recipient",
37074
+ description: "The element the class moves ONTO (`take .active from .tab for me`)",
37075
+ required: false,
37076
+ // References only, deliberately. Upstream accepts an element expression,
37077
+ // but the 23 non-en corpus surfaces carry the recipient as a BARE
37078
+ // trailing pronoun (i18n renders `\u2026 von .tab-button ich`), so this slot
37079
+ // is marker-less almost everywhere and a selector-typed slot would
37080
+ // swallow the second selector of `take .active from .a .b`. English is
37081
+ // unaffected: `take` is on the core parser's skipSemanticParsing list,
37082
+ // so the traditional parser owns `for <anything>` there.
37083
+ expectedTypes: ["reference"],
37084
+ svoPosition: 3,
37085
+ sovPosition: 3,
37086
+ // NO default. The runtime already defaults the recipient to `me`
37087
+ // (commands/animation/take.ts), and a schema default would emit an
37088
+ // explicit `for me` modifier on every take \u2014 re-smuggling the exact
37089
+ // "absent means absent" semantics #859 removed from `source`.
37090
+ //
37091
+ // Shape-anchored on `reference`: without it this optional slot weighs
37092
+ // into every take pattern's denominator in `scoreRoleCoverage`, dropping
37093
+ // plain `take .active from .tab-button` from 1.0 to ~0.69 \u2014 the toggle-es
37094
+ // regression class the R1 role-set flip ratchet exists to catch.
37095
+ valueShape: "reference",
37096
+ // en only. The other 23 languages render the recipient unmarked, so a
37097
+ // marker there would never match their corpus rows; where the marker-less
37098
+ // slot proves inert they stay uncaptured and the pattern lands in the
37099
+ // baseline's `roleLossyPatterns` as named R1 burn-down tail. A language
37100
+ // gets a real particle here ONLY if the empty slot perturbs its other
37101
+ // parses (toggle's ja \u9593 / ko \ub3d9\uc548 case).
37102
+ markerOverride: { en: "for" }
37015
37103
  }
37016
37104
  ]
37017
37105
  };
@@ -38076,6 +38164,47 @@ var init_command_schemas = __esm({
38076
38164
  }
38077
38165
  ]
38078
38166
  };
38167
+ USING_VIEW_MARKER_ALL_LANGS = {
38168
+ en: "using view",
38169
+ es: "using view",
38170
+ pt: "using view",
38171
+ fr: "using view",
38172
+ de: "using view",
38173
+ it: "using view",
38174
+ ja: "using view",
38175
+ ko: "using view",
38176
+ zh: "using view",
38177
+ ar: "using view",
38178
+ he: "using view",
38179
+ hi: "using view",
38180
+ bn: "using view",
38181
+ tr: "using view",
38182
+ ru: "using view",
38183
+ uk: "using view",
38184
+ pl: "using view",
38185
+ id: "using view",
38186
+ vi: "using view",
38187
+ th: "using view",
38188
+ ms: "using view",
38189
+ tl: "using view",
38190
+ sw: "using view",
38191
+ qu: "using view"
38192
+ };
38193
+ VIEW_TRANSITION_MANNER_ROLE = {
38194
+ role: "manner",
38195
+ description: "Run the swap inside a `document.startViewTransition()` (`using view transition`)",
38196
+ required: false,
38197
+ // Both types, because the SAME word tokenizes differently per language and
38198
+ // the difference is an accident of vocabulary: `transition` is a command
38199
+ // keyword in en/fr (it is also their verb) and a bare identifier everywhere
38200
+ // else, which types it `literal` in the first group and `expression` in the
38201
+ // second. Measured: with `['literal']` alone only en and fr captured the
38202
+ // tail. Widening is safe precisely because the slot is marker-guarded \u2014
38203
+ // nothing reaches it until `using view` has matched.
38204
+ expectedTypes: ["literal", "expression"],
38205
+ valueShape: "keyword",
38206
+ markerOverride: USING_VIEW_MARKER_ALL_LANGS
38207
+ };
38079
38208
  swapSchema = {
38080
38209
  action: "swap",
38081
38210
  description: "Swap DOM content using various strategies (innerHTML, outerHTML, delete, etc.)",
@@ -38096,7 +38225,11 @@ var init_command_schemas = __esm({
38096
38225
  // work. Preserved verbatim by the Arc F migration (a faithful migration must
38097
38226
  // not change output) and pinned as two `drift` exemptions; this is the
38098
38227
  // behavior fix those entries were waiting for.
38099
- ast: { args: ["method", "destination", "patient"] },
38228
+ //
38229
+ // `manner` is the exception to "keyword-positional args": it rides as
38230
+ // `modifiers.viewTransition`, which SwapCommand.parseInput reads for presence
38231
+ // alongside its existing flat-args `using`/`view`/`transition` scan.
38232
+ ast: { args: ["method", "destination", "patient"], modifiers: { viewTransition: "manner" } },
38100
38233
  roles: [
38101
38234
  {
38102
38235
  role: "method",
@@ -38191,6 +38324,11 @@ var init_command_schemas = __esm({
38191
38324
  ar: "\u0628\u0640",
38192
38325
  tl: "nang"
38193
38326
  }
38327
+ },
38328
+ {
38329
+ ...VIEW_TRANSITION_MANNER_ROLE,
38330
+ svoPosition: 4,
38331
+ sovPosition: 4
38194
38332
  }
38195
38333
  ]
38196
38334
  };
@@ -38201,7 +38339,15 @@ var init_command_schemas = __esm({
38201
38339
  primaryRole: "patient",
38202
38340
  // `morph #list to it` \u2192 args [content], modifiers { on: element }.
38203
38341
  // Content is source or destination; the element being morphed is the patient.
38204
- ast: { args: [["source", "destination"]], modifiers: { on: "patient" } },
38342
+ //
38343
+ // `manner` rides as `modifiers.viewTransition`, same as swap/process \u2014
38344
+ // MorphCommand.parseInput reads it for presence alongside its existing
38345
+ // flat-args `using`/`view`/`transition` scan (the traditional-parser path,
38346
+ // which owns English because morph sits on SKIP_SEMANTIC_COMMANDS).
38347
+ ast: {
38348
+ args: [["source", "destination"]],
38349
+ modifiers: { on: "patient", viewTransition: "manner" }
38350
+ },
38205
38351
  roles: [
38206
38352
  {
38207
38353
  role: "patient",
@@ -38222,6 +38368,18 @@ var init_command_schemas = __esm({
38222
38368
  sovPosition: 2,
38223
38369
  markerOverride: { en: "to" }
38224
38370
  // "morph #target to it"
38371
+ },
38372
+ {
38373
+ // `morph #target to it using view transition` \u2014 the same tail as swap and
38374
+ // process, closed here for the same reason (#870's third-schema filing):
38375
+ // without the role the semantic parser matched morph at confidence 1.0
38376
+ // and stranded the tail, so every semantic-only consumer (multilingual
38377
+ // bundles, the bridge, `translate()`) silently dropped the animation
38378
+ // request in all 24 languages. Morph has NO hand-written patterns in any
38379
+ // language, so this schema role is the whole fix on the pattern side.
38380
+ ...VIEW_TRANSITION_MANNER_ROLE,
38381
+ svoPosition: 3,
38382
+ sovPosition: 3
38225
38383
  }
38226
38384
  ]
38227
38385
  };
@@ -38408,6 +38566,13 @@ var init_command_schemas = __esm({
38408
38566
  description: "Process hx-partial markup in HTML content",
38409
38567
  category: "dom-content",
38410
38568
  primaryRole: "patient",
38569
+ // `process partials in it` \u2192 args ['it']; the optional tail rides as
38570
+ // `modifiers.viewTransition`, which ProcessPartialsCommand.parseInput has
38571
+ // read since #861 (`raw.modifiers?.viewTransition !== undefined`). Without a
38572
+ // descriptor this schema fell through to `buildGenericCommand`, whose
38573
+ // modifier list is fixed (destination/duration/method/style) and would have
38574
+ // dropped a captured `manner` on the floor.
38575
+ ast: { args: ["patient"], modifiers: { viewTransition: "manner" } },
38411
38576
  roles: [
38412
38577
  {
38413
38578
  role: "patient",
@@ -38417,6 +38582,11 @@ var init_command_schemas = __esm({
38417
38582
  svoPosition: 1,
38418
38583
  sovPosition: 1,
38419
38584
  markerOverride: PARTIALS_IN_MARKER_ALL_LANGS
38585
+ },
38586
+ {
38587
+ ...VIEW_TRANSITION_MANNER_ROLE,
38588
+ svoPosition: 2,
38589
+ sovPosition: 2
38420
38590
  }
38421
38591
  ]
38422
38592
  };
@@ -40011,7 +40181,9 @@ var init_french = __esm({
40011
40181
  trigger: { primary: "d\xE9clencher", normalized: "trigger" },
40012
40182
  send: { primary: "envoyer", alternatives: ["envoie"], normalized: "send" },
40013
40183
  focus: { primary: "focaliser", alternatives: ["concentrer"], normalized: "focus" },
40014
- blur: { primary: "d\xE9focaliser", normalized: "blur" },
40184
+ // `d\u00e9focaliser` is an unattested infinitive; French pedagogy writes
40185
+ // `perte de focus` for the event (2026-07 terminology review).
40186
+ blur: { primary: "perte de focus", alternatives: ["d\xE9focaliser"], normalized: "blur" },
40015
40187
  // Phase 1 (v0.9.90): DOM / form state / debug
40016
40188
  // `vide` (adjective, "empty") is the i18n transformer's `is empty` predicate
40017
40189
  // form; `vider` is the verb ("to empty"). Accept both so the emptiness check
@@ -40024,7 +40196,13 @@ var init_french = __esm({
40024
40196
  reset: { primary: "r\xE9initialiser", alternatives: ["reinitialiser"], normalized: "reset" },
40025
40197
  breakpoint: { primary: "point-arr\xEAt", alternatives: ["point-arret"], normalized: "breakpoint" },
40026
40198
  go: { primary: "aller", alternatives: ["naviguer", "va"], normalized: "go" },
40027
- scroll: { primary: "d\xE9filer", alternatives: ["faire-d\xE9filer"], normalized: "scroll" },
40199
+ // MDN fr and the OQLF standardize the noun `d\u00e9filement` for the event; the
40200
+ // infinitive stays as an alternative.
40201
+ scroll: {
40202
+ primary: "d\xE9filement",
40203
+ alternatives: ["defilement", "d\xE9filer", "faire-d\xE9filer"],
40204
+ normalized: "scroll"
40205
+ },
40028
40206
  push: { primary: "pousser", normalized: "push" },
40029
40207
  replace: { primary: "remplacer", normalized: "replace" },
40030
40208
  process: { primary: "traiter", normalized: "process" },
@@ -40090,9 +40268,15 @@ var init_french = __esm({
40090
40268
  after: { primary: "apr\xE8s", normalized: "after" },
40091
40269
  // Common event names (for event handler patterns)
40092
40270
  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" },
40271
+ // `resize` event (window-resize): the noun `redimensionnement` is the
40272
+ // attested event form ("lors du redimensionnement de la fen\u00eatre"). The dict
40273
+ // still emits redimensionner, kept as an alternative so the event keeps
40274
+ // typing as literal="resize" (matching en) instead of expression.
40275
+ resize: {
40276
+ primary: "redimensionnement",
40277
+ alternatives: ["redimensionner"],
40278
+ normalized: "resize"
40279
+ },
40096
40280
  hover: { primary: "survol", alternatives: ["survoler"], normalized: "hover" },
40097
40281
  submit: { primary: "soumission", alternatives: ["soumettre"], normalized: "submit" },
40098
40282
  input: { primary: "saisie", alternatives: ["entr\xE9e"], normalized: "input" },
@@ -43875,9 +44059,17 @@ var init_turkish = __esm({
43875
44059
  on: { primary: "\xFCzerinde", alternatives: ["zaman"], normalized: "on" },
43876
44060
  trigger: { primary: "tetikle", normalized: "trigger" },
43877
44061
  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" },
44062
+ // DOM focus. `odaklanma` (the act of focusing) leads over the static state
44063
+ // noun `odak` \u2014 Turkish event prose says "odaklanma olay\u0131". `bulan\u0131k` was
44064
+ // the optical blur (CSS filters, image processing), never the DOM event;
44065
+ // native usage is `odak kayb\u0131` (loss of focus). 2026-07 terminology-review
44066
+ // corrections; old forms stay as parse alternatives.
44067
+ focus: { primary: "odaklanma", alternatives: ["odak"], normalized: "focus" },
44068
+ blur: {
44069
+ primary: "odak kayb\u0131",
44070
+ alternatives: ["odak kaybi", "bulan\u0131k", "bulan\u0131kl\u0131k", "bulanik"],
44071
+ normalized: "blur"
44072
+ },
43881
44073
  // Phase 1 (v0.9.90): DOM / form state / debug
43882
44074
  empty: { primary: "bo\u015Falt", alternatives: ["bosalt", "bo\u015F"], normalized: "empty" },
43883
44075
  open: { primary: "a\xE7", alternatives: ["ac"], normalized: "open" },
@@ -43898,7 +44090,9 @@ var init_turkish = __esm({
43898
44090
  },
43899
44091
  hover: { primary: "\xFCzerine gelme", alternatives: ["\xFCzerinde gezinme"], normalized: "hover" },
43900
44092
  submit: { primary: "g\xF6nderme", normalized: "submit" },
43901
- input: { primary: "giri\u015F", alternatives: ["girdi", "giris"], normalized: "input" },
44093
+ // `giri\u015f` reads as entry/login (giri\u015f yapma) and can imply an auth event;
44094
+ // the data-input term is `girdi` ("Girdi (Input) Eventleri").
44095
+ input: { primary: "girdi", alternatives: ["giri\u015F", "giris"], normalized: "input" },
43902
44096
  change: { primary: "de\u011Fi\u015Fiklik", alternatives: ["de\u011Fi\u015Fim", "degisim"], normalized: "change" },
43903
44097
  // `load` event: the i18n dict emits y\u00fckle for `load`. Without this keyword the
43904
44098
  // SOV reorder's mid-stream `y\u00fckle de` (on load) tokenized as the `install`
@@ -43908,7 +44102,13 @@ var init_turkish = __esm({
43908
44102
  load: { primary: "y\xFCkle", normalized: "load" },
43909
44103
  // Navigation
43910
44104
  go: { primary: "git", normalized: "go" },
43911
- scroll: { primary: "kayd\u0131r", alternatives: ["kaydir"], normalized: "scroll" },
44105
+ // `kayd\u0131r` is the bare imperative; the attested event noun is `kayd\u0131rma`
44106
+ // ("kayd\u0131rma olay\u0131"). The imperative stays as an alternative.
44107
+ scroll: {
44108
+ primary: "kayd\u0131rma",
44109
+ alternatives: ["kaydirma", "kayd\u0131r", "kaydir"],
44110
+ normalized: "scroll"
44111
+ },
43912
44112
  push: { primary: "itele", alternatives: ["push"], normalized: "push" },
43913
44113
  replace: { primary: "de\u011Fi\u015Ftir_url", alternatives: ["degistir_url"], normalized: "replace" },
43914
44114
  process: { primary: "i\u015Fle", alternatives: ["isle"], normalized: "process" },
@@ -44861,6 +45061,60 @@ var init_chinese = __esm({
44861
45061
  }
44862
45062
  });
44863
45063
 
45064
+ // src/parser/utils/marker-resolution.ts
45065
+ function resolveMarkerForRole(roleSpec, profile) {
45066
+ const overrideMarker = roleSpec.markerOverride?.[profile.code];
45067
+ const defaultMarker = profile.roleMarkers[roleSpec.role];
45068
+ if (overrideMarker !== void 0) {
45069
+ const alternatives = legacyMarkerAlternatives(roleSpec, profile.code, overrideMarker);
45070
+ return {
45071
+ primary: overrideMarker,
45072
+ ...alternatives && { alternatives },
45073
+ position: defaultMarker?.position ?? "before",
45074
+ isOverride: true
45075
+ };
45076
+ }
45077
+ if (defaultMarker && defaultMarker.primary) {
45078
+ const result = {
45079
+ primary: defaultMarker.primary,
45080
+ position: defaultMarker.position,
45081
+ isOverride: false
45082
+ };
45083
+ if (defaultMarker.alternatives) {
45084
+ result.alternatives = defaultMarker.alternatives;
45085
+ }
45086
+ return result;
45087
+ }
45088
+ return null;
45089
+ }
45090
+ function legacyMarkerAlternatives(roleSpec, languageCode, overrideMarker) {
45091
+ const legacy = roleSpec.markerLegacy?.[languageCode];
45092
+ if (!legacy?.length) return void 0;
45093
+ const alternatives = [...new Set(legacy)].filter((a) => a && a !== overrideMarker);
45094
+ return alternatives.length ? alternatives : void 0;
45095
+ }
45096
+ function schemaMarkerAlternatives(roleSpec, languageCode, marker) {
45097
+ const legacy = roleSpec.markerLegacy?.[languageCode] ?? [];
45098
+ const variants = roleSpec.methodCarrier ? [] : roleSpec.markerVariants?.[languageCode] ?? [];
45099
+ const alternatives = [.../* @__PURE__ */ new Set([...legacy, ...variants])].filter((a) => a && a !== marker);
45100
+ return alternatives.length ? alternatives : void 0;
45101
+ }
45102
+ var ROLE_MARKER_CONCEPTS;
45103
+ var init_marker_resolution = __esm({
45104
+ "src/parser/utils/marker-resolution.ts"() {
45105
+ ROLE_MARKER_CONCEPTS = /* @__PURE__ */ new Set([
45106
+ "destination",
45107
+ "source",
45108
+ "patient",
45109
+ "object",
45110
+ "event",
45111
+ "eventmarker",
45112
+ "manner",
45113
+ "instrument"
45114
+ ]);
45115
+ }
45116
+ });
45117
+
44864
45118
  // src/patterns/put.ts
44865
45119
  function getPutPatternsBn() {
44866
45120
  return [
@@ -59721,49 +59975,6 @@ var init_role_positioning = __esm({
59721
59975
  }
59722
59976
  });
59723
59977
 
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
59978
  // src/generators/event-handlers-sov.ts
59768
59979
  function resolveRoleMarker(roleSpec, profile) {
59769
59980
  let marker;
@@ -59797,6 +60008,43 @@ function appendOptionalScope(tokens, extraction, commandSchema) {
59797
60008
  });
59798
60009
  extraction.scope = { fromRole: "scope" };
59799
60010
  }
60011
+ function appendOptionalViewTransition(tokens, extraction, commandSchema, languageCode) {
60012
+ appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, "manner", {
60013
+ requireMarker: true
60014
+ });
60015
+ }
60016
+ function appendOptionalRecipient(tokens, extraction, commandSchema, languageCode) {
60017
+ appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, "recipient", {
60018
+ requireMarker: false
60019
+ });
60020
+ }
60021
+ function appendOptionalTailRole(tokens, extraction, commandSchema, languageCode, role, opts) {
60022
+ const spec = commandSchema.roles.find((r) => r.role === role && !r.required);
60023
+ if (!spec) return;
60024
+ const marker = spec.markerOverride?.[languageCode];
60025
+ if (opts.requireMarker && !marker) return;
60026
+ tokens.push({
60027
+ type: "group",
60028
+ optional: true,
60029
+ tokens: [
60030
+ ...(marker ? marker.split(/\s+/) : []).map(
60031
+ (word) => ({ type: "literal", value: word })
60032
+ ),
60033
+ {
60034
+ type: "role",
60035
+ role,
60036
+ optional: true,
60037
+ expectedTypes: spec.expectedTypes,
60038
+ // Load-bearing, same as on the generated command patterns: it exempts
60039
+ // the trailing slot from the matcher's verb guard, keeps the uncaptured
60040
+ // slot out of `scoreRoleCoverage`'s denominator, and (for `keyword`)
60041
+ // normalizes the captured value type to the EN reference's `literal`.
60042
+ ...spec.valueShape !== void 0 ? { valueShape: spec.valueShape } : {}
60043
+ }
60044
+ ]
60045
+ });
60046
+ extraction[role] = { fromRole: role };
60047
+ }
59800
60048
  function generateSOVEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
59801
60049
  const tokens = [];
59802
60050
  tokens.push({ type: "role", role: "event", optional: false });
@@ -59891,6 +60139,15 @@ function generateSOVPatientFirstEventHandlerPattern(commandSchema, profile, keyw
59891
60139
  tokens.push(
59892
60140
  ...swapsOperands ? eventHandlerPatientGroup(commandSchema, trailingMarker) : eventHandlerDestinationGroup(commandSchema, trailingMarker)
59893
60141
  );
60142
+ const extraction = {
60143
+ action: { value: commandSchema.action },
60144
+ event: { fromRole: "event" },
60145
+ [frontedRole]: { fromRole: frontedRole },
60146
+ ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
60147
+ ...eventHandlerSourceExtraction(commandSchema)
60148
+ };
60149
+ appendOptionalRecipient(tokens, extraction, commandSchema, profile.code);
60150
+ appendOptionalViewTransition(tokens, extraction, commandSchema, profile.code);
59894
60151
  return {
59895
60152
  id: `${commandSchema.action}-event-${profile.code}-sov-patient-first`,
59896
60153
  language: profile.code,
@@ -59900,13 +60157,7 @@ function generateSOVPatientFirstEventHandlerPattern(commandSchema, profile, keyw
59900
60157
  format: `{patient} ${patientMarker?.primary || ""} {event} ${eventMarker.primary} ${keyword.primary}`,
59901
60158
  tokens
59902
60159
  },
59903
- extraction: {
59904
- action: { value: commandSchema.action },
59905
- event: { fromRole: "event" },
59906
- [frontedRole]: { fromRole: frontedRole },
59907
- ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
59908
- ...eventHandlerSourceExtraction(commandSchema)
59909
- }
60160
+ extraction
59910
60161
  };
59911
60162
  }
59912
60163
  function generateSOVPatientFirstWithDestEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
@@ -60348,6 +60599,16 @@ function generateVSOVerbFirstEventHandlerPattern(commandSchema, profile, keyword
60348
60599
  });
60349
60600
  }
60350
60601
  }
60602
+ const extraction = {
60603
+ action: { value: commandSchema.action },
60604
+ event: { fromRole: "event" },
60605
+ [swapsOperands ? "destination" : "patient"]: {
60606
+ fromRole: swapsOperands ? "destination" : "patient"
60607
+ },
60608
+ ...swapsOperands ? {} : eventHandlerDestinationExtraction(commandSchema),
60609
+ ...eventHandlerSourceExtraction(commandSchema)
60610
+ };
60611
+ appendOptionalViewTransition(tokens, extraction, commandSchema, profile.code);
60351
60612
  return {
60352
60613
  id: `${commandSchema.action}-event-${profile.code}-vso-verb-first`,
60353
60614
  language: profile.code,
@@ -60358,15 +60619,7 @@ function generateVSOVerbFirstEventHandlerPattern(commandSchema, profile, keyword
60358
60619
  format: `${keyword.primary} {patient} ${destMarker?.primary || ""} {destination?} ${eventMarker.primary} {event}`,
60359
60620
  tokens
60360
60621
  },
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
- }
60622
+ extraction
60370
60623
  };
60371
60624
  }
60372
60625
  function generateVSOVerbFirstTwoRoleEventHandlerPattern(commandSchema, profile, keyword, eventMarker, config) {
@@ -60968,7 +61221,11 @@ function buildRoleToken(roleSpec, profile) {
60968
61221
  type: "role",
60969
61222
  role: roleSpec.role,
60970
61223
  optional: !roleSpec.required,
60971
- expectedTypes: roleSpec.expectedTypes
61224
+ expectedTypes: roleSpec.expectedTypes,
61225
+ // The matcher reads this too \u2014 a `'keyword'`-shaped slot holds a fixed
61226
+ // keyword phrase (`using view transition`) and must not be skipped by the
61227
+ // trailing-slot verb guard.
61228
+ ...roleSpec.valueShape !== void 0 ? { valueShape: roleSpec.valueShape } : {}
60972
61229
  };
60973
61230
  const prefixLiteral = roleSpec.valuePrefixLiteral?.[profile.code];
60974
61231
  const pushPrefixed = () => {
@@ -61277,9 +61534,24 @@ var init_pick = __esm({
61277
61534
  });
61278
61535
 
61279
61536
  // src/patterns/languages/en/swap.ts
61280
- var swapSimpleEnglish, swapElementEnglish, swapStrategyOfEnglish, swapStrategyEnglish, swapPatternsEn;
61537
+ var VIEW_TRANSITION_TAIL, swapSimpleEnglish, swapElementEnglish, swapStrategyOfEnglish, swapStrategyEnglish, swapPatternsEn;
61281
61538
  var init_swap = __esm({
61282
61539
  "src/patterns/languages/en/swap.ts"() {
61540
+ VIEW_TRANSITION_TAIL = {
61541
+ type: "group",
61542
+ optional: true,
61543
+ tokens: [
61544
+ { type: "literal", value: "using" },
61545
+ { type: "literal", value: "view" },
61546
+ {
61547
+ type: "role",
61548
+ role: "manner",
61549
+ optional: true,
61550
+ expectedTypes: ["literal", "expression"],
61551
+ valueShape: "keyword"
61552
+ }
61553
+ ]
61554
+ };
61283
61555
  swapSimpleEnglish = {
61284
61556
  id: "swap-en-handcrafted",
61285
61557
  language: "en",
@@ -61287,11 +61559,12 @@ var init_swap = __esm({
61287
61559
  priority: 110,
61288
61560
  // Higher than generated patterns
61289
61561
  template: {
61290
- format: "swap {method} {destination}",
61562
+ format: "swap {method} {destination} [using view {manner}]",
61291
61563
  tokens: [
61292
61564
  { type: "literal", value: "swap" },
61293
61565
  { type: "role", role: "method" },
61294
- { type: "role", role: "destination" }
61566
+ { type: "role", role: "destination" },
61567
+ VIEW_TRANSITION_TAIL
61295
61568
  ]
61296
61569
  },
61297
61570
  extraction: {
@@ -61305,12 +61578,13 @@ var init_swap = __esm({
61305
61578
  command: "swap",
61306
61579
  priority: 120,
61307
61580
  template: {
61308
- format: "swap {destination} with {patient}",
61581
+ format: "swap {destination} with {patient} [using view {manner}]",
61309
61582
  tokens: [
61310
61583
  { type: "literal", value: "swap" },
61311
61584
  { type: "role", role: "destination" },
61312
61585
  { type: "literal", value: "with" },
61313
- { type: "role", role: "patient" }
61586
+ { type: "role", role: "patient" },
61587
+ VIEW_TRANSITION_TAIL
61314
61588
  ]
61315
61589
  },
61316
61590
  extraction: {}
@@ -61321,14 +61595,15 @@ var init_swap = __esm({
61321
61595
  command: "swap",
61322
61596
  priority: 140,
61323
61597
  template: {
61324
- format: "swap {method} of {destination} with {patient}",
61598
+ format: "swap {method} of {destination} with {patient} [using view {manner}]",
61325
61599
  tokens: [
61326
61600
  { type: "literal", value: "swap" },
61327
61601
  { type: "role", role: "method" },
61328
61602
  { type: "literal", value: "of" },
61329
61603
  { type: "role", role: "destination" },
61330
61604
  { type: "literal", value: "with" },
61331
- { type: "role", role: "patient" }
61605
+ { type: "role", role: "patient" },
61606
+ VIEW_TRANSITION_TAIL
61332
61607
  ]
61333
61608
  },
61334
61609
  extraction: {}
@@ -61339,13 +61614,14 @@ var init_swap = __esm({
61339
61614
  command: "swap",
61340
61615
  priority: 130,
61341
61616
  template: {
61342
- format: "swap {method} {destination} with {patient}",
61617
+ format: "swap {method} {destination} with {patient} [using view {manner}]",
61343
61618
  tokens: [
61344
61619
  { type: "literal", value: "swap" },
61345
61620
  { type: "role", role: "method" },
61346
61621
  { type: "role", role: "destination" },
61347
61622
  { type: "literal", value: "with" },
61348
- { type: "role", role: "patient" }
61623
+ { type: "role", role: "patient" },
61624
+ VIEW_TRANSITION_TAIL
61349
61625
  ]
61350
61626
  },
61351
61627
  extraction: {}
@@ -64715,6 +64991,7 @@ function isTypeCompatible(actualType, expectedTypes) {
64715
64991
  }
64716
64992
 
64717
64993
  // src/parser/pattern-matcher.ts
64994
+ init_marker_resolution();
64718
64995
  init_command_schemas();
64719
64996
 
64720
64997
  // src/parser/utils/possessive-keywords.ts
@@ -65279,7 +65556,8 @@ var DefaultConfidenceModel = class {
65279
65556
  const hasDefault = (role) => {
65280
65557
  return pattern.extraction?.[role]?.default !== void 0;
65281
65558
  };
65282
- const schemaRoles = commandSchemas[pattern.command]?.roles;
65559
+ const wrappedAction = pattern.command === "on" ? pattern.extraction?.action?.value : void 0;
65560
+ const schemaRoles = commandSchemas[wrappedAction ?? pattern.command]?.roles;
65283
65561
  const isShapeAnchored = (role) => schemaRoles?.find((r) => r.role === role)?.valueShape !== void 0;
65284
65562
  for (const token of pattern.template.tokens) {
65285
65563
  if (token.type === "role") {
@@ -65683,7 +65961,7 @@ var _PatternMatcher = class _PatternMatcher {
65683
65961
  return patternToken.optional || false;
65684
65962
  }
65685
65963
  }
65686
- if (patternToken.optional && nextPatternToken === void 0 && patternToken.role !== "event" && patternToken.role !== "action" && token.kind === "keyword") {
65964
+ if (patternToken.optional && nextPatternToken === void 0 && patternToken.role !== "event" && patternToken.role !== "action" && patternToken.valueShape !== "keyword" && token.kind === "keyword") {
65687
65965
  const verbNorm = (token.normalized ?? token.value).toLowerCase();
65688
65966
  if (verbNorm in commandSchemas) {
65689
65967
  return true;
@@ -65838,7 +66116,11 @@ var _PatternMatcher = class _PatternMatcher {
65838
66116
  }
65839
66117
  }
65840
66118
  }
65841
- captured.set(patternToken.role, value);
66119
+ if (patternToken.valueShape === "keyword" && value.type === "expression") {
66120
+ captured.set(patternToken.role, createLiteral(String(value.raw ?? "")));
66121
+ } else {
66122
+ captured.set(patternToken.role, value);
66123
+ }
65842
66124
  tokens.advance();
65843
66125
  if (patternToken.role === "event") {
65844
66126
  const filterTok = tokens.peek();
@@ -66427,17 +66709,7 @@ var _PatternMatcher = class _PatternMatcher {
66427
66709
  * so this never blocks a genuine `my value` / `its style` possessive.
66428
66710
  */
66429
66711
  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());
66712
+ return ROLE_MARKER_CONCEPTS.has(normalized2.toLowerCase());
66441
66713
  }
66442
66714
  /**
66443
66715
  * Does `token` look like an EVENT name for the `event` role? Events are bare
@@ -66823,7 +67095,7 @@ var _PatternMatcher = class _PatternMatcher {
66823
67095
  */
66824
67096
  matchGroupToken(tokens, patternToken, captured, nextPatternToken) {
66825
67097
  const mark = tokens.mark();
66826
- const capturedBefore = new Set(captured.keys());
67098
+ const capturedBefore = new Map(captured);
66827
67099
  const success = this.matchTokenSequence(
66828
67100
  tokens,
66829
67101
  patternToken.tokens,
@@ -66837,6 +67109,11 @@ var _PatternMatcher = class _PatternMatcher {
66837
67109
  captured.delete(role);
66838
67110
  }
66839
67111
  }
67112
+ for (const [role, value] of capturedBefore) {
67113
+ if (captured.get(role) !== value) {
67114
+ captured.set(role, value);
67115
+ }
67116
+ }
66840
67117
  return patternToken.optional || false;
66841
67118
  }
66842
67119
  return true;
@@ -67226,6 +67503,7 @@ function registerTokenizer2(tokenizer) {
67226
67503
  // src/parser/semantic-parser.ts
67227
67504
  init_registry();
67228
67505
  init_command_schemas();
67506
+ init_marker_resolution();
67229
67507
 
67230
67508
  // src/parser/block-parser.ts
67231
67509
  init_registry();
@@ -69275,13 +69553,18 @@ var _SemanticParserImpl = class _SemanticParserImpl {
69275
69553
  if (!spec) return true;
69276
69554
  return spec.expectedTypes.length > 0 && !spec.expectedTypes.includes(valType(val));
69277
69555
  };
69556
+ const isMarkerConceptJunk = (role, val) => role === "patient" && !!schema && !schema.roles.some((r) => r.role === "patient") && valType(val) === "literal" && ROLE_MARKER_CONCEPTS.has(
69557
+ String(val.value ?? "").toLowerCase()
69558
+ );
69278
69559
  const preservesFused = !!first && first.kind === "command" && Object.entries(roles).every(([role, val]) => {
69279
- if (isIgnorableFusedRole(role, val)) return true;
69560
+ if (isIgnorableFusedRole(role, val) || isMarkerConceptJunk(role, val)) return true;
69280
69561
  const rv = first.roles.get(mapRole(role));
69281
69562
  if (rv !== void 0 && valType(rv) === valType(val)) return true;
69282
69563
  if (role === "patient" && actionName === "pick" && valType(val) === "literal") {
69283
69564
  const mv = first.roles.get("method");
69284
- return mv !== void 0 && valType(mv) === "literal" && String(mv.value) === String(val.value);
69565
+ const mvType = valType(mv);
69566
+ const mvSurface = mvType === "literal" ? String(mv.value) : mvType === "expression" ? String(mv.raw) : void 0;
69567
+ return mvSurface !== void 0 && mvSurface === String(val.value);
69285
69568
  }
69286
69569
  return false;
69287
69570
  });
@@ -69291,7 +69574,12 @@ var _SemanticParserImpl = class _SemanticParserImpl {
69291
69574
  // the swap can never swallow a body command. The body-swallowing
69292
69575
  // generated repeat matches none of these ids.
69293
69576
  /^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) {
69577
+ if (reparsed.length === 1 && first && first.kind === "command" && first.action === actionName && preservesFused && headOnlyOk && // Strictly-more: the re-parse must recover something the fused
69578
+ // capture lacked. Junk marker captures are excluded from the
69579
+ // count \u2014 a fused shape whose ONLY role is a swallowed marker
69580
+ // (scroll: `destination:literal="destination"`) would otherwise
69581
+ // tie 1 > 1 and veto its own repair.
69582
+ first.roles.size > Object.entries(roles).filter(([r, v]) => !isMarkerConceptJunk(r, v)).length) {
69295
69583
  commandNode = first;
69296
69584
  while (tokens.position() < clauseEnd) tokens.advance();
69297
69585
  } else {
@@ -76090,7 +76378,7 @@ function getGetPatternsBn() {
76090
76378
  tokens: [
76091
76379
  { type: "role", role: "source" },
76092
76380
  { type: "literal", value: "\u09A5\u09C7\u0995\u09C7" },
76093
- { type: "literal", value: "\u09AA\u09BE\u09A8", alternatives: ["\u09A8\u09BF\u09A8"] }
76381
+ { type: "literal", value: "\u09AA\u09BE\u09A8" }
76094
76382
  ]
76095
76383
  },
76096
76384
  extraction: {
@@ -76106,7 +76394,7 @@ function getGetPatternsBn() {
76106
76394
  template: {
76107
76395
  format: "\u09AA\u09BE\u09A8 {source}",
76108
76396
  tokens: [
76109
- { type: "literal", value: "\u09AA\u09BE\u09A8", alternatives: ["\u09A8\u09BF\u09A8"] },
76397
+ { type: "literal", value: "\u09AA\u09BE\u09A8" },
76110
76398
  { type: "role", role: "source" }
76111
76399
  ]
76112
76400
  },
@@ -76190,7 +76478,7 @@ function getGetPatternsIt() {
76190
76478
  template: {
76191
76479
  format: "ottenere {patient} da {source}",
76192
76480
  tokens: [
76193
- { type: "literal", value: "ottenere", alternatives: ["ottieni", "get", "prendere"] },
76481
+ { type: "literal", value: "ottenere", alternatives: ["ottieni", "get"] },
76194
76482
  { type: "role", role: "patient" },
76195
76483
  {
76196
76484
  type: "group",
@@ -76280,7 +76568,7 @@ function getGetPatternsRu() {
76280
76568
  template: {
76281
76569
  format: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C {patient} \u0438\u0437 {source}",
76282
76570
  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"] },
76571
+ { type: "literal", value: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C", alternatives: ["\u043F\u043E\u043B\u0443\u0447\u0438"] },
76284
76572
  { type: "role", role: "patient" },
76285
76573
  {
76286
76574
  type: "group",
@@ -76305,7 +76593,7 @@ function getGetPatternsRu() {
76305
76593
  template: {
76306
76594
  format: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C {patient}",
76307
76595
  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"] },
76596
+ { type: "literal", value: "\u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C", alternatives: ["\u043F\u043E\u043B\u0443\u0447\u0438"] },
76309
76597
  { type: "role", role: "patient" }
76310
76598
  ]
76311
76599
  },
@@ -76346,7 +76634,7 @@ function getGetPatternsUk() {
76346
76634
  template: {
76347
76635
  format: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438 {patient} \u0437 {source}",
76348
76636
  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"] },
76637
+ { type: "literal", value: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438", alternatives: ["\u043E\u0442\u0440\u0438\u043C\u0430\u0439"] },
76350
76638
  { type: "role", role: "patient" },
76351
76639
  {
76352
76640
  type: "group",
@@ -76371,7 +76659,7 @@ function getGetPatternsUk() {
76371
76659
  template: {
76372
76660
  format: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438 {patient}",
76373
76661
  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"] },
76662
+ { type: "literal", value: "\u043E\u0442\u0440\u0438\u043C\u0430\u0442\u0438", alternatives: ["\u043E\u0442\u0440\u0438\u043C\u0430\u0439"] },
76375
76663
  { type: "role", role: "patient" }
76376
76664
  ]
76377
76665
  },
@@ -76391,7 +76679,7 @@ function getGetPatternsVi() {
76391
76679
  template: {
76392
76680
  format: "l\u1EA5y gi\xE1 tr\u1ECB c\u1EE7a {target}",
76393
76681
  tokens: [
76394
- { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn", "l\u1EA5y"] },
76682
+ { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn"] },
76395
76683
  { type: "group", optional: true, tokens: [{ type: "literal", value: "c\u1EE7a" }] },
76396
76684
  { type: "role", role: "patient" }
76397
76685
  ]
@@ -76402,13 +76690,17 @@ function getGetPatternsVi() {
76402
76690
  },
76403
76691
  {
76404
76692
  id: "get-vi-simple",
76693
+ // Head was `l\u1ea5y` (alt `l\u1ea5y gi\u00e1 tr\u1ecb`) \u2014 but bare `l\u1ea5y` is vi's TAKE verb,
76694
+ // so this pattern claimed every `l\u1ea5y .active t\u1eeb \u2026`. vi's get verb is the
76695
+ // three-word `l\u1ea5y gi\u00e1 tr\u1ecb` ("take the value of"), which is what the i18n
76696
+ // transformer renders; the bare form has no valid `get` surface.
76405
76697
  language: "vi",
76406
76698
  command: "get",
76407
76699
  priority: 90,
76408
76700
  template: {
76409
- format: "l\u1EA5y {target}",
76701
+ format: "l\u1EA5y gi\xE1 tr\u1ECB {target}",
76410
76702
  tokens: [
76411
- { type: "literal", value: "l\u1EA5y", alternatives: ["nh\u1EADn", "l\u1EA5y gi\xE1 tr\u1ECB"] },
76703
+ { type: "literal", value: "l\u1EA5y gi\xE1 tr\u1ECB", alternatives: ["nh\u1EADn"] },
76412
76704
  { type: "role", role: "patient" }
76413
76705
  ]
76414
76706
  },
@@ -78167,6 +78459,12 @@ function getSendPatternsForLanguage(language) {
78167
78459
  }
78168
78460
 
78169
78461
  // src/patterns/pick.ts
78462
+ var PICK_UNIT_WORDS = /* @__PURE__ */ new Set(["character", "characters", "item", "items"]);
78463
+ var retypePickUnitWord = (raw) => {
78464
+ if (PICK_UNIT_WORDS.has(raw)) return { type: "expression", raw };
78465
+ const n = Number(raw);
78466
+ return createLiteral(raw !== "" && !Number.isNaN(n) ? n : raw);
78467
+ };
78170
78468
  function makePickVariantPattern(language, spec) {
78171
78469
  const tokens = [{ type: "literal", value: "pick" }];
78172
78470
  if (spec.objectMarkers?.length) {
@@ -78206,7 +78504,7 @@ function makePickVariantPattern(language, spec) {
78206
78504
  tokens
78207
78505
  },
78208
78506
  extraction: {
78209
- method: { position: 1 },
78507
+ method: { position: 1, transform: retypePickUnitWord },
78210
78508
  patient: { position: 2 },
78211
78509
  source: {
78212
78510
  marker: spec.srcMarker,
@@ -78257,7 +78555,7 @@ function makePickVerbFinalPattern(language, spec) {
78257
78555
  },
78258
78556
  extraction: {
78259
78557
  source: { position: 0 },
78260
- method: { position: 2 },
78558
+ method: { position: 2, transform: retypePickUnitWord },
78261
78559
  patient: { position: 3 }
78262
78560
  }
78263
78561
  };