@statelyai/sdk 0.6.1 → 0.7.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.
@@ -0,0 +1,2513 @@
1
+ import { createStatelyClient } from "./studio.mjs";
2
+ import { d as upsertStatelyPragma, l as findStatelyPragmaAttachments, t as graphToXStateTS, u as getStatelyPragma } from "./graphToXStateTS-Gzh0ZqbN.mjs";
3
+ import { fromStudioMachine, toStudioMachine } from "./graph.mjs";
4
+ import * as ts$1 from "typescript";
5
+ import { getDiff, isEmptyDiff } from "@statelyai/graph";
6
+ import fs from "node:fs/promises";
7
+ import path from "node:path";
8
+ import { execFile } from "node:child_process";
9
+ import { promisify } from "node:util";
10
+ import * as vm from "node:vm";
11
+ import * as esbuild from "esbuild";
12
+ import * as fs$1 from "fs";
13
+ import * as path$1 from "path";
14
+ import { fileURLToPath, pathToFileURL } from "url";
15
+
16
+ //#region ../editor-sync/src/fs.ts
17
+ function createTextDocument(fileName, text, uri = path$1.isAbsolute(fileName) ? pathToFileURL(fileName).toString() : fileName) {
18
+ const lineStarts = getLineStarts(text);
19
+ return {
20
+ fileName,
21
+ uri,
22
+ getText() {
23
+ return text;
24
+ },
25
+ positionAt(offset) {
26
+ const clampedOffset = Math.max(0, Math.min(offset, text.length));
27
+ let low = 0;
28
+ let high = lineStarts.length - 1;
29
+ while (low <= high) {
30
+ const mid = Math.floor((low + high) / 2);
31
+ const start = lineStarts[mid];
32
+ const nextStart = mid + 1 < lineStarts.length ? lineStarts[mid + 1] : text.length + 1;
33
+ if (clampedOffset < start) {
34
+ high = mid - 1;
35
+ continue;
36
+ }
37
+ if (clampedOffset >= nextStart) {
38
+ low = mid + 1;
39
+ continue;
40
+ }
41
+ return {
42
+ line: mid,
43
+ character: clampedOffset - start
44
+ };
45
+ }
46
+ return {
47
+ line: lineStarts.length - 1,
48
+ character: clampedOffset - lineStarts[lineStarts.length - 1]
49
+ };
50
+ }
51
+ };
52
+ }
53
+ function getLineStarts(text) {
54
+ const lineStarts = [0];
55
+ for (let index = 0; index < text.length; index += 1) if (text.charCodeAt(index) === 10) lineStarts.push(index + 1);
56
+ return lineStarts;
57
+ }
58
+
59
+ //#endregion
60
+ //#region ../editor-sync/src/internal/sourceLocations.ts
61
+ function collectXStateSourceLocations(sourceText, document) {
62
+ const sourceFile = ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$1(document.fileName));
63
+ const uri = document.uri?.toString() ?? document.fileName;
64
+ const bindings = collectBindings(sourceFile, uri, document.fileName);
65
+ const staticValues = collectStaticValueBindings(sourceFile);
66
+ const root = findMachineConfigObjectLiteral$1(sourceFile, bindings);
67
+ if (!root) return;
68
+ const states = [];
69
+ collectStateLocations(root, [], states, bindings, staticValues, root);
70
+ return {
71
+ version: 1,
72
+ root: {
73
+ uri,
74
+ range: toSourceRange(sourceFile, root)
75
+ },
76
+ states,
77
+ staticValues: collectStaticValueReferences(sourceFile, uri, root, staticValues)
78
+ };
79
+ }
80
+ function collectStaticValueBindings(sourceFile) {
81
+ const bindings = /* @__PURE__ */ new Map();
82
+ for (const statement of sourceFile.statements) {
83
+ if (ts$1.isVariableStatement(statement)) {
84
+ if (!((statement.declarationList.flags & ts$1.NodeFlags.Const) === ts$1.NodeFlags.Const)) continue;
85
+ for (const declaration of statement.declarationList.declarations) {
86
+ if (!ts$1.isIdentifier(declaration.name) || !declaration.initializer) continue;
87
+ const value = getStaticStringValue(declaration.initializer);
88
+ if (value === null) continue;
89
+ bindings.set(declaration.name.text, {
90
+ kind: "const",
91
+ symbol: declaration.name.text,
92
+ value,
93
+ valueRange: toSourceRange(sourceFile, declaration.initializer)
94
+ });
95
+ }
96
+ continue;
97
+ }
98
+ if (ts$1.isEnumDeclaration(statement)) for (const member of statement.members) {
99
+ const memberName = getEnumMemberName(member.name);
100
+ if (!memberName || !member.initializer) continue;
101
+ const value = getStaticStringValue(member.initializer);
102
+ if (value === null) continue;
103
+ const symbol = `${statement.name.text}.${memberName}`;
104
+ bindings.set(symbol, {
105
+ kind: "enumMember",
106
+ symbol,
107
+ value,
108
+ valueRange: toSourceRange(sourceFile, member.initializer)
109
+ });
110
+ }
111
+ }
112
+ return bindings;
113
+ }
114
+ function collectBindings(sourceFile, uri, fileName) {
115
+ const bindings = collectTopLevelBindings(sourceFile, uri);
116
+ addImportedBindings(bindings, sourceFile, fileName);
117
+ return bindings;
118
+ }
119
+ function collectTopLevelBindings(sourceFile, uri) {
120
+ const bindings = /* @__PURE__ */ new Map();
121
+ for (const statement of sourceFile.statements) {
122
+ if (!ts$1.isVariableStatement(statement)) continue;
123
+ for (const declaration of statement.declarationList.declarations) {
124
+ if (!ts$1.isIdentifier(declaration.name) || !declaration.initializer) continue;
125
+ const objectLiteral = unwrapObjectLiteralExpression$1(declaration.initializer);
126
+ if (objectLiteral) {
127
+ bindings.set(declaration.name.text, {
128
+ kind: "objectReference",
129
+ node: objectLiteral,
130
+ sourceFile,
131
+ uri,
132
+ bindings
133
+ });
134
+ continue;
135
+ }
136
+ const stateConfig = unwrapCreateConfigArgument(declaration.initializer);
137
+ if (stateConfig) bindings.set(declaration.name.text, {
138
+ kind: "createStateConfig",
139
+ node: stateConfig,
140
+ sourceFile,
141
+ uri,
142
+ bindings
143
+ });
144
+ }
145
+ }
146
+ return bindings;
147
+ }
148
+ function addImportedBindings(bindings, sourceFile, fileName) {
149
+ for (const statement of sourceFile.statements) {
150
+ if (!ts$1.isImportDeclaration(statement) || !ts$1.isStringLiteral(statement.moduleSpecifier)) continue;
151
+ const namedBindings = statement.importClause?.namedBindings;
152
+ if (!namedBindings || !ts$1.isNamedImports(namedBindings)) continue;
153
+ const importedFileName = resolveImportPath(fileName, statement.moduleSpecifier.text);
154
+ if (!importedFileName) continue;
155
+ const importedText = readSourceFile(importedFileName);
156
+ if (importedText === null) continue;
157
+ const importedBindings = collectBindings(ts$1.createSourceFile(importedFileName, importedText, ts$1.ScriptTarget.Latest, true, getScriptKind$1(importedFileName)), pathToFileURL(importedFileName).toString(), importedFileName);
158
+ for (const element of namedBindings.elements) {
159
+ const importedName = element.propertyName?.text ?? element.name.text;
160
+ const binding = importedBindings.get(importedName);
161
+ if (binding) bindings.set(element.name.text, binding);
162
+ }
163
+ }
164
+ }
165
+ function findMachineConfigObjectLiteral$1(sourceFile, bindings) {
166
+ let found = null;
167
+ const visit = (node) => {
168
+ if (found) return;
169
+ if (ts$1.isCallExpression(node) && isCreateMachineExpression(node.expression)) {
170
+ const [firstArgument] = node.arguments;
171
+ if (!firstArgument || !ts$1.isExpression(firstArgument)) return;
172
+ found = unwrapObjectLiteralExpression$1(firstArgument) ?? resolveIdentifierObject(firstArgument, bindings);
173
+ return;
174
+ }
175
+ ts$1.forEachChild(node, visit);
176
+ };
177
+ visit(sourceFile);
178
+ return found;
179
+ }
180
+ function collectStateLocations(stateObject, parentPath, locations, bindings, staticValues, root) {
181
+ const statesObject = getObjectLiteralProperty$1(stateObject, "states");
182
+ if (!statesObject) return;
183
+ for (const property of statesObject.properties) {
184
+ const resolved = resolveStateProperty(property, bindings, staticValues, root);
185
+ if (!resolved) continue;
186
+ const path = [...parentPath, resolved.key];
187
+ locations.push({
188
+ uri: resolved.uri,
189
+ path,
190
+ kind: resolved.kind,
191
+ symbol: resolved.symbol,
192
+ keyRange: resolved.keyRange,
193
+ referenceRange: resolved.referenceRange,
194
+ keySource: resolved.keySource,
195
+ keyReplacementText: resolved.keyReplacementText,
196
+ range: toSourceRange(resolved.sourceFile, resolved.stateObject)
197
+ });
198
+ collectStateLocations(resolved.stateObject, path, locations, resolved.bindings, staticValues, root);
199
+ }
200
+ }
201
+ function resolveStateProperty(property, bindings, staticValues, root) {
202
+ if (ts$1.isShorthandPropertyAssignment(property)) {
203
+ const binding = bindings.get(property.name.text);
204
+ if (!binding) return null;
205
+ return {
206
+ key: property.name.text,
207
+ kind: binding.kind,
208
+ symbol: property.name.text,
209
+ keyRange: toSourceRange(property.getSourceFile(), property.name),
210
+ referenceRange: toSourceRange(property.getSourceFile(), property.name),
211
+ stateObject: binding.node,
212
+ sourceFile: binding.sourceFile,
213
+ uri: binding.uri,
214
+ bindings: binding.bindings
215
+ };
216
+ }
217
+ if (!ts$1.isPropertyAssignment(property)) return null;
218
+ const resolvedKey = resolvePropertyKey(property.name, staticValues, root);
219
+ if (!resolvedKey) return null;
220
+ const inlineObject = unwrapObjectLiteralExpression$1(property.initializer);
221
+ if (inlineObject) return {
222
+ key: resolvedKey.key,
223
+ kind: "inline",
224
+ keyRange: toSourceRange(property.getSourceFile(), property.name),
225
+ keySource: resolvedKey.keySource,
226
+ keyReplacementText: resolvedKey.keyReplacementText,
227
+ stateObject: inlineObject,
228
+ sourceFile: property.getSourceFile(),
229
+ uri: getSourceFileUri(property.getSourceFile()),
230
+ bindings
231
+ };
232
+ if (ts$1.isIdentifier(property.initializer)) {
233
+ const binding = bindings.get(property.initializer.text);
234
+ if (!binding) return null;
235
+ return {
236
+ key: resolvedKey.key,
237
+ kind: binding.kind,
238
+ symbol: property.initializer.text,
239
+ keyRange: toSourceRange(property.getSourceFile(), property.name),
240
+ referenceRange: toSourceRange(property.getSourceFile(), property.initializer),
241
+ keySource: resolvedKey.keySource,
242
+ keyReplacementText: resolvedKey.keyReplacementText,
243
+ stateObject: binding.node,
244
+ sourceFile: binding.sourceFile,
245
+ uri: binding.uri,
246
+ bindings: binding.bindings
247
+ };
248
+ }
249
+ return null;
250
+ }
251
+ function resolveImportPath(fromFileName, specifier) {
252
+ if (!specifier.startsWith(".")) return null;
253
+ const basePath = path$1.resolve(path$1.dirname(fromFileName), specifier);
254
+ return [
255
+ basePath,
256
+ `${basePath}.ts`,
257
+ `${basePath}.tsx`,
258
+ `${basePath}.js`,
259
+ `${basePath}.jsx`,
260
+ path$1.join(basePath, "index.ts"),
261
+ path$1.join(basePath, "index.tsx"),
262
+ path$1.join(basePath, "index.js"),
263
+ path$1.join(basePath, "index.jsx")
264
+ ].find((candidate) => isReadableFile(candidate)) ?? null;
265
+ }
266
+ function isReadableFile(fileName) {
267
+ try {
268
+ return fs$1.statSync(fileName).isFile();
269
+ } catch {
270
+ return false;
271
+ }
272
+ }
273
+ function readSourceFile(fileName) {
274
+ try {
275
+ return fs$1.readFileSync(fileName, "utf8");
276
+ } catch {
277
+ return null;
278
+ }
279
+ }
280
+ function getSourceFileUri(sourceFile) {
281
+ return path$1.isAbsolute(sourceFile.fileName) ? pathToFileURL(sourceFile.fileName).toString() : sourceFile.fileName;
282
+ }
283
+ function unwrapCreateConfigArgument(expression) {
284
+ const unwrapped = unwrapExpression(expression);
285
+ if (!ts$1.isCallExpression(unwrapped)) return null;
286
+ const callee = unwrapped.expression;
287
+ if (!ts$1.isPropertyAccessExpression(callee) || !isSetupCreateConfigName(callee.name.text)) return null;
288
+ const [firstArgument] = unwrapped.arguments;
289
+ if (!firstArgument || !ts$1.isExpression(firstArgument)) return null;
290
+ return unwrapObjectLiteralExpression$1(firstArgument);
291
+ }
292
+ function isSetupCreateConfigName(name) {
293
+ return /^create[A-Z_$][\w$]*Config$/.test(name);
294
+ }
295
+ function resolveIdentifierObject(expression, bindings) {
296
+ const unwrapped = unwrapExpression(expression);
297
+ if (!ts$1.isIdentifier(unwrapped)) return null;
298
+ const binding = bindings.get(unwrapped.text);
299
+ return binding?.kind === "objectReference" ? binding.node : null;
300
+ }
301
+ function getObjectLiteralProperty$1(objectLiteral, propertyName) {
302
+ for (const property of objectLiteral.properties) {
303
+ if (!ts$1.isPropertyAssignment(property)) continue;
304
+ if (getPropertyNameText$1(property.name) !== propertyName) continue;
305
+ return unwrapObjectLiteralExpression$1(property.initializer);
306
+ }
307
+ return null;
308
+ }
309
+ function getPropertyNameText$1(name) {
310
+ if (ts$1.isIdentifier(name) || ts$1.isStringLiteral(name) || ts$1.isNumericLiteral(name)) return name.text;
311
+ if (ts$1.isComputedPropertyName(name)) {
312
+ const expression = name.expression;
313
+ if (ts$1.isStringLiteral(expression) || ts$1.isNoSubstitutionTemplateLiteral(expression) || ts$1.isNumericLiteral(expression)) return expression.text;
314
+ }
315
+ return null;
316
+ }
317
+ function resolvePropertyKey(name, staticValues, root) {
318
+ const literalKey = getPropertyNameText$1(name);
319
+ if (literalKey !== null) {
320
+ if (ts$1.isComputedPropertyName(name)) return {
321
+ key: literalKey,
322
+ keySource: { kind: "computedLiteral" },
323
+ keyReplacementText: JSON.stringify(literalKey)
324
+ };
325
+ return { key: literalKey };
326
+ }
327
+ if (!ts$1.isComputedPropertyName(name)) return null;
328
+ const binding = getStaticValueBindingForExpression(name.expression, staticValues);
329
+ if (!binding) return null;
330
+ return {
331
+ key: binding.value,
332
+ keySource: {
333
+ kind: binding.kind,
334
+ symbol: binding.symbol,
335
+ valueRange: binding.valueRange,
336
+ machineLocal: isStaticValueMachineLocal(name.getSourceFile(), binding, root)
337
+ },
338
+ keyReplacementText: JSON.stringify(binding.value)
339
+ };
340
+ }
341
+ function getStaticValueBindingForExpression(expression, staticValues) {
342
+ const unwrapped = unwrapExpression(expression);
343
+ if (ts$1.isIdentifier(unwrapped)) return staticValues.get(unwrapped.text) ?? null;
344
+ if (ts$1.isPropertyAccessExpression(unwrapped) && ts$1.isIdentifier(unwrapped.expression)) return staticValues.get(`${unwrapped.expression.text}.${unwrapped.name.text}`) ?? null;
345
+ return null;
346
+ }
347
+ function collectStaticValueReferences(sourceFile, uri, root, staticValues) {
348
+ const references = [];
349
+ if (staticValues.size === 0) return references;
350
+ const rootStart = root.getStart(sourceFile);
351
+ const rootEnd = root.getEnd();
352
+ const visit = (node) => {
353
+ if (ts$1.isComputedPropertyName(node)) {
354
+ const binding = getStaticValueBindingForExpression(node.expression, staticValues);
355
+ if (binding && !isStateKeyComputedPropertyName(node)) references.push({
356
+ uri,
357
+ range: toSourceRange(sourceFile, node),
358
+ value: binding.value
359
+ });
360
+ return;
361
+ }
362
+ if (!(node.getStart(sourceFile) >= rootStart && node.getEnd() <= rootEnd)) {
363
+ ts$1.forEachChild(node, visit);
364
+ return;
365
+ }
366
+ const binding = getStaticValueReferenceBinding(node, staticValues);
367
+ if (binding) {
368
+ references.push({
369
+ uri,
370
+ range: toSourceRange(sourceFile, node),
371
+ value: binding.value
372
+ });
373
+ return;
374
+ }
375
+ ts$1.forEachChild(node, visit);
376
+ };
377
+ visit(root);
378
+ return references;
379
+ }
380
+ function getStaticValueReferenceBinding(node, staticValues) {
381
+ if (ts$1.isIdentifier(node)) {
382
+ if (ts$1.isVariableDeclaration(node.parent) && node.parent.name === node) return null;
383
+ if (ts$1.isPropertyAssignment(node.parent) && node.parent.name === node) return null;
384
+ if (ts$1.isPropertyAccessExpression(node.parent)) return null;
385
+ return staticValues.get(node.text) ?? null;
386
+ }
387
+ if (ts$1.isPropertyAccessExpression(node) && ts$1.isIdentifier(node.expression)) {
388
+ if (ts$1.isComputedPropertyName(node.parent) && ts$1.isEnumMember(node.parent.parent)) return null;
389
+ return staticValues.get(`${node.expression.text}.${node.name.text}`) ?? null;
390
+ }
391
+ return null;
392
+ }
393
+ function isStaticValueMachineLocal(sourceFile, binding, root) {
394
+ const rootStart = root.getStart(sourceFile);
395
+ const rootEnd = root.getEnd();
396
+ let referenceCount = 0;
397
+ let hasOutsideReference = false;
398
+ const visit = (node) => {
399
+ if (getStaticValueReferenceBinding(node, new Map([[binding.symbol, binding]]))) {
400
+ referenceCount += 1;
401
+ if (node.getStart(sourceFile) < rootStart || node.getEnd() > rootEnd) hasOutsideReference = true;
402
+ return;
403
+ }
404
+ ts$1.forEachChild(node, visit);
405
+ };
406
+ visit(sourceFile);
407
+ return referenceCount > 0 && !hasOutsideReference;
408
+ }
409
+ function isStateKeyComputedPropertyName(name) {
410
+ const property = name.parent;
411
+ if (!ts$1.isPropertyAssignment(property)) return false;
412
+ const objectLiteral = property.parent;
413
+ if (!ts$1.isObjectLiteralExpression(objectLiteral)) return false;
414
+ const parentProperty = objectLiteral.parent;
415
+ if (!ts$1.isPropertyAssignment(parentProperty)) return false;
416
+ return getPropertyNameText$1(parentProperty.name) === "states";
417
+ }
418
+ function getStaticStringValue(expression) {
419
+ const unwrapped = unwrapExpression(expression);
420
+ if (ts$1.isStringLiteral(unwrapped) || ts$1.isNoSubstitutionTemplateLiteral(unwrapped) || ts$1.isNumericLiteral(unwrapped)) return unwrapped.text;
421
+ return null;
422
+ }
423
+ function getEnumMemberName(name) {
424
+ if (ts$1.isIdentifier(name) || ts$1.isStringLiteral(name) || ts$1.isNumericLiteral(name)) return name.text;
425
+ return null;
426
+ }
427
+ function isCreateMachineExpression(expression) {
428
+ return ts$1.isIdentifier(expression) && expression.text === "createMachine" || ts$1.isPropertyAccessExpression(expression) && expression.name.text === "createMachine";
429
+ }
430
+ function unwrapObjectLiteralExpression$1(expression) {
431
+ const unwrapped = unwrapExpression(expression);
432
+ return ts$1.isObjectLiteralExpression(unwrapped) ? unwrapped : null;
433
+ }
434
+ function unwrapExpression(expression) {
435
+ let current = expression;
436
+ for (;;) {
437
+ if (ts$1.isParenthesizedExpression(current)) {
438
+ current = current.expression;
439
+ continue;
440
+ }
441
+ if (ts$1.isAsExpression(current) || ts$1.isSatisfiesExpression(current)) {
442
+ current = current.expression;
443
+ continue;
444
+ }
445
+ if (ts$1.isTypeAssertionExpression(current) || ts$1.isNonNullExpression(current)) {
446
+ current = current.expression;
447
+ continue;
448
+ }
449
+ return current;
450
+ }
451
+ }
452
+ function toSourceRange(sourceFile, node) {
453
+ const start = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
454
+ const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
455
+ return {
456
+ startLine: start.line,
457
+ startChar: start.character,
458
+ endLine: end.line,
459
+ endChar: end.character
460
+ };
461
+ }
462
+ function getScriptKind$1(fileName) {
463
+ if (fileName.endsWith(".tsx")) return ts$1.ScriptKind.TSX;
464
+ if (fileName.endsWith(".jsx")) return ts$1.ScriptKind.JSX;
465
+ if (fileName.endsWith(".js")) return ts$1.ScriptKind.JS;
466
+ return ts$1.ScriptKind.TS;
467
+ }
468
+
469
+ //#endregion
470
+ //#region ../editor-sync/src/internal/codeToGraph.ts
471
+ /**
472
+ * Returns source text for the embed to parse.
473
+ *
474
+ * The returned text is still a temporary parse payload, not the source we write
475
+ * back to. Directly imported modular states are hydrated into the root
476
+ * `states` object so Viz can see their transition bodies even though it only
477
+ * receives one string.
478
+ */
479
+ function parseSourceToMachine(text, document) {
480
+ const sourceLocations = collectXStateSourceLocations(text, document);
481
+ if (!sourceLocations) return text;
482
+ const staticValueReplacements = (sourceLocations.staticValues ?? []).map((location) => ({
483
+ range: location.range,
484
+ newText: JSON.stringify(location.value)
485
+ }));
486
+ const stateReplacements = sourceLocations.states.filter((location) => location.path.length === 1 && location.keyRange).flatMap((location) => {
487
+ const keyRange = location.keyRange;
488
+ const keyReplacement = location.keyReplacementText ? [{
489
+ range: keyRange,
490
+ newText: location.keyReplacementText
491
+ }] : [];
492
+ const stateText = readSourceRange(location.uri, location.range);
493
+ if (!stateText) return keyReplacement;
494
+ if (location.referenceRange && !areSourceRangesEqual(location.referenceRange, keyRange)) return [...keyReplacement, {
495
+ range: location.referenceRange,
496
+ newText: stateText
497
+ }];
498
+ if (!canHydrateShorthandState(text, keyRange)) return keyReplacement;
499
+ return [...keyReplacement, {
500
+ range: keyRange,
501
+ newText: `${location.path[0]}: ${stateText}`
502
+ }];
503
+ });
504
+ return applySourceRangeReplacements(text, [...staticValueReplacements, ...stateReplacements].filter(removeOverlappingRanges).sort(compareSourceRangesDescending));
505
+ }
506
+ function removeOverlappingRanges(replacement, index, replacements) {
507
+ return !replacements.some((candidate, candidateIndex) => {
508
+ if (candidateIndex === index) return false;
509
+ return compareSourceRangesDescending(candidate, replacement) < 0 && rangesOverlap(candidate.range, replacement.range);
510
+ });
511
+ }
512
+ function rangesOverlap(left, right) {
513
+ const leftStart = rangePositionKey(left.startLine, left.startChar);
514
+ const leftEnd = rangePositionKey(left.endLine, left.endChar);
515
+ const rightStart = rangePositionKey(right.startLine, right.startChar);
516
+ return leftStart < rangePositionKey(right.endLine, right.endChar) && rightStart < leftEnd;
517
+ }
518
+ function rangePositionKey(line, character) {
519
+ return line * 1e6 + character;
520
+ }
521
+ function areSourceRangesEqual(left, right) {
522
+ return left.startLine === right.startLine && left.startChar === right.startChar && left.endLine === right.endLine && left.endChar === right.endChar;
523
+ }
524
+ function canHydrateShorthandState(text, range) {
525
+ const end = offsetAtRangePosition$1(text, range.endLine, range.endChar);
526
+ return text.slice(end).match(/\S/)?.[0] !== ":";
527
+ }
528
+ function readSourceRange(uri, range) {
529
+ const fileName = sourceUriToFileName(uri);
530
+ if (!fileName) return null;
531
+ try {
532
+ const text = fs$1.readFileSync(fileName, "utf8");
533
+ const start = offsetAtRangePosition$1(text, range.startLine, range.startChar);
534
+ const end = offsetAtRangePosition$1(text, range.endLine, range.endChar);
535
+ return text.slice(start, end);
536
+ } catch {
537
+ return null;
538
+ }
539
+ }
540
+ function sourceUriToFileName(uri) {
541
+ if (uri.startsWith("file://")) return fileURLToPath(uri);
542
+ if (/^[a-z][a-z\d+.-]*:/i.test(uri)) return null;
543
+ return uri;
544
+ }
545
+ function applySourceRangeReplacements(text, replacements) {
546
+ let updated = text;
547
+ for (const replacement of replacements) {
548
+ const start = offsetAtRangePosition$1(updated, replacement.range.startLine, replacement.range.startChar);
549
+ const end = offsetAtRangePosition$1(updated, replacement.range.endLine, replacement.range.endChar);
550
+ updated = `${updated.slice(0, start)}${replacement.newText}${updated.slice(end)}`;
551
+ }
552
+ return updated;
553
+ }
554
+ function compareSourceRangesDescending(left, right) {
555
+ if (left.range.startLine !== right.range.startLine) return right.range.startLine - left.range.startLine;
556
+ return right.range.startChar - left.range.startChar;
557
+ }
558
+ function offsetAtRangePosition$1(text, line, character) {
559
+ if (line <= 0) return character;
560
+ let currentLine = 0;
561
+ for (let index = 0; index < text.length; index += 1) {
562
+ if (text.charCodeAt(index) !== 10) continue;
563
+ currentLine += 1;
564
+ if (currentLine === line) return index + 1 + character;
565
+ }
566
+ return text.length;
567
+ }
568
+
569
+ //#endregion
570
+ //#region ../editor-sync/src/internal/graphToCode.ts
571
+ async function applyMachineToSourceDocuments(machineConfig, document, options = {}) {
572
+ if (!isMachineConfig(machineConfig)) return [];
573
+ const sourceFile = createSourceFile(document, document.getText());
574
+ const machineConfigNode = getMappedRootObjectLiteral(document, sourceFile, options.sourceLocations) ?? findMachineConfigObjectLiteral(sourceFile);
575
+ if (!machineConfigNode) return [];
576
+ const parsedPatches = parseGraphPatches(options.patches);
577
+ const prevGraph = parseGraph(options.prevGraph);
578
+ const nextGraph = parseGraph(options.nextGraph);
579
+ if (!parsedPatches || !prevGraph || !nextGraph || parsedPatches.length === 0) {
580
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
581
+ return [createReplacement(document, sourceFile, machineConfigNode, machineConfig)];
582
+ }
583
+ const semanticSplit = await tryCreateSemanticPatchSplitForDocuments(document, sourceFile, machineConfigNode, parsedPatches, prevGraph, nextGraph, options.sourceLocations, options.openTextDocument);
584
+ if (semanticSplit && semanticSplit.remainingPatches.length === 0) return semanticSplit.replacements.sort(compareReplacementRangesDescending);
585
+ const activePatches = semanticSplit?.remainingPatches ?? parsedPatches;
586
+ const activeSourceLocations = semanticSplit?.sourceLocations ?? options.sourceLocations;
587
+ let semanticReplacements = semanticSplit?.replacements ?? [];
588
+ const implementationSplit = tryCreateImplementationPatchSplit(document, sourceFile, activePatches, nextGraph);
589
+ if (implementationSplit && implementationSplit.remainingPatches.length === 0) return [...semanticReplacements, ...implementationSplit.replacements].sort(compareReplacementRangesDescending);
590
+ if (implementationSplit) semanticReplacements = [...semanticReplacements, ...implementationSplit.replacements];
591
+ const patchesAfterImplementationSplit = implementationSplit?.remainingPatches ?? activePatches;
592
+ const stateMembershipSplit = await tryCreateStateMembershipPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, patchesAfterImplementationSplit, prevGraph, nextGraph, activeSourceLocations, options.openTextDocument);
593
+ if (stateMembershipSplit) {
594
+ if (stateMembershipSplit.remainingPatches.length === 0) return [...semanticReplacements, ...stateMembershipSplit.replacements].sort(compareReplacementRangesDescending);
595
+ const remainingPlan = deriveReplacementPlan(stateMembershipSplit.remainingPatches, prevGraph, nextGraph);
596
+ if (remainingPlan.type === "root") {
597
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
598
+ return [createReplacement(document, sourceFile, machineConfigNode, machineConfig)];
599
+ }
600
+ const replacements = [...semanticReplacements, ...stateMembershipSplit.replacements];
601
+ for (const path of remainingPlan.paths) {
602
+ const nextValue = getStateConfigByPath(machineConfig, path);
603
+ if (!isMachineConfig(nextValue)) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
604
+ const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, activeSourceLocations, path, options.openTextDocument);
605
+ const currentNode = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, path);
606
+ const targetDocument = mappedTarget?.document ?? document;
607
+ const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
608
+ if (!currentNode) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
609
+ replacements.push(createReplacement(targetDocument, targetSourceFile, currentNode, nextValue));
610
+ }
611
+ return replacements.sort(compareReplacementRangesDescending);
612
+ }
613
+ const plan = deriveReplacementPlan(patchesAfterImplementationSplit, prevGraph, nextGraph);
614
+ if (plan.type === "root") {
615
+ if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
616
+ return [createReplacement(document, sourceFile, machineConfigNode, machineConfig)];
617
+ }
618
+ const replacements = [...semanticReplacements];
619
+ for (const path of plan.paths) {
620
+ const nextValue = getStateConfigByPath(machineConfig, path);
621
+ if (!isMachineConfig(nextValue)) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
622
+ const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, activeSourceLocations, path, options.openTextDocument);
623
+ const currentNode = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, path);
624
+ const targetDocument = mappedTarget?.document ?? document;
625
+ const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
626
+ if (!currentNode) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
627
+ replacements.push(createReplacement(targetDocument, targetSourceFile, currentNode, nextValue));
628
+ }
629
+ return replacements.sort(compareReplacementRangesDescending);
630
+ }
631
+ function fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, sourceLocations) {
632
+ if (wouldDeModularizeRootReplacement(sourceLocations)) return [];
633
+ return [createReplacement(document, sourceFile, machineConfigNode, machineConfig)];
634
+ }
635
+ function tryCreateImplementationPatchSplit(document, sourceFile, patches, nextGraph) {
636
+ const replacements = [];
637
+ const remainingPatches = [];
638
+ for (const patch of patches) {
639
+ if (!isImplementationPatch(patch)) {
640
+ remainingPatches.push(patch);
641
+ continue;
642
+ }
643
+ const patchReplacements = createImplementationPatchReplacements(document, sourceFile, patch, nextGraph);
644
+ if (!patchReplacements) {
645
+ remainingPatches.push(patch);
646
+ continue;
647
+ }
648
+ replacements.push(...patchReplacements);
649
+ }
650
+ return replacements.length > 0 ? {
651
+ replacements: replacements.sort(compareReplacementRangesDescending),
652
+ remainingPatches
653
+ } : null;
654
+ }
655
+ function isImplementationPatch(patch) {
656
+ return patch.op === "createImplementation" || patch.op === "updateImplementation" || patch.op === "deleteImplementation";
657
+ }
658
+ function createImplementationPatchReplacements(document, sourceFile, patch, nextGraph) {
659
+ const implementationRoot = findSetupObjectLiteral(sourceFile) ?? findCreateMachineImplementationObjectLiteral(sourceFile);
660
+ if (!implementationRoot) return null;
661
+ const categoryName = implementationSourceTypeToCategoryName(patch.sourceType);
662
+ const categoryObject = getObjectLiteralProperty(implementationRoot, categoryName);
663
+ if (patch.op === "createImplementation") return createImplementationCreateReplacements(document, sourceFile, implementationRoot, categoryName, getGraphImplementation(nextGraph, patch.sourceType, patch.implementation.id) ?? patch.implementation);
664
+ if (!categoryObject) return null;
665
+ const implementationProperty = findObjectLiteralProperty(categoryObject, patch.implementationId);
666
+ if (!implementationProperty) return null;
667
+ if (patch.op === "deleteImplementation") {
668
+ const deletionRange = getObjectLiteralPropertyDeletionRange(sourceFile, categoryObject, implementationProperty);
669
+ return [createOffsetReplacement(document, deletionRange.start, deletionRange.end, "")];
670
+ }
671
+ const nextImplementation = getGraphImplementation(nextGraph, patch.sourceType, patch.implementationId);
672
+ const nextName = patch.data.name ?? nextImplementation?.name;
673
+ const nextCode = patch.data.code ?? nextImplementation?.code?.body;
674
+ const replacements = [];
675
+ if (nextName && nextName !== patch.implementationId) {
676
+ const nameNode = getObjectLiteralElementName(implementationProperty);
677
+ if (!nameNode) return null;
678
+ replacements.push(createOffsetReplacement(document, nameNode.getStart(sourceFile), nameNode.getEnd(), propertyNameTextForSource(nextName)));
679
+ }
680
+ if (nextCode !== void 0) {
681
+ if (!ts$1.isPropertyAssignment(implementationProperty)) return null;
682
+ replacements.push(createOffsetReplacement(document, implementationProperty.initializer.getStart(sourceFile), implementationProperty.initializer.getEnd(), nextCode));
683
+ }
684
+ return replacements.length > 0 ? replacements : null;
685
+ }
686
+ function createImplementationCreateReplacements(document, sourceFile, implementationRoot, categoryName, implementation) {
687
+ const implementationCode = implementation.code?.body;
688
+ if (!implementation.id || !implementationCode) return null;
689
+ const categoryObject = getObjectLiteralProperty(implementationRoot, categoryName);
690
+ if (!categoryObject) {
691
+ const text = objectPropertyTextForInsertion(implementationRoot, `${propertyNameTextForSource(categoryName)}: {\n${getIndentForNewObjectProperty(sourceFile, implementationRoot)}${propertyNameTextForSource(implementation.id)}: ${implementationCode},\n${getIndentForObjectClose(sourceFile, implementationRoot)}}`);
692
+ return [createOffsetReplacement(document, implementationRoot.properties.end, implementationRoot.properties.end, text)];
693
+ }
694
+ const text = objectPropertyTextForInsertion(categoryObject, `${propertyNameTextForSource(implementation.id)}: ${implementationCode}`);
695
+ return [createOffsetReplacement(document, categoryObject.properties.end, categoryObject.properties.end, text)];
696
+ }
697
+ function objectPropertyTextForInsertion(objectLiteral, propertyText) {
698
+ return `${objectLiteral.properties.length > 0 ? "," : ""}${getLineBreak(objectLiteral.getSourceFile())}${getIndentForNewObjectProperty(objectLiteral.getSourceFile(), objectLiteral)}${propertyText}`;
699
+ }
700
+ function getLineBreak(sourceFile) {
701
+ return sourceFile.text.includes("\r\n") ? "\r\n" : "\n";
702
+ }
703
+ function getIndentForNewObjectProperty(sourceFile, objectLiteral) {
704
+ const closeIndent = getIndentForObjectClose(sourceFile, objectLiteral);
705
+ const existingProperty = objectLiteral.properties[0];
706
+ if (existingProperty) {
707
+ const propertyLineStart = getLineStartOffset(sourceFile.text, existingProperty.getStart(sourceFile));
708
+ return sourceFile.text.slice(propertyLineStart, existingProperty.getStart(sourceFile)).match(/^[ \t]*/)?.[0] ?? `${closeIndent} `;
709
+ }
710
+ return `${closeIndent} `;
711
+ }
712
+ function getIndentForObjectClose(sourceFile, objectLiteral) {
713
+ const objectStart = objectLiteral.getStart(sourceFile);
714
+ const lineStart = getLineStartOffset(sourceFile.text, objectStart);
715
+ return sourceFile.text.slice(lineStart, objectStart).match(/^[ \t]*/)?.[0] ?? "";
716
+ }
717
+ function createOffsetReplacement(document, startOffset, endOffset, newText) {
718
+ const start = document.positionAt(startOffset);
719
+ const end = document.positionAt(endOffset);
720
+ return {
721
+ uri: getDocumentUri(document),
722
+ range: {
723
+ startLine: start.line,
724
+ startChar: start.character,
725
+ endLine: end.line,
726
+ endChar: end.character
727
+ },
728
+ newText
729
+ };
730
+ }
731
+ function propertyNameTextForSource(name) {
732
+ return isIdentifierText(name) ? name : JSON.stringify(name);
733
+ }
734
+ function getGraphImplementation(graph, sourceType, implementationId) {
735
+ if (!implementationId) return;
736
+ return graph.data?.implementations?.[implementationSourceTypeToCategoryName(sourceType)]?.find((implementation) => implementation.id === implementationId);
737
+ }
738
+ function implementationSourceTypeToCategoryName(sourceType) {
739
+ switch (sourceType) {
740
+ case "action": return "actions";
741
+ case "guard": return "guards";
742
+ case "actor": return "actors";
743
+ case "delay": return "delays";
744
+ }
745
+ }
746
+ async function tryCreateStateMembershipPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) {
747
+ const split = splitStateMembershipPatches(patches, prevGraph, nextGraph, sourceLocations);
748
+ if (!split) return null;
749
+ const replacements = await createStateMembershipReplacementsForDocuments(document, sourceFile, machineConfigNode, machineConfig, split.changes, sourceLocations, openTextDocument);
750
+ if (!replacements) return null;
751
+ return {
752
+ replacements,
753
+ remainingPatches: split.remainingPatches
754
+ };
755
+ }
756
+ function splitStateMembershipPatches(patches, prevGraph, nextGraph, sourceLocations) {
757
+ const createdById = /* @__PURE__ */ new Map();
758
+ const changesByParent = /* @__PURE__ */ new Map();
759
+ const remainingPatches = [];
760
+ const getChange = (parentPath) => {
761
+ const key = parentPath.join(".");
762
+ const existing = changesByParent.get(key);
763
+ if (existing) return existing;
764
+ const change = {
765
+ parentPath,
766
+ createdPaths: [],
767
+ deletedPaths: [],
768
+ patches: []
769
+ };
770
+ changesByParent.set(key, change);
771
+ return change;
772
+ };
773
+ for (const patch of patches) switch (patch.op) {
774
+ case "createState": {
775
+ if (!patch.id) {
776
+ remainingPatches.push(patch);
777
+ break;
778
+ }
779
+ const parentPath = resolveStatePath(nextGraph, patch.parentId);
780
+ const nextPath = resolveStatePath(nextGraph, patch.id);
781
+ if (!parentPath || !nextPath || nextPath.length === 0) {
782
+ remainingPatches.push(patch);
783
+ break;
784
+ }
785
+ const change = getChange(parentPath);
786
+ createdById.set(patch.id, {
787
+ parentPath,
788
+ path: nextPath
789
+ });
790
+ change.createdPaths.push(nextPath);
791
+ change.patches.push(patch);
792
+ break;
793
+ }
794
+ case "updateState": {
795
+ const created = createdById.get(patch.stateId);
796
+ const nextPath = resolveStatePath(nextGraph, patch.stateId);
797
+ if (created && nextPath && arePathsEqual(created.path, nextPath)) {
798
+ getChange(created.parentPath).patches.push(patch);
799
+ break;
800
+ }
801
+ remainingPatches.push(patch);
802
+ break;
803
+ }
804
+ case "deleteState": {
805
+ const prevPath = resolveStatePath(prevGraph, patch.stateId);
806
+ if (!prevPath || prevPath.length === 0) {
807
+ remainingPatches.push(patch);
808
+ break;
809
+ }
810
+ const change = getChange(prevPath.slice(0, -1));
811
+ change.deletedPaths.push(prevPath);
812
+ change.patches.push(patch);
813
+ break;
814
+ }
815
+ default: remainingPatches.push(patch);
816
+ }
817
+ const deletedPaths = [...changesByParent.values()].flatMap((change) => change.deletedPaths);
818
+ const remainingPatchesWithSurvivingOwners = remainingPatches.filter((patch) => {
819
+ const owner = resolvePatchOwner(patch, prevGraph, nextGraph);
820
+ return owner.type !== "covered" && !isPatchOwnerCoveredByDeletedPaths(owner, deletedPaths);
821
+ });
822
+ const split = coalesceMembershipChangesWithRemainingPatches([...changesByParent.values()], remainingPatchesWithSurvivingOwners, prevGraph, nextGraph, sourceLocations);
823
+ return split.changes.length > 0 ? split : null;
824
+ }
825
+ function isPatchOwnerCoveredByDeletedPaths(owner, deletedPaths) {
826
+ if (owner.type !== "state" || deletedPaths.length === 0) return false;
827
+ return deletedPaths.some((deletedPath) => isPathEqualOrDescendant(owner.path, deletedPath));
828
+ }
829
+ function coalesceMembershipChangesWithRemainingPatches(changes, remainingPatches, prevGraph, nextGraph, sourceLocations) {
830
+ if (remainingPatches.length === 0) return {
831
+ changes,
832
+ remainingPatches
833
+ };
834
+ const remainingPlan = deriveReplacementPlan(remainingPatches, prevGraph, nextGraph);
835
+ const activeChanges = [];
836
+ const activeRemainingPatches = [...remainingPatches];
837
+ for (const change of changes) {
838
+ if (shouldCoalesceMembershipChangeWithRemainingPlan(change, remainingPlan, sourceLocations)) {
839
+ activeRemainingPatches.push(...change.patches);
840
+ continue;
841
+ }
842
+ activeChanges.push(change);
843
+ }
844
+ return {
845
+ changes: activeChanges,
846
+ remainingPatches: activeRemainingPatches
847
+ };
848
+ }
849
+ function shouldCoalesceMembershipChangeWithRemainingPlan(change, remainingPlan, sourceLocations) {
850
+ if (change.parentPath.length === 0 && wouldDeModularizeRootReplacement(sourceLocations)) return false;
851
+ if (remainingPlan.type === "root") return true;
852
+ return remainingPlan.paths.some((path) => isPathEqualOrDescendant(path, change.parentPath) || isPathEqualOrDescendant(change.parentPath, path));
853
+ }
854
+ function isPathEqualOrDescendant(path, candidateParentPath) {
855
+ return candidateParentPath.every((segment, index) => path[index] === segment);
856
+ }
857
+ async function createStateMembershipReplacementsForDocuments(document, sourceFile, machineConfigNode, machineConfig, changes, sourceLocations, openTextDocument) {
858
+ const replacements = [];
859
+ for (const change of changes) {
860
+ const target = await getStateMembershipParentTargetForDocuments(document, sourceFile, machineConfigNode, sourceLocations, change.parentPath, openTextDocument);
861
+ if (!target) return null;
862
+ const changeReplacements = createStateMembershipReplacementsForTarget(target.document, target.sourceFile, target.node, machineConfig, change);
863
+ if (!changeReplacements) return null;
864
+ replacements.push(...changeReplacements);
865
+ }
866
+ return replacements.sort(compareReplacementRangesDescending);
867
+ }
868
+ function createStateMembershipReplacementsForTarget(document, sourceFile, parentObject, machineConfig, change) {
869
+ const statesObject = getObjectLiteralProperty(parentObject, "states");
870
+ if (!statesObject) return null;
871
+ const stateEntries = [];
872
+ for (const path of change.createdPaths) {
873
+ const key = path[path.length - 1];
874
+ const stateConfig = getStateConfigByPath(machineConfig, path);
875
+ if (!key || !isMachineConfig(stateConfig)) return null;
876
+ stateEntries.push({
877
+ key,
878
+ config: stateConfig
879
+ });
880
+ }
881
+ const deletionReplacements = [];
882
+ for (const path of change.deletedPaths) {
883
+ const key = path[path.length - 1];
884
+ const property = key ? findObjectLiteralProperty(statesObject, key) : null;
885
+ if (!property) return null;
886
+ deletionReplacements.push(createObjectLiteralPropertyDeletion(document, sourceFile, statesObject, property));
887
+ }
888
+ return [...stateEntries.length > 0 ? [createObjectLiteralPropertiesInsertion(document, sourceFile, statesObject, stateEntries)] : [], ...deletionReplacements].sort(compareReplacementRangesDescending);
889
+ }
890
+ async function getStateMembershipParentTargetForDocuments(document, sourceFile, machineConfigNode, sourceLocations, parentPath, openTextDocument) {
891
+ if (parentPath.length === 0) return {
892
+ document,
893
+ sourceFile,
894
+ node: machineConfigNode
895
+ };
896
+ const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, sourceLocations, parentPath, openTextDocument);
897
+ if (mappedTarget) return mappedTarget;
898
+ const node = getStateObjectLiteralByPath(machineConfigNode, parentPath);
899
+ return node ? {
900
+ document,
901
+ sourceFile,
902
+ node
903
+ } : null;
904
+ }
905
+ function createObjectLiteralPropertiesInsertion(document, sourceFile, objectLiteral, entries) {
906
+ const formatting = getFormattingContext(document, sourceFile, objectLiteral);
907
+ const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
908
+ const propertyTexts = entries.map((entry) => printObjectLiteralProperty(entry.key, entry.config, sourceFile, formatting));
909
+ const existingProperties = objectLiteral.properties;
910
+ const closeBraceOffset = objectLiteral.getEnd() - 1;
911
+ const startOffset = existingProperties.length === 0 ? closeBraceOffset : existingProperties[existingProperties.length - 1].getEnd();
912
+ const start = document.positionAt(startOffset);
913
+ const end = document.positionAt(closeBraceOffset);
914
+ const prefix = existingProperties.length === 0 ? lineSeparator : `,${lineSeparator}`;
915
+ const suffix = `${lineSeparator}${formatting.baseIndent}`;
916
+ return {
917
+ uri: getDocumentUri(document),
918
+ range: {
919
+ startLine: start.line,
920
+ startChar: start.character,
921
+ endLine: end.line,
922
+ endChar: end.character
923
+ },
924
+ newText: `${prefix}${propertyTexts.join(`,${lineSeparator}`)}${suffix}`
925
+ };
926
+ }
927
+ function createObjectLiteralPropertyDeletion(document, sourceFile, objectLiteral, property) {
928
+ const range = getObjectLiteralPropertyDeletionRange(sourceFile, objectLiteral, property);
929
+ const start = document.positionAt(range.start);
930
+ const end = document.positionAt(range.end);
931
+ return {
932
+ uri: getDocumentUri(document),
933
+ range: {
934
+ startLine: start.line,
935
+ startChar: start.character,
936
+ endLine: end.line,
937
+ endChar: end.character
938
+ },
939
+ newText: ""
940
+ };
941
+ }
942
+ function getObjectLiteralPropertyDeletionRange(sourceFile, objectLiteral, property) {
943
+ const properties = [...objectLiteral.properties];
944
+ const propertyIndex = properties.indexOf(property);
945
+ const propertyStart = property.getFullStart();
946
+ const propertyEnd = property.getEnd();
947
+ if (properties.length === 1) return {
948
+ start: propertyStart,
949
+ end: propertyEnd
950
+ };
951
+ if (propertyIndex === properties.length - 1) {
952
+ const previousProperty = properties[propertyIndex - 1];
953
+ const commaOffset = sourceFile.text.lastIndexOf(",", propertyStart - 1);
954
+ return {
955
+ start: commaOffset >= previousProperty.getEnd() && commaOffset < propertyStart ? commaOffset : propertyStart,
956
+ end: propertyEnd
957
+ };
958
+ }
959
+ const nextProperty = properties[propertyIndex + 1];
960
+ const commaOffset = sourceFile.text.indexOf(",", propertyEnd);
961
+ return {
962
+ start: propertyStart,
963
+ end: commaOffset >= propertyEnd && commaOffset < nextProperty.getFullStart() ? commaOffset + 1 : propertyEnd
964
+ };
965
+ }
966
+ function findObjectLiteralProperty(objectLiteral, propertyName) {
967
+ for (const property of objectLiteral.properties) {
968
+ if (ts$1.isShorthandPropertyAssignment(property) && property.name.text === propertyName) return property;
969
+ if (ts$1.isPropertyAssignment(property)) {
970
+ if (getPropertyNameText(property.name) === propertyName) return property;
971
+ }
972
+ }
973
+ return null;
974
+ }
975
+ function findObjectLiteralPropertyByRange(sourceFile, objectLiteral, range) {
976
+ if (!range) return null;
977
+ const start = offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar);
978
+ const end = offsetAtRangePosition(sourceFile.text, range.endLine, range.endChar);
979
+ for (const property of objectLiteral.properties) {
980
+ const propertyName = getObjectLiteralElementName(property);
981
+ if (propertyName && propertyName.getStart(sourceFile) === start && propertyName.getEnd() === end) return property;
982
+ }
983
+ return null;
984
+ }
985
+ function getObjectLiteralElementName(property) {
986
+ if (ts$1.isPropertyAssignment(property) || ts$1.isShorthandPropertyAssignment(property) || ts$1.isMethodDeclaration(property) || ts$1.isGetAccessorDeclaration(property) || ts$1.isSetAccessorDeclaration(property)) return property.name;
987
+ return null;
988
+ }
989
+ function getStatePropertyKeyText(property) {
990
+ if (ts$1.isShorthandPropertyAssignment(property)) return property.name.text;
991
+ if (ts$1.isPropertyAssignment(property)) return getPropertyNameText(property.name);
992
+ return null;
993
+ }
994
+ function printObjectLiteralProperty(key, value, sourceFile, formatting) {
995
+ const objectText = printExpression(valueToExpression({ [key]: value }), sourceFile, formatting);
996
+ const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
997
+ const lines = objectText.split(/\r?\n/);
998
+ if (lines.length <= 2) return objectText.replace(/^\{\s*/, "").replace(/\s*\}$/, "");
999
+ return lines.slice(1, -1).join(lineSeparator);
1000
+ }
1001
+ function wouldDeModularizeRootReplacement(sourceLocations) {
1002
+ return sourceLocations?.states.some((location) => location.kind !== "inline") ?? false;
1003
+ }
1004
+ function parseGraphPatches(value) {
1005
+ if (!Array.isArray(value)) return null;
1006
+ return value.filter(isGraphPatch);
1007
+ }
1008
+ function parseGraph(value) {
1009
+ if (!value || typeof value !== "object") return null;
1010
+ const candidate = value;
1011
+ if (!Array.isArray(candidate.nodes) || !Array.isArray(candidate.edges)) return null;
1012
+ return candidate;
1013
+ }
1014
+ function isGraphPatch(value) {
1015
+ return Boolean(value && typeof value === "object" && "op" in value && typeof value.op === "string");
1016
+ }
1017
+ function isMachineConfig(value) {
1018
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
1019
+ }
1020
+ function getScriptKind(fileName) {
1021
+ if (fileName.endsWith(".tsx")) return ts$1.ScriptKind.TSX;
1022
+ if (fileName.endsWith(".jsx")) return ts$1.ScriptKind.JSX;
1023
+ if (fileName.endsWith(".js")) return ts$1.ScriptKind.JS;
1024
+ return ts$1.ScriptKind.TS;
1025
+ }
1026
+ function createSourceFile(document, sourceText) {
1027
+ return ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind(document.fileName));
1028
+ }
1029
+ function findMachineConfigObjectLiteral(sourceFile) {
1030
+ let found = null;
1031
+ const visit = (node) => {
1032
+ if (found) return;
1033
+ if (ts$1.isCallExpression(node)) {
1034
+ const expression = node.expression;
1035
+ if (ts$1.isIdentifier(expression) && expression.text === "createMachine" || ts$1.isPropertyAccessExpression(expression) && expression.name.text === "createMachine") {
1036
+ const [firstArgument] = node.arguments;
1037
+ const objectLiteral = firstArgument && unwrapObjectLiteralExpression(firstArgument);
1038
+ if (objectLiteral) {
1039
+ found = objectLiteral;
1040
+ return;
1041
+ }
1042
+ }
1043
+ }
1044
+ ts$1.forEachChild(node, visit);
1045
+ };
1046
+ visit(sourceFile);
1047
+ return found;
1048
+ }
1049
+ function findSetupObjectLiteral(sourceFile) {
1050
+ let found = null;
1051
+ const visit = (node) => {
1052
+ if (found) return;
1053
+ if (ts$1.isCallExpression(node) && isSetupCallExpression(node)) {
1054
+ const [firstArgument] = node.arguments;
1055
+ if (firstArgument && ts$1.isExpression(firstArgument)) {
1056
+ found = unwrapObjectLiteralExpression(firstArgument);
1057
+ if (found) return;
1058
+ }
1059
+ }
1060
+ ts$1.forEachChild(node, visit);
1061
+ };
1062
+ visit(sourceFile);
1063
+ return found;
1064
+ }
1065
+ function findCreateMachineImplementationObjectLiteral(sourceFile) {
1066
+ let found = null;
1067
+ const visit = (node) => {
1068
+ if (found) return;
1069
+ if (ts$1.isCallExpression(node) && isCreateMachineCallExpression(node)) {
1070
+ const secondArgument = node.arguments[1];
1071
+ if (secondArgument && ts$1.isExpression(secondArgument)) {
1072
+ found = unwrapObjectLiteralExpression(secondArgument);
1073
+ if (found) return;
1074
+ }
1075
+ }
1076
+ ts$1.forEachChild(node, visit);
1077
+ };
1078
+ visit(sourceFile);
1079
+ return found;
1080
+ }
1081
+ function isCreateMachineCallExpression(node) {
1082
+ const expression = node.expression;
1083
+ return ts$1.isIdentifier(expression) && expression.text === "createMachine" || ts$1.isPropertyAccessExpression(expression) && expression.name.text === "createMachine";
1084
+ }
1085
+ function isSetupCallExpression(node) {
1086
+ const expression = node.expression;
1087
+ return ts$1.isIdentifier(expression) && expression.text === "setup" || ts$1.isPropertyAccessExpression(expression) && expression.name.text === "setup";
1088
+ }
1089
+ function unwrapObjectLiteralExpression(expression) {
1090
+ let current = expression;
1091
+ for (;;) {
1092
+ if (ts$1.isParenthesizedExpression(current)) {
1093
+ current = current.expression;
1094
+ continue;
1095
+ }
1096
+ if (ts$1.isAsExpression(current) || ts$1.isSatisfiesExpression(current)) {
1097
+ current = current.expression;
1098
+ continue;
1099
+ }
1100
+ if (ts$1.isTypeAssertionExpression(current)) {
1101
+ current = current.expression;
1102
+ continue;
1103
+ }
1104
+ break;
1105
+ }
1106
+ return ts$1.isObjectLiteralExpression(current) ? current : null;
1107
+ }
1108
+ function resolveStatePath(graph, nodeId) {
1109
+ const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
1110
+ const segments = [];
1111
+ let current = nodeById.get(nodeId);
1112
+ if (!current) return null;
1113
+ while (current && current.parentId !== null) {
1114
+ segments.push(current.data.key);
1115
+ current = nodeById.get(current.parentId);
1116
+ }
1117
+ return segments.reverse();
1118
+ }
1119
+ function getEdgeSourceId(graph, edgeId) {
1120
+ return graph.edges.find((edge) => edge.id === edgeId)?.sourceId ?? null;
1121
+ }
1122
+ function resolveEdgeSourcePath(graph, edgeId) {
1123
+ const sourceId = getEdgeSourceId(graph, edgeId);
1124
+ return sourceId ? resolveStatePath(graph, sourceId) : null;
1125
+ }
1126
+ function resolvePatchOwner(patch, prevGraph, nextGraph) {
1127
+ switch (patch.op) {
1128
+ case "createState": {
1129
+ const parentPath = resolveStatePath(nextGraph, patch.parentId);
1130
+ return parentPath ? {
1131
+ type: "state",
1132
+ path: parentPath
1133
+ } : { type: "covered" };
1134
+ }
1135
+ case "updateState": {
1136
+ const nextPath = resolveStatePath(nextGraph, patch.stateId);
1137
+ const prevPath = resolveStatePath(prevGraph, patch.stateId);
1138
+ if (patch.key !== void 0 && prevPath && nextPath) return { type: "root" };
1139
+ const path = nextPath ?? prevPath;
1140
+ return path ? {
1141
+ type: "state",
1142
+ path
1143
+ } : { type: "covered" };
1144
+ }
1145
+ case "deleteState": {
1146
+ const node = prevGraph.nodes.find((item) => item.id === patch.stateId);
1147
+ if (!node) return { type: "covered" };
1148
+ if (!node.parentId) return { type: "root" };
1149
+ const parentPath = resolveStatePath(prevGraph, node.parentId);
1150
+ return parentPath ? {
1151
+ type: "state",
1152
+ path: parentPath
1153
+ } : { type: "root" };
1154
+ }
1155
+ case "createTransition": {
1156
+ const path = resolveStatePath(nextGraph, patch.sourceId);
1157
+ return path ? {
1158
+ type: "state",
1159
+ path
1160
+ } : { type: "covered" };
1161
+ }
1162
+ case "updateTransition": {
1163
+ const path = resolveEdgeSourcePath(nextGraph, patch.transitionId) ?? resolveEdgeSourcePath(prevGraph, patch.transitionId);
1164
+ return path ? {
1165
+ type: "state",
1166
+ path
1167
+ } : { type: "covered" };
1168
+ }
1169
+ case "deleteTransition":
1170
+ case "setGuard":
1171
+ case "deleteGuard": {
1172
+ const edgeId = "transitionId" in patch ? patch.transitionId : patch.edgeId;
1173
+ const path = resolveEdgeSourcePath(nextGraph, edgeId) ?? resolveEdgeSourcePath(prevGraph, edgeId);
1174
+ return path ? {
1175
+ type: "state",
1176
+ path
1177
+ } : { type: "covered" };
1178
+ }
1179
+ case "createAction":
1180
+ case "updateAction":
1181
+ case "deleteAction": {
1182
+ if ("nodeId" in patch.location) {
1183
+ const path = resolveStatePath(nextGraph, patch.location.nodeId) ?? resolveStatePath(prevGraph, patch.location.nodeId);
1184
+ return path ? {
1185
+ type: "state",
1186
+ path
1187
+ } : { type: "covered" };
1188
+ }
1189
+ const path = resolveEdgeSourcePath(nextGraph, patch.location.edgeId) ?? resolveEdgeSourcePath(prevGraph, patch.location.edgeId);
1190
+ return path ? {
1191
+ type: "state",
1192
+ path
1193
+ } : { type: "covered" };
1194
+ }
1195
+ case "createInvoke":
1196
+ case "updateInvoke":
1197
+ case "deleteInvoke":
1198
+ case "createTag":
1199
+ case "deleteTag": {
1200
+ const path = resolveStatePath(nextGraph, patch.nodeId) ?? resolveStatePath(prevGraph, patch.nodeId);
1201
+ return path ? {
1202
+ type: "state",
1203
+ path
1204
+ } : { type: "covered" };
1205
+ }
1206
+ case "updateSchemas": return { type: "root" };
1207
+ default: return { type: "root" };
1208
+ }
1209
+ }
1210
+ function deriveReplacementPlan(patches, prevGraph, nextGraph) {
1211
+ const rawPaths = [];
1212
+ for (const patch of patches) {
1213
+ const owner = resolvePatchOwner(patch, prevGraph, nextGraph);
1214
+ if (owner.type === "root") return { type: "root" };
1215
+ if (owner.type === "covered") continue;
1216
+ rawPaths.push(owner.path);
1217
+ }
1218
+ const reducedPaths = reducePaths(rawPaths);
1219
+ if (reducedPaths.length === 0 || reducedPaths.some((path) => path.length === 0)) return { type: "root" };
1220
+ return {
1221
+ type: "states",
1222
+ paths: reducedPaths
1223
+ };
1224
+ }
1225
+ function reducePaths(paths) {
1226
+ const uniquePaths = Array.from(new Set(paths.map((path) => path.join(".")))).map((value) => value === "" ? [] : value.split(".")).sort((a, b) => a.length - b.length);
1227
+ return uniquePaths.filter((path, index) => {
1228
+ return !uniquePaths.some((candidate, candidateIndex) => {
1229
+ if (candidateIndex === index || candidate.length >= path.length) return false;
1230
+ return candidate.every((segment, segmentIndex) => segment === path[segmentIndex]);
1231
+ });
1232
+ });
1233
+ }
1234
+ function getStateConfigByPath(machineConfig, path) {
1235
+ let current = machineConfig;
1236
+ for (const segment of path) {
1237
+ const states = current?.states;
1238
+ if (!isMachineConfig(states)) return;
1239
+ const next = states[segment];
1240
+ if (!isMachineConfig(next)) return;
1241
+ current = next;
1242
+ }
1243
+ return current;
1244
+ }
1245
+ function getStateObjectLiteralByPath(root, path) {
1246
+ let current = root;
1247
+ for (const segment of path) {
1248
+ if (!current) return null;
1249
+ const statesProperty = getObjectLiteralProperty(current, "states");
1250
+ current = statesProperty && getObjectLiteralProperty(statesProperty, segment);
1251
+ }
1252
+ return current;
1253
+ }
1254
+ function getMappedRootObjectLiteral(document, sourceFile, sourceLocations) {
1255
+ if (!sourceLocations?.root || !isSourceLocationForDocument(sourceLocations.root.uri, document)) return null;
1256
+ return findObjectLiteralByRange(sourceFile, sourceLocations.root.range);
1257
+ }
1258
+ async function getMappedStateReplacementTarget(rootDocument, rootSourceFile, sourceLocations, path, openTextDocument) {
1259
+ if (!sourceLocations) return null;
1260
+ const location = sourceLocations.states.find((item) => arePathsEqual(item.path, path));
1261
+ if (!location) return null;
1262
+ const targetDocument = isSourceLocationForDocument(location.uri, rootDocument) ? rootDocument : await openDocumentBySourceUri(location.uri, openTextDocument);
1263
+ if (!targetDocument) return null;
1264
+ const targetSourceFile = isSourceLocationForDocument(location.uri, rootDocument) ? rootSourceFile : createSourceFile(targetDocument, targetDocument.getText());
1265
+ const node = findObjectLiteralByRange(targetSourceFile, location.range);
1266
+ if (!node) return null;
1267
+ return {
1268
+ document: targetDocument,
1269
+ sourceFile: targetSourceFile,
1270
+ node
1271
+ };
1272
+ }
1273
+ async function openDocumentBySourceUri(uri, openTextDocument) {
1274
+ if (!openTextDocument) return null;
1275
+ try {
1276
+ return await openTextDocument(uri);
1277
+ } catch {
1278
+ return null;
1279
+ }
1280
+ }
1281
+ function isSourceLocationForDocument(uri, document) {
1282
+ return uri === (typeof document.uri === "string" ? document.uri : document.uri?.toString()) || uri === document.fileName;
1283
+ }
1284
+ function findObjectLiteralByRange(sourceFile, range) {
1285
+ const start = offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar);
1286
+ const end = offsetAtRangePosition(sourceFile.text, range.endLine, range.endChar);
1287
+ let found = null;
1288
+ const visit = (node) => {
1289
+ if (found) return;
1290
+ if (ts$1.isObjectLiteralExpression(node) && node.getStart(sourceFile) === start && node.getEnd() === end) {
1291
+ found = node;
1292
+ return;
1293
+ }
1294
+ ts$1.forEachChild(node, visit);
1295
+ };
1296
+ visit(sourceFile);
1297
+ return found;
1298
+ }
1299
+ function offsetAtRangePosition(sourceText, line, character) {
1300
+ if (line <= 0) return character;
1301
+ let currentLine = 0;
1302
+ for (let index = 0; index < sourceText.length; index += 1) {
1303
+ if (sourceText.charCodeAt(index) !== 10) continue;
1304
+ currentLine += 1;
1305
+ if (currentLine === line) return index + 1 + character;
1306
+ }
1307
+ return sourceText.length;
1308
+ }
1309
+ function getObjectLiteralProperty(objectLiteral, propertyName) {
1310
+ for (const property of objectLiteral.properties) {
1311
+ if (!ts$1.isPropertyAssignment(property)) continue;
1312
+ if (getPropertyNameText(property.name) !== propertyName) continue;
1313
+ return unwrapObjectLiteralExpression(property.initializer) ?? null;
1314
+ }
1315
+ return null;
1316
+ }
1317
+ function getPropertyNameText(name) {
1318
+ if (ts$1.isIdentifier(name) || ts$1.isStringLiteral(name) || ts$1.isNumericLiteral(name)) return name.text;
1319
+ if (ts$1.isComputedPropertyName(name)) {
1320
+ const expression = name.expression;
1321
+ if (ts$1.isStringLiteral(expression) || ts$1.isNoSubstitutionTemplateLiteral(expression) || ts$1.isNumericLiteral(expression)) return expression.text;
1322
+ }
1323
+ return null;
1324
+ }
1325
+ function createReplacement(document, sourceFile, node, value) {
1326
+ const start = document.positionAt(node.getStart(sourceFile));
1327
+ const end = document.positionAt(node.getEnd());
1328
+ const formatting = getFormattingContext(document, sourceFile, node);
1329
+ return {
1330
+ uri: getDocumentUri(document),
1331
+ range: {
1332
+ startLine: start.line,
1333
+ startChar: start.character,
1334
+ endLine: end.line,
1335
+ endChar: end.character
1336
+ },
1337
+ newText: printExpression(valueToExpression(value, node), sourceFile, formatting)
1338
+ };
1339
+ }
1340
+ function getDocumentUri(document) {
1341
+ return (typeof document.uri === "string" ? document.uri : document.uri?.toString()) ?? document.fileName;
1342
+ }
1343
+ async function tryCreateSemanticPatchSplitForDocuments(document, sourceFile, machineConfigNode, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) {
1344
+ const split = getSemanticStateRenamePatchSplit(patches, prevGraph, nextGraph);
1345
+ if (!split) return null;
1346
+ const { rename } = split;
1347
+ const parentTarget = await getStateMembershipParentTargetForDocuments(document, sourceFile, machineConfigNode, sourceLocations, rename.parentPath, openTextDocument);
1348
+ if (!parentTarget) return null;
1349
+ const targetLiterals = await collectMappedTargetStringLiterals(document, sourceFile, machineConfigNode, sourceLocations, openTextDocument);
1350
+ const replacements = createStateKeyRenameReplacementsForTarget(parentTarget.document, parentTarget.sourceFile, parentTarget.node, rename, sourceLocations, targetLiterals);
1351
+ if (!replacements) return null;
1352
+ return {
1353
+ replacements: replacements.sort(compareReplacementRangesDescending),
1354
+ remainingPatches: split.remainingPatches,
1355
+ sourceLocations: createRenamedSourceLocations(sourceLocations, rename)
1356
+ };
1357
+ }
1358
+ function getSemanticStateRenameFromPatch(patch, prevGraph, nextGraph) {
1359
+ if (patch.op !== "updateState" || patch.key === void 0) return null;
1360
+ const prevPath = resolveStatePath(prevGraph, patch.stateId);
1361
+ const nextPath = resolveStatePath(nextGraph, patch.stateId);
1362
+ if (!prevPath || !nextPath || prevPath.length !== nextPath.length || prevPath.length === 0) return null;
1363
+ const oldKey = prevPath[prevPath.length - 1];
1364
+ const newKey = nextPath[nextPath.length - 1];
1365
+ const parentPath = prevPath.slice(0, -1);
1366
+ if (oldKey === newKey) return null;
1367
+ return {
1368
+ oldKey,
1369
+ newKey,
1370
+ oldPath: prevPath,
1371
+ newPath: nextPath,
1372
+ parentPath
1373
+ };
1374
+ }
1375
+ function getSemanticStateRenamePatchSplit(patches, prevGraph, nextGraph) {
1376
+ let rename = null;
1377
+ const remainingPatches = [];
1378
+ for (const patch of patches) {
1379
+ const patchRename = getSemanticStateRenameFromPatch(patch, prevGraph, nextGraph);
1380
+ if (patchRename) {
1381
+ if (rename) return null;
1382
+ rename = patchRename;
1383
+ continue;
1384
+ }
1385
+ remainingPatches.push(patch);
1386
+ }
1387
+ return rename ? {
1388
+ rename,
1389
+ remainingPatches
1390
+ } : null;
1391
+ }
1392
+ function createRenamedSourceLocations(sourceLocations, rename) {
1393
+ if (!sourceLocations) return;
1394
+ return {
1395
+ ...sourceLocations,
1396
+ states: sourceLocations.states.map((location) => {
1397
+ if (!isPathEqualOrDescendant(location.path, rename.oldPath)) return location;
1398
+ return {
1399
+ ...location,
1400
+ path: [...rename.newPath, ...location.path.slice(rename.oldPath.length)]
1401
+ };
1402
+ })
1403
+ };
1404
+ }
1405
+ function createStateKeyRenameReplacementsForTarget(document, sourceFile, parentObject, rename, sourceLocations, targetLiterals) {
1406
+ const statesObject = getObjectLiteralProperty(parentObject, "states");
1407
+ const location = sourceLocations?.states.find((item) => rename.oldPath && arePathsEqual(item.path, rename.oldPath));
1408
+ const stateProperty = statesObject && (findObjectLiteralProperty(statesObject, rename.oldKey) ?? findObjectLiteralPropertyByRange(sourceFile, statesObject, location?.keyRange));
1409
+ if (!statesObject || !stateProperty) return null;
1410
+ const keyReplacement = createStatePropertyRenameReplacement(document, sourceFile, stateProperty, rename.oldKey, rename.newKey, location?.keySource);
1411
+ if (!keyReplacement) return null;
1412
+ const replacements = [keyReplacement];
1413
+ const initialProperty = getPropertyAssignment(parentObject, "initial");
1414
+ if (initialProperty) {
1415
+ const initialReplacement = createStringInitializerRenameReplacement(document, sourceFile, initialProperty.initializer, rename.oldKey, rename.newKey);
1416
+ if (initialReplacement) replacements.push(initialReplacement);
1417
+ }
1418
+ const supportedScope = new Set([rename.parentPath.join("."), ...getDirectChildStatePaths(parentObject, rename.parentPath).map((path) => path.join("."))]);
1419
+ for (const target of targetLiterals) {
1420
+ if (!referencesRenamedSibling(target.node.text, rename.oldKey)) continue;
1421
+ const sourceKey = target.sourcePath.join(".");
1422
+ if (!(target.sourcePath.length === rename.parentPath.length || arePathsEqual(target.sourcePath.slice(0, -1), rename.parentPath)) || !supportedScope.has(sourceKey)) return null;
1423
+ const replacement = createStringLiteralReplacement(target.document, target.sourceFile, target.node, renameSiblingReference(target.node.text, rename.oldKey, rename.newKey));
1424
+ replacements.push(replacement);
1425
+ }
1426
+ return replacements;
1427
+ }
1428
+ function getDirectChildStatePaths(stateObject, parentPath) {
1429
+ const statesObject = getObjectLiteralProperty(stateObject, "states");
1430
+ if (!statesObject) return [];
1431
+ return statesObject.properties.flatMap((property) => {
1432
+ const key = getStatePropertyKeyText(property);
1433
+ if (!key) return [];
1434
+ return [[...parentPath, key]];
1435
+ });
1436
+ }
1437
+ function collectTargetStringLiterals(machineConfigNode) {
1438
+ const literals = [];
1439
+ const visitStateObject = (stateObject, sourcePath) => {
1440
+ for (const propertyName of [
1441
+ "always",
1442
+ "after",
1443
+ "on",
1444
+ "onDone"
1445
+ ]) {
1446
+ const property = getPropertyAssignment(stateObject, propertyName);
1447
+ if (!property) continue;
1448
+ collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals);
1449
+ }
1450
+ const statesObject = getObjectLiteralProperty(stateObject, "states");
1451
+ if (!statesObject) return;
1452
+ for (const property of statesObject.properties) {
1453
+ if (!ts$1.isPropertyAssignment(property)) continue;
1454
+ const key = getPropertyNameText(property.name);
1455
+ const childState = unwrapObjectLiteralExpression(property.initializer);
1456
+ if (!key || !childState) continue;
1457
+ visitStateObject(childState, [...sourcePath, key]);
1458
+ }
1459
+ };
1460
+ visitStateObject(machineConfigNode, []);
1461
+ return literals;
1462
+ }
1463
+ async function collectMappedTargetStringLiterals(rootDocument, rootSourceFile, machineConfigNode, sourceLocations, openTextDocument) {
1464
+ const literals = collectTargetStringLiterals(machineConfigNode).map((target) => ({
1465
+ ...target,
1466
+ document: rootDocument,
1467
+ sourceFile: rootSourceFile
1468
+ }));
1469
+ if (!sourceLocations) return literals;
1470
+ const seen = new Set(literals.map((target) => getTargetLiteralReplacementKey(rootDocument, rootSourceFile, target.node)));
1471
+ for (const location of sourceLocations.states) {
1472
+ const targetDocument = isSourceLocationForDocument(location.uri, rootDocument) ? rootDocument : await openDocumentBySourceUri(location.uri, openTextDocument);
1473
+ if (!targetDocument) continue;
1474
+ const targetSourceFile = isSourceLocationForDocument(location.uri, rootDocument) ? rootSourceFile : createSourceFile(targetDocument, targetDocument.getText());
1475
+ const stateObject = findObjectLiteralByRange(targetSourceFile, location.range);
1476
+ if (!stateObject) continue;
1477
+ const stateLiterals = [];
1478
+ collectTargetStringLiteralsFromStateObject(stateObject, location.path, stateLiterals);
1479
+ for (const target of stateLiterals) {
1480
+ const key = getTargetLiteralReplacementKey(targetDocument, targetSourceFile, target.node);
1481
+ if (seen.has(key)) continue;
1482
+ seen.add(key);
1483
+ literals.push({
1484
+ ...target,
1485
+ document: targetDocument,
1486
+ sourceFile: targetSourceFile
1487
+ });
1488
+ }
1489
+ }
1490
+ return literals;
1491
+ }
1492
+ function getTargetLiteralReplacementKey(document, sourceFile, node) {
1493
+ return `${getDocumentUri(document)}:${node.getStart(sourceFile)}:${node.getEnd()}`;
1494
+ }
1495
+ function collectTargetStringLiteralsFromStateObject(stateObject, sourcePath, literals) {
1496
+ for (const propertyName of [
1497
+ "always",
1498
+ "after",
1499
+ "on",
1500
+ "onDone"
1501
+ ]) {
1502
+ const property = getPropertyAssignment(stateObject, propertyName);
1503
+ if (!property) continue;
1504
+ collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals);
1505
+ }
1506
+ const statesObject = getObjectLiteralProperty(stateObject, "states");
1507
+ if (!statesObject) return;
1508
+ for (const property of statesObject.properties) {
1509
+ if (!ts$1.isPropertyAssignment(property)) continue;
1510
+ const key = getPropertyNameText(property.name);
1511
+ const childState = unwrapObjectLiteralExpression(property.initializer);
1512
+ if (!key || !childState) continue;
1513
+ collectTargetStringLiteralsFromStateObject(childState, [...sourcePath, key], literals);
1514
+ }
1515
+ }
1516
+ function collectTargetStringLiteralsFromExpression(expression, sourcePath, literals) {
1517
+ if (ts$1.isStringLiteralLike(expression)) {
1518
+ literals.push({
1519
+ sourcePath,
1520
+ node: expression
1521
+ });
1522
+ return;
1523
+ }
1524
+ if (ts$1.isArrayLiteralExpression(expression)) {
1525
+ for (const element of expression.elements) if (ts$1.isExpression(element)) collectTargetStringLiteralsFromExpression(element, sourcePath, literals);
1526
+ return;
1527
+ }
1528
+ if (!ts$1.isObjectLiteralExpression(expression)) return;
1529
+ const targetProperty = getPropertyAssignment(expression, "target");
1530
+ if (targetProperty) {
1531
+ collectTargetStringLiteralsFromExpression(targetProperty.initializer, sourcePath, literals);
1532
+ return;
1533
+ }
1534
+ for (const property of expression.properties) {
1535
+ if (!ts$1.isPropertyAssignment(property)) continue;
1536
+ collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals);
1537
+ }
1538
+ }
1539
+ function referencesRenamedSibling(value, oldKey) {
1540
+ return value === oldKey || value.startsWith(`${oldKey}.`);
1541
+ }
1542
+ function renameSiblingReference(value, oldKey, newKey) {
1543
+ if (value === oldKey) return newKey;
1544
+ return value.startsWith(`${oldKey}.`) ? `${newKey}${value.slice(oldKey.length)}` : value;
1545
+ }
1546
+ function arePathsEqual(left, right) {
1547
+ return left.length === right.length && left.every((segment, index) => segment === right[index]);
1548
+ }
1549
+ function createPropertyNameReplacement(document, sourceFile, propertyName, nextName) {
1550
+ if (!isSupportedPropertyName(propertyName)) return null;
1551
+ const start = document.positionAt(propertyName.getStart(sourceFile));
1552
+ const end = document.positionAt(propertyName.getEnd());
1553
+ const sourceText = sourceFile.text.slice(propertyName.getStart(sourceFile), propertyName.getEnd());
1554
+ return {
1555
+ range: {
1556
+ startLine: start.line,
1557
+ startChar: start.character,
1558
+ endLine: end.line,
1559
+ endChar: end.character
1560
+ },
1561
+ uri: getDocumentUri(document),
1562
+ newText: formatPropertyNameText(propertyName, nextName, sourceText)
1563
+ };
1564
+ }
1565
+ function createStatePropertyRenameReplacement(document, sourceFile, property, oldKey, newKey, keySource) {
1566
+ 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));
1567
+ if (ts$1.isPropertyAssignment(property)) {
1568
+ if (ts$1.isComputedPropertyName(property.name)) return createPropertyNameLiteralReplacement(document, sourceFile, property.name, newKey);
1569
+ return createPropertyNameReplacement(document, sourceFile, property.name, newKey);
1570
+ }
1571
+ if (!ts$1.isShorthandPropertyAssignment(property)) return null;
1572
+ const start = document.positionAt(property.name.getStart(sourceFile));
1573
+ const end = document.positionAt(property.name.getEnd());
1574
+ const sourceText = sourceFile.text.slice(property.name.getStart(sourceFile), property.name.getEnd());
1575
+ const nextPropertyName = formatPropertyNameText(property.name, newKey, sourceText);
1576
+ return {
1577
+ range: {
1578
+ startLine: start.line,
1579
+ startChar: start.character,
1580
+ endLine: end.line,
1581
+ endChar: end.character
1582
+ },
1583
+ uri: getDocumentUri(document),
1584
+ newText: `${nextPropertyName}: ${oldKey}`
1585
+ };
1586
+ }
1587
+ function createPropertyNameLiteralReplacement(document, sourceFile, propertyName, nextName) {
1588
+ const start = document.positionAt(propertyName.getStart(sourceFile));
1589
+ const end = document.positionAt(propertyName.getEnd());
1590
+ return {
1591
+ range: {
1592
+ startLine: start.line,
1593
+ startChar: start.character,
1594
+ endLine: end.line,
1595
+ endChar: end.character
1596
+ },
1597
+ uri: getDocumentUri(document),
1598
+ newText: isIdentifierText(nextName) ? nextName : JSON.stringify(nextName)
1599
+ };
1600
+ }
1601
+ function createStringInitializerRenameReplacement(document, sourceFile, expression, oldValue, newValue) {
1602
+ if (!ts$1.isStringLiteralLike(expression) || expression.text !== oldValue) return null;
1603
+ return createStringLiteralReplacement(document, sourceFile, expression, newValue);
1604
+ }
1605
+ function createStringLiteralReplacement(document, sourceFile, expression, nextValue) {
1606
+ const start = document.positionAt(expression.getStart(sourceFile));
1607
+ const end = document.positionAt(expression.getEnd());
1608
+ const sourceText = sourceFile.text.slice(expression.getStart(sourceFile), expression.getEnd());
1609
+ return {
1610
+ range: {
1611
+ startLine: start.line,
1612
+ startChar: start.character,
1613
+ endLine: end.line,
1614
+ endChar: end.character
1615
+ },
1616
+ uri: getDocumentUri(document),
1617
+ newText: formatStringLiteralText(sourceText, nextValue)
1618
+ };
1619
+ }
1620
+ function createSourceRangeReplacement(document, sourceFile, range, newText) {
1621
+ const startOffset = offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar);
1622
+ const endOffset = offsetAtRangePosition(sourceFile.text, range.endLine, range.endChar);
1623
+ const start = document.positionAt(startOffset);
1624
+ const end = document.positionAt(endOffset);
1625
+ return {
1626
+ range: {
1627
+ startLine: start.line,
1628
+ startChar: start.character,
1629
+ endLine: end.line,
1630
+ endChar: end.character
1631
+ },
1632
+ uri: getDocumentUri(document),
1633
+ newText
1634
+ };
1635
+ }
1636
+ function isSourceRangeInDocument(sourceFile, range) {
1637
+ return offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar) <= sourceFile.text.length;
1638
+ }
1639
+ function isSupportedPropertyName(propertyName) {
1640
+ if (ts$1.isIdentifier(propertyName) || ts$1.isStringLiteral(propertyName) || ts$1.isNumericLiteral(propertyName)) return true;
1641
+ if (ts$1.isComputedPropertyName(propertyName)) {
1642
+ const expression = propertyName.expression;
1643
+ return ts$1.isStringLiteral(expression) || ts$1.isNoSubstitutionTemplateLiteral(expression) || ts$1.isNumericLiteral(expression);
1644
+ }
1645
+ return false;
1646
+ }
1647
+ function formatPropertyNameText(propertyName, nextName, sourceText) {
1648
+ if (ts$1.isIdentifier(propertyName) && isIdentifierText(nextName)) return nextName;
1649
+ if (ts$1.isComputedPropertyName(propertyName)) return `[${formatStringLiteralText(sourceText.slice(1, -1), nextName)}]`;
1650
+ return formatStringLiteralText(sourceText, nextName);
1651
+ }
1652
+ function formatStringLiteralText(sourceText, nextValue) {
1653
+ const quote = sourceText.startsWith("'") ? "'" : sourceText.startsWith("`") ? "`" : "\"";
1654
+ return `${quote}${quote === "'" ? nextValue.replace(/\\/g, "\\\\").replace(/'/g, "\\'") : quote === "\"" ? nextValue.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") : nextValue.replace(/\\/g, "\\\\").replace(/`/g, "\\`")}${quote}`;
1655
+ }
1656
+ function compareReplacementRangesDescending(a, b) {
1657
+ if (a.range.startLine !== b.range.startLine) return b.range.startLine - a.range.startLine;
1658
+ return b.range.startChar - a.range.startChar;
1659
+ }
1660
+ function printExpression(expression, sourceFile, formatting) {
1661
+ return reindentPrintedExpression(ts$1.createPrinter({ newLine: formatting.newLineKind }).printNode(ts$1.EmitHint.Expression, expression, sourceFile), formatting);
1662
+ }
1663
+ function reindentPrintedExpression(printed, formatting) {
1664
+ const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
1665
+ const lines = printed.split(/\r?\n/);
1666
+ if (lines.length <= 1) return printed;
1667
+ return lines.map((line, index) => {
1668
+ if (index === 0) return line;
1669
+ if (line.trim() === "") return "";
1670
+ const leadingSpaces = line.match(/^ */)?.[0].length ?? 0;
1671
+ const indentLevel = Math.floor(leadingSpaces / 4);
1672
+ return `${formatting.baseIndent}${formatting.indentUnit.repeat(indentLevel)}${line.slice(leadingSpaces)}`;
1673
+ }).join(lineSeparator);
1674
+ }
1675
+ function getFormattingContext(document, sourceFile, node) {
1676
+ const sourceText = sourceFile.text;
1677
+ const lineStart = getLineStartOffset(sourceText, node.getStart(sourceFile));
1678
+ const lineIndent = sourceText.slice(lineStart).match(/^[ \t]*/)?.[0] ?? "";
1679
+ const editorIndentUnit = getEditorIndentUnit(document);
1680
+ const inferredIndentUnit = inferIndentUnitFromNode(sourceText, node, sourceFile, lineIndent) ?? inferIndentUnitFromSource(sourceText);
1681
+ return {
1682
+ baseIndent: lineIndent,
1683
+ indentUnit: editorIndentUnit ?? inferredIndentUnit ?? " ",
1684
+ newLineKind: sourceText.includes("\r\n") ? ts$1.NewLineKind.CarriageReturnLineFeed : ts$1.NewLineKind.LineFeed
1685
+ };
1686
+ }
1687
+ function getEditorIndentUnit(document) {
1688
+ return document.editorIndentUnit ?? null;
1689
+ }
1690
+ function inferIndentUnitFromNode(sourceText, node, sourceFile, baseIndent) {
1691
+ 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));
1692
+ }
1693
+ function inferIndentUnitFromSource(sourceText) {
1694
+ return getShortestIndent(sourceText.split(/\r?\n/).map((line) => line.match(/^[ \t]+(?=\S)/)?.[0] ?? "").filter(Boolean));
1695
+ }
1696
+ function getShortestIndent(indents) {
1697
+ if (indents.length === 0) return null;
1698
+ return indents.reduce((shortest, current) => current.length < shortest.length ? current : shortest);
1699
+ }
1700
+ function getLineStartOffset(sourceText, offset) {
1701
+ const lastNewline = sourceText.lastIndexOf("\n", offset - 1);
1702
+ if (lastNewline === -1) return 0;
1703
+ return lastNewline + 1;
1704
+ }
1705
+ function valueToExpression(value, existingExpression) {
1706
+ const inlineExpression = inlineExpressionDirectiveToExpression(value);
1707
+ if (inlineExpression) return inlineExpression;
1708
+ if (value === null) return ts$1.factory.createNull();
1709
+ if (typeof value === "string") return ts$1.factory.createStringLiteral(value);
1710
+ if (typeof value === "number") {
1711
+ if (value < 0) return ts$1.factory.createPrefixUnaryExpression(ts$1.SyntaxKind.MinusToken, ts$1.factory.createNumericLiteral(Math.abs(value)));
1712
+ return ts$1.factory.createNumericLiteral(value);
1713
+ }
1714
+ if (typeof value === "boolean") return value ? ts$1.factory.createTrue() : ts$1.factory.createFalse();
1715
+ if (Array.isArray(value)) {
1716
+ const existingArray = existingExpression && ts$1.isArrayLiteralExpression(existingExpression) ? existingExpression : void 0;
1717
+ const elements = value.map((item, index) => valueToExpression(item, existingArray && ts$1.isExpression(existingArray.elements[index]) ? existingArray.elements[index] : void 0));
1718
+ if (existingArray) {
1719
+ const updatedArray = ts$1.factory.createArrayLiteralExpression(elements, true);
1720
+ ts$1.setOriginalNode(updatedArray, existingArray);
1721
+ ts$1.setTextRange(updatedArray, existingArray);
1722
+ return updatedArray;
1723
+ }
1724
+ return ts$1.factory.createArrayLiteralExpression(elements, true);
1725
+ }
1726
+ if (isMachineConfig(value)) {
1727
+ const existingObject = existingExpression && ts$1.isObjectLiteralExpression(existingExpression) ? existingExpression : void 0;
1728
+ const properties = Object.entries(value).filter(([, propertyValue]) => propertyValue !== void 0).map(([key, propertyValue]) => {
1729
+ const existingProperty = existingObject ? getPropertyAssignment(existingObject, key) : null;
1730
+ const nextInitializer = getPreservedPropertyInitializer(key, propertyValue, existingProperty?.initializer) ?? valueToExpression(propertyValue, existingProperty?.initializer);
1731
+ if (existingProperty) return ts$1.factory.updatePropertyAssignment(existingProperty, existingProperty.name, nextInitializer);
1732
+ return ts$1.factory.createPropertyAssignment(toPropertyName(key), nextInitializer);
1733
+ });
1734
+ if (existingObject) {
1735
+ const updatedObject = ts$1.factory.createObjectLiteralExpression(properties, true);
1736
+ ts$1.setOriginalNode(updatedObject, existingObject);
1737
+ ts$1.setTextRange(updatedObject, existingObject);
1738
+ return updatedObject;
1739
+ }
1740
+ return ts$1.factory.createObjectLiteralExpression(properties, true);
1741
+ }
1742
+ return ts$1.factory.createIdentifier("undefined");
1743
+ }
1744
+ function inlineExpressionDirectiveToExpression(value) {
1745
+ if (!isInlineExpressionDirective(value)) return null;
1746
+ return ts$1.factory.createIdentifier(value.expr);
1747
+ }
1748
+ function isInlineExpressionDirective(value) {
1749
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1750
+ const directive = value;
1751
+ return directive["@type"] === "code" && typeof directive.expr === "string";
1752
+ }
1753
+ function getPreservedPropertyInitializer(propertyName, nextValue, existingInitializer) {
1754
+ if (propertyName !== "description" || typeof nextValue !== "string" || !existingInitializer) return null;
1755
+ if (ts$1.isStringLiteralLike(existingInitializer)) return existingInitializer.text === nextValue ? existingInitializer : null;
1756
+ return existingInitializer;
1757
+ }
1758
+ function getPropertyAssignment(objectLiteral, propertyName) {
1759
+ for (const property of objectLiteral.properties) {
1760
+ if (!ts$1.isPropertyAssignment(property)) continue;
1761
+ if (getPropertyNameText(property.name) === propertyName) return property;
1762
+ }
1763
+ return null;
1764
+ }
1765
+ function toPropertyName(name) {
1766
+ return isIdentifierText(name) ? ts$1.factory.createIdentifier(name) : ts$1.factory.createStringLiteral(name);
1767
+ }
1768
+ function isIdentifierText(value) {
1769
+ return /^[$A-Z_][0-9A-Z_$]*$/i.test(value);
1770
+ }
1771
+
1772
+ //#endregion
1773
+ //#region ../editor-sync/src/internal/statelyMetadata.ts
1774
+ const STATELY_METADATA_PREFIX = "@statelyai.";
1775
+ function isPlainObject(value) {
1776
+ return !!value && typeof value === "object" && !Array.isArray(value);
1777
+ }
1778
+ function stripStatelyMetadata(value) {
1779
+ if (Array.isArray(value)) return value.map((item) => stripStatelyMetadata(item));
1780
+ if (!isPlainObject(value)) return value;
1781
+ const result = {};
1782
+ for (const [key, child] of Object.entries(value)) {
1783
+ if (key.startsWith(STATELY_METADATA_PREFIX)) continue;
1784
+ const nextChild = stripStatelyMetadata(child);
1785
+ if (isPlainObject(nextChild) && Object.keys(nextChild).length === 0 && isPlainObject(child)) continue;
1786
+ result[key] = nextChild;
1787
+ }
1788
+ return result;
1789
+ }
1790
+
1791
+ //#endregion
1792
+ //#region ../editor-sync/src/internal/adapters.ts
1793
+ const xstateAdapter = {
1794
+ id: "xstate",
1795
+ format: "xstate",
1796
+ parseSourceToMachine(text, document) {
1797
+ return parseSourceToMachine(text, document);
1798
+ },
1799
+ collectSourceLocations(text, document) {
1800
+ return collectXStateSourceLocations(text, document);
1801
+ },
1802
+ async applyMachineToDocument(machineConfig, document, options) {
1803
+ return applyMachineToSourceDocuments(options?.preserveStatelyMetadata === false ? stripStatelyMetadata(machineConfig) : machineConfig, document, options);
1804
+ }
1805
+ };
1806
+ function createSerializedExportAdapter(format) {
1807
+ return {
1808
+ id: format,
1809
+ format,
1810
+ parseSourceToMachine(text) {
1811
+ return text;
1812
+ },
1813
+ async applyMachineToDocument(_machineConfig, document, options) {
1814
+ const serialized = await options?.requestSerialized?.(format);
1815
+ if (typeof serialized !== "string") return [];
1816
+ const fullText = document.getText();
1817
+ const end = document.positionAt(fullText.length);
1818
+ return [{
1819
+ range: {
1820
+ startLine: 0,
1821
+ startChar: 0,
1822
+ endLine: end.line,
1823
+ endChar: end.character
1824
+ },
1825
+ newText: serialized
1826
+ }];
1827
+ }
1828
+ };
1829
+ }
1830
+ const xstateJsonAdapter = createSerializedExportAdapter("xstate-json");
1831
+ const xgraphAdapter = createSerializedExportAdapter("xgraph");
1832
+ const mermaidAdapter = createSerializedExportAdapter("mermaid");
1833
+ const aslJsonAdapter = createSerializedExportAdapter("asl-json");
1834
+ const aslYamlAdapter = createSerializedExportAdapter("asl-yaml");
1835
+ const reduxAdapter = createSerializedExportAdapter("redux");
1836
+ const zustandAdapter = createSerializedExportAdapter("zustand");
1837
+ function isJavaScriptOrTypeScriptFile(fileName) {
1838
+ return /\.(?:c|m)?(?:jsx?|tsx?)$/i.test(fileName);
1839
+ }
1840
+ function isYamlFile(fileName) {
1841
+ return /\.(?:asl\.)?ya?ml$/i.test(fileName);
1842
+ }
1843
+ function hasAslExtension(fileName) {
1844
+ return /\.asl\.(?:jsonc?|ya?ml)$/i.test(fileName);
1845
+ }
1846
+ function isJsonFile(fileName) {
1847
+ return /\.jsonc?$/i.test(fileName);
1848
+ }
1849
+ function isMermaidFile(fileName) {
1850
+ return /\.(?:mmd|mermaid)$/i.test(fileName);
1851
+ }
1852
+ function stripMermaidFrontmatter(text) {
1853
+ return text.replace(/^\s*---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
1854
+ }
1855
+ function looksLikeMermaid(text) {
1856
+ return /^\s*(?:stateDiagram(?:-v2)?|flowchart(?:\s+(?:TB|TD|BT|LR|RL))?|graph\s+(?:TB|TD|BT|LR|RL))\b/.test(stripMermaidFrontmatter(text));
1857
+ }
1858
+ function looksLikeAmazonStatesLanguage(text) {
1859
+ return /(^|\s|["'])StartAt["']?\s*:/m.test(text) && /(^|\s|["'])States["']?\s*:/m.test(text);
1860
+ }
1861
+ function looksLikeXStateJson(text) {
1862
+ try {
1863
+ const value = JSON.parse(text);
1864
+ return Boolean(value && typeof value === "object" && !Array.isArray(value) && "states" in value);
1865
+ } catch {
1866
+ return false;
1867
+ }
1868
+ }
1869
+ function looksLikeXGraphJson(text) {
1870
+ try {
1871
+ const value = JSON.parse(text);
1872
+ return Boolean(value && typeof value === "object" && !Array.isArray(value) && Array.isArray(value.nodes) && Array.isArray(value.edges));
1873
+ } catch {
1874
+ return false;
1875
+ }
1876
+ }
1877
+ function looksLikeReduxToolkit(text) {
1878
+ return /\bcreateSlice\s*\(/.test(text) && /@reduxjs\/toolkit/.test(text);
1879
+ }
1880
+ function looksLikeZustand(text) {
1881
+ return /\bcreate\s*\(\s*\(/.test(text) && /from\s+["']zustand["']/.test(text);
1882
+ }
1883
+ function getSyncAdapter(document, text = "") {
1884
+ const { fileName } = document;
1885
+ const resolvedText = text || document.getText?.() || "";
1886
+ if (isJavaScriptOrTypeScriptFile(fileName)) {
1887
+ if (looksLikeReduxToolkit(resolvedText)) return reduxAdapter;
1888
+ if (looksLikeZustand(resolvedText)) return zustandAdapter;
1889
+ return xstateAdapter;
1890
+ }
1891
+ if (hasAslExtension(fileName) || looksLikeAmazonStatesLanguage(resolvedText)) {
1892
+ if (isYamlFile(fileName)) return aslYamlAdapter;
1893
+ return aslJsonAdapter;
1894
+ }
1895
+ if (isMermaidFile(fileName) || looksLikeMermaid(resolvedText)) return mermaidAdapter;
1896
+ if (isJsonFile(fileName) && looksLikeXGraphJson(resolvedText)) return xgraphAdapter;
1897
+ if (isJsonFile(fileName) && looksLikeXStateJson(resolvedText)) return xstateJsonAdapter;
1898
+ throw new Error(`Unsupported document for Stately sync: ${fileName}`);
1899
+ }
1900
+ function parseDocumentToMachine(document) {
1901
+ const text = document.getText();
1902
+ const adapter = getSyncAdapter(document, text);
1903
+ return {
1904
+ adapter,
1905
+ format: adapter.format,
1906
+ machine: adapter.parseSourceToMachine(text, document),
1907
+ sourceLocations: adapter.collectSourceLocations?.(text, document)
1908
+ };
1909
+ }
1910
+
1911
+ //#endregion
1912
+ //#region src/sync.ts
1913
+ const execFileAsync = promisify(execFile);
1914
+ const LOCAL_EXTRACTION_TIMEOUT_MS = 5e3;
1915
+ const MAX_CAPTURED_LOCAL_MACHINES = 100;
1916
+ function createLocalCapturePlugin() {
1917
+ return {
1918
+ name: "statelyai-xstate-capture",
1919
+ setup(build) {
1920
+ build.onResolve({ filter: /^xstate(?:\/.*)?$/ }, (args) => ({
1921
+ path: args.path,
1922
+ namespace: "statelyai-xstate-capture"
1923
+ }));
1924
+ build.onLoad({
1925
+ filter: /^xstate(?:\/.*)?$/,
1926
+ namespace: "statelyai-xstate-capture"
1927
+ }, async (args) => {
1928
+ const xstateModule = await import(args.path);
1929
+ return {
1930
+ contents: `
1931
+ const __xstate = globalThis.__statelyaiXState;
1932
+ const __captured = globalThis.__capturedMachines ?? (globalThis.__capturedMachines = []);
1933
+ const __maxCaptured = ${MAX_CAPTURED_LOCAL_MACHINES};
1934
+
1935
+ function __capture(machine, type) {
1936
+ if (__captured.length >= __maxCaptured || !machine?.config) {
1937
+ return machine;
1938
+ }
1939
+
1940
+ try {
1941
+ __captured.push(JSON.stringify({
1942
+ config: machine.config,
1943
+ _type: type,
1944
+ }));
1945
+ } catch {}
1946
+
1947
+ return machine;
1948
+ }
1949
+
1950
+ ${Object.keys(xstateModule).filter((key) => key !== "createMachine" && key !== "setup").filter((key) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)).sort().map((key) => `export const ${key} = __xstate.${key};`).join("\n")}
1951
+ export const createMachine = (...args) => __capture(__xstate.createMachine(...args), 'createMachine');
1952
+ export const setup = (...args) => {
1953
+ const setupResult = __xstate.setup(...args);
1954
+ return {
1955
+ ...setupResult,
1956
+ createMachine: (...machineArgs) =>
1957
+ __capture(setupResult.createMachine(...machineArgs), 'setup.createMachine'),
1958
+ };
1959
+ };
1960
+ `,
1961
+ loader: "js"
1962
+ };
1963
+ });
1964
+ }
1965
+ };
1966
+ }
1967
+ function getEsbuildLoader(sourcePath) {
1968
+ switch (path.extname(sourcePath).toLowerCase()) {
1969
+ case ".tsx": return "tsx";
1970
+ case ".jsx": return "jsx";
1971
+ case ".js":
1972
+ case ".mjs":
1973
+ case ".cjs": return "js";
1974
+ default: return "ts";
1975
+ }
1976
+ }
1977
+ async function extractMachinesFromLocalSource(sourcePath, contents) {
1978
+ try {
1979
+ const parsed = parseDocumentToMachine(createTextDocument(sourcePath, contents));
1980
+ if (parsed.format !== "xstate" || typeof parsed.machine !== "string") return {
1981
+ machines: [],
1982
+ error: `Unsupported local source format: ${parsed.format}`
1983
+ };
1984
+ const bundledCode = (await esbuild.build({
1985
+ stdin: {
1986
+ contents: parsed.machine,
1987
+ sourcefile: sourcePath,
1988
+ loader: getEsbuildLoader(sourcePath),
1989
+ resolveDir: path.dirname(sourcePath)
1990
+ },
1991
+ absWorkingDir: path.dirname(sourcePath),
1992
+ bundle: true,
1993
+ write: false,
1994
+ format: "iife",
1995
+ target: "es2020",
1996
+ platform: "neutral",
1997
+ logLevel: "silent",
1998
+ plugins: [createLocalCapturePlugin()]
1999
+ })).outputFiles[0]?.text;
2000
+ if (!bundledCode) return {
2001
+ machines: [],
2002
+ error: "Failed to bundle source for local machine extraction."
2003
+ };
2004
+ const sandbox = {
2005
+ __statelyaiXState: await import("xstate"),
2006
+ __capturedMachines: [],
2007
+ console: {
2008
+ log: () => {},
2009
+ error: () => {},
2010
+ warn: () => {},
2011
+ info: () => {},
2012
+ debug: () => {}
2013
+ },
2014
+ setTimeout: () => 0,
2015
+ clearTimeout: () => {},
2016
+ setInterval: () => 0,
2017
+ clearInterval: () => {},
2018
+ queueMicrotask: () => {}
2019
+ };
2020
+ const context = vm.createContext(sandbox);
2021
+ new vm.Script(bundledCode, { filename: sourcePath }).runInContext(context, { timeout: LOCAL_EXTRACTION_TIMEOUT_MS });
2022
+ const captured = sandbox.__capturedMachines;
2023
+ if (!Array.isArray(captured)) return { machines: [] };
2024
+ return { machines: captured.map((entry) => typeof entry === "string" ? JSON.parse(entry) : entry).filter((entry) => typeof entry === "object" && entry !== null && "config" in entry) };
2025
+ } catch (error) {
2026
+ return {
2027
+ machines: [],
2028
+ error: error instanceof Error ? error.message : String(error)
2029
+ };
2030
+ }
2031
+ }
2032
+ function isUrl(value) {
2033
+ try {
2034
+ const url = new URL(value);
2035
+ return url.protocol === "http:" || url.protocol === "https:";
2036
+ } catch {
2037
+ return false;
2038
+ }
2039
+ }
2040
+ async function fileExists(filePath) {
2041
+ try {
2042
+ await fs.access(filePath);
2043
+ return true;
2044
+ } catch {
2045
+ return false;
2046
+ }
2047
+ }
2048
+ function parseGitHubRemote(remoteUrl) {
2049
+ const httpsMatch = remoteUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
2050
+ if (httpsMatch) {
2051
+ const [, owner, repo] = httpsMatch;
2052
+ if (!owner || !repo) return null;
2053
+ return {
2054
+ url: `https://github.com/${owner}/${repo}`,
2055
+ owner,
2056
+ repo
2057
+ };
2058
+ }
2059
+ const sshMatch = remoteUrl.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/);
2060
+ if (sshMatch) {
2061
+ const [, owner, repo] = sshMatch;
2062
+ if (!owner || !repo) return null;
2063
+ return {
2064
+ url: `https://github.com/${owner}/${repo}`,
2065
+ owner,
2066
+ repo
2067
+ };
2068
+ }
2069
+ return null;
2070
+ }
2071
+ async function inferConnectedRepo(filePath, cwd) {
2072
+ const workingDir = cwd ?? path.dirname(filePath);
2073
+ try {
2074
+ const [{ stdout: repoRootStdout }, { stdout: remoteStdout }, { stdout: branchStdout }, { stdout: treeShaStdout }] = await Promise.all([
2075
+ execFileAsync("git", ["rev-parse", "--show-toplevel"], { cwd: workingDir }),
2076
+ execFileAsync("git", [
2077
+ "remote",
2078
+ "get-url",
2079
+ "origin"
2080
+ ], { cwd: workingDir }),
2081
+ execFileAsync("git", ["branch", "--show-current"], { cwd: workingDir }),
2082
+ execFileAsync("git", ["rev-parse", "HEAD"], { cwd: workingDir })
2083
+ ]);
2084
+ const repoRoot = repoRootStdout.trim();
2085
+ const remote = parseGitHubRemote(remoteStdout.trim());
2086
+ const branch = branchStdout.trim();
2087
+ const treeSha = treeShaStdout.trim();
2088
+ if (!remote || !branch || !treeSha) return;
2089
+ const relativePath = path.relative(repoRoot, filePath).replace(/\\/g, "/");
2090
+ const relativeDir = path.dirname(relativePath).replace(/\\/g, "/");
2091
+ const selectedPaths = relativePath && relativePath !== "." ? [relativePath] : [];
2092
+ return {
2093
+ ...remote,
2094
+ branch,
2095
+ treeSha,
2096
+ autoSync: false,
2097
+ pathForNewFiles: relativeDir && relativeDir !== "." ? relativeDir : "src/stately-studio",
2098
+ selectedPaths
2099
+ };
2100
+ } catch {
2101
+ return;
2102
+ }
2103
+ }
2104
+ function normalizeActions(value) {
2105
+ if (value == null) return [];
2106
+ return (Array.isArray(value) ? value : [value]).map((item) => {
2107
+ if (typeof item === "string") return { type: item };
2108
+ if (typeof item === "object" && item !== null && "type" in item) {
2109
+ const type = item.type;
2110
+ const params = "params" in item && typeof item.params === "object" && item.params ? item.params : void 0;
2111
+ return {
2112
+ type,
2113
+ ...params ? { params } : {}
2114
+ };
2115
+ }
2116
+ return { type: String(item) };
2117
+ });
2118
+ }
2119
+ function normalizeTags(value) {
2120
+ if (!value) return [];
2121
+ if (Array.isArray(value)) return value.map((tag) => String(tag));
2122
+ return [String(value)];
2123
+ }
2124
+ function normalizeInvoke(value) {
2125
+ if (!value) return [];
2126
+ return (Array.isArray(value) ? value : [value]).map((invoke, index) => ({
2127
+ src: invoke.src,
2128
+ id: invoke.id ?? `invoke[${index}]`,
2129
+ ...invoke.input ? { input: invoke.input } : {}
2130
+ }));
2131
+ }
2132
+ function resolveTargetId(sourceParentPath, target) {
2133
+ if (!target) return;
2134
+ if (target.startsWith("#")) {
2135
+ const stripped = target.slice(1);
2136
+ const machineIndex = stripped.indexOf(".");
2137
+ if (machineIndex >= 0) return `(machine).${stripped.slice(machineIndex + 1)}`;
2138
+ return `(machine).${stripped}`;
2139
+ }
2140
+ if (target.startsWith("(machine)")) return target;
2141
+ if (target.includes(".")) return `(machine).${target}`;
2142
+ return `${sourceParentPath}.${target}`;
2143
+ }
2144
+ function appendTransitionEdges(edges, sourceId, sourceParentPath, eventType, transition, edgeCounts) {
2145
+ const transitions = Array.isArray(transition) ? transition : [transition];
2146
+ for (const item of transitions) {
2147
+ const normalized = typeof item === "string" ? { target: item } : item;
2148
+ const targetId = resolveTargetId(sourceParentPath, Array.isArray(normalized.target) ? normalized.target[0] : normalized.target);
2149
+ const groupKey = `${sourceId}:${eventType}`;
2150
+ const index = edgeCounts.get(groupKey) ?? 0;
2151
+ edgeCounts.set(groupKey, index + 1);
2152
+ edges.push({
2153
+ type: "edge",
2154
+ id: `${sourceId}#${eventType}[${index}]`,
2155
+ sourceId,
2156
+ targetId: targetId ?? sourceId,
2157
+ label: eventType,
2158
+ data: {
2159
+ eventType,
2160
+ transitionType: normalized.reenter === true ? "reenter" : normalized.internal === true || !targetId ? "targetless" : "normal",
2161
+ ...normalized.guard ? { guard: typeof normalized.guard === "string" ? { type: normalized.guard } : {
2162
+ type: normalized.guard.type,
2163
+ ...normalized.guard.params ? { params: normalized.guard.params } : {}
2164
+ } } : {},
2165
+ actions: normalizeActions(normalized.actions),
2166
+ ...normalized.description ? { description: normalized.description } : {}
2167
+ }
2168
+ });
2169
+ }
2170
+ }
2171
+ function fromXStateConfig(config) {
2172
+ const nodes = [];
2173
+ const edges = [];
2174
+ const edgeCounts = /* @__PURE__ */ new Map();
2175
+ function visitNode(key, nodeConfig, parentId, parentPath) {
2176
+ const nodeId = parentPath ? `${parentPath}.${key}` : "(machine)";
2177
+ const currentPath = parentPath ? nodeId : "(machine)";
2178
+ const initialId = nodeConfig.initial ? `${currentPath}.${nodeConfig.initial}` : void 0;
2179
+ nodes.push({
2180
+ type: "node",
2181
+ id: nodeId,
2182
+ parentId,
2183
+ label: key,
2184
+ ...initialId ? { initialNodeId: initialId } : {},
2185
+ data: {
2186
+ key,
2187
+ ...nodeConfig.type ? { type: nodeConfig.type } : {},
2188
+ ...nodeConfig.history ? { history: nodeConfig.history } : {},
2189
+ ...initialId ? { initialId } : {},
2190
+ entry: normalizeActions(nodeConfig.entry),
2191
+ exit: normalizeActions(nodeConfig.exit),
2192
+ invokes: normalizeInvoke(nodeConfig.invoke),
2193
+ tags: normalizeTags(nodeConfig.tags),
2194
+ ...nodeConfig.description ? { description: nodeConfig.description } : {}
2195
+ }
2196
+ });
2197
+ for (const [eventType, transition] of Object.entries(nodeConfig.on ?? {})) appendTransitionEdges(edges, nodeId, parentPath ?? "(machine)", eventType, transition, edgeCounts);
2198
+ if (nodeConfig.always) appendTransitionEdges(edges, nodeId, parentPath ?? "(machine)", "", nodeConfig.always, edgeCounts);
2199
+ for (const [childKey, childConfig] of Object.entries(nodeConfig.states ?? {})) visitNode(childKey, childConfig, nodeId, currentPath);
2200
+ }
2201
+ visitNode("(machine)", config, null, null);
2202
+ return {
2203
+ id: config.id ?? "machine",
2204
+ nodes,
2205
+ edges,
2206
+ data: {}
2207
+ };
2208
+ }
2209
+ async function pushLocalMachineLinks(options) {
2210
+ const client = options.client ?? createStatelyClient({
2211
+ apiKey: options.apiKey,
2212
+ baseUrl: options.baseUrl,
2213
+ fetch: options.fetch
2214
+ });
2215
+ const sourcePath = path.resolve(options.cwd ?? process.cwd(), options.source);
2216
+ const project = await resolvePushProject(client, sourcePath, options);
2217
+ if (!project.projectVersionId) throw new Error("Resolved project is missing projectVersionId.");
2218
+ const contents = await fs.readFile(sourcePath, "utf8");
2219
+ const attachments = findStatelyPragmaAttachments(contents, sourcePath);
2220
+ const extracted = await extractMachinesFromLocalSource(sourcePath, contents);
2221
+ if (attachments.length === 0 || extracted.machines.length === 0) return {
2222
+ sourcePath,
2223
+ project,
2224
+ created: [],
2225
+ updated: [],
2226
+ skipped: [{
2227
+ machineIndex: 0,
2228
+ reason: extracted.error != null && attachments.length > 0 ? `Local machine extraction failed: ${extracted.error}` : "No local machines were discovered in this file."
2229
+ }]
2230
+ };
2231
+ if (attachments.length !== extracted.machines.length) return {
2232
+ sourcePath,
2233
+ project,
2234
+ created: [],
2235
+ updated: [],
2236
+ skipped: [{
2237
+ machineIndex: 0,
2238
+ reason: "The local machine extractor did not align with the source attachments for this file."
2239
+ }]
2240
+ };
2241
+ let nextContents = contents;
2242
+ let outputPath;
2243
+ const created = [];
2244
+ const updated = [];
2245
+ const skipped = [];
2246
+ for (const [machineIndex, attachment] of attachments.entries()) {
2247
+ const extractedMachine = extracted.machines[machineIndex];
2248
+ if (!extractedMachine?.config) {
2249
+ skipped.push({
2250
+ machineIndex,
2251
+ reason: "No extracted machine config was available for this source."
2252
+ });
2253
+ continue;
2254
+ }
2255
+ if (attachment.pragma?.id) {
2256
+ const updatedMachine = await client.machines.update({
2257
+ id: attachment.pragma.id,
2258
+ definition: toStudioMachine(fromXStateConfig(extractedMachine.config))
2259
+ });
2260
+ updated.push({
2261
+ machineIndex,
2262
+ machine: updatedMachine
2263
+ });
2264
+ continue;
2265
+ }
2266
+ const machine = await client.machines.create({
2267
+ projectVersionId: project.projectVersionId,
2268
+ definition: toStudioMachine(fromXStateConfig(extractedMachine.config)),
2269
+ xstateVersion: Math.max(5, options.xstateVersion ?? 5)
2270
+ });
2271
+ nextContents = upsertStatelyPragma(nextContents, machine.id, {
2272
+ fileName: sourcePath,
2273
+ machineIndex
2274
+ });
2275
+ created.push({
2276
+ machineIndex,
2277
+ machine
2278
+ });
2279
+ }
2280
+ if (nextContents !== contents) {
2281
+ await fs.writeFile(sourcePath, nextContents, "utf8");
2282
+ outputPath = sourcePath;
2283
+ }
2284
+ return {
2285
+ sourcePath,
2286
+ project,
2287
+ created,
2288
+ updated,
2289
+ skipped,
2290
+ ...outputPath ? { outputPath } : {}
2291
+ };
2292
+ }
2293
+ async function resolveLocalFile(locator, options) {
2294
+ const filePath = path.resolve(options.cwd ?? process.cwd(), locator);
2295
+ const contents = await fs.readFile(filePath, "utf8");
2296
+ const extension = path.extname(filePath).toLowerCase();
2297
+ if (extension === ".ts" || extension === ".tsx" || extension === ".js" || extension === ".jsx") {
2298
+ const config = (await (options.client ?? createStatelyClient({
2299
+ apiKey: options.apiKey,
2300
+ baseUrl: options.baseUrl,
2301
+ fetch: options.fetch
2302
+ })).code.extractMachines(contents)).machines[0]?.config;
2303
+ if (!config) throw new Error(`No machines extracted from ${filePath}`);
2304
+ return {
2305
+ kind: "local-file",
2306
+ locator: filePath,
2307
+ format: "xstate",
2308
+ graph: fromXStateConfig(config)
2309
+ };
2310
+ }
2311
+ const parsed = JSON.parse(contents);
2312
+ if ("rootNode" in parsed && "edges" in parsed) return {
2313
+ kind: "local-file",
2314
+ locator: filePath,
2315
+ format: "digraph",
2316
+ graph: fromStudioMachine(parsed)
2317
+ };
2318
+ if ("nodes" in parsed && "edges" in parsed) return {
2319
+ kind: "local-file",
2320
+ locator: filePath,
2321
+ format: "graph",
2322
+ graph: parsed
2323
+ };
2324
+ if ("states" in parsed) return {
2325
+ kind: "local-file",
2326
+ locator: filePath,
2327
+ format: "xstate",
2328
+ graph: fromXStateConfig(parsed)
2329
+ };
2330
+ throw new Error(`Unsupported local sync input: ${filePath}`);
2331
+ }
2332
+ function inferWritableTargetFormat(filePath) {
2333
+ if (filePath.endsWith(".ts") || filePath.endsWith(".tsx") || filePath.endsWith(".js") || filePath.endsWith(".jsx")) return "xstate";
2334
+ if (filePath.endsWith(".digraph.json")) return "digraph";
2335
+ if (filePath.endsWith(".graph.json")) return "graph";
2336
+ return null;
2337
+ }
2338
+ function resolveLocalXStateMachineId(graph) {
2339
+ const rootKey = (graph.nodes.find((node) => node.parentId == null) ?? null)?.data?.key;
2340
+ if (rootKey && rootKey !== "(machine)") return rootKey;
2341
+ return graph.id;
2342
+ }
2343
+ function serializeGraph(graph, format, options = {}) {
2344
+ switch (format) {
2345
+ case "digraph": return `${JSON.stringify(toStudioMachine(graph), null, 2)}\n`;
2346
+ case "graph": return `${JSON.stringify(graph, null, 2)}\n`;
2347
+ case "xstate": {
2348
+ const source = graphToXStateTS({
2349
+ ...graph,
2350
+ id: resolveLocalXStateMachineId(graph)
2351
+ });
2352
+ if (!options.remoteMachineId) return source;
2353
+ return upsertStatelyPragma(source, options.remoteMachineId, options.targetPath ? { fileName: options.targetPath } : {});
2354
+ }
2355
+ default: {
2356
+ const exhaustive = format;
2357
+ throw new Error(`Unsupported sync output format: ${exhaustive}`);
2358
+ }
2359
+ }
2360
+ }
2361
+ async function resolveRemoteMachine(machineId, baseUrl, kind, locator, options) {
2362
+ const machineResponse = await (options.client ?? createStatelyClient({
2363
+ apiKey: options.apiKey,
2364
+ baseUrl,
2365
+ fetch: options.fetch
2366
+ })).machines.get(machineId);
2367
+ return {
2368
+ kind,
2369
+ locator,
2370
+ format: "digraph",
2371
+ graph: fromStudioMachine(machineResponse && typeof machineResponse === "object" && "definition" in machineResponse && machineResponse.definition ? machineResponse.definition : machineResponse),
2372
+ remoteMachineId: machineId
2373
+ };
2374
+ }
2375
+ async function resolveSyncInput(locator, options) {
2376
+ if (await fileExists(path.resolve(options.cwd ?? process.cwd(), locator))) return resolveLocalFile(locator, options);
2377
+ if (isUrl(locator)) {
2378
+ const url = new URL(locator);
2379
+ const machineId = url.pathname.split("/").filter(Boolean).at(-1);
2380
+ if (!machineId) throw new Error(`Could not resolve machine ID from URL: ${locator}`);
2381
+ return resolveRemoteMachine(machineId, url.origin, "studio-url", locator, options);
2382
+ }
2383
+ return resolveRemoteMachine(locator, options.baseUrl, "studio-machine-id", locator, options);
2384
+ }
2385
+ function summarizeDiff(diff) {
2386
+ const nodeChanges = diff.nodes.added.length + diff.nodes.removed.length + diff.nodes.updated.length;
2387
+ const edgeChanges = diff.edges.added.length + diff.edges.removed.length + diff.edges.updated.length;
2388
+ return {
2389
+ hasChanges: !isEmptyDiff(diff),
2390
+ nodeChanges,
2391
+ edgeChanges
2392
+ };
2393
+ }
2394
+ async function planSync(options) {
2395
+ const source = await resolveSyncInput(options.source, options);
2396
+ const target = await resolveSyncInput(options.target, options);
2397
+ const diff = getDiff(source.graph, target.graph);
2398
+ return {
2399
+ source,
2400
+ target,
2401
+ diff,
2402
+ summary: summarizeDiff(diff),
2403
+ warnings: []
2404
+ };
2405
+ }
2406
+ async function pullSync(options) {
2407
+ const source = await resolveSyncInput(options.source, options);
2408
+ const outputPath = path.resolve(options.cwd ?? process.cwd(), options.target);
2409
+ const fallbackFormat = inferWritableTargetFormat(outputPath);
2410
+ let targetFormat = fallbackFormat;
2411
+ if (await fileExists(outputPath)) try {
2412
+ targetFormat = (await resolveLocalFile(options.target, options)).format;
2413
+ } catch (error) {
2414
+ if (!fallbackFormat) throw error;
2415
+ }
2416
+ 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.`);
2417
+ const serialized = serializeGraph(source.graph, targetFormat, {
2418
+ remoteMachineId: source.remoteMachineId,
2419
+ targetPath: outputPath
2420
+ });
2421
+ await fs.writeFile(outputPath, serialized, "utf8");
2422
+ return {
2423
+ source,
2424
+ target: {
2425
+ kind: "local-file",
2426
+ locator: outputPath,
2427
+ format: targetFormat,
2428
+ graph: source.graph
2429
+ },
2430
+ outputPath
2431
+ };
2432
+ }
2433
+ function inferDefaultProjectName(sourcePath, repo) {
2434
+ if (repo?.repo) return repo.repo;
2435
+ const parentDir = path.basename(path.dirname(sourcePath));
2436
+ if (parentDir && parentDir !== ".") return parentDir;
2437
+ return path.basename(sourcePath, path.extname(sourcePath));
2438
+ }
2439
+ async function resolvePushProject(client, sourcePath, options) {
2440
+ async function withResolvedProjectVersionId(project, explicitProjectVersionId) {
2441
+ if (project.projectVersionId) return project;
2442
+ if (explicitProjectVersionId) return {
2443
+ ...project,
2444
+ projectVersionId: explicitProjectVersionId
2445
+ };
2446
+ const matchedProject = (await client.projects.list()).find((candidate) => {
2447
+ return candidate.projectId === project.projectId || candidate.id != null && project.id != null && candidate.id === project.id;
2448
+ });
2449
+ if (matchedProject?.projectVersionId) return {
2450
+ ...project,
2451
+ projectVersionId: matchedProject.projectVersionId
2452
+ };
2453
+ return project;
2454
+ }
2455
+ const explicitProject = options.project;
2456
+ if (explicitProject?.projectVersionId) return withResolvedProjectVersionId(await client.projects.get(explicitProject.projectVersionId), explicitProject.projectVersionId);
2457
+ if (explicitProject?.projectId) return withResolvedProjectVersionId(await client.projects.get(explicitProject.projectId));
2458
+ const inferredRepo = explicitProject?.repo ?? await inferConnectedRepo(sourcePath, options.cwd);
2459
+ const projectInput = {
2460
+ name: explicitProject?.name ?? inferDefaultProjectName(sourcePath, inferredRepo),
2461
+ visibility: explicitProject?.visibility ?? "Private",
2462
+ ...explicitProject?.description ? { description: explicitProject.description } : {},
2463
+ ...explicitProject?.keywords ? { keywords: explicitProject.keywords } : {},
2464
+ ...inferredRepo ? { repo: inferredRepo } : {}
2465
+ };
2466
+ return withResolvedProjectVersionId(await client.projects.ensure(projectInput));
2467
+ }
2468
+ async function pushSync(options) {
2469
+ const client = options.client ?? createStatelyClient({
2470
+ apiKey: options.apiKey,
2471
+ baseUrl: options.baseUrl,
2472
+ fetch: options.fetch
2473
+ });
2474
+ const source = await resolveSyncInput(options.source, {
2475
+ ...options,
2476
+ target: options.source
2477
+ });
2478
+ if (source.kind !== "local-file") throw new Error("pushSync currently requires a local source file.");
2479
+ const sourcePath = source.locator;
2480
+ const project = await resolvePushProject(client, sourcePath, options);
2481
+ const existingMachineId = source.format === "xstate" ? getStatelyPragma(await fs.readFile(sourcePath, "utf8"), sourcePath)?.id : void 0;
2482
+ let machine;
2483
+ if (existingMachineId) machine = await client.machines.update({
2484
+ id: existingMachineId,
2485
+ definition: toStudioMachine(source.graph)
2486
+ });
2487
+ else {
2488
+ if (!project.projectVersionId) throw new Error("Resolved project is missing projectVersionId.");
2489
+ machine = await client.machines.create({
2490
+ projectVersionId: project.projectVersionId,
2491
+ definition: toStudioMachine(source.graph),
2492
+ xstateVersion: options.xstateVersion ?? 5
2493
+ });
2494
+ }
2495
+ let outputPath;
2496
+ if (source.format === "xstate") {
2497
+ const contents = await fs.readFile(sourcePath, "utf8");
2498
+ const nextContents = upsertStatelyPragma(contents, machine.id, { fileName: sourcePath });
2499
+ if (nextContents !== contents) {
2500
+ await fs.writeFile(sourcePath, nextContents, "utf8");
2501
+ outputPath = sourcePath;
2502
+ }
2503
+ }
2504
+ return {
2505
+ source,
2506
+ project,
2507
+ machine,
2508
+ ...outputPath ? { outputPath } : {}
2509
+ };
2510
+ }
2511
+
2512
+ //#endregion
2513
+ export { pushSync as i, pullSync as n, pushLocalMachineLinks as r, planSync as t };