@statelyai/sdk 0.34.2 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +17 -34
  2. package/dist/assetStorage.d.mts +1 -1
  3. package/dist/auth.d.mts +14 -1
  4. package/dist/bin.mjs +1 -3
  5. package/dist/editor-sync-types-DNFk7Xtj.d.mts +53 -0
  6. package/dist/editorHostProtocol.d.mts +197 -0
  7. package/dist/{editorHostProtocol-B2_t3Le7.mjs → editorHostProtocol.mjs} +1 -1
  8. package/dist/embed.d.mts +3 -3
  9. package/dist/embed.mjs +2 -2
  10. package/dist/{graph-DVfx7FwN.d.mts → graph-B6xUxqR5.d.mts} +1 -1
  11. package/dist/graph.d.mts +1 -1
  12. package/dist/{index-A5CMACoO.d.mts → index-CoxF4Saw.d.mts} +8 -255
  13. package/dist/index.d.mts +8 -31
  14. package/dist/index.mjs +5 -9
  15. package/dist/{inspect-DBH9oOAd.d.mts → inspect-DCdu0ST3.d.mts} +1 -1
  16. package/dist/{inspect-ZVDq9tK2.mjs → inspect-GSXRhzOx.mjs} +1 -1
  17. package/dist/inspect.d.mts +2 -2
  18. package/dist/inspect.mjs +2 -2
  19. package/dist/patchTypes.d.mts +1 -1
  20. package/dist/{protocol-CCf9j_SZ.d.mts → protocol-nOWsz3UV.d.mts} +3 -3
  21. package/dist/protocol.d.mts +1 -1
  22. package/dist/relay.d.mts +1 -1
  23. package/dist/{studio-CFN3-0-2.d.mts → studio-3ujfe2z0.d.mts} +2 -2
  24. package/dist/{openapi-BTDjYWXd.mjs → studio-Bn3alVku.mjs} +637 -1
  25. package/dist/studio.d.mts +1 -1
  26. package/dist/studio.mjs +2 -2
  27. package/dist/{version-CUFh-PYe.mjs → version-DECst76A.mjs} +1 -1
  28. package/package.json +18 -14
  29. package/dist/auth-CVFc85uF.d.mts +0 -15
  30. package/dist/dist-DsOTTfYv.mjs +0 -8361
  31. package/dist/editor-sync-types-D7YYz6fb.d.mts +0 -98
  32. package/dist/editorHostSession-DCTHhBqC.mjs +0 -912
  33. package/dist/editorHostSession-yGUKdLjq.d.mts +0 -325
  34. package/dist/editorHostSession.d.mts +0 -2
  35. package/dist/editorHostSession.mjs +0 -6
  36. package/dist/statelyPragma-YtVaBuIe.mjs +0 -102
  37. package/dist/studio-BZP6DaIO.mjs +0 -638
  38. package/dist/sync.d.mts +0 -86
  39. package/dist/sync.mjs +0 -4646
package/dist/sync.mjs DELETED
@@ -1,4646 +0,0 @@
1
- import "./openapi-BTDjYWXd.mjs";
2
- import { r as createStatelyClient } from "./studio-BZP6DaIO.mjs";
3
- import { C as toXStateV6MachineConfig, S as serializeJS, a as alignCompareGraphIds, b as normalizeMachineProfile, c as diffGraphsSemantically, d as getDelayKeyFromEventType, g as graphToXStateTS, i as XSTATE_V6_FN_TRANSITION_META, m as graphToMachineConfig, p as graphChangeToPatchesResult, r as XSTATE_V6_BRANCH_DESCRIPTION_META, s as detectXStateSourceProfile, t as INLINE_EXPRESSION_DIRECTIVE_FIELDS, u as extractXStateMachineConfigEntries, v as isCodeExpression } from "./dist-DsOTTfYv.mjs";
4
- import { n as getStatelyPragma, r as upsertStatelyPragma, t as findStatelyPragmaAttachments } from "./statelyPragma-YtVaBuIe.mjs";
5
- import { fromStudioMachine, toStudioMachine } from "./graph.mjs";
6
- import * as ts$1 from "typescript";
7
- import ts from "typescript";
8
- import { isEmptyDiff } from "@statelyai/graph";
9
- import fs from "node:fs/promises";
10
- import path from "node:path";
11
- import { execFile } from "node:child_process";
12
- import { promisify } from "node:util";
13
- import * as fs$1 from "fs";
14
- import * as path$1 from "path";
15
- import { fileURLToPath, pathToFileURL } from "url";
16
-
17
- //#region ../editor-sync/src/fs.ts
18
- function createTextDocument(fileName, text, uri = path$1.isAbsolute(fileName) ? pathToFileURL(fileName).toString() : fileName) {
19
- const lineStarts = getLineStarts(text);
20
- return {
21
- fileName,
22
- uri,
23
- getText() {
24
- return text;
25
- },
26
- positionAt(offset) {
27
- const clampedOffset = Math.max(0, Math.min(offset, text.length));
28
- let low = 0;
29
- let high = lineStarts.length - 1;
30
- while (low <= high) {
31
- const mid = Math.floor((low + high) / 2);
32
- const start = lineStarts[mid];
33
- const nextStart = mid + 1 < lineStarts.length ? lineStarts[mid + 1] : text.length + 1;
34
- if (clampedOffset < start) {
35
- high = mid - 1;
36
- continue;
37
- }
38
- if (clampedOffset >= nextStart) {
39
- low = mid + 1;
40
- continue;
41
- }
42
- return {
43
- line: mid,
44
- character: clampedOffset - start
45
- };
46
- }
47
- return {
48
- line: lineStarts.length - 1,
49
- character: clampedOffset - lineStarts[lineStarts.length - 1]
50
- };
51
- }
52
- };
53
- }
54
- function applyReplacementsToText(text, replacements) {
55
- let updated = text;
56
- const sorted = [...replacements].sort(compareReplacementRangesDescending$1);
57
- for (const replacement of sorted) {
58
- const lineStarts = getLineStarts(updated);
59
- const start = offsetAt(lineStarts, replacement.range.startLine, replacement.range.startChar);
60
- const end = offsetAt(lineStarts, replacement.range.endLine, replacement.range.endChar);
61
- updated = `${updated.slice(0, start)}${replacement.newText}${updated.slice(end)}`;
62
- }
63
- return updated;
64
- }
65
- function sourceUriToFileName(uriOrPath) {
66
- if (uriOrPath.startsWith("file://")) return fileURLToPath(uriOrPath);
67
- if (/^[a-z][a-z\d+.-]*:/i.test(uriOrPath)) throw new Error(`Unsupported non-file URI: ${uriOrPath}`);
68
- return path$1.resolve(uriOrPath);
69
- }
70
- function fileNameToUri(fileName) {
71
- return pathToFileURL(path$1.resolve(fileName)).toString();
72
- }
73
- function createFileSourceDocumentResolver() {
74
- return {
75
- read(uri) {
76
- return readFileSnapshot(sourceUriToFileName(uri));
77
- },
78
- resolveImport(fromDocument, specifier) {
79
- const importedFileName = resolveImportPath(fromDocument.fileName, specifier);
80
- return importedFileName ? readFileSnapshot(importedFileName) : null;
81
- },
82
- resolvePackageJson(fromDocument, packageName) {
83
- let directory = path$1.dirname(path$1.resolve(fromDocument.fileName));
84
- while (true) {
85
- const packageJson = readFileSnapshot(path$1.join(directory, "package.json"));
86
- if (packageJson && packageJsonDeclares(packageJson.text, packageName)) return packageJson;
87
- const parent = path$1.dirname(directory);
88
- if (parent === directory) return null;
89
- directory = parent;
90
- }
91
- }
92
- };
93
- }
94
- function packageJsonDeclares(text, packageName) {
95
- try {
96
- const manifest = JSON.parse(text);
97
- return [
98
- "dependencies",
99
- "devDependencies",
100
- "peerDependencies",
101
- "optionalDependencies"
102
- ].some((field) => {
103
- const dependencies = manifest[field];
104
- return Boolean(dependencies && typeof dependencies === "object" && Object.prototype.hasOwnProperty.call(dependencies, packageName));
105
- });
106
- } catch {
107
- return false;
108
- }
109
- }
110
- function resolveImportPath(fromFileName, specifier) {
111
- if (!specifier.startsWith(".")) return null;
112
- const basePath = path$1.resolve(path$1.dirname(fromFileName), specifier);
113
- return [
114
- basePath,
115
- `${basePath}.ts`,
116
- `${basePath}.tsx`,
117
- `${basePath}.js`,
118
- `${basePath}.jsx`,
119
- path$1.join(basePath, "index.ts"),
120
- path$1.join(basePath, "index.tsx"),
121
- path$1.join(basePath, "index.js"),
122
- path$1.join(basePath, "index.jsx")
123
- ].find((candidate) => isReadableFile(candidate)) ?? null;
124
- }
125
- function isReadableFile(fileName) {
126
- try {
127
- return fs$1.statSync(fileName).isFile();
128
- } catch {
129
- return false;
130
- }
131
- }
132
- function readFileSnapshot(fileName) {
133
- try {
134
- return {
135
- fileName,
136
- uri: fileNameToUri(fileName),
137
- text: fs$1.readFileSync(fileName, "utf8")
138
- };
139
- } catch {
140
- return null;
141
- }
142
- }
143
- function getLineStarts(text) {
144
- const lineStarts = [0];
145
- for (let index = 0; index < text.length; index += 1) if (text.charCodeAt(index) === 10) lineStarts.push(index + 1);
146
- return lineStarts;
147
- }
148
- function offsetAt(lineStarts, line, character) {
149
- const lineStart = lineStarts[line];
150
- if (lineStart === void 0) return lineStarts[lineStarts.length - 1] + character;
151
- return lineStart + character;
152
- }
153
- function compareReplacementRangesDescending$1(left, right) {
154
- if (left.range.startLine !== right.range.startLine) return right.range.startLine - left.range.startLine;
155
- return right.range.startChar - left.range.startChar;
156
- }
157
-
158
- //#endregion
159
- //#region ../editor-sync/src/internal/sourceLocations.ts
160
- const sourceFileUris = /* @__PURE__ */ new WeakMap();
161
- function collectXStateSourceLocations(sourceText, document, options = {}) {
162
- const sourceFile = ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$3(document.fileName));
163
- const uri = document.uri?.toString() ?? document.fileName;
164
- sourceFileUris.set(sourceFile, uri);
165
- const bindings = collectBindings(sourceFile, uri, document.fileName, options);
166
- const staticValues = collectStaticValueBindings(sourceFile);
167
- const root = findMachineConfigObjectLiteral$1(sourceFile, bindings, options.machineIndex);
168
- if (!root) return;
169
- const states = [];
170
- const statesObjectLocations = [];
171
- collectStateLocations(root, [], states, statesObjectLocations, bindings, staticValues, root);
172
- const packageProfile = detectXStatePackageProfile(options.resolver?.resolvePackageJson?.({
173
- fileName: document.fileName,
174
- uri
175
- }, "xstate"));
176
- const rootProfile = detectXStateSourceProfile(sourceText);
177
- const referencedStateSymbols = new Set([...states, ...statesObjectLocations].map((state) => state.symbol).filter((symbol) => typeof symbol === "string"));
178
- const resolvedTransitionFunctions = collectResolvedTransitionFunctions(root, bindings);
179
- const inferredProfile = rootProfile === "xstate-v6-alpha" || resolvedTransitionFunctions.size > 0 || [...referencedStateSymbols].some((symbol) => {
180
- const binding = bindings.get(symbol);
181
- return binding?.kind === "createStateConfig" || detectXStateSourceProfile(binding?.sourceFile.text ?? "") === "xstate-v6-alpha";
182
- }) ? "xstate-v6-alpha" : rootProfile;
183
- return {
184
- version: 1,
185
- profile: packageProfile?.profile ?? inferredProfile,
186
- profileRef: packageProfile?.profileRef ?? normalizeMachineProfile(inferredProfile),
187
- root: {
188
- uri,
189
- range: toSourceRange$1(sourceFile, root)
190
- },
191
- statesObject: statesObjectLocations[0],
192
- states,
193
- staticValues: collectStaticValueReferences(sourceFile, uri, root, staticValues),
194
- transitionFunctions: [...resolvedTransitionFunctions].flatMap(([symbol, resolved]) => resolved.binding.uri === uri ? [] : [{
195
- symbol,
196
- uri: resolved.binding.uri,
197
- range: toSourceRange$1(resolved.binding.sourceFile, resolved.binding.node),
198
- sourcePaths: resolved.sourcePaths
199
- }])
200
- };
201
- }
202
- function detectXStatePackageProfile(packageJson) {
203
- if (!packageJson) return void 0;
204
- let manifest;
205
- try {
206
- manifest = JSON.parse(packageJson.text);
207
- } catch {
208
- return;
209
- }
210
- const dependencyFields = [
211
- "dependencies",
212
- "devDependencies",
213
- "peerDependencies",
214
- "optionalDependencies"
215
- ];
216
- let range;
217
- for (const field of dependencyFields) {
218
- const dependencies = manifest[field];
219
- if (!dependencies || typeof dependencies !== "object") continue;
220
- const value = dependencies.xstate;
221
- if (typeof value === "string") {
222
- range = value;
223
- break;
224
- }
225
- }
226
- if (!range) return void 0;
227
- const normalizedRange = range.replace(/^(?:workspace:|npm:xstate@)/, "");
228
- const clauseProfiles = normalizedRange.split("||").map((clause) => detectXStateRangeClauseProfile(clause.trim()));
229
- const profiles = new Set(clauseProfiles);
230
- if (profiles.size !== 1 || profiles.has(void 0)) return void 0;
231
- const profile = clauseProfiles[0];
232
- if (!profile) return void 0;
233
- return {
234
- profile,
235
- profileRef: /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(normalizedRange) ? `@statelyai/xstate@${normalizedRange}` : normalizeMachineProfile(profile)
236
- };
237
- }
238
- function detectXStateRangeClauseProfile(clause) {
239
- const normalizedClause = clause.replace(/([<>]=?)\s+/g, "$1");
240
- let lowerRequiresV6 = false;
241
- let upperRequiresV5 = false;
242
- let directProfile;
243
- for (const match of normalizedClause.matchAll(/(?:^|\s)([<>]=?|[~^])?v?(\d+)(?:\.(\d+|x|\*))?(?:\.(\d+|x|\*))?(?:-[0-9A-Za-z.-]+)?(?=\s|$)/g)) {
244
- const operator = match[1] ?? "";
245
- const major = Number(match[2]);
246
- const minor = parseRangePart(match[3]);
247
- const patch = parseRangePart(match[4]);
248
- if (operator === ">" || operator === ">=") {
249
- if (major >= 6) lowerRequiresV6 = true;
250
- continue;
251
- }
252
- if (operator === "<") {
253
- if (major < 6 || major === 6 && (minor ?? 0) === 0 && (patch ?? 0) === 0) upperRequiresV5 = true;
254
- continue;
255
- }
256
- if (operator === "<=") {
257
- if (major < 6) upperRequiresV5 = true;
258
- continue;
259
- }
260
- const profile = major >= 6 ? "xstate-v6-alpha" : "xstate-v5";
261
- if (directProfile && directProfile !== profile) return void 0;
262
- directProfile = profile;
263
- }
264
- if (lowerRequiresV6 && upperRequiresV5) return void 0;
265
- if (lowerRequiresV6) return "xstate-v6-alpha";
266
- if (upperRequiresV5) return "xstate-v5";
267
- return directProfile;
268
- }
269
- function parseRangePart(value) {
270
- return value && /^\d+$/.test(value) ? Number(value) : void 0;
271
- }
272
- function collectImportedXStateTransitionSources(sourceText, document, options = {}) {
273
- if (!options.resolver) return [];
274
- const sourceFile = ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$3(document.fileName));
275
- const uri = document.uri?.toString() ?? document.fileName;
276
- sourceFileUris.set(sourceFile, uri);
277
- const bindings = collectBindings(sourceFile, uri, document.fileName, options);
278
- const root = findMachineConfigObjectLiteral$1(sourceFile, bindings, options.machineIndex);
279
- if (!root) return [];
280
- return [...collectResolvedTransitionFunctions(root, bindings)].flatMap(([localName, resolved]) => {
281
- const { binding } = resolved;
282
- if (binding.uri === uri) return [];
283
- if (ts$1.isFunctionDeclaration(binding.node)) {
284
- const name = binding.node.name;
285
- if (!name) return [];
286
- const suffix = binding.node.getText(binding.sourceFile).slice(name.getEnd() - binding.node.getStart(binding.sourceFile));
287
- return [`${binding.node.modifiers?.some((modifier) => modifier.kind === ts$1.SyntaxKind.AsyncKeyword) ? "async " : ""}function ${localName}${suffix}`];
288
- }
289
- return [`const ${localName} = ${binding.node.getText(binding.sourceFile)};`];
290
- });
291
- }
292
- function collectStaticValueBindings(sourceFile) {
293
- const bindings = /* @__PURE__ */ new Map();
294
- for (const statement of sourceFile.statements) {
295
- if (ts$1.isVariableStatement(statement)) {
296
- if (!((statement.declarationList.flags & ts$1.NodeFlags.Const) === ts$1.NodeFlags.Const)) continue;
297
- for (const declaration of statement.declarationList.declarations) {
298
- if (!ts$1.isIdentifier(declaration.name) || !declaration.initializer) continue;
299
- const value = getStaticStringValue(declaration.initializer);
300
- if (value === null) continue;
301
- bindings.set(declaration.name.text, {
302
- kind: "const",
303
- symbol: declaration.name.text,
304
- value,
305
- valueRange: toSourceRange$1(sourceFile, declaration.initializer)
306
- });
307
- }
308
- continue;
309
- }
310
- if (ts$1.isEnumDeclaration(statement)) for (const member of statement.members) {
311
- const memberName = getEnumMemberName(member.name);
312
- if (!memberName || !member.initializer) continue;
313
- const value = getStaticStringValue(member.initializer);
314
- if (value === null) continue;
315
- const symbol = `${statement.name.text}.${memberName}`;
316
- bindings.set(symbol, {
317
- kind: "enumMember",
318
- symbol,
319
- value,
320
- valueRange: toSourceRange$1(sourceFile, member.initializer)
321
- });
322
- }
323
- }
324
- return bindings;
325
- }
326
- function collectBindings(sourceFile, uri, fileName, options, cache = /* @__PURE__ */ new Map()) {
327
- const cached = cache.get(fileName);
328
- if (cached) return cached;
329
- const bindings = collectTopLevelBindings(sourceFile, uri);
330
- cache.set(fileName, bindings);
331
- addImportedBindings(bindings, sourceFile, uri, fileName, options, cache);
332
- return bindings;
333
- }
334
- function collectTopLevelBindings(sourceFile, uri) {
335
- const bindings = /* @__PURE__ */ new Map();
336
- for (const statement of sourceFile.statements) {
337
- if (ts$1.isFunctionDeclaration(statement) && statement.name) {
338
- bindings.set(statement.name.text, {
339
- kind: "transitionFunction",
340
- node: statement,
341
- sourceFile,
342
- uri,
343
- bindings
344
- });
345
- continue;
346
- }
347
- if (!ts$1.isVariableStatement(statement)) continue;
348
- for (const declaration of statement.declarationList.declarations) {
349
- if (!ts$1.isIdentifier(declaration.name) || !declaration.initializer) continue;
350
- const initializer = unwrapExpression$2(declaration.initializer);
351
- if (ts$1.isArrowFunction(initializer) || ts$1.isFunctionExpression(initializer)) {
352
- bindings.set(declaration.name.text, {
353
- kind: "transitionFunction",
354
- node: initializer,
355
- sourceFile,
356
- uri,
357
- bindings
358
- });
359
- continue;
360
- }
361
- const objectLiteral = unwrapObjectLiteralExpression$1(declaration.initializer);
362
- if (objectLiteral) {
363
- bindings.set(declaration.name.text, {
364
- kind: "objectReference",
365
- node: objectLiteral,
366
- sourceFile,
367
- uri,
368
- bindings
369
- });
370
- continue;
371
- }
372
- const stateConfig = unwrapCreateConfigArgument(declaration.initializer);
373
- if (stateConfig) bindings.set(declaration.name.text, {
374
- kind: "createStateConfig",
375
- node: stateConfig,
376
- sourceFile,
377
- uri,
378
- bindings
379
- });
380
- }
381
- }
382
- return bindings;
383
- }
384
- function addImportedBindings(bindings, sourceFile, uri, fileName, options, cache) {
385
- const resolver = options.resolver;
386
- if (!resolver) return;
387
- for (const statement of sourceFile.statements) {
388
- if (!ts$1.isImportDeclaration(statement) || !ts$1.isStringLiteral(statement.moduleSpecifier)) continue;
389
- const namedBindings = statement.importClause?.namedBindings;
390
- if (!namedBindings || !ts$1.isNamedImports(namedBindings)) continue;
391
- const importedDocument = resolver.resolveImport({
392
- fileName,
393
- uri
394
- }, statement.moduleSpecifier.text);
395
- if (!importedDocument) continue;
396
- const importedSourceFile = ts$1.createSourceFile(importedDocument.fileName, importedDocument.text, ts$1.ScriptTarget.Latest, true, getScriptKind$3(importedDocument.fileName));
397
- sourceFileUris.set(importedSourceFile, importedDocument.uri);
398
- const importedBindings = collectBindings(importedSourceFile, importedDocument.uri, importedDocument.fileName, options, cache);
399
- for (const element of namedBindings.elements) {
400
- const importedName = element.propertyName?.text ?? element.name.text;
401
- const binding = importedBindings.get(importedName);
402
- if (binding) bindings.set(element.name.text, binding);
403
- }
404
- }
405
- }
406
- function collectResolvedTransitionFunctions(root, bindings) {
407
- const found = /* @__PURE__ */ new Map();
408
- const visitExpression = (expression, sourcePath) => {
409
- const current = unwrapExpression$2(expression);
410
- if (ts$1.isIdentifier(current)) {
411
- const binding = bindings.get(current.text);
412
- if (binding?.kind === "transitionFunction") {
413
- const resolved = found.get(current.text) ?? {
414
- binding,
415
- sourcePaths: []
416
- };
417
- if (!resolved.sourcePaths.some((existing) => existing.length === sourcePath.length && existing.every((segment, index) => segment === sourcePath[index]))) resolved.sourcePaths.push(sourcePath);
418
- found.set(current.text, resolved);
419
- }
420
- return;
421
- }
422
- if (ts$1.isObjectLiteralExpression(current)) {
423
- for (const property of current.properties) if (ts$1.isPropertyAssignment(property)) visitExpression(property.initializer, sourcePath);
424
- else if (ts$1.isShorthandPropertyAssignment(property)) visitExpression(property.name, sourcePath);
425
- else if (ts$1.isSpreadAssignment(property)) visitExpression(property.expression, sourcePath);
426
- return;
427
- }
428
- if (ts$1.isArrayLiteralExpression(current)) {
429
- for (const element of current.elements) if (ts$1.isExpression(element)) visitExpression(element, sourcePath);
430
- return;
431
- }
432
- ts$1.forEachChild(current, (child) => {
433
- if (ts$1.isExpression(child)) visitExpression(child, sourcePath);
434
- });
435
- };
436
- const visitState = (state, sourcePath) => {
437
- for (const propertyName of [
438
- "on",
439
- "after",
440
- "always",
441
- "onDone",
442
- "onError",
443
- "onSnapshot",
444
- "onTimeout"
445
- ]) {
446
- const property = state.properties.find((candidate) => ts$1.isPropertyAssignment(candidate) && getPropertyNameText$2(candidate.name) === propertyName);
447
- if (property) visitExpression(property.initializer, sourcePath);
448
- }
449
- const states = state.properties.find((candidate) => ts$1.isPropertyAssignment(candidate) && getPropertyNameText$2(candidate.name) === "states");
450
- const statesObject = states && unwrapObjectLiteralExpression$1(states.initializer);
451
- if (!statesObject) return;
452
- for (const property of statesObject.properties) {
453
- if (!ts$1.isPropertyAssignment(property)) continue;
454
- const child = unwrapObjectLiteralExpression$1(property.initializer);
455
- const key = getPropertyNameText$2(property.name);
456
- if (child && key) visitState(child, [...sourcePath, key]);
457
- }
458
- };
459
- visitState(root, []);
460
- return found;
461
- }
462
- function findMachineConfigObjectLiteral$1(sourceFile, bindings, machineIndex = 0) {
463
- let found = null;
464
- let currentMachineIndex = 0;
465
- const visit = (node) => {
466
- if (found) return;
467
- if (ts$1.isCallExpression(node) && isCreateMachineExpression$2(node.expression)) {
468
- const isSelectedMachine = currentMachineIndex === machineIndex;
469
- currentMachineIndex += 1;
470
- if (!isSelectedMachine) return;
471
- const [firstArgument] = node.arguments;
472
- if (!firstArgument || !ts$1.isExpression(firstArgument)) return;
473
- found = unwrapObjectLiteralExpression$1(firstArgument) ?? resolveIdentifierObject(firstArgument, bindings);
474
- return;
475
- }
476
- ts$1.forEachChild(node, visit);
477
- };
478
- visit(sourceFile);
479
- return found;
480
- }
481
- function collectStateLocations(stateObject, parentPath, locations, statesObjectLocations, bindings, staticValues, root) {
482
- const statesObject = resolveObjectLiteralProperty(stateObject, "states", bindings);
483
- if (!statesObject) return;
484
- statesObjectLocations.push({
485
- uri: statesObject.uri,
486
- path: parentPath,
487
- kind: statesObject.kind,
488
- symbol: statesObject.symbol,
489
- keyRange: statesObject.keyRange,
490
- referenceRange: statesObject.referenceRange,
491
- range: toSourceRange$1(statesObject.sourceFile, statesObject.object)
492
- });
493
- for (const property of statesObject.object.properties) {
494
- const resolved = resolveStateProperty(property, statesObject.bindings, staticValues, root);
495
- if (!resolved) continue;
496
- const path = [...parentPath, resolved.key];
497
- locations.push({
498
- uri: resolved.uri,
499
- path,
500
- kind: resolved.kind,
501
- symbol: resolved.symbol,
502
- keyRange: resolved.keyRange,
503
- referenceRange: resolved.referenceRange,
504
- keySource: resolved.keySource,
505
- keyReplacementText: resolved.keyReplacementText,
506
- range: toSourceRange$1(resolved.sourceFile, resolved.stateObject)
507
- });
508
- collectStateLocations(resolved.stateObject, path, locations, statesObjectLocations, resolved.bindings, staticValues, root);
509
- }
510
- }
511
- function resolveStateProperty(property, bindings, staticValues, root) {
512
- if (ts$1.isShorthandPropertyAssignment(property)) {
513
- const binding = bindings.get(property.name.text);
514
- if (!binding || binding.kind === "transitionFunction") return null;
515
- return {
516
- key: property.name.text,
517
- kind: binding.kind,
518
- symbol: property.name.text,
519
- keyRange: toSourceRange$1(property.getSourceFile(), property.name),
520
- referenceRange: toSourceRange$1(property.getSourceFile(), property.name),
521
- stateObject: binding.node,
522
- sourceFile: binding.sourceFile,
523
- uri: binding.uri,
524
- bindings: binding.bindings
525
- };
526
- }
527
- if (!ts$1.isPropertyAssignment(property)) return null;
528
- const resolvedKey = resolvePropertyKey(property.name, staticValues, root);
529
- if (!resolvedKey) return null;
530
- const inlineObject = unwrapObjectLiteralExpression$1(property.initializer);
531
- if (inlineObject) return {
532
- key: resolvedKey.key,
533
- kind: "inline",
534
- keyRange: toSourceRange$1(property.getSourceFile(), property.name),
535
- keySource: resolvedKey.keySource,
536
- keyReplacementText: resolvedKey.keyReplacementText,
537
- stateObject: inlineObject,
538
- sourceFile: property.getSourceFile(),
539
- uri: getSourceFileUri(property.getSourceFile()),
540
- bindings
541
- };
542
- if (ts$1.isIdentifier(property.initializer)) {
543
- const binding = bindings.get(property.initializer.text);
544
- if (!binding || binding.kind === "transitionFunction") return null;
545
- return {
546
- key: resolvedKey.key,
547
- kind: binding.kind,
548
- symbol: property.initializer.text,
549
- keyRange: toSourceRange$1(property.getSourceFile(), property.name),
550
- referenceRange: toSourceRange$1(property.getSourceFile(), property.initializer),
551
- keySource: resolvedKey.keySource,
552
- keyReplacementText: resolvedKey.keyReplacementText,
553
- stateObject: binding.node,
554
- sourceFile: binding.sourceFile,
555
- uri: binding.uri,
556
- bindings: binding.bindings
557
- };
558
- }
559
- return null;
560
- }
561
- function getSourceFileUri(sourceFile) {
562
- return sourceFileUris.get(sourceFile) ?? sourceFile.fileName;
563
- }
564
- function unwrapCreateConfigArgument(expression) {
565
- const unwrapped = unwrapExpression$2(expression);
566
- if (!ts$1.isCallExpression(unwrapped)) return null;
567
- const callee = unwrapped.expression;
568
- if (!ts$1.isPropertyAccessExpression(callee) || !isSetupCreateConfigName(callee.name.text)) return null;
569
- const [firstArgument] = unwrapped.arguments;
570
- if (!firstArgument || !ts$1.isExpression(firstArgument)) return null;
571
- return unwrapObjectLiteralExpression$1(firstArgument);
572
- }
573
- function isSetupCreateConfigName(name) {
574
- return /^create[A-Z_$][\w$]*Config$/.test(name);
575
- }
576
- function resolveIdentifierObject(expression, bindings) {
577
- const unwrapped = unwrapExpression$2(expression);
578
- if (!ts$1.isIdentifier(unwrapped)) return null;
579
- const binding = bindings.get(unwrapped.text);
580
- return binding?.kind === "objectReference" ? binding.node : null;
581
- }
582
- function resolveObjectLiteralProperty(objectLiteral, propertyName, bindings) {
583
- for (const property of objectLiteral.properties) {
584
- if (!ts$1.isPropertyAssignment(property) && !ts$1.isShorthandPropertyAssignment(property)) continue;
585
- if (getPropertyNameText$2(property.name) !== propertyName) continue;
586
- const initializer = ts$1.isShorthandPropertyAssignment(property) ? property.name : property.initializer;
587
- const inlineObject = unwrapObjectLiteralExpression$1(initializer);
588
- if (inlineObject) return {
589
- object: inlineObject,
590
- kind: "inline",
591
- keyRange: toSourceRange$1(property.getSourceFile(), property.name),
592
- sourceFile: property.getSourceFile(),
593
- uri: getSourceFileUri(property.getSourceFile()),
594
- bindings
595
- };
596
- if (ts$1.isIdentifier(initializer)) {
597
- const binding = bindings.get(initializer.text);
598
- if (binding?.kind !== "objectReference") return null;
599
- return {
600
- object: binding.node,
601
- kind: binding.kind,
602
- symbol: initializer.text,
603
- keyRange: toSourceRange$1(property.getSourceFile(), property.name),
604
- referenceRange: toSourceRange$1(property.getSourceFile(), initializer),
605
- sourceFile: binding.sourceFile,
606
- uri: binding.uri,
607
- bindings: binding.bindings
608
- };
609
- }
610
- return null;
611
- }
612
- return null;
613
- }
614
- function getPropertyNameText$2(name) {
615
- if (ts$1.isIdentifier(name) || ts$1.isStringLiteral(name) || ts$1.isNumericLiteral(name)) return name.text;
616
- if (ts$1.isComputedPropertyName(name)) {
617
- const expression = name.expression;
618
- if (ts$1.isStringLiteral(expression) || ts$1.isNoSubstitutionTemplateLiteral(expression) || ts$1.isNumericLiteral(expression)) return expression.text;
619
- }
620
- return null;
621
- }
622
- function resolvePropertyKey(name, staticValues, root) {
623
- const literalKey = getPropertyNameText$2(name);
624
- if (literalKey !== null) {
625
- if (ts$1.isComputedPropertyName(name)) return {
626
- key: literalKey,
627
- keySource: { kind: "computedLiteral" },
628
- keyReplacementText: JSON.stringify(literalKey)
629
- };
630
- return { key: literalKey };
631
- }
632
- if (!ts$1.isComputedPropertyName(name)) return null;
633
- const binding = getStaticValueBindingForExpression(name.expression, staticValues);
634
- if (!binding) return null;
635
- return {
636
- key: binding.value,
637
- keySource: {
638
- kind: binding.kind,
639
- symbol: binding.symbol,
640
- valueRange: binding.valueRange,
641
- machineLocal: isStaticValueMachineLocal(name.getSourceFile(), binding, root)
642
- },
643
- keyReplacementText: JSON.stringify(binding.value)
644
- };
645
- }
646
- function getStaticValueBindingForExpression(expression, staticValues) {
647
- const unwrapped = unwrapExpression$2(expression);
648
- if (ts$1.isIdentifier(unwrapped)) return staticValues.get(unwrapped.text) ?? null;
649
- if (ts$1.isPropertyAccessExpression(unwrapped) && ts$1.isIdentifier(unwrapped.expression)) return staticValues.get(`${unwrapped.expression.text}.${unwrapped.name.text}`) ?? null;
650
- return null;
651
- }
652
- function collectStaticValueReferences(sourceFile, uri, root, staticValues) {
653
- const references = [];
654
- if (staticValues.size === 0) return references;
655
- const rootStart = root.getStart(sourceFile);
656
- const rootEnd = root.getEnd();
657
- const visit = (node) => {
658
- if (ts$1.isComputedPropertyName(node)) {
659
- const binding = getStaticValueBindingForExpression(node.expression, staticValues);
660
- if (binding && !isStateKeyComputedPropertyName(node)) references.push({
661
- uri,
662
- range: toSourceRange$1(sourceFile, node),
663
- value: binding.value
664
- });
665
- return;
666
- }
667
- if (!(node.getStart(sourceFile) >= rootStart && node.getEnd() <= rootEnd)) {
668
- ts$1.forEachChild(node, visit);
669
- return;
670
- }
671
- const binding = getStaticValueReferenceBinding(node, staticValues);
672
- if (binding) {
673
- references.push({
674
- uri,
675
- range: toSourceRange$1(sourceFile, node),
676
- value: binding.value
677
- });
678
- return;
679
- }
680
- ts$1.forEachChild(node, visit);
681
- };
682
- visit(root);
683
- return references;
684
- }
685
- function getStaticValueReferenceBinding(node, staticValues) {
686
- if (ts$1.isIdentifier(node)) {
687
- if (ts$1.isVariableDeclaration(node.parent) && node.parent.name === node) return null;
688
- if (ts$1.isPropertyAssignment(node.parent) && node.parent.name === node) return null;
689
- if (ts$1.isPropertyAccessExpression(node.parent)) return null;
690
- return staticValues.get(node.text) ?? null;
691
- }
692
- if (ts$1.isPropertyAccessExpression(node) && ts$1.isIdentifier(node.expression)) {
693
- if (ts$1.isComputedPropertyName(node.parent) && ts$1.isEnumMember(node.parent.parent)) return null;
694
- return staticValues.get(`${node.expression.text}.${node.name.text}`) ?? null;
695
- }
696
- return null;
697
- }
698
- function isStaticValueMachineLocal(sourceFile, binding, root) {
699
- const rootStart = root.getStart(sourceFile);
700
- const rootEnd = root.getEnd();
701
- let referenceCount = 0;
702
- let hasOutsideReference = false;
703
- const visit = (node) => {
704
- if (getStaticValueReferenceBinding(node, new Map([[binding.symbol, binding]]))) {
705
- referenceCount += 1;
706
- if (node.getStart(sourceFile) < rootStart || node.getEnd() > rootEnd) hasOutsideReference = true;
707
- return;
708
- }
709
- ts$1.forEachChild(node, visit);
710
- };
711
- visit(sourceFile);
712
- return referenceCount > 0 && !hasOutsideReference;
713
- }
714
- function isStateKeyComputedPropertyName(name) {
715
- const property = name.parent;
716
- if (!ts$1.isPropertyAssignment(property)) return false;
717
- const objectLiteral = property.parent;
718
- if (!ts$1.isObjectLiteralExpression(objectLiteral)) return false;
719
- const parentProperty = objectLiteral.parent;
720
- if (!ts$1.isPropertyAssignment(parentProperty)) return false;
721
- return getPropertyNameText$2(parentProperty.name) === "states";
722
- }
723
- function getStaticStringValue(expression) {
724
- const unwrapped = unwrapExpression$2(expression);
725
- if (ts$1.isStringLiteral(unwrapped) || ts$1.isNoSubstitutionTemplateLiteral(unwrapped) || ts$1.isNumericLiteral(unwrapped)) return unwrapped.text;
726
- return null;
727
- }
728
- function getEnumMemberName(name) {
729
- if (ts$1.isIdentifier(name) || ts$1.isStringLiteral(name) || ts$1.isNumericLiteral(name)) return name.text;
730
- return null;
731
- }
732
- function isCreateMachineExpression$2(expression) {
733
- const isMachineFactoryName = (name) => name === "createMachine" || name === "createMachineFromConfig";
734
- return ts$1.isIdentifier(expression) && isMachineFactoryName(expression.text) || ts$1.isPropertyAccessExpression(expression) && isMachineFactoryName(expression.name.text);
735
- }
736
- function unwrapObjectLiteralExpression$1(expression) {
737
- const unwrapped = unwrapExpression$2(expression);
738
- return ts$1.isObjectLiteralExpression(unwrapped) ? unwrapped : null;
739
- }
740
- function unwrapExpression$2(expression) {
741
- let current = expression;
742
- for (;;) {
743
- if (ts$1.isParenthesizedExpression(current)) {
744
- current = current.expression;
745
- continue;
746
- }
747
- if (ts$1.isAsExpression(current) || ts$1.isSatisfiesExpression(current)) {
748
- current = current.expression;
749
- continue;
750
- }
751
- if (ts$1.isTypeAssertionExpression(current) || ts$1.isNonNullExpression(current)) {
752
- current = current.expression;
753
- continue;
754
- }
755
- return current;
756
- }
757
- }
758
- function toSourceRange$1(sourceFile, node) {
759
- const start = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
760
- const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
761
- return {
762
- startLine: start.line,
763
- startChar: start.character,
764
- endLine: end.line,
765
- endChar: end.character
766
- };
767
- }
768
- function getScriptKind$3(fileName) {
769
- if (fileName.endsWith(".tsx")) return ts$1.ScriptKind.TSX;
770
- if (fileName.endsWith(".jsx")) return ts$1.ScriptKind.JSX;
771
- if (fileName.endsWith(".js")) return ts$1.ScriptKind.JS;
772
- return ts$1.ScriptKind.TS;
773
- }
774
-
775
- //#endregion
776
- //#region ../editor-sync/src/internal/codeToGraph.ts
777
- /**
778
- * Returns source text for the embed to parse.
779
- *
780
- * The returned text is still a temporary parse payload, not the source we write
781
- * back to. Directly imported modular states are hydrated into the root
782
- * `states` object so Viz can see their transition bodies even though it only
783
- * receives one string.
784
- */
785
- function parseSourceToMachine(text, document, options = {}) {
786
- const sourceLocations = collectXStateSourceLocations(text, document, options);
787
- if (!sourceLocations) return text;
788
- const staticValueReplacements = (sourceLocations.staticValues ?? []).map((location) => ({
789
- range: location.range,
790
- newText: JSON.stringify(location.value)
791
- }));
792
- const stateReplacements = sourceLocations.states.filter((location) => location.path.length === 1 && location.keyRange && !sourceLocations.statesObject?.referenceRange).flatMap((location) => {
793
- const keyRange = location.keyRange;
794
- const keyReplacement = location.keyReplacementText ? [{
795
- range: keyRange,
796
- newText: location.keyReplacementText
797
- }] : [];
798
- const stateText = readSourceRange(location.uri, location.range, options.resolver);
799
- if (!stateText) return keyReplacement;
800
- if (location.referenceRange && !areSourceRangesEqual(location.referenceRange, keyRange)) return [...keyReplacement, {
801
- range: location.referenceRange,
802
- newText: stateText
803
- }];
804
- if (!canHydrateShorthandState(text, keyRange)) return keyReplacement;
805
- return [...keyReplacement, {
806
- range: keyRange,
807
- newText: `${location.path[0]}: ${stateText}`
808
- }];
809
- });
810
- const statesObjectReplacements = sourceLocations.statesObject?.referenceRange && sourceLocations.statesObject.kind !== "inline" ? (() => {
811
- const statesText = readHydratedStatesObject(sourceLocations.statesObject.uri, sourceLocations.statesObject.range, sourceLocations.states, options.resolver);
812
- return statesText ? [{
813
- range: sourceLocations.statesObject.referenceRange,
814
- newText: areSourceRangesEqual(sourceLocations.statesObject.referenceRange, sourceLocations.statesObject.keyRange) ? `states: ${statesText}` : statesText
815
- }] : [];
816
- })() : [];
817
- const importReplacements = collectHydratedImportReplacements(text, document, new Set([...sourceLocations.states.filter((location) => location.path.length === 1 && location.referenceRange).map((location) => location.symbol).filter((symbol) => typeof symbol === "string"), ...sourceLocations.statesObject?.symbol ? [sourceLocations.statesObject.symbol] : []]));
818
- const hydratedText = applySourceRangeReplacements(text, [
819
- ...staticValueReplacements,
820
- ...stateReplacements,
821
- ...statesObjectReplacements,
822
- ...importReplacements
823
- ].filter(removeOverlappingRanges).sort(compareSourceRangesDescending));
824
- if (sourceLocations.profile === "xstate-v6-alpha" || options.machineIndex !== void 0) {
825
- const importedTransitionSources = collectImportedXStateTransitionSources(text, document, options);
826
- const parseText = importedTransitionSources.length ? `${hydratedText}\n${importedTransitionSources.join("\n")}` : hydratedText;
827
- const selectedMachineIndex = options.machineIndex ?? 0;
828
- const config = extractXStateMachineConfigEntries(parseText, { profile: sourceLocations.profile }).find((entry) => entry.machineIndex === selectedMachineIndex)?.config;
829
- if (!config) throw new Error(`No machine at index ${selectedMachineIndex} was found in ${document.fileName}.`);
830
- return `import { createMachine } from "xstate";
831
-
832
- export const machine = createMachine(${serializeJS(config, 0)});
833
- `;
834
- }
835
- return hydratedText;
836
- }
837
- function readHydratedStatesObject(uri, range, states, resolver) {
838
- if (!resolver) return null;
839
- const document = resolver.read(uri);
840
- if (!document) return null;
841
- const replacements = states.filter((state) => state.path.length === 1 && state.referenceRange).flatMap((state) => {
842
- const stateText = readSourceRange(state.uri, state.range, resolver);
843
- if (!stateText || !state.referenceRange) return [];
844
- const isShorthand = state.keyRange && areSourceRangesEqual(state.referenceRange, state.keyRange);
845
- return [{
846
- range: state.referenceRange,
847
- newText: isShorthand ? `${state.path[0]}: ${stateText}` : stateText
848
- }];
849
- });
850
- return applySourceRangeReplacementsToSlice(document.text, range, replacements);
851
- }
852
- function applySourceRangeReplacementsToSlice(text, range, replacements) {
853
- const sliceStart = offsetAtRangePosition$2(text, range.startLine, range.startChar);
854
- const sliceEnd = offsetAtRangePosition$2(text, range.endLine, range.endChar);
855
- let updated = text.slice(sliceStart, sliceEnd);
856
- for (const replacement of replacements.sort(compareSourceRangesDescending)) {
857
- const start = offsetAtRangePosition$2(text, replacement.range.startLine, replacement.range.startChar);
858
- const end = offsetAtRangePosition$2(text, replacement.range.endLine, replacement.range.endChar);
859
- if (start < sliceStart || end > sliceEnd) continue;
860
- const localStart = start - sliceStart;
861
- const localEnd = end - sliceStart;
862
- updated = `${updated.slice(0, localStart)}${replacement.newText}${updated.slice(localEnd)}`;
863
- }
864
- return updated;
865
- }
866
- function collectHydratedImportReplacements(text, document, hydratedSymbols) {
867
- if (hydratedSymbols.size === 0) return [];
868
- const sourceFile = ts$1.createSourceFile(document.fileName, text, ts$1.ScriptTarget.Latest, true, getScriptKind$2(document.fileName));
869
- const replacements = [];
870
- for (const statement of sourceFile.statements) {
871
- if (!ts$1.isImportDeclaration(statement) || !ts$1.isStringLiteral(statement.moduleSpecifier)) continue;
872
- if (!statement.moduleSpecifier.text.startsWith(".")) continue;
873
- const namedBindings = statement.importClause?.namedBindings;
874
- if (!namedBindings || !ts$1.isNamedImports(namedBindings)) continue;
875
- const importedNames = namedBindings.elements.map((element) => element.name.text);
876
- if (importedNames.length === 0 || !importedNames.every((name) => hydratedSymbols.has(name))) continue;
877
- replacements.push({
878
- range: toSourceRange(sourceFile, statement, { includeTrailingNewline: true }),
879
- newText: ""
880
- });
881
- }
882
- return replacements;
883
- }
884
- function toSourceRange(sourceFile, node, options = {}) {
885
- const start = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
886
- let endOffset = node.getEnd();
887
- if (options.includeTrailingNewline) {
888
- const match = sourceFile.text.slice(endOffset).match(/^\r?\n/);
889
- if (match) endOffset += match[0].length;
890
- }
891
- const end = sourceFile.getLineAndCharacterOfPosition(endOffset);
892
- return {
893
- startLine: start.line,
894
- startChar: start.character,
895
- endLine: end.line,
896
- endChar: end.character
897
- };
898
- }
899
- function getScriptKind$2(fileName) {
900
- if (fileName.endsWith(".tsx")) return ts$1.ScriptKind.TSX;
901
- if (fileName.endsWith(".jsx")) return ts$1.ScriptKind.JSX;
902
- if (fileName.endsWith(".js")) return ts$1.ScriptKind.JS;
903
- return ts$1.ScriptKind.TS;
904
- }
905
- function removeOverlappingRanges(replacement, index, replacements) {
906
- return !replacements.some((candidate, candidateIndex) => {
907
- if (candidateIndex === index) return false;
908
- return compareSourceRangesDescending(candidate, replacement) < 0 && rangesOverlap$1(candidate.range, replacement.range);
909
- });
910
- }
911
- function rangesOverlap$1(left, right) {
912
- const leftStart = rangePositionKey(left.startLine, left.startChar);
913
- const leftEnd = rangePositionKey(left.endLine, left.endChar);
914
- const rightStart = rangePositionKey(right.startLine, right.startChar);
915
- return leftStart < rangePositionKey(right.endLine, right.endChar) && rightStart < leftEnd;
916
- }
917
- function rangePositionKey(line, character) {
918
- return line * 1e6 + character;
919
- }
920
- function areSourceRangesEqual(left, right) {
921
- return left.startLine === right.startLine && left.startChar === right.startChar && left.endLine === right.endLine && left.endChar === right.endChar;
922
- }
923
- function canHydrateShorthandState(text, range) {
924
- const end = offsetAtRangePosition$2(text, range.endLine, range.endChar);
925
- return text.slice(end).match(/\S/)?.[0] !== ":";
926
- }
927
- function readSourceRange(uri, range, resolver) {
928
- if (!resolver) return null;
929
- const document = resolver.read(uri);
930
- if (!document) return null;
931
- const start = offsetAtRangePosition$2(document.text, range.startLine, range.startChar);
932
- const end = offsetAtRangePosition$2(document.text, range.endLine, range.endChar);
933
- return document.text.slice(start, end);
934
- }
935
- function applySourceRangeReplacements(text, replacements) {
936
- let updated = text;
937
- for (const replacement of replacements) {
938
- const start = offsetAtRangePosition$2(updated, replacement.range.startLine, replacement.range.startChar);
939
- const end = offsetAtRangePosition$2(updated, replacement.range.endLine, replacement.range.endChar);
940
- updated = `${updated.slice(0, start)}${replacement.newText}${updated.slice(end)}`;
941
- }
942
- return updated;
943
- }
944
- function compareSourceRangesDescending(left, right) {
945
- if (left.range.startLine !== right.range.startLine) return right.range.startLine - left.range.startLine;
946
- return right.range.startChar - left.range.startChar;
947
- }
948
- function offsetAtRangePosition$2(text, line, character) {
949
- if (line <= 0) return character;
950
- let currentLine = 0;
951
- for (let index = 0; index < text.length; index += 1) {
952
- if (text.charCodeAt(index) !== 10) continue;
953
- currentLine += 1;
954
- if (currentLine === line) return index + 1 + character;
955
- }
956
- return text.length;
957
- }
958
-
959
- //#endregion
960
- //#region ../editor-sync/src/internal/editTargets.ts
961
- function createSourceFile(document, sourceText) {
962
- return ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$1(document.fileName));
963
- }
964
- function getMappedRootObjectLiteral(document, sourceFile, sourceLocations) {
965
- if (!sourceLocations?.root || !isSourceLocationForDocument(sourceLocations.root.uri, document)) return null;
966
- return findObjectLiteralByRange(sourceFile, sourceLocations.root.range);
967
- }
968
- function getMappedStateObjectLiteral(document, sourceFile, sourceLocations, path) {
969
- if (!sourceLocations) return null;
970
- const location = sourceLocations.states.find((item) => arePathsEqual$1(item.path, path));
971
- if (!location || !isSourceLocationForDocument(location.uri, document)) return null;
972
- return findObjectLiteralByRange(sourceFile, location.range);
973
- }
974
- async function getMappedStateReplacementTarget(rootDocument, rootSourceFile, sourceLocations, path, openTextDocument) {
975
- if (!sourceLocations) return null;
976
- const location = sourceLocations.states.find((item) => arePathsEqual$1(item.path, path));
977
- if (!location) return null;
978
- return getObjectTargetFromLocation(rootDocument, rootSourceFile, location.uri, location.range, openTextDocument);
979
- }
980
- function getStateMembershipParentTarget(document, sourceFile, machineConfigNode, sourceLocations, parentPath, getStateObjectLiteralByPath) {
981
- if (parentPath.length === 0) return getMappedStatesObjectTarget(document, sourceFile, sourceLocations) ?? {
982
- document,
983
- sourceFile,
984
- node: machineConfigNode,
985
- nodeKind: "machineConfig"
986
- };
987
- const node = getMappedStateObjectLiteral(document, sourceFile, sourceLocations, parentPath) ?? getStateObjectLiteralByPath(machineConfigNode, parentPath);
988
- return node ? {
989
- document,
990
- sourceFile,
991
- node,
992
- nodeKind: "machineConfig"
993
- } : null;
994
- }
995
- async function getStateMembershipParentTargetForDocuments(document, sourceFile, machineConfigNode, sourceLocations, parentPath, openTextDocument, getStateObjectLiteralByPath) {
996
- if (parentPath.length === 0) return await getMappedStatesObjectTargetForDocuments(document, sourceFile, sourceLocations, openTextDocument) ?? {
997
- document,
998
- sourceFile,
999
- node: machineConfigNode,
1000
- nodeKind: "machineConfig"
1001
- };
1002
- const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, sourceLocations, parentPath, openTextDocument);
1003
- if (mappedTarget) return {
1004
- ...mappedTarget,
1005
- nodeKind: "machineConfig"
1006
- };
1007
- const node = getStateObjectLiteralByPath(machineConfigNode, parentPath);
1008
- return node ? {
1009
- document,
1010
- sourceFile,
1011
- node,
1012
- nodeKind: "machineConfig"
1013
- } : null;
1014
- }
1015
- async function openDocumentBySourceUri(uri, openTextDocument) {
1016
- if (!openTextDocument) return null;
1017
- try {
1018
- return await openTextDocument(uri);
1019
- } catch {
1020
- return null;
1021
- }
1022
- }
1023
- function isSourceLocationForDocument(uri, document) {
1024
- return uri === (typeof document.uri === "string" ? document.uri : document.uri?.toString()) || uri === document.fileName;
1025
- }
1026
- function findObjectLiteralByRange(sourceFile, range) {
1027
- const start = offsetAtRangePosition$1(sourceFile.text, range.startLine, range.startChar);
1028
- const end = offsetAtRangePosition$1(sourceFile.text, range.endLine, range.endChar);
1029
- let found = null;
1030
- const visit = (node) => {
1031
- if (found) return;
1032
- if (ts$1.isObjectLiteralExpression(node) && node.getStart(sourceFile) === start && node.getEnd() >= end) {
1033
- found = node;
1034
- return;
1035
- }
1036
- ts$1.forEachChild(node, visit);
1037
- };
1038
- visit(sourceFile);
1039
- return found;
1040
- }
1041
- function getMappedStatesObjectTarget(rootDocument, rootSourceFile, sourceLocations) {
1042
- const location = sourceLocations?.statesObject;
1043
- if (!location || !isSourceLocationForDocument(location.uri, rootDocument)) return null;
1044
- const node = findObjectLiteralByRange(rootSourceFile, location.range);
1045
- return node ? {
1046
- document: rootDocument,
1047
- sourceFile: rootSourceFile,
1048
- node,
1049
- nodeKind: "statesObject"
1050
- } : null;
1051
- }
1052
- async function getMappedStatesObjectTargetForDocuments(rootDocument, rootSourceFile, sourceLocations, openTextDocument) {
1053
- const location = sourceLocations?.statesObject;
1054
- if (!location) return null;
1055
- const target = await getObjectTargetFromLocation(rootDocument, rootSourceFile, location.uri, location.range, openTextDocument);
1056
- return target ? {
1057
- ...target,
1058
- nodeKind: "statesObject"
1059
- } : null;
1060
- }
1061
- async function getObjectTargetFromLocation(rootDocument, rootSourceFile, uri, range, openTextDocument) {
1062
- const targetDocument = isSourceLocationForDocument(uri, rootDocument) ? rootDocument : await openDocumentBySourceUri(uri, openTextDocument);
1063
- if (!targetDocument) return null;
1064
- const targetSourceFile = isSourceLocationForDocument(uri, rootDocument) ? rootSourceFile : createSourceFile(targetDocument, targetDocument.getText());
1065
- const node = findObjectLiteralByRange(targetSourceFile, range);
1066
- if (!node) return null;
1067
- return {
1068
- document: targetDocument,
1069
- sourceFile: targetSourceFile,
1070
- node
1071
- };
1072
- }
1073
- function getScriptKind$1(fileName) {
1074
- if (fileName.endsWith(".tsx")) return ts$1.ScriptKind.TSX;
1075
- if (fileName.endsWith(".jsx")) return ts$1.ScriptKind.JSX;
1076
- if (fileName.endsWith(".js")) return ts$1.ScriptKind.JS;
1077
- return ts$1.ScriptKind.TS;
1078
- }
1079
- function arePathsEqual$1(left, right) {
1080
- return left.length === right.length && left.every((segment, index) => segment === right[index]);
1081
- }
1082
- function offsetAtRangePosition$1(sourceText, line, character) {
1083
- let currentLine = 0;
1084
- let lineStart = 0;
1085
- for (let index = 0; index < sourceText.length; index += 1) {
1086
- if (currentLine === line) return Math.min(lineStart + character, sourceText.length);
1087
- if (sourceText.charCodeAt(index) === 10) {
1088
- currentLine += 1;
1089
- lineStart = index + 1;
1090
- }
1091
- }
1092
- return Math.min(lineStart + character, sourceText.length);
1093
- }
1094
-
1095
- //#endregion
1096
- //#region ../editor-sync/src/internal/graphToCode.ts
1097
- function applyMachineToSource(machineConfig, document, options = {}) {
1098
- if (!isMachineConfig(machineConfig)) return [];
1099
- const sourceFile = createSourceFile(document, document.getText());
1100
- const machineConfigNode = getMappedRootObjectLiteral(document, sourceFile, options.sourceLocations) ?? findMachineConfigObjectLiteral(sourceFile, options.machineIndex);
1101
- if (!machineConfigNode) return [];
1102
- if (options.sourceUpdateStrategy === "rewrite") return addCodeImportReplacements(document, sourceFile, machineConfig, [createRewriteReplacement(document, sourceFile, machineConfigNode, machineConfig)]).sort(compareReplacementRangesDescending);
1103
- const parsedPatches = parseGraphPatches(options.patches);
1104
- const prevGraph = parseGraph(options.prevGraph);
1105
- const nextGraph = parseGraph(options.nextGraph);
1106
- const rootNode = machineConfigNode;
1107
- if (!parsedPatches || !prevGraph || !nextGraph || parsedPatches.length === 0) {
1108
- if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1109
- return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1110
- }
1111
- if (hasNestedStateRenameBatch(parsedPatches, prevGraph, nextGraph)) return [];
1112
- const semanticReplacements = tryCreateSemanticReplacements(document, sourceFile, machineConfigNode, parsedPatches, prevGraph, nextGraph);
1113
- if (semanticReplacements) return semanticReplacements.sort(compareReplacementRangesDescending);
1114
- let patchesForSplit = parsedPatches;
1115
- const implementationSplit = tryCreateImplementationPatchSplit(document, sourceFile, patchesForSplit, nextGraph, options.machineIndex);
1116
- if (implementationSplit) {
1117
- const implementationRemainingPatches = dropCoveredSchemaPatches(implementationSplit.remainingPatches, implementationSplit.replacements.length > 0);
1118
- if (implementationRemainingPatches.length === 0) return implementationSplit.replacements.sort(compareReplacementRangesDescending);
1119
- const remainingPlan = deriveReplacementPlan(implementationRemainingPatches, prevGraph, nextGraph);
1120
- if (remainingPlan.type === "root") {
1121
- if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1122
- return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1123
- }
1124
- const replacements = [...implementationSplit.replacements];
1125
- for (const path of remainingPlan.paths) {
1126
- const currentNode = getMappedStateObjectLiteral(document, sourceFile, options.sourceLocations, path) ?? getStateObjectLiteralByPath(machineConfigNode, path);
1127
- const nextValue = getStateConfigByPath(machineConfig, path);
1128
- if (!currentNode || !isMachineConfig(nextValue)) {
1129
- if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1130
- return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1131
- }
1132
- replacements.push(createReplacement(document, sourceFile, currentNode, nextValue));
1133
- }
1134
- return replacements.sort(compareReplacementRangesDescending);
1135
- }
1136
- patchesForSplit = dropCoveredSchemaPatches(patchesForSplit, false);
1137
- const stateMembershipSplit = tryCreateStateMembershipPatchSplit(document, sourceFile, rootNode, machineConfig, patchesForSplit, prevGraph, nextGraph, options.sourceLocations);
1138
- if (stateMembershipSplit) {
1139
- const stateMembershipRemainingPatches = dropCoveredSchemaPatches(stateMembershipSplit.remainingPatches, stateMembershipSplit.replacements.length > 0);
1140
- if (stateMembershipRemainingPatches.length === 0) return stateMembershipSplit.replacements;
1141
- const remainingPlan = deriveReplacementPlan(stateMembershipRemainingPatches, prevGraph, nextGraph);
1142
- if (remainingPlan.type === "root") {
1143
- if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1144
- return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1145
- }
1146
- const replacements = [...stateMembershipSplit.replacements];
1147
- for (const path of remainingPlan.paths) {
1148
- const currentNode = getMappedStateObjectLiteral(document, sourceFile, options.sourceLocations, path) ?? getStateObjectLiteralByPath(machineConfigNode, path);
1149
- const nextValue = getStateConfigByPath(machineConfig, path);
1150
- if (!currentNode || !isMachineConfig(nextValue)) {
1151
- if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1152
- return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1153
- }
1154
- replacements.push(createReplacement(document, sourceFile, currentNode, nextValue));
1155
- }
1156
- return replacements.sort(compareReplacementRangesDescending);
1157
- }
1158
- const plan = deriveReplacementPlan(patchesForSplit, prevGraph, nextGraph);
1159
- if (plan.type === "root") {
1160
- if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1161
- return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1162
- }
1163
- const replacements = [];
1164
- for (const path of plan.paths) {
1165
- const currentNode = getMappedStateObjectLiteral(document, sourceFile, options.sourceLocations, path) ?? getStateObjectLiteralByPath(machineConfigNode, path);
1166
- const nextValue = getStateConfigByPath(machineConfig, path);
1167
- if (!currentNode || !isMachineConfig(nextValue)) {
1168
- if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1169
- return [createReplacement(document, sourceFile, rootNode, machineConfig)];
1170
- }
1171
- replacements.push(createReplacement(document, sourceFile, currentNode, nextValue));
1172
- }
1173
- return replacements.sort(compareReplacementRangesDescending);
1174
- }
1175
- async function applyMachineToSourceDocuments(machineConfig, document, options = {}) {
1176
- if (!isMachineConfig(machineConfig)) return [];
1177
- const sourceFile = createSourceFile(document, document.getText());
1178
- const machineConfigNode = getMappedRootObjectLiteral(document, sourceFile, options.sourceLocations) ?? findMachineConfigObjectLiteral(sourceFile, options.machineIndex);
1179
- if (!machineConfigNode) return [];
1180
- if (options.sourceUpdateStrategy === "rewrite") return addCodeImportReplacements(document, sourceFile, machineConfig, [createRewriteReplacement(document, sourceFile, machineConfigNode, machineConfig)]).sort(compareReplacementRangesDescending);
1181
- const parsedPatches = parseGraphPatches(options.patches);
1182
- const prevGraph = parseGraph(options.prevGraph);
1183
- const nextGraph = parseGraph(options.nextGraph);
1184
- const finalize = (replacements) => {
1185
- return normalizeOverlappingReplacements(addCodeImportReplacements(document, sourceFile, machineConfig, replacements)).sort(compareReplacementRangesDescending);
1186
- };
1187
- if (!parsedPatches || !prevGraph || !nextGraph || parsedPatches.length === 0) {
1188
- if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1189
- return finalize([createReplacement(document, sourceFile, machineConfigNode, machineConfig)]);
1190
- }
1191
- if (hasNestedStateRenameBatch(parsedPatches, prevGraph, nextGraph)) return [];
1192
- const semanticSplit = await tryCreateSemanticPatchSplitForDocuments(document, sourceFile, machineConfigNode, parsedPatches, prevGraph, nextGraph, options.sourceLocations, options.openTextDocument);
1193
- if (semanticSplit && semanticSplit.remainingPatches.length === 0) return finalize(semanticSplit.replacements);
1194
- const activePatches = dropCoveredSchemaPatches(semanticSplit?.remainingPatches ?? parsedPatches, (semanticSplit?.replacements.length ?? 0) > 0);
1195
- const activeSourceLocations = semanticSplit?.sourceLocations ?? options.sourceLocations;
1196
- let semanticReplacements = semanticSplit?.replacements ?? [];
1197
- if (activePatches.length === 0) return finalize(semanticReplacements);
1198
- const transitionSplit = await tryCreateTransitionPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, activePatches, prevGraph, nextGraph, activeSourceLocations, options.openTextDocument);
1199
- if (transitionSplit && transitionSplit.remainingPatches.length === 0) return finalize([...semanticReplacements, ...transitionSplit.replacements]);
1200
- if (transitionSplit) semanticReplacements = [...semanticReplacements, ...transitionSplit.replacements];
1201
- const implementationSplit = tryCreateImplementationPatchSplit(document, sourceFile, transitionSplit?.remainingPatches ?? activePatches, nextGraph, options.machineIndex);
1202
- if (implementationSplit && implementationSplit.remainingPatches.length === 0) return finalize([...semanticReplacements, ...implementationSplit.replacements]);
1203
- if (implementationSplit) semanticReplacements = [...semanticReplacements, ...implementationSplit.replacements];
1204
- const patchesAfterImplementationSplit = dropCoveredSchemaPatches(implementationSplit?.remainingPatches ?? activePatches, semanticReplacements.length > 0);
1205
- if (patchesAfterImplementationSplit.length === 0) return finalize(semanticReplacements);
1206
- const stateMembershipSplit = await tryCreateStateMembershipPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, patchesAfterImplementationSplit, prevGraph, nextGraph, activeSourceLocations, options.openTextDocument);
1207
- if (stateMembershipSplit) {
1208
- const stateMembershipRemainingPatches = dropCoveredSchemaPatches(stateMembershipSplit.remainingPatches, semanticReplacements.length + stateMembershipSplit.replacements.length > 0);
1209
- if (stateMembershipRemainingPatches.length === 0) return finalize([...semanticReplacements, ...stateMembershipSplit.replacements]);
1210
- const remainingPlan = deriveReplacementPlan(stateMembershipRemainingPatches, prevGraph, nextGraph);
1211
- if (remainingPlan.type === "root") {
1212
- if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1213
- return finalize([createReplacement(document, sourceFile, machineConfigNode, machineConfig)]);
1214
- }
1215
- const replacements = [...semanticReplacements, ...stateMembershipSplit.replacements];
1216
- for (const path of remainingPlan.paths) {
1217
- const nextValue = getStateConfigByPath(machineConfig, path);
1218
- if (!isMachineConfig(nextValue)) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
1219
- const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, activeSourceLocations, path, options.openTextDocument);
1220
- const currentNode = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, path);
1221
- const targetDocument = mappedTarget?.document ?? document;
1222
- const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
1223
- if (!currentNode) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
1224
- replacements.push(createReplacement(targetDocument, targetSourceFile, currentNode, nextValue));
1225
- }
1226
- return finalize(replacements);
1227
- }
1228
- const plan = deriveReplacementPlan(patchesAfterImplementationSplit, prevGraph, nextGraph);
1229
- if (plan.type === "root") {
1230
- if (wouldDeModularizeRootReplacement(options.sourceLocations)) return [];
1231
- return finalize([createReplacement(document, sourceFile, machineConfigNode, machineConfig)]);
1232
- }
1233
- const replacements = [...semanticReplacements];
1234
- for (const path of plan.paths) {
1235
- const nextValue = getStateConfigByPath(machineConfig, path);
1236
- if (!isMachineConfig(nextValue)) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
1237
- const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, activeSourceLocations, path, options.openTextDocument);
1238
- const currentNode = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, path);
1239
- const targetDocument = mappedTarget?.document ?? document;
1240
- const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
1241
- if (!currentNode) return fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, activeSourceLocations);
1242
- replacements.push(createReplacement(targetDocument, targetSourceFile, currentNode, nextValue));
1243
- }
1244
- return finalize(replacements);
1245
- }
1246
- function fallbackRootReplacement(document, sourceFile, machineConfigNode, machineConfig, sourceLocations) {
1247
- if (wouldDeModularizeRootReplacement(sourceLocations)) return [];
1248
- return addCodeImportReplacements(document, sourceFile, machineConfig, [createReplacement(document, sourceFile, machineConfigNode, machineConfig)]).sort(compareReplacementRangesDescending);
1249
- }
1250
- async function tryCreateTransitionPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) {
1251
- if (isXStateV6Source(sourceLocations)) {
1252
- const v6Split = await tryCreateV6TransitionPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, patches, prevGraph, nextGraph, sourceLocations, openTextDocument);
1253
- if (v6Split) return v6Split;
1254
- }
1255
- const replacements = [];
1256
- const remainingPatches = [];
1257
- const handledTransitionKeys = /* @__PURE__ */ new Set();
1258
- const handledStatePropertyKeys = /* @__PURE__ */ new Set();
1259
- const deletedStatePaths = patches.flatMap((patch) => {
1260
- if (patch.op !== "deleteState") return [];
1261
- const path = resolveStatePath(prevGraph, patch.stateId);
1262
- return path ? [path] : [];
1263
- });
1264
- for (const patch of patches) {
1265
- const transitionTarget = getTransitionPatchTarget(patch, prevGraph, nextGraph);
1266
- if (transitionTarget) {
1267
- if (deletedStatePaths.some((deletedPath) => isPathEqualOrDescendant(transitionTarget.sourcePath, deletedPath))) continue;
1268
- const transitionKey = `${transitionTarget.sourcePath.join(".")}:${transitionTarget.previousEventType}:${transitionTarget.index ?? "single"}`;
1269
- if (handledTransitionKeys.has(transitionKey)) continue;
1270
- const patchReplacements = patch.op === "deleteTransition" ? await createDeleteTransitionReplacementsForDocuments(document, sourceFile, machineConfigNode, transitionTarget, sourceLocations, openTextDocument) : await createTransitionReplacementForDocuments(document, sourceFile, machineConfigNode, machineConfig, transitionTarget, sourceLocations, openTextDocument);
1271
- if (!patchReplacements) {
1272
- remainingPatches.push(patch);
1273
- continue;
1274
- }
1275
- handledTransitionKeys.add(transitionKey);
1276
- replacements.push(...patchReplacements);
1277
- continue;
1278
- }
1279
- const [statePropertyTarget] = getStatePropertyPatchTargets(patch, prevGraph, nextGraph);
1280
- if (!statePropertyTarget) {
1281
- remainingPatches.push(patch);
1282
- continue;
1283
- }
1284
- const statePathKey = statePropertyTarget.path.join(".");
1285
- const statePropertyKey = `${statePathKey}:${statePropertyTarget.propertyName}`;
1286
- if (handledStatePropertyKeys.has(statePropertyKey)) continue;
1287
- const propertyNames = /* @__PURE__ */ new Set();
1288
- for (const candidate of patches) {
1289
- const candidateTargets = getStatePropertyPatchTargets(candidate, prevGraph, nextGraph);
1290
- for (const candidateTarget of candidateTargets) {
1291
- if (candidateTarget.path.join(".") !== statePathKey) continue;
1292
- const candidateKey = `${statePathKey}:${candidateTarget.propertyName}`;
1293
- if (!handledStatePropertyKeys.has(candidateKey)) propertyNames.add(candidateTarget.propertyName);
1294
- }
1295
- }
1296
- const patchReplacements = await createStatePropertiesReplacementForDocuments(document, sourceFile, machineConfigNode, machineConfig, statePropertyTarget.path, [...propertyNames], sourceLocations, openTextDocument);
1297
- if (!patchReplacements) {
1298
- remainingPatches.push(patch);
1299
- continue;
1300
- }
1301
- replacements.push(...patchReplacements);
1302
- for (const propertyName of propertyNames) handledStatePropertyKeys.add(`${statePathKey}:${propertyName}`);
1303
- }
1304
- return replacements.length > 0 ? {
1305
- replacements: replacements.sort(compareReplacementRangesDescending),
1306
- remainingPatches
1307
- } : null;
1308
- }
1309
- async function tryCreateV6TransitionPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) {
1310
- applyV6FunctionDescriptionEdits(machineConfig, machineConfigNode, patches, prevGraph, nextGraph);
1311
- const propertiesByPath = /* @__PURE__ */ new Map();
1312
- const remainingPatches = [];
1313
- const deletedStatePaths = patches.flatMap((patch) => {
1314
- if (patch.op !== "deleteState") return [];
1315
- const path = resolveStatePath(prevGraph, patch.stateId);
1316
- return path ? [path] : [];
1317
- });
1318
- for (const patch of patches) {
1319
- const edgeId = getTransitionPatchEdgeId(patch, prevGraph, nextGraph);
1320
- if ((edgeId ? prevGraph.edges.find((edge) => edge.id === edgeId) ?? nextGraph.edges.find((edge) => edge.id === edgeId) : void 0)?.data?.meta?.[XSTATE_V6_FN_TRANSITION_META] === true && patch.op !== "deleteTransition") return {
1321
- replacements: [],
1322
- remainingPatches: []
1323
- };
1324
- const targets = getV6TransitionPropertyTargets(patch, prevGraph, nextGraph);
1325
- if (targets.length === 0) {
1326
- remainingPatches.push(patch);
1327
- continue;
1328
- }
1329
- for (const target of targets) {
1330
- if (deletedStatePaths.some((deletedPath) => isPathEqualOrDescendant(target.path, deletedPath))) continue;
1331
- const key = target.path.join(".");
1332
- const group = propertiesByPath.get(key) ?? {
1333
- path: target.path,
1334
- properties: /* @__PURE__ */ new Map()
1335
- };
1336
- const slots = group.properties.get(target.propertyName) ?? /* @__PURE__ */ new Set();
1337
- if (target.slotKey !== null) slots.add(target.slotKey);
1338
- group.properties.set(target.propertyName, slots);
1339
- propertiesByPath.set(key, group);
1340
- }
1341
- }
1342
- if (propertiesByPath.size === 0) return null;
1343
- const replacements = [];
1344
- for (const { path, properties } of propertiesByPath.values()) {
1345
- if (!canSerializeXStateV6TransitionProperties(machineConfig, path, properties)) return {
1346
- replacements: [],
1347
- remainingPatches: []
1348
- };
1349
- const propertyReplacements = await createStatePropertiesReplacementForDocuments(document, sourceFile, machineConfigNode, machineConfig, path, [...properties.keys()], sourceLocations, openTextDocument, properties);
1350
- if (!propertyReplacements) return null;
1351
- replacements.push(...propertyReplacements);
1352
- }
1353
- return {
1354
- replacements: replacements.sort(compareReplacementRangesDescending),
1355
- remainingPatches
1356
- };
1357
- }
1358
- function applyV6FunctionDescriptionEdits(machineConfig, machineConfigNode, patches, prevGraph, nextGraph) {
1359
- for (const patch of patches) {
1360
- if (patch.op !== "updateTransition" || patch.transitionDescription === void 0 || Object.prototype.hasOwnProperty.call(patch.meta ?? {}, XSTATE_V6_BRANCH_DESCRIPTION_META)) continue;
1361
- const target = getTransitionPatchTarget(patch, prevGraph, nextGraph);
1362
- if (!target) continue;
1363
- const stateObject = getStateObjectLiteralByPath(machineConfigNode, target.sourcePath);
1364
- if (!stateObject || !isV6FunctionTransitionSource(stateObject, target.previousEventType)) continue;
1365
- const stateConfig = getStateConfigByPath(machineConfig, target.sourcePath);
1366
- const transitions = (isMachineConfig(stateConfig?.on) ? stateConfig.on : null)?.[target.eventType];
1367
- if (!Array.isArray(transitions)) continue;
1368
- for (const transition of transitions) {
1369
- if (!isMachineConfig(transition)) continue;
1370
- if (patch.transitionDescription === null) delete transition.description;
1371
- else transition.description = patch.transitionDescription;
1372
- }
1373
- }
1374
- }
1375
- function isV6FunctionTransitionSource(stateObject, eventType) {
1376
- const onObject = getObjectLiteralProperty(stateObject, "on");
1377
- if (!onObject) return false;
1378
- const eventProperty = findObjectLiteralProperty(onObject, eventType);
1379
- if (!eventProperty || !ts$1.isPropertyAssignment(eventProperty)) return false;
1380
- const initializer = unwrapExpression$1(eventProperty.initializer);
1381
- if (ts$1.isArrowFunction(initializer) || ts$1.isFunctionExpression(initializer)) return true;
1382
- if (!ts$1.isObjectLiteralExpression(initializer)) return false;
1383
- return initializer.properties.some((property) => ts$1.isPropertyAssignment(property) && property.name.getText().replace(/^['"]|['"]$/g, "") === "to");
1384
- }
1385
- function canSerializeXStateV6TransitionProperties(machineConfig, path, properties) {
1386
- const stateConfig = getStateConfigByPath(machineConfig, path);
1387
- if (!stateConfig) return false;
1388
- for (const [propertyName, slots] of properties) {
1389
- const value = stateConfig[propertyName];
1390
- if (value === void 0) continue;
1391
- const converted = getXStateV6PropertyValue(propertyName, value);
1392
- if (propertyName === "on" || propertyName === "after") {
1393
- if (!isMachineConfig(converted)) return false;
1394
- if ([...slots].some((slot) => Array.isArray(converted[slot]))) return false;
1395
- continue;
1396
- }
1397
- if (propertyName === "invoke") {
1398
- const invokes = Array.isArray(converted) ? converted : [converted];
1399
- for (const slotRef of slots) {
1400
- const match = /^@statelyai\.invoke\.(done|error|snapshot|timeout)\.(.+)$/.exec(slotRef);
1401
- if (!match) return false;
1402
- const invoke = invokes[findXStateV6InvokeIndex(invokes, match[2])];
1403
- const slot = {
1404
- done: "onDone",
1405
- error: "onError",
1406
- snapshot: "onSnapshot",
1407
- timeout: "onTimeout"
1408
- }[match[1]];
1409
- if (!isMachineConfig(invoke) || Array.isArray(invoke[slot])) return false;
1410
- }
1411
- continue;
1412
- }
1413
- if (Array.isArray(converted)) return false;
1414
- }
1415
- return true;
1416
- }
1417
- async function createDeleteTransitionReplacementsForDocuments(document, sourceFile, machineConfigNode, transitionTarget, sourceLocations, openTextDocument) {
1418
- const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, sourceLocations, transitionTarget.sourcePath, openTextDocument);
1419
- const targetDocument = mappedTarget?.document ?? document;
1420
- const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
1421
- const stateObject = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, transitionTarget.sourcePath);
1422
- if (!stateObject) return null;
1423
- const transitionSource = getTransitionSourceExpression(stateObject, transitionTarget.previousEventType, transitionTarget.index);
1424
- if (!transitionSource) return null;
1425
- if (transitionSource.array && transitionSource.element) return [createArrayElementDeletion(targetDocument, targetSourceFile, transitionSource.array, transitionSource.element)];
1426
- return [createObjectLiteralPropertyDeletion(targetDocument, targetSourceFile, transitionSource.onObject, transitionSource.eventProperty)];
1427
- }
1428
- async function createTransitionReplacementForDocuments(document, sourceFile, machineConfigNode, machineConfig, transitionTarget, sourceLocations, openTextDocument) {
1429
- const nextTransitionValue = getTransitionConfigValue(machineConfig, transitionTarget.sourcePath, transitionTarget.eventType, transitionTarget.index);
1430
- if (nextTransitionValue === void 0) return null;
1431
- const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, sourceLocations, transitionTarget.sourcePath, openTextDocument);
1432
- const targetDocument = mappedTarget?.document ?? document;
1433
- const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
1434
- const stateObject = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, transitionTarget.sourcePath);
1435
- if (!stateObject) return null;
1436
- const transitionSource = getTransitionSourceExpression(stateObject, transitionTarget.previousEventType, transitionTarget.index);
1437
- if (transitionSource?.array && transitionSource.element) return [createExpressionReplacement(targetDocument, targetSourceFile, transitionSource.element, nextTransitionValue)];
1438
- if (transitionSource && transitionTarget.previousEventType === transitionTarget.eventType) return [createPropertyValueReplacement(targetDocument, targetSourceFile, transitionSource.eventProperty, nextTransitionValue)];
1439
- if (transitionSource) return [createPropertyAssignmentReplacement(targetDocument, targetSourceFile, transitionSource.eventProperty, transitionTarget.eventType, nextTransitionValue)];
1440
- const onObject = getObjectLiteralProperty(stateObject, "on");
1441
- if (onObject) return createObjectLiteralPropertyInsertion(targetDocument, targetSourceFile, onObject, transitionTarget.eventType, nextTransitionValue);
1442
- return createObjectLiteralPropertyInsertion(targetDocument, targetSourceFile, stateObject, "on", { [transitionTarget.eventType]: nextTransitionValue });
1443
- }
1444
- async function createStatePropertiesReplacementForDocuments(document, sourceFile, machineConfigNode, machineConfig, path, propertyNames, sourceLocations, openTextDocument, affectedV6Slots) {
1445
- const nextStateConfig = getStateConfigByPath(machineConfig, path);
1446
- if (!isMachineConfig(nextStateConfig)) return null;
1447
- const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, sourceLocations, path, openTextDocument);
1448
- const targetDocument = mappedTarget?.document ?? document;
1449
- const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
1450
- const stateObject = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, path);
1451
- if (!stateObject) return null;
1452
- const replacements = [];
1453
- const insertionEntries = [];
1454
- for (const propertyName of propertyNames) {
1455
- const rawNextValue = nextStateConfig[propertyName];
1456
- const property = findObjectLiteralProperty(stateObject, propertyName);
1457
- const affectedSlots = affectedV6Slots?.get(propertyName);
1458
- const nextValue = rawNextValue === void 0 || !isXStateV6Source(sourceLocations) ? rawNextValue : getXStateV6PropertyValue(propertyName, rawNextValue);
1459
- if (affectedSlots && (propertyName === "on" || propertyName === "after") && property && ts$1.isPropertyAssignment(property) && isMachineConfig(nextValue)) {
1460
- const existingMap = unwrapObjectLiteralExpression(property.initializer);
1461
- if (existingMap) {
1462
- const insertedSlots = [];
1463
- for (const slot of affectedSlots) {
1464
- const existingSlot = findObjectLiteralProperty(existingMap, slot);
1465
- const nextSlotValue = nextValue[slot];
1466
- if (nextSlotValue === void 0) {
1467
- if (existingSlot) replacements.push(createObjectLiteralPropertyDeletion(targetDocument, targetSourceFile, existingMap, existingSlot));
1468
- } else if (existingSlot) replacements.push(createPropertyValueReplacement(targetDocument, targetSourceFile, existingSlot, nextSlotValue));
1469
- else insertedSlots.push({
1470
- key: slot,
1471
- config: nextSlotValue
1472
- });
1473
- }
1474
- if (insertedSlots.length > 0) replacements.push(createObjectLiteralPropertiesInsertion(targetDocument, targetSourceFile, existingMap, insertedSlots));
1475
- continue;
1476
- }
1477
- }
1478
- if (affectedSlots && propertyName === "invoke" && property && ts$1.isPropertyAssignment(property)) {
1479
- const invokeReplacements = createXStateV6InvokeSlotReplacements(targetDocument, targetSourceFile, property.initializer, nextValue, affectedSlots);
1480
- if (invokeReplacements) {
1481
- replacements.push(...invokeReplacements);
1482
- continue;
1483
- }
1484
- }
1485
- if (nextValue === void 0) {
1486
- if (!property) continue;
1487
- replacements.push(createObjectLiteralPropertyDeletion(targetDocument, targetSourceFile, stateObject, property));
1488
- continue;
1489
- }
1490
- if (property) {
1491
- replacements.push(createPropertyValueReplacement(targetDocument, targetSourceFile, property, nextValue));
1492
- continue;
1493
- }
1494
- insertionEntries.push({
1495
- key: propertyName,
1496
- config: nextValue
1497
- });
1498
- }
1499
- if (insertionEntries.length > 0) replacements.push(createObjectLiteralPropertiesInsertion(targetDocument, targetSourceFile, stateObject, insertionEntries));
1500
- return replacements.length > 0 ? replacements.sort(compareReplacementRangesDescending) : [];
1501
- }
1502
- function createXStateV6InvokeSlotReplacements(document, sourceFile, initializer, nextValue, affectedSlots) {
1503
- const expression = unwrapExpression$1(initializer);
1504
- const existingInvokes = ts$1.isArrayLiteralExpression(expression) ? expression.elements.filter(ts$1.isExpression) : [expression];
1505
- const nextInvokes = Array.isArray(nextValue) ? nextValue : [nextValue];
1506
- const replacements = [];
1507
- const insertions = /* @__PURE__ */ new Map();
1508
- for (const slotRef of affectedSlots) {
1509
- const match = /^@statelyai\.invoke\.(done|error|snapshot|timeout)\.(.+)$/.exec(slotRef);
1510
- if (!match) return null;
1511
- const propertyName = {
1512
- done: "onDone",
1513
- error: "onError",
1514
- snapshot: "onSnapshot",
1515
- timeout: "onTimeout"
1516
- }[match[1]];
1517
- const invokeId = match[2];
1518
- const invokeIndex = findXStateV6InvokeIndex(nextInvokes, invokeId);
1519
- const existingInvoke = existingInvokes[invokeIndex];
1520
- const nextInvoke = nextInvokes[invokeIndex];
1521
- if (invokeIndex < 0 || !existingInvoke || !nextInvoke || !isMachineConfig(nextInvoke)) return null;
1522
- const existingObject = unwrapObjectLiteralExpression(existingInvoke);
1523
- if (!existingObject) return null;
1524
- const existingProperty = findObjectLiteralProperty(existingObject, propertyName);
1525
- const nextSlotValue = nextInvoke[propertyName];
1526
- if (nextSlotValue === void 0) {
1527
- if (existingProperty) replacements.push(createObjectLiteralPropertyDeletion(document, sourceFile, existingObject, existingProperty));
1528
- } else if (existingProperty) replacements.push(createPropertyValueReplacement(document, sourceFile, existingProperty, nextSlotValue));
1529
- else {
1530
- const entries = insertions.get(existingObject) ?? [];
1531
- entries.push({
1532
- key: propertyName,
1533
- config: nextSlotValue
1534
- });
1535
- insertions.set(existingObject, entries);
1536
- }
1537
- }
1538
- for (const [existingObject, entries] of insertions) replacements.push(createObjectLiteralPropertiesInsertion(document, sourceFile, existingObject, entries));
1539
- return replacements;
1540
- }
1541
- function findXStateV6InvokeIndex(invokes, invokeId) {
1542
- return invokes.findIndex((candidate, index) => {
1543
- if (!isMachineConfig(candidate)) return false;
1544
- if (candidate.id === invokeId) return true;
1545
- if (candidate.id !== void 0) return false;
1546
- if (invokeId === `$auto-inline-${index}`) return true;
1547
- return typeof candidate.src === "string" && invokeId === `$auto-invoke-${candidate.src}`;
1548
- });
1549
- }
1550
- function getXStateV6PropertyValue(propertyName, value) {
1551
- const converted = toXStateV6MachineConfig({ [propertyName]: value });
1552
- return isMachineConfig(converted) ? converted[propertyName] : value;
1553
- }
1554
- function getTransitionPatchTarget(patch, prevGraph, nextGraph) {
1555
- const patchRecord = patch;
1556
- if (patch.op === "createTransition") {
1557
- const edge = getCreatedTransitionEdge(patch, prevGraph, nextGraph);
1558
- if (!edge) return null;
1559
- const sourcePath = resolveStatePath(nextGraph, patch.sourceId);
1560
- const eventType = edge?.data?.eventType ?? edge?.label ?? patchRecord.eventType;
1561
- if (!sourcePath || !eventType) return null;
1562
- return {
1563
- sourcePath,
1564
- eventType,
1565
- previousEventType: eventType,
1566
- transitionId: edge.id,
1567
- index: getTransitionIndexFromId(edge.id)
1568
- };
1569
- }
1570
- const edgeId = patch.op === "updateTransition" || patch.op === "deleteTransition" ? patch.transitionId : patch.op === "setGuard" || patch.op === "deleteGuard" ? patch.edgeId : patch.op === "createAction" || patch.op === "updateAction" || patch.op === "deleteAction" ? "edgeId" in patch.location ? patch.location.edgeId : null : null;
1571
- if (!edgeId) return null;
1572
- const nextEdge = nextGraph.edges.find((item) => item.id === edgeId);
1573
- const prevEdge = prevGraph.edges.find((item) => item.id === edgeId);
1574
- const sourcePath = resolveEdgeSourcePath(nextGraph, edgeId) ?? resolveEdgeSourcePath(prevGraph, edgeId);
1575
- const eventType = nextEdge?.data?.eventType ?? nextEdge?.label ?? patchRecord.eventType ?? prevEdge?.data?.eventType ?? prevEdge?.label;
1576
- const previousEventType = prevEdge?.data?.eventType ?? prevEdge?.label ?? eventType;
1577
- if (!sourcePath || !eventType || !previousEventType) return null;
1578
- return {
1579
- sourcePath,
1580
- eventType,
1581
- previousEventType,
1582
- transitionId: edgeId,
1583
- index: getTransitionIndexFromId(edgeId)
1584
- };
1585
- }
1586
- function isXStateV6Source(sourceLocations) {
1587
- return sourceLocations?.profile === "xstate-v6-alpha" || sourceLocations?.profileRef?.startsWith("@statelyai/xstate@6") === true;
1588
- }
1589
- function getV6TransitionPropertyTargets(patch, prevGraph, nextGraph) {
1590
- const edgeId = getTransitionPatchEdgeId(patch, prevGraph, nextGraph);
1591
- if (!edgeId) return [];
1592
- const candidates = [{
1593
- edge: prevGraph.edges.find((edge) => edge.id === edgeId),
1594
- graph: prevGraph
1595
- }, {
1596
- edge: nextGraph.edges.find((edge) => edge.id === edgeId),
1597
- graph: nextGraph
1598
- }];
1599
- const targets = /* @__PURE__ */ new Map();
1600
- for (const { edge, graph } of candidates) {
1601
- if (!edge || edge.data?.route) continue;
1602
- const path = resolveStatePath(graph, edge.sourceId);
1603
- if (!path) continue;
1604
- const eventType = edge.data?.eventType ?? edge.label ?? "";
1605
- const sourceNode = graph.nodes.find((node) => node.id === edge.sourceId);
1606
- let propertyName;
1607
- let slotKey = null;
1608
- if (eventType === "") propertyName = sourceNode?.data.type === "choice" ? "choice" : "always";
1609
- else if (eventType.startsWith("xstate.after.")) {
1610
- propertyName = "after";
1611
- slotKey = getDelayKeyFromEventType(eventType, edge.sourceId);
1612
- } else if (eventType.startsWith("@statelyai.invoke.")) {
1613
- propertyName = "invoke";
1614
- slotKey = eventType;
1615
- } else if (eventType.startsWith("@statelyai.state.done.")) propertyName = "onDone";
1616
- else if (eventType.startsWith("@statelyai.state.error.")) propertyName = "onError";
1617
- else if (eventType.startsWith("@statelyai.state.timeout.")) propertyName = "onTimeout";
1618
- else {
1619
- propertyName = "on";
1620
- slotKey = eventType;
1621
- }
1622
- targets.set(`${path.join(".")}:${propertyName}:${slotKey ?? ""}`, {
1623
- path,
1624
- propertyName,
1625
- slotKey
1626
- });
1627
- }
1628
- return [...targets.values()];
1629
- }
1630
- function getCreatedTransitionEdge(patch, prevGraph, nextGraph) {
1631
- const previousIds = new Set(prevGraph.edges.map((edge) => edge.id));
1632
- let candidates = nextGraph.edges.filter((edge) => !previousIds.has(edge.id) && edge.sourceId === patch.sourceId);
1633
- const createdWithRequestedId = patch.id ? candidates.find((edge) => edge.id === patch.id) : void 0;
1634
- if (createdWithRequestedId) return createdWithRequestedId;
1635
- if (patch.eventType !== void 0) candidates = candidates.filter((edge) => (edge.data?.eventType ?? edge.label) === patch.eventType);
1636
- if (patch.targetId !== void 0) candidates = candidates.filter((edge) => edge.targetId === patch.targetId);
1637
- if (patch.transitionType !== void 0) candidates = candidates.filter((edge) => edge.data?.transitionType === patch.transitionType);
1638
- if (patch.matches !== void 0) candidates = candidates.filter((edge) => JSON.stringify(edge.data?.matches) === JSON.stringify(patch.matches));
1639
- return candidates.length === 1 ? candidates[0] : null;
1640
- }
1641
- function getTransitionPatchEdgeId(patch, prevGraph, nextGraph) {
1642
- if (patch.op === "createTransition") return getCreatedTransitionEdge(patch, prevGraph, nextGraph)?.id ?? null;
1643
- if (patch.op === "updateTransition" || patch.op === "deleteTransition") return patch.transitionId;
1644
- if (patch.op === "setGuard" || patch.op === "deleteGuard") return patch.edgeId;
1645
- if ((patch.op === "createAction" || patch.op === "updateAction" || patch.op === "deleteAction") && "edgeId" in patch.location) return patch.location.edgeId;
1646
- return null;
1647
- }
1648
- function getStatePropertyPatchTargets(patch, prevGraph, nextGraph) {
1649
- if (patch.op === "updateSchemas") return [{
1650
- path: [],
1651
- propertyName: "schemas"
1652
- }];
1653
- if (patch.op === "updateState") {
1654
- const propertyNames = getStatePropertyNamesFromUpdatePatch(patch);
1655
- if (propertyNames.length === 0) return [];
1656
- const path = resolveStatePath(nextGraph, patch.stateId) ?? resolveStatePath(prevGraph, patch.stateId);
1657
- return path ? propertyNames.map((propertyName) => ({
1658
- path,
1659
- propertyName
1660
- })) : [];
1661
- }
1662
- if (patch.op === "createAction" || patch.op === "updateAction" || patch.op === "deleteAction") {
1663
- if (!("nodeId" in patch.location)) return [];
1664
- const path = resolveStatePath(nextGraph, patch.location.nodeId) ?? resolveStatePath(prevGraph, patch.location.nodeId);
1665
- return path ? [{
1666
- path,
1667
- propertyName: patch.location.group
1668
- }] : [];
1669
- }
1670
- if (patch.op === "createInvoke" || patch.op === "updateInvoke" || patch.op === "deleteInvoke") {
1671
- const path = resolveStatePath(nextGraph, patch.nodeId) ?? resolveStatePath(prevGraph, patch.nodeId);
1672
- return path ? [{
1673
- path,
1674
- propertyName: "invoke"
1675
- }] : [];
1676
- }
1677
- if (patch.op === "createTag" || patch.op === "deleteTag") {
1678
- const path = resolveStatePath(nextGraph, patch.nodeId) ?? resolveStatePath(prevGraph, patch.nodeId);
1679
- return path ? [{
1680
- path,
1681
- propertyName: "tags"
1682
- }] : [];
1683
- }
1684
- return [];
1685
- }
1686
- function getStatePropertyNamesFromUpdatePatch(patch) {
1687
- if (patch.op !== "updateState") return [];
1688
- const patchRecord = patch;
1689
- const propertyNames = [];
1690
- if (patchRecord.stateDescription !== void 0) propertyNames.push("description");
1691
- if (patchRecord.meta !== void 0) propertyNames.push("meta");
1692
- if (patchRecord.type !== void 0) propertyNames.push("type");
1693
- if (patchRecord.history !== void 0) propertyNames.push("history");
1694
- if (patchRecord.initialId !== void 0 || patchRecord.initialInput !== void 0) propertyNames.push("initial");
1695
- if (patchRecord.timeout !== void 0) propertyNames.push("timeout");
1696
- if (patchRecord.route !== void 0) propertyNames.push("route");
1697
- return propertyNames;
1698
- }
1699
- function getTransitionConfigValue(machineConfig, sourcePath, eventType, index) {
1700
- const sourceConfig = getStateConfigByPath(machineConfig, sourcePath);
1701
- const eventConfig = (isMachineConfig(sourceConfig?.on) ? sourceConfig.on : null)?.[eventType];
1702
- if (Array.isArray(eventConfig) && index !== null) return eventConfig[index];
1703
- return eventConfig;
1704
- }
1705
- function getTransitionSourceExpression(stateObject, eventType, index) {
1706
- const onObject = getObjectLiteralProperty(stateObject, "on");
1707
- if (!onObject) return null;
1708
- const eventProperty = findObjectLiteralProperty(onObject, eventType);
1709
- if (!eventProperty) return null;
1710
- if (!ts$1.isPropertyAssignment(eventProperty)) return {
1711
- onObject,
1712
- eventProperty
1713
- };
1714
- const initializer = unwrapExpression$1(eventProperty.initializer);
1715
- if (ts$1.isArrayLiteralExpression(initializer) && index !== null) {
1716
- const element = initializer.elements[index];
1717
- if (element && ts$1.isExpression(element)) return {
1718
- onObject,
1719
- eventProperty,
1720
- array: initializer,
1721
- element
1722
- };
1723
- }
1724
- return {
1725
- onObject,
1726
- eventProperty
1727
- };
1728
- }
1729
- function getTransitionIndexFromId(id) {
1730
- const match = id.match(/\[(\d+)\](?:$|#)/);
1731
- return match ? Number(match[1]) : null;
1732
- }
1733
- function createArrayElementDeletion(document, sourceFile, arrayLiteral, element) {
1734
- const range = getArrayElementDeletionRange(sourceFile, arrayLiteral, element);
1735
- return createOffsetReplacement(document, range.start, range.end, "");
1736
- }
1737
- function createExpressionReplacement(document, sourceFile, expression, nextValue) {
1738
- const formatting = getFormattingContextForExpression(document, sourceFile, expression);
1739
- const printed = containsRawCodeLike(nextValue) ? reindentPrintedExpression(serializeJS(nextValue), formatting) : printExpression(valueToExpression(nextValue, unwrapExpression$1(expression)), sourceFile, formatting);
1740
- return createOffsetReplacement(document, expression.getStart(sourceFile), expression.getEnd(), preserveExpressionComments(expression, sourceFile, printed, formatting));
1741
- }
1742
- function preserveExpressionComments(expression, sourceFile, printed, formatting) {
1743
- const original = sourceFile.text.slice(expression.getStart(sourceFile), expression.getEnd());
1744
- const scanner = ts$1.createScanner(ts$1.ScriptTarget.Latest, false, ts$1.LanguageVariant.JSX, original);
1745
- const comments = [];
1746
- for (let token = scanner.scan(); token !== ts$1.SyntaxKind.EndOfFileToken; token = scanner.scan()) if (token === ts$1.SyntaxKind.SingleLineCommentTrivia || token === ts$1.SyntaxKind.MultiLineCommentTrivia) comments.push(scanner.getTokenText());
1747
- const missing = comments.filter((comment) => !printed.includes(comment));
1748
- if (missing.length === 0) return printed;
1749
- const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
1750
- const bodyStart = printed.indexOf("=> {");
1751
- if (bodyStart >= 0) {
1752
- const insertion = bodyStart + 4;
1753
- const indent = `${formatting.baseIndent}${formatting.indentUnit}`;
1754
- return `${printed.slice(0, insertion)}${lineSeparator}${missing.map((comment) => `${indent}${comment}`).join(lineSeparator)}${printed.slice(insertion)}`;
1755
- }
1756
- return `${missing.join(lineSeparator)}${lineSeparator}${formatting.baseIndent}${printed}`;
1757
- }
1758
- function createPropertyValueReplacement(document, sourceFile, property, nextValue) {
1759
- if (!ts$1.isPropertyAssignment(property)) return createPropertyAssignmentReplacement(document, sourceFile, property, getStatePropertyKeyText(property) ?? "value", nextValue);
1760
- return createExpressionReplacement(document, sourceFile, property.initializer, nextValue);
1761
- }
1762
- function createPropertyAssignmentReplacement(document, sourceFile, property, key, nextValue) {
1763
- const text = printObjectLiteralProperty(key, nextValue, sourceFile, getFormattingContextForExpression(document, sourceFile, property));
1764
- return createOffsetReplacement(document, property.getStart(sourceFile), property.getEnd(), text);
1765
- }
1766
- function createObjectLiteralPropertyInsertion(document, sourceFile, objectLiteral, key, nextValue) {
1767
- const propertyText = objectPropertyTextForInsertion(objectLiteral, printObjectLiteralProperty(key, nextValue, sourceFile, getFormattingContext(document, sourceFile, objectLiteral)));
1768
- return createObjectPropertyInsertionReplacements(document, objectLiteral, getObjectLiteralPropertyInsertionOffset(sourceFile, objectLiteral), propertyText);
1769
- }
1770
- function getObjectLiteralPropertyInsertionOffset(sourceFile, objectLiteral) {
1771
- const propertiesEnd = objectLiteral.properties.end;
1772
- const objectEnd = objectLiteral.getEnd() - 1;
1773
- const trailingTrivia = sourceFile.text.slice(propertiesEnd, objectEnd);
1774
- const commentMatch = /^[ \t]*(\/\/|\/\*)/.exec(trailingTrivia);
1775
- if (!commentMatch) return propertiesEnd;
1776
- const commentStart = propertiesEnd + commentMatch.index + commentMatch[0].length - 2;
1777
- if (commentMatch[1] === "//") {
1778
- const lineFeed = sourceFile.text.indexOf("\n", commentStart);
1779
- const lineEnd = lineFeed === -1 ? objectEnd : Math.min(lineFeed, objectEnd);
1780
- return lineEnd > commentStart && sourceFile.text.charCodeAt(lineEnd - 1) === 13 ? lineEnd - 1 : lineEnd;
1781
- }
1782
- const commentEnd = sourceFile.text.indexOf("*/", commentStart + 2);
1783
- return commentEnd === -1 ? propertiesEnd : Math.min(commentEnd + 2, objectEnd);
1784
- }
1785
- function createObjectPropertyInsertionReplacements(document, objectLiteral, insertionOffset, propertyText) {
1786
- const propertiesEnd = objectLiteral.properties.end;
1787
- const needsComma = objectLiteral.properties.length > 0 && !objectLiteral.properties.hasTrailingComma;
1788
- const replacements = [createOffsetReplacement(document, insertionOffset, insertionOffset, `${needsComma && insertionOffset === propertiesEnd ? "," : ""}${propertyText}`)];
1789
- if (needsComma && insertionOffset !== propertiesEnd) replacements.push(createOffsetReplacement(document, propertiesEnd, propertiesEnd, ","));
1790
- return replacements;
1791
- }
1792
- function getArrayElementDeletionRange(sourceFile, arrayLiteral, element) {
1793
- const elements = [...arrayLiteral.elements];
1794
- const elementIndex = elements.indexOf(element);
1795
- const elementStart = element.getFullStart();
1796
- const elementEnd = element.getEnd();
1797
- if (elements.length === 1) return {
1798
- start: elementStart,
1799
- end: elementEnd
1800
- };
1801
- if (elementIndex === elements.length - 1) {
1802
- const previousElement = elements[elementIndex - 1];
1803
- const commaOffset = sourceFile.text.lastIndexOf(",", elementStart - 1);
1804
- return {
1805
- start: commaOffset >= previousElement.getEnd() && commaOffset < elementStart ? commaOffset : elementStart,
1806
- end: elementEnd
1807
- };
1808
- }
1809
- const nextElement = elements[elementIndex + 1];
1810
- const commaOffset = sourceFile.text.indexOf(",", elementEnd);
1811
- return {
1812
- start: elementStart,
1813
- end: commaOffset >= elementEnd && commaOffset < nextElement.getFullStart() ? commaOffset + 1 : elementEnd
1814
- };
1815
- }
1816
- function tryCreateImplementationPatchSplit(document, sourceFile, patches, nextGraph, machineIndex = 0) {
1817
- const replacements = [];
1818
- const remainingPatches = [];
1819
- for (const patch of patches) {
1820
- if (!isImplementationPatch(patch)) {
1821
- remainingPatches.push(patch);
1822
- continue;
1823
- }
1824
- const patchReplacements = createImplementationPatchReplacements(document, sourceFile, patch, nextGraph, machineIndex);
1825
- if (!patchReplacements) {
1826
- remainingPatches.push(patch);
1827
- continue;
1828
- }
1829
- replacements.push(...patchReplacements);
1830
- }
1831
- return replacements.length > 0 ? {
1832
- replacements: replacements.sort(compareReplacementRangesDescending),
1833
- remainingPatches
1834
- } : null;
1835
- }
1836
- function isImplementationPatch(patch) {
1837
- return patch.op === "createImplementation" || patch.op === "updateImplementation" || patch.op === "deleteImplementation";
1838
- }
1839
- function createImplementationPatchReplacements(document, sourceFile, patch, nextGraph, machineIndex) {
1840
- const createMachineCall = findCreateMachineCall(sourceFile, machineIndex);
1841
- if (!createMachineCall) return null;
1842
- const implementationRoot = findImplementationObjectLiteralForMachine(sourceFile, createMachineCall);
1843
- const categoryName = implementationSourceTypeToCategoryName(patch.sourceType);
1844
- const categoryObject = implementationRoot ? getObjectLiteralProperty(implementationRoot, categoryName) : null;
1845
- if (patch.op === "createImplementation") {
1846
- const implementation = getGraphImplementation(nextGraph, patch.sourceType, patch.implementation.id) ?? patch.implementation;
1847
- if (!implementationRoot) return createMachineCall.arguments.length < 2 && !isObjectOfProvideCall(createMachineCall) ? createProvideCreateReplacements(document, sourceFile, createMachineCall, categoryName, implementation) : null;
1848
- return createImplementationCreateReplacements(document, sourceFile, implementationRoot, categoryName, implementation);
1849
- }
1850
- if (!implementationRoot || !categoryObject) return null;
1851
- const implementationProperty = findObjectLiteralProperty(categoryObject, patch.implementationId);
1852
- if (!implementationProperty) return null;
1853
- if (patch.op === "deleteImplementation") {
1854
- const deletionRange = getObjectLiteralPropertyDeletionRange(sourceFile, categoryObject, implementationProperty);
1855
- return [createOffsetReplacement(document, deletionRange.start, deletionRange.end, "")];
1856
- }
1857
- const nextImplementation = getGraphImplementation(nextGraph, patch.sourceType, patch.implementationId);
1858
- const nextName = patch.data.name ?? nextImplementation?.name;
1859
- const nextCode = patch.data.code ?? nextImplementation?.code?.body;
1860
- const replacements = [];
1861
- if (nextName && nextName !== patch.implementationId) {
1862
- const nameNode = getObjectLiteralElementName(implementationProperty);
1863
- if (!nameNode) return null;
1864
- replacements.push(createOffsetReplacement(document, nameNode.getStart(sourceFile), nameNode.getEnd(), propertyNameTextForSource(nextName)));
1865
- }
1866
- if (nextCode !== void 0) {
1867
- if (!ts$1.isPropertyAssignment(implementationProperty)) return null;
1868
- replacements.push(createOffsetReplacement(document, implementationProperty.initializer.getStart(sourceFile), implementationProperty.initializer.getEnd(), nextCode));
1869
- }
1870
- return replacements.length > 0 ? replacements : null;
1871
- }
1872
- function createProvideCreateReplacements(document, sourceFile, createMachineCall, categoryName, implementation) {
1873
- const implementationCode = implementation.code?.body;
1874
- if (!implementation.id || !implementationCode) return null;
1875
- const lineBreak = getLineBreak(sourceFile);
1876
- const baseIndent = getLineIndent(sourceFile.text, createMachineCall.getStart(sourceFile));
1877
- const propertyIndent = `${baseIndent} `;
1878
- const nestedIndent = `${baseIndent} `;
1879
- const text = `.provide({${lineBreak}${propertyIndent}${propertyNameTextForSource(categoryName)}: {${lineBreak}${nestedIndent}${propertyNameTextForSource(implementation.id)}: ${implementationCode},${lineBreak}${propertyIndent}},${lineBreak}${baseIndent}})`;
1880
- return [createOffsetReplacement(document, createMachineCall.getEnd(), createMachineCall.getEnd(), text)];
1881
- }
1882
- function createImplementationCreateReplacements(document, sourceFile, implementationRoot, categoryName, implementation) {
1883
- const implementationCode = implementation.code?.body;
1884
- if (!implementation.id || !implementationCode) return null;
1885
- const categoryObject = getObjectLiteralProperty(implementationRoot, categoryName);
1886
- if (!categoryObject) {
1887
- const propertyText = objectPropertyTextForInsertion(implementationRoot, `${propertyNameTextForSource(categoryName)}: {\n${getIndentForNewObjectProperty(sourceFile, implementationRoot)}${propertyNameTextForSource(implementation.id)}: ${implementationCode},\n${getIndentForObjectClose(sourceFile, implementationRoot)}}`);
1888
- return createObjectPropertyInsertionReplacements(document, implementationRoot, getObjectLiteralPropertyInsertionOffset(sourceFile, implementationRoot), propertyText);
1889
- }
1890
- const propertyText = objectPropertyTextForInsertion(categoryObject, `${propertyNameTextForSource(implementation.id)}: ${implementationCode}`);
1891
- return createObjectPropertyInsertionReplacements(document, categoryObject, getObjectLiteralPropertyInsertionOffset(sourceFile, categoryObject), propertyText);
1892
- }
1893
- function objectPropertyTextForInsertion(objectLiteral, propertyText) {
1894
- const lineBreak = getLineBreak(objectLiteral.getSourceFile());
1895
- const indent = getIndentForNewObjectProperty(objectLiteral.getSourceFile(), objectLiteral);
1896
- return `${lineBreak}${indent}${propertyText.startsWith(indent) ? propertyText.slice(indent.length) : propertyText}`;
1897
- }
1898
- function getLineBreak(sourceFile) {
1899
- return sourceFile.text.includes("\r\n") ? "\r\n" : "\n";
1900
- }
1901
- function getLineIndent(sourceText, offset) {
1902
- const lineStart = getLineStartOffset(sourceText, offset);
1903
- return sourceText.slice(lineStart, offset).match(/^[ \t]*/)?.[0] ?? "";
1904
- }
1905
- function getIndentForNewObjectProperty(sourceFile, objectLiteral) {
1906
- const closeIndent = getIndentForObjectClose(sourceFile, objectLiteral);
1907
- const existingProperty = objectLiteral.properties[0];
1908
- if (existingProperty) {
1909
- const propertyLineStart = getLineStartOffset(sourceFile.text, existingProperty.getStart(sourceFile));
1910
- return sourceFile.text.slice(propertyLineStart, existingProperty.getStart(sourceFile)).match(/^[ \t]*/)?.[0] ?? `${closeIndent} `;
1911
- }
1912
- return `${closeIndent} `;
1913
- }
1914
- function getIndentForObjectClose(sourceFile, objectLiteral) {
1915
- const objectStart = objectLiteral.getStart(sourceFile);
1916
- const lineStart = getLineStartOffset(sourceFile.text, objectStart);
1917
- return sourceFile.text.slice(lineStart, objectStart).match(/^[ \t]*/)?.[0] ?? "";
1918
- }
1919
- function createOffsetReplacement(document, startOffset, endOffset, newText) {
1920
- const start = document.positionAt(startOffset);
1921
- const end = document.positionAt(endOffset);
1922
- return {
1923
- uri: getDocumentUri(document),
1924
- range: {
1925
- startLine: start.line,
1926
- startChar: start.character,
1927
- endLine: end.line,
1928
- endChar: end.character
1929
- },
1930
- newText
1931
- };
1932
- }
1933
- function propertyNameTextForSource(name) {
1934
- return isIdentifierText(name) ? name : JSON.stringify(name);
1935
- }
1936
- function getGraphImplementation(graph, sourceType, implementationId) {
1937
- if (!implementationId) return;
1938
- return graph.data?.implementations?.[implementationSourceTypeToCategoryName(sourceType)]?.find((implementation) => implementation.id === implementationId);
1939
- }
1940
- function implementationSourceTypeToCategoryName(sourceType) {
1941
- switch (sourceType) {
1942
- case "action": return "actions";
1943
- case "guard": return "guards";
1944
- case "actor": return "actors";
1945
- case "delay": return "delays";
1946
- }
1947
- }
1948
- function tryCreateStateMembershipPatchSplit(document, sourceFile, machineConfigNode, machineConfig, patches, prevGraph, nextGraph, sourceLocations, allowDisjointDescendantReplacements = false) {
1949
- const split = splitStateMembershipPatches(patches, prevGraph, nextGraph, sourceLocations, allowDisjointDescendantReplacements);
1950
- if (!split) return null;
1951
- const replacements = createStateMembershipReplacements(document, sourceFile, machineConfigNode, machineConfig, split.changes, sourceLocations);
1952
- if (!replacements) return null;
1953
- return {
1954
- replacements,
1955
- remainingPatches: split.remainingPatches
1956
- };
1957
- }
1958
- async function tryCreateStateMembershipPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) {
1959
- const split = splitStateMembershipPatches(patches, prevGraph, nextGraph, sourceLocations, true);
1960
- if (!split) return null;
1961
- const replacements = await createStateMembershipReplacementsForDocuments(document, sourceFile, machineConfigNode, machineConfig, split.changes, sourceLocations, openTextDocument);
1962
- if (!replacements) return null;
1963
- return {
1964
- replacements,
1965
- remainingPatches: split.remainingPatches
1966
- };
1967
- }
1968
- function splitStateMembershipPatches(patches, prevGraph, nextGraph, sourceLocations, allowDisjointDescendantReplacements) {
1969
- const createdById = /* @__PURE__ */ new Map();
1970
- const changesByParent = /* @__PURE__ */ new Map();
1971
- const remainingPatches = [];
1972
- const getChange = (parentPath) => {
1973
- const key = parentPath.join(".");
1974
- const existing = changesByParent.get(key);
1975
- if (existing) return existing;
1976
- const change = {
1977
- parentPath,
1978
- createdPaths: [],
1979
- deletedPaths: [],
1980
- patches: []
1981
- };
1982
- changesByParent.set(key, change);
1983
- return change;
1984
- };
1985
- for (const patch of patches) switch (patch.op) {
1986
- case "createState": {
1987
- if (!patch.id) {
1988
- remainingPatches.push(patch);
1989
- break;
1990
- }
1991
- const parentPath = resolveStatePath(nextGraph, patch.parentId);
1992
- const nextPath = resolveStatePath(nextGraph, patch.id);
1993
- if (!parentPath || !nextPath || nextPath.length === 0) {
1994
- remainingPatches.push(patch);
1995
- break;
1996
- }
1997
- const change = getChange(parentPath);
1998
- createdById.set(patch.id, {
1999
- parentPath,
2000
- path: nextPath
2001
- });
2002
- change.createdPaths.push(nextPath);
2003
- change.patches.push(patch);
2004
- break;
2005
- }
2006
- case "updateState": {
2007
- const created = createdById.get(patch.stateId);
2008
- const nextPath = resolveStatePath(nextGraph, patch.stateId);
2009
- if (created && nextPath && arePathsEqual(created.path, nextPath)) {
2010
- getChange(created.parentPath).patches.push(patch);
2011
- break;
2012
- }
2013
- remainingPatches.push(patch);
2014
- break;
2015
- }
2016
- case "deleteState": {
2017
- const prevPath = resolveStatePath(prevGraph, patch.stateId);
2018
- if (!prevPath || prevPath.length === 0) {
2019
- remainingPatches.push(patch);
2020
- break;
2021
- }
2022
- const change = getChange(prevPath.slice(0, -1));
2023
- change.deletedPaths.push(prevPath);
2024
- change.patches.push(patch);
2025
- break;
2026
- }
2027
- default: remainingPatches.push(patch);
2028
- }
2029
- const deletedPaths = [...changesByParent.values()].flatMap((change) => change.deletedPaths);
2030
- const createdPaths = [...changesByParent.values()].flatMap((change) => change.createdPaths);
2031
- const remainingPatchesWithSurvivingOwners = remainingPatches.filter((patch) => {
2032
- const owner = resolvePatchOwner(patch, prevGraph, nextGraph);
2033
- return owner.type !== "covered" && !isPatchOwnerCoveredByPaths(owner, deletedPaths) && !isPatchOwnerCoveredByPaths(owner, createdPaths);
2034
- });
2035
- const split = coalesceMembershipChangesWithRemainingPatches([...changesByParent.values()].filter((change) => !createdPaths.some((path) => isPathEqualOrDescendant(change.parentPath, path))), remainingPatchesWithSurvivingOwners, prevGraph, nextGraph, sourceLocations, allowDisjointDescendantReplacements);
2036
- return split.changes.length > 0 ? split : null;
2037
- }
2038
- function isPatchOwnerCoveredByPaths(owner, paths) {
2039
- if (owner.type !== "state" || paths.length === 0) return false;
2040
- return paths.some((path) => isPathEqualOrDescendant(owner.path, path));
2041
- }
2042
- function coalesceMembershipChangesWithRemainingPatches(changes, remainingPatches, prevGraph, nextGraph, sourceLocations, allowDisjointDescendantReplacements) {
2043
- if (remainingPatches.length === 0) return {
2044
- changes,
2045
- remainingPatches
2046
- };
2047
- const remainingPlan = deriveReplacementPlan(remainingPatches, prevGraph, nextGraph);
2048
- const activeChanges = [];
2049
- const activeRemainingPatches = [...remainingPatches];
2050
- for (const change of changes) {
2051
- if (shouldCoalesceMembershipChangeWithRemainingPlan(change, remainingPlan, sourceLocations, allowDisjointDescendantReplacements)) {
2052
- activeRemainingPatches.push(...change.patches);
2053
- continue;
2054
- }
2055
- activeChanges.push(change);
2056
- }
2057
- return {
2058
- changes: activeChanges,
2059
- remainingPatches: activeRemainingPatches
2060
- };
2061
- }
2062
- function shouldCoalesceMembershipChangeWithRemainingPlan(change, remainingPlan, sourceLocations, allowDisjointDescendantReplacements) {
2063
- if (change.parentPath.length === 0 && wouldDeModularizeRootReplacement(sourceLocations)) return false;
2064
- if (remainingPlan.type === "root") return true;
2065
- return remainingPlan.paths.some((path) => isPathEqualOrDescendant(change.parentPath, path) || !allowDisjointDescendantReplacements && isPathEqualOrDescendant(path, change.parentPath));
2066
- }
2067
- function isPathEqualOrDescendant(path, candidateParentPath) {
2068
- return candidateParentPath.every((segment, index) => path[index] === segment);
2069
- }
2070
- function createStateMembershipReplacements(document, sourceFile, machineConfigNode, machineConfig, changes, sourceLocations) {
2071
- const replacements = [];
2072
- for (const change of changes) {
2073
- const target = getStateMembershipParentTarget(document, sourceFile, machineConfigNode, sourceLocations, change.parentPath, getStateObjectLiteralByPath);
2074
- if (!target) return null;
2075
- const changeReplacements = createStateMembershipReplacementsForTarget(target.document, target.sourceFile, target.node, machineConfig, change, target.nodeKind);
2076
- if (!changeReplacements) return null;
2077
- replacements.push(...changeReplacements);
2078
- replacements.push(...createStateMembershipInitialReplacements(change.parentPath.length === 0 ? document : target.document, change.parentPath.length === 0 ? sourceFile : target.sourceFile, change.parentPath.length === 0 ? machineConfigNode : target.node, machineConfig, change));
2079
- }
2080
- return replacements.sort(compareReplacementRangesDescending);
2081
- }
2082
- async function createStateMembershipReplacementsForDocuments(document, sourceFile, machineConfigNode, machineConfig, changes, sourceLocations, openTextDocument) {
2083
- const replacements = [];
2084
- for (const change of changes) {
2085
- const target = await getStateMembershipParentTargetForDocuments(document, sourceFile, machineConfigNode, sourceLocations, change.parentPath, openTextDocument, getStateObjectLiteralByPath);
2086
- if (!target) return null;
2087
- const changeReplacements = createStateMembershipReplacementsForTarget(target.document, target.sourceFile, target.node, machineConfig, change, target.nodeKind);
2088
- if (!changeReplacements) return null;
2089
- replacements.push(...changeReplacements);
2090
- replacements.push(...createStateMembershipInitialReplacements(change.parentPath.length === 0 ? document : target.document, change.parentPath.length === 0 ? sourceFile : target.sourceFile, change.parentPath.length === 0 ? machineConfigNode : target.node, machineConfig, change));
2091
- }
2092
- return replacements.sort(compareReplacementRangesDescending);
2093
- }
2094
- function createStateMembershipReplacementsForTarget(document, sourceFile, parentObject, machineConfig, change, nodeKind = "machineConfig") {
2095
- const statesObject = nodeKind === "statesObject" ? parentObject : getObjectLiteralProperty(parentObject, "states");
2096
- if (!statesObject) return null;
2097
- const stateEntries = [];
2098
- for (const path of change.createdPaths) {
2099
- const key = path[path.length - 1];
2100
- const stateConfig = getStateConfigByPath(machineConfig, path);
2101
- if (!key || !isMachineConfig(stateConfig)) return null;
2102
- stateEntries.push({
2103
- key,
2104
- config: stateConfig
2105
- });
2106
- }
2107
- const deletionReplacements = [];
2108
- for (const path of change.deletedPaths) {
2109
- const key = path[path.length - 1];
2110
- const property = key ? findObjectLiteralProperty(statesObject, key) : null;
2111
- if (!property) return null;
2112
- deletionReplacements.push(createObjectLiteralPropertyDeletion(document, sourceFile, statesObject, property));
2113
- }
2114
- return [...stateEntries.length > 0 ? [createObjectLiteralPropertiesInsertion(document, sourceFile, statesObject, stateEntries)] : [], ...deletionReplacements].sort(compareReplacementRangesDescending);
2115
- }
2116
- function createStateMembershipInitialReplacements(document, sourceFile, parentObject, machineConfig, change) {
2117
- if (!change.patches.some((patch) => patch.op === "createState" && patch.initial === true || patch.op === "deleteState")) return [];
2118
- const parentConfig = getStateConfigByPath(machineConfig, change.parentPath);
2119
- if (!parentConfig) return [];
2120
- const nextInitial = parentConfig.initial;
2121
- const initialProperty = getPropertyAssignment(parentObject, "initial");
2122
- if (nextInitial === void 0) return initialProperty ? [createObjectLiteralPropertyDeletion(document, sourceFile, parentObject, initialProperty)] : [];
2123
- if (isMachineConfig(nextInitial)) {
2124
- if (!initialProperty) return [createObjectLiteralPropertiesInsertion(document, sourceFile, parentObject, [{
2125
- key: "initial",
2126
- config: nextInitial
2127
- }])];
2128
- const initializer = unwrapExpression$1(initialProperty.initializer);
2129
- const targetProperty = ts$1.isObjectLiteralExpression(initializer) ? getPropertyAssignment(initializer, "target") : null;
2130
- if (targetProperty && typeof nextInitial.target === "string") {
2131
- const targetInitializer = unwrapExpression$1(targetProperty.initializer);
2132
- if (ts$1.isStringLiteralLike(targetInitializer) && targetInitializer.text === nextInitial.target) return [];
2133
- return [createPropertyValueReplacement(document, sourceFile, targetProperty, nextInitial.target)];
2134
- }
2135
- return [createPropertyValueReplacement(document, sourceFile, initialProperty, nextInitial)];
2136
- }
2137
- if (typeof nextInitial !== "string") return [];
2138
- if (initialProperty) {
2139
- const initializer = unwrapExpression$1(initialProperty.initializer);
2140
- if (ts$1.isStringLiteralLike(initializer) && initializer.text === nextInitial) return [];
2141
- return [createPropertyValueReplacement(document, sourceFile, initialProperty, nextInitial)];
2142
- }
2143
- return [createObjectLiteralPropertiesInsertion(document, sourceFile, parentObject, [{
2144
- key: "initial",
2145
- config: nextInitial
2146
- }])];
2147
- }
2148
- function createObjectLiteralPropertiesInsertion(document, sourceFile, objectLiteral, entries) {
2149
- const formatting = getFormattingContext(document, sourceFile, objectLiteral);
2150
- const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
2151
- const propertyTexts = entries.map((entry) => printObjectLiteralProperty(entry.key, entry.config, sourceFile, formatting));
2152
- const existingProperties = objectLiteral.properties;
2153
- const closeBraceOffset = objectLiteral.getEnd() - 1;
2154
- const startOffset = existingProperties.length === 0 ? closeBraceOffset : existingProperties[existingProperties.length - 1].getEnd();
2155
- const start = document.positionAt(startOffset);
2156
- const end = document.positionAt(closeBraceOffset);
2157
- const prefix = existingProperties.length === 0 ? lineSeparator : `,${lineSeparator}`;
2158
- const suffix = `${lineSeparator}${formatting.baseIndent}`;
2159
- return {
2160
- uri: getDocumentUri(document),
2161
- range: {
2162
- startLine: start.line,
2163
- startChar: start.character,
2164
- endLine: end.line,
2165
- endChar: end.character
2166
- },
2167
- newText: `${prefix}${propertyTexts.join(`,${lineSeparator}`)}${suffix}`
2168
- };
2169
- }
2170
- function createObjectLiteralPropertyDeletion(document, sourceFile, objectLiteral, property) {
2171
- const range = getObjectLiteralPropertyDeletionRange(sourceFile, objectLiteral, property);
2172
- const start = document.positionAt(range.start);
2173
- const end = document.positionAt(range.end);
2174
- return {
2175
- uri: getDocumentUri(document),
2176
- range: {
2177
- startLine: start.line,
2178
- startChar: start.character,
2179
- endLine: end.line,
2180
- endChar: end.character
2181
- },
2182
- newText: ""
2183
- };
2184
- }
2185
- function getObjectLiteralPropertyDeletionRange(sourceFile, objectLiteral, property) {
2186
- const properties = [...objectLiteral.properties];
2187
- const propertyIndex = properties.indexOf(property);
2188
- const propertyStart = property.getFullStart();
2189
- const propertyEnd = property.getEnd();
2190
- if (properties.length === 1) return {
2191
- start: propertyStart,
2192
- end: objectLiteral.properties.hasTrailingComma ? objectLiteral.properties.end : propertyEnd
2193
- };
2194
- if (propertyIndex === properties.length - 1) {
2195
- const previousProperty = properties[propertyIndex - 1];
2196
- const commaOffset = sourceFile.text.lastIndexOf(",", propertyStart - 1);
2197
- return {
2198
- start: commaOffset >= previousProperty.getEnd() && commaOffset < propertyStart ? commaOffset : propertyStart,
2199
- end: propertyEnd
2200
- };
2201
- }
2202
- const nextProperty = properties[propertyIndex + 1];
2203
- const commaOffset = sourceFile.text.indexOf(",", propertyEnd);
2204
- return {
2205
- start: propertyStart,
2206
- end: commaOffset >= propertyEnd && commaOffset < nextProperty.getFullStart() ? commaOffset + 1 : propertyEnd
2207
- };
2208
- }
2209
- function findObjectLiteralProperty(objectLiteral, propertyName) {
2210
- for (const property of objectLiteral.properties) {
2211
- if (ts$1.isShorthandPropertyAssignment(property) && property.name.text === propertyName) return property;
2212
- if (ts$1.isPropertyAssignment(property)) {
2213
- if (getPropertyNameText$1(property.name) === propertyName) return property;
2214
- }
2215
- }
2216
- return null;
2217
- }
2218
- function findObjectLiteralPropertyByRange(sourceFile, objectLiteral, range) {
2219
- if (!range) return null;
2220
- const start = offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar);
2221
- const end = offsetAtRangePosition(sourceFile.text, range.endLine, range.endChar);
2222
- for (const property of objectLiteral.properties) {
2223
- const propertyName = getObjectLiteralElementName(property);
2224
- if (propertyName && propertyName.getStart(sourceFile) === start && propertyName.getEnd() === end) return property;
2225
- }
2226
- return null;
2227
- }
2228
- function getObjectLiteralElementName(property) {
2229
- if (ts$1.isPropertyAssignment(property) || ts$1.isShorthandPropertyAssignment(property) || ts$1.isMethodDeclaration(property) || ts$1.isGetAccessorDeclaration(property) || ts$1.isSetAccessorDeclaration(property)) return property.name;
2230
- return null;
2231
- }
2232
- function getStatePropertyKeyText(property) {
2233
- if (ts$1.isShorthandPropertyAssignment(property)) return property.name.text;
2234
- if (ts$1.isPropertyAssignment(property)) return getPropertyNameText$1(property.name);
2235
- return null;
2236
- }
2237
- function printObjectLiteralProperty(key, value, sourceFile, formatting) {
2238
- const objectValue = { [key]: value };
2239
- const objectText = containsRawCodeLike(value) ? reindentPrintedExpression(serializeJS(objectValue), formatting) : printExpression(valueToExpression(objectValue), sourceFile, formatting);
2240
- const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
2241
- const lines = objectText.split(/\r?\n/);
2242
- if (lines.length <= 2) return objectText.replace(/^\{\s*/, "").replace(/\s*\}$/, "");
2243
- return lines.slice(1, -1).join(lineSeparator);
2244
- }
2245
- function wouldDeModularizeRootReplacement(sourceLocations) {
2246
- const root = sourceLocations?.root;
2247
- return sourceLocations?.states.some((location) => location.kind !== "inline" || (root ? !isSourceLocationInsideRoot(location, root) : false)) ?? false;
2248
- }
2249
- function isSourceLocationInsideRoot(location, root) {
2250
- if (location.uri !== root.uri) return false;
2251
- const startsAfterRootStart = location.range.startLine > root.range.startLine || location.range.startLine === root.range.startLine && location.range.startChar >= root.range.startChar;
2252
- const endsBeforeRootEnd = location.range.endLine < root.range.endLine || location.range.endLine === root.range.endLine && location.range.endChar <= root.range.endChar;
2253
- return startsAfterRootStart && endsBeforeRootEnd;
2254
- }
2255
- function parseGraphPatches(value) {
2256
- if (!Array.isArray(value)) return null;
2257
- return value.filter(isGraphPatch);
2258
- }
2259
- function parseGraph(value) {
2260
- if (!value || typeof value !== "object") return null;
2261
- const candidate = value;
2262
- if (!Array.isArray(candidate.nodes) || !Array.isArray(candidate.edges)) return null;
2263
- return candidate;
2264
- }
2265
- function isGraphPatch(value) {
2266
- return Boolean(value && typeof value === "object" && "op" in value && typeof value.op === "string");
2267
- }
2268
- function isMachineConfig(value) {
2269
- return Boolean(value && typeof value === "object" && !Array.isArray(value));
2270
- }
2271
- function findMachineConfigObjectLiteral(sourceFile, machineIndex = 0) {
2272
- const firstArgument = findCreateMachineCall(sourceFile, machineIndex)?.arguments[0];
2273
- return firstArgument ? unwrapObjectLiteralExpression(firstArgument) : null;
2274
- }
2275
- function findCreateMachineCall(sourceFile, machineIndex = 0) {
2276
- let found = null;
2277
- let currentMachineIndex = 0;
2278
- const visit = (node) => {
2279
- if (found) return;
2280
- if (ts$1.isCallExpression(node)) {
2281
- const expression = node.expression;
2282
- if (isCreateMachineExpression$1(expression)) {
2283
- const isSelectedMachine = currentMachineIndex === machineIndex;
2284
- currentMachineIndex += 1;
2285
- if (!isSelectedMachine) return;
2286
- found = node;
2287
- return;
2288
- }
2289
- }
2290
- ts$1.forEachChild(node, visit);
2291
- };
2292
- visit(sourceFile);
2293
- return found;
2294
- }
2295
- function findImplementationObjectLiteralForMachine(sourceFile, createMachineCall) {
2296
- const setupObject = findSetupObjectLiteralForMachine(sourceFile, createMachineCall);
2297
- if (setupObject) return setupObject;
2298
- const secondArgument = createMachineCall.arguments[1];
2299
- if (secondArgument) {
2300
- const implementationObject = unwrapObjectLiteralExpression(secondArgument);
2301
- if (implementationObject) return implementationObject;
2302
- }
2303
- if (isObjectOfProvideCall(createMachineCall)) {
2304
- const provideCall = createMachineCall.parent.parent;
2305
- if (ts$1.isCallExpression(provideCall)) {
2306
- const firstArgument = provideCall.arguments[0];
2307
- return firstArgument ? unwrapObjectLiteralExpression(firstArgument) : null;
2308
- }
2309
- }
2310
- return null;
2311
- }
2312
- function findSetupObjectLiteralForMachine(sourceFile, createMachineCall) {
2313
- const expression = createMachineCall.expression;
2314
- if (!ts$1.isPropertyAccessExpression(expression)) return null;
2315
- const receiver = unwrapExpression$1(expression.expression);
2316
- if (ts$1.isCallExpression(receiver) && isSetupCallExpression(receiver)) {
2317
- const setupArgument = receiver.arguments[0];
2318
- return setupArgument ? unwrapObjectLiteralExpression(setupArgument) : null;
2319
- }
2320
- if (!ts$1.isIdentifier(receiver)) return null;
2321
- for (const statement of sourceFile.statements) {
2322
- if (!ts$1.isVariableStatement(statement)) continue;
2323
- for (const declaration of statement.declarationList.declarations) {
2324
- if (!ts$1.isIdentifier(declaration.name) || declaration.name.text !== receiver.text || !declaration.initializer) continue;
2325
- const initializer = unwrapExpression$1(declaration.initializer);
2326
- if (!ts$1.isCallExpression(initializer) || !isSetupCallExpression(initializer)) return null;
2327
- const setupArgument = initializer.arguments[0];
2328
- return setupArgument ? unwrapObjectLiteralExpression(setupArgument) : null;
2329
- }
2330
- }
2331
- return null;
2332
- }
2333
- function isObjectOfProvideCall(node) {
2334
- const parent = node.parent;
2335
- const grandparent = parent?.parent;
2336
- return !!parent && !!grandparent && ts$1.isPropertyAccessExpression(parent) && parent.expression === node && parent.name.text === "provide" && ts$1.isCallExpression(grandparent) && grandparent.expression === parent;
2337
- }
2338
- function isCreateMachineExpression$1(expression) {
2339
- const isMachineFactoryName = (name) => name === "createMachine" || name === "createMachineFromConfig";
2340
- return ts$1.isIdentifier(expression) && isMachineFactoryName(expression.text) || ts$1.isPropertyAccessExpression(expression) && isMachineFactoryName(expression.name.text);
2341
- }
2342
- function isSetupCallExpression(node) {
2343
- const expression = node.expression;
2344
- return ts$1.isIdentifier(expression) && expression.text === "setup" || ts$1.isPropertyAccessExpression(expression) && expression.name.text === "setup";
2345
- }
2346
- function unwrapObjectLiteralExpression(expression) {
2347
- const current = unwrapExpression$1(expression);
2348
- return ts$1.isObjectLiteralExpression(current) ? current : null;
2349
- }
2350
- function unwrapExpression$1(expression) {
2351
- let current = expression;
2352
- for (;;) {
2353
- if (ts$1.isParenthesizedExpression(current)) {
2354
- current = current.expression;
2355
- continue;
2356
- }
2357
- if (ts$1.isAsExpression(current) || ts$1.isSatisfiesExpression(current)) {
2358
- current = current.expression;
2359
- continue;
2360
- }
2361
- if (ts$1.isTypeAssertionExpression(current)) {
2362
- current = current.expression;
2363
- continue;
2364
- }
2365
- break;
2366
- }
2367
- return current;
2368
- }
2369
- function resolveStatePath(graph, nodeId) {
2370
- const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
2371
- const segments = [];
2372
- let current = nodeById.get(nodeId);
2373
- if (!current) return null;
2374
- while (current && current.parentId !== null) {
2375
- segments.push(current.data.key);
2376
- current = nodeById.get(current.parentId);
2377
- }
2378
- return segments.reverse();
2379
- }
2380
- function getEdgeSourceId(graph, edgeId) {
2381
- return graph.edges.find((edge) => edge.id === edgeId)?.sourceId ?? null;
2382
- }
2383
- function resolveEdgeSourcePath(graph, edgeId) {
2384
- const sourceId = getEdgeSourceId(graph, edgeId);
2385
- return sourceId ? resolveStatePath(graph, sourceId) : null;
2386
- }
2387
- function resolvePatchOwner(patch, prevGraph, nextGraph) {
2388
- switch (patch.op) {
2389
- case "createState": {
2390
- const parentPath = resolveStatePath(nextGraph, patch.parentId);
2391
- return parentPath ? {
2392
- type: "state",
2393
- path: parentPath
2394
- } : { type: "covered" };
2395
- }
2396
- case "updateState": {
2397
- const nextPath = resolveStatePath(nextGraph, patch.stateId);
2398
- const prevPath = resolveStatePath(prevGraph, patch.stateId);
2399
- if (patch.key !== void 0 && prevPath && nextPath) return { type: "root" };
2400
- const path = nextPath ?? prevPath;
2401
- return path ? {
2402
- type: "state",
2403
- path
2404
- } : { type: "covered" };
2405
- }
2406
- case "deleteState": {
2407
- const node = prevGraph.nodes.find((item) => item.id === patch.stateId);
2408
- if (!node) return { type: "covered" };
2409
- if (!node.parentId) return { type: "root" };
2410
- const parentPath = resolveStatePath(prevGraph, node.parentId);
2411
- return parentPath ? {
2412
- type: "state",
2413
- path: parentPath
2414
- } : { type: "root" };
2415
- }
2416
- case "createTransition": {
2417
- const path = resolveStatePath(nextGraph, patch.sourceId);
2418
- return path ? {
2419
- type: "state",
2420
- path
2421
- } : { type: "covered" };
2422
- }
2423
- case "updateTransition": {
2424
- const path = resolveEdgeSourcePath(nextGraph, patch.transitionId) ?? resolveEdgeSourcePath(prevGraph, patch.transitionId);
2425
- return path ? {
2426
- type: "state",
2427
- path
2428
- } : { type: "covered" };
2429
- }
2430
- case "deleteTransition":
2431
- case "setGuard":
2432
- case "deleteGuard": {
2433
- const edgeId = "transitionId" in patch ? patch.transitionId : patch.edgeId;
2434
- const path = resolveEdgeSourcePath(nextGraph, edgeId) ?? resolveEdgeSourcePath(prevGraph, edgeId);
2435
- return path ? {
2436
- type: "state",
2437
- path
2438
- } : { type: "covered" };
2439
- }
2440
- case "createAction":
2441
- case "updateAction":
2442
- case "deleteAction": {
2443
- if ("nodeId" in patch.location) {
2444
- const path = resolveStatePath(nextGraph, patch.location.nodeId) ?? resolveStatePath(prevGraph, patch.location.nodeId);
2445
- return path ? {
2446
- type: "state",
2447
- path
2448
- } : { type: "covered" };
2449
- }
2450
- const path = resolveEdgeSourcePath(nextGraph, patch.location.edgeId) ?? resolveEdgeSourcePath(prevGraph, patch.location.edgeId);
2451
- return path ? {
2452
- type: "state",
2453
- path
2454
- } : { type: "covered" };
2455
- }
2456
- case "createInvoke":
2457
- case "updateInvoke":
2458
- case "deleteInvoke":
2459
- case "createTag":
2460
- case "deleteTag": {
2461
- const path = resolveStatePath(nextGraph, patch.nodeId) ?? resolveStatePath(prevGraph, patch.nodeId);
2462
- return path ? {
2463
- type: "state",
2464
- path
2465
- } : { type: "covered" };
2466
- }
2467
- case "updateSchemas": return { type: "root" };
2468
- default: return { type: "root" };
2469
- }
2470
- }
2471
- function deriveReplacementPlan(patches, prevGraph, nextGraph) {
2472
- const rawPaths = [];
2473
- const hasConcretePatch = patches.some((patch) => patch.op !== "updateSchemas");
2474
- for (const patch of patches) {
2475
- if (patch.op === "updateSchemas" && hasConcretePatch) continue;
2476
- const owner = resolvePatchOwner(patch, prevGraph, nextGraph);
2477
- if (owner.type === "root") return { type: "root" };
2478
- if (owner.type === "covered") continue;
2479
- rawPaths.push(owner.path);
2480
- }
2481
- const reducedPaths = reducePaths(rawPaths);
2482
- if (reducedPaths.length === 0 || reducedPaths.some((path) => path.length === 0)) return { type: "root" };
2483
- return {
2484
- type: "states",
2485
- paths: reducedPaths
2486
- };
2487
- }
2488
- function dropCoveredSchemaPatches(patches, hasConcreteReplacement) {
2489
- return hasConcreteReplacement ? patches.filter((patch) => patch.op !== "updateSchemas") : patches;
2490
- }
2491
- function reducePaths(paths) {
2492
- const uniquePaths = Array.from(new Set(paths.map((path) => path.join(".")))).map((value) => value === "" ? [] : value.split(".")).sort((a, b) => a.length - b.length);
2493
- return uniquePaths.filter((path, index) => {
2494
- return !uniquePaths.some((candidate, candidateIndex) => {
2495
- if (candidateIndex === index || candidate.length >= path.length) return false;
2496
- return candidate.every((segment, segmentIndex) => segment === path[segmentIndex]);
2497
- });
2498
- });
2499
- }
2500
- function getStateConfigByPath(machineConfig, path) {
2501
- let current = machineConfig;
2502
- for (const segment of path) {
2503
- const states = current?.states;
2504
- if (!isMachineConfig(states)) return;
2505
- const next = states[segment];
2506
- if (!isMachineConfig(next)) return;
2507
- current = next;
2508
- }
2509
- return current;
2510
- }
2511
- function getStateObjectLiteralByPath(root, path) {
2512
- let current = root;
2513
- for (const segment of path) {
2514
- if (!current) return null;
2515
- const statesProperty = getObjectLiteralProperty(current, "states");
2516
- current = statesProperty && getObjectLiteralProperty(statesProperty, segment);
2517
- }
2518
- return current;
2519
- }
2520
- function offsetAtRangePosition(sourceText, line, character) {
2521
- if (line <= 0) return character;
2522
- let currentLine = 0;
2523
- for (let index = 0; index < sourceText.length; index += 1) {
2524
- if (sourceText.charCodeAt(index) !== 10) continue;
2525
- currentLine += 1;
2526
- if (currentLine === line) return index + 1 + character;
2527
- }
2528
- return sourceText.length;
2529
- }
2530
- function getObjectLiteralProperty(objectLiteral, propertyName) {
2531
- for (const property of objectLiteral.properties) {
2532
- if (!ts$1.isPropertyAssignment(property)) continue;
2533
- if (getPropertyNameText$1(property.name) !== propertyName) continue;
2534
- return unwrapObjectLiteralExpression(property.initializer) ?? null;
2535
- }
2536
- return null;
2537
- }
2538
- function getPropertyNameText$1(name) {
2539
- if (ts$1.isIdentifier(name) || ts$1.isStringLiteral(name) || ts$1.isNumericLiteral(name)) return name.text;
2540
- if (ts$1.isComputedPropertyName(name)) {
2541
- const expression = name.expression;
2542
- if (ts$1.isStringLiteral(expression) || ts$1.isNoSubstitutionTemplateLiteral(expression) || ts$1.isNumericLiteral(expression)) return expression.text;
2543
- }
2544
- return null;
2545
- }
2546
- function createReplacement(document, sourceFile, node, value) {
2547
- const start = document.positionAt(node.getStart(sourceFile));
2548
- const end = document.positionAt(node.getEnd());
2549
- const formatting = getFormattingContext(document, sourceFile, node);
2550
- return {
2551
- uri: getDocumentUri(document),
2552
- range: {
2553
- startLine: start.line,
2554
- startChar: start.character,
2555
- endLine: end.line,
2556
- endChar: end.character
2557
- },
2558
- newText: printExpression(valueToExpression(value, node), sourceFile, formatting)
2559
- };
2560
- }
2561
- function createRewriteReplacement(document, sourceFile, node, value) {
2562
- const start = document.positionAt(node.getStart(sourceFile));
2563
- const end = document.positionAt(node.getEnd());
2564
- const formatting = getFormattingContext(document, sourceFile, node);
2565
- return {
2566
- uri: getDocumentUri(document),
2567
- range: {
2568
- startLine: start.line,
2569
- startChar: start.character,
2570
- endLine: end.line,
2571
- endChar: end.character
2572
- },
2573
- newText: printExpression(valueToExpression(value), sourceFile, formatting)
2574
- };
2575
- }
2576
- function addCodeImportReplacements(document, sourceFile, machineConfig, replacements) {
2577
- const importReplacements = createCodeImportReplacements(document, sourceFile, collectCodeImports(machineConfig));
2578
- return [...replacements, ...importReplacements];
2579
- }
2580
- function collectCodeImports(value) {
2581
- const imports = [];
2582
- const visit = (item) => {
2583
- if (!item || typeof item !== "object") return;
2584
- if (Array.isArray(item)) {
2585
- for (const child of item) visit(child);
2586
- return;
2587
- }
2588
- if (isCodeExpression(item)) {
2589
- const itemImports = item.imports;
2590
- if (Array.isArray(itemImports)) {
2591
- for (const candidate of itemImports) if (isCodeImport(candidate)) imports.push(candidate);
2592
- }
2593
- }
2594
- for (const child of Object.values(item)) visit(child);
2595
- };
2596
- visit(value);
2597
- return imports;
2598
- }
2599
- function isCodeImport(value) {
2600
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
2601
- const candidate = value;
2602
- return typeof candidate.package === "string" && typeof candidate.import === "string" && (!candidate.version || typeof candidate.version === "string") && (!candidate.importKind || candidate.importKind === "named" || candidate.importKind === "default" || candidate.importKind === "namespace");
2603
- }
2604
- function createCodeImportReplacements(document, sourceFile, imports) {
2605
- const namedImportsByPackage = /* @__PURE__ */ new Map();
2606
- for (const codeImport of imports) {
2607
- if ((codeImport.importKind ?? "named") !== "named") continue;
2608
- const namedImports = namedImportsByPackage.get(codeImport.package) ?? /* @__PURE__ */ new Set();
2609
- namedImports.add(codeImport.import);
2610
- namedImportsByPackage.set(codeImport.package, namedImports);
2611
- }
2612
- const replacements = [];
2613
- for (const [packageName, importNames] of namedImportsByPackage) {
2614
- const missing = new Set(importNames);
2615
- const importDeclaration = findImportDeclaration(sourceFile, packageName);
2616
- if (importDeclaration) {
2617
- const namedBindings = importDeclaration.importClause?.namedBindings;
2618
- if (namedBindings && ts$1.isNamedImports(namedBindings)) {
2619
- for (const element of namedBindings.elements) missing.delete(element.name.text);
2620
- if (missing.size > 0) {
2621
- const insertion = `${namedBindings.elements.length > 0 ? ", " : ""}${[...missing].sort().join(", ")}`;
2622
- replacements.push(createOffsetReplacement(document, namedBindings.elements.end, namedBindings.elements.end, insertion));
2623
- }
2624
- }
2625
- continue;
2626
- }
2627
- replacements.push(createOffsetReplacement(document, getImportInsertionOffset(sourceFile), getImportInsertionOffset(sourceFile), `import { ${[...missing].sort().join(", ")} } from "${packageName}";${getLineBreak(sourceFile)}`));
2628
- }
2629
- return replacements;
2630
- }
2631
- function findImportDeclaration(sourceFile, packageName) {
2632
- for (const statement of sourceFile.statements) if (ts$1.isImportDeclaration(statement) && ts$1.isStringLiteral(statement.moduleSpecifier) && statement.moduleSpecifier.text === packageName) return statement;
2633
- return null;
2634
- }
2635
- function getImportInsertionOffset(sourceFile) {
2636
- let offset = 0;
2637
- for (const statement of sourceFile.statements) {
2638
- if (!ts$1.isImportDeclaration(statement)) break;
2639
- offset = statement.getEnd();
2640
- const nextLineStart = getLineStartOffset(sourceFile.text, offset + 1);
2641
- if (nextLineStart > offset) offset = nextLineStart;
2642
- }
2643
- return offset;
2644
- }
2645
- function getDocumentUri(document) {
2646
- return (typeof document.uri === "string" ? document.uri : document.uri?.toString()) ?? document.fileName;
2647
- }
2648
- function tryCreateSemanticReplacements(document, sourceFile, machineConfigNode, patches, prevGraph, nextGraph) {
2649
- const split = getSemanticStateRenamePatchSplit(patches, prevGraph, nextGraph);
2650
- if (!split || split.remainingPatches.length > 0) return null;
2651
- const replacements = [];
2652
- const targetLiterals = collectTargetStringLiterals(machineConfigNode).map((target) => ({
2653
- ...target,
2654
- document,
2655
- sourceFile
2656
- }));
2657
- for (const rename of split.renames) {
2658
- const parentObject = getStateObjectLiteralByPath(machineConfigNode, rename.parentPath);
2659
- if (!parentObject) return null;
2660
- const renameReplacements = createStateKeyRenameReplacementsForTarget(document, sourceFile, parentObject, rename, void 0, targetLiterals);
2661
- if (!renameReplacements || hasDuplicateReplacementRange([...replacements, ...renameReplacements])) return null;
2662
- replacements.push(...renameReplacements);
2663
- }
2664
- return replacements.sort(compareReplacementRangesDescending);
2665
- }
2666
- async function tryCreateSemanticPatchSplitForDocuments(document, sourceFile, machineConfigNode, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) {
2667
- const descriptionSplit = isXStateV6Source(sourceLocations) ? await tryCreateV6WrapperDescriptionPatchSplitForDocuments(document, sourceFile, machineConfigNode, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) : null;
2668
- const split = getSemanticStateRenamePatchSplit(descriptionSplit?.remainingPatches ?? patches, prevGraph, nextGraph);
2669
- if (!split) return descriptionSplit;
2670
- const replacements = [...descriptionSplit?.replacements ?? []];
2671
- const targetLiterals = await collectMappedTargetStringLiterals(document, sourceFile, machineConfigNode, sourceLocations, openTextDocument);
2672
- let activeSourceLocations = sourceLocations;
2673
- for (const rename of split.renames) {
2674
- const parentTarget = await getStateMembershipParentTargetForDocuments(document, sourceFile, machineConfigNode, activeSourceLocations, rename.parentPath, openTextDocument, getStateObjectLiteralByPath);
2675
- if (!parentTarget) return null;
2676
- const renameReplacements = createStateKeyRenameReplacementsForTarget(parentTarget.document, parentTarget.sourceFile, parentTarget.node, rename, activeSourceLocations, targetLiterals, parentTarget.nodeKind, parentTarget.nodeKind === "statesObject" && rename.parentPath.length === 0 ? machineConfigNode : parentTarget.node);
2677
- if (!renameReplacements || hasDuplicateReplacementRange([...replacements, ...renameReplacements])) return null;
2678
- replacements.push(...renameReplacements);
2679
- activeSourceLocations = createRenamedSourceLocations(activeSourceLocations, rename);
2680
- }
2681
- return {
2682
- replacements: replacements.sort(compareReplacementRangesDescending),
2683
- remainingPatches: split.remainingPatches,
2684
- sourceLocations: activeSourceLocations
2685
- };
2686
- }
2687
- async function tryCreateV6WrapperDescriptionPatchSplitForDocuments(document, sourceFile, machineConfigNode, patches, prevGraph, nextGraph, sourceLocations, openTextDocument) {
2688
- const replacements = [];
2689
- const remainingPatches = [];
2690
- const descriptionsByTarget = /* @__PURE__ */ new Map();
2691
- for (const patch of patches) {
2692
- if (patch.op !== "updateTransition" || patch.transitionDescription === void 0 || Object.entries(patch).some(([key, value]) => value !== void 0 && ![
2693
- "op",
2694
- "transitionId",
2695
- "transitionDescription"
2696
- ].includes(key))) {
2697
- remainingPatches.push(patch);
2698
- continue;
2699
- }
2700
- const target = getTransitionPatchTarget(patch, prevGraph, nextGraph);
2701
- if (!target || target.previousEventType !== target.eventType) {
2702
- remainingPatches.push(patch);
2703
- continue;
2704
- }
2705
- const targetKey = `${target.sourcePath.join(".")}:${target.eventType}`;
2706
- if (descriptionsByTarget.has(targetKey)) {
2707
- if (descriptionsByTarget.get(targetKey) !== patch.transitionDescription) return null;
2708
- continue;
2709
- }
2710
- descriptionsByTarget.set(targetKey, patch.transitionDescription);
2711
- const mappedTarget = await getMappedStateReplacementTarget(document, sourceFile, sourceLocations, target.sourcePath, openTextDocument);
2712
- const targetDocument = mappedTarget?.document ?? document;
2713
- const targetSourceFile = mappedTarget?.sourceFile ?? sourceFile;
2714
- const stateObject = mappedTarget?.node ?? getStateObjectLiteralByPath(machineConfigNode, target.sourcePath);
2715
- const onObject = stateObject ? getObjectLiteralProperty(stateObject, "on") : null;
2716
- const eventProperty = onObject ? findObjectLiteralProperty(onObject, target.eventType) : null;
2717
- const initializer = eventProperty && ts$1.isPropertyAssignment(eventProperty) ? unwrapExpression$1(eventProperty.initializer) : null;
2718
- const wrapper = initializer && ts$1.isObjectLiteralExpression(initializer) ? initializer : null;
2719
- const toProperty = wrapper ? getPropertyAssignment(wrapper, "to") : null;
2720
- if (!wrapper || !toProperty) {
2721
- remainingPatches.push(patch);
2722
- continue;
2723
- }
2724
- const descriptionProperty = getPropertyAssignment(wrapper, "description");
2725
- if (patch.transitionDescription === null) {
2726
- if (descriptionProperty) replacements.push(createObjectLiteralPropertyDeletion(targetDocument, targetSourceFile, wrapper, descriptionProperty));
2727
- } else if (descriptionProperty) replacements.push(createPropertyValueReplacement(targetDocument, targetSourceFile, descriptionProperty, patch.transitionDescription));
2728
- else replacements.push(...createObjectLiteralPropertyInsertion(targetDocument, targetSourceFile, wrapper, "description", patch.transitionDescription));
2729
- }
2730
- return replacements.length > 0 ? {
2731
- replacements,
2732
- remainingPatches,
2733
- sourceLocations
2734
- } : null;
2735
- }
2736
- function getSemanticStateRenameFromPatch(patch, prevGraph, nextGraph) {
2737
- if (patch.op !== "updateState" || patch.key === void 0) return null;
2738
- const prevPath = resolveStatePath(prevGraph, patch.stateId);
2739
- const nextPath = resolveStatePath(nextGraph, patch.stateId);
2740
- if (!prevPath || !nextPath || prevPath.length !== nextPath.length || prevPath.length === 0) return null;
2741
- const oldKey = prevPath[prevPath.length - 1];
2742
- const newKey = nextPath[nextPath.length - 1];
2743
- const parentPath = prevPath.slice(0, -1);
2744
- if (oldKey === newKey) return null;
2745
- return {
2746
- oldKey,
2747
- newKey,
2748
- oldPath: prevPath,
2749
- newPath: nextPath,
2750
- parentPath,
2751
- oldAbsolutePath: getAbsoluteStatePath(prevGraph, patch.stateId),
2752
- newAbsolutePath: getAbsoluteStatePath(nextGraph, patch.stateId)
2753
- };
2754
- }
2755
- function getSemanticStateRenamePatchSplit(patches, prevGraph, nextGraph) {
2756
- const renames = [];
2757
- const remainingPatches = [];
2758
- for (const patch of patches) {
2759
- const patchRename = getSemanticStateRenameFromPatch(patch, prevGraph, nextGraph);
2760
- if (patchRename) {
2761
- renames.push(patchRename);
2762
- if (getStatePropertyNamesFromUpdatePatch(patch).length > 0) remainingPatches.push(patch);
2763
- continue;
2764
- }
2765
- remainingPatches.push(patch);
2766
- }
2767
- return renames.length > 0 ? {
2768
- renames,
2769
- remainingPatches
2770
- } : null;
2771
- }
2772
- function hasNestedStateRenameBatch(patches, prevGraph, nextGraph) {
2773
- const renames = patches.flatMap((patch) => {
2774
- const rename = getSemanticStateRenameFromPatch(patch, prevGraph, nextGraph);
2775
- return rename ? [rename] : [];
2776
- });
2777
- return renames.some((ancestor, ancestorIndex) => renames.some((descendant, descendantIndex) => ancestorIndex !== descendantIndex && ancestor.oldPath.length < descendant.oldPath.length && isPathEqualOrDescendant(descendant.oldPath, ancestor.oldPath)));
2778
- }
2779
- function hasDuplicateReplacementRange(replacements) {
2780
- const ranges = /* @__PURE__ */ new Set();
2781
- for (const replacement of replacements) {
2782
- const key = `${replacement.uri ?? ""}:${replacement.range.startLine}:${replacement.range.startChar}:${replacement.range.endLine}:${replacement.range.endChar}`;
2783
- if (ranges.has(key)) return true;
2784
- ranges.add(key);
2785
- }
2786
- return false;
2787
- }
2788
- function createRenamedSourceLocations(sourceLocations, rename) {
2789
- if (!sourceLocations) return;
2790
- return {
2791
- ...sourceLocations,
2792
- states: sourceLocations.states.map((location) => {
2793
- if (!isPathEqualOrDescendant(location.path, rename.oldPath)) return location;
2794
- return {
2795
- ...location,
2796
- path: [...rename.newPath, ...location.path.slice(rename.oldPath.length)]
2797
- };
2798
- }),
2799
- transitionFunctions: sourceLocations.transitionFunctions?.map((location) => ({
2800
- ...location,
2801
- sourcePaths: location.sourcePaths.map((path) => isPathEqualOrDescendant(path, rename.oldPath) ? [...rename.newPath, ...path.slice(rename.oldPath.length)] : path)
2802
- }))
2803
- };
2804
- }
2805
- function createStateKeyRenameReplacementsForTarget(document, sourceFile, parentObject, rename, sourceLocations, targetLiterals, nodeKind = "machineConfig", initialOwnerObject = parentObject) {
2806
- const statesObject = nodeKind === "statesObject" ? parentObject : getObjectLiteralProperty(parentObject, "states");
2807
- const location = sourceLocations?.states.find((item) => rename.oldPath && arePathsEqual(item.path, rename.oldPath));
2808
- const stateProperty = statesObject && (findObjectLiteralProperty(statesObject, rename.oldKey) ?? findObjectLiteralPropertyByRange(sourceFile, statesObject, location?.keyRange));
2809
- if (!statesObject || !stateProperty) return null;
2810
- const keyReplacement = createStatePropertyRenameReplacement(document, sourceFile, stateProperty, rename.oldKey, rename.newKey, location?.keySource);
2811
- if (!keyReplacement) return null;
2812
- const replacements = [keyReplacement];
2813
- const initialProperty = getPropertyAssignment(initialOwnerObject, "initial");
2814
- if (initialProperty) {
2815
- const initialReplacement = createStringInitializerRenameReplacement(document, sourceFile, initialProperty.initializer, rename.oldKey, rename.newKey);
2816
- if (initialReplacement) replacements.push(initialReplacement);
2817
- }
2818
- const supportedScope = new Set([rename.parentPath.join("."), ...getDirectChildStatePaths(nodeKind === "statesObject" ? initialOwnerObject : parentObject, rename.parentPath).map((path) => path.join("."))]);
2819
- for (const target of targetLiterals) {
2820
- if (!referencesRenamedState(target.node.text, rename)) continue;
2821
- if (!referencesRenamedAbsoluteState(target.node.text, rename)) {
2822
- const initialSourcePaths = target.initialSourcePaths ?? [];
2823
- if (initialSourcePaths.length > 0) {
2824
- if (!target.sourcePaths.every((sourcePath) => arePathsEqual(sourcePath, rename.parentPath))) {
2825
- if (initialSourcePaths.length === target.sourcePaths.length && !initialSourcePaths.some((sourcePath) => arePathsEqual(sourcePath, rename.parentPath))) continue;
2826
- return null;
2827
- }
2828
- } else for (const sourcePath of target.sourcePaths) {
2829
- const sourceKey = sourcePath.join(".");
2830
- if (!(sourcePath.length === rename.parentPath.length || arePathsEqual(sourcePath.slice(0, -1), rename.parentPath)) || !supportedScope.has(sourceKey)) return null;
2831
- }
2832
- }
2833
- const replacement = createStringLiteralReplacement(target.document, target.sourceFile, target.node, renameStateReference(target.node.text, rename));
2834
- replacements.push(replacement);
2835
- }
2836
- return replacements;
2837
- }
2838
- function getDirectChildStatePaths(stateObject, parentPath) {
2839
- const statesObject = getObjectLiteralProperty(stateObject, "states");
2840
- if (!statesObject) return [];
2841
- return statesObject.properties.flatMap((property) => {
2842
- const key = getStatePropertyKeyText(property);
2843
- if (!key) return [];
2844
- return [[...parentPath, key]];
2845
- });
2846
- }
2847
- function collectTargetStringLiterals(machineConfigNode) {
2848
- const literals = [];
2849
- const bindings = collectTopLevelExpressionBindings(machineConfigNode.getSourceFile());
2850
- const visitStateObject = (stateObject, sourcePath) => {
2851
- collectInitialTargetStringLiterals(stateObject, sourcePath, literals, bindings);
2852
- for (const propertyName of [
2853
- "always",
2854
- "after",
2855
- "on",
2856
- "onDone"
2857
- ]) {
2858
- const property = getPropertyAssignment(stateObject, propertyName);
2859
- if (!property) continue;
2860
- collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals, bindings);
2861
- }
2862
- const statesObject = getObjectLiteralProperty(stateObject, "states");
2863
- if (!statesObject) return;
2864
- for (const property of statesObject.properties) {
2865
- if (!ts$1.isPropertyAssignment(property)) continue;
2866
- const key = getPropertyNameText$1(property.name);
2867
- const childState = unwrapObjectLiteralExpression(property.initializer);
2868
- if (!key || !childState) continue;
2869
- visitStateObject(childState, [...sourcePath, key]);
2870
- }
2871
- };
2872
- visitStateObject(machineConfigNode, []);
2873
- return literals;
2874
- }
2875
- function collectInitialTargetStringLiterals(stateObject, sourcePath, literals, bindings) {
2876
- const initialProperty = getPropertyAssignment(stateObject, "initial");
2877
- if (!initialProperty) return;
2878
- const initializer = unwrapExpression$1(initialProperty.initializer);
2879
- if (ts$1.isObjectLiteralExpression(initializer)) {
2880
- const initialLiterals = [];
2881
- collectTargetStringLiteralsFromExpression(initializer, sourcePath, initialLiterals, bindings);
2882
- for (const literal of initialLiterals) for (const literalSourcePath of literal.sourcePaths) addTargetLiteral(literals, literal.node, literalSourcePath, true);
2883
- }
2884
- }
2885
- async function collectMappedTargetStringLiterals(rootDocument, rootSourceFile, machineConfigNode, sourceLocations, openTextDocument) {
2886
- const literals = collectTargetStringLiterals(machineConfigNode).map((target) => ({
2887
- ...target,
2888
- document: rootDocument,
2889
- sourceFile: rootSourceFile
2890
- }));
2891
- if (!sourceLocations) return literals;
2892
- const seen = new Set(literals.map((target) => getTargetLiteralReplacementKey(rootDocument, rootSourceFile, target.node)));
2893
- const targetByKey = new Map(literals.map((target) => [getTargetLiteralReplacementKey(rootDocument, rootSourceFile, target.node), target]));
2894
- for (const location of sourceLocations.states) {
2895
- const targetDocument = isSourceLocationForDocument(location.uri, rootDocument) ? rootDocument : await openDocumentBySourceUri(location.uri, openTextDocument);
2896
- if (!targetDocument) continue;
2897
- const targetSourceFile = isSourceLocationForDocument(location.uri, rootDocument) ? rootSourceFile : createSourceFile(targetDocument, targetDocument.getText());
2898
- const stateObject = findObjectLiteralByRange(targetSourceFile, location.range);
2899
- if (!stateObject) continue;
2900
- const stateLiterals = [];
2901
- collectTargetStringLiteralsFromStateObject(stateObject, location.path, stateLiterals, collectTopLevelExpressionBindings(targetSourceFile));
2902
- for (const target of stateLiterals) {
2903
- const key = getTargetLiteralReplacementKey(targetDocument, targetSourceFile, target.node);
2904
- if (seen.has(key)) {
2905
- const existing = targetByKey.get(key);
2906
- if (existing) {
2907
- mergeTargetSourcePaths(existing, target.sourcePaths);
2908
- mergeInitialSourcePaths(existing, target.initialSourcePaths ?? []);
2909
- }
2910
- continue;
2911
- }
2912
- seen.add(key);
2913
- const mappedTarget = {
2914
- ...target,
2915
- document: targetDocument,
2916
- sourceFile: targetSourceFile
2917
- };
2918
- literals.push(mappedTarget);
2919
- targetByKey.set(key, mappedTarget);
2920
- }
2921
- }
2922
- for (const location of sourceLocations.transitionFunctions ?? []) {
2923
- const targetDocument = isSourceLocationForDocument(location.uri, rootDocument) ? rootDocument : await openDocumentBySourceUri(location.uri, openTextDocument);
2924
- if (!targetDocument) continue;
2925
- const targetSourceFile = isSourceLocationForDocument(location.uri, rootDocument) ? rootSourceFile : createSourceFile(targetDocument, targetDocument.getText());
2926
- const fn = findTransitionFunctionByRange(targetSourceFile, location.range);
2927
- if (!fn) continue;
2928
- const targetParameterIndexes = getTransitionTargetParameterIndexes(fn);
2929
- if (targetParameterIndexes.length > 0) {
2930
- const callTargets = collectTransitionCallArgumentLiterals(machineConfigNode, location.symbol, targetParameterIndexes);
2931
- for (const target of callTargets) {
2932
- const key = getTargetLiteralReplacementKey(rootDocument, rootSourceFile, target.node);
2933
- if (seen.has(key)) {
2934
- const existing = targetByKey.get(key);
2935
- if (existing) {
2936
- mergeTargetSourcePaths(existing, target.sourcePaths);
2937
- mergeInitialSourcePaths(existing, target.initialSourcePaths ?? []);
2938
- }
2939
- continue;
2940
- }
2941
- seen.add(key);
2942
- const mappedTarget = {
2943
- ...target,
2944
- document: rootDocument,
2945
- sourceFile: rootSourceFile
2946
- };
2947
- literals.push(mappedTarget);
2948
- targetByKey.set(key, mappedTarget);
2949
- }
2950
- }
2951
- const functionLiterals = [];
2952
- const bindings = collectTopLevelExpressionBindings(targetSourceFile);
2953
- for (const sourcePath of location.sourcePaths) collectTargetStringLiteralsFromFunction(fn, sourcePath, functionLiterals, bindings, new Set([location.symbol]));
2954
- for (const target of functionLiterals) {
2955
- const key = getTargetLiteralReplacementKey(targetDocument, targetSourceFile, target.node);
2956
- if (seen.has(key)) {
2957
- const existing = targetByKey.get(key);
2958
- if (existing) {
2959
- mergeTargetSourcePaths(existing, target.sourcePaths);
2960
- mergeInitialSourcePaths(existing, target.initialSourcePaths ?? []);
2961
- }
2962
- continue;
2963
- }
2964
- seen.add(key);
2965
- const mappedTarget = {
2966
- ...target,
2967
- document: targetDocument,
2968
- sourceFile: targetSourceFile
2969
- };
2970
- literals.push(mappedTarget);
2971
- targetByKey.set(key, mappedTarget);
2972
- }
2973
- }
2974
- return literals;
2975
- }
2976
- function findTransitionFunctionByRange(sourceFile, range) {
2977
- const start = offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar);
2978
- const end = offsetAtRangePosition(sourceFile.text, range.endLine, range.endChar);
2979
- let found = null;
2980
- const visit = (node) => {
2981
- if (found) return;
2982
- if ((ts$1.isArrowFunction(node) || ts$1.isFunctionExpression(node) || ts$1.isFunctionDeclaration(node)) && node.getStart(sourceFile) === start && node.getEnd() >= end) {
2983
- found = node;
2984
- return;
2985
- }
2986
- ts$1.forEachChild(node, visit);
2987
- };
2988
- visit(sourceFile);
2989
- return found;
2990
- }
2991
- function getTransitionTargetParameterIndexes(fn) {
2992
- const parameterIndexes = /* @__PURE__ */ new Map();
2993
- for (const [index, parameter] of fn.parameters.entries()) if (ts$1.isIdentifier(parameter.name)) parameterIndexes.set(parameter.name.text, index);
2994
- const indexes = /* @__PURE__ */ new Set();
2995
- const visit = (node) => {
2996
- if (ts$1.isObjectLiteralExpression(node)) for (const property of node.properties) {
2997
- const targetIdentifier = ts$1.isShorthandPropertyAssignment(property) && property.name.text === "target" ? property.name : ts$1.isPropertyAssignment(property) && getPropertyNameText$1(property.name) === "target" && ts$1.isIdentifier(unwrapExpression$1(property.initializer)) ? unwrapExpression$1(property.initializer) : null;
2998
- if (targetIdentifier) {
2999
- const index = parameterIndexes.get(targetIdentifier.text);
3000
- if (index !== void 0) indexes.add(index);
3001
- }
3002
- }
3003
- ts$1.forEachChild(node, visit);
3004
- };
3005
- visit(fn);
3006
- return [...indexes];
3007
- }
3008
- function collectTransitionCallArgumentLiterals(machineConfigNode, symbol, targetParameterIndexes) {
3009
- const literals = [];
3010
- const visitExpression = (expression, sourcePath) => {
3011
- const current = unwrapExpression$1(expression);
3012
- if (ts$1.isCallExpression(current) && ts$1.isIdentifier(current.expression) && current.expression.text === symbol) {
3013
- for (const index of targetParameterIndexes) {
3014
- const argument = current.arguments[index];
3015
- if (argument && ts$1.isStringLiteralLike(unwrapExpression$1(argument))) addTargetLiteral(literals, unwrapExpression$1(argument), sourcePath);
3016
- }
3017
- return;
3018
- }
3019
- if (ts$1.isObjectLiteralExpression(current)) {
3020
- for (const property of current.properties) if (ts$1.isPropertyAssignment(property)) visitExpression(property.initializer, sourcePath);
3021
- else if (ts$1.isShorthandPropertyAssignment(property)) visitExpression(property.name, sourcePath);
3022
- else if (ts$1.isSpreadAssignment(property)) visitExpression(property.expression, sourcePath);
3023
- return;
3024
- }
3025
- if (ts$1.isArrayLiteralExpression(current)) {
3026
- for (const element of current.elements) if (ts$1.isExpression(element)) visitExpression(element, sourcePath);
3027
- return;
3028
- }
3029
- ts$1.forEachChild(current, (child) => {
3030
- if (ts$1.isExpression(child)) visitExpression(child, sourcePath);
3031
- });
3032
- };
3033
- const visitState = (stateObject, sourcePath) => {
3034
- for (const propertyName of [
3035
- "always",
3036
- "after",
3037
- "on",
3038
- "onDone"
3039
- ]) {
3040
- const property = getPropertyAssignment(stateObject, propertyName);
3041
- if (property) visitExpression(property.initializer, sourcePath);
3042
- }
3043
- const states = getObjectLiteralProperty(stateObject, "states");
3044
- if (!states) return;
3045
- for (const property of states.properties) {
3046
- if (!ts$1.isPropertyAssignment(property)) continue;
3047
- const key = getPropertyNameText$1(property.name);
3048
- const child = unwrapObjectLiteralExpression(property.initializer);
3049
- if (key && child) visitState(child, [...sourcePath, key]);
3050
- }
3051
- };
3052
- visitState(machineConfigNode, []);
3053
- return literals;
3054
- }
3055
- function getTargetLiteralReplacementKey(document, sourceFile, node) {
3056
- return `${getDocumentUri(document)}:${node.getStart(sourceFile)}:${node.getEnd()}`;
3057
- }
3058
- function collectTargetStringLiteralsFromStateObject(stateObject, sourcePath, literals, bindings) {
3059
- collectInitialTargetStringLiterals(stateObject, sourcePath, literals, bindings);
3060
- for (const propertyName of [
3061
- "always",
3062
- "after",
3063
- "on",
3064
- "onDone"
3065
- ]) {
3066
- const property = getPropertyAssignment(stateObject, propertyName);
3067
- if (!property) continue;
3068
- collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals, bindings);
3069
- }
3070
- const statesObject = getObjectLiteralProperty(stateObject, "states");
3071
- if (!statesObject) return;
3072
- for (const property of statesObject.properties) {
3073
- if (!ts$1.isPropertyAssignment(property)) continue;
3074
- const key = getPropertyNameText$1(property.name);
3075
- const childState = unwrapObjectLiteralExpression(property.initializer);
3076
- if (!key || !childState) continue;
3077
- collectTargetStringLiteralsFromStateObject(childState, [...sourcePath, key], literals, bindings);
3078
- }
3079
- }
3080
- function collectTargetStringLiteralsFromExpression(expression, sourcePath, literals, bindings, seenBindings = /* @__PURE__ */ new Set()) {
3081
- const current = unwrapExpression$1(expression);
3082
- if (ts$1.isStringLiteralLike(current)) {
3083
- addTargetLiteral(literals, current, sourcePath);
3084
- return;
3085
- }
3086
- if (ts$1.isIdentifier(current)) {
3087
- if (seenBindings.has(current.text)) return;
3088
- const binding = bindings.get(current.text);
3089
- if (binding) {
3090
- const nextSeenBindings = new Set([...seenBindings, current.text]);
3091
- if (isTransitionFunctionBinding(binding)) collectTargetStringLiteralsFromFunction(binding, sourcePath, literals, bindings, nextSeenBindings);
3092
- else collectTargetStringLiteralsFromExpression(binding, sourcePath, literals, bindings, nextSeenBindings);
3093
- }
3094
- return;
3095
- }
3096
- if (ts$1.isArrowFunction(current) || ts$1.isFunctionExpression(current)) {
3097
- collectTargetStringLiteralsFromFunction(current, sourcePath, literals, bindings, seenBindings);
3098
- return;
3099
- }
3100
- if (ts$1.isCallExpression(current) && ts$1.isIdentifier(current.expression)) {
3101
- const binding = bindings.get(current.expression.text);
3102
- if (binding && isTransitionFunctionBinding(binding)) {
3103
- const scopedBindings = new Map(bindings);
3104
- for (const [index, parameter] of binding.parameters.entries()) {
3105
- if (!ts$1.isIdentifier(parameter.name)) continue;
3106
- const argument = current.arguments[index];
3107
- if (argument) scopedBindings.set(parameter.name.text, argument);
3108
- else if (parameter.initializer) scopedBindings.set(parameter.name.text, parameter.initializer);
3109
- }
3110
- collectTargetStringLiteralsFromFunction(binding, sourcePath, literals, scopedBindings, seenBindings);
3111
- }
3112
- return;
3113
- }
3114
- if (ts$1.isArrayLiteralExpression(current)) {
3115
- for (const element of current.elements) if (ts$1.isExpression(element)) collectTargetStringLiteralsFromExpression(element, sourcePath, literals, bindings, seenBindings);
3116
- return;
3117
- }
3118
- if (!ts$1.isObjectLiteralExpression(current)) return;
3119
- const targetProperty = current.properties.find((property) => ts$1.isPropertyAssignment(property) && getPropertyNameText$1(property.name) === "target" || ts$1.isShorthandPropertyAssignment(property) && property.name.text === "target");
3120
- if (targetProperty) {
3121
- collectTargetStringLiteralsFromExpression(ts$1.isPropertyAssignment(targetProperty) ? targetProperty.initializer : targetProperty.name, sourcePath, literals, bindings, seenBindings);
3122
- return;
3123
- }
3124
- for (const property of current.properties) {
3125
- if (!ts$1.isPropertyAssignment(property)) continue;
3126
- collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals, bindings, seenBindings);
3127
- }
3128
- }
3129
- function collectTargetStringLiteralsFromFunctionBody(body, sourcePath, literals, bindings, seenBindings) {
3130
- const visit = (node) => {
3131
- if (ts$1.isFunctionLike(node)) return;
3132
- if (ts$1.isReturnStatement(node) && node.expression) {
3133
- collectTargetStringLiteralsFromExpression(node.expression, sourcePath, literals, bindings, seenBindings);
3134
- return;
3135
- }
3136
- ts$1.forEachChild(node, visit);
3137
- };
3138
- ts$1.forEachChild(body, visit);
3139
- }
3140
- function isTransitionFunctionBinding(binding) {
3141
- return ts$1.isArrowFunction(binding) || ts$1.isFunctionExpression(binding) || ts$1.isFunctionDeclaration(binding);
3142
- }
3143
- function collectTargetStringLiteralsFromFunction(fn, sourcePath, literals, bindings, seenBindings) {
3144
- if (!fn.body) return;
3145
- if (ts$1.isBlock(fn.body)) {
3146
- collectTargetStringLiteralsFromFunctionBody(fn.body, sourcePath, literals, bindings, seenBindings);
3147
- return;
3148
- }
3149
- collectTargetStringLiteralsFromExpression(fn.body, sourcePath, literals, bindings, seenBindings);
3150
- }
3151
- function collectTopLevelExpressionBindings(sourceFile) {
3152
- const bindings = /* @__PURE__ */ new Map();
3153
- for (const statement of sourceFile.statements) {
3154
- if (ts$1.isFunctionDeclaration(statement) && statement.name) {
3155
- bindings.set(statement.name.text, statement);
3156
- continue;
3157
- }
3158
- if (!ts$1.isVariableStatement(statement)) continue;
3159
- for (const declaration of statement.declarationList.declarations) if (ts$1.isIdentifier(declaration.name) && declaration.initializer) bindings.set(declaration.name.text, declaration.initializer);
3160
- }
3161
- return bindings;
3162
- }
3163
- function addTargetLiteral(literals, node, sourcePath, isInitialTarget = false) {
3164
- const existing = literals.find((literal) => literal.node.getStart() === node.getStart() && literal.node.getEnd() === node.getEnd());
3165
- if (existing) {
3166
- mergeTargetSourcePaths(existing, [sourcePath]);
3167
- if (isInitialTarget) mergeInitialSourcePaths(existing, [sourcePath]);
3168
- return;
3169
- }
3170
- literals.push({
3171
- node,
3172
- sourcePaths: [sourcePath],
3173
- ...isInitialTarget ? { initialSourcePaths: [sourcePath] } : {}
3174
- });
3175
- }
3176
- function mergeInitialSourcePaths(target, initialSourcePaths) {
3177
- if (initialSourcePaths.length === 0) return;
3178
- const merged = target.initialSourcePaths ?? [];
3179
- for (const sourcePath of initialSourcePaths) if (!merged.some((existing) => arePathsEqual(existing, sourcePath))) merged.push(sourcePath);
3180
- target.initialSourcePaths = merged;
3181
- }
3182
- function mergeTargetSourcePaths(target, sourcePaths) {
3183
- for (const sourcePath of sourcePaths) if (!target.sourcePaths.some((existing) => arePathsEqual(existing, sourcePath))) target.sourcePaths.push(sourcePath);
3184
- }
3185
- function referencesRenamedState(value, rename) {
3186
- if (referencesRenamedSibling(value, rename.oldKey)) return true;
3187
- return referencesRenamedAbsoluteState(value, rename);
3188
- }
3189
- function referencesRenamedAbsoluteState(value, rename) {
3190
- const oldAbsolutePath = rename.oldAbsolutePath;
3191
- return oldAbsolutePath !== void 0 && (value === oldAbsolutePath || value.startsWith(`${oldAbsolutePath}.`));
3192
- }
3193
- function renameStateReference(value, rename) {
3194
- const oldAbsolutePath = rename.oldAbsolutePath;
3195
- const newAbsolutePath = rename.newAbsolutePath;
3196
- if (oldAbsolutePath && newAbsolutePath) {
3197
- if (value === oldAbsolutePath) return newAbsolutePath;
3198
- if (value.startsWith(`${oldAbsolutePath}.`)) return `${newAbsolutePath}${value.slice(oldAbsolutePath.length)}`;
3199
- }
3200
- return renameSiblingReference(value, rename.oldKey, rename.newKey);
3201
- }
3202
- function referencesRenamedSibling(value, oldKey) {
3203
- return value === oldKey || value.startsWith(`${oldKey}.`);
3204
- }
3205
- function getAbsoluteStatePath(graph, nodeId) {
3206
- const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
3207
- const node = nodeById.get(nodeId);
3208
- if (!node) return;
3209
- const resolvedId = resolveGraphStateId(node, nodeById);
3210
- return resolvedId ? `#${resolvedId}` : void 0;
3211
- }
3212
- function resolveGraphStateId(node, nodeById) {
3213
- const authoredId = node.data.nodeId;
3214
- if (authoredId && !authoredId.startsWith("$auto-")) return authoredId.replace(/^#/, "");
3215
- if (node.parentId === null) return node.data.key;
3216
- const parent = nodeById.get(node.parentId);
3217
- const parentId = parent && resolveGraphStateId(parent, nodeById);
3218
- return parentId ? `${parentId}.${node.data.key}` : node.data.key;
3219
- }
3220
- function renameSiblingReference(value, oldKey, newKey) {
3221
- if (value === oldKey) return newKey;
3222
- return value.startsWith(`${oldKey}.`) ? `${newKey}${value.slice(oldKey.length)}` : value;
3223
- }
3224
- function arePathsEqual(left, right) {
3225
- return left.length === right.length && left.every((segment, index) => segment === right[index]);
3226
- }
3227
- function createPropertyNameReplacement(document, sourceFile, propertyName, nextName) {
3228
- if (!isSupportedPropertyName(propertyName)) return null;
3229
- const start = document.positionAt(propertyName.getStart(sourceFile));
3230
- const end = document.positionAt(propertyName.getEnd());
3231
- const sourceText = sourceFile.text.slice(propertyName.getStart(sourceFile), propertyName.getEnd());
3232
- return {
3233
- range: {
3234
- startLine: start.line,
3235
- startChar: start.character,
3236
- endLine: end.line,
3237
- endChar: end.character
3238
- },
3239
- uri: getDocumentUri(document),
3240
- newText: formatPropertyNameText(propertyName, nextName, sourceText)
3241
- };
3242
- }
3243
- function createStatePropertyRenameReplacement(document, sourceFile, property, oldKey, newKey, keySource) {
3244
- 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));
3245
- if (ts$1.isPropertyAssignment(property)) {
3246
- if (ts$1.isComputedPropertyName(property.name)) return createPropertyNameLiteralReplacement(document, sourceFile, property.name, newKey);
3247
- return createPropertyNameReplacement(document, sourceFile, property.name, newKey);
3248
- }
3249
- if (!ts$1.isShorthandPropertyAssignment(property)) return null;
3250
- const start = document.positionAt(property.name.getStart(sourceFile));
3251
- const end = document.positionAt(property.name.getEnd());
3252
- const sourceText = sourceFile.text.slice(property.name.getStart(sourceFile), property.name.getEnd());
3253
- const nextPropertyName = formatPropertyNameText(property.name, newKey, sourceText);
3254
- return {
3255
- range: {
3256
- startLine: start.line,
3257
- startChar: start.character,
3258
- endLine: end.line,
3259
- endChar: end.character
3260
- },
3261
- uri: getDocumentUri(document),
3262
- newText: `${nextPropertyName}: ${oldKey}`
3263
- };
3264
- }
3265
- function createPropertyNameLiteralReplacement(document, sourceFile, propertyName, nextName) {
3266
- const start = document.positionAt(propertyName.getStart(sourceFile));
3267
- const end = document.positionAt(propertyName.getEnd());
3268
- return {
3269
- range: {
3270
- startLine: start.line,
3271
- startChar: start.character,
3272
- endLine: end.line,
3273
- endChar: end.character
3274
- },
3275
- uri: getDocumentUri(document),
3276
- newText: isIdentifierText(nextName) ? nextName : JSON.stringify(nextName)
3277
- };
3278
- }
3279
- function createStringInitializerRenameReplacement(document, sourceFile, expression, oldValue, newValue) {
3280
- if (!ts$1.isStringLiteralLike(expression) || expression.text !== oldValue) return null;
3281
- return createStringLiteralReplacement(document, sourceFile, expression, newValue);
3282
- }
3283
- function createStringLiteralReplacement(document, sourceFile, expression, nextValue) {
3284
- const start = document.positionAt(expression.getStart(sourceFile));
3285
- const end = document.positionAt(expression.getEnd());
3286
- const sourceText = sourceFile.text.slice(expression.getStart(sourceFile), expression.getEnd());
3287
- return {
3288
- range: {
3289
- startLine: start.line,
3290
- startChar: start.character,
3291
- endLine: end.line,
3292
- endChar: end.character
3293
- },
3294
- uri: getDocumentUri(document),
3295
- newText: formatStringLiteralText(sourceText, nextValue)
3296
- };
3297
- }
3298
- function createSourceRangeReplacement(document, sourceFile, range, newText) {
3299
- const startOffset = offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar);
3300
- const endOffset = offsetAtRangePosition(sourceFile.text, range.endLine, range.endChar);
3301
- const start = document.positionAt(startOffset);
3302
- const end = document.positionAt(endOffset);
3303
- return {
3304
- range: {
3305
- startLine: start.line,
3306
- startChar: start.character,
3307
- endLine: end.line,
3308
- endChar: end.character
3309
- },
3310
- uri: getDocumentUri(document),
3311
- newText
3312
- };
3313
- }
3314
- function isSourceRangeInDocument(sourceFile, range) {
3315
- return offsetAtRangePosition(sourceFile.text, range.startLine, range.startChar) <= sourceFile.text.length;
3316
- }
3317
- function isSupportedPropertyName(propertyName) {
3318
- if (ts$1.isIdentifier(propertyName) || ts$1.isStringLiteral(propertyName) || ts$1.isNumericLiteral(propertyName)) return true;
3319
- if (ts$1.isComputedPropertyName(propertyName)) {
3320
- const expression = propertyName.expression;
3321
- return ts$1.isStringLiteral(expression) || ts$1.isNoSubstitutionTemplateLiteral(expression) || ts$1.isNumericLiteral(expression);
3322
- }
3323
- return false;
3324
- }
3325
- function formatPropertyNameText(propertyName, nextName, sourceText) {
3326
- if (ts$1.isIdentifier(propertyName) && isIdentifierText(nextName)) return nextName;
3327
- if (ts$1.isComputedPropertyName(propertyName)) return `[${formatStringLiteralText(sourceText.slice(1, -1), nextName)}]`;
3328
- return formatStringLiteralText(sourceText, nextName);
3329
- }
3330
- function formatStringLiteralText(sourceText, nextValue) {
3331
- const quote = sourceText.startsWith("'") ? "'" : sourceText.startsWith("`") ? "`" : "\"";
3332
- return `${quote}${quote === "'" ? nextValue.replace(/\\/g, "\\\\").replace(/'/g, "\\'") : quote === "\"" ? nextValue.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") : nextValue.replace(/\\/g, "\\\\").replace(/`/g, "\\`")}${quote}`;
3333
- }
3334
- function compareReplacementRangesDescending(a, b) {
3335
- if (a.range.startLine !== b.range.startLine) return b.range.startLine - a.range.startLine;
3336
- return b.range.startChar - a.range.startChar;
3337
- }
3338
- function normalizeOverlappingReplacements(replacements) {
3339
- const result = [];
3340
- for (const candidate of replacements) {
3341
- if (replacements.find((other) => other !== candidate && other.uri === candidate.uri && rangeContains(other.range, candidate.range))) continue;
3342
- const overlappingDeletion = result.find((other) => other.uri === candidate.uri && other.newText === "" && candidate.newText === "" && rangesOverlap(other.range, candidate.range));
3343
- if (overlappingDeletion) {
3344
- overlappingDeletion.range = unionRanges(overlappingDeletion.range, candidate.range);
3345
- continue;
3346
- }
3347
- result.push(candidate);
3348
- }
3349
- return result;
3350
- }
3351
- const position = (line, char) => [line, char];
3352
- const comparePosition = (a, b) => a[0] - b[0] || a[1] - b[1];
3353
- const rangeStart = (range) => position(range.startLine, range.startChar);
3354
- const rangeEnd = (range) => position(range.endLine, range.endChar);
3355
- const rangeContains = (outer, inner) => comparePosition(rangeStart(outer), rangeStart(inner)) <= 0 && comparePosition(rangeEnd(outer), rangeEnd(inner)) >= 0;
3356
- const rangesOverlap = (a, b) => comparePosition(rangeStart(a), rangeEnd(b)) <= 0 && comparePosition(rangeStart(b), rangeEnd(a)) <= 0;
3357
- function unionRanges(a, b) {
3358
- const start = comparePosition(rangeStart(a), rangeStart(b)) <= 0 ? a : b;
3359
- const end = comparePosition(rangeEnd(a), rangeEnd(b)) >= 0 ? a : b;
3360
- return {
3361
- startLine: start.startLine,
3362
- startChar: start.startChar,
3363
- endLine: end.endLine,
3364
- endChar: end.endChar
3365
- };
3366
- }
3367
- function printExpression(expression, sourceFile, formatting) {
3368
- return reindentPrintedExpression(ts$1.createPrinter({ newLine: formatting.newLineKind }).printNode(ts$1.EmitHint.Expression, expression, sourceFile), formatting);
3369
- }
3370
- function reindentPrintedExpression(printed, formatting) {
3371
- const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
3372
- const lines = printed.split(/\r?\n/);
3373
- if (lines.length <= 1) return printed;
3374
- const printedIndentUnit = Math.min(...lines.slice(1).map((line) => line.match(/^ */)?.[0].length ?? 0).filter((indent) => indent > 0), 4);
3375
- return lines.map((line, index) => {
3376
- if (index === 0) return line;
3377
- if (line.trim() === "") return "";
3378
- const leadingSpaces = line.match(/^ */)?.[0].length ?? 0;
3379
- const indentLevel = Math.floor(leadingSpaces / printedIndentUnit);
3380
- return `${formatting.baseIndent}${formatting.indentUnit.repeat(indentLevel)}${line.slice(leadingSpaces)}`;
3381
- }).join(lineSeparator);
3382
- }
3383
- function getFormattingContext(document, sourceFile, node) {
3384
- const sourceText = sourceFile.text;
3385
- const lineStart = getLineStartOffset(sourceText, node.getStart(sourceFile));
3386
- const lineIndent = sourceText.slice(lineStart).match(/^[ \t]*/)?.[0] ?? "";
3387
- const editorIndentUnit = getEditorIndentUnit(document);
3388
- const inferredIndentUnit = inferIndentUnitFromNode(sourceText, node, sourceFile, lineIndent) ?? inferIndentUnitFromSource(sourceText);
3389
- return {
3390
- baseIndent: lineIndent,
3391
- indentUnit: editorIndentUnit ?? inferredIndentUnit ?? " ",
3392
- newLineKind: sourceText.includes("\r\n") ? ts$1.NewLineKind.CarriageReturnLineFeed : ts$1.NewLineKind.LineFeed
3393
- };
3394
- }
3395
- function getFormattingContextForExpression(document, sourceFile, node) {
3396
- const sourceText = sourceFile.text;
3397
- const nodeStart = node.getStart(sourceFile);
3398
- const lineStart = getLineStartOffset(sourceText, nodeStart);
3399
- return {
3400
- baseIndent: sourceText.slice(lineStart, nodeStart).match(/^[ \t]*/)?.[0] ?? "",
3401
- indentUnit: getEditorIndentUnit(document) ?? inferIndentUnitFromSource(sourceText) ?? " ",
3402
- newLineKind: sourceText.includes("\r\n") ? ts$1.NewLineKind.CarriageReturnLineFeed : ts$1.NewLineKind.LineFeed
3403
- };
3404
- }
3405
- function getEditorIndentUnit(document) {
3406
- return document.editorIndentUnit ?? null;
3407
- }
3408
- function inferIndentUnitFromNode(sourceText, node, sourceFile, baseIndent) {
3409
- 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));
3410
- }
3411
- function inferIndentUnitFromSource(sourceText) {
3412
- return getShortestIndent(sourceText.split(/\r?\n/).map((line) => line.match(/^[ \t]+(?=\S)/)?.[0] ?? "").filter(Boolean));
3413
- }
3414
- function getShortestIndent(indents) {
3415
- if (indents.length === 0) return null;
3416
- return indents.reduce((shortest, current) => current.length < shortest.length ? current : shortest);
3417
- }
3418
- function getLineStartOffset(sourceText, offset) {
3419
- const lastNewline = sourceText.lastIndexOf("\n", offset - 1);
3420
- if (lastNewline === -1) return 0;
3421
- return lastNewline + 1;
3422
- }
3423
- function valueToExpression(value, existingExpression) {
3424
- const rawCodeExpression = rawCodeToExpression(value);
3425
- if (rawCodeExpression) return rawCodeExpression;
3426
- const inlineExpression = inlineExpressionDirectiveToExpression(value);
3427
- if (inlineExpression) return inlineExpression;
3428
- if (value === null) return ts$1.factory.createNull();
3429
- if (typeof value === "string") return ts$1.factory.createStringLiteral(value);
3430
- if (typeof value === "number") {
3431
- if (value < 0) return ts$1.factory.createPrefixUnaryExpression(ts$1.SyntaxKind.MinusToken, ts$1.factory.createNumericLiteral(Math.abs(value)));
3432
- return ts$1.factory.createNumericLiteral(value);
3433
- }
3434
- if (typeof value === "boolean") return value ? ts$1.factory.createTrue() : ts$1.factory.createFalse();
3435
- if (Array.isArray(value)) {
3436
- const existingArray = existingExpression && ts$1.isArrayLiteralExpression(existingExpression) ? existingExpression : void 0;
3437
- const elements = value.map((item, index) => valueToExpression(item, existingArray && ts$1.isExpression(existingArray.elements[index]) ? existingArray.elements[index] : void 0));
3438
- if (existingArray) {
3439
- const updatedArray = ts$1.factory.createArrayLiteralExpression(elements, true);
3440
- ts$1.setOriginalNode(updatedArray, existingArray);
3441
- ts$1.setTextRange(updatedArray, existingArray);
3442
- return updatedArray;
3443
- }
3444
- return ts$1.factory.createArrayLiteralExpression(elements, true);
3445
- }
3446
- if (isMachineConfig(value)) {
3447
- const existingObject = existingExpression && ts$1.isObjectLiteralExpression(existingExpression) ? existingExpression : void 0;
3448
- const entries = Object.entries(value).filter(([, propertyValue]) => propertyValue !== void 0);
3449
- if (existingObject) {
3450
- const existingOrder = new Map(existingObject.properties.map((property, index) => [getStatePropertyKeyText(property), index]));
3451
- entries.sort(([left], [right]) => (existingOrder.get(left) ?? Number.MAX_SAFE_INTEGER) - (existingOrder.get(right) ?? Number.MAX_SAFE_INTEGER));
3452
- }
3453
- const properties = entries.map(([key, propertyValue]) => {
3454
- const existingProperty = existingObject ? getPropertyAssignment(existingObject, key) : null;
3455
- const nextInitializer = getPreservedPropertyInitializer(key, propertyValue, existingProperty?.initializer) ?? valueToExpression(propertyValue, existingProperty?.initializer);
3456
- if (existingProperty) return ts$1.factory.updatePropertyAssignment(existingProperty, existingProperty.name, nextInitializer);
3457
- return ts$1.factory.createPropertyAssignment(toPropertyName(key), nextInitializer);
3458
- });
3459
- if (existingObject) {
3460
- const updatedObject = ts$1.factory.createObjectLiteralExpression(properties, true);
3461
- ts$1.setOriginalNode(updatedObject, existingObject);
3462
- ts$1.setTextRange(updatedObject, existingObject);
3463
- return updatedObject;
3464
- }
3465
- return ts$1.factory.createObjectLiteralExpression(properties, true);
3466
- }
3467
- return ts$1.factory.createIdentifier("undefined");
3468
- }
3469
- function rawCodeToExpression(value) {
3470
- if (!isRawCodeLike(value)) return null;
3471
- return ts$1.factory.createIdentifier(value.code);
3472
- }
3473
- function isRawCodeLike(value) {
3474
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
3475
- const raw = value;
3476
- return raw.constructor?.name === "RawCode" && typeof raw.code === "string";
3477
- }
3478
- function containsRawCodeLike(value) {
3479
- if (isRawCodeLike(value)) return true;
3480
- if (Array.isArray(value)) return value.some(containsRawCodeLike);
3481
- return Boolean(value) && typeof value === "object" && Object.values(value).some(containsRawCodeLike);
3482
- }
3483
- function inlineExpressionDirectiveToExpression(value) {
3484
- if (!isCodeExpression(value)) return null;
3485
- return ts$1.factory.createIdentifier(value.expr);
3486
- }
3487
- function getPreservedPropertyInitializer(propertyName, nextValue, existingInitializer) {
3488
- if (propertyName !== "description" || typeof nextValue !== "string" || !existingInitializer) return null;
3489
- if (ts$1.isStringLiteralLike(existingInitializer)) return existingInitializer.text === nextValue ? existingInitializer : null;
3490
- return existingInitializer;
3491
- }
3492
- function getPropertyAssignment(objectLiteral, propertyName) {
3493
- for (const property of objectLiteral.properties) {
3494
- if (!ts$1.isPropertyAssignment(property)) continue;
3495
- if (getPropertyNameText$1(property.name) === propertyName) return property;
3496
- }
3497
- return null;
3498
- }
3499
- function toPropertyName(name) {
3500
- return isIdentifierText(name) ? ts$1.factory.createIdentifier(name) : ts$1.factory.createStringLiteral(name);
3501
- }
3502
- function isIdentifierText(value) {
3503
- return /^[$A-Z_][0-9A-Z_$]*$/i.test(value);
3504
- }
3505
-
3506
- //#endregion
3507
- //#region ../editor-sync/src/internal/statelyMetadata.ts
3508
- const STATELY_METADATA_PREFIX = "@statelyai.";
3509
- function isPlainObject(value) {
3510
- return !!value && typeof value === "object" && !Array.isArray(value);
3511
- }
3512
- function stripStatelyMetadata(value) {
3513
- if (Array.isArray(value)) return value.map((item) => stripStatelyMetadata(item));
3514
- if (!isPlainObject(value)) return value;
3515
- const result = {};
3516
- for (const [key, child] of Object.entries(value)) {
3517
- if (key.startsWith(STATELY_METADATA_PREFIX)) continue;
3518
- const nextChild = stripStatelyMetadata(child);
3519
- if (isPlainObject(nextChild) && Object.keys(nextChild).length === 0 && isPlainObject(child)) continue;
3520
- result[key] = nextChild;
3521
- }
3522
- return result;
3523
- }
3524
-
3525
- //#endregion
3526
- //#region ../editor-sync/src/internal/adapters.ts
3527
- const xstateAdapter = {
3528
- id: "xstate",
3529
- format: "xstate",
3530
- matches(document, text) {
3531
- return isJavaScriptOrTypeScriptFile(document.fileName) && looksLikeXStateMachine(text);
3532
- },
3533
- matchesFallback(document) {
3534
- return isJavaScriptOrTypeScriptFile(document.fileName);
3535
- },
3536
- parseSourceToMachine(text, document, options) {
3537
- return parseSourceToMachine(text, document, options);
3538
- },
3539
- collectSourceLocations(text, document, options) {
3540
- return collectXStateSourceLocations(text, document, options);
3541
- },
3542
- async applyMachineToDocument(machineConfig, document, options) {
3543
- const detectedSourceLocations = collectXStateSourceLocations(document.getText(), document, { machineIndex: options?.machineIndex });
3544
- const rootSourceLocation = options?.sourceLocations?.root ?? detectedSourceLocations?.root;
3545
- const sanitizedMachineConfig = options?.preserveStatelyMetadata === false ? stripStatelyMetadata(machineConfig) : machineConfig;
3546
- if (!options?.patches?.length) return [];
3547
- const replacements = await applyMachineToSourceDocuments(sanitizedMachineConfig, document, options);
3548
- if (replacements.some(containsXStateExpressionPlaceholder) || options?.sourceUpdateStrategy !== "rewrite" && replacements.some((replacement) => isImplicitRootReplacement(replacement, rootSourceLocation))) return [];
3549
- return replacements;
3550
- }
3551
- };
3552
- function containsXStateExpressionPlaceholder(replacement) {
3553
- return /["']\{\{\s*[^}]+\s*\}\}["']/.test(replacement.newText);
3554
- }
3555
- function isImplicitRootReplacement(replacement, root) {
3556
- if (!root) return false;
3557
- if (replacement.uri && replacement.uri !== root.uri) return false;
3558
- const startsBeforeRoot = replacement.range.startLine < root.range.startLine || replacement.range.startLine === root.range.startLine && replacement.range.startChar <= root.range.startChar;
3559
- const endsAfterRoot = replacement.range.endLine > root.range.endLine || replacement.range.endLine === root.range.endLine && replacement.range.endChar >= root.range.endChar;
3560
- return startsBeforeRoot && endsAfterRoot;
3561
- }
3562
- function createSerializedExportAdapter(format, matches) {
3563
- return {
3564
- id: format,
3565
- format,
3566
- matches,
3567
- parseSourceToMachine(text) {
3568
- return text;
3569
- },
3570
- async applyMachineToDocument(_machineConfig, document, options) {
3571
- return createSerializedDocumentReplacement(document, options, format);
3572
- }
3573
- };
3574
- }
3575
- async function createSerializedDocumentReplacement(document, options, format) {
3576
- const serialized = await options?.requestSerialized?.(format);
3577
- if (typeof serialized !== "string") return [];
3578
- const fullText = document.getText();
3579
- const end = document.positionAt(fullText.length);
3580
- return [{
3581
- range: {
3582
- startLine: 0,
3583
- startChar: 0,
3584
- endLine: end.line,
3585
- endChar: end.character
3586
- },
3587
- newText: serialized
3588
- }];
3589
- }
3590
- const xstateJsonAdapter = createSerializedExportAdapter("xstate-json", (document, text) => isJsonFile(document.fileName) && looksLikeXStateJson(text));
3591
- const asyncAdapter = createSerializedExportAdapter("async", (document, text) => isJavaScriptOrTypeScriptFile(document.fileName) && looksLikeAsyncWorkflow(text));
3592
- const xgraphAdapter = createSerializedExportAdapter("xgraph", (document, text) => isJsonFile(document.fileName) && looksLikeXGraphJson(text));
3593
- const mermaidAdapter = createSerializedExportAdapter("mermaid", (document, text) => isMermaidFile(document.fileName) || looksLikeMermaid(text));
3594
- const aslJsonAdapter = createSerializedExportAdapter("asl-json", (document, text) => (hasAslExtension(document.fileName) || looksLikeAmazonStatesLanguage(text)) && !isYamlFile(document.fileName));
3595
- const aslYamlAdapter = createSerializedExportAdapter("asl-yaml", (document, text) => (hasAslExtension(document.fileName) || looksLikeAmazonStatesLanguage(text)) && isYamlFile(document.fileName));
3596
- const adapters = [
3597
- xstateAdapter,
3598
- asyncAdapter,
3599
- createSerializedExportAdapter("redux", (document, text) => isJavaScriptOrTypeScriptFile(document.fileName) && looksLikeReduxToolkit(text)),
3600
- createSerializedExportAdapter("zustand", (document, text) => isJavaScriptOrTypeScriptFile(document.fileName) && looksLikeZustand(text)),
3601
- aslYamlAdapter,
3602
- aslJsonAdapter,
3603
- mermaidAdapter,
3604
- xgraphAdapter,
3605
- xstateJsonAdapter
3606
- ];
3607
- function isJavaScriptOrTypeScriptFile(fileName) {
3608
- return /\.(?:c|m)?(?:jsx?|tsx?)$/i.test(fileName);
3609
- }
3610
- function isYamlFile(fileName) {
3611
- return /\.(?:asl\.)?ya?ml$/i.test(fileName);
3612
- }
3613
- function hasAslExtension(fileName) {
3614
- return /\.asl\.(?:jsonc?|ya?ml)$/i.test(fileName);
3615
- }
3616
- function isJsonFile(fileName) {
3617
- return /\.jsonc?$/i.test(fileName);
3618
- }
3619
- function isMermaidFile(fileName) {
3620
- return /\.(?:mmd|mermaid)$/i.test(fileName);
3621
- }
3622
- function stripMermaidFrontmatter(text) {
3623
- return text.replace(/^\s*---\r?\n[\s\S]*?\r?\n---\r?\n?/, "");
3624
- }
3625
- function looksLikeMermaid(text) {
3626
- return /^\s*(?:stateDiagram(?:-v2)?|flowchart(?:\s+(?:TB|TD|BT|LR|RL))?|graph\s+(?:TB|TD|BT|LR|RL))\b/.test(stripMermaidFrontmatter(text));
3627
- }
3628
- function looksLikeAmazonStatesLanguage(text) {
3629
- return /(^|\s|["'])StartAt["']?\s*:/m.test(text) && /(^|\s|["'])States["']?\s*:/m.test(text);
3630
- }
3631
- function looksLikeXStateJson(text) {
3632
- try {
3633
- const value = JSON.parse(text);
3634
- return Boolean(value && typeof value === "object" && !Array.isArray(value) && "states" in value);
3635
- } catch {
3636
- return false;
3637
- }
3638
- }
3639
- function looksLikeXGraphJson(text) {
3640
- try {
3641
- const value = JSON.parse(text);
3642
- return Boolean(value && typeof value === "object" && !Array.isArray(value) && Array.isArray(value.nodes) && Array.isArray(value.edges));
3643
- } catch {
3644
- return false;
3645
- }
3646
- }
3647
- function looksLikeReduxToolkit(text) {
3648
- return /\bcreateSlice\s*\(/.test(text) && /@reduxjs\/toolkit/.test(text);
3649
- }
3650
- function looksLikeZustand(text) {
3651
- return /\bcreate\s*\(\s*\(/.test(text) && /from\s+["']zustand["']/.test(text);
3652
- }
3653
- function looksLikeAsyncWorkflow(text) {
3654
- return /\bawait\b/.test(text) && (/\basync\s+function\b/.test(text) || /\basync\s*\([^)]*\)\s*=>/.test(text) || /\basync\s+\w+\s*=>/.test(text));
3655
- }
3656
- function looksLikeXStateMachine(text) {
3657
- return /\b(?:createMachine|createMachineFromConfig)\s*\(/.test(text) || /\bMachine\s*\(/.test(text) || /\.createMachine\s*\(/.test(text);
3658
- }
3659
- function getSyncAdapter(document, text = "") {
3660
- const resolvedText = text || document.getText?.() || "";
3661
- const matched = adapters.find((adapter) => adapter.matches(document, resolvedText));
3662
- if (matched) return matched;
3663
- const fallback = adapters.find((adapter) => adapter.matchesFallback?.(document, resolvedText));
3664
- if (fallback) return fallback;
3665
- throw new Error(`Unsupported document for Stately sync: ${document.fileName}`);
3666
- }
3667
- function parseDocumentToMachine(document, options = {}) {
3668
- const text = document.getText();
3669
- const adapter = getSyncAdapter(document, text);
3670
- return {
3671
- adapter,
3672
- format: adapter.format,
3673
- machine: adapter.parseSourceToMachine(text, document, options),
3674
- sourceLocations: adapter.collectSourceLocations?.(text, document, options)
3675
- };
3676
- }
3677
-
3678
- //#endregion
3679
- //#region src/pushMerge.ts
3680
- const GEOMETRY_KEYS = [
3681
- "x",
3682
- "y",
3683
- "width",
3684
- "height"
3685
- ];
3686
- const DEFAULT_NODE_SIZE = {
3687
- width: 160,
3688
- height: 64
3689
- };
3690
- const DEFAULT_ANNOTATION_SIZE = {
3691
- width: 240,
3692
- height: 120
3693
- };
3694
- const NEW_NODE_GAP = 80;
3695
- const MAX_CONCURRENT_MERGE_ATTEMPTS = 3;
3696
- function indexBySemanticId(normalized, original) {
3697
- const bySemanticId = /* @__PURE__ */ new Map();
3698
- normalized.forEach((entity, index) => {
3699
- const source = original[index];
3700
- if (source && !bySemanticId.has(entity.id)) bySemanticId.set(entity.id, source);
3701
- });
3702
- return bySemanticId;
3703
- }
3704
- function carryGeometry(target, remote) {
3705
- for (const key of GEOMETRY_KEYS) if (remote[key] !== void 0) target[key] = remote[key];
3706
- }
3707
- function collectDigraphNodes(node, into) {
3708
- into.set(node.id, node);
3709
- node.nodes.forEach((child) => collectDigraphNodes(child, into));
3710
- return into;
3711
- }
3712
- function restoreNodeFields(node, remoteNodesById, remoteNodeIdByLocalId) {
3713
- const structuralChildren = [...node.nodes];
3714
- const remoteId = remoteNodeIdByLocalId.get(node.id);
3715
- const remote = remoteId ? remoteNodesById.get(remoteId) : void 0;
3716
- if (remote) {
3717
- if (remote.uniqueId !== void 0) node.uniqueId = remote.uniqueId;
3718
- if (remote.data.assets !== void 0) node.data.assets = structuredClone(remote.data.assets);
3719
- if (remote.data.blockFlowDirection !== void 0) node.data.blockFlowDirection = remote.data.blockFlowDirection;
3720
- if (remote.data.order !== void 0) node.data.order = remote.data.order;
3721
- const existingIds = new Set(node.nodes.map((child) => child.id));
3722
- const annotations = remote.nodes.filter((child) => child.data.type === "annotation" && !existingIds.has(child.id));
3723
- node.nodes.push(...annotations.map((annotation) => structuredClone(annotation)));
3724
- }
3725
- structuralChildren.forEach((child) => restoreNodeFields(child, remoteNodesById, remoteNodeIdByLocalId));
3726
- }
3727
- function restoreEdgeFields(edges, remoteEdgesById, remoteEdgeIdByLocalId) {
3728
- for (const edge of edges) {
3729
- const remoteId = remoteEdgeIdByLocalId.get(edge.id);
3730
- const remote = remoteId ? remoteEdgesById.get(remoteId) : void 0;
3731
- if (remote) {
3732
- if (remote.uniqueId !== void 0) edge.uniqueId = remote.uniqueId;
3733
- if (remote.data.assets !== void 0) edge.data.assets = structuredClone(remote.data.assets);
3734
- }
3735
- }
3736
- }
3737
- function hasFinitePoint(value) {
3738
- return Boolean(value && Number.isFinite(value.x) && Number.isFinite(value.y));
3739
- }
3740
- function hasFiniteSize(value) {
3741
- return Boolean(value && Number.isFinite(value.width) && Number.isFinite(value.height) && value.width > 0 && value.height > 0);
3742
- }
3743
- function ensureCompleteNodeGeometry(rootNode) {
3744
- if (!hasFinitePoint(rootNode.position)) rootNode.position = {
3745
- x: 0,
3746
- y: 0
3747
- };
3748
- if (!hasFiniteSize(rootNode.size)) rootNode.size = {
3749
- width: 320,
3750
- height: 200
3751
- };
3752
- const visit = (parent) => {
3753
- const parentPosition = parent.position;
3754
- let nextX = parentPosition.x + 40;
3755
- for (const child of parent.nodes) if (hasFinitePoint(child.position) && hasFiniteSize(child.size)) nextX = Math.max(nextX, child.position.x + child.size.width + NEW_NODE_GAP);
3756
- for (const child of parent.nodes) {
3757
- const childSize = hasFiniteSize(child.size) ? child.size : child.data.type === "annotation" ? { ...DEFAULT_ANNOTATION_SIZE } : { ...DEFAULT_NODE_SIZE };
3758
- child.size = childSize;
3759
- if (!hasFinitePoint(child.position)) {
3760
- child.position = {
3761
- x: nextX,
3762
- y: parentPosition.y + 80
3763
- };
3764
- nextX += childSize.width + NEW_NODE_GAP;
3765
- }
3766
- visit(child);
3767
- }
3768
- };
3769
- visit(rootNode);
3770
- }
3771
- function mergeLocalGraphIntoRemoteDefinition(localGraph, remoteDefinition) {
3772
- const remoteNodesById = collectDigraphNodes(remoteDefinition.rootNode, /* @__PURE__ */ new Map());
3773
- const annotationIds = new Set([...remoteNodesById.values()].filter((node) => node.data.type === "annotation").map((node) => node.id));
3774
- const remoteGraph = fromStudioMachine(remoteDefinition);
3775
- remoteGraph.nodes = remoteGraph.nodes.filter((node) => !annotationIds.has(node.id));
3776
- remoteGraph.edges = remoteGraph.edges.filter((edge) => !annotationIds.has(edge.sourceId) && !annotationIds.has(edge.targetId));
3777
- const { base, compare, summary } = diffGraphsSemantically(remoteGraph, localGraph);
3778
- const remoteNodesBySemanticId = indexBySemanticId(base.nodes, remoteGraph.nodes);
3779
- const remoteEdgesBySemanticId = indexBySemanticId(base.edges, remoteGraph.edges);
3780
- const merged = structuredClone(localGraph);
3781
- const remoteNodeIdByLocalId = /* @__PURE__ */ new Map();
3782
- const remoteEdgeIdByLocalId = /* @__PURE__ */ new Map();
3783
- merged.nodes.forEach((node, index) => {
3784
- const semanticId = compare.nodes[index]?.id;
3785
- const remote = semanticId ? remoteNodesBySemanticId.get(semanticId) : void 0;
3786
- if (!remote) return;
3787
- remoteNodeIdByLocalId.set(node.id, remote.id);
3788
- carryGeometry(node, remote);
3789
- if (node.data.color === void 0 && remote.data?.color !== void 0) node.data.color = remote.data.color;
3790
- });
3791
- merged.edges.forEach((edge, index) => {
3792
- const semanticId = compare.edges[index]?.id;
3793
- const remote = semanticId ? remoteEdgesBySemanticId.get(semanticId) : void 0;
3794
- if (!remote) return;
3795
- remoteEdgeIdByLocalId.set(edge.id, remote.id);
3796
- carryGeometry(edge, remote);
3797
- if (edge.data.color === void 0 && remote.data?.color !== void 0) edge.data.color = remote.data.color;
3798
- });
3799
- const definition = toStudioMachine(merged);
3800
- restoreNodeFields(definition.rootNode, remoteNodesById, remoteNodeIdByLocalId);
3801
- restoreEdgeFields(definition.edges, new Map(remoteDefinition.edges.map((edge) => [edge.id, edge])), remoteEdgeIdByLocalId);
3802
- ensureCompleteNodeGeometry(definition.rootNode);
3803
- return {
3804
- definition: {
3805
- ...remoteDefinition,
3806
- ...definition,
3807
- context: remoteDefinition.context
3808
- },
3809
- summary
3810
- };
3811
- }
3812
- function isRecord(value) {
3813
- return typeof value === "object" && value !== null && !Array.isArray(value);
3814
- }
3815
- function isDigraphNodeConfig(value) {
3816
- if (!isRecord(value) || typeof value.id !== "string") return false;
3817
- if (!isRecord(value.data) || typeof value.data.key !== "string") return false;
3818
- if (!Array.isArray(value.data.entry) || !Array.isArray(value.data.exit) || !Array.isArray(value.data.invoke) || !Array.isArray(value.data.tags) || !Array.isArray(value.nodes)) return false;
3819
- return value.nodes.every(isDigraphNodeConfig);
3820
- }
3821
- function isDigraphEdgeConfig(value) {
3822
- return isRecord(value) && typeof value.id === "string" && typeof value.source === "string" && (value.target === void 0 || typeof value.target === "string") && isRecord(value.data) && isRecord(value.data.eventTypeData) && Array.isArray(value.data.actions);
3823
- }
3824
- function isDigraphConfig(value) {
3825
- if (!isRecord(value) || typeof value.id !== "string" || !isDigraphNodeConfig(value.rootNode) || !Array.isArray(value.edges) || !value.edges.every(isDigraphEdgeConfig)) return false;
3826
- if (value.implementations !== void 0) {
3827
- if (!isRecord(value.implementations)) return false;
3828
- if (!isRecord(value.implementations.actions) || !isRecord(value.implementations.actors) || !isRecord(value.implementations.guards)) return false;
3829
- }
3830
- return true;
3831
- }
3832
- function requireDigraphConfig(machineId, value) {
3833
- if (!isDigraphConfig(value)) throw new Error(`Cannot safely push machine "${machineId}": its remote definition is invalid.`);
3834
- return value;
3835
- }
3836
- function stableStringify(value) {
3837
- return JSON.stringify(value, (_key, item) => {
3838
- if (isRecord(item)) return Object.fromEntries(Object.entries(item).sort(([left], [right]) => left.localeCompare(right)));
3839
- return item;
3840
- });
3841
- }
3842
- function definitionsMatch(left, right) {
3843
- return stableStringify(left) === stableStringify(right);
3844
- }
3845
- async function updateMachineDefinition(client, machineId, localGraph) {
3846
- if (typeof client.machines?.get !== "function") return client.machines.update({
3847
- id: machineId,
3848
- definition: toStudioMachine(localGraph)
3849
- });
3850
- let remoteRecord = await client.machines.get(machineId);
3851
- for (let attempt = 0; attempt < MAX_CONCURRENT_MERGE_ATTEMPTS; attempt += 1) {
3852
- const remoteDefinition = requireDigraphConfig(machineId, remoteRecord.definition);
3853
- const mergedDefinition = mergeLocalGraphIntoRemoteDefinition(localGraph, remoteDefinition).definition;
3854
- const latestRecord = await client.machines.get(machineId);
3855
- requireDigraphConfig(machineId, latestRecord.definition);
3856
- if (definitionsMatch(remoteDefinition, latestRecord.definition)) return client.machines.update({
3857
- id: machineId,
3858
- definition: mergedDefinition
3859
- });
3860
- remoteRecord = latestRecord;
3861
- }
3862
- throw new Error(`Cannot safely push machine "${machineId}": its remote definition kept changing during the push. Try again after Studio edits have settled.`);
3863
- }
3864
-
3865
- //#endregion
3866
- //#region src/sync.ts
3867
- const execFileAsync = promisify(execFile);
3868
- const MAX_CAPTURED_LOCAL_MACHINES = 100;
3869
- var PullSourceReconciliationError = class extends Error {
3870
- code = "source_reconciliation_failed";
3871
- constructor(message) {
3872
- super(message);
3873
- this.name = "PullSourceReconciliationError";
3874
- }
3875
- };
3876
- const INLINE_EXPRESSION_FIELD_SET = new Set(INLINE_EXPRESSION_DIRECTIVE_FIELDS);
3877
- async function extractMachinesFromLocalSource(sourcePath, contents, machineIndex) {
3878
- try {
3879
- return { machines: extractMachineConfigsFromAst(sourcePath, parseSourceToMachine(contents, createTextDocument(sourcePath, contents), {
3880
- machineIndex,
3881
- resolver: createFileSourceDocumentResolver()
3882
- }), machineIndex === void 0 ? void 0 : 0) };
3883
- } catch (error) {
3884
- return {
3885
- machines: [],
3886
- error: error instanceof Error ? error.message : String(error)
3887
- };
3888
- }
3889
- }
3890
- function isInvalidLocalMachineDefinitionError(message) {
3891
- return /No initial state specified for compound state node/.test(message) || /Try adding \{\s*initial:\s*['"`]/.test(message);
3892
- }
3893
- function formatLocalMachineExtractionIssue(message) {
3894
- if (isInvalidLocalMachineDefinitionError(message)) return `Invalid local machine definition: ${message}`;
3895
- return `Could not extract a local machine from this file: ${message}`;
3896
- }
3897
- function extractMachineConfigsFromAst(fileName, sourceText, selectedMachineIndex) {
3898
- const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(fileName));
3899
- const bindings = collectLocalBindings(sourceFile);
3900
- const machines = [];
3901
- let currentMachineIndex = 0;
3902
- const visit = (node) => {
3903
- if (selectedMachineIndex === void 0 && machines.length >= MAX_CAPTURED_LOCAL_MACHINES) return;
3904
- if (!ts.isCallExpression(node) || !isCreateMachineExpression(node.expression)) {
3905
- ts.forEachChild(node, visit);
3906
- return;
3907
- }
3908
- const machineIndex = currentMachineIndex;
3909
- currentMachineIndex += 1;
3910
- if (selectedMachineIndex !== void 0 && machineIndex !== selectedMachineIndex) return;
3911
- const [firstArgument] = node.arguments;
3912
- if (!firstArgument || !ts.isExpression(firstArgument)) return;
3913
- const config = evaluateExpression(firstArgument, sourceFile, bindings, /* @__PURE__ */ new Set());
3914
- if (!config || typeof config !== "object" || Array.isArray(config)) return;
3915
- machines.push({
3916
- config,
3917
- _type: ts.isPropertyAccessExpression(unwrapExpression(node.expression)) ? "setup.createMachine" : "createMachine"
3918
- });
3919
- };
3920
- ts.forEachChild(sourceFile, visit);
3921
- return machines;
3922
- }
3923
- function countSourceMachines(fileName, sourceText) {
3924
- const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(fileName));
3925
- let count = 0;
3926
- const visit = (node) => {
3927
- if (ts.isCallExpression(node) && isCreateMachineExpression(node.expression)) count += 1;
3928
- ts.forEachChild(node, visit);
3929
- };
3930
- visit(sourceFile);
3931
- return count;
3932
- }
3933
- function collectLocalBindings(sourceFile) {
3934
- const bindings = /* @__PURE__ */ new Map();
3935
- for (const statement of sourceFile.statements) {
3936
- if (ts.isVariableStatement(statement)) {
3937
- for (const declaration of statement.declarationList.declarations) {
3938
- if (!ts.isIdentifier(declaration.name) || !declaration.initializer) continue;
3939
- bindings.set(declaration.name.text, {
3940
- kind: "value",
3941
- expression: declaration.initializer
3942
- });
3943
- }
3944
- continue;
3945
- }
3946
- if (!ts.isEnumDeclaration(statement)) continue;
3947
- let nextNumericValue = 0;
3948
- for (const member of statement.members) {
3949
- const memberName = getPropertyNameText(member.name);
3950
- if (!memberName) continue;
3951
- const symbol = `${statement.name.text}.${memberName}`;
3952
- if (!member.initializer) {
3953
- bindings.set(symbol, {
3954
- kind: "enumMember",
3955
- value: nextNumericValue
3956
- });
3957
- nextNumericValue += 1;
3958
- continue;
3959
- }
3960
- const value = evaluateExpression(member.initializer, sourceFile, bindings, /* @__PURE__ */ new Set());
3961
- if (typeof value === "string" || typeof value === "number") {
3962
- bindings.set(symbol, {
3963
- kind: "enumMember",
3964
- value
3965
- });
3966
- if (typeof value === "number") nextNumericValue = value + 1;
3967
- }
3968
- }
3969
- }
3970
- return bindings;
3971
- }
3972
- function evaluateExpression(expression, sourceFile, bindings, seenBindings) {
3973
- const unwrapped = unwrapExpression(expression);
3974
- if (ts.isStringLiteral(unwrapped) || ts.isNoSubstitutionTemplateLiteral(unwrapped)) return unwrapped.text;
3975
- if (ts.isNumericLiteral(unwrapped)) return Number(unwrapped.text);
3976
- if (unwrapped.kind === ts.SyntaxKind.TrueKeyword) return true;
3977
- if (unwrapped.kind === ts.SyntaxKind.FalseKeyword) return false;
3978
- if (unwrapped.kind === ts.SyntaxKind.NullKeyword) return null;
3979
- if (ts.isIdentifier(unwrapped)) {
3980
- if (unwrapped.text === "undefined") return;
3981
- const binding = bindings.get(unwrapped.text);
3982
- if (!binding || binding.kind !== "value" || seenBindings.has(unwrapped.text)) return unwrapped.getText(sourceFile);
3983
- const nextSeen = new Set(seenBindings);
3984
- nextSeen.add(unwrapped.text);
3985
- return evaluateExpression(binding.expression, sourceFile, bindings, nextSeen);
3986
- }
3987
- if (ts.isPropertyAccessExpression(unwrapped) && ts.isIdentifier(unwrapped.expression)) {
3988
- const binding = bindings.get(`${unwrapped.expression.text}.${unwrapped.name.text}`);
3989
- if (binding?.kind === "enumMember") return binding.value;
3990
- return unwrapped.getText(sourceFile);
3991
- }
3992
- if (ts.isArrayLiteralExpression(unwrapped)) return unwrapped.elements.map((element) => ts.isSpreadElement(element) ? evaluateExpression(element.expression, sourceFile, bindings, seenBindings) : evaluateExpression(element, sourceFile, bindings, seenBindings));
3993
- if (ts.isObjectLiteralExpression(unwrapped)) {
3994
- const result = {};
3995
- for (const property of unwrapped.properties) {
3996
- if (ts.isSpreadAssignment(property)) {
3997
- const spreadValue = evaluateExpression(property.expression, sourceFile, bindings, seenBindings);
3998
- if (spreadValue && typeof spreadValue === "object" && !Array.isArray(spreadValue)) Object.assign(result, spreadValue);
3999
- continue;
4000
- }
4001
- if (ts.isShorthandPropertyAssignment(property)) {
4002
- result[property.name.text] = evaluateExpression(property.name, sourceFile, bindings, seenBindings);
4003
- continue;
4004
- }
4005
- if (!ts.isPropertyAssignment(property)) continue;
4006
- const key = resolvePropertyNameValue(property.name, sourceFile, bindings, seenBindings);
4007
- if (key == null) continue;
4008
- const fieldName = String(key);
4009
- if (shouldPreserveInlineExpression(fieldName, property.initializer, sourceFile, bindings, seenBindings)) {
4010
- result[fieldName] = createInlineExpressionDirective(property.initializer.getText(sourceFile));
4011
- continue;
4012
- }
4013
- result[fieldName] = evaluateExpression(property.initializer, sourceFile, bindings, seenBindings);
4014
- }
4015
- return result;
4016
- }
4017
- if (ts.isPrefixUnaryExpression(unwrapped)) {
4018
- const operand = evaluateExpression(unwrapped.operand, sourceFile, bindings, seenBindings);
4019
- if (typeof operand !== "number") return unwrapped.getText(sourceFile);
4020
- switch (unwrapped.operator) {
4021
- case ts.SyntaxKind.MinusToken: return -operand;
4022
- case ts.SyntaxKind.PlusToken: return operand;
4023
- default: return unwrapped.getText(sourceFile);
4024
- }
4025
- }
4026
- if (ts.isTemplateExpression(unwrapped)) {
4027
- let value = unwrapped.head.text;
4028
- for (const span of unwrapped.templateSpans) {
4029
- const expressionValue = evaluateExpression(span.expression, sourceFile, bindings, seenBindings);
4030
- value += String(expressionValue ?? "");
4031
- value += span.literal.text;
4032
- }
4033
- return value;
4034
- }
4035
- return unwrapped.getText(sourceFile);
4036
- }
4037
- function shouldPreserveInlineExpression(fieldName, expression, sourceFile, bindings, seenBindings) {
4038
- if (!INLINE_EXPRESSION_FIELD_SET.has(fieldName)) return false;
4039
- const unwrapped = unwrapExpression(expression);
4040
- if (ts.isIdentifier(unwrapped)) {
4041
- const binding = bindings.get(unwrapped.text);
4042
- if (!binding || binding.kind !== "value" || seenBindings.has(unwrapped.text)) return true;
4043
- const nextSeen = new Set(seenBindings);
4044
- nextSeen.add(unwrapped.text);
4045
- return shouldPreserveInlineExpression(fieldName, binding.expression, sourceFile, bindings, nextSeen);
4046
- }
4047
- if (ts.isStringLiteral(unwrapped) || ts.isNoSubstitutionTemplateLiteral(unwrapped) || ts.isNumericLiteral(unwrapped) || unwrapped.kind === ts.SyntaxKind.TrueKeyword || unwrapped.kind === ts.SyntaxKind.FalseKeyword || unwrapped.kind === ts.SyntaxKind.NullKeyword || ts.isObjectLiteralExpression(unwrapped) || ts.isArrayLiteralExpression(unwrapped)) return false;
4048
- return unwrapped.getText(sourceFile).trim().length > 0;
4049
- }
4050
- function createInlineExpressionDirective(expr) {
4051
- return {
4052
- "@type": "code",
4053
- lang: "ts",
4054
- expr
4055
- };
4056
- }
4057
- function resolvePropertyNameValue(name, sourceFile, bindings, seenBindings) {
4058
- if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
4059
- if (!ts.isComputedPropertyName(name)) return null;
4060
- const value = evaluateExpression(name.expression, sourceFile, bindings, seenBindings);
4061
- if (typeof value === "string" || typeof value === "number") return value;
4062
- return name.getText(sourceFile);
4063
- }
4064
- function isCreateMachineExpression(expression) {
4065
- const unwrapped = unwrapExpression(expression);
4066
- return ts.isIdentifier(unwrapped) && unwrapped.text === "createMachine" || ts.isPropertyAccessExpression(unwrapped) && unwrapped.name.text === "createMachine";
4067
- }
4068
- function unwrapExpression(expression) {
4069
- let current = expression;
4070
- for (;;) {
4071
- if (ts.isParenthesizedExpression(current)) {
4072
- current = current.expression;
4073
- continue;
4074
- }
4075
- if (ts.isAsExpression(current) || ts.isSatisfiesExpression(current)) {
4076
- current = current.expression;
4077
- continue;
4078
- }
4079
- if (ts.isTypeAssertionExpression(current) || ts.isNonNullExpression(current)) {
4080
- current = current.expression;
4081
- continue;
4082
- }
4083
- return current;
4084
- }
4085
- }
4086
- function getPropertyNameText(name) {
4087
- if (ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) return name.text;
4088
- return null;
4089
- }
4090
- function getScriptKind(fileName) {
4091
- if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
4092
- if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
4093
- if (fileName.endsWith(".js")) return ts.ScriptKind.JS;
4094
- return ts.ScriptKind.TS;
4095
- }
4096
- function isUrl(value) {
4097
- try {
4098
- const url = new URL(value);
4099
- return url.protocol === "http:" || url.protocol === "https:";
4100
- } catch {
4101
- return false;
4102
- }
4103
- }
4104
- async function fileExists(filePath) {
4105
- try {
4106
- await fs.access(filePath);
4107
- return true;
4108
- } catch {
4109
- return false;
4110
- }
4111
- }
4112
- function parseGitHubRemote(remoteUrl) {
4113
- const httpsMatch = remoteUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
4114
- if (httpsMatch) {
4115
- const [, owner, repo] = httpsMatch;
4116
- if (!owner || !repo) return null;
4117
- return {
4118
- url: `https://github.com/${owner}/${repo}`,
4119
- owner,
4120
- repo
4121
- };
4122
- }
4123
- const sshMatch = remoteUrl.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/);
4124
- if (sshMatch) {
4125
- const [, owner, repo] = sshMatch;
4126
- if (!owner || !repo) return null;
4127
- return {
4128
- url: `https://github.com/${owner}/${repo}`,
4129
- owner,
4130
- repo
4131
- };
4132
- }
4133
- return null;
4134
- }
4135
- async function inferConnectedRepo(filePath, cwd) {
4136
- const workingDir = cwd ?? path.dirname(filePath);
4137
- try {
4138
- const [{ stdout: repoRootStdout }, { stdout: remoteStdout }, { stdout: branchStdout }, { stdout: treeShaStdout }] = await Promise.all([
4139
- execFileAsync("git", ["rev-parse", "--show-toplevel"], { cwd: workingDir }),
4140
- execFileAsync("git", [
4141
- "remote",
4142
- "get-url",
4143
- "origin"
4144
- ], { cwd: workingDir }),
4145
- execFileAsync("git", ["branch", "--show-current"], { cwd: workingDir }),
4146
- execFileAsync("git", ["rev-parse", "HEAD"], { cwd: workingDir })
4147
- ]);
4148
- const repoRoot = repoRootStdout.trim();
4149
- const remote = parseGitHubRemote(remoteStdout.trim());
4150
- const branch = branchStdout.trim();
4151
- const treeSha = treeShaStdout.trim();
4152
- if (!remote || !branch || !treeSha) return;
4153
- const relativePath = path.relative(repoRoot, filePath).replace(/\\/g, "/");
4154
- const relativeDir = path.dirname(relativePath).replace(/\\/g, "/");
4155
- const selectedPaths = relativePath && relativePath !== "." ? [relativePath] : [];
4156
- return {
4157
- ...remote,
4158
- branch,
4159
- treeSha,
4160
- autoSync: false,
4161
- pathForNewFiles: relativeDir && relativeDir !== "." ? relativeDir : "src/stately-studio",
4162
- selectedPaths
4163
- };
4164
- } catch {
4165
- return;
4166
- }
4167
- }
4168
- function normalizeActions(value) {
4169
- if (value == null) return [];
4170
- return (Array.isArray(value) ? value : [value]).map((item) => {
4171
- if (typeof item === "string") return { type: item };
4172
- if (typeof item === "object" && item !== null && "type" in item) {
4173
- const type = item.type;
4174
- const params = "params" in item && typeof item.params === "object" && item.params ? item.params : void 0;
4175
- return {
4176
- type,
4177
- ...params ? { params } : {}
4178
- };
4179
- }
4180
- return { type: String(item) };
4181
- });
4182
- }
4183
- function normalizeTags(value) {
4184
- if (!value) return [];
4185
- if (Array.isArray(value)) return value.map((tag) => String(tag));
4186
- return [String(value)];
4187
- }
4188
- function normalizeInvoke(value) {
4189
- if (!value) return [];
4190
- return (Array.isArray(value) ? value : [value]).map((invoke, index) => ({
4191
- src: invoke.src,
4192
- id: invoke.id ?? `invoke[${index}]`,
4193
- ...invoke.input ? { input: invoke.input } : {}
4194
- }));
4195
- }
4196
- function resolveTargetId(sourceParentPath, target) {
4197
- if (!target) return;
4198
- if (target.startsWith("#")) {
4199
- const stripped = target.slice(1);
4200
- const machineIndex = stripped.indexOf(".");
4201
- if (machineIndex >= 0) return `(machine).${stripped.slice(machineIndex + 1)}`;
4202
- return `(machine).${stripped}`;
4203
- }
4204
- if (target.startsWith("(machine)")) return target;
4205
- if (target.includes(".")) return `(machine).${target}`;
4206
- return `${sourceParentPath}.${target}`;
4207
- }
4208
- function appendTransitionEdges(edges, sourceId, sourceParentPath, eventType, transition, edgeCounts) {
4209
- const transitions = Array.isArray(transition) ? transition : [transition];
4210
- for (const item of transitions) {
4211
- const normalized = typeof item === "string" ? { target: item } : item;
4212
- const targetId = resolveTargetId(sourceParentPath, Array.isArray(normalized.target) ? normalized.target[0] : normalized.target);
4213
- const groupKey = `${sourceId}:${eventType}`;
4214
- const index = edgeCounts.get(groupKey) ?? 0;
4215
- edgeCounts.set(groupKey, index + 1);
4216
- edges.push({
4217
- type: "edge",
4218
- id: `${sourceId}#${eventType}[${index}]`,
4219
- sourceId,
4220
- targetId: targetId ?? sourceId,
4221
- label: eventType,
4222
- data: {
4223
- eventType,
4224
- transitionType: normalized.reenter === true ? "reenter" : normalized.internal === true || !targetId ? "targetless" : "normal",
4225
- ...normalized.guard ? { guard: typeof normalized.guard === "string" ? { type: normalized.guard } : {
4226
- type: normalized.guard.type,
4227
- ...normalized.guard.params ? { params: normalized.guard.params } : {}
4228
- } } : {},
4229
- actions: normalizeActions(normalized.actions),
4230
- ...normalized.description ? { description: normalized.description } : {}
4231
- }
4232
- });
4233
- }
4234
- }
4235
- function fromXStateConfig(config) {
4236
- const nodes = [];
4237
- const edges = [];
4238
- const edgeCounts = /* @__PURE__ */ new Map();
4239
- function visitNode(key, nodeConfig, parentId, parentPath) {
4240
- const nodeId = parentPath ? `${parentPath}.${key}` : "(machine)";
4241
- const currentPath = parentPath ? nodeId : "(machine)";
4242
- const initialId = nodeConfig.initial ? `${currentPath}.${nodeConfig.initial}` : void 0;
4243
- nodes.push({
4244
- type: "node",
4245
- id: nodeId,
4246
- parentId,
4247
- label: key,
4248
- ...initialId ? { initialNodeId: initialId } : {},
4249
- data: {
4250
- key,
4251
- ...nodeConfig.type ? { type: nodeConfig.type } : {},
4252
- ...nodeConfig.history ? { history: nodeConfig.history } : {},
4253
- ...initialId ? { initialId } : {},
4254
- entry: normalizeActions(nodeConfig.entry),
4255
- exit: normalizeActions(nodeConfig.exit),
4256
- invokes: normalizeInvoke(nodeConfig.invoke),
4257
- tags: normalizeTags(nodeConfig.tags),
4258
- ...nodeConfig.description ? { description: nodeConfig.description } : {}
4259
- }
4260
- });
4261
- for (const [eventType, transition] of Object.entries(nodeConfig.on ?? {})) appendTransitionEdges(edges, nodeId, parentPath ?? "(machine)", eventType, transition, edgeCounts);
4262
- if (nodeConfig.always) appendTransitionEdges(edges, nodeId, parentPath ?? "(machine)", "", nodeConfig.always, edgeCounts);
4263
- for (const [childKey, childConfig] of Object.entries(nodeConfig.states ?? {})) visitNode(childKey, childConfig, nodeId, currentPath);
4264
- }
4265
- visitNode("(machine)", config, null, null);
4266
- return {
4267
- id: config.id ?? "machine",
4268
- nodes,
4269
- edges,
4270
- data: {}
4271
- };
4272
- }
4273
- async function pushLocalMachineLinks(options) {
4274
- const client = options.client ?? createStatelyClient({
4275
- apiKey: options.apiKey,
4276
- baseUrl: options.baseUrl,
4277
- fetch: options.fetch
4278
- });
4279
- const sourcePath = path.resolve(options.cwd ?? process.cwd(), options.source);
4280
- const project = await resolvePushProject(client, sourcePath, options);
4281
- if (!project.projectVersionId) throw new Error("Resolved project is missing projectVersionId.");
4282
- const contents = await fs.readFile(sourcePath, "utf8");
4283
- const attachments = findStatelyPragmaAttachments(contents, sourcePath);
4284
- const extracted = await extractMachinesFromLocalSource(sourcePath, contents);
4285
- if (attachments.length === 0 || extracted.machines.length === 0) return {
4286
- sourcePath,
4287
- project,
4288
- created: [],
4289
- updated: [],
4290
- skipped: [{
4291
- machineIndex: 0,
4292
- reason: extracted.error != null ? formatLocalMachineExtractionIssue(extracted.error) : "No local machines were discovered in this file."
4293
- }]
4294
- };
4295
- if (attachments.length !== extracted.machines.length) return {
4296
- sourcePath,
4297
- project,
4298
- created: [],
4299
- updated: [],
4300
- skipped: [{
4301
- machineIndex: 0,
4302
- reason: "The local machine extractor did not align with the source attachments for this file."
4303
- }]
4304
- };
4305
- let nextContents = contents;
4306
- let outputPath;
4307
- const created = [];
4308
- const updated = [];
4309
- const skipped = [];
4310
- for (const [machineIndex, attachment] of attachments.entries()) {
4311
- const extractedMachine = extracted.machines[machineIndex];
4312
- if (!extractedMachine?.config) {
4313
- skipped.push({
4314
- machineIndex,
4315
- reason: "No extracted machine config was available for this source."
4316
- });
4317
- continue;
4318
- }
4319
- if (attachment.pragma?.id && !options.relink) {
4320
- const localGraph = fromXStateConfig(extractedMachine.config);
4321
- try {
4322
- const updatedMachine = await updateMachineDefinition(client, attachment.pragma.id, localGraph);
4323
- updated.push({
4324
- machineIndex,
4325
- machine: updatedMachine
4326
- });
4327
- } catch (error) {
4328
- skipped.push({
4329
- machineIndex,
4330
- reason: error instanceof Error ? error.message : String(error)
4331
- });
4332
- }
4333
- continue;
4334
- }
4335
- const machine = await client.machines.create({
4336
- projectVersionId: project.projectVersionId,
4337
- definition: toStudioMachine(fromXStateConfig(extractedMachine.config)),
4338
- xstateVersion: Math.max(5, options.xstateVersion ?? 5)
4339
- });
4340
- nextContents = upsertStatelyPragma(nextContents, machine.id, {
4341
- fileName: sourcePath,
4342
- machineIndex
4343
- });
4344
- created.push({
4345
- machineIndex,
4346
- machine
4347
- });
4348
- }
4349
- if (nextContents !== contents) {
4350
- await fs.writeFile(sourcePath, nextContents, "utf8");
4351
- outputPath = sourcePath;
4352
- }
4353
- return {
4354
- sourcePath,
4355
- project,
4356
- created,
4357
- updated,
4358
- skipped,
4359
- ...outputPath ? { outputPath } : {}
4360
- };
4361
- }
4362
- async function resolveLocalFile(locator, options, machineIndex = 0) {
4363
- const filePath = path.resolve(options.cwd ?? process.cwd(), locator);
4364
- const contents = await fs.readFile(filePath, "utf8");
4365
- const extension = path.extname(filePath).toLowerCase();
4366
- if (extension === ".ts" || extension === ".tsx" || extension === ".js" || extension === ".jsx") {
4367
- const localExtraction = await extractMachinesFromLocalSource(filePath, contents, machineIndex);
4368
- let config = localExtraction.machines[0]?.config;
4369
- const extractionIssue = localExtraction.error;
4370
- if (!config) {
4371
- const extracted = await (options.client ?? createStatelyClient({
4372
- apiKey: options.apiKey,
4373
- baseUrl: options.baseUrl,
4374
- fetch: options.fetch
4375
- })).code.extractMachines(contents);
4376
- const indexedMachine = extracted.machines.find((machine) => machine.machineIndex === machineIndex);
4377
- config = extracted.machines.some((machine) => machine.machineIndex !== void 0) ? indexedMachine?.config : extracted.machines[machineIndex]?.config;
4378
- }
4379
- if (!config) throw new Error(extractionIssue ? `No machines extracted from ${filePath}: ${formatLocalMachineExtractionIssue(extractionIssue)}` : `No machine at index ${machineIndex} was extracted from ${filePath}`);
4380
- return {
4381
- kind: "local-file",
4382
- locator: filePath,
4383
- format: "xstate",
4384
- graph: fromXStateConfig(config)
4385
- };
4386
- }
4387
- const parsed = JSON.parse(contents);
4388
- if ("rootNode" in parsed && "edges" in parsed) return {
4389
- kind: "local-file",
4390
- locator: filePath,
4391
- format: "digraph",
4392
- graph: fromStudioMachine(parsed)
4393
- };
4394
- if ("nodes" in parsed && "edges" in parsed) return {
4395
- kind: "local-file",
4396
- locator: filePath,
4397
- format: "graph",
4398
- graph: parsed
4399
- };
4400
- if ("states" in parsed) return {
4401
- kind: "local-file",
4402
- locator: filePath,
4403
- format: "xstate",
4404
- graph: fromXStateConfig(parsed)
4405
- };
4406
- throw new Error(`Unsupported local sync input: ${filePath}`);
4407
- }
4408
- function inferWritableTargetFormat(filePath) {
4409
- if (filePath.endsWith(".ts") || filePath.endsWith(".tsx") || filePath.endsWith(".js") || filePath.endsWith(".jsx")) return "xstate";
4410
- if (filePath.endsWith(".digraph.json")) return "digraph";
4411
- if (filePath.endsWith(".graph.json")) return "graph";
4412
- return null;
4413
- }
4414
- function resolveLocalXStateMachineId(graph) {
4415
- const rootKey = (graph.nodes.find((node) => node.parentId == null) ?? null)?.data?.key;
4416
- if (rootKey && rootKey !== "(machine)") return rootKey;
4417
- return graph.id;
4418
- }
4419
- function serializeGraph(graph, format, options = {}) {
4420
- switch (format) {
4421
- case "digraph": return `${JSON.stringify(toStudioMachine(graph), null, 2)}\n`;
4422
- case "graph": return `${JSON.stringify(graph, null, 2)}\n`;
4423
- case "xstate": {
4424
- const targetLanguage = inferXStateTargetLanguage(options.targetPath);
4425
- const source = graphToXStateTS({
4426
- ...graph,
4427
- id: resolveLocalXStateMachineId(graph)
4428
- }, { targetLanguage });
4429
- if (!options.remoteMachineId) return source;
4430
- return upsertStatelyPragma(source, options.remoteMachineId, options.targetPath ? { fileName: options.targetPath } : {});
4431
- }
4432
- default: {
4433
- const exhaustive = format;
4434
- throw new Error(`Unsupported sync output format: ${exhaustive}`);
4435
- }
4436
- }
4437
- }
4438
- function inferXStateTargetLanguage(targetPath) {
4439
- if (!targetPath) return "typescript";
4440
- return /\.(?:c|m)?jsx?$/i.test(targetPath) ? "javascript" : "typescript";
4441
- }
4442
- async function resolveRemoteMachine(machineId, baseUrl, kind, locator, options) {
4443
- const digraph = (await (options.client ?? createStatelyClient({
4444
- apiKey: options.apiKey,
4445
- baseUrl,
4446
- fetch: options.fetch
4447
- })).machines.get(machineId)).definition;
4448
- return {
4449
- kind,
4450
- locator,
4451
- format: "digraph",
4452
- graph: fromStudioMachine(digraph),
4453
- remoteMachineId: machineId
4454
- };
4455
- }
4456
- async function resolveSyncInput(locator, options) {
4457
- if (await fileExists(path.resolve(options.cwd ?? process.cwd(), locator))) return resolveLocalFile(locator, options);
4458
- if (isUrl(locator)) {
4459
- const url = new URL(locator);
4460
- const machineId = url.pathname.split("/").filter(Boolean).at(-1);
4461
- if (!machineId) throw new Error(`Could not resolve machine ID from URL: ${locator}`);
4462
- return resolveRemoteMachine(machineId, url.origin, "studio-url", locator, options);
4463
- }
4464
- return resolveRemoteMachine(locator, options.baseUrl, "studio-machine-id", locator, options);
4465
- }
4466
- function summarizeDiff(diff) {
4467
- const nodeChanges = diff.nodes.added.length + diff.nodes.removed.length + diff.nodes.updated.length;
4468
- const edgeChanges = diff.edges.added.length + diff.edges.removed.length + diff.edges.updated.length;
4469
- return {
4470
- hasChanges: !isEmptyDiff(diff),
4471
- nodeChanges,
4472
- edgeChanges
4473
- };
4474
- }
4475
- async function planSync(options) {
4476
- const source = await resolveSyncInput(options.source, options);
4477
- const target = await resolveSyncInput(options.target, options);
4478
- const { diff } = diffGraphsSemantically(source.graph, target.graph);
4479
- return {
4480
- source,
4481
- target,
4482
- diff,
4483
- summary: summarizeDiff(diff),
4484
- warnings: []
4485
- };
4486
- }
4487
- async function pullSync(options) {
4488
- const source = await resolveSyncInput(options.source, options);
4489
- const outputPath = path.resolve(options.cwd ?? process.cwd(), options.target);
4490
- const fallbackFormat = inferWritableTargetFormat(outputPath);
4491
- let targetFormat = fallbackFormat;
4492
- let existingTarget = null;
4493
- const targetExists = await fileExists(outputPath);
4494
- let machineIndex = options.machineIndex ?? 0;
4495
- if (targetExists && options.machineIndex === void 0 && source.remoteMachineId) {
4496
- const matchingIndex = findStatelyPragmaAttachments(await fs.readFile(outputPath, "utf8"), outputPath).findIndex((attachment) => attachment.pragma?.id === source.remoteMachineId);
4497
- if (matchingIndex >= 0) machineIndex = matchingIndex;
4498
- }
4499
- if (targetExists) try {
4500
- const target = await resolveLocalFile(options.target, options, machineIndex);
4501
- existingTarget = target;
4502
- targetFormat = target.format;
4503
- } catch (error) {
4504
- if (!fallbackFormat) throw error;
4505
- const contents = await fs.readFile(outputPath, "utf8");
4506
- if (fallbackFormat === "xstate" && contents.trim() !== "" && !options.force) throw new PullSourceReconciliationError(`Could not update ${outputPath} surgically: ${error instanceof Error ? error.message : String(error)} Pass --force to replace the file.`);
4507
- }
4508
- 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.`);
4509
- let wroteSurgically = false;
4510
- if (targetFormat === "xstate" && existingTarget?.format === "xstate") {
4511
- const currentSource = await fs.readFile(outputPath, "utf8");
4512
- const document = createTextDocument(outputPath, currentSource);
4513
- let parsedTarget = null;
4514
- try {
4515
- parsedTarget = parseDocumentToMachine(document, {
4516
- machineIndex,
4517
- resolver: createFileSourceDocumentResolver()
4518
- });
4519
- } catch (error) {
4520
- if (!options.force) throw new PullSourceReconciliationError(`Could not update ${outputPath} surgically: ${error instanceof Error ? error.message : String(error)} The source file was left unchanged. Pass --force to replace the file.`);
4521
- }
4522
- if (parsedTarget) {
4523
- const semanticResult = diffGraphsSemantically(existingTarget.graph, source.graph);
4524
- const alignedSource = alignCompareGraphIds(existingTarget.graph, source.graph, semanticResult.base, semanticResult.compare);
4525
- const patchResult = graphChangeToPatchesResult(existingTarget.graph, alignedSource);
4526
- const patches = patchResult.patches;
4527
- if (patchResult.unsupportedChanges.length > 0) {
4528
- if (!options.force) throw new PullSourceReconciliationError(`Could not update ${outputPath} surgically: ${patchResult.unsupportedChanges.join(" ")} The source file was left unchanged. Pass --force to replace the file.`);
4529
- } else if (patches.length > 0) {
4530
- const replacements = applyMachineToSource(graphToMachineConfig(alignedSource), document, {
4531
- patches,
4532
- prevGraph: existingTarget.graph,
4533
- nextGraph: alignedSource,
4534
- sourceLocations: parsedTarget.sourceLocations,
4535
- machineIndex
4536
- });
4537
- if (replacements.length === 0) {
4538
- if (!options.force) throw new PullSourceReconciliationError(`Could not write remote changes to ${outputPath}: source reconciliation produced no replacements. The source file was left unchanged. Pass --force to replace the file.`);
4539
- } else {
4540
- let updatedSource = applyReplacementsToText(currentSource, replacements);
4541
- if (source.remoteMachineId) updatedSource = upsertStatelyPragma(updatedSource, source.remoteMachineId, {
4542
- fileName: outputPath,
4543
- machineIndex
4544
- });
4545
- await fs.writeFile(outputPath, updatedSource, "utf8");
4546
- wroteSurgically = true;
4547
- }
4548
- } else {
4549
- const updatedSource = source.remoteMachineId ? upsertStatelyPragma(currentSource, source.remoteMachineId, {
4550
- fileName: outputPath,
4551
- machineIndex
4552
- }) : currentSource;
4553
- if (updatedSource !== currentSource) await fs.writeFile(outputPath, updatedSource, "utf8");
4554
- wroteSurgically = true;
4555
- }
4556
- }
4557
- }
4558
- if (!wroteSurgically) {
4559
- if (targetFormat === "xstate" && targetExists) {
4560
- const machineCount = countSourceMachines(outputPath, await fs.readFile(outputPath, "utf8"));
4561
- if (machineCount > 1) throw new PullSourceReconciliationError(`Could not update ${outputPath} surgically, and full regeneration would remove the other ${machineCount - 1} machine(s) in this file. The source file was left unchanged.`);
4562
- }
4563
- const serialized = serializeGraph(source.graph, targetFormat, {
4564
- remoteMachineId: source.remoteMachineId,
4565
- targetPath: outputPath
4566
- });
4567
- await fs.writeFile(outputPath, serialized, "utf8");
4568
- }
4569
- return {
4570
- source,
4571
- target: {
4572
- kind: "local-file",
4573
- locator: outputPath,
4574
- format: targetFormat,
4575
- graph: source.graph
4576
- },
4577
- outputPath
4578
- };
4579
- }
4580
- function inferDefaultProjectName(sourcePath, repo) {
4581
- if (repo?.repo) return repo.repo;
4582
- const parentDir = path.basename(path.dirname(sourcePath));
4583
- if (parentDir && parentDir !== ".") return parentDir;
4584
- return path.basename(sourcePath, path.extname(sourcePath));
4585
- }
4586
- async function resolvePushProject(client, sourcePath, options) {
4587
- const explicitProject = options.project;
4588
- if (explicitProject?.projectId) return client.projects.get(explicitProject.projectId);
4589
- if (explicitProject?.projectVersionId) {
4590
- const matchedProject = (await client.projects.list()).find((candidate) => candidate.projectVersionId === explicitProject.projectVersionId);
4591
- if (!matchedProject) throw new Error(`No project found for projectVersionId "${explicitProject.projectVersionId}".`);
4592
- return client.projects.get(matchedProject.projectId);
4593
- }
4594
- const inferredRepo = explicitProject?.repo ?? await inferConnectedRepo(sourcePath, options.cwd);
4595
- const projectInput = {
4596
- name: explicitProject?.name ?? inferDefaultProjectName(sourcePath, inferredRepo),
4597
- visibility: explicitProject?.visibility ?? "private",
4598
- ...explicitProject?.description ? { description: explicitProject.description } : {},
4599
- ...explicitProject?.keywords ? { keywords: explicitProject.keywords } : {},
4600
- ...inferredRepo ? { repo: inferredRepo } : {}
4601
- };
4602
- return client.projects.ensure(projectInput);
4603
- }
4604
- async function pushSync(options) {
4605
- const client = options.client ?? createStatelyClient({
4606
- apiKey: options.apiKey,
4607
- baseUrl: options.baseUrl,
4608
- fetch: options.fetch
4609
- });
4610
- const source = await resolveSyncInput(options.source, {
4611
- ...options,
4612
- target: options.source
4613
- });
4614
- if (source.kind !== "local-file") throw new Error("pushSync currently requires a local source file.");
4615
- const sourcePath = source.locator;
4616
- const project = await resolvePushProject(client, sourcePath, options);
4617
- const existingMachineId = source.format === "xstate" ? getStatelyPragma(await fs.readFile(sourcePath, "utf8"), sourcePath)?.id : void 0;
4618
- let machine;
4619
- if (existingMachineId) machine = await updateMachineDefinition(client, existingMachineId, source.graph);
4620
- else {
4621
- if (!project.projectVersionId) throw new Error("Resolved project is missing projectVersionId.");
4622
- machine = await client.machines.create({
4623
- projectVersionId: project.projectVersionId,
4624
- definition: toStudioMachine(source.graph),
4625
- xstateVersion: options.xstateVersion ?? 5
4626
- });
4627
- }
4628
- let outputPath;
4629
- if (source.format === "xstate") {
4630
- const contents = await fs.readFile(sourcePath, "utf8");
4631
- const nextContents = upsertStatelyPragma(contents, machine.id, { fileName: sourcePath });
4632
- if (nextContents !== contents) {
4633
- await fs.writeFile(sourcePath, nextContents, "utf8");
4634
- outputPath = sourcePath;
4635
- }
4636
- }
4637
- return {
4638
- source,
4639
- project,
4640
- machine,
4641
- ...outputPath ? { outputPath } : {}
4642
- };
4643
- }
4644
-
4645
- //#endregion
4646
- export { PullSourceReconciliationError, planSync, pullSync, pushLocalMachineLinks, pushSync };