@statelyai/sdk 0.26.3 → 0.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +30 -2
  2. package/dist/auth.d.mts +1 -1
  3. package/dist/{editorHostSession-DFjM-RoT.d.mts → editorHostSession-CWAuoMtC.d.mts} +9 -3
  4. package/dist/{editorHostSession-CwGeXJ6g.mjs → editorHostSession-shrjfosC.mjs} +6 -3
  5. package/dist/editorHostSession.d.mts +1 -1
  6. package/dist/editorHostSession.mjs +1 -1
  7. package/dist/embed.d.mts +6 -3
  8. package/dist/embed.mjs +23 -1
  9. package/dist/embedPanel-Bpbq4sfJ.d.mts +13 -0
  10. package/dist/{graph-DoUReqxz.d.mts → graph-BwHnhzpC.d.mts} +48 -6
  11. package/dist/graph.d.mts +1 -1
  12. package/dist/graph.mjs +36 -4
  13. package/dist/{index-DKRB-u93.d.mts → index-D2I1qPsf.d.mts} +19 -3
  14. package/dist/index.d.mts +8 -7
  15. package/dist/index.mjs +6 -6
  16. package/dist/{inspect-CiPPDR7Q.mjs → inspect-CebH2l6F.mjs} +3 -5
  17. package/dist/{inspect-Br_vS_lK.d.mts → inspect-D61HS-t7.d.mts} +2 -5
  18. package/dist/inspect.d.mts +1 -1
  19. package/dist/inspect.mjs +2 -2
  20. package/dist/patchTypes.d.mts +1 -1
  21. package/dist/protocol.d.mts +46 -15
  22. package/dist/{statelyPragma-B-axv279.mjs → statelyPragma-ByF0-L-N.mjs} +1198 -31
  23. package/dist/{studio-B6P177N3.d.mts → studio-B9-1Ynrx.d.mts} +4 -2
  24. package/dist/{studio-iNSHtNmP.mjs → studio-CNkxMZyz.mjs} +4 -1
  25. package/dist/studio.d.mts +1 -1
  26. package/dist/studio.mjs +1 -1
  27. package/dist/sync.d.mts +12 -4
  28. package/dist/sync.mjs +2920 -262
  29. package/dist/{version-At1lONTa.mjs → version-usAEzut8.mjs} +19 -7
  30. package/package.json +3 -3
  31. package/schemas/xstate.schema.json +41 -5
  32. /package/dist/{auth-B0ZTKri2.d.mts → auth-BPyCCHYo.d.mts} +0 -0
  33. /package/dist/{editor-sync-types-C-zWaaVk.d.mts → editor-sync-types-CTKArS8n.d.mts} +0 -0
package/dist/sync.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import "./openapi-BTDjYWXd.mjs";
2
- import { r as createStatelyClient } from "./studio-iNSHtNmP.mjs";
3
- import { f as normalizeMachineProfile, h as xstateSourceToConfig, i as INLINE_EXPRESSION_DIRECTIVE_FIELDS, m as serializeJS, n as getStatelyPragma, r as upsertStatelyPragma, s as detectXStateSourceProfile, t as findStatelyPragmaAttachments, u as graphToXStateTS } from "./statelyPragma-B-axv279.mjs";
2
+ import { r as createStatelyClient } from "./studio-CNkxMZyz.mjs";
3
+ import { _ as normalizeMachineProfile, b as xstateSourceToConfig, c as detectXStateSourceProfile, f as graphChangeToPatchesResult, h as graphToXStateTS, i as INLINE_EXPRESSION_DIRECTIVE_FIELDS, l as diffGraphsSemantically, n as getStatelyPragma, o as alignCompareGraphIds, p as graphToMachineConfig, r as upsertStatelyPragma, t as findStatelyPragmaAttachments, y as serializeJS } from "./statelyPragma-ByF0-L-N.mjs";
4
4
  import { fromStudioMachine, toStudioMachine } from "./graph.mjs";
5
5
  import * as ts$1 from "typescript";
6
6
  import ts from "typescript";
7
- import { getDiff, isEmptyDiff } from "@statelyai/graph";
7
+ import { isEmptyDiff } from "@statelyai/graph";
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import { execFile } from "node:child_process";
@@ -50,6 +50,17 @@ function createTextDocument(fileName, text, uri = path$1.isAbsolute(fileName) ?
50
50
  }
51
51
  };
52
52
  }
53
+ function applyReplacementsToText(text, replacements) {
54
+ let updated = text;
55
+ const sorted = [...replacements].sort(compareReplacementRangesDescending$1);
56
+ for (const replacement of sorted) {
57
+ const lineStarts = getLineStarts(updated);
58
+ const start = offsetAt(lineStarts, replacement.range.startLine, replacement.range.startChar);
59
+ const end = offsetAt(lineStarts, replacement.range.endLine, replacement.range.endChar);
60
+ updated = `${updated.slice(0, start)}${replacement.newText}${updated.slice(end)}`;
61
+ }
62
+ return updated;
63
+ }
53
64
  function sourceUriToFileName(uriOrPath) {
54
65
  if (uriOrPath.startsWith("file://")) return fileURLToPath(uriOrPath);
55
66
  if (/^[a-z][a-z\d+.-]*:/i.test(uriOrPath)) throw new Error(`Unsupported non-file URI: ${uriOrPath}`);
@@ -133,17 +144,26 @@ function getLineStarts(text) {
133
144
  for (let index = 0; index < text.length; index += 1) if (text.charCodeAt(index) === 10) lineStarts.push(index + 1);
134
145
  return lineStarts;
135
146
  }
147
+ function offsetAt(lineStarts, line, character) {
148
+ const lineStart = lineStarts[line];
149
+ if (lineStart === void 0) return lineStarts[lineStarts.length - 1] + character;
150
+ return lineStart + character;
151
+ }
152
+ function compareReplacementRangesDescending$1(left, right) {
153
+ if (left.range.startLine !== right.range.startLine) return right.range.startLine - left.range.startLine;
154
+ return right.range.startChar - left.range.startChar;
155
+ }
136
156
 
137
157
  //#endregion
138
158
  //#region ../editor-sync/src/internal/sourceLocations.ts
139
159
  const sourceFileUris = /* @__PURE__ */ new WeakMap();
140
160
  function collectXStateSourceLocations(sourceText, document, options = {}) {
141
- const sourceFile = ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$2(document.fileName));
161
+ const sourceFile = ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$3(document.fileName));
142
162
  const uri = document.uri?.toString() ?? document.fileName;
143
163
  sourceFileUris.set(sourceFile, uri);
144
164
  const bindings = collectBindings(sourceFile, uri, document.fileName, options);
145
165
  const staticValues = collectStaticValueBindings(sourceFile);
146
- const root = findMachineConfigObjectLiteral(sourceFile, bindings);
166
+ const root = findMachineConfigObjectLiteral$1(sourceFile, bindings, options.machineIndex);
147
167
  if (!root) return;
148
168
  const states = [];
149
169
  const statesObjectLocations = [];
@@ -250,11 +270,11 @@ function parseRangePart(value) {
250
270
  }
251
271
  function collectImportedXStateTransitionSources(sourceText, document, options = {}) {
252
272
  if (!options.resolver) return [];
253
- const sourceFile = ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$2(document.fileName));
273
+ const sourceFile = ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$3(document.fileName));
254
274
  const uri = document.uri?.toString() ?? document.fileName;
255
275
  sourceFileUris.set(sourceFile, uri);
256
276
  const bindings = collectBindings(sourceFile, uri, document.fileName, options);
257
- const root = findMachineConfigObjectLiteral(sourceFile, bindings);
277
+ const root = findMachineConfigObjectLiteral$1(sourceFile, bindings, options.machineIndex);
258
278
  if (!root) return [];
259
279
  return [...collectResolvedTransitionFunctions(root, bindings)].flatMap(([localName, resolved]) => {
260
280
  const { binding } = resolved;
@@ -326,7 +346,7 @@ function collectTopLevelBindings(sourceFile, uri) {
326
346
  if (!ts$1.isVariableStatement(statement)) continue;
327
347
  for (const declaration of statement.declarationList.declarations) {
328
348
  if (!ts$1.isIdentifier(declaration.name) || !declaration.initializer) continue;
329
- const initializer = unwrapExpression$1(declaration.initializer);
349
+ const initializer = unwrapExpression$2(declaration.initializer);
330
350
  if (ts$1.isArrowFunction(initializer) || ts$1.isFunctionExpression(initializer)) {
331
351
  bindings.set(declaration.name.text, {
332
352
  kind: "transitionFunction",
@@ -337,7 +357,7 @@ function collectTopLevelBindings(sourceFile, uri) {
337
357
  });
338
358
  continue;
339
359
  }
340
- const objectLiteral = unwrapObjectLiteralExpression(declaration.initializer);
360
+ const objectLiteral = unwrapObjectLiteralExpression$1(declaration.initializer);
341
361
  if (objectLiteral) {
342
362
  bindings.set(declaration.name.text, {
343
363
  kind: "objectReference",
@@ -372,7 +392,7 @@ function addImportedBindings(bindings, sourceFile, uri, fileName, options, cache
372
392
  uri
373
393
  }, statement.moduleSpecifier.text);
374
394
  if (!importedDocument) continue;
375
- const importedSourceFile = ts$1.createSourceFile(importedDocument.fileName, importedDocument.text, ts$1.ScriptTarget.Latest, true, getScriptKind$2(importedDocument.fileName));
395
+ const importedSourceFile = ts$1.createSourceFile(importedDocument.fileName, importedDocument.text, ts$1.ScriptTarget.Latest, true, getScriptKind$3(importedDocument.fileName));
376
396
  sourceFileUris.set(importedSourceFile, importedDocument.uri);
377
397
  const importedBindings = collectBindings(importedSourceFile, importedDocument.uri, importedDocument.fileName, options, cache);
378
398
  for (const element of namedBindings.elements) {
@@ -385,7 +405,7 @@ function addImportedBindings(bindings, sourceFile, uri, fileName, options, cache
385
405
  function collectResolvedTransitionFunctions(root, bindings) {
386
406
  const found = /* @__PURE__ */ new Map();
387
407
  const visitExpression = (expression, sourcePath) => {
388
- const current = unwrapExpression$1(expression);
408
+ const current = unwrapExpression$2(expression);
389
409
  if (ts$1.isIdentifier(current)) {
390
410
  const binding = bindings.get(current.text);
391
411
  if (binding?.kind === "transitionFunction") {
@@ -422,30 +442,34 @@ function collectResolvedTransitionFunctions(root, bindings) {
422
442
  "onSnapshot",
423
443
  "onTimeout"
424
444
  ]) {
425
- const property = state.properties.find((candidate) => ts$1.isPropertyAssignment(candidate) && getPropertyNameText$1(candidate.name) === propertyName);
445
+ const property = state.properties.find((candidate) => ts$1.isPropertyAssignment(candidate) && getPropertyNameText$2(candidate.name) === propertyName);
426
446
  if (property) visitExpression(property.initializer, sourcePath);
427
447
  }
428
- const states = state.properties.find((candidate) => ts$1.isPropertyAssignment(candidate) && getPropertyNameText$1(candidate.name) === "states");
429
- const statesObject = states && unwrapObjectLiteralExpression(states.initializer);
448
+ const states = state.properties.find((candidate) => ts$1.isPropertyAssignment(candidate) && getPropertyNameText$2(candidate.name) === "states");
449
+ const statesObject = states && unwrapObjectLiteralExpression$1(states.initializer);
430
450
  if (!statesObject) return;
431
451
  for (const property of statesObject.properties) {
432
452
  if (!ts$1.isPropertyAssignment(property)) continue;
433
- const child = unwrapObjectLiteralExpression(property.initializer);
434
- const key = getPropertyNameText$1(property.name);
453
+ const child = unwrapObjectLiteralExpression$1(property.initializer);
454
+ const key = getPropertyNameText$2(property.name);
435
455
  if (child && key) visitState(child, [...sourcePath, key]);
436
456
  }
437
457
  };
438
458
  visitState(root, []);
439
459
  return found;
440
460
  }
441
- function findMachineConfigObjectLiteral(sourceFile, bindings) {
461
+ function findMachineConfigObjectLiteral$1(sourceFile, bindings, machineIndex = 0) {
442
462
  let found = null;
463
+ let currentMachineIndex = 0;
443
464
  const visit = (node) => {
444
465
  if (found) return;
445
- if (ts$1.isCallExpression(node) && isCreateMachineExpression$1(node.expression)) {
466
+ if (ts$1.isCallExpression(node) && isCreateMachineExpression$2(node.expression)) {
467
+ const isSelectedMachine = currentMachineIndex === machineIndex;
468
+ currentMachineIndex += 1;
469
+ if (!isSelectedMachine) return;
446
470
  const [firstArgument] = node.arguments;
447
471
  if (!firstArgument || !ts$1.isExpression(firstArgument)) return;
448
- found = unwrapObjectLiteralExpression(firstArgument) ?? resolveIdentifierObject(firstArgument, bindings);
472
+ found = unwrapObjectLiteralExpression$1(firstArgument) ?? resolveIdentifierObject(firstArgument, bindings);
449
473
  return;
450
474
  }
451
475
  ts$1.forEachChild(node, visit);
@@ -502,7 +526,7 @@ function resolveStateProperty(property, bindings, staticValues, root) {
502
526
  if (!ts$1.isPropertyAssignment(property)) return null;
503
527
  const resolvedKey = resolvePropertyKey(property.name, staticValues, root);
504
528
  if (!resolvedKey) return null;
505
- const inlineObject = unwrapObjectLiteralExpression(property.initializer);
529
+ const inlineObject = unwrapObjectLiteralExpression$1(property.initializer);
506
530
  if (inlineObject) return {
507
531
  key: resolvedKey.key,
508
532
  kind: "inline",
@@ -537,19 +561,19 @@ function getSourceFileUri(sourceFile) {
537
561
  return sourceFileUris.get(sourceFile) ?? sourceFile.fileName;
538
562
  }
539
563
  function unwrapCreateConfigArgument(expression) {
540
- const unwrapped = unwrapExpression$1(expression);
564
+ const unwrapped = unwrapExpression$2(expression);
541
565
  if (!ts$1.isCallExpression(unwrapped)) return null;
542
566
  const callee = unwrapped.expression;
543
567
  if (!ts$1.isPropertyAccessExpression(callee) || !isSetupCreateConfigName(callee.name.text)) return null;
544
568
  const [firstArgument] = unwrapped.arguments;
545
569
  if (!firstArgument || !ts$1.isExpression(firstArgument)) return null;
546
- return unwrapObjectLiteralExpression(firstArgument);
570
+ return unwrapObjectLiteralExpression$1(firstArgument);
547
571
  }
548
572
  function isSetupCreateConfigName(name) {
549
573
  return /^create[A-Z_$][\w$]*Config$/.test(name);
550
574
  }
551
575
  function resolveIdentifierObject(expression, bindings) {
552
- const unwrapped = unwrapExpression$1(expression);
576
+ const unwrapped = unwrapExpression$2(expression);
553
577
  if (!ts$1.isIdentifier(unwrapped)) return null;
554
578
  const binding = bindings.get(unwrapped.text);
555
579
  return binding?.kind === "objectReference" ? binding.node : null;
@@ -557,8 +581,8 @@ function resolveIdentifierObject(expression, bindings) {
557
581
  function resolveObjectLiteralProperty(objectLiteral, propertyName, bindings) {
558
582
  for (const property of objectLiteral.properties) {
559
583
  if (!ts$1.isPropertyAssignment(property)) continue;
560
- if (getPropertyNameText$1(property.name) !== propertyName) continue;
561
- const inlineObject = unwrapObjectLiteralExpression(property.initializer);
584
+ if (getPropertyNameText$2(property.name) !== propertyName) continue;
585
+ const inlineObject = unwrapObjectLiteralExpression$1(property.initializer);
562
586
  if (inlineObject) return {
563
587
  object: inlineObject,
564
588
  kind: "inline",
@@ -585,7 +609,7 @@ function resolveObjectLiteralProperty(objectLiteral, propertyName, bindings) {
585
609
  }
586
610
  return null;
587
611
  }
588
- function getPropertyNameText$1(name) {
612
+ function getPropertyNameText$2(name) {
589
613
  if (ts$1.isIdentifier(name) || ts$1.isStringLiteral(name) || ts$1.isNumericLiteral(name)) return name.text;
590
614
  if (ts$1.isComputedPropertyName(name)) {
591
615
  const expression = name.expression;
@@ -594,7 +618,7 @@ function getPropertyNameText$1(name) {
594
618
  return null;
595
619
  }
596
620
  function resolvePropertyKey(name, staticValues, root) {
597
- const literalKey = getPropertyNameText$1(name);
621
+ const literalKey = getPropertyNameText$2(name);
598
622
  if (literalKey !== null) {
599
623
  if (ts$1.isComputedPropertyName(name)) return {
600
624
  key: literalKey,
@@ -618,7 +642,7 @@ function resolvePropertyKey(name, staticValues, root) {
618
642
  };
619
643
  }
620
644
  function getStaticValueBindingForExpression(expression, staticValues) {
621
- const unwrapped = unwrapExpression$1(expression);
645
+ const unwrapped = unwrapExpression$2(expression);
622
646
  if (ts$1.isIdentifier(unwrapped)) return staticValues.get(unwrapped.text) ?? null;
623
647
  if (ts$1.isPropertyAccessExpression(unwrapped) && ts$1.isIdentifier(unwrapped.expression)) return staticValues.get(`${unwrapped.expression.text}.${unwrapped.name.text}`) ?? null;
624
648
  return null;
@@ -692,10 +716,10 @@ function isStateKeyComputedPropertyName(name) {
692
716
  if (!ts$1.isObjectLiteralExpression(objectLiteral)) return false;
693
717
  const parentProperty = objectLiteral.parent;
694
718
  if (!ts$1.isPropertyAssignment(parentProperty)) return false;
695
- return getPropertyNameText$1(parentProperty.name) === "states";
719
+ return getPropertyNameText$2(parentProperty.name) === "states";
696
720
  }
697
721
  function getStaticStringValue(expression) {
698
- const unwrapped = unwrapExpression$1(expression);
722
+ const unwrapped = unwrapExpression$2(expression);
699
723
  if (ts$1.isStringLiteral(unwrapped) || ts$1.isNoSubstitutionTemplateLiteral(unwrapped) || ts$1.isNumericLiteral(unwrapped)) return unwrapped.text;
700
724
  return null;
701
725
  }
@@ -703,15 +727,15 @@ function getEnumMemberName(name) {
703
727
  if (ts$1.isIdentifier(name) || ts$1.isStringLiteral(name) || ts$1.isNumericLiteral(name)) return name.text;
704
728
  return null;
705
729
  }
706
- function isCreateMachineExpression$1(expression) {
730
+ function isCreateMachineExpression$2(expression) {
707
731
  const isMachineFactoryName = (name) => name === "createMachine" || name === "createMachineFromConfig";
708
732
  return ts$1.isIdentifier(expression) && isMachineFactoryName(expression.text) || ts$1.isPropertyAccessExpression(expression) && isMachineFactoryName(expression.name.text);
709
733
  }
710
- function unwrapObjectLiteralExpression(expression) {
711
- const unwrapped = unwrapExpression$1(expression);
734
+ function unwrapObjectLiteralExpression$1(expression) {
735
+ const unwrapped = unwrapExpression$2(expression);
712
736
  return ts$1.isObjectLiteralExpression(unwrapped) ? unwrapped : null;
713
737
  }
714
- function unwrapExpression$1(expression) {
738
+ function unwrapExpression$2(expression) {
715
739
  let current = expression;
716
740
  for (;;) {
717
741
  if (ts$1.isParenthesizedExpression(current)) {
@@ -739,7 +763,7 @@ function toSourceRange$1(sourceFile, node) {
739
763
  endChar: end.character
740
764
  };
741
765
  }
742
- function getScriptKind$2(fileName) {
766
+ function getScriptKind$3(fileName) {
743
767
  if (fileName.endsWith(".tsx")) return ts$1.ScriptKind.TSX;
744
768
  if (fileName.endsWith(".jsx")) return ts$1.ScriptKind.JSX;
745
769
  if (fileName.endsWith(".js")) return ts$1.ScriptKind.JS;
@@ -820,12 +844,12 @@ function readHydratedStatesObject(uri, range, states, resolver) {
820
844
  return applySourceRangeReplacementsToSlice(document.text, range, replacements);
821
845
  }
822
846
  function applySourceRangeReplacementsToSlice(text, range, replacements) {
823
- const sliceStart = offsetAtRangePosition(text, range.startLine, range.startChar);
824
- const sliceEnd = offsetAtRangePosition(text, range.endLine, range.endChar);
847
+ const sliceStart = offsetAtRangePosition$2(text, range.startLine, range.startChar);
848
+ const sliceEnd = offsetAtRangePosition$2(text, range.endLine, range.endChar);
825
849
  let updated = text.slice(sliceStart, sliceEnd);
826
850
  for (const replacement of replacements.sort(compareSourceRangesDescending)) {
827
- const start = offsetAtRangePosition(text, replacement.range.startLine, replacement.range.startChar);
828
- const end = offsetAtRangePosition(text, replacement.range.endLine, replacement.range.endChar);
851
+ const start = offsetAtRangePosition$2(text, replacement.range.startLine, replacement.range.startChar);
852
+ const end = offsetAtRangePosition$2(text, replacement.range.endLine, replacement.range.endChar);
829
853
  if (start < sliceStart || end > sliceEnd) continue;
830
854
  const localStart = start - sliceStart;
831
855
  const localEnd = end - sliceStart;
@@ -835,7 +859,7 @@ function applySourceRangeReplacementsToSlice(text, range, replacements) {
835
859
  }
836
860
  function collectHydratedImportReplacements(text, document, hydratedSymbols) {
837
861
  if (hydratedSymbols.size === 0) return [];
838
- const sourceFile = ts$1.createSourceFile(document.fileName, text, ts$1.ScriptTarget.Latest, true, getScriptKind$1(document.fileName));
862
+ const sourceFile = ts$1.createSourceFile(document.fileName, text, ts$1.ScriptTarget.Latest, true, getScriptKind$2(document.fileName));
839
863
  const replacements = [];
840
864
  for (const statement of sourceFile.statements) {
841
865
  if (!ts$1.isImportDeclaration(statement) || !ts$1.isStringLiteral(statement.moduleSpecifier)) continue;
@@ -866,7 +890,7 @@ function toSourceRange(sourceFile, node, options = {}) {
866
890
  endChar: end.character
867
891
  };
868
892
  }
869
- function getScriptKind$1(fileName) {
893
+ function getScriptKind$2(fileName) {
870
894
  if (fileName.endsWith(".tsx")) return ts$1.ScriptKind.TSX;
871
895
  if (fileName.endsWith(".jsx")) return ts$1.ScriptKind.JSX;
872
896
  if (fileName.endsWith(".js")) return ts$1.ScriptKind.JS;
@@ -875,10 +899,10 @@ function getScriptKind$1(fileName) {
875
899
  function removeOverlappingRanges(replacement, index, replacements) {
876
900
  return !replacements.some((candidate, candidateIndex) => {
877
901
  if (candidateIndex === index) return false;
878
- return compareSourceRangesDescending(candidate, replacement) < 0 && rangesOverlap(candidate.range, replacement.range);
902
+ return compareSourceRangesDescending(candidate, replacement) < 0 && rangesOverlap$1(candidate.range, replacement.range);
879
903
  });
880
904
  }
881
- function rangesOverlap(left, right) {
905
+ function rangesOverlap$1(left, right) {
882
906
  const leftStart = rangePositionKey(left.startLine, left.startChar);
883
907
  const leftEnd = rangePositionKey(left.endLine, left.endChar);
884
908
  const rightStart = rangePositionKey(right.startLine, right.startChar);
@@ -891,22 +915,22 @@ function areSourceRangesEqual(left, right) {
891
915
  return left.startLine === right.startLine && left.startChar === right.startChar && left.endLine === right.endLine && left.endChar === right.endChar;
892
916
  }
893
917
  function canHydrateShorthandState(text, range) {
894
- const end = offsetAtRangePosition(text, range.endLine, range.endChar);
918
+ const end = offsetAtRangePosition$2(text, range.endLine, range.endChar);
895
919
  return text.slice(end).match(/\S/)?.[0] !== ":";
896
920
  }
897
921
  function readSourceRange(uri, range, resolver) {
898
922
  if (!resolver) return null;
899
923
  const document = resolver.read(uri);
900
924
  if (!document) return null;
901
- const start = offsetAtRangePosition(document.text, range.startLine, range.startChar);
902
- const end = offsetAtRangePosition(document.text, range.endLine, range.endChar);
925
+ const start = offsetAtRangePosition$2(document.text, range.startLine, range.startChar);
926
+ const end = offsetAtRangePosition$2(document.text, range.endLine, range.endChar);
903
927
  return document.text.slice(start, end);
904
928
  }
905
929
  function applySourceRangeReplacements(text, replacements) {
906
930
  let updated = text;
907
931
  for (const replacement of replacements) {
908
- const start = offsetAtRangePosition(updated, replacement.range.startLine, replacement.range.startChar);
909
- const end = offsetAtRangePosition(updated, replacement.range.endLine, replacement.range.endChar);
932
+ const start = offsetAtRangePosition$2(updated, replacement.range.startLine, replacement.range.startChar);
933
+ const end = offsetAtRangePosition$2(updated, replacement.range.endLine, replacement.range.endChar);
910
934
  updated = `${updated.slice(0, start)}${replacement.newText}${updated.slice(end)}`;
911
935
  }
912
936
  return updated;
@@ -915,7 +939,7 @@ function compareSourceRangesDescending(left, right) {
915
939
  if (left.range.startLine !== right.range.startLine) return right.range.startLine - left.range.startLine;
916
940
  return right.range.startChar - left.range.startChar;
917
941
  }
918
- function offsetAtRangePosition(text, line, character) {
942
+ function offsetAtRangePosition$2(text, line, character) {
919
943
  if (line <= 0) return character;
920
944
  let currentLine = 0;
921
945
  for (let index = 0; index < text.length; index += 1) {
@@ -927,227 +951,2786 @@ function offsetAtRangePosition(text, line, character) {
927
951
  }
928
952
 
929
953
  //#endregion
930
- //#region src/sync.ts
931
- const execFileAsync = promisify(execFile);
932
- const MAX_CAPTURED_LOCAL_MACHINES = 100;
933
- const INLINE_EXPRESSION_FIELD_SET = new Set(INLINE_EXPRESSION_DIRECTIVE_FIELDS);
934
- async function extractMachinesFromLocalSource(sourcePath, contents) {
954
+ //#region ../editor-sync/src/internal/editTargets.ts
955
+ function createSourceFile(document, sourceText) {
956
+ return ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$1(document.fileName));
957
+ }
958
+ function getMappedRootObjectLiteral(document, sourceFile, sourceLocations) {
959
+ if (!sourceLocations?.root || !isSourceLocationForDocument(sourceLocations.root.uri, document)) return null;
960
+ return findObjectLiteralByRange(sourceFile, sourceLocations.root.range);
961
+ }
962
+ function getMappedStateObjectLiteral(document, sourceFile, sourceLocations, path) {
963
+ if (!sourceLocations) return null;
964
+ const location = sourceLocations.states.find((item) => arePathsEqual$1(item.path, path));
965
+ if (!location || !isSourceLocationForDocument(location.uri, document)) return null;
966
+ return findObjectLiteralByRange(sourceFile, location.range);
967
+ }
968
+ async function getMappedStateReplacementTarget(rootDocument, rootSourceFile, sourceLocations, path, openTextDocument) {
969
+ if (!sourceLocations) return null;
970
+ const location = sourceLocations.states.find((item) => arePathsEqual$1(item.path, path));
971
+ if (!location) return null;
972
+ return getObjectTargetFromLocation(rootDocument, rootSourceFile, location.uri, location.range, openTextDocument);
973
+ }
974
+ function getStateMembershipParentTarget(document, sourceFile, machineConfigNode, sourceLocations, parentPath, getStateObjectLiteralByPath) {
975
+ if (parentPath.length === 0) return getMappedStatesObjectTarget(document, sourceFile, sourceLocations) ?? {
976
+ document,
977
+ sourceFile,
978
+ node: machineConfigNode,
979
+ nodeKind: "machineConfig"
980
+ };
981
+ const node = getMappedStateObjectLiteral(document, sourceFile, sourceLocations, parentPath) ?? getStateObjectLiteralByPath(machineConfigNode, parentPath);
982
+ return node ? {
983
+ document,
984
+ sourceFile,
985
+ node,
986
+ nodeKind: "machineConfig"
987
+ } : null;
988
+ }
989
+ async function getStateMembershipParentTargetForDocuments(document, sourceFile, machineConfigNode, sourceLocations, parentPath, openTextDocument, getStateObjectLiteralByPath) {
990
+ if (parentPath.length === 0) return await getMappedStatesObjectTargetForDocuments(document, sourceFile, sourceLocations, openTextDocument) ?? {
991
+ document,
992
+ sourceFile,
993
+ node: machineConfigNode,
994
+ nodeKind: "machineConfig"
995
+ };
996
+ const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, sourceLocations, parentPath, openTextDocument);
997
+ if (mappedTarget) return {
998
+ ...mappedTarget,
999
+ nodeKind: "machineConfig"
1000
+ };
1001
+ const node = getStateObjectLiteralByPath(machineConfigNode, parentPath);
1002
+ return node ? {
1003
+ document,
1004
+ sourceFile,
1005
+ node,
1006
+ nodeKind: "machineConfig"
1007
+ } : null;
1008
+ }
1009
+ async function openDocumentBySourceUri(uri, openTextDocument) {
1010
+ if (!openTextDocument) return null;
935
1011
  try {
936
- return { machines: extractMachineConfigsFromAst(sourcePath, parseSourceToMachine(contents, createTextDocument(sourcePath, contents), { resolver: createFileSourceDocumentResolver() })) };
937
- } catch (error) {
938
- return {
939
- machines: [],
940
- error: error instanceof Error ? error.message : String(error)
941
- };
1012
+ return await openTextDocument(uri);
1013
+ } catch {
1014
+ return null;
942
1015
  }
943
1016
  }
944
- function isInvalidLocalMachineDefinitionError(message) {
945
- return /No initial state specified for compound state node/.test(message) || /Try adding \{\s*initial:\s*['"`]/.test(message);
946
- }
947
- function formatLocalMachineExtractionIssue(message) {
948
- if (isInvalidLocalMachineDefinitionError(message)) return `Invalid local machine definition: ${message}`;
949
- return `Could not extract a local machine from this file: ${message}`;
1017
+ function isSourceLocationForDocument(uri, document) {
1018
+ return uri === (typeof document.uri === "string" ? document.uri : document.uri?.toString()) || uri === document.fileName;
950
1019
  }
951
- function extractMachineConfigsFromAst(fileName, sourceText) {
952
- const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(fileName));
953
- const bindings = collectLocalBindings(sourceFile);
954
- const machines = [];
1020
+ function findObjectLiteralByRange(sourceFile, range) {
1021
+ const start = offsetAtRangePosition$1(sourceFile.text, range.startLine, range.startChar);
1022
+ const end = offsetAtRangePosition$1(sourceFile.text, range.endLine, range.endChar);
1023
+ let found = null;
955
1024
  const visit = (node) => {
956
- if (machines.length >= MAX_CAPTURED_LOCAL_MACHINES) return;
957
- if (!ts.isCallExpression(node) || !isCreateMachineExpression(node.expression)) {
958
- ts.forEachChild(node, visit);
1025
+ if (found) return;
1026
+ if (ts$1.isObjectLiteralExpression(node) && node.getStart(sourceFile) === start && node.getEnd() >= end) {
1027
+ found = node;
959
1028
  return;
960
1029
  }
961
- const [firstArgument] = node.arguments;
962
- if (!firstArgument || !ts.isExpression(firstArgument)) return;
963
- const config = evaluateExpression(firstArgument, sourceFile, bindings, /* @__PURE__ */ new Set());
964
- if (!config || typeof config !== "object" || Array.isArray(config)) return;
965
- machines.push({
966
- config,
967
- _type: ts.isPropertyAccessExpression(unwrapExpression(node.expression)) ? "setup.createMachine" : "createMachine"
968
- });
1030
+ ts$1.forEachChild(node, visit);
969
1031
  };
970
- ts.forEachChild(sourceFile, visit);
971
- return machines;
1032
+ visit(sourceFile);
1033
+ return found;
972
1034
  }
973
- function collectLocalBindings(sourceFile) {
974
- const bindings = /* @__PURE__ */ new Map();
975
- for (const statement of sourceFile.statements) {
976
- if (ts.isVariableStatement(statement)) {
977
- for (const declaration of statement.declarationList.declarations) {
978
- if (!ts.isIdentifier(declaration.name) || !declaration.initializer) continue;
979
- bindings.set(declaration.name.text, {
980
- kind: "value",
981
- expression: declaration.initializer
982
- });
983
- }
984
- continue;
985
- }
986
- if (!ts.isEnumDeclaration(statement)) continue;
987
- let nextNumericValue = 0;
988
- for (const member of statement.members) {
989
- const memberName = getPropertyNameText(member.name);
990
- if (!memberName) continue;
991
- const symbol = `${statement.name.text}.${memberName}`;
992
- if (!member.initializer) {
993
- bindings.set(symbol, {
994
- kind: "enumMember",
995
- value: nextNumericValue
996
- });
997
- nextNumericValue += 1;
998
- continue;
999
- }
1000
- const value = evaluateExpression(member.initializer, sourceFile, bindings, /* @__PURE__ */ new Set());
1001
- if (typeof value === "string" || typeof value === "number") {
1002
- bindings.set(symbol, {
1003
- kind: "enumMember",
1004
- value
1005
- });
1006
- if (typeof value === "number") nextNumericValue = value + 1;
1007
- }
1035
+ function getMappedStatesObjectTarget(rootDocument, rootSourceFile, sourceLocations) {
1036
+ const location = sourceLocations?.statesObject;
1037
+ if (!location || !isSourceLocationForDocument(location.uri, rootDocument)) return null;
1038
+ const node = findObjectLiteralByRange(rootSourceFile, location.range);
1039
+ return node ? {
1040
+ document: rootDocument,
1041
+ sourceFile: rootSourceFile,
1042
+ node,
1043
+ nodeKind: "statesObject"
1044
+ } : null;
1045
+ }
1046
+ async function getMappedStatesObjectTargetForDocuments(rootDocument, rootSourceFile, sourceLocations, openTextDocument) {
1047
+ const location = sourceLocations?.statesObject;
1048
+ if (!location) return null;
1049
+ const target = await getObjectTargetFromLocation(rootDocument, rootSourceFile, location.uri, location.range, openTextDocument);
1050
+ return target ? {
1051
+ ...target,
1052
+ nodeKind: "statesObject"
1053
+ } : null;
1054
+ }
1055
+ async function getObjectTargetFromLocation(rootDocument, rootSourceFile, uri, range, openTextDocument) {
1056
+ const targetDocument = isSourceLocationForDocument(uri, rootDocument) ? rootDocument : await openDocumentBySourceUri(uri, openTextDocument);
1057
+ if (!targetDocument) return null;
1058
+ const targetSourceFile = isSourceLocationForDocument(uri, rootDocument) ? rootSourceFile : createSourceFile(targetDocument, targetDocument.getText());
1059
+ const node = findObjectLiteralByRange(targetSourceFile, range);
1060
+ if (!node) return null;
1061
+ return {
1062
+ document: targetDocument,
1063
+ sourceFile: targetSourceFile,
1064
+ node
1065
+ };
1066
+ }
1067
+ function getScriptKind$1(fileName) {
1068
+ if (fileName.endsWith(".tsx")) return ts$1.ScriptKind.TSX;
1069
+ if (fileName.endsWith(".jsx")) return ts$1.ScriptKind.JSX;
1070
+ if (fileName.endsWith(".js")) return ts$1.ScriptKind.JS;
1071
+ return ts$1.ScriptKind.TS;
1072
+ }
1073
+ function arePathsEqual$1(left, right) {
1074
+ return left.length === right.length && left.every((segment, index) => segment === right[index]);
1075
+ }
1076
+ function offsetAtRangePosition$1(sourceText, line, character) {
1077
+ let currentLine = 0;
1078
+ let lineStart = 0;
1079
+ for (let index = 0; index < sourceText.length; index += 1) {
1080
+ if (currentLine === line) return Math.min(lineStart + character, sourceText.length);
1081
+ if (sourceText.charCodeAt(index) === 10) {
1082
+ currentLine += 1;
1083
+ lineStart = index + 1;
1008
1084
  }
1009
1085
  }
1010
- return bindings;
1086
+ return Math.min(lineStart + character, sourceText.length);
1011
1087
  }
1012
- function evaluateExpression(expression, sourceFile, bindings, seenBindings) {
1013
- const unwrapped = unwrapExpression(expression);
1014
- if (ts.isStringLiteral(unwrapped) || ts.isNoSubstitutionTemplateLiteral(unwrapped)) return unwrapped.text;
1015
- if (ts.isNumericLiteral(unwrapped)) return Number(unwrapped.text);
1016
- if (unwrapped.kind === ts.SyntaxKind.TrueKeyword) return true;
1017
- if (unwrapped.kind === ts.SyntaxKind.FalseKeyword) return false;
1018
- if (unwrapped.kind === ts.SyntaxKind.NullKeyword) return null;
1019
- if (ts.isIdentifier(unwrapped)) {
1020
- if (unwrapped.text === "undefined") return;
1021
- const binding = bindings.get(unwrapped.text);
1022
- if (!binding || binding.kind !== "value" || seenBindings.has(unwrapped.text)) return unwrapped.getText(sourceFile);
1023
- const nextSeen = new Set(seenBindings);
1024
- nextSeen.add(unwrapped.text);
1025
- return evaluateExpression(binding.expression, sourceFile, bindings, nextSeen);
1026
- }
1027
- if (ts.isPropertyAccessExpression(unwrapped) && ts.isIdentifier(unwrapped.expression)) {
1028
- const binding = bindings.get(`${unwrapped.expression.text}.${unwrapped.name.text}`);
1029
- if (binding?.kind === "enumMember") return binding.value;
1030
- return unwrapped.getText(sourceFile);
1088
+
1089
+ //#endregion
1090
+ //#region ../editor-sync/src/internal/graphToCode.ts
1091
+ function applyMachineToSource(machineConfig, document, options = {}) {
1092
+ if (!isMachineConfig(machineConfig)) return [];
1093
+ const sourceFile = createSourceFile(document, document.getText());
1094
+ const machineConfigNode = findMachineConfigObjectLiteral(sourceFile, options.machineIndex);
1095
+ if (!machineConfigNode) return [];
1096
+ const parsedPatches = parseGraphPatches(options.patches);
1097
+ const prevGraph = parseGraph(options.prevGraph);
1098
+ const nextGraph = parseGraph(options.nextGraph);
1099
+ const rootNode = getMappedRootObjectLiteral(document, sourceFile, options.sourceLocations) ?? machineConfigNode;
1100
+ if (!parsedPatches || !prevGraph || !nextGraph || parsedPatches.length === 0) {
1101
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1102
+ return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1031
1103
  }
1032
- if (ts.isArrayLiteralExpression(unwrapped)) return unwrapped.elements.map((element) => ts.isSpreadElement(element) ? evaluateExpression(element.expression, sourceFile, bindings, seenBindings) : evaluateExpression(element, sourceFile, bindings, seenBindings));
1033
- if (ts.isObjectLiteralExpression(unwrapped)) {
1034
- const result = {};
1035
- for (const property of unwrapped.properties) {
1036
- if (ts.isSpreadAssignment(property)) {
1037
- const spreadValue = evaluateExpression(property.expression, sourceFile, bindings, seenBindings);
1038
- if (spreadValue && typeof spreadValue === "object" && !Array.isArray(spreadValue)) Object.assign(result, spreadValue);
1039
- continue;
1040
- }
1041
- if (ts.isShorthandPropertyAssignment(property)) {
1042
- result[property.name.text] = evaluateExpression(property.name, sourceFile, bindings, seenBindings);
1043
- continue;
1044
- }
1045
- if (!ts.isPropertyAssignment(property)) continue;
1046
- const key = resolvePropertyNameValue(property.name, sourceFile, bindings, seenBindings);
1047
- if (key == null) continue;
1048
- const fieldName = String(key);
1049
- if (shouldPreserveInlineExpression(fieldName, property.initializer, sourceFile, bindings, seenBindings)) {
1050
- result[fieldName] = createInlineExpressionDirective(property.initializer.getText(sourceFile));
1051
- continue;
1104
+ if (hasNestedStateRenameBatch(parsedPatches, prevGraph, nextGraph)) return [];
1105
+ const semanticReplacements = tryCreateSemanticReplacements(document, sourceFile, machineConfigNode, parsedPatches, prevGraph, nextGraph);
1106
+ if (semanticReplacements) return semanticReplacements.sort(compareReplacementRangesDescending);
1107
+ let patchesForSplit = parsedPatches;
1108
+ const implementationSplit = tryCreateImplementationPatchSplit(document, sourceFile, patchesForSplit, nextGraph, options.machineIndex);
1109
+ if (implementationSplit) {
1110
+ const implementationRemainingPatches = dropCoveredSchemaPatches(implementationSplit.remainingPatches, implementationSplit.replacements.length > 0);
1111
+ if (implementationRemainingPatches.length === 0) return implementationSplit.replacements.sort(compareReplacementRangesDescending);
1112
+ const remainingPlan = deriveReplacementPlan(implementationRemainingPatches, prevGraph, nextGraph);
1113
+ if (remainingPlan.type === "root") {
1114
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1115
+ return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1116
+ }
1117
+ const replacements = [...implementationSplit.replacements];
1118
+ for (const path of remainingPlan.paths) {
1119
+ const currentNode = getMappedStateObjectLiteral(document, sourceFile, options.sourceLocations, path) ?? getStateObjectLiteralByPath(machineConfigNode, path);
1120
+ const nextValue = getStateConfigByPath(machineConfig, path);
1121
+ if (!currentNode || !isMachineConfig(nextValue)) {
1122
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1123
+ return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1052
1124
  }
1053
- result[fieldName] = evaluateExpression(property.initializer, sourceFile, bindings, seenBindings);
1125
+ replacements.push(createReplacement(document, sourceFile, currentNode, nextValue));
1054
1126
  }
1055
- return result;
1127
+ return replacements.sort(compareReplacementRangesDescending);
1056
1128
  }
1057
- if (ts.isPrefixUnaryExpression(unwrapped)) {
1058
- const operand = evaluateExpression(unwrapped.operand, sourceFile, bindings, seenBindings);
1059
- if (typeof operand !== "number") return unwrapped.getText(sourceFile);
1060
- switch (unwrapped.operator) {
1061
- case ts.SyntaxKind.MinusToken: return -operand;
1062
- case ts.SyntaxKind.PlusToken: return operand;
1063
- default: return unwrapped.getText(sourceFile);
1129
+ patchesForSplit = dropCoveredSchemaPatches(patchesForSplit, false);
1130
+ const stateMembershipSplit = tryCreateStateMembershipPatchSplit(document, sourceFile, rootNode, machineConfig, patchesForSplit, prevGraph, nextGraph, options.sourceLocations);
1131
+ if (stateMembershipSplit) {
1132
+ const stateMembershipRemainingPatches = dropCoveredSchemaPatches(stateMembershipSplit.remainingPatches, stateMembershipSplit.replacements.length > 0);
1133
+ if (stateMembershipRemainingPatches.length === 0) return stateMembershipSplit.replacements;
1134
+ const remainingPlan = deriveReplacementPlan(stateMembershipRemainingPatches, prevGraph, nextGraph);
1135
+ if (remainingPlan.type === "root") {
1136
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1137
+ return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1064
1138
  }
1065
- }
1066
- if (ts.isTemplateExpression(unwrapped)) {
1067
- let value = unwrapped.head.text;
1068
- for (const span of unwrapped.templateSpans) {
1069
- const expressionValue = evaluateExpression(span.expression, sourceFile, bindings, seenBindings);
1070
- value += String(expressionValue ?? "");
1071
- value += span.literal.text;
1139
+ const replacements = [...stateMembershipSplit.replacements];
1140
+ for (const path of remainingPlan.paths) {
1141
+ const currentNode = getMappedStateObjectLiteral(document, sourceFile, options.sourceLocations, path) ?? getStateObjectLiteralByPath(machineConfigNode, path);
1142
+ const nextValue = getStateConfigByPath(machineConfig, path);
1143
+ if (!currentNode || !isMachineConfig(nextValue)) {
1144
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1145
+ return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1146
+ }
1147
+ replacements.push(createReplacement(document, sourceFile, currentNode, nextValue));
1072
1148
  }
1073
- return value;
1149
+ return replacements.sort(compareReplacementRangesDescending);
1074
1150
  }
1075
- return unwrapped.getText(sourceFile);
1076
- }
1077
- function shouldPreserveInlineExpression(fieldName, expression, sourceFile, bindings, seenBindings) {
1078
- if (!INLINE_EXPRESSION_FIELD_SET.has(fieldName)) return false;
1079
- const unwrapped = unwrapExpression(expression);
1080
- if (ts.isIdentifier(unwrapped)) {
1081
- const binding = bindings.get(unwrapped.text);
1082
- if (!binding || binding.kind !== "value" || seenBindings.has(unwrapped.text)) return true;
1083
- const nextSeen = new Set(seenBindings);
1084
- nextSeen.add(unwrapped.text);
1085
- return shouldPreserveInlineExpression(fieldName, binding.expression, sourceFile, bindings, nextSeen);
1151
+ const plan = deriveReplacementPlan(patchesForSplit, prevGraph, nextGraph);
1152
+ if (plan.type === "root") {
1153
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1154
+ return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1086
1155
  }
1087
- if (ts.isStringLiteral(unwrapped) || ts.isNoSubstitutionTemplateLiteral(unwrapped) || ts.isNumericLiteral(unwrapped) || unwrapped.kind === ts.SyntaxKind.TrueKeyword || unwrapped.kind === ts.SyntaxKind.FalseKeyword || unwrapped.kind === ts.SyntaxKind.NullKeyword || ts.isObjectLiteralExpression(unwrapped) || ts.isArrayLiteralExpression(unwrapped)) return false;
1088
- return unwrapped.getText(sourceFile).trim().length > 0;
1156
+ const replacements = [];
1157
+ for (const path of plan.paths) {
1158
+ const currentNode = getMappedStateObjectLiteral(document, sourceFile, options.sourceLocations, path) ?? getStateObjectLiteralByPath(machineConfigNode, path);
1159
+ const nextValue = getStateConfigByPath(machineConfig, path);
1160
+ if (!currentNode || !isMachineConfig(nextValue)) {
1161
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1162
+ return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1163
+ }
1164
+ replacements.push(createReplacement(document, sourceFile, currentNode, nextValue));
1165
+ }
1166
+ return replacements.sort(compareReplacementRangesDescending);
1089
1167
  }
1090
- function createInlineExpressionDirective(expr) {
1091
- return {
1092
- "@type": "code",
1093
- lang: "ts",
1094
- expr
1168
+ async function applyMachineToSourceDocuments(machineConfig, document, options = {}) {
1169
+ if (!isMachineConfig(machineConfig)) return [];
1170
+ const sourceFile = createSourceFile(document, document.getText());
1171
+ const machineConfigNode = getMappedRootObjectLiteral(document, sourceFile, options.sourceLocations) ?? findMachineConfigObjectLiteral(sourceFile, options.machineIndex);
1172
+ if (!machineConfigNode) return [];
1173
+ const parsedPatches = parseGraphPatches(options.patches);
1174
+ const prevGraph = parseGraph(options.prevGraph);
1175
+ const nextGraph = parseGraph(options.nextGraph);
1176
+ const finalize = (replacements) => {
1177
+ return normalizeOverlappingReplacements(addCodeImportReplacements(document, sourceFile, machineConfig, replacements)).sort(compareReplacementRangesDescending);
1095
1178
  };
1179
+ if (!parsedPatches || !prevGraph || !nextGraph || parsedPatches.length === 0) {
1180
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1181
+ return finalize([createReplacement(document, sourceFile, machineConfigNode, machineConfig)]);
1182
+ }
1183
+ if (hasNestedStateRenameBatch(parsedPatches, prevGraph, nextGraph)) return [];
1184
+ const semanticSplit = await tryCreateSemanticPatchSplitForDocuments(document, sourceFile, machineConfigNode, parsedPatches, prevGraph, nextGraph, options.sourceLocations, options.openTextDocument);
1185
+ if (semanticSplit && semanticSplit.remainingPatches.length === 0) return finalize(semanticSplit.replacements);
1186
+ const activePatches = dropCoveredSchemaPatches(semanticSplit?.remainingPatches ?? parsedPatches, (semanticSplit?.replacements.length ?? 0) > 0);
1187
+ const activeSourceLocations = semanticSplit?.sourceLocations ?? options.sourceLocations;
1188
+ let semanticReplacements = semanticSplit?.replacements ?? [];
1189
+ if (activePatches.length === 0) return finalize(semanticReplacements);
1190
+ const transitionSplit = await tryCreateTransitionPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, activePatches, prevGraph, nextGraph, activeSourceLocations, options.openTextDocument);
1191
+ if (transitionSplit && transitionSplit.remainingPatches.length === 0) return finalize([...semanticReplacements, ...transitionSplit.replacements]);
1192
+ if (transitionSplit) semanticReplacements = [...semanticReplacements, ...transitionSplit.replacements];
1193
+ const implementationSplit = tryCreateImplementationPatchSplit(document, sourceFile, transitionSplit?.remainingPatches ?? activePatches, nextGraph, options.machineIndex);
1194
+ if (implementationSplit && implementationSplit.remainingPatches.length === 0) return finalize([...semanticReplacements, ...implementationSplit.replacements]);
1195
+ if (implementationSplit) semanticReplacements = [...semanticReplacements, ...implementationSplit.replacements];
1196
+ const patchesAfterImplementationSplit = dropCoveredSchemaPatches(implementationSplit?.remainingPatches ?? activePatches, semanticReplacements.length > 0);
1197
+ if (patchesAfterImplementationSplit.length === 0) return finalize(semanticReplacements);
1198
+ const stateMembershipSplit = await tryCreateStateMembershipPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, patchesAfterImplementationSplit, prevGraph, nextGraph, activeSourceLocations, options.openTextDocument);
1199
+ if (stateMembershipSplit) {
1200
+ const stateMembershipRemainingPatches = dropCoveredSchemaPatches(stateMembershipSplit.remainingPatches, semanticReplacements.length + stateMembershipSplit.replacements.length > 0);
1201
+ if (stateMembershipRemainingPatches.length === 0) return finalize([...semanticReplacements, ...stateMembershipSplit.replacements]);
1202
+ const remainingPlan = deriveReplacementPlan(stateMembershipRemainingPatches, prevGraph, nextGraph);
1203
+ if (remainingPlan.type === "root") {
1204
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1205
+ return finalize([createReplacement(document, sourceFile, machineConfigNode, machineConfig)]);
1206
+ }
1207
+ const replacements = [...semanticReplacements, ...stateMembershipSplit.replacements];
1208
+ for (const path of remainingPlan.paths) {
1209
+ const nextValue = getStateConfigByPath(machineConfig, path);
1210
+ if (!isMachineConfig(nextValue)) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
1211
+ const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, activeSourceLocations, path, options.openTextDocument);
1212
+ const currentNode = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, path);
1213
+ const targetDocument = mappedTarget?.document ?? document;
1214
+ const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
1215
+ if (!currentNode) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
1216
+ replacements.push(createReplacement(targetDocument, targetSourceFile, currentNode, nextValue));
1217
+ }
1218
+ return finalize(replacements);
1219
+ }
1220
+ const plan = deriveReplacementPlan(patchesAfterImplementationSplit, prevGraph, nextGraph);
1221
+ if (plan.type === "root") {
1222
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1223
+ return finalize([createReplacement(document, sourceFile, machineConfigNode, machineConfig)]);
1224
+ }
1225
+ const replacements = [...semanticReplacements];
1226
+ for (const path of plan.paths) {
1227
+ const nextValue = getStateConfigByPath(machineConfig, path);
1228
+ if (!isMachineConfig(nextValue)) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
1229
+ const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, activeSourceLocations, path, options.openTextDocument);
1230
+ const currentNode = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, path);
1231
+ const targetDocument = mappedTarget?.document ?? document;
1232
+ const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
1233
+ if (!currentNode) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
1234
+ replacements.push(createReplacement(targetDocument, targetSourceFile, currentNode, nextValue));
1235
+ }
1236
+ return finalize(replacements);
1096
1237
  }
1097
- function resolvePropertyNameValue(name, sourceFile, bindings, seenBindings) {
1098
- if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
1099
- if (!ts.isComputedPropertyName(name)) return null;
1100
- const value = evaluateExpression(name.expression, sourceFile, bindings, seenBindings);
1101
- if (typeof value === "string" || typeof value === "number") return value;
1102
- return name.getText(sourceFile);
1103
- }
1104
- function isCreateMachineExpression(expression) {
1105
- const unwrapped = unwrapExpression(expression);
1106
- return ts.isIdentifier(unwrapped) && unwrapped.text === "createMachine" || ts.isPropertyAccessExpression(unwrapped) && unwrapped.name.text === "createMachine";
1238
+ function fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, sourceLocations) {
1239
+ if (wouldDeModularizeRootReplacement(sourceLocations)) return [];
1240
+ return addCodeImportReplacements(document, sourceFile, machineConfig, [createReplacement(document, sourceFile, machineConfigNode, machineConfig)]).sort(compareReplacementRangesDescending);
1107
1241
  }
1108
- function unwrapExpression(expression) {
1109
- let current = expression;
1110
- for (;;) {
1111
- if (ts.isParenthesizedExpression(current)) {
1112
- current = current.expression;
1242
+ async function tryCreateTransitionPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) {
1243
+ const replacements = [];
1244
+ const remainingPatches = [];
1245
+ const handledTransitionKeys = /* @__PURE__ */ new Set();
1246
+ const handledStatePropertyKeys = /* @__PURE__ */ new Set();
1247
+ const deletedStatePaths = patches.flatMap((patch) => {
1248
+ if (patch.op !== "deleteState") return [];
1249
+ const path = resolveStatePath(prevGraph, patch.stateId);
1250
+ return path ? [path] : [];
1251
+ });
1252
+ for (const patch of patches) {
1253
+ const transitionTarget = getTransitionPatchTarget(patch, prevGraph, nextGraph);
1254
+ if (transitionTarget) {
1255
+ if (deletedStatePaths.some((deletedPath) => isPathEqualOrDescendant(transitionTarget.sourcePath, deletedPath))) continue;
1256
+ const transitionKey = `${transitionTarget.sourcePath.join(".")}:${transitionTarget.previousEventType}:${transitionTarget.index ?? "single"}`;
1257
+ if (handledTransitionKeys.has(transitionKey)) continue;
1258
+ const patchReplacements = patch.op === "deleteTransition" ? await createDeleteTransitionReplacementsForDocuments(document, sourceFile, machineConfigNode, transitionTarget, sourceLocations, openTextDocument) : await createTransitionReplacementForDocuments(document, sourceFile, machineConfigNode, machineConfig, transitionTarget, sourceLocations, openTextDocument);
1259
+ if (!patchReplacements) {
1260
+ remainingPatches.push(patch);
1261
+ continue;
1262
+ }
1263
+ handledTransitionKeys.add(transitionKey);
1264
+ replacements.push(...patchReplacements);
1113
1265
  continue;
1114
1266
  }
1115
- if (ts.isAsExpression(current) || ts.isSatisfiesExpression(current)) {
1116
- current = current.expression;
1267
+ const [statePropertyTarget] = getStatePropertyPatchTargets(patch, prevGraph, nextGraph);
1268
+ if (!statePropertyTarget) {
1269
+ remainingPatches.push(patch);
1117
1270
  continue;
1118
1271
  }
1119
- if (ts.isTypeAssertionExpression(current) || ts.isNonNullExpression(current)) {
1120
- current = current.expression;
1272
+ const statePathKey = statePropertyTarget.path.join(".");
1273
+ const statePropertyKey = `${statePathKey}:${statePropertyTarget.propertyName}`;
1274
+ if (handledStatePropertyKeys.has(statePropertyKey)) continue;
1275
+ const propertyNames = /* @__PURE__ */ new Set();
1276
+ for (const candidate of patches) {
1277
+ const candidateTargets = getStatePropertyPatchTargets(candidate, prevGraph, nextGraph);
1278
+ for (const candidateTarget of candidateTargets) {
1279
+ if (candidateTarget.path.join(".") !== statePathKey) continue;
1280
+ const candidateKey = `${statePathKey}:${candidateTarget.propertyName}`;
1281
+ if (!handledStatePropertyKeys.has(candidateKey)) propertyNames.add(candidateTarget.propertyName);
1282
+ }
1283
+ }
1284
+ const patchReplacements = await createStatePropertiesReplacementForDocuments(document, sourceFile, machineConfigNode, machineConfig, statePropertyTarget.path, [...propertyNames], sourceLocations, openTextDocument);
1285
+ if (!patchReplacements) {
1286
+ remainingPatches.push(patch);
1121
1287
  continue;
1122
1288
  }
1123
- return current;
1289
+ replacements.push(...patchReplacements);
1290
+ for (const propertyName of propertyNames) handledStatePropertyKeys.add(`${statePathKey}:${propertyName}`);
1124
1291
  }
1292
+ return replacements.length > 0 ? {
1293
+ replacements: replacements.sort(compareReplacementRangesDescending),
1294
+ remainingPatches
1295
+ } : null;
1125
1296
  }
1126
- function getPropertyNameText(name) {
1127
- if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
1128
- return null;
1297
+ async function createDeleteTransitionReplacementsForDocuments(document, sourceFile, machineConfigNode, transitionTarget, sourceLocations, openTextDocument) {
1298
+ const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, sourceLocations, transitionTarget.sourcePath, openTextDocument);
1299
+ const targetDocument = mappedTarget?.document ?? document;
1300
+ const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
1301
+ const stateObject = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, transitionTarget.sourcePath);
1302
+ if (!stateObject) return null;
1303
+ const transitionSource = getTransitionSourceExpression(stateObject, transitionTarget.previousEventType, transitionTarget.index);
1304
+ if (!transitionSource) return null;
1305
+ if (transitionSource.array && transitionSource.element) return [createArrayElementDeletion(targetDocument, targetSourceFile, transitionSource.array, transitionSource.element)];
1306
+ return [createObjectLiteralPropertyDeletion(targetDocument, targetSourceFile, transitionSource.onObject, transitionSource.eventProperty)];
1129
1307
  }
1130
- function getScriptKind(fileName) {
1131
- if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
1132
- if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
1133
- if (fileName.endsWith(".js")) return ts.ScriptKind.JS;
1134
- return ts.ScriptKind.TS;
1308
+ async function createTransitionReplacementForDocuments(document, sourceFile, machineConfigNode, machineConfig, transitionTarget, sourceLocations, openTextDocument) {
1309
+ const nextTransitionValue = getTransitionConfigValue(machineConfig, transitionTarget.sourcePath, transitionTarget.eventType, transitionTarget.index);
1310
+ if (nextTransitionValue === void 0) return null;
1311
+ const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, sourceLocations, transitionTarget.sourcePath, openTextDocument);
1312
+ const targetDocument = mappedTarget?.document ?? document;
1313
+ const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
1314
+ const stateObject = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, transitionTarget.sourcePath);
1315
+ if (!stateObject) return null;
1316
+ const transitionSource = getTransitionSourceExpression(stateObject, transitionTarget.previousEventType, transitionTarget.index);
1317
+ if (transitionSource?.array && transitionSource.element) return [createExpressionReplacement(targetDocument, targetSourceFile, transitionSource.element, nextTransitionValue)];
1318
+ if (transitionSource && transitionTarget.previousEventType === transitionTarget.eventType) return [createPropertyValueReplacement(targetDocument, targetSourceFile, transitionSource.eventProperty, nextTransitionValue)];
1319
+ if (transitionSource) return [createPropertyAssignmentReplacement(targetDocument, targetSourceFile, transitionSource.eventProperty, transitionTarget.eventType, nextTransitionValue)];
1320
+ const onObject = getObjectLiteralProperty(stateObject, "on");
1321
+ if (onObject) return [createObjectLiteralPropertyInsertion(targetDocument, targetSourceFile, onObject, transitionTarget.eventType, nextTransitionValue)];
1322
+ return [createObjectLiteralPropertyInsertion(targetDocument, targetSourceFile, stateObject, "on", { [transitionTarget.eventType]: nextTransitionValue })];
1135
1323
  }
1136
- function isUrl(value) {
1137
- try {
1138
- const url = new URL(value);
1139
- return url.protocol === "http:" || url.protocol === "https:";
1140
- } catch {
1141
- return false;
1324
+ async function createStatePropertiesReplacementForDocuments(document, sourceFile, machineConfigNode, machineConfig, path, propertyNames, sourceLocations, openTextDocument) {
1325
+ const nextStateConfig = getStateConfigByPath(machineConfig, path);
1326
+ if (!isMachineConfig(nextStateConfig)) return null;
1327
+ const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, sourceLocations, path, openTextDocument);
1328
+ const targetDocument = mappedTarget?.document ?? document;
1329
+ const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
1330
+ const stateObject = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, path);
1331
+ if (!stateObject) return null;
1332
+ const replacements = [];
1333
+ const insertionEntries = [];
1334
+ for (const propertyName of propertyNames) {
1335
+ const nextValue = nextStateConfig[propertyName];
1336
+ const property = findObjectLiteralProperty(stateObject, propertyName);
1337
+ if (nextValue === void 0) {
1338
+ if (!property) continue;
1339
+ replacements.push(createObjectLiteralPropertyDeletion(targetDocument, targetSourceFile, stateObject, property));
1340
+ continue;
1341
+ }
1342
+ if (property) {
1343
+ replacements.push(createPropertyValueReplacement(targetDocument, targetSourceFile, property, nextValue));
1344
+ continue;
1345
+ }
1346
+ insertionEntries.push({
1347
+ key: propertyName,
1348
+ config: nextValue
1349
+ });
1142
1350
  }
1351
+ if (insertionEntries.length > 0) replacements.push(createObjectLiteralPropertiesInsertion(targetDocument, targetSourceFile, stateObject, insertionEntries));
1352
+ return replacements.length > 0 ? replacements.sort(compareReplacementRangesDescending) : [];
1143
1353
  }
1144
- async function fileExists(filePath) {
1145
- try {
1146
- await fs.access(filePath);
1147
- return true;
1148
- } catch {
1149
- return false;
1150
- }
1354
+ function getTransitionPatchTarget(patch, prevGraph, nextGraph) {
1355
+ const patchRecord = patch;
1356
+ if (patch.op === "createTransition") {
1357
+ const edge = patch.id ? nextGraph.edges.find((item) => item.id === patch.id) : nextGraph.edges.find((item) => item.sourceId === patch.sourceId);
1358
+ const sourcePath = resolveStatePath(nextGraph, patch.sourceId);
1359
+ const eventType = edge?.data?.eventType ?? edge?.label ?? patchRecord.eventType;
1360
+ if (!sourcePath || !eventType) return null;
1361
+ return {
1362
+ sourcePath,
1363
+ eventType,
1364
+ previousEventType: eventType,
1365
+ transitionId: edge?.id ?? patch.id,
1366
+ index: getTransitionIndexFromId(edge?.id ?? patch.id ?? "")
1367
+ };
1368
+ }
1369
+ const edgeId = patch.op === "updateTransition" || patch.op === "deleteTransition" ? patch.transitionId : patch.op === "setGuard" || patch.op === "deleteGuard" ? patch.edgeId : patch.op === "createAction" || patch.op === "updateAction" || patch.op === "deleteAction" ? "edgeId" in patch.location ? patch.location.edgeId : null : null;
1370
+ if (!edgeId) return null;
1371
+ const nextEdge = nextGraph.edges.find((item) => item.id === edgeId);
1372
+ const prevEdge = prevGraph.edges.find((item) => item.id === edgeId);
1373
+ const sourcePath = resolveEdgeSourcePath(nextGraph, edgeId) ?? resolveEdgeSourcePath(prevGraph, edgeId);
1374
+ const eventType = nextEdge?.data?.eventType ?? nextEdge?.label ?? patchRecord.eventType ?? prevEdge?.data?.eventType ?? prevEdge?.label;
1375
+ const previousEventType = prevEdge?.data?.eventType ?? prevEdge?.label ?? eventType;
1376
+ if (!sourcePath || !eventType || !previousEventType) return null;
1377
+ return {
1378
+ sourcePath,
1379
+ eventType,
1380
+ previousEventType,
1381
+ transitionId: edgeId,
1382
+ index: getTransitionIndexFromId(edgeId)
1383
+ };
1384
+ }
1385
+ function getStatePropertyPatchTargets(patch, prevGraph, nextGraph) {
1386
+ if (patch.op === "updateSchemas") return [{
1387
+ path: [],
1388
+ propertyName: "schemas"
1389
+ }];
1390
+ if (patch.op === "updateState") {
1391
+ const propertyNames = getStatePropertyNamesFromUpdatePatch(patch);
1392
+ if (propertyNames.length === 0) return [];
1393
+ const path = resolveStatePath(nextGraph, patch.stateId) ?? resolveStatePath(prevGraph, patch.stateId);
1394
+ return path ? propertyNames.map((propertyName) => ({
1395
+ path,
1396
+ propertyName
1397
+ })) : [];
1398
+ }
1399
+ if (patch.op === "createAction" || patch.op === "updateAction" || patch.op === "deleteAction") {
1400
+ if (!("nodeId" in patch.location)) return [];
1401
+ const path = resolveStatePath(nextGraph, patch.location.nodeId) ?? resolveStatePath(prevGraph, patch.location.nodeId);
1402
+ return path ? [{
1403
+ path,
1404
+ propertyName: patch.location.group
1405
+ }] : [];
1406
+ }
1407
+ if (patch.op === "createInvoke" || patch.op === "updateInvoke" || patch.op === "deleteInvoke") {
1408
+ const path = resolveStatePath(nextGraph, patch.nodeId) ?? resolveStatePath(prevGraph, patch.nodeId);
1409
+ return path ? [{
1410
+ path,
1411
+ propertyName: "invoke"
1412
+ }] : [];
1413
+ }
1414
+ if (patch.op === "createTag" || patch.op === "deleteTag") {
1415
+ const path = resolveStatePath(nextGraph, patch.nodeId) ?? resolveStatePath(prevGraph, patch.nodeId);
1416
+ return path ? [{
1417
+ path,
1418
+ propertyName: "tags"
1419
+ }] : [];
1420
+ }
1421
+ return [];
1422
+ }
1423
+ function getStatePropertyNamesFromUpdatePatch(patch) {
1424
+ if (patch.op !== "updateState") return [];
1425
+ const patchRecord = patch;
1426
+ const propertyNames = [];
1427
+ if (patchRecord.stateDescription !== void 0) propertyNames.push("description");
1428
+ if (patchRecord.meta !== void 0) propertyNames.push("meta");
1429
+ if (patchRecord.type !== void 0) propertyNames.push("type");
1430
+ if (patchRecord.history !== void 0) propertyNames.push("history");
1431
+ if (patchRecord.initialId !== void 0 || patchRecord.initialInput !== void 0) propertyNames.push("initial");
1432
+ if (patchRecord.timeout !== void 0) propertyNames.push("timeout");
1433
+ if (patchRecord.route !== void 0) propertyNames.push("route");
1434
+ return propertyNames;
1435
+ }
1436
+ function getTransitionConfigValue(machineConfig, sourcePath, eventType, index) {
1437
+ const sourceConfig = getStateConfigByPath(machineConfig, sourcePath);
1438
+ const eventConfig = (isMachineConfig(sourceConfig?.on) ? sourceConfig.on : null)?.[eventType];
1439
+ if (Array.isArray(eventConfig) && index !== null) return eventConfig[index];
1440
+ return eventConfig;
1441
+ }
1442
+ function getTransitionSourceExpression(stateObject, eventType, index) {
1443
+ const onObject = getObjectLiteralProperty(stateObject, "on");
1444
+ if (!onObject) return null;
1445
+ const eventProperty = findObjectLiteralProperty(onObject, eventType);
1446
+ if (!eventProperty) return null;
1447
+ if (!ts$1.isPropertyAssignment(eventProperty)) return {
1448
+ onObject,
1449
+ eventProperty
1450
+ };
1451
+ const initializer = unwrapExpression$1(eventProperty.initializer);
1452
+ if (ts$1.isArrayLiteralExpression(initializer) && index !== null) {
1453
+ const element = initializer.elements[index];
1454
+ if (element && ts$1.isExpression(element)) return {
1455
+ onObject,
1456
+ eventProperty,
1457
+ array: initializer,
1458
+ element
1459
+ };
1460
+ }
1461
+ return {
1462
+ onObject,
1463
+ eventProperty
1464
+ };
1465
+ }
1466
+ function getTransitionIndexFromId(id) {
1467
+ const match = id.match(/\[(\d+)\](?:$|#)/);
1468
+ return match ? Number(match[1]) : null;
1469
+ }
1470
+ function createArrayElementDeletion(document, sourceFile, arrayLiteral, element) {
1471
+ const range = getArrayElementDeletionRange(sourceFile, arrayLiteral, element);
1472
+ return createOffsetReplacement(document, range.start, range.end, "");
1473
+ }
1474
+ function createExpressionReplacement(document, sourceFile, expression, nextValue) {
1475
+ const formatting = getFormattingContextForExpression(document, sourceFile, expression);
1476
+ return createOffsetReplacement(document, expression.getStart(sourceFile), expression.getEnd(), printExpression(valueToExpression(nextValue, unwrapExpression$1(expression)), sourceFile, formatting));
1477
+ }
1478
+ function createPropertyValueReplacement(document, sourceFile, property, nextValue) {
1479
+ if (!ts$1.isPropertyAssignment(property)) return createPropertyAssignmentReplacement(document, sourceFile, property, getStatePropertyKeyText(property) ?? "value", nextValue);
1480
+ return createExpressionReplacement(document, sourceFile, property.initializer, nextValue);
1481
+ }
1482
+ function createPropertyAssignmentReplacement(document, sourceFile, property, key, nextValue) {
1483
+ const text = printObjectLiteralProperty(key, nextValue, sourceFile, getFormattingContextForExpression(document, sourceFile, property));
1484
+ return createOffsetReplacement(document, property.getStart(sourceFile), property.getEnd(), text);
1485
+ }
1486
+ function createObjectLiteralPropertyInsertion(document, sourceFile, objectLiteral, key, nextValue) {
1487
+ const text = objectPropertyTextForInsertion(objectLiteral, printObjectLiteralProperty(key, nextValue, sourceFile, getFormattingContext(document, sourceFile, objectLiteral)));
1488
+ return createOffsetReplacement(document, objectLiteral.properties.end, objectLiteral.properties.end, text);
1489
+ }
1490
+ function getArrayElementDeletionRange(sourceFile, arrayLiteral, element) {
1491
+ const elements = [...arrayLiteral.elements];
1492
+ const elementIndex = elements.indexOf(element);
1493
+ const elementStart = element.getFullStart();
1494
+ const elementEnd = element.getEnd();
1495
+ if (elements.length === 1) return {
1496
+ start: elementStart,
1497
+ end: elementEnd
1498
+ };
1499
+ if (elementIndex === elements.length - 1) {
1500
+ const previousElement = elements[elementIndex - 1];
1501
+ const commaOffset = sourceFile.text.lastIndexOf(",", elementStart - 1);
1502
+ return {
1503
+ start: commaOffset >= previousElement.getEnd() && commaOffset < elementStart ? commaOffset : elementStart,
1504
+ end: elementEnd
1505
+ };
1506
+ }
1507
+ const nextElement = elements[elementIndex + 1];
1508
+ const commaOffset = sourceFile.text.indexOf(",", elementEnd);
1509
+ return {
1510
+ start: elementStart,
1511
+ end: commaOffset >= elementEnd && commaOffset < nextElement.getFullStart() ? commaOffset + 1 : elementEnd
1512
+ };
1513
+ }
1514
+ function tryCreateImplementationPatchSplit(document, sourceFile, patches, nextGraph, machineIndex = 0) {
1515
+ const replacements = [];
1516
+ const remainingPatches = [];
1517
+ for (const patch of patches) {
1518
+ if (!isImplementationPatch(patch)) {
1519
+ remainingPatches.push(patch);
1520
+ continue;
1521
+ }
1522
+ const patchReplacements = createImplementationPatchReplacements(document, sourceFile, patch, nextGraph, machineIndex);
1523
+ if (!patchReplacements) {
1524
+ remainingPatches.push(patch);
1525
+ continue;
1526
+ }
1527
+ replacements.push(...patchReplacements);
1528
+ }
1529
+ return replacements.length > 0 ? {
1530
+ replacements: replacements.sort(compareReplacementRangesDescending),
1531
+ remainingPatches
1532
+ } : null;
1533
+ }
1534
+ function isImplementationPatch(patch) {
1535
+ return patch.op === "createImplementation" || patch.op === "updateImplementation" || patch.op === "deleteImplementation";
1536
+ }
1537
+ function createImplementationPatchReplacements(document, sourceFile, patch, nextGraph, machineIndex) {
1538
+ const createMachineCall = findCreateMachineCall(sourceFile, machineIndex);
1539
+ if (!createMachineCall) return null;
1540
+ const implementationRoot = findImplementationObjectLiteralForMachine(sourceFile, createMachineCall);
1541
+ const categoryName = implementationSourceTypeToCategoryName(patch.sourceType);
1542
+ const categoryObject = implementationRoot ? getObjectLiteralProperty(implementationRoot, categoryName) : null;
1543
+ if (patch.op === "createImplementation") {
1544
+ const implementation = getGraphImplementation(nextGraph, patch.sourceType, patch.implementation.id) ?? patch.implementation;
1545
+ if (!implementationRoot) return createMachineCall.arguments.length < 2 && !isObjectOfProvideCall(createMachineCall) ? createProvideCreateReplacements(document, sourceFile, createMachineCall, categoryName, implementation) : null;
1546
+ return createImplementationCreateReplacements(document, sourceFile, implementationRoot, categoryName, implementation);
1547
+ }
1548
+ if (!implementationRoot || !categoryObject) return null;
1549
+ const implementationProperty = findObjectLiteralProperty(categoryObject, patch.implementationId);
1550
+ if (!implementationProperty) return null;
1551
+ if (patch.op === "deleteImplementation") {
1552
+ const deletionRange = getObjectLiteralPropertyDeletionRange(sourceFile, categoryObject, implementationProperty);
1553
+ return [createOffsetReplacement(document, deletionRange.start, deletionRange.end, "")];
1554
+ }
1555
+ const nextImplementation = getGraphImplementation(nextGraph, patch.sourceType, patch.implementationId);
1556
+ const nextName = patch.data.name ?? nextImplementation?.name;
1557
+ const nextCode = patch.data.code ?? nextImplementation?.code?.body;
1558
+ const replacements = [];
1559
+ if (nextName && nextName !== patch.implementationId) {
1560
+ const nameNode = getObjectLiteralElementName(implementationProperty);
1561
+ if (!nameNode) return null;
1562
+ replacements.push(createOffsetReplacement(document, nameNode.getStart(sourceFile), nameNode.getEnd(), propertyNameTextForSource(nextName)));
1563
+ }
1564
+ if (nextCode !== void 0) {
1565
+ if (!ts$1.isPropertyAssignment(implementationProperty)) return null;
1566
+ replacements.push(createOffsetReplacement(document, implementationProperty.initializer.getStart(sourceFile), implementationProperty.initializer.getEnd(), nextCode));
1567
+ }
1568
+ return replacements.length > 0 ? replacements : null;
1569
+ }
1570
+ function createProvideCreateReplacements(document, sourceFile, createMachineCall, categoryName, implementation) {
1571
+ const implementationCode = implementation.code?.body;
1572
+ if (!implementation.id || !implementationCode) return null;
1573
+ const lineBreak = getLineBreak(sourceFile);
1574
+ const baseIndent = getLineIndent(sourceFile.text, createMachineCall.getStart(sourceFile));
1575
+ const propertyIndent = `${baseIndent} `;
1576
+ const nestedIndent = `${baseIndent} `;
1577
+ const text = `.provide({${lineBreak}${propertyIndent}${propertyNameTextForSource(categoryName)}: {${lineBreak}${nestedIndent}${propertyNameTextForSource(implementation.id)}: ${implementationCode},${lineBreak}${propertyIndent}},${lineBreak}${baseIndent}})`;
1578
+ return [createOffsetReplacement(document, createMachineCall.getEnd(), createMachineCall.getEnd(), text)];
1579
+ }
1580
+ function createImplementationCreateReplacements(document, sourceFile, implementationRoot, categoryName, implementation) {
1581
+ const implementationCode = implementation.code?.body;
1582
+ if (!implementation.id || !implementationCode) return null;
1583
+ const categoryObject = getObjectLiteralProperty(implementationRoot, categoryName);
1584
+ if (!categoryObject) {
1585
+ const text = objectPropertyTextForInsertion(implementationRoot, `${propertyNameTextForSource(categoryName)}: {\n${getIndentForNewObjectProperty(sourceFile, implementationRoot)}${propertyNameTextForSource(implementation.id)}: ${implementationCode},\n${getIndentForObjectClose(sourceFile, implementationRoot)}}`);
1586
+ return [createOffsetReplacement(document, implementationRoot.properties.end, implementationRoot.properties.end, text)];
1587
+ }
1588
+ const text = objectPropertyTextForInsertion(categoryObject, `${propertyNameTextForSource(implementation.id)}: ${implementationCode}`);
1589
+ return [createOffsetReplacement(document, categoryObject.properties.end, categoryObject.properties.end, text)];
1590
+ }
1591
+ function objectPropertyTextForInsertion(objectLiteral, propertyText) {
1592
+ return `${objectLiteral.properties.length > 0 ? "," : ""}${getLineBreak(objectLiteral.getSourceFile())}${getIndentForNewObjectProperty(objectLiteral.getSourceFile(), objectLiteral)}${propertyText}`;
1593
+ }
1594
+ function getLineBreak(sourceFile) {
1595
+ return sourceFile.text.includes("\r\n") ? "\r\n" : "\n";
1596
+ }
1597
+ function getLineIndent(sourceText, offset) {
1598
+ const lineStart = getLineStartOffset(sourceText, offset);
1599
+ return sourceText.slice(lineStart, offset).match(/^[ \t]*/)?.[0] ?? "";
1600
+ }
1601
+ function getIndentForNewObjectProperty(sourceFile, objectLiteral) {
1602
+ const closeIndent = getIndentForObjectClose(sourceFile, objectLiteral);
1603
+ const existingProperty = objectLiteral.properties[0];
1604
+ if (existingProperty) {
1605
+ const propertyLineStart = getLineStartOffset(sourceFile.text, existingProperty.getStart(sourceFile));
1606
+ return sourceFile.text.slice(propertyLineStart, existingProperty.getStart(sourceFile)).match(/^[ \t]*/)?.[0] ?? `${closeIndent} `;
1607
+ }
1608
+ return `${closeIndent} `;
1609
+ }
1610
+ function getIndentForObjectClose(sourceFile, objectLiteral) {
1611
+ const objectStart = objectLiteral.getStart(sourceFile);
1612
+ const lineStart = getLineStartOffset(sourceFile.text, objectStart);
1613
+ return sourceFile.text.slice(lineStart, objectStart).match(/^[ \t]*/)?.[0] ?? "";
1614
+ }
1615
+ function createOffsetReplacement(document, startOffset, endOffset, newText) {
1616
+ const start = document.positionAt(startOffset);
1617
+ const end = document.positionAt(endOffset);
1618
+ return {
1619
+ uri: getDocumentUri(document),
1620
+ range: {
1621
+ startLine: start.line,
1622
+ startChar: start.character,
1623
+ endLine: end.line,
1624
+ endChar: end.character
1625
+ },
1626
+ newText
1627
+ };
1628
+ }
1629
+ function propertyNameTextForSource(name) {
1630
+ return isIdentifierText(name) ? name : JSON.stringify(name);
1631
+ }
1632
+ function getGraphImplementation(graph, sourceType, implementationId) {
1633
+ if (!implementationId) return;
1634
+ return graph.data?.implementations?.[implementationSourceTypeToCategoryName(sourceType)]?.find((implementation) => implementation.id === implementationId);
1635
+ }
1636
+ function implementationSourceTypeToCategoryName(sourceType) {
1637
+ switch (sourceType) {
1638
+ case "action": return "actions";
1639
+ case "guard": return "guards";
1640
+ case "actor": return "actors";
1641
+ case "delay": return "delays";
1642
+ }
1643
+ }
1644
+ function tryCreateStateMembershipPatchSplit(document, sourceFile, machineConfigNode, machineConfig, patches, prevGraph, nextGraph, sourceLocations, allowDisjointDescendantReplacements = false) {
1645
+ const split = splitStateMembershipPatches(patches, prevGraph, nextGraph, sourceLocations, allowDisjointDescendantReplacements);
1646
+ if (!split) return null;
1647
+ const replacements = createStateMembershipReplacements(document, sourceFile, machineConfigNode, machineConfig, split.changes, sourceLocations);
1648
+ if (!replacements) return null;
1649
+ return {
1650
+ replacements,
1651
+ remainingPatches: split.remainingPatches
1652
+ };
1653
+ }
1654
+ async function tryCreateStateMembershipPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) {
1655
+ const split = splitStateMembershipPatches(patches, prevGraph, nextGraph, sourceLocations, true);
1656
+ if (!split) return null;
1657
+ const replacements = await createStateMembershipReplacementsForDocuments(document, sourceFile, machineConfigNode, machineConfig, split.changes, sourceLocations, openTextDocument);
1658
+ if (!replacements) return null;
1659
+ return {
1660
+ replacements,
1661
+ remainingPatches: split.remainingPatches
1662
+ };
1663
+ }
1664
+ function splitStateMembershipPatches(patches, prevGraph, nextGraph, sourceLocations, allowDisjointDescendantReplacements) {
1665
+ const createdById = /* @__PURE__ */ new Map();
1666
+ const changesByParent = /* @__PURE__ */ new Map();
1667
+ const remainingPatches = [];
1668
+ const getChange = (parentPath) => {
1669
+ const key = parentPath.join(".");
1670
+ const existing = changesByParent.get(key);
1671
+ if (existing) return existing;
1672
+ const change = {
1673
+ parentPath,
1674
+ createdPaths: [],
1675
+ deletedPaths: [],
1676
+ patches: []
1677
+ };
1678
+ changesByParent.set(key, change);
1679
+ return change;
1680
+ };
1681
+ for (const patch of patches) switch (patch.op) {
1682
+ case "createState": {
1683
+ if (!patch.id) {
1684
+ remainingPatches.push(patch);
1685
+ break;
1686
+ }
1687
+ const parentPath = resolveStatePath(nextGraph, patch.parentId);
1688
+ const nextPath = resolveStatePath(nextGraph, patch.id);
1689
+ if (!parentPath || !nextPath || nextPath.length === 0) {
1690
+ remainingPatches.push(patch);
1691
+ break;
1692
+ }
1693
+ const change = getChange(parentPath);
1694
+ createdById.set(patch.id, {
1695
+ parentPath,
1696
+ path: nextPath
1697
+ });
1698
+ change.createdPaths.push(nextPath);
1699
+ change.patches.push(patch);
1700
+ break;
1701
+ }
1702
+ case "updateState": {
1703
+ const created = createdById.get(patch.stateId);
1704
+ const nextPath = resolveStatePath(nextGraph, patch.stateId);
1705
+ if (created && nextPath && arePathsEqual(created.path, nextPath)) {
1706
+ getChange(created.parentPath).patches.push(patch);
1707
+ break;
1708
+ }
1709
+ remainingPatches.push(patch);
1710
+ break;
1711
+ }
1712
+ case "deleteState": {
1713
+ const prevPath = resolveStatePath(prevGraph, patch.stateId);
1714
+ if (!prevPath || prevPath.length === 0) {
1715
+ remainingPatches.push(patch);
1716
+ break;
1717
+ }
1718
+ const change = getChange(prevPath.slice(0, -1));
1719
+ change.deletedPaths.push(prevPath);
1720
+ change.patches.push(patch);
1721
+ break;
1722
+ }
1723
+ default: remainingPatches.push(patch);
1724
+ }
1725
+ const deletedPaths = [...changesByParent.values()].flatMap((change) => change.deletedPaths);
1726
+ const createdPaths = [...changesByParent.values()].flatMap((change) => change.createdPaths);
1727
+ const remainingPatchesWithSurvivingOwners = remainingPatches.filter((patch) => {
1728
+ const owner = resolvePatchOwner(patch, prevGraph, nextGraph);
1729
+ return owner.type !== "covered" && !isPatchOwnerCoveredByPaths(owner, deletedPaths) && !isPatchOwnerCoveredByPaths(owner, createdPaths);
1730
+ });
1731
+ const split = coalesceMembershipChangesWithRemainingPatches([...changesByParent.values()].filter((change) => !createdPaths.some((path) => isPathEqualOrDescendant(change.parentPath, path))), remainingPatchesWithSurvivingOwners, prevGraph, nextGraph, sourceLocations, allowDisjointDescendantReplacements);
1732
+ return split.changes.length > 0 ? split : null;
1733
+ }
1734
+ function isPatchOwnerCoveredByPaths(owner, paths) {
1735
+ if (owner.type !== "state" || paths.length === 0) return false;
1736
+ return paths.some((path) => isPathEqualOrDescendant(owner.path, path));
1737
+ }
1738
+ function coalesceMembershipChangesWithRemainingPatches(changes, remainingPatches, prevGraph, nextGraph, sourceLocations, allowDisjointDescendantReplacements) {
1739
+ if (remainingPatches.length === 0) return {
1740
+ changes,
1741
+ remainingPatches
1742
+ };
1743
+ const remainingPlan = deriveReplacementPlan(remainingPatches, prevGraph, nextGraph);
1744
+ const activeChanges = [];
1745
+ const activeRemainingPatches = [...remainingPatches];
1746
+ for (const change of changes) {
1747
+ if (shouldCoalesceMembershipChangeWithRemainingPlan(change, remainingPlan, sourceLocations, allowDisjointDescendantReplacements)) {
1748
+ activeRemainingPatches.push(...change.patches);
1749
+ continue;
1750
+ }
1751
+ activeChanges.push(change);
1752
+ }
1753
+ return {
1754
+ changes: activeChanges,
1755
+ remainingPatches: activeRemainingPatches
1756
+ };
1757
+ }
1758
+ function shouldCoalesceMembershipChangeWithRemainingPlan(change, remainingPlan, sourceLocations, allowDisjointDescendantReplacements) {
1759
+ if (change.parentPath.length === 0 && wouldDeModularizeRootReplacement(sourceLocations)) return false;
1760
+ if (remainingPlan.type === "root") return true;
1761
+ return remainingPlan.paths.some((path) => isPathEqualOrDescendant(change.parentPath, path) || !allowDisjointDescendantReplacements && isPathEqualOrDescendant(path, change.parentPath));
1762
+ }
1763
+ function isPathEqualOrDescendant(path, candidateParentPath) {
1764
+ return candidateParentPath.every((segment, index) => path[index] === segment);
1765
+ }
1766
+ function createStateMembershipReplacements(document, sourceFile, machineConfigNode, machineConfig, changes, sourceLocations) {
1767
+ const replacements = [];
1768
+ for (const change of changes) {
1769
+ const target = getStateMembershipParentTarget(document, sourceFile, machineConfigNode, sourceLocations, change.parentPath, getStateObjectLiteralByPath);
1770
+ if (!target) return null;
1771
+ const changeReplacements = createStateMembershipReplacementsForTarget(target.document, target.sourceFile, target.node, machineConfig, change, target.nodeKind);
1772
+ if (!changeReplacements) return null;
1773
+ replacements.push(...changeReplacements);
1774
+ replacements.push(...createStateMembershipInitialReplacements(change.parentPath.length === 0 ? document : target.document, change.parentPath.length === 0 ? sourceFile : target.sourceFile, change.parentPath.length === 0 ? machineConfigNode : target.node, machineConfig, change));
1775
+ }
1776
+ return replacements.sort(compareReplacementRangesDescending);
1777
+ }
1778
+ async function createStateMembershipReplacementsForDocuments(document, sourceFile, machineConfigNode, machineConfig, changes, sourceLocations, openTextDocument) {
1779
+ const replacements = [];
1780
+ for (const change of changes) {
1781
+ const target = await getStateMembershipParentTargetForDocuments(document, sourceFile, machineConfigNode, sourceLocations, change.parentPath, openTextDocument, getStateObjectLiteralByPath);
1782
+ if (!target) return null;
1783
+ const changeReplacements = createStateMembershipReplacementsForTarget(target.document, target.sourceFile, target.node, machineConfig, change, target.nodeKind);
1784
+ if (!changeReplacements) return null;
1785
+ replacements.push(...changeReplacements);
1786
+ replacements.push(...createStateMembershipInitialReplacements(change.parentPath.length === 0 ? document : target.document, change.parentPath.length === 0 ? sourceFile : target.sourceFile, change.parentPath.length === 0 ? machineConfigNode : target.node, machineConfig, change));
1787
+ }
1788
+ return replacements.sort(compareReplacementRangesDescending);
1789
+ }
1790
+ function createStateMembershipReplacementsForTarget(document, sourceFile, parentObject, machineConfig, change, nodeKind = "machineConfig") {
1791
+ const statesObject = nodeKind === "statesObject" ? parentObject : getObjectLiteralProperty(parentObject, "states");
1792
+ if (!statesObject) return null;
1793
+ const stateEntries = [];
1794
+ for (const path of change.createdPaths) {
1795
+ const key = path[path.length - 1];
1796
+ const stateConfig = getStateConfigByPath(machineConfig, path);
1797
+ if (!key || !isMachineConfig(stateConfig)) return null;
1798
+ stateEntries.push({
1799
+ key,
1800
+ config: stateConfig
1801
+ });
1802
+ }
1803
+ const deletionReplacements = [];
1804
+ for (const path of change.deletedPaths) {
1805
+ const key = path[path.length - 1];
1806
+ const property = key ? findObjectLiteralProperty(statesObject, key) : null;
1807
+ if (!property) return null;
1808
+ deletionReplacements.push(createObjectLiteralPropertyDeletion(document, sourceFile, statesObject, property));
1809
+ }
1810
+ return [...stateEntries.length > 0 ? [createObjectLiteralPropertiesInsertion(document, sourceFile, statesObject, stateEntries)] : [], ...deletionReplacements].sort(compareReplacementRangesDescending);
1811
+ }
1812
+ function createStateMembershipInitialReplacements(document, sourceFile, parentObject, machineConfig, change) {
1813
+ if (!change.patches.some((patch) => patch.op === "createState" && patch.initial === true || patch.op === "deleteState")) return [];
1814
+ const parentConfig = getStateConfigByPath(machineConfig, change.parentPath);
1815
+ if (!parentConfig) return [];
1816
+ const nextInitial = parentConfig.initial;
1817
+ const initialProperty = getPropertyAssignment(parentObject, "initial");
1818
+ if (nextInitial === void 0) return initialProperty ? [createObjectLiteralPropertyDeletion(document, sourceFile, parentObject, initialProperty)] : [];
1819
+ if (isMachineConfig(nextInitial)) {
1820
+ if (!initialProperty) return [createObjectLiteralPropertiesInsertion(document, sourceFile, parentObject, [{
1821
+ key: "initial",
1822
+ config: nextInitial
1823
+ }])];
1824
+ const initializer = unwrapExpression$1(initialProperty.initializer);
1825
+ const targetProperty = ts$1.isObjectLiteralExpression(initializer) ? getPropertyAssignment(initializer, "target") : null;
1826
+ if (targetProperty && typeof nextInitial.target === "string") {
1827
+ const targetInitializer = unwrapExpression$1(targetProperty.initializer);
1828
+ if (ts$1.isStringLiteralLike(targetInitializer) && targetInitializer.text === nextInitial.target) return [];
1829
+ return [createPropertyValueReplacement(document, sourceFile, targetProperty, nextInitial.target)];
1830
+ }
1831
+ return [createPropertyValueReplacement(document, sourceFile, initialProperty, nextInitial)];
1832
+ }
1833
+ if (typeof nextInitial !== "string") return [];
1834
+ if (initialProperty) {
1835
+ const initializer = unwrapExpression$1(initialProperty.initializer);
1836
+ if (ts$1.isStringLiteralLike(initializer) && initializer.text === nextInitial) return [];
1837
+ return [createPropertyValueReplacement(document, sourceFile, initialProperty, nextInitial)];
1838
+ }
1839
+ return [createObjectLiteralPropertiesInsertion(document, sourceFile, parentObject, [{
1840
+ key: "initial",
1841
+ config: nextInitial
1842
+ }])];
1843
+ }
1844
+ function createObjectLiteralPropertiesInsertion(document, sourceFile, objectLiteral, entries) {
1845
+ const formatting = getFormattingContext(document, sourceFile, objectLiteral);
1846
+ const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
1847
+ const propertyTexts = entries.map((entry) => printObjectLiteralProperty(entry.key, entry.config, sourceFile, formatting));
1848
+ const existingProperties = objectLiteral.properties;
1849
+ const closeBraceOffset = objectLiteral.getEnd() - 1;
1850
+ const startOffset = existingProperties.length === 0 ? closeBraceOffset : existingProperties[existingProperties.length - 1].getEnd();
1851
+ const start = document.positionAt(startOffset);
1852
+ const end = document.positionAt(closeBraceOffset);
1853
+ const prefix = existingProperties.length === 0 ? lineSeparator : `,${lineSeparator}`;
1854
+ const suffix = `${lineSeparator}${formatting.baseIndent}`;
1855
+ return {
1856
+ uri: getDocumentUri(document),
1857
+ range: {
1858
+ startLine: start.line,
1859
+ startChar: start.character,
1860
+ endLine: end.line,
1861
+ endChar: end.character
1862
+ },
1863
+ newText: `${prefix}${propertyTexts.join(`,${lineSeparator}`)}${suffix}`
1864
+ };
1865
+ }
1866
+ function createObjectLiteralPropertyDeletion(document, sourceFile, objectLiteral, property) {
1867
+ const range = getObjectLiteralPropertyDeletionRange(sourceFile, objectLiteral, property);
1868
+ const start = document.positionAt(range.start);
1869
+ const end = document.positionAt(range.end);
1870
+ return {
1871
+ uri: getDocumentUri(document),
1872
+ range: {
1873
+ startLine: start.line,
1874
+ startChar: start.character,
1875
+ endLine: end.line,
1876
+ endChar: end.character
1877
+ },
1878
+ newText: ""
1879
+ };
1880
+ }
1881
+ function getObjectLiteralPropertyDeletionRange(sourceFile, objectLiteral, property) {
1882
+ const properties = [...objectLiteral.properties];
1883
+ const propertyIndex = properties.indexOf(property);
1884
+ const propertyStart = property.getFullStart();
1885
+ const propertyEnd = property.getEnd();
1886
+ if (properties.length === 1) return {
1887
+ start: propertyStart,
1888
+ end: propertyEnd
1889
+ };
1890
+ if (propertyIndex === properties.length - 1) {
1891
+ const previousProperty = properties[propertyIndex - 1];
1892
+ const commaOffset = sourceFile.text.lastIndexOf(",", propertyStart - 1);
1893
+ return {
1894
+ start: commaOffset >= previousProperty.getEnd() && commaOffset < propertyStart ? commaOffset : propertyStart,
1895
+ end: propertyEnd
1896
+ };
1897
+ }
1898
+ const nextProperty = properties[propertyIndex + 1];
1899
+ const commaOffset = sourceFile.text.indexOf(",", propertyEnd);
1900
+ return {
1901
+ start: propertyStart,
1902
+ end: commaOffset >= propertyEnd && commaOffset < nextProperty.getFullStart() ? commaOffset + 1 : propertyEnd
1903
+ };
1904
+ }
1905
+ function findObjectLiteralProperty(objectLiteral, propertyName) {
1906
+ for (const property of objectLiteral.properties) {
1907
+ if (ts$1.isShorthandPropertyAssignment(property) && property.name.text === propertyName) return property;
1908
+ if (ts$1.isPropertyAssignment(property)) {
1909
+ if (getPropertyNameText$1(property.name) === propertyName) return property;
1910
+ }
1911
+ }
1912
+ return null;
1913
+ }
1914
+ function findObjectLiteralPropertyByRange(sourceFile, objectLiteral, range) {
1915
+ if (!range) return null;
1916
+ const start = offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar);
1917
+ const end = offsetAtRangePosition(sourceFile.text, range.endLine, range.endChar);
1918
+ for (const property of objectLiteral.properties) {
1919
+ const propertyName = getObjectLiteralElementName(property);
1920
+ if (propertyName && propertyName.getStart(sourceFile) === start && propertyName.getEnd() === end) return property;
1921
+ }
1922
+ return null;
1923
+ }
1924
+ function getObjectLiteralElementName(property) {
1925
+ if (ts$1.isPropertyAssignment(property) || ts$1.isShorthandPropertyAssignment(property) || ts$1.isMethodDeclaration(property) || ts$1.isGetAccessorDeclaration(property) || ts$1.isSetAccessorDeclaration(property)) return property.name;
1926
+ return null;
1927
+ }
1928
+ function getStatePropertyKeyText(property) {
1929
+ if (ts$1.isShorthandPropertyAssignment(property)) return property.name.text;
1930
+ if (ts$1.isPropertyAssignment(property)) return getPropertyNameText$1(property.name);
1931
+ return null;
1932
+ }
1933
+ function printObjectLiteralProperty(key, value, sourceFile, formatting) {
1934
+ const objectText = printExpression(valueToExpression({ [key]: value }), sourceFile, formatting);
1935
+ const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
1936
+ const lines = objectText.split(/\r?\n/);
1937
+ if (lines.length <= 2) return objectText.replace(/^\{\s*/, "").replace(/\s*\}$/, "");
1938
+ return lines.slice(1, -1).join(lineSeparator);
1939
+ }
1940
+ function wouldDeModularizeRootReplacement(sourceLocations) {
1941
+ const root = sourceLocations?.root;
1942
+ return sourceLocations?.states.some((location) => location.kind !== "inline" || (root ? !isSourceLocationInsideRoot(location, root) : false)) ?? false;
1943
+ }
1944
+ function isSourceLocationInsideRoot(location, root) {
1945
+ if (location.uri !== root.uri) return false;
1946
+ const startsAfterRootStart = location.range.startLine > root.range.startLine || location.range.startLine === root.range.startLine && location.range.startChar >= root.range.startChar;
1947
+ const endsBeforeRootEnd = location.range.endLine < root.range.endLine || location.range.endLine === root.range.endLine && location.range.endChar <= root.range.endChar;
1948
+ return startsAfterRootStart && endsBeforeRootEnd;
1949
+ }
1950
+ function parseGraphPatches(value) {
1951
+ if (!Array.isArray(value)) return null;
1952
+ return value.filter(isGraphPatch);
1953
+ }
1954
+ function parseGraph(value) {
1955
+ if (!value || typeof value !== "object") return null;
1956
+ const candidate = value;
1957
+ if (!Array.isArray(candidate.nodes) || !Array.isArray(candidate.edges)) return null;
1958
+ return candidate;
1959
+ }
1960
+ function isGraphPatch(value) {
1961
+ return Boolean(value && typeof value === "object" && "op" in value && typeof value.op === "string");
1962
+ }
1963
+ function isMachineConfig(value) {
1964
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
1965
+ }
1966
+ function findMachineConfigObjectLiteral(sourceFile, machineIndex = 0) {
1967
+ const firstArgument = findCreateMachineCall(sourceFile, machineIndex)?.arguments[0];
1968
+ return firstArgument ? unwrapObjectLiteralExpression(firstArgument) : null;
1969
+ }
1970
+ function findCreateMachineCall(sourceFile, machineIndex = 0) {
1971
+ let found = null;
1972
+ let currentMachineIndex = 0;
1973
+ const visit = (node) => {
1974
+ if (found) return;
1975
+ if (ts$1.isCallExpression(node)) {
1976
+ const expression = node.expression;
1977
+ if (isCreateMachineExpression$1(expression)) {
1978
+ const isSelectedMachine = currentMachineIndex === machineIndex;
1979
+ currentMachineIndex += 1;
1980
+ if (!isSelectedMachine) return;
1981
+ found = node;
1982
+ return;
1983
+ }
1984
+ }
1985
+ ts$1.forEachChild(node, visit);
1986
+ };
1987
+ visit(sourceFile);
1988
+ return found;
1989
+ }
1990
+ function findImplementationObjectLiteralForMachine(sourceFile, createMachineCall) {
1991
+ const setupObject = findSetupObjectLiteralForMachine(sourceFile, createMachineCall);
1992
+ if (setupObject) return setupObject;
1993
+ const secondArgument = createMachineCall.arguments[1];
1994
+ if (secondArgument) {
1995
+ const implementationObject = unwrapObjectLiteralExpression(secondArgument);
1996
+ if (implementationObject) return implementationObject;
1997
+ }
1998
+ if (isObjectOfProvideCall(createMachineCall)) {
1999
+ const provideCall = createMachineCall.parent.parent;
2000
+ if (ts$1.isCallExpression(provideCall)) {
2001
+ const firstArgument = provideCall.arguments[0];
2002
+ return firstArgument ? unwrapObjectLiteralExpression(firstArgument) : null;
2003
+ }
2004
+ }
2005
+ return null;
2006
+ }
2007
+ function findSetupObjectLiteralForMachine(sourceFile, createMachineCall) {
2008
+ const expression = createMachineCall.expression;
2009
+ if (!ts$1.isPropertyAccessExpression(expression)) return null;
2010
+ const receiver = unwrapExpression$1(expression.expression);
2011
+ if (ts$1.isCallExpression(receiver) && isSetupCallExpression(receiver)) {
2012
+ const setupArgument = receiver.arguments[0];
2013
+ return setupArgument ? unwrapObjectLiteralExpression(setupArgument) : null;
2014
+ }
2015
+ if (!ts$1.isIdentifier(receiver)) return null;
2016
+ for (const statement of sourceFile.statements) {
2017
+ if (!ts$1.isVariableStatement(statement)) continue;
2018
+ for (const declaration of statement.declarationList.declarations) {
2019
+ if (!ts$1.isIdentifier(declaration.name) || declaration.name.text !== receiver.text || !declaration.initializer) continue;
2020
+ const initializer = unwrapExpression$1(declaration.initializer);
2021
+ if (!ts$1.isCallExpression(initializer) || !isSetupCallExpression(initializer)) return null;
2022
+ const setupArgument = initializer.arguments[0];
2023
+ return setupArgument ? unwrapObjectLiteralExpression(setupArgument) : null;
2024
+ }
2025
+ }
2026
+ return null;
2027
+ }
2028
+ function isObjectOfProvideCall(node) {
2029
+ const parent = node.parent;
2030
+ const grandparent = parent?.parent;
2031
+ return !!parent && !!grandparent && ts$1.isPropertyAccessExpression(parent) && parent.expression === node && parent.name.text === "provide" && ts$1.isCallExpression(grandparent) && grandparent.expression === parent;
2032
+ }
2033
+ function isCreateMachineExpression$1(expression) {
2034
+ const isMachineFactoryName = (name) => name === "createMachine" || name === "createMachineFromConfig";
2035
+ return ts$1.isIdentifier(expression) && isMachineFactoryName(expression.text) || ts$1.isPropertyAccessExpression(expression) && isMachineFactoryName(expression.name.text);
2036
+ }
2037
+ function isSetupCallExpression(node) {
2038
+ const expression = node.expression;
2039
+ return ts$1.isIdentifier(expression) && expression.text === "setup" || ts$1.isPropertyAccessExpression(expression) && expression.name.text === "setup";
2040
+ }
2041
+ function unwrapObjectLiteralExpression(expression) {
2042
+ const current = unwrapExpression$1(expression);
2043
+ return ts$1.isObjectLiteralExpression(current) ? current : null;
2044
+ }
2045
+ function unwrapExpression$1(expression) {
2046
+ let current = expression;
2047
+ for (;;) {
2048
+ if (ts$1.isParenthesizedExpression(current)) {
2049
+ current = current.expression;
2050
+ continue;
2051
+ }
2052
+ if (ts$1.isAsExpression(current) || ts$1.isSatisfiesExpression(current)) {
2053
+ current = current.expression;
2054
+ continue;
2055
+ }
2056
+ if (ts$1.isTypeAssertionExpression(current)) {
2057
+ current = current.expression;
2058
+ continue;
2059
+ }
2060
+ break;
2061
+ }
2062
+ return current;
2063
+ }
2064
+ function resolveStatePath(graph, nodeId) {
2065
+ const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
2066
+ const segments = [];
2067
+ let current = nodeById.get(nodeId);
2068
+ if (!current) return null;
2069
+ while (current && current.parentId !== null) {
2070
+ segments.push(current.data.key);
2071
+ current = nodeById.get(current.parentId);
2072
+ }
2073
+ return segments.reverse();
2074
+ }
2075
+ function getEdgeSourceId(graph, edgeId) {
2076
+ return graph.edges.find((edge) => edge.id === edgeId)?.sourceId ?? null;
2077
+ }
2078
+ function resolveEdgeSourcePath(graph, edgeId) {
2079
+ const sourceId = getEdgeSourceId(graph, edgeId);
2080
+ return sourceId ? resolveStatePath(graph, sourceId) : null;
2081
+ }
2082
+ function resolvePatchOwner(patch, prevGraph, nextGraph) {
2083
+ switch (patch.op) {
2084
+ case "createState": {
2085
+ const parentPath = resolveStatePath(nextGraph, patch.parentId);
2086
+ return parentPath ? {
2087
+ type: "state",
2088
+ path: parentPath
2089
+ } : { type: "covered" };
2090
+ }
2091
+ case "updateState": {
2092
+ const nextPath = resolveStatePath(nextGraph, patch.stateId);
2093
+ const prevPath = resolveStatePath(prevGraph, patch.stateId);
2094
+ if (patch.key !== void 0 && prevPath && nextPath) return { type: "root" };
2095
+ const path = nextPath ?? prevPath;
2096
+ return path ? {
2097
+ type: "state",
2098
+ path
2099
+ } : { type: "covered" };
2100
+ }
2101
+ case "deleteState": {
2102
+ const node = prevGraph.nodes.find((item) => item.id === patch.stateId);
2103
+ if (!node) return { type: "covered" };
2104
+ if (!node.parentId) return { type: "root" };
2105
+ const parentPath = resolveStatePath(prevGraph, node.parentId);
2106
+ return parentPath ? {
2107
+ type: "state",
2108
+ path: parentPath
2109
+ } : { type: "root" };
2110
+ }
2111
+ case "createTransition": {
2112
+ const path = resolveStatePath(nextGraph, patch.sourceId);
2113
+ return path ? {
2114
+ type: "state",
2115
+ path
2116
+ } : { type: "covered" };
2117
+ }
2118
+ case "updateTransition": {
2119
+ const path = resolveEdgeSourcePath(nextGraph, patch.transitionId) ?? resolveEdgeSourcePath(prevGraph, patch.transitionId);
2120
+ return path ? {
2121
+ type: "state",
2122
+ path
2123
+ } : { type: "covered" };
2124
+ }
2125
+ case "deleteTransition":
2126
+ case "setGuard":
2127
+ case "deleteGuard": {
2128
+ const edgeId = "transitionId" in patch ? patch.transitionId : patch.edgeId;
2129
+ const path = resolveEdgeSourcePath(nextGraph, edgeId) ?? resolveEdgeSourcePath(prevGraph, edgeId);
2130
+ return path ? {
2131
+ type: "state",
2132
+ path
2133
+ } : { type: "covered" };
2134
+ }
2135
+ case "createAction":
2136
+ case "updateAction":
2137
+ case "deleteAction": {
2138
+ if ("nodeId" in patch.location) {
2139
+ const path = resolveStatePath(nextGraph, patch.location.nodeId) ?? resolveStatePath(prevGraph, patch.location.nodeId);
2140
+ return path ? {
2141
+ type: "state",
2142
+ path
2143
+ } : { type: "covered" };
2144
+ }
2145
+ const path = resolveEdgeSourcePath(nextGraph, patch.location.edgeId) ?? resolveEdgeSourcePath(prevGraph, patch.location.edgeId);
2146
+ return path ? {
2147
+ type: "state",
2148
+ path
2149
+ } : { type: "covered" };
2150
+ }
2151
+ case "createInvoke":
2152
+ case "updateInvoke":
2153
+ case "deleteInvoke":
2154
+ case "createTag":
2155
+ case "deleteTag": {
2156
+ const path = resolveStatePath(nextGraph, patch.nodeId) ?? resolveStatePath(prevGraph, patch.nodeId);
2157
+ return path ? {
2158
+ type: "state",
2159
+ path
2160
+ } : { type: "covered" };
2161
+ }
2162
+ case "updateSchemas": return { type: "root" };
2163
+ default: return { type: "root" };
2164
+ }
2165
+ }
2166
+ function deriveReplacementPlan(patches, prevGraph, nextGraph) {
2167
+ const rawPaths = [];
2168
+ const hasConcretePatch = patches.some((patch) => patch.op !== "updateSchemas");
2169
+ for (const patch of patches) {
2170
+ if (patch.op === "updateSchemas" && hasConcretePatch) continue;
2171
+ const owner = resolvePatchOwner(patch, prevGraph, nextGraph);
2172
+ if (owner.type === "root") return { type: "root" };
2173
+ if (owner.type === "covered") continue;
2174
+ rawPaths.push(owner.path);
2175
+ }
2176
+ const reducedPaths = reducePaths(rawPaths);
2177
+ if (reducedPaths.length === 0 || reducedPaths.some((path) => path.length === 0)) return { type: "root" };
2178
+ return {
2179
+ type: "states",
2180
+ paths: reducedPaths
2181
+ };
2182
+ }
2183
+ function dropCoveredSchemaPatches(patches, hasConcreteReplacement) {
2184
+ return hasConcreteReplacement ? patches.filter((patch) => patch.op !== "updateSchemas") : patches;
2185
+ }
2186
+ function reducePaths(paths) {
2187
+ const uniquePaths = Array.from(new Set(paths.map((path) => path.join(".")))).map((value) => value === "" ? [] : value.split(".")).sort((a, b) => a.length - b.length);
2188
+ return uniquePaths.filter((path, index) => {
2189
+ return !uniquePaths.some((candidate, candidateIndex) => {
2190
+ if (candidateIndex === index || candidate.length >= path.length) return false;
2191
+ return candidate.every((segment, segmentIndex) => segment === path[segmentIndex]);
2192
+ });
2193
+ });
2194
+ }
2195
+ function getStateConfigByPath(machineConfig, path) {
2196
+ let current = machineConfig;
2197
+ for (const segment of path) {
2198
+ const states = current?.states;
2199
+ if (!isMachineConfig(states)) return;
2200
+ const next = states[segment];
2201
+ if (!isMachineConfig(next)) return;
2202
+ current = next;
2203
+ }
2204
+ return current;
2205
+ }
2206
+ function getStateObjectLiteralByPath(root, path) {
2207
+ let current = root;
2208
+ for (const segment of path) {
2209
+ if (!current) return null;
2210
+ const statesProperty = getObjectLiteralProperty(current, "states");
2211
+ current = statesProperty && getObjectLiteralProperty(statesProperty, segment);
2212
+ }
2213
+ return current;
2214
+ }
2215
+ function offsetAtRangePosition(sourceText, line, character) {
2216
+ if (line <= 0) return character;
2217
+ let currentLine = 0;
2218
+ for (let index = 0; index < sourceText.length; index += 1) {
2219
+ if (sourceText.charCodeAt(index) !== 10) continue;
2220
+ currentLine += 1;
2221
+ if (currentLine === line) return index + 1 + character;
2222
+ }
2223
+ return sourceText.length;
2224
+ }
2225
+ function getObjectLiteralProperty(objectLiteral, propertyName) {
2226
+ for (const property of objectLiteral.properties) {
2227
+ if (!ts$1.isPropertyAssignment(property)) continue;
2228
+ if (getPropertyNameText$1(property.name) !== propertyName) continue;
2229
+ return unwrapObjectLiteralExpression(property.initializer) ?? null;
2230
+ }
2231
+ return null;
2232
+ }
2233
+ function getPropertyNameText$1(name) {
2234
+ if (ts$1.isIdentifier(name) || ts$1.isStringLiteral(name) || ts$1.isNumericLiteral(name)) return name.text;
2235
+ if (ts$1.isComputedPropertyName(name)) {
2236
+ const expression = name.expression;
2237
+ if (ts$1.isStringLiteral(expression) || ts$1.isNoSubstitutionTemplateLiteral(expression) || ts$1.isNumericLiteral(expression)) return expression.text;
2238
+ }
2239
+ return null;
2240
+ }
2241
+ function createReplacement(document, sourceFile, node, value) {
2242
+ const start = document.positionAt(node.getStart(sourceFile));
2243
+ const end = document.positionAt(node.getEnd());
2244
+ const formatting = getFormattingContext(document, sourceFile, node);
2245
+ return {
2246
+ uri: getDocumentUri(document),
2247
+ range: {
2248
+ startLine: start.line,
2249
+ startChar: start.character,
2250
+ endLine: end.line,
2251
+ endChar: end.character
2252
+ },
2253
+ newText: printExpression(valueToExpression(value, node), sourceFile, formatting)
2254
+ };
2255
+ }
2256
+ function addCodeImportReplacements(document, sourceFile, machineConfig, replacements) {
2257
+ const importReplacements = createCodeImportReplacements(document, sourceFile, collectCodeImports(machineConfig));
2258
+ return [...replacements, ...importReplacements];
2259
+ }
2260
+ function collectCodeImports(value) {
2261
+ const imports = [];
2262
+ const visit = (item) => {
2263
+ if (!item || typeof item !== "object") return;
2264
+ if (Array.isArray(item)) {
2265
+ for (const child of item) visit(child);
2266
+ return;
2267
+ }
2268
+ if (isInlineExpressionDirective(item)) {
2269
+ const itemImports = item.imports;
2270
+ if (Array.isArray(itemImports)) {
2271
+ for (const candidate of itemImports) if (isCodeImport(candidate)) imports.push(candidate);
2272
+ }
2273
+ }
2274
+ for (const child of Object.values(item)) visit(child);
2275
+ };
2276
+ visit(value);
2277
+ return imports;
2278
+ }
2279
+ function isCodeImport(value) {
2280
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
2281
+ const candidate = value;
2282
+ return typeof candidate.package === "string" && typeof candidate.import === "string" && (!candidate.version || typeof candidate.version === "string") && (!candidate.importKind || candidate.importKind === "named" || candidate.importKind === "default" || candidate.importKind === "namespace");
2283
+ }
2284
+ function createCodeImportReplacements(document, sourceFile, imports) {
2285
+ const namedImportsByPackage = /* @__PURE__ */ new Map();
2286
+ for (const codeImport of imports) {
2287
+ if ((codeImport.importKind ?? "named") !== "named") continue;
2288
+ const namedImports = namedImportsByPackage.get(codeImport.package) ?? /* @__PURE__ */ new Set();
2289
+ namedImports.add(codeImport.import);
2290
+ namedImportsByPackage.set(codeImport.package, namedImports);
2291
+ }
2292
+ const replacements = [];
2293
+ for (const [packageName, importNames] of namedImportsByPackage) {
2294
+ const missing = new Set(importNames);
2295
+ const importDeclaration = findImportDeclaration(sourceFile, packageName);
2296
+ if (importDeclaration) {
2297
+ const namedBindings = importDeclaration.importClause?.namedBindings;
2298
+ if (namedBindings && ts$1.isNamedImports(namedBindings)) {
2299
+ for (const element of namedBindings.elements) missing.delete(element.name.text);
2300
+ if (missing.size > 0) {
2301
+ const insertion = `${namedBindings.elements.length > 0 ? ", " : ""}${[...missing].sort().join(", ")}`;
2302
+ replacements.push(createOffsetReplacement(document, namedBindings.elements.end, namedBindings.elements.end, insertion));
2303
+ }
2304
+ }
2305
+ continue;
2306
+ }
2307
+ replacements.push(createOffsetReplacement(document, getImportInsertionOffset(sourceFile), getImportInsertionOffset(sourceFile), `import { ${[...missing].sort().join(", ")} } from "${packageName}";${getLineBreak(sourceFile)}`));
2308
+ }
2309
+ return replacements;
2310
+ }
2311
+ function findImportDeclaration(sourceFile, packageName) {
2312
+ for (const statement of sourceFile.statements) if (ts$1.isImportDeclaration(statement) && ts$1.isStringLiteral(statement.moduleSpecifier) && statement.moduleSpecifier.text === packageName) return statement;
2313
+ return null;
2314
+ }
2315
+ function getImportInsertionOffset(sourceFile) {
2316
+ let offset = 0;
2317
+ for (const statement of sourceFile.statements) {
2318
+ if (!ts$1.isImportDeclaration(statement)) break;
2319
+ offset = statement.getEnd();
2320
+ const nextLineStart = getLineStartOffset(sourceFile.text, offset + 1);
2321
+ if (nextLineStart > offset) offset = nextLineStart;
2322
+ }
2323
+ return offset;
2324
+ }
2325
+ function getDocumentUri(document) {
2326
+ return (typeof document.uri === "string" ? document.uri : document.uri?.toString()) ?? document.fileName;
2327
+ }
2328
+ function tryCreateSemanticReplacements(document, sourceFile, machineConfigNode, patches, prevGraph, nextGraph) {
2329
+ const split = getSemanticStateRenamePatchSplit(patches, prevGraph, nextGraph);
2330
+ if (!split || split.remainingPatches.length > 0) return null;
2331
+ const replacements = [];
2332
+ const targetLiterals = collectTargetStringLiterals(machineConfigNode).map((target) => ({
2333
+ ...target,
2334
+ document,
2335
+ sourceFile
2336
+ }));
2337
+ for (const rename of split.renames) {
2338
+ const parentObject = getStateObjectLiteralByPath(machineConfigNode, rename.parentPath);
2339
+ if (!parentObject) return null;
2340
+ const renameReplacements = createStateKeyRenameReplacementsForTarget(document, sourceFile, parentObject, rename, void 0, targetLiterals);
2341
+ if (!renameReplacements || hasDuplicateReplacementRange([...replacements, ...renameReplacements])) return null;
2342
+ replacements.push(...renameReplacements);
2343
+ }
2344
+ return replacements.sort(compareReplacementRangesDescending);
2345
+ }
2346
+ async function tryCreateSemanticPatchSplitForDocuments(document, sourceFile, machineConfigNode, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) {
2347
+ const split = getSemanticStateRenamePatchSplit(patches, prevGraph, nextGraph);
2348
+ if (!split) return null;
2349
+ const replacements = [];
2350
+ const targetLiterals = await collectMappedTargetStringLiterals(document, sourceFile, machineConfigNode, sourceLocations, openTextDocument);
2351
+ let activeSourceLocations = sourceLocations;
2352
+ for (const rename of split.renames) {
2353
+ const parentTarget = await getStateMembershipParentTargetForDocuments(document, sourceFile, machineConfigNode, activeSourceLocations, rename.parentPath, openTextDocument, getStateObjectLiteralByPath);
2354
+ if (!parentTarget) return null;
2355
+ const renameReplacements = createStateKeyRenameReplacementsForTarget(parentTarget.document, parentTarget.sourceFile, parentTarget.node, rename, activeSourceLocations, targetLiterals, parentTarget.nodeKind, parentTarget.nodeKind === "statesObject" && rename.parentPath.length === 0 ? machineConfigNode : parentTarget.node);
2356
+ if (!renameReplacements || hasDuplicateReplacementRange([...replacements, ...renameReplacements])) return null;
2357
+ replacements.push(...renameReplacements);
2358
+ activeSourceLocations = createRenamedSourceLocations(activeSourceLocations, rename);
2359
+ }
2360
+ return {
2361
+ replacements: replacements.sort(compareReplacementRangesDescending),
2362
+ remainingPatches: split.remainingPatches,
2363
+ sourceLocations: activeSourceLocations
2364
+ };
2365
+ }
2366
+ function getSemanticStateRenameFromPatch(patch, prevGraph, nextGraph) {
2367
+ if (patch.op !== "updateState" || patch.key === void 0) return null;
2368
+ const prevPath = resolveStatePath(prevGraph, patch.stateId);
2369
+ const nextPath = resolveStatePath(nextGraph, patch.stateId);
2370
+ if (!prevPath || !nextPath || prevPath.length !== nextPath.length || prevPath.length === 0) return null;
2371
+ const oldKey = prevPath[prevPath.length - 1];
2372
+ const newKey = nextPath[nextPath.length - 1];
2373
+ const parentPath = prevPath.slice(0, -1);
2374
+ if (oldKey === newKey) return null;
2375
+ return {
2376
+ oldKey,
2377
+ newKey,
2378
+ oldPath: prevPath,
2379
+ newPath: nextPath,
2380
+ parentPath,
2381
+ oldAbsolutePath: getAbsoluteStatePath(prevGraph, patch.stateId),
2382
+ newAbsolutePath: getAbsoluteStatePath(nextGraph, patch.stateId)
2383
+ };
2384
+ }
2385
+ function getSemanticStateRenamePatchSplit(patches, prevGraph, nextGraph) {
2386
+ const renames = [];
2387
+ const remainingPatches = [];
2388
+ for (const patch of patches) {
2389
+ const patchRename = getSemanticStateRenameFromPatch(patch, prevGraph, nextGraph);
2390
+ if (patchRename) {
2391
+ renames.push(patchRename);
2392
+ if (getStatePropertyNamesFromUpdatePatch(patch).length > 0) remainingPatches.push(patch);
2393
+ continue;
2394
+ }
2395
+ remainingPatches.push(patch);
2396
+ }
2397
+ return renames.length > 0 ? {
2398
+ renames,
2399
+ remainingPatches
2400
+ } : null;
2401
+ }
2402
+ function hasNestedStateRenameBatch(patches, prevGraph, nextGraph) {
2403
+ const renames = patches.flatMap((patch) => {
2404
+ const rename = getSemanticStateRenameFromPatch(patch, prevGraph, nextGraph);
2405
+ return rename ? [rename] : [];
2406
+ });
2407
+ return renames.some((ancestor, ancestorIndex) => renames.some((descendant, descendantIndex) => ancestorIndex !== descendantIndex && ancestor.oldPath.length < descendant.oldPath.length && isPathEqualOrDescendant(descendant.oldPath, ancestor.oldPath)));
2408
+ }
2409
+ function hasDuplicateReplacementRange(replacements) {
2410
+ const ranges = /* @__PURE__ */ new Set();
2411
+ for (const replacement of replacements) {
2412
+ const key = `${replacement.uri ?? ""}:${replacement.range.startLine}:${replacement.range.startChar}:${replacement.range.endLine}:${replacement.range.endChar}`;
2413
+ if (ranges.has(key)) return true;
2414
+ ranges.add(key);
2415
+ }
2416
+ return false;
2417
+ }
2418
+ function createRenamedSourceLocations(sourceLocations, rename) {
2419
+ if (!sourceLocations) return;
2420
+ return {
2421
+ ...sourceLocations,
2422
+ states: sourceLocations.states.map((location) => {
2423
+ if (!isPathEqualOrDescendant(location.path, rename.oldPath)) return location;
2424
+ return {
2425
+ ...location,
2426
+ path: [...rename.newPath, ...location.path.slice(rename.oldPath.length)]
2427
+ };
2428
+ }),
2429
+ transitionFunctions: sourceLocations.transitionFunctions?.map((location) => ({
2430
+ ...location,
2431
+ sourcePaths: location.sourcePaths.map((path) => isPathEqualOrDescendant(path, rename.oldPath) ? [...rename.newPath, ...path.slice(rename.oldPath.length)] : path)
2432
+ }))
2433
+ };
2434
+ }
2435
+ function createStateKeyRenameReplacementsForTarget(document, sourceFile, parentObject, rename, sourceLocations, targetLiterals, nodeKind = "machineConfig", initialOwnerObject = parentObject) {
2436
+ const statesObject = nodeKind === "statesObject" ? parentObject : getObjectLiteralProperty(parentObject, "states");
2437
+ const location = sourceLocations?.states.find((item) => rename.oldPath && arePathsEqual(item.path, rename.oldPath));
2438
+ const stateProperty = statesObject && (findObjectLiteralProperty(statesObject, rename.oldKey) ?? findObjectLiteralPropertyByRange(sourceFile, statesObject, location?.keyRange));
2439
+ if (!statesObject || !stateProperty) return null;
2440
+ const keyReplacement = createStatePropertyRenameReplacement(document, sourceFile, stateProperty, rename.oldKey, rename.newKey, location?.keySource);
2441
+ if (!keyReplacement) return null;
2442
+ const replacements = [keyReplacement];
2443
+ const initialProperty = getPropertyAssignment(initialOwnerObject, "initial");
2444
+ if (initialProperty) {
2445
+ const initialReplacement = createStringInitializerRenameReplacement(document, sourceFile, initialProperty.initializer, rename.oldKey, rename.newKey);
2446
+ if (initialReplacement) replacements.push(initialReplacement);
2447
+ }
2448
+ const supportedScope = new Set([rename.parentPath.join("."), ...getDirectChildStatePaths(nodeKind === "statesObject" ? initialOwnerObject : parentObject, rename.parentPath).map((path) => path.join("."))]);
2449
+ for (const target of targetLiterals) {
2450
+ if (!referencesRenamedState(target.node.text, rename)) continue;
2451
+ if (!referencesRenamedAbsoluteState(target.node.text, rename)) {
2452
+ const initialSourcePaths = target.initialSourcePaths ?? [];
2453
+ if (initialSourcePaths.length > 0) {
2454
+ if (!target.sourcePaths.every((sourcePath) => arePathsEqual(sourcePath, rename.parentPath))) {
2455
+ if (initialSourcePaths.length === target.sourcePaths.length && !initialSourcePaths.some((sourcePath) => arePathsEqual(sourcePath, rename.parentPath))) continue;
2456
+ return null;
2457
+ }
2458
+ } else for (const sourcePath of target.sourcePaths) {
2459
+ const sourceKey = sourcePath.join(".");
2460
+ if (!(sourcePath.length === rename.parentPath.length || arePathsEqual(sourcePath.slice(0, -1), rename.parentPath)) || !supportedScope.has(sourceKey)) return null;
2461
+ }
2462
+ }
2463
+ const replacement = createStringLiteralReplacement(target.document, target.sourceFile, target.node, renameStateReference(target.node.text, rename));
2464
+ replacements.push(replacement);
2465
+ }
2466
+ return replacements;
2467
+ }
2468
+ function getDirectChildStatePaths(stateObject, parentPath) {
2469
+ const statesObject = getObjectLiteralProperty(stateObject, "states");
2470
+ if (!statesObject) return [];
2471
+ return statesObject.properties.flatMap((property) => {
2472
+ const key = getStatePropertyKeyText(property);
2473
+ if (!key) return [];
2474
+ return [[...parentPath, key]];
2475
+ });
2476
+ }
2477
+ function collectTargetStringLiterals(machineConfigNode) {
2478
+ const literals = [];
2479
+ const bindings = collectTopLevelExpressionBindings(machineConfigNode.getSourceFile());
2480
+ const visitStateObject = (stateObject, sourcePath) => {
2481
+ collectInitialTargetStringLiterals(stateObject, sourcePath, literals, bindings);
2482
+ for (const propertyName of [
2483
+ "always",
2484
+ "after",
2485
+ "on",
2486
+ "onDone"
2487
+ ]) {
2488
+ const property = getPropertyAssignment(stateObject, propertyName);
2489
+ if (!property) continue;
2490
+ collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals, bindings);
2491
+ }
2492
+ const statesObject = getObjectLiteralProperty(stateObject, "states");
2493
+ if (!statesObject) return;
2494
+ for (const property of statesObject.properties) {
2495
+ if (!ts$1.isPropertyAssignment(property)) continue;
2496
+ const key = getPropertyNameText$1(property.name);
2497
+ const childState = unwrapObjectLiteralExpression(property.initializer);
2498
+ if (!key || !childState) continue;
2499
+ visitStateObject(childState, [...sourcePath, key]);
2500
+ }
2501
+ };
2502
+ visitStateObject(machineConfigNode, []);
2503
+ return literals;
2504
+ }
2505
+ function collectInitialTargetStringLiterals(stateObject, sourcePath, literals, bindings) {
2506
+ const initialProperty = getPropertyAssignment(stateObject, "initial");
2507
+ if (!initialProperty) return;
2508
+ const initializer = unwrapExpression$1(initialProperty.initializer);
2509
+ if (ts$1.isObjectLiteralExpression(initializer)) {
2510
+ const initialLiterals = [];
2511
+ collectTargetStringLiteralsFromExpression(initializer, sourcePath, initialLiterals, bindings);
2512
+ for (const literal of initialLiterals) for (const literalSourcePath of literal.sourcePaths) addTargetLiteral(literals, literal.node, literalSourcePath, true);
2513
+ }
2514
+ }
2515
+ async function collectMappedTargetStringLiterals(rootDocument, rootSourceFile, machineConfigNode, sourceLocations, openTextDocument) {
2516
+ const literals = collectTargetStringLiterals(machineConfigNode).map((target) => ({
2517
+ ...target,
2518
+ document: rootDocument,
2519
+ sourceFile: rootSourceFile
2520
+ }));
2521
+ if (!sourceLocations) return literals;
2522
+ const seen = new Set(literals.map((target) => getTargetLiteralReplacementKey(rootDocument, rootSourceFile, target.node)));
2523
+ const targetByKey = new Map(literals.map((target) => [getTargetLiteralReplacementKey(rootDocument, rootSourceFile, target.node), target]));
2524
+ for (const location of sourceLocations.states) {
2525
+ const targetDocument = isSourceLocationForDocument(location.uri, rootDocument) ? rootDocument : await openDocumentBySourceUri(location.uri, openTextDocument);
2526
+ if (!targetDocument) continue;
2527
+ const targetSourceFile = isSourceLocationForDocument(location.uri, rootDocument) ? rootSourceFile : createSourceFile(targetDocument, targetDocument.getText());
2528
+ const stateObject = findObjectLiteralByRange(targetSourceFile, location.range);
2529
+ if (!stateObject) continue;
2530
+ const stateLiterals = [];
2531
+ collectTargetStringLiteralsFromStateObject(stateObject, location.path, stateLiterals, collectTopLevelExpressionBindings(targetSourceFile));
2532
+ for (const target of stateLiterals) {
2533
+ const key = getTargetLiteralReplacementKey(targetDocument, targetSourceFile, target.node);
2534
+ if (seen.has(key)) {
2535
+ const existing = targetByKey.get(key);
2536
+ if (existing) {
2537
+ mergeTargetSourcePaths(existing, target.sourcePaths);
2538
+ mergeInitialSourcePaths(existing, target.initialSourcePaths ?? []);
2539
+ }
2540
+ continue;
2541
+ }
2542
+ seen.add(key);
2543
+ const mappedTarget = {
2544
+ ...target,
2545
+ document: targetDocument,
2546
+ sourceFile: targetSourceFile
2547
+ };
2548
+ literals.push(mappedTarget);
2549
+ targetByKey.set(key, mappedTarget);
2550
+ }
2551
+ }
2552
+ for (const location of sourceLocations.transitionFunctions ?? []) {
2553
+ const targetDocument = isSourceLocationForDocument(location.uri, rootDocument) ? rootDocument : await openDocumentBySourceUri(location.uri, openTextDocument);
2554
+ if (!targetDocument) continue;
2555
+ const targetSourceFile = isSourceLocationForDocument(location.uri, rootDocument) ? rootSourceFile : createSourceFile(targetDocument, targetDocument.getText());
2556
+ const fn = findTransitionFunctionByRange(targetSourceFile, location.range);
2557
+ if (!fn) continue;
2558
+ const targetParameterIndexes = getTransitionTargetParameterIndexes(fn);
2559
+ if (targetParameterIndexes.length > 0) {
2560
+ const callTargets = collectTransitionCallArgumentLiterals(machineConfigNode, location.symbol, targetParameterIndexes);
2561
+ for (const target of callTargets) {
2562
+ const key = getTargetLiteralReplacementKey(rootDocument, rootSourceFile, target.node);
2563
+ if (seen.has(key)) {
2564
+ const existing = targetByKey.get(key);
2565
+ if (existing) {
2566
+ mergeTargetSourcePaths(existing, target.sourcePaths);
2567
+ mergeInitialSourcePaths(existing, target.initialSourcePaths ?? []);
2568
+ }
2569
+ continue;
2570
+ }
2571
+ seen.add(key);
2572
+ const mappedTarget = {
2573
+ ...target,
2574
+ document: rootDocument,
2575
+ sourceFile: rootSourceFile
2576
+ };
2577
+ literals.push(mappedTarget);
2578
+ targetByKey.set(key, mappedTarget);
2579
+ }
2580
+ }
2581
+ const functionLiterals = [];
2582
+ const bindings = collectTopLevelExpressionBindings(targetSourceFile);
2583
+ for (const sourcePath of location.sourcePaths) collectTargetStringLiteralsFromFunction(fn, sourcePath, functionLiterals, bindings, new Set([location.symbol]));
2584
+ for (const target of functionLiterals) {
2585
+ const key = getTargetLiteralReplacementKey(targetDocument, targetSourceFile, target.node);
2586
+ if (seen.has(key)) {
2587
+ const existing = targetByKey.get(key);
2588
+ if (existing) {
2589
+ mergeTargetSourcePaths(existing, target.sourcePaths);
2590
+ mergeInitialSourcePaths(existing, target.initialSourcePaths ?? []);
2591
+ }
2592
+ continue;
2593
+ }
2594
+ seen.add(key);
2595
+ const mappedTarget = {
2596
+ ...target,
2597
+ document: targetDocument,
2598
+ sourceFile: targetSourceFile
2599
+ };
2600
+ literals.push(mappedTarget);
2601
+ targetByKey.set(key, mappedTarget);
2602
+ }
2603
+ }
2604
+ return literals;
2605
+ }
2606
+ function findTransitionFunctionByRange(sourceFile, range) {
2607
+ const start = offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar);
2608
+ const end = offsetAtRangePosition(sourceFile.text, range.endLine, range.endChar);
2609
+ let found = null;
2610
+ const visit = (node) => {
2611
+ if (found) return;
2612
+ if ((ts$1.isArrowFunction(node) || ts$1.isFunctionExpression(node) || ts$1.isFunctionDeclaration(node)) && node.getStart(sourceFile) === start && node.getEnd() >= end) {
2613
+ found = node;
2614
+ return;
2615
+ }
2616
+ ts$1.forEachChild(node, visit);
2617
+ };
2618
+ visit(sourceFile);
2619
+ return found;
2620
+ }
2621
+ function getTransitionTargetParameterIndexes(fn) {
2622
+ const parameterIndexes = /* @__PURE__ */ new Map();
2623
+ for (const [index, parameter] of fn.parameters.entries()) if (ts$1.isIdentifier(parameter.name)) parameterIndexes.set(parameter.name.text, index);
2624
+ const indexes = /* @__PURE__ */ new Set();
2625
+ const visit = (node) => {
2626
+ if (ts$1.isObjectLiteralExpression(node)) for (const property of node.properties) {
2627
+ const targetIdentifier = ts$1.isShorthandPropertyAssignment(property) && property.name.text === "target" ? property.name : ts$1.isPropertyAssignment(property) && getPropertyNameText$1(property.name) === "target" && ts$1.isIdentifier(unwrapExpression$1(property.initializer)) ? unwrapExpression$1(property.initializer) : null;
2628
+ if (targetIdentifier) {
2629
+ const index = parameterIndexes.get(targetIdentifier.text);
2630
+ if (index !== void 0) indexes.add(index);
2631
+ }
2632
+ }
2633
+ ts$1.forEachChild(node, visit);
2634
+ };
2635
+ visit(fn);
2636
+ return [...indexes];
2637
+ }
2638
+ function collectTransitionCallArgumentLiterals(machineConfigNode, symbol, targetParameterIndexes) {
2639
+ const literals = [];
2640
+ const visitExpression = (expression, sourcePath) => {
2641
+ const current = unwrapExpression$1(expression);
2642
+ if (ts$1.isCallExpression(current) && ts$1.isIdentifier(current.expression) && current.expression.text === symbol) {
2643
+ for (const index of targetParameterIndexes) {
2644
+ const argument = current.arguments[index];
2645
+ if (argument && ts$1.isStringLiteralLike(unwrapExpression$1(argument))) addTargetLiteral(literals, unwrapExpression$1(argument), sourcePath);
2646
+ }
2647
+ return;
2648
+ }
2649
+ if (ts$1.isObjectLiteralExpression(current)) {
2650
+ for (const property of current.properties) if (ts$1.isPropertyAssignment(property)) visitExpression(property.initializer, sourcePath);
2651
+ else if (ts$1.isShorthandPropertyAssignment(property)) visitExpression(property.name, sourcePath);
2652
+ else if (ts$1.isSpreadAssignment(property)) visitExpression(property.expression, sourcePath);
2653
+ return;
2654
+ }
2655
+ if (ts$1.isArrayLiteralExpression(current)) {
2656
+ for (const element of current.elements) if (ts$1.isExpression(element)) visitExpression(element, sourcePath);
2657
+ return;
2658
+ }
2659
+ ts$1.forEachChild(current, (child) => {
2660
+ if (ts$1.isExpression(child)) visitExpression(child, sourcePath);
2661
+ });
2662
+ };
2663
+ const visitState = (stateObject, sourcePath) => {
2664
+ for (const propertyName of [
2665
+ "always",
2666
+ "after",
2667
+ "on",
2668
+ "onDone"
2669
+ ]) {
2670
+ const property = getPropertyAssignment(stateObject, propertyName);
2671
+ if (property) visitExpression(property.initializer, sourcePath);
2672
+ }
2673
+ const states = getObjectLiteralProperty(stateObject, "states");
2674
+ if (!states) return;
2675
+ for (const property of states.properties) {
2676
+ if (!ts$1.isPropertyAssignment(property)) continue;
2677
+ const key = getPropertyNameText$1(property.name);
2678
+ const child = unwrapObjectLiteralExpression(property.initializer);
2679
+ if (key && child) visitState(child, [...sourcePath, key]);
2680
+ }
2681
+ };
2682
+ visitState(machineConfigNode, []);
2683
+ return literals;
2684
+ }
2685
+ function getTargetLiteralReplacementKey(document, sourceFile, node) {
2686
+ return `${getDocumentUri(document)}:${node.getStart(sourceFile)}:${node.getEnd()}`;
2687
+ }
2688
+ function collectTargetStringLiteralsFromStateObject(stateObject, sourcePath, literals, bindings) {
2689
+ collectInitialTargetStringLiterals(stateObject, sourcePath, literals, bindings);
2690
+ for (const propertyName of [
2691
+ "always",
2692
+ "after",
2693
+ "on",
2694
+ "onDone"
2695
+ ]) {
2696
+ const property = getPropertyAssignment(stateObject, propertyName);
2697
+ if (!property) continue;
2698
+ collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals, bindings);
2699
+ }
2700
+ const statesObject = getObjectLiteralProperty(stateObject, "states");
2701
+ if (!statesObject) return;
2702
+ for (const property of statesObject.properties) {
2703
+ if (!ts$1.isPropertyAssignment(property)) continue;
2704
+ const key = getPropertyNameText$1(property.name);
2705
+ const childState = unwrapObjectLiteralExpression(property.initializer);
2706
+ if (!key || !childState) continue;
2707
+ collectTargetStringLiteralsFromStateObject(childState, [...sourcePath, key], literals, bindings);
2708
+ }
2709
+ }
2710
+ function collectTargetStringLiteralsFromExpression(expression, sourcePath, literals, bindings, seenBindings = /* @__PURE__ */ new Set()) {
2711
+ const current = unwrapExpression$1(expression);
2712
+ if (ts$1.isStringLiteralLike(current)) {
2713
+ addTargetLiteral(literals, current, sourcePath);
2714
+ return;
2715
+ }
2716
+ if (ts$1.isIdentifier(current)) {
2717
+ if (seenBindings.has(current.text)) return;
2718
+ const binding = bindings.get(current.text);
2719
+ if (binding) {
2720
+ const nextSeenBindings = new Set([...seenBindings, current.text]);
2721
+ if (isTransitionFunctionBinding(binding)) collectTargetStringLiteralsFromFunction(binding, sourcePath, literals, bindings, nextSeenBindings);
2722
+ else collectTargetStringLiteralsFromExpression(binding, sourcePath, literals, bindings, nextSeenBindings);
2723
+ }
2724
+ return;
2725
+ }
2726
+ if (ts$1.isArrowFunction(current) || ts$1.isFunctionExpression(current)) {
2727
+ collectTargetStringLiteralsFromFunction(current, sourcePath, literals, bindings, seenBindings);
2728
+ return;
2729
+ }
2730
+ if (ts$1.isCallExpression(current) && ts$1.isIdentifier(current.expression)) {
2731
+ const binding = bindings.get(current.expression.text);
2732
+ if (binding && isTransitionFunctionBinding(binding)) {
2733
+ const scopedBindings = new Map(bindings);
2734
+ for (const [index, parameter] of binding.parameters.entries()) {
2735
+ if (!ts$1.isIdentifier(parameter.name)) continue;
2736
+ const argument = current.arguments[index];
2737
+ if (argument) scopedBindings.set(parameter.name.text, argument);
2738
+ else if (parameter.initializer) scopedBindings.set(parameter.name.text, parameter.initializer);
2739
+ }
2740
+ collectTargetStringLiteralsFromFunction(binding, sourcePath, literals, scopedBindings, seenBindings);
2741
+ }
2742
+ return;
2743
+ }
2744
+ if (ts$1.isArrayLiteralExpression(current)) {
2745
+ for (const element of current.elements) if (ts$1.isExpression(element)) collectTargetStringLiteralsFromExpression(element, sourcePath, literals, bindings, seenBindings);
2746
+ return;
2747
+ }
2748
+ if (!ts$1.isObjectLiteralExpression(current)) return;
2749
+ const targetProperty = current.properties.find((property) => ts$1.isPropertyAssignment(property) && getPropertyNameText$1(property.name) === "target" || ts$1.isShorthandPropertyAssignment(property) && property.name.text === "target");
2750
+ if (targetProperty) {
2751
+ collectTargetStringLiteralsFromExpression(ts$1.isPropertyAssignment(targetProperty) ? targetProperty.initializer : targetProperty.name, sourcePath, literals, bindings, seenBindings);
2752
+ return;
2753
+ }
2754
+ for (const property of current.properties) {
2755
+ if (!ts$1.isPropertyAssignment(property)) continue;
2756
+ collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals, bindings, seenBindings);
2757
+ }
2758
+ }
2759
+ function collectTargetStringLiteralsFromFunctionBody(body, sourcePath, literals, bindings, seenBindings) {
2760
+ const visit = (node) => {
2761
+ if (ts$1.isFunctionLike(node)) return;
2762
+ if (ts$1.isReturnStatement(node) && node.expression) {
2763
+ collectTargetStringLiteralsFromExpression(node.expression, sourcePath, literals, bindings, seenBindings);
2764
+ return;
2765
+ }
2766
+ ts$1.forEachChild(node, visit);
2767
+ };
2768
+ ts$1.forEachChild(body, visit);
2769
+ }
2770
+ function isTransitionFunctionBinding(binding) {
2771
+ return ts$1.isArrowFunction(binding) || ts$1.isFunctionExpression(binding) || ts$1.isFunctionDeclaration(binding);
2772
+ }
2773
+ function collectTargetStringLiteralsFromFunction(fn, sourcePath, literals, bindings, seenBindings) {
2774
+ if (!fn.body) return;
2775
+ if (ts$1.isBlock(fn.body)) {
2776
+ collectTargetStringLiteralsFromFunctionBody(fn.body, sourcePath, literals, bindings, seenBindings);
2777
+ return;
2778
+ }
2779
+ collectTargetStringLiteralsFromExpression(fn.body, sourcePath, literals, bindings, seenBindings);
2780
+ }
2781
+ function collectTopLevelExpressionBindings(sourceFile) {
2782
+ const bindings = /* @__PURE__ */ new Map();
2783
+ for (const statement of sourceFile.statements) {
2784
+ if (ts$1.isFunctionDeclaration(statement) && statement.name) {
2785
+ bindings.set(statement.name.text, statement);
2786
+ continue;
2787
+ }
2788
+ if (!ts$1.isVariableStatement(statement)) continue;
2789
+ for (const declaration of statement.declarationList.declarations) if (ts$1.isIdentifier(declaration.name) && declaration.initializer) bindings.set(declaration.name.text, declaration.initializer);
2790
+ }
2791
+ return bindings;
2792
+ }
2793
+ function addTargetLiteral(literals, node, sourcePath, isInitialTarget = false) {
2794
+ const existing = literals.find((literal) => literal.node.getStart() === node.getStart() && literal.node.getEnd() === node.getEnd());
2795
+ if (existing) {
2796
+ mergeTargetSourcePaths(existing, [sourcePath]);
2797
+ if (isInitialTarget) mergeInitialSourcePaths(existing, [sourcePath]);
2798
+ return;
2799
+ }
2800
+ literals.push({
2801
+ node,
2802
+ sourcePaths: [sourcePath],
2803
+ ...isInitialTarget ? { initialSourcePaths: [sourcePath] } : {}
2804
+ });
2805
+ }
2806
+ function mergeInitialSourcePaths(target, initialSourcePaths) {
2807
+ if (initialSourcePaths.length === 0) return;
2808
+ const merged = target.initialSourcePaths ?? [];
2809
+ for (const sourcePath of initialSourcePaths) if (!merged.some((existing) => arePathsEqual(existing, sourcePath))) merged.push(sourcePath);
2810
+ target.initialSourcePaths = merged;
2811
+ }
2812
+ function mergeTargetSourcePaths(target, sourcePaths) {
2813
+ for (const sourcePath of sourcePaths) if (!target.sourcePaths.some((existing) => arePathsEqual(existing, sourcePath))) target.sourcePaths.push(sourcePath);
2814
+ }
2815
+ function referencesRenamedState(value, rename) {
2816
+ if (referencesRenamedSibling(value, rename.oldKey)) return true;
2817
+ return referencesRenamedAbsoluteState(value, rename);
2818
+ }
2819
+ function referencesRenamedAbsoluteState(value, rename) {
2820
+ const oldAbsolutePath = rename.oldAbsolutePath;
2821
+ return oldAbsolutePath !== void 0 && (value === oldAbsolutePath || value.startsWith(`${oldAbsolutePath}.`));
2822
+ }
2823
+ function renameStateReference(value, rename) {
2824
+ const oldAbsolutePath = rename.oldAbsolutePath;
2825
+ const newAbsolutePath = rename.newAbsolutePath;
2826
+ if (oldAbsolutePath && newAbsolutePath) {
2827
+ if (value === oldAbsolutePath) return newAbsolutePath;
2828
+ if (value.startsWith(`${oldAbsolutePath}.`)) return `${newAbsolutePath}${value.slice(oldAbsolutePath.length)}`;
2829
+ }
2830
+ return renameSiblingReference(value, rename.oldKey, rename.newKey);
2831
+ }
2832
+ function referencesRenamedSibling(value, oldKey) {
2833
+ return value === oldKey || value.startsWith(`${oldKey}.`);
2834
+ }
2835
+ function getAbsoluteStatePath(graph, nodeId) {
2836
+ const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
2837
+ const node = nodeById.get(nodeId);
2838
+ if (!node) return;
2839
+ const resolvedId = resolveGraphStateId(node, nodeById);
2840
+ return resolvedId ? `#${resolvedId}` : void 0;
2841
+ }
2842
+ function resolveGraphStateId(node, nodeById) {
2843
+ const authoredId = node.data.nodeId;
2844
+ if (authoredId && !authoredId.startsWith("$auto-")) return authoredId.replace(/^#/, "");
2845
+ if (node.parentId === null) return node.data.key;
2846
+ const parent = nodeById.get(node.parentId);
2847
+ const parentId = parent && resolveGraphStateId(parent, nodeById);
2848
+ return parentId ? `${parentId}.${node.data.key}` : node.data.key;
2849
+ }
2850
+ function renameSiblingReference(value, oldKey, newKey) {
2851
+ if (value === oldKey) return newKey;
2852
+ return value.startsWith(`${oldKey}.`) ? `${newKey}${value.slice(oldKey.length)}` : value;
2853
+ }
2854
+ function arePathsEqual(left, right) {
2855
+ return left.length === right.length && left.every((segment, index) => segment === right[index]);
2856
+ }
2857
+ function createPropertyNameReplacement(document, sourceFile, propertyName, nextName) {
2858
+ if (!isSupportedPropertyName(propertyName)) return null;
2859
+ const start = document.positionAt(propertyName.getStart(sourceFile));
2860
+ const end = document.positionAt(propertyName.getEnd());
2861
+ const sourceText = sourceFile.text.slice(propertyName.getStart(sourceFile), propertyName.getEnd());
2862
+ return {
2863
+ range: {
2864
+ startLine: start.line,
2865
+ startChar: start.character,
2866
+ endLine: end.line,
2867
+ endChar: end.character
2868
+ },
2869
+ uri: getDocumentUri(document),
2870
+ newText: formatPropertyNameText(propertyName, nextName, sourceText)
2871
+ };
2872
+ }
2873
+ function createStatePropertyRenameReplacement(document, sourceFile, property, oldKey, newKey, keySource) {
2874
+ if (keySource?.machineLocal && keySource.valueRange && isSourceRangeInDocument(sourceFile, keySource.valueRange)) return createSourceRangeReplacement(document, sourceFile, keySource.valueRange, formatStringLiteralText(sourceFile.text.slice(offsetAtRangePosition(sourceFile.text, keySource.valueRange.startLine, keySource.valueRange.startChar), offsetAtRangePosition(sourceFile.text, keySource.valueRange.endLine, keySource.valueRange.endChar)), newKey));
2875
+ if (ts$1.isPropertyAssignment(property)) {
2876
+ if (ts$1.isComputedPropertyName(property.name)) return createPropertyNameLiteralReplacement(document, sourceFile, property.name, newKey);
2877
+ return createPropertyNameReplacement(document, sourceFile, property.name, newKey);
2878
+ }
2879
+ if (!ts$1.isShorthandPropertyAssignment(property)) return null;
2880
+ const start = document.positionAt(property.name.getStart(sourceFile));
2881
+ const end = document.positionAt(property.name.getEnd());
2882
+ const sourceText = sourceFile.text.slice(property.name.getStart(sourceFile), property.name.getEnd());
2883
+ const nextPropertyName = formatPropertyNameText(property.name, newKey, sourceText);
2884
+ return {
2885
+ range: {
2886
+ startLine: start.line,
2887
+ startChar: start.character,
2888
+ endLine: end.line,
2889
+ endChar: end.character
2890
+ },
2891
+ uri: getDocumentUri(document),
2892
+ newText: `${nextPropertyName}: ${oldKey}`
2893
+ };
2894
+ }
2895
+ function createPropertyNameLiteralReplacement(document, sourceFile, propertyName, nextName) {
2896
+ const start = document.positionAt(propertyName.getStart(sourceFile));
2897
+ const end = document.positionAt(propertyName.getEnd());
2898
+ return {
2899
+ range: {
2900
+ startLine: start.line,
2901
+ startChar: start.character,
2902
+ endLine: end.line,
2903
+ endChar: end.character
2904
+ },
2905
+ uri: getDocumentUri(document),
2906
+ newText: isIdentifierText(nextName) ? nextName : JSON.stringify(nextName)
2907
+ };
2908
+ }
2909
+ function createStringInitializerRenameReplacement(document, sourceFile, expression, oldValue, newValue) {
2910
+ if (!ts$1.isStringLiteralLike(expression) || expression.text !== oldValue) return null;
2911
+ return createStringLiteralReplacement(document, sourceFile, expression, newValue);
2912
+ }
2913
+ function createStringLiteralReplacement(document, sourceFile, expression, nextValue) {
2914
+ const start = document.positionAt(expression.getStart(sourceFile));
2915
+ const end = document.positionAt(expression.getEnd());
2916
+ const sourceText = sourceFile.text.slice(expression.getStart(sourceFile), expression.getEnd());
2917
+ return {
2918
+ range: {
2919
+ startLine: start.line,
2920
+ startChar: start.character,
2921
+ endLine: end.line,
2922
+ endChar: end.character
2923
+ },
2924
+ uri: getDocumentUri(document),
2925
+ newText: formatStringLiteralText(sourceText, nextValue)
2926
+ };
2927
+ }
2928
+ function createSourceRangeReplacement(document, sourceFile, range, newText) {
2929
+ const startOffset = offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar);
2930
+ const endOffset = offsetAtRangePosition(sourceFile.text, range.endLine, range.endChar);
2931
+ const start = document.positionAt(startOffset);
2932
+ const end = document.positionAt(endOffset);
2933
+ return {
2934
+ range: {
2935
+ startLine: start.line,
2936
+ startChar: start.character,
2937
+ endLine: end.line,
2938
+ endChar: end.character
2939
+ },
2940
+ uri: getDocumentUri(document),
2941
+ newText
2942
+ };
2943
+ }
2944
+ function isSourceRangeInDocument(sourceFile, range) {
2945
+ return offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar) <= sourceFile.text.length;
2946
+ }
2947
+ function isSupportedPropertyName(propertyName) {
2948
+ if (ts$1.isIdentifier(propertyName) || ts$1.isStringLiteral(propertyName) || ts$1.isNumericLiteral(propertyName)) return true;
2949
+ if (ts$1.isComputedPropertyName(propertyName)) {
2950
+ const expression = propertyName.expression;
2951
+ return ts$1.isStringLiteral(expression) || ts$1.isNoSubstitutionTemplateLiteral(expression) || ts$1.isNumericLiteral(expression);
2952
+ }
2953
+ return false;
2954
+ }
2955
+ function formatPropertyNameText(propertyName, nextName, sourceText) {
2956
+ if (ts$1.isIdentifier(propertyName) && isIdentifierText(nextName)) return nextName;
2957
+ if (ts$1.isComputedPropertyName(propertyName)) return `[${formatStringLiteralText(sourceText.slice(1, -1), nextName)}]`;
2958
+ return formatStringLiteralText(sourceText, nextName);
2959
+ }
2960
+ function formatStringLiteralText(sourceText, nextValue) {
2961
+ const quote = sourceText.startsWith("'") ? "'" : sourceText.startsWith("`") ? "`" : "\"";
2962
+ return `${quote}${quote === "'" ? nextValue.replace(/\\/g, "\\\\").replace(/'/g, "\\'") : quote === "\"" ? nextValue.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") : nextValue.replace(/\\/g, "\\\\").replace(/`/g, "\\`")}${quote}`;
2963
+ }
2964
+ function compareReplacementRangesDescending(a, b) {
2965
+ if (a.range.startLine !== b.range.startLine) return b.range.startLine - a.range.startLine;
2966
+ return b.range.startChar - a.range.startChar;
2967
+ }
2968
+ function normalizeOverlappingReplacements(replacements) {
2969
+ const result = [];
2970
+ for (const candidate of replacements) {
2971
+ if (replacements.find((other) => other !== candidate && other.uri === candidate.uri && rangeContains(other.range, candidate.range))) continue;
2972
+ const overlappingDeletion = result.find((other) => other.uri === candidate.uri && other.newText === "" && candidate.newText === "" && rangesOverlap(other.range, candidate.range));
2973
+ if (overlappingDeletion) {
2974
+ overlappingDeletion.range = unionRanges(overlappingDeletion.range, candidate.range);
2975
+ continue;
2976
+ }
2977
+ result.push(candidate);
2978
+ }
2979
+ return result;
2980
+ }
2981
+ const position = (line, char) => [line, char];
2982
+ const comparePosition = (a, b) => a[0] - b[0] || a[1] - b[1];
2983
+ const rangeStart = (range) => position(range.startLine, range.startChar);
2984
+ const rangeEnd = (range) => position(range.endLine, range.endChar);
2985
+ const rangeContains = (outer, inner) => comparePosition(rangeStart(outer), rangeStart(inner)) <= 0 && comparePosition(rangeEnd(outer), rangeEnd(inner)) >= 0;
2986
+ const rangesOverlap = (a, b) => comparePosition(rangeStart(a), rangeEnd(b)) <= 0 && comparePosition(rangeStart(b), rangeEnd(a)) <= 0;
2987
+ function unionRanges(a, b) {
2988
+ const start = comparePosition(rangeStart(a), rangeStart(b)) <= 0 ? a : b;
2989
+ const end = comparePosition(rangeEnd(a), rangeEnd(b)) >= 0 ? a : b;
2990
+ return {
2991
+ startLine: start.startLine,
2992
+ startChar: start.startChar,
2993
+ endLine: end.endLine,
2994
+ endChar: end.endChar
2995
+ };
2996
+ }
2997
+ function printExpression(expression, sourceFile, formatting) {
2998
+ return reindentPrintedExpression(ts$1.createPrinter({ newLine: formatting.newLineKind }).printNode(ts$1.EmitHint.Expression, expression, sourceFile), formatting);
2999
+ }
3000
+ function reindentPrintedExpression(printed, formatting) {
3001
+ const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
3002
+ const lines = printed.split(/\r?\n/);
3003
+ if (lines.length <= 1) return printed;
3004
+ return lines.map((line, index) => {
3005
+ if (index === 0) return line;
3006
+ if (line.trim() === "") return "";
3007
+ const leadingSpaces = line.match(/^ */)?.[0].length ?? 0;
3008
+ const indentLevel = Math.floor(leadingSpaces / 4);
3009
+ return `${formatting.baseIndent}${formatting.indentUnit.repeat(indentLevel)}${line.slice(leadingSpaces)}`;
3010
+ }).join(lineSeparator);
3011
+ }
3012
+ function getFormattingContext(document, sourceFile, node) {
3013
+ const sourceText = sourceFile.text;
3014
+ const lineStart = getLineStartOffset(sourceText, node.getStart(sourceFile));
3015
+ const lineIndent = sourceText.slice(lineStart).match(/^[ \t]*/)?.[0] ?? "";
3016
+ const editorIndentUnit = getEditorIndentUnit(document);
3017
+ const inferredIndentUnit = inferIndentUnitFromNode(sourceText, node, sourceFile, lineIndent) ?? inferIndentUnitFromSource(sourceText);
3018
+ return {
3019
+ baseIndent: lineIndent,
3020
+ indentUnit: editorIndentUnit ?? inferredIndentUnit ?? " ",
3021
+ newLineKind: sourceText.includes("\r\n") ? ts$1.NewLineKind.CarriageReturnLineFeed : ts$1.NewLineKind.LineFeed
3022
+ };
3023
+ }
3024
+ function getFormattingContextForExpression(document, sourceFile, node) {
3025
+ const sourceText = sourceFile.text;
3026
+ const nodeStart = node.getStart(sourceFile);
3027
+ const lineStart = getLineStartOffset(sourceText, nodeStart);
3028
+ return {
3029
+ baseIndent: sourceText.slice(lineStart, nodeStart).match(/^[ \t]*/)?.[0] ?? "",
3030
+ indentUnit: getEditorIndentUnit(document) ?? inferIndentUnitFromSource(sourceText) ?? " ",
3031
+ newLineKind: sourceText.includes("\r\n") ? ts$1.NewLineKind.CarriageReturnLineFeed : ts$1.NewLineKind.LineFeed
3032
+ };
3033
+ }
3034
+ function getEditorIndentUnit(document) {
3035
+ return document.editorIndentUnit ?? null;
3036
+ }
3037
+ function inferIndentUnitFromNode(sourceText, node, sourceFile, baseIndent) {
3038
+ return getShortestIndent(sourceText.slice(node.getStart(sourceFile), node.getEnd()).split(/\r?\n/).slice(1).map((line) => line.match(/^[ \t]*/)?.[0] ?? "").filter((indent) => indent.startsWith(baseIndent)).map((indent) => indent.slice(baseIndent.length)).filter((indent) => indent.length > 0));
3039
+ }
3040
+ function inferIndentUnitFromSource(sourceText) {
3041
+ return getShortestIndent(sourceText.split(/\r?\n/).map((line) => line.match(/^[ \t]+(?=\S)/)?.[0] ?? "").filter(Boolean));
3042
+ }
3043
+ function getShortestIndent(indents) {
3044
+ if (indents.length === 0) return null;
3045
+ return indents.reduce((shortest, current) => current.length < shortest.length ? current : shortest);
3046
+ }
3047
+ function getLineStartOffset(sourceText, offset) {
3048
+ const lastNewline = sourceText.lastIndexOf("\n", offset - 1);
3049
+ if (lastNewline === -1) return 0;
3050
+ return lastNewline + 1;
3051
+ }
3052
+ function valueToExpression(value, existingExpression) {
3053
+ const rawCodeExpression = rawCodeToExpression(value);
3054
+ if (rawCodeExpression) return rawCodeExpression;
3055
+ const inlineExpression = inlineExpressionDirectiveToExpression(value);
3056
+ if (inlineExpression) return inlineExpression;
3057
+ if (value === null) return ts$1.factory.createNull();
3058
+ if (typeof value === "string") return ts$1.factory.createStringLiteral(value);
3059
+ if (typeof value === "number") {
3060
+ if (value < 0) return ts$1.factory.createPrefixUnaryExpression(ts$1.SyntaxKind.MinusToken, ts$1.factory.createNumericLiteral(Math.abs(value)));
3061
+ return ts$1.factory.createNumericLiteral(value);
3062
+ }
3063
+ if (typeof value === "boolean") return value ? ts$1.factory.createTrue() : ts$1.factory.createFalse();
3064
+ if (Array.isArray(value)) {
3065
+ const existingArray = existingExpression && ts$1.isArrayLiteralExpression(existingExpression) ? existingExpression : void 0;
3066
+ const elements = value.map((item, index) => valueToExpression(item, existingArray && ts$1.isExpression(existingArray.elements[index]) ? existingArray.elements[index] : void 0));
3067
+ if (existingArray) {
3068
+ const updatedArray = ts$1.factory.createArrayLiteralExpression(elements, true);
3069
+ ts$1.setOriginalNode(updatedArray, existingArray);
3070
+ ts$1.setTextRange(updatedArray, existingArray);
3071
+ return updatedArray;
3072
+ }
3073
+ return ts$1.factory.createArrayLiteralExpression(elements, true);
3074
+ }
3075
+ if (isMachineConfig(value)) {
3076
+ const existingObject = existingExpression && ts$1.isObjectLiteralExpression(existingExpression) ? existingExpression : void 0;
3077
+ const properties = Object.entries(value).filter(([, propertyValue]) => propertyValue !== void 0).map(([key, propertyValue]) => {
3078
+ const existingProperty = existingObject ? getPropertyAssignment(existingObject, key) : null;
3079
+ const nextInitializer = getPreservedPropertyInitializer(key, propertyValue, existingProperty?.initializer) ?? valueToExpression(propertyValue, existingProperty?.initializer);
3080
+ if (existingProperty) return ts$1.factory.updatePropertyAssignment(existingProperty, existingProperty.name, nextInitializer);
3081
+ return ts$1.factory.createPropertyAssignment(toPropertyName(key), nextInitializer);
3082
+ });
3083
+ if (existingObject) {
3084
+ const updatedObject = ts$1.factory.createObjectLiteralExpression(properties, true);
3085
+ ts$1.setOriginalNode(updatedObject, existingObject);
3086
+ ts$1.setTextRange(updatedObject, existingObject);
3087
+ return updatedObject;
3088
+ }
3089
+ return ts$1.factory.createObjectLiteralExpression(properties, true);
3090
+ }
3091
+ return ts$1.factory.createIdentifier("undefined");
3092
+ }
3093
+ function rawCodeToExpression(value) {
3094
+ if (!isRawCodeLike(value)) return null;
3095
+ return ts$1.factory.createIdentifier(value.code);
3096
+ }
3097
+ function isRawCodeLike(value) {
3098
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
3099
+ const raw = value;
3100
+ return raw.constructor?.name === "RawCode" && typeof raw.code === "string";
3101
+ }
3102
+ function inlineExpressionDirectiveToExpression(value) {
3103
+ if (!isInlineExpressionDirective(value)) return null;
3104
+ return ts$1.factory.createIdentifier(value.expr);
3105
+ }
3106
+ function isInlineExpressionDirective(value) {
3107
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
3108
+ const directive = value;
3109
+ return directive["@type"] === "code" && typeof directive.expr === "string";
3110
+ }
3111
+ function getPreservedPropertyInitializer(propertyName, nextValue, existingInitializer) {
3112
+ if (propertyName !== "description" || typeof nextValue !== "string" || !existingInitializer) return null;
3113
+ if (ts$1.isStringLiteralLike(existingInitializer)) return existingInitializer.text === nextValue ? existingInitializer : null;
3114
+ return existingInitializer;
3115
+ }
3116
+ function getPropertyAssignment(objectLiteral, propertyName) {
3117
+ for (const property of objectLiteral.properties) {
3118
+ if (!ts$1.isPropertyAssignment(property)) continue;
3119
+ if (getPropertyNameText$1(property.name) === propertyName) return property;
3120
+ }
3121
+ return null;
3122
+ }
3123
+ function toPropertyName(name) {
3124
+ return isIdentifierText(name) ? ts$1.factory.createIdentifier(name) : ts$1.factory.createStringLiteral(name);
3125
+ }
3126
+ function isIdentifierText(value) {
3127
+ return /^[$A-Z_][0-9A-Z_$]*$/i.test(value);
3128
+ }
3129
+
3130
+ //#endregion
3131
+ //#region ../editor-sync/src/internal/statelyMetadata.ts
3132
+ const STATELY_METADATA_PREFIX = "@statelyai.";
3133
+ function isPlainObject(value) {
3134
+ return !!value && typeof value === "object" && !Array.isArray(value);
3135
+ }
3136
+ function stripStatelyMetadata(value) {
3137
+ if (Array.isArray(value)) return value.map((item) => stripStatelyMetadata(item));
3138
+ if (!isPlainObject(value)) return value;
3139
+ const result = {};
3140
+ for (const [key, child] of Object.entries(value)) {
3141
+ if (key.startsWith(STATELY_METADATA_PREFIX)) continue;
3142
+ const nextChild = stripStatelyMetadata(child);
3143
+ if (isPlainObject(nextChild) && Object.keys(nextChild).length === 0 && isPlainObject(child)) continue;
3144
+ result[key] = nextChild;
3145
+ }
3146
+ return result;
3147
+ }
3148
+
3149
+ //#endregion
3150
+ //#region ../editor-sync/src/internal/adapters.ts
3151
+ const xstateAdapter = {
3152
+ id: "xstate",
3153
+ format: "xstate",
3154
+ matches(document, text) {
3155
+ return isJavaScriptOrTypeScriptFile(document.fileName) && looksLikeXStateMachine(text);
3156
+ },
3157
+ matchesFallback(document) {
3158
+ return isJavaScriptOrTypeScriptFile(document.fileName);
3159
+ },
3160
+ parseSourceToMachine(text, document, options) {
3161
+ return parseSourceToMachine(text, document, options);
3162
+ },
3163
+ collectSourceLocations(text, document, options) {
3164
+ return collectXStateSourceLocations(text, document, options);
3165
+ },
3166
+ async applyMachineToDocument(machineConfig, document, options) {
3167
+ const rootSourceLocation = collectXStateSourceLocations(document.getText(), document, { machineIndex: options?.machineIndex })?.root ?? options?.sourceLocations?.root;
3168
+ const sanitizedMachineConfig = options?.preserveStatelyMetadata === false ? stripStatelyMetadata(machineConfig) : machineConfig;
3169
+ if (!options?.patches?.length) return [];
3170
+ const replacements = await applyMachineToSourceDocuments(sanitizedMachineConfig, document, options);
3171
+ if (replacements.some(containsXStateExpressionPlaceholder) || replacements.some((replacement) => isImplicitRootReplacement(replacement, rootSourceLocation))) return [];
3172
+ return replacements;
3173
+ }
3174
+ };
3175
+ function containsXStateExpressionPlaceholder(replacement) {
3176
+ return /["']\{\{\s*[^}]+\s*\}\}["']/.test(replacement.newText);
3177
+ }
3178
+ function isImplicitRootReplacement(replacement, root) {
3179
+ if (!root) return false;
3180
+ if (replacement.uri && replacement.uri !== root.uri) return false;
3181
+ const startsBeforeRoot = replacement.range.startLine < root.range.startLine || replacement.range.startLine === root.range.startLine && replacement.range.startChar <= root.range.startChar;
3182
+ const endsAfterRoot = replacement.range.endLine > root.range.endLine || replacement.range.endLine === root.range.endLine && replacement.range.endChar >= root.range.endChar;
3183
+ return startsBeforeRoot && endsAfterRoot;
3184
+ }
3185
+ function createSerializedExportAdapter(format, matches) {
3186
+ return {
3187
+ id: format,
3188
+ format,
3189
+ matches,
3190
+ parseSourceToMachine(text) {
3191
+ return text;
3192
+ },
3193
+ async applyMachineToDocument(_machineConfig, document, options) {
3194
+ return createSerializedDocumentReplacement(document, options, format);
3195
+ }
3196
+ };
3197
+ }
3198
+ async function createSerializedDocumentReplacement(document, options, format) {
3199
+ const serialized = await options?.requestSerialized?.(format);
3200
+ if (typeof serialized !== "string") return [];
3201
+ const fullText = document.getText();
3202
+ const end = document.positionAt(fullText.length);
3203
+ return [{
3204
+ range: {
3205
+ startLine: 0,
3206
+ startChar: 0,
3207
+ endLine: end.line,
3208
+ endChar: end.character
3209
+ },
3210
+ newText: serialized
3211
+ }];
3212
+ }
3213
+ const xstateJsonAdapter = createSerializedExportAdapter("xstate-json", (document, text) => isJsonFile(document.fileName) && looksLikeXStateJson(text));
3214
+ const asyncAdapter = createSerializedExportAdapter("async", (document, text) => isJavaScriptOrTypeScriptFile(document.fileName) && looksLikeAsyncWorkflow(text));
3215
+ const xgraphAdapter = createSerializedExportAdapter("xgraph", (document, text) => isJsonFile(document.fileName) && looksLikeXGraphJson(text));
3216
+ const mermaidAdapter = createSerializedExportAdapter("mermaid", (document, text) => isMermaidFile(document.fileName) || looksLikeMermaid(text));
3217
+ const aslJsonAdapter = createSerializedExportAdapter("asl-json", (document, text) => (hasAslExtension(document.fileName) || looksLikeAmazonStatesLanguage(text)) && !isYamlFile(document.fileName));
3218
+ const aslYamlAdapter = createSerializedExportAdapter("asl-yaml", (document, text) => (hasAslExtension(document.fileName) || looksLikeAmazonStatesLanguage(text)) && isYamlFile(document.fileName));
3219
+ const adapters = [
3220
+ xstateAdapter,
3221
+ asyncAdapter,
3222
+ createSerializedExportAdapter("redux", (document, text) => isJavaScriptOrTypeScriptFile(document.fileName) && looksLikeReduxToolkit(text)),
3223
+ createSerializedExportAdapter("zustand", (document, text) => isJavaScriptOrTypeScriptFile(document.fileName) && looksLikeZustand(text)),
3224
+ aslYamlAdapter,
3225
+ aslJsonAdapter,
3226
+ mermaidAdapter,
3227
+ xgraphAdapter,
3228
+ xstateJsonAdapter
3229
+ ];
3230
+ function isJavaScriptOrTypeScriptFile(fileName) {
3231
+ return /\.(?:c|m)?(?:jsx?|tsx?)$/i.test(fileName);
3232
+ }
3233
+ function isYamlFile(fileName) {
3234
+ return /\.(?:asl\.)?ya?ml$/i.test(fileName);
3235
+ }
3236
+ function hasAslExtension(fileName) {
3237
+ return /\.asl\.(?:jsonc?|ya?ml)$/i.test(fileName);
3238
+ }
3239
+ function isJsonFile(fileName) {
3240
+ return /\.jsonc?$/i.test(fileName);
3241
+ }
3242
+ function isMermaidFile(fileName) {
3243
+ return /\.(?:mmd|mermaid)$/i.test(fileName);
3244
+ }
3245
+ function stripMermaidFrontmatter(text) {
3246
+ return text.replace(/^\s*---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
3247
+ }
3248
+ function looksLikeMermaid(text) {
3249
+ return /^\s*(?:stateDiagram(?:-v2)?|flowchart(?:\s+(?:TB|TD|BT|LR|RL))?|graph\s+(?:TB|TD|BT|LR|RL))\b/.test(stripMermaidFrontmatter(text));
3250
+ }
3251
+ function looksLikeAmazonStatesLanguage(text) {
3252
+ return /(^|\s|["'])StartAt["']?\s*:/m.test(text) && /(^|\s|["'])States["']?\s*:/m.test(text);
3253
+ }
3254
+ function looksLikeXStateJson(text) {
3255
+ try {
3256
+ const value = JSON.parse(text);
3257
+ return Boolean(value && typeof value === "object" && !Array.isArray(value) && "states" in value);
3258
+ } catch {
3259
+ return false;
3260
+ }
3261
+ }
3262
+ function looksLikeXGraphJson(text) {
3263
+ try {
3264
+ const value = JSON.parse(text);
3265
+ return Boolean(value && typeof value === "object" && !Array.isArray(value) && Array.isArray(value.nodes) && Array.isArray(value.edges));
3266
+ } catch {
3267
+ return false;
3268
+ }
3269
+ }
3270
+ function looksLikeReduxToolkit(text) {
3271
+ return /\bcreateSlice\s*\(/.test(text) && /@reduxjs\/toolkit/.test(text);
3272
+ }
3273
+ function looksLikeZustand(text) {
3274
+ return /\bcreate\s*\(\s*\(/.test(text) && /from\s+["']zustand["']/.test(text);
3275
+ }
3276
+ function looksLikeAsyncWorkflow(text) {
3277
+ return /\bawait\b/.test(text) && (/\basync\s+function\b/.test(text) || /\basync\s*\([^)]*\)\s*=>/.test(text) || /\basync\s+\w+\s*=>/.test(text));
3278
+ }
3279
+ function looksLikeXStateMachine(text) {
3280
+ return /\b(?:createMachine|createMachineFromConfig)\s*\(/.test(text) || /\bMachine\s*\(/.test(text) || /\.createMachine\s*\(/.test(text);
3281
+ }
3282
+ function getSyncAdapter(document, text = "") {
3283
+ const resolvedText = text || document.getText?.() || "";
3284
+ const matched = adapters.find((adapter) => adapter.matches(document, resolvedText));
3285
+ if (matched) return matched;
3286
+ const fallback = adapters.find((adapter) => adapter.matchesFallback?.(document, resolvedText));
3287
+ if (fallback) return fallback;
3288
+ throw new Error(`Unsupported document for Stately sync: ${document.fileName}`);
3289
+ }
3290
+ function parseDocumentToMachine(document, options = {}) {
3291
+ const text = document.getText();
3292
+ const adapter = getSyncAdapter(document, text);
3293
+ return {
3294
+ adapter,
3295
+ format: adapter.format,
3296
+ machine: adapter.parseSourceToMachine(text, document, options),
3297
+ sourceLocations: adapter.collectSourceLocations?.(text, document, options)
3298
+ };
3299
+ }
3300
+
3301
+ //#endregion
3302
+ //#region src/pushMerge.ts
3303
+ const GEOMETRY_KEYS = [
3304
+ "x",
3305
+ "y",
3306
+ "width",
3307
+ "height"
3308
+ ];
3309
+ const DEFAULT_NODE_SIZE = {
3310
+ width: 160,
3311
+ height: 64
3312
+ };
3313
+ const DEFAULT_ANNOTATION_SIZE = {
3314
+ width: 240,
3315
+ height: 120
3316
+ };
3317
+ const NEW_NODE_GAP = 80;
3318
+ const MAX_CONCURRENT_MERGE_ATTEMPTS = 3;
3319
+ function indexBySemanticId(normalized, original) {
3320
+ const bySemanticId = /* @__PURE__ */ new Map();
3321
+ normalized.forEach((entity, index) => {
3322
+ const source = original[index];
3323
+ if (source && !bySemanticId.has(entity.id)) bySemanticId.set(entity.id, source);
3324
+ });
3325
+ return bySemanticId;
3326
+ }
3327
+ function carryGeometry(target, remote) {
3328
+ for (const key of GEOMETRY_KEYS) if (remote[key] !== void 0) target[key] = remote[key];
3329
+ }
3330
+ function collectDigraphNodes(node, into) {
3331
+ into.set(node.id, node);
3332
+ node.nodes.forEach((child) => collectDigraphNodes(child, into));
3333
+ return into;
3334
+ }
3335
+ function restoreNodeFields(node, remoteNodesById, remoteNodeIdByLocalId) {
3336
+ const structuralChildren = [...node.nodes];
3337
+ const remoteId = remoteNodeIdByLocalId.get(node.id);
3338
+ const remote = remoteId ? remoteNodesById.get(remoteId) : void 0;
3339
+ if (remote) {
3340
+ if (remote.uniqueId !== void 0) node.uniqueId = remote.uniqueId;
3341
+ if (remote.data.assets !== void 0) node.data.assets = structuredClone(remote.data.assets);
3342
+ if (remote.data.blockFlowDirection !== void 0) node.data.blockFlowDirection = remote.data.blockFlowDirection;
3343
+ if (remote.data.order !== void 0) node.data.order = remote.data.order;
3344
+ const existingIds = new Set(node.nodes.map((child) => child.id));
3345
+ const annotations = remote.nodes.filter((child) => child.data.type === "annotation" && !existingIds.has(child.id));
3346
+ node.nodes.push(...annotations.map((annotation) => structuredClone(annotation)));
3347
+ }
3348
+ structuralChildren.forEach((child) => restoreNodeFields(child, remoteNodesById, remoteNodeIdByLocalId));
3349
+ }
3350
+ function restoreEdgeFields(edges, remoteEdgesById, remoteEdgeIdByLocalId) {
3351
+ for (const edge of edges) {
3352
+ const remoteId = remoteEdgeIdByLocalId.get(edge.id);
3353
+ const remote = remoteId ? remoteEdgesById.get(remoteId) : void 0;
3354
+ if (remote) {
3355
+ if (remote.uniqueId !== void 0) edge.uniqueId = remote.uniqueId;
3356
+ if (remote.data.assets !== void 0) edge.data.assets = structuredClone(remote.data.assets);
3357
+ }
3358
+ }
3359
+ }
3360
+ function hasFinitePoint(value) {
3361
+ return Boolean(value && Number.isFinite(value.x) && Number.isFinite(value.y));
3362
+ }
3363
+ function hasFiniteSize(value) {
3364
+ return Boolean(value && Number.isFinite(value.width) && Number.isFinite(value.height) && value.width > 0 && value.height > 0);
3365
+ }
3366
+ function ensureCompleteNodeGeometry(rootNode) {
3367
+ if (!hasFinitePoint(rootNode.position)) rootNode.position = {
3368
+ x: 0,
3369
+ y: 0
3370
+ };
3371
+ if (!hasFiniteSize(rootNode.size)) rootNode.size = {
3372
+ width: 320,
3373
+ height: 200
3374
+ };
3375
+ const visit = (parent) => {
3376
+ const parentPosition = parent.position;
3377
+ let nextX = parentPosition.x + 40;
3378
+ for (const child of parent.nodes) if (hasFinitePoint(child.position) && hasFiniteSize(child.size)) nextX = Math.max(nextX, child.position.x + child.size.width + NEW_NODE_GAP);
3379
+ for (const child of parent.nodes) {
3380
+ const childSize = hasFiniteSize(child.size) ? child.size : child.data.type === "annotation" ? { ...DEFAULT_ANNOTATION_SIZE } : { ...DEFAULT_NODE_SIZE };
3381
+ child.size = childSize;
3382
+ if (!hasFinitePoint(child.position)) {
3383
+ child.position = {
3384
+ x: nextX,
3385
+ y: parentPosition.y + 80
3386
+ };
3387
+ nextX += childSize.width + NEW_NODE_GAP;
3388
+ }
3389
+ visit(child);
3390
+ }
3391
+ };
3392
+ visit(rootNode);
3393
+ }
3394
+ function mergeLocalGraphIntoRemoteDefinition(localGraph, remoteDefinition) {
3395
+ const remoteNodesById = collectDigraphNodes(remoteDefinition.rootNode, /* @__PURE__ */ new Map());
3396
+ const annotationIds = new Set([...remoteNodesById.values()].filter((node) => node.data.type === "annotation").map((node) => node.id));
3397
+ const remoteGraph = fromStudioMachine(remoteDefinition);
3398
+ remoteGraph.nodes = remoteGraph.nodes.filter((node) => !annotationIds.has(node.id));
3399
+ remoteGraph.edges = remoteGraph.edges.filter((edge) => !annotationIds.has(edge.sourceId) && !annotationIds.has(edge.targetId));
3400
+ const { base, compare, summary } = diffGraphsSemantically(remoteGraph, localGraph);
3401
+ const remoteNodesBySemanticId = indexBySemanticId(base.nodes, remoteGraph.nodes);
3402
+ const remoteEdgesBySemanticId = indexBySemanticId(base.edges, remoteGraph.edges);
3403
+ const merged = structuredClone(localGraph);
3404
+ const remoteNodeIdByLocalId = /* @__PURE__ */ new Map();
3405
+ const remoteEdgeIdByLocalId = /* @__PURE__ */ new Map();
3406
+ merged.nodes.forEach((node, index) => {
3407
+ const semanticId = compare.nodes[index]?.id;
3408
+ const remote = semanticId ? remoteNodesBySemanticId.get(semanticId) : void 0;
3409
+ if (!remote) return;
3410
+ remoteNodeIdByLocalId.set(node.id, remote.id);
3411
+ carryGeometry(node, remote);
3412
+ if (node.data.color === void 0 && remote.data?.color !== void 0) node.data.color = remote.data.color;
3413
+ });
3414
+ merged.edges.forEach((edge, index) => {
3415
+ const semanticId = compare.edges[index]?.id;
3416
+ const remote = semanticId ? remoteEdgesBySemanticId.get(semanticId) : void 0;
3417
+ if (!remote) return;
3418
+ remoteEdgeIdByLocalId.set(edge.id, remote.id);
3419
+ carryGeometry(edge, remote);
3420
+ if (edge.data.color === void 0 && remote.data?.color !== void 0) edge.data.color = remote.data.color;
3421
+ });
3422
+ const definition = toStudioMachine(merged);
3423
+ restoreNodeFields(definition.rootNode, remoteNodesById, remoteNodeIdByLocalId);
3424
+ restoreEdgeFields(definition.edges, new Map(remoteDefinition.edges.map((edge) => [edge.id, edge])), remoteEdgeIdByLocalId);
3425
+ ensureCompleteNodeGeometry(definition.rootNode);
3426
+ return {
3427
+ definition: {
3428
+ ...remoteDefinition,
3429
+ ...definition,
3430
+ context: remoteDefinition.context
3431
+ },
3432
+ summary
3433
+ };
3434
+ }
3435
+ function isRecord(value) {
3436
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3437
+ }
3438
+ function isDigraphNodeConfig(value) {
3439
+ if (!isRecord(value) || typeof value.id !== "string") return false;
3440
+ if (!isRecord(value.data) || typeof value.data.key !== "string") return false;
3441
+ if (!Array.isArray(value.data.entry) || !Array.isArray(value.data.exit) || !Array.isArray(value.data.invoke) || !Array.isArray(value.data.tags) || !Array.isArray(value.nodes)) return false;
3442
+ return value.nodes.every(isDigraphNodeConfig);
3443
+ }
3444
+ function isDigraphEdgeConfig(value) {
3445
+ return isRecord(value) && typeof value.id === "string" && typeof value.source === "string" && (value.target === void 0 || typeof value.target === "string") && isRecord(value.data) && isRecord(value.data.eventTypeData) && Array.isArray(value.data.actions);
3446
+ }
3447
+ function isDigraphConfig(value) {
3448
+ if (!isRecord(value) || typeof value.id !== "string" || !isDigraphNodeConfig(value.rootNode) || !Array.isArray(value.edges) || !value.edges.every(isDigraphEdgeConfig)) return false;
3449
+ if (value.implementations !== void 0) {
3450
+ if (!isRecord(value.implementations)) return false;
3451
+ if (!isRecord(value.implementations.actions) || !isRecord(value.implementations.actors) || !isRecord(value.implementations.guards)) return false;
3452
+ }
3453
+ return true;
3454
+ }
3455
+ function requireDigraphConfig(machineId, value) {
3456
+ if (!isDigraphConfig(value)) throw new Error(`Cannot safely push machine "${machineId}": its remote definition is invalid.`);
3457
+ return value;
3458
+ }
3459
+ function stableStringify(value) {
3460
+ return JSON.stringify(value, (_key, item) => {
3461
+ if (isRecord(item)) return Object.fromEntries(Object.entries(item).sort(([left], [right]) => left.localeCompare(right)));
3462
+ return item;
3463
+ });
3464
+ }
3465
+ function definitionsMatch(left, right) {
3466
+ return stableStringify(left) === stableStringify(right);
3467
+ }
3468
+ async function updateMachineDefinition(client, machineId, localGraph) {
3469
+ if (typeof client.machines?.get !== "function") return client.machines.update({
3470
+ id: machineId,
3471
+ definition: toStudioMachine(localGraph)
3472
+ });
3473
+ let remoteRecord = await client.machines.get(machineId);
3474
+ for (let attempt = 0; attempt < MAX_CONCURRENT_MERGE_ATTEMPTS; attempt += 1) {
3475
+ const remoteDefinition = requireDigraphConfig(machineId, remoteRecord.definition);
3476
+ const mergedDefinition = mergeLocalGraphIntoRemoteDefinition(localGraph, remoteDefinition).definition;
3477
+ const latestRecord = await client.machines.get(machineId);
3478
+ requireDigraphConfig(machineId, latestRecord.definition);
3479
+ if (definitionsMatch(remoteDefinition, latestRecord.definition)) return client.machines.update({
3480
+ id: machineId,
3481
+ definition: mergedDefinition
3482
+ });
3483
+ remoteRecord = latestRecord;
3484
+ }
3485
+ throw new Error(`Cannot safely push machine "${machineId}": its remote definition kept changing during the push. Try again after Studio edits have settled.`);
3486
+ }
3487
+
3488
+ //#endregion
3489
+ //#region src/sync.ts
3490
+ const execFileAsync = promisify(execFile);
3491
+ const MAX_CAPTURED_LOCAL_MACHINES = 100;
3492
+ var PullSourceReconciliationError = class extends Error {
3493
+ code = "source_reconciliation_failed";
3494
+ constructor(message) {
3495
+ super(message);
3496
+ this.name = "PullSourceReconciliationError";
3497
+ }
3498
+ };
3499
+ const INLINE_EXPRESSION_FIELD_SET = new Set(INLINE_EXPRESSION_DIRECTIVE_FIELDS);
3500
+ async function extractMachinesFromLocalSource(sourcePath, contents, machineIndex) {
3501
+ try {
3502
+ return { machines: extractMachineConfigsFromAst(sourcePath, parseSourceToMachine(contents, createTextDocument(sourcePath, contents), {
3503
+ machineIndex,
3504
+ resolver: createFileSourceDocumentResolver()
3505
+ }), machineIndex) };
3506
+ } catch (error) {
3507
+ return {
3508
+ machines: [],
3509
+ error: error instanceof Error ? error.message : String(error)
3510
+ };
3511
+ }
3512
+ }
3513
+ function isInvalidLocalMachineDefinitionError(message) {
3514
+ return /No initial state specified for compound state node/.test(message) || /Try adding \{\s*initial:\s*['"`]/.test(message);
3515
+ }
3516
+ function formatLocalMachineExtractionIssue(message) {
3517
+ if (isInvalidLocalMachineDefinitionError(message)) return `Invalid local machine definition: ${message}`;
3518
+ return `Could not extract a local machine from this file: ${message}`;
3519
+ }
3520
+ function extractMachineConfigsFromAst(fileName, sourceText, selectedMachineIndex) {
3521
+ const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(fileName));
3522
+ const bindings = collectLocalBindings(sourceFile);
3523
+ const machines = [];
3524
+ let currentMachineIndex = 0;
3525
+ const visit = (node) => {
3526
+ if (selectedMachineIndex === void 0 && machines.length >= MAX_CAPTURED_LOCAL_MACHINES) return;
3527
+ if (!ts.isCallExpression(node) || !isCreateMachineExpression(node.expression)) {
3528
+ ts.forEachChild(node, visit);
3529
+ return;
3530
+ }
3531
+ const machineIndex = currentMachineIndex;
3532
+ currentMachineIndex += 1;
3533
+ if (selectedMachineIndex !== void 0 && machineIndex !== selectedMachineIndex) return;
3534
+ const [firstArgument] = node.arguments;
3535
+ if (!firstArgument || !ts.isExpression(firstArgument)) return;
3536
+ const config = evaluateExpression(firstArgument, sourceFile, bindings, /* @__PURE__ */ new Set());
3537
+ if (!config || typeof config !== "object" || Array.isArray(config)) return;
3538
+ machines.push({
3539
+ config,
3540
+ _type: ts.isPropertyAccessExpression(unwrapExpression(node.expression)) ? "setup.createMachine" : "createMachine"
3541
+ });
3542
+ };
3543
+ ts.forEachChild(sourceFile, visit);
3544
+ return machines;
3545
+ }
3546
+ function countSourceMachines(fileName, sourceText) {
3547
+ const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(fileName));
3548
+ let count = 0;
3549
+ const visit = (node) => {
3550
+ if (ts.isCallExpression(node) && isCreateMachineExpression(node.expression)) count += 1;
3551
+ ts.forEachChild(node, visit);
3552
+ };
3553
+ visit(sourceFile);
3554
+ return count;
3555
+ }
3556
+ function collectLocalBindings(sourceFile) {
3557
+ const bindings = /* @__PURE__ */ new Map();
3558
+ for (const statement of sourceFile.statements) {
3559
+ if (ts.isVariableStatement(statement)) {
3560
+ for (const declaration of statement.declarationList.declarations) {
3561
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer) continue;
3562
+ bindings.set(declaration.name.text, {
3563
+ kind: "value",
3564
+ expression: declaration.initializer
3565
+ });
3566
+ }
3567
+ continue;
3568
+ }
3569
+ if (!ts.isEnumDeclaration(statement)) continue;
3570
+ let nextNumericValue = 0;
3571
+ for (const member of statement.members) {
3572
+ const memberName = getPropertyNameText(member.name);
3573
+ if (!memberName) continue;
3574
+ const symbol = `${statement.name.text}.${memberName}`;
3575
+ if (!member.initializer) {
3576
+ bindings.set(symbol, {
3577
+ kind: "enumMember",
3578
+ value: nextNumericValue
3579
+ });
3580
+ nextNumericValue += 1;
3581
+ continue;
3582
+ }
3583
+ const value = evaluateExpression(member.initializer, sourceFile, bindings, /* @__PURE__ */ new Set());
3584
+ if (typeof value === "string" || typeof value === "number") {
3585
+ bindings.set(symbol, {
3586
+ kind: "enumMember",
3587
+ value
3588
+ });
3589
+ if (typeof value === "number") nextNumericValue = value + 1;
3590
+ }
3591
+ }
3592
+ }
3593
+ return bindings;
3594
+ }
3595
+ function evaluateExpression(expression, sourceFile, bindings, seenBindings) {
3596
+ const unwrapped = unwrapExpression(expression);
3597
+ if (ts.isStringLiteral(unwrapped) || ts.isNoSubstitutionTemplateLiteral(unwrapped)) return unwrapped.text;
3598
+ if (ts.isNumericLiteral(unwrapped)) return Number(unwrapped.text);
3599
+ if (unwrapped.kind === ts.SyntaxKind.TrueKeyword) return true;
3600
+ if (unwrapped.kind === ts.SyntaxKind.FalseKeyword) return false;
3601
+ if (unwrapped.kind === ts.SyntaxKind.NullKeyword) return null;
3602
+ if (ts.isIdentifier(unwrapped)) {
3603
+ if (unwrapped.text === "undefined") return;
3604
+ const binding = bindings.get(unwrapped.text);
3605
+ if (!binding || binding.kind !== "value" || seenBindings.has(unwrapped.text)) return unwrapped.getText(sourceFile);
3606
+ const nextSeen = new Set(seenBindings);
3607
+ nextSeen.add(unwrapped.text);
3608
+ return evaluateExpression(binding.expression, sourceFile, bindings, nextSeen);
3609
+ }
3610
+ if (ts.isPropertyAccessExpression(unwrapped) && ts.isIdentifier(unwrapped.expression)) {
3611
+ const binding = bindings.get(`${unwrapped.expression.text}.${unwrapped.name.text}`);
3612
+ if (binding?.kind === "enumMember") return binding.value;
3613
+ return unwrapped.getText(sourceFile);
3614
+ }
3615
+ if (ts.isArrayLiteralExpression(unwrapped)) return unwrapped.elements.map((element) => ts.isSpreadElement(element) ? evaluateExpression(element.expression, sourceFile, bindings, seenBindings) : evaluateExpression(element, sourceFile, bindings, seenBindings));
3616
+ if (ts.isObjectLiteralExpression(unwrapped)) {
3617
+ const result = {};
3618
+ for (const property of unwrapped.properties) {
3619
+ if (ts.isSpreadAssignment(property)) {
3620
+ const spreadValue = evaluateExpression(property.expression, sourceFile, bindings, seenBindings);
3621
+ if (spreadValue && typeof spreadValue === "object" && !Array.isArray(spreadValue)) Object.assign(result, spreadValue);
3622
+ continue;
3623
+ }
3624
+ if (ts.isShorthandPropertyAssignment(property)) {
3625
+ result[property.name.text] = evaluateExpression(property.name, sourceFile, bindings, seenBindings);
3626
+ continue;
3627
+ }
3628
+ if (!ts.isPropertyAssignment(property)) continue;
3629
+ const key = resolvePropertyNameValue(property.name, sourceFile, bindings, seenBindings);
3630
+ if (key == null) continue;
3631
+ const fieldName = String(key);
3632
+ if (shouldPreserveInlineExpression(fieldName, property.initializer, sourceFile, bindings, seenBindings)) {
3633
+ result[fieldName] = createInlineExpressionDirective(property.initializer.getText(sourceFile));
3634
+ continue;
3635
+ }
3636
+ result[fieldName] = evaluateExpression(property.initializer, sourceFile, bindings, seenBindings);
3637
+ }
3638
+ return result;
3639
+ }
3640
+ if (ts.isPrefixUnaryExpression(unwrapped)) {
3641
+ const operand = evaluateExpression(unwrapped.operand, sourceFile, bindings, seenBindings);
3642
+ if (typeof operand !== "number") return unwrapped.getText(sourceFile);
3643
+ switch (unwrapped.operator) {
3644
+ case ts.SyntaxKind.MinusToken: return -operand;
3645
+ case ts.SyntaxKind.PlusToken: return operand;
3646
+ default: return unwrapped.getText(sourceFile);
3647
+ }
3648
+ }
3649
+ if (ts.isTemplateExpression(unwrapped)) {
3650
+ let value = unwrapped.head.text;
3651
+ for (const span of unwrapped.templateSpans) {
3652
+ const expressionValue = evaluateExpression(span.expression, sourceFile, bindings, seenBindings);
3653
+ value += String(expressionValue ?? "");
3654
+ value += span.literal.text;
3655
+ }
3656
+ return value;
3657
+ }
3658
+ return unwrapped.getText(sourceFile);
3659
+ }
3660
+ function shouldPreserveInlineExpression(fieldName, expression, sourceFile, bindings, seenBindings) {
3661
+ if (!INLINE_EXPRESSION_FIELD_SET.has(fieldName)) return false;
3662
+ const unwrapped = unwrapExpression(expression);
3663
+ if (ts.isIdentifier(unwrapped)) {
3664
+ const binding = bindings.get(unwrapped.text);
3665
+ if (!binding || binding.kind !== "value" || seenBindings.has(unwrapped.text)) return true;
3666
+ const nextSeen = new Set(seenBindings);
3667
+ nextSeen.add(unwrapped.text);
3668
+ return shouldPreserveInlineExpression(fieldName, binding.expression, sourceFile, bindings, nextSeen);
3669
+ }
3670
+ if (ts.isStringLiteral(unwrapped) || ts.isNoSubstitutionTemplateLiteral(unwrapped) || ts.isNumericLiteral(unwrapped) || unwrapped.kind === ts.SyntaxKind.TrueKeyword || unwrapped.kind === ts.SyntaxKind.FalseKeyword || unwrapped.kind === ts.SyntaxKind.NullKeyword || ts.isObjectLiteralExpression(unwrapped) || ts.isArrayLiteralExpression(unwrapped)) return false;
3671
+ return unwrapped.getText(sourceFile).trim().length > 0;
3672
+ }
3673
+ function createInlineExpressionDirective(expr) {
3674
+ return {
3675
+ "@type": "code",
3676
+ lang: "ts",
3677
+ expr
3678
+ };
3679
+ }
3680
+ function resolvePropertyNameValue(name, sourceFile, bindings, seenBindings) {
3681
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
3682
+ if (!ts.isComputedPropertyName(name)) return null;
3683
+ const value = evaluateExpression(name.expression, sourceFile, bindings, seenBindings);
3684
+ if (typeof value === "string" || typeof value === "number") return value;
3685
+ return name.getText(sourceFile);
3686
+ }
3687
+ function isCreateMachineExpression(expression) {
3688
+ const unwrapped = unwrapExpression(expression);
3689
+ return ts.isIdentifier(unwrapped) && unwrapped.text === "createMachine" || ts.isPropertyAccessExpression(unwrapped) && unwrapped.name.text === "createMachine";
3690
+ }
3691
+ function unwrapExpression(expression) {
3692
+ let current = expression;
3693
+ for (;;) {
3694
+ if (ts.isParenthesizedExpression(current)) {
3695
+ current = current.expression;
3696
+ continue;
3697
+ }
3698
+ if (ts.isAsExpression(current) || ts.isSatisfiesExpression(current)) {
3699
+ current = current.expression;
3700
+ continue;
3701
+ }
3702
+ if (ts.isTypeAssertionExpression(current) || ts.isNonNullExpression(current)) {
3703
+ current = current.expression;
3704
+ continue;
3705
+ }
3706
+ return current;
3707
+ }
3708
+ }
3709
+ function getPropertyNameText(name) {
3710
+ if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
3711
+ return null;
3712
+ }
3713
+ function getScriptKind(fileName) {
3714
+ if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
3715
+ if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
3716
+ if (fileName.endsWith(".js")) return ts.ScriptKind.JS;
3717
+ return ts.ScriptKind.TS;
3718
+ }
3719
+ function isUrl(value) {
3720
+ try {
3721
+ const url = new URL(value);
3722
+ return url.protocol === "http:" || url.protocol === "https:";
3723
+ } catch {
3724
+ return false;
3725
+ }
3726
+ }
3727
+ async function fileExists(filePath) {
3728
+ try {
3729
+ await fs.access(filePath);
3730
+ return true;
3731
+ } catch {
3732
+ return false;
3733
+ }
1151
3734
  }
1152
3735
  function parseGitHubRemote(remoteUrl) {
1153
3736
  const httpsMatch = remoteUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
@@ -1357,14 +3940,19 @@ async function pushLocalMachineLinks(options) {
1357
3940
  continue;
1358
3941
  }
1359
3942
  if (attachment.pragma?.id && !options.relink) {
1360
- const updatedMachine = await client.machines.update({
1361
- id: attachment.pragma.id,
1362
- definition: toStudioMachine(fromXStateConfig(extractedMachine.config))
1363
- });
1364
- updated.push({
1365
- machineIndex,
1366
- machine: updatedMachine
1367
- });
3943
+ const localGraph = fromXStateConfig(extractedMachine.config);
3944
+ try {
3945
+ const updatedMachine = await updateMachineDefinition(client, attachment.pragma.id, localGraph);
3946
+ updated.push({
3947
+ machineIndex,
3948
+ machine: updatedMachine
3949
+ });
3950
+ } catch (error) {
3951
+ skipped.push({
3952
+ machineIndex,
3953
+ reason: error instanceof Error ? error.message : String(error)
3954
+ });
3955
+ }
1368
3956
  continue;
1369
3957
  }
1370
3958
  const machine = await client.machines.create({
@@ -1394,17 +3982,24 @@ async function pushLocalMachineLinks(options) {
1394
3982
  ...outputPath ? { outputPath } : {}
1395
3983
  };
1396
3984
  }
1397
- async function resolveLocalFile(locator, options) {
3985
+ async function resolveLocalFile(locator, options, machineIndex = 0) {
1398
3986
  const filePath = path.resolve(options.cwd ?? process.cwd(), locator);
1399
3987
  const contents = await fs.readFile(filePath, "utf8");
1400
3988
  const extension = path.extname(filePath).toLowerCase();
1401
3989
  if (extension === ".ts" || extension === ".tsx" || extension === ".js" || extension === ".jsx") {
1402
- const config = (await (options.client ?? createStatelyClient({
1403
- apiKey: options.apiKey,
1404
- baseUrl: options.baseUrl,
1405
- fetch: options.fetch
1406
- })).code.extractMachines(contents)).machines[0]?.config;
1407
- if (!config) throw new Error(`No machines extracted from ${filePath}`);
3990
+ const localExtraction = await extractMachinesFromLocalSource(filePath, contents, machineIndex);
3991
+ let config = localExtraction.machines[0]?.config;
3992
+ const extractionIssue = localExtraction.error;
3993
+ if (!config) {
3994
+ const extracted = await (options.client ?? createStatelyClient({
3995
+ apiKey: options.apiKey,
3996
+ baseUrl: options.baseUrl,
3997
+ fetch: options.fetch
3998
+ })).code.extractMachines(contents);
3999
+ const indexedMachine = extracted.machines.find((machine) => machine.machineIndex === machineIndex);
4000
+ config = extracted.machines.some((machine) => machine.machineIndex !== void 0) ? indexedMachine?.config : extracted.machines[machineIndex]?.config;
4001
+ }
4002
+ if (!config) throw new Error(extractionIssue ? `No machines extracted from ${filePath}: ${formatLocalMachineExtractionIssue(extractionIssue)}` : `No machine at index ${machineIndex} was extracted from ${filePath}`);
1408
4003
  return {
1409
4004
  kind: "local-file",
1410
4005
  locator: filePath,
@@ -1503,7 +4098,7 @@ function summarizeDiff(diff) {
1503
4098
  async function planSync(options) {
1504
4099
  const source = await resolveSyncInput(options.source, options);
1505
4100
  const target = await resolveSyncInput(options.target, options);
1506
- const diff = getDiff(source.graph, target.graph);
4101
+ const { diff } = diffGraphsSemantically(source.graph, target.graph);
1507
4102
  return {
1508
4103
  source,
1509
4104
  target,
@@ -1517,17 +4112,83 @@ async function pullSync(options) {
1517
4112
  const outputPath = path.resolve(options.cwd ?? process.cwd(), options.target);
1518
4113
  const fallbackFormat = inferWritableTargetFormat(outputPath);
1519
4114
  let targetFormat = fallbackFormat;
1520
- if (await fileExists(outputPath)) try {
1521
- targetFormat = (await resolveLocalFile(options.target, options)).format;
4115
+ let existingTarget = null;
4116
+ const targetExists = await fileExists(outputPath);
4117
+ let machineIndex = options.machineIndex ?? 0;
4118
+ if (targetExists && options.machineIndex === void 0 && source.remoteMachineId) {
4119
+ const matchingIndex = findStatelyPragmaAttachments(await fs.readFile(outputPath, "utf8"), outputPath).findIndex((attachment) => attachment.pragma?.id === source.remoteMachineId);
4120
+ if (matchingIndex >= 0) machineIndex = matchingIndex;
4121
+ }
4122
+ if (targetExists) try {
4123
+ const target = await resolveLocalFile(options.target, options, machineIndex);
4124
+ existingTarget = target;
4125
+ targetFormat = target.format;
1522
4126
  } catch (error) {
1523
4127
  if (!fallbackFormat) throw error;
4128
+ const contents = await fs.readFile(outputPath, "utf8");
4129
+ if (fallbackFormat === "xstate" && contents.trim() !== "" && !options.force) throw new PullSourceReconciliationError(`Could not update ${outputPath} surgically: ${error instanceof Error ? error.message : String(error)} Pass --force to replace the file.`);
1524
4130
  }
1525
4131
  if (!targetFormat) throw new Error(`Could not infer a writable target format from ${outputPath}. Use an existing digraph/graph file or a .digraph.json/.graph.json target.`);
1526
- const serialized = serializeGraph(source.graph, targetFormat, {
1527
- remoteMachineId: source.remoteMachineId,
1528
- targetPath: outputPath
1529
- });
1530
- await fs.writeFile(outputPath, serialized, "utf8");
4132
+ let wroteSurgically = false;
4133
+ if (targetFormat === "xstate" && existingTarget?.format === "xstate") {
4134
+ const currentSource = await fs.readFile(outputPath, "utf8");
4135
+ const document = createTextDocument(outputPath, currentSource);
4136
+ let parsedTarget = null;
4137
+ try {
4138
+ parsedTarget = parseDocumentToMachine(document, {
4139
+ machineIndex,
4140
+ resolver: createFileSourceDocumentResolver()
4141
+ });
4142
+ } catch (error) {
4143
+ if (!options.force) throw new PullSourceReconciliationError(`Could not update ${outputPath} surgically: ${error instanceof Error ? error.message : String(error)} The source file was left unchanged. Pass --force to replace the file.`);
4144
+ }
4145
+ if (parsedTarget) {
4146
+ const semanticResult = diffGraphsSemantically(existingTarget.graph, source.graph);
4147
+ const alignedSource = alignCompareGraphIds(existingTarget.graph, source.graph, semanticResult.base, semanticResult.compare);
4148
+ const patchResult = graphChangeToPatchesResult(existingTarget.graph, alignedSource);
4149
+ const patches = patchResult.patches;
4150
+ if (patchResult.unsupportedChanges.length > 0) {
4151
+ if (!options.force) throw new PullSourceReconciliationError(`Could not update ${outputPath} surgically: ${patchResult.unsupportedChanges.join(" ")} The source file was left unchanged. Pass --force to replace the file.`);
4152
+ } else if (patches.length > 0) {
4153
+ const replacements = applyMachineToSource(graphToMachineConfig(alignedSource), document, {
4154
+ patches,
4155
+ prevGraph: existingTarget.graph,
4156
+ nextGraph: alignedSource,
4157
+ sourceLocations: parsedTarget.sourceLocations,
4158
+ machineIndex
4159
+ });
4160
+ if (replacements.length === 0) {
4161
+ if (!options.force) throw new PullSourceReconciliationError(`Could not write remote changes to ${outputPath}: source reconciliation produced no replacements. The source file was left unchanged. Pass --force to replace the file.`);
4162
+ } else {
4163
+ let updatedSource = applyReplacementsToText(currentSource, replacements);
4164
+ if (source.remoteMachineId) updatedSource = upsertStatelyPragma(updatedSource, source.remoteMachineId, {
4165
+ fileName: outputPath,
4166
+ machineIndex
4167
+ });
4168
+ await fs.writeFile(outputPath, updatedSource, "utf8");
4169
+ wroteSurgically = true;
4170
+ }
4171
+ } else {
4172
+ const updatedSource = source.remoteMachineId ? upsertStatelyPragma(currentSource, source.remoteMachineId, {
4173
+ fileName: outputPath,
4174
+ machineIndex
4175
+ }) : currentSource;
4176
+ if (updatedSource !== currentSource) await fs.writeFile(outputPath, updatedSource, "utf8");
4177
+ wroteSurgically = true;
4178
+ }
4179
+ }
4180
+ }
4181
+ if (!wroteSurgically) {
4182
+ if (targetFormat === "xstate" && targetExists) {
4183
+ const machineCount = countSourceMachines(outputPath, await fs.readFile(outputPath, "utf8"));
4184
+ if (machineCount > 1) throw new PullSourceReconciliationError(`Could not update ${outputPath} surgically, and full regeneration would remove the other ${machineCount - 1} machine(s) in this file. The source file was left unchanged.`);
4185
+ }
4186
+ const serialized = serializeGraph(source.graph, targetFormat, {
4187
+ remoteMachineId: source.remoteMachineId,
4188
+ targetPath: outputPath
4189
+ });
4190
+ await fs.writeFile(outputPath, serialized, "utf8");
4191
+ }
1531
4192
  return {
1532
4193
  source,
1533
4194
  target: {
@@ -1578,10 +4239,7 @@ async function pushSync(options) {
1578
4239
  const project = await resolvePushProject(client, sourcePath, options);
1579
4240
  const existingMachineId = source.format === "xstate" ? getStatelyPragma(await fs.readFile(sourcePath, "utf8"), sourcePath)?.id : void 0;
1580
4241
  let machine;
1581
- if (existingMachineId) machine = await client.machines.update({
1582
- id: existingMachineId,
1583
- definition: toStudioMachine(source.graph)
1584
- });
4242
+ if (existingMachineId) machine = await updateMachineDefinition(client, existingMachineId, source.graph);
1585
4243
  else {
1586
4244
  if (!project.projectVersionId) throw new Error("Resolved project is missing projectVersionId.");
1587
4245
  machine = await client.machines.create({
@@ -1608,4 +4266,4 @@ async function pushSync(options) {
1608
4266
  }
1609
4267
 
1610
4268
  //#endregion
1611
- export { planSync, pullSync, pushLocalMachineLinks, pushSync };
4269
+ export { PullSourceReconciliationError, planSync, pullSync, pushLocalMachineLinks, pushSync };