statelyai 0.12.2 → 0.12.4
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.
- package/README.md +19 -3
- package/dist/bin.mjs +1 -1
- package/dist/{cli-DkgwcbvD.mjs → cli-_FAuSk1y.mjs} +836 -161
- package/dist/index.d.mts +3 -1
- package/dist/index.mjs +1 -1
- package/package.json +4 -4
|
@@ -6877,13 +6877,13 @@ function getDefaultPathId(graph, node) {
|
|
|
6877
6877
|
if (!node.parentId) return getRootEmittedId(graph, node) ?? "(machine)";
|
|
6878
6878
|
const parentNode = graph.nodes.find((candidate) => candidate.id === node.parentId);
|
|
6879
6879
|
if (!parentNode) return node.data.key;
|
|
6880
|
-
return `${
|
|
6880
|
+
return `${getDefaultPathId(graph, parentNode)}.${node.data.key}`;
|
|
6881
6881
|
}
|
|
6882
6882
|
function getEmittedNodeId(graph, node) {
|
|
6883
6883
|
const authored = getAuthoredNodeId(node);
|
|
6884
6884
|
if (!node.parentId) return getRootEmittedId(graph, node);
|
|
6885
6885
|
if (!authored) return void 0;
|
|
6886
|
-
return authored
|
|
6886
|
+
return authored;
|
|
6887
6887
|
}
|
|
6888
6888
|
function getResolvedNodeId(graph, node) {
|
|
6889
6889
|
return getEmittedNodeId(graph, node) ?? getDefaultPathId(graph, node);
|
|
@@ -6908,14 +6908,15 @@ function containsCodeExpression(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
|
6908
6908
|
*/
|
|
6909
6909
|
const VALID_IDENT = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
6910
6910
|
var RawCode = class {
|
|
6911
|
-
constructor(code, sourceValue, sourceSlice) {
|
|
6911
|
+
constructor(code, sourceValue, sourceSlice, preserveWhitespace = false) {
|
|
6912
6912
|
this.code = code;
|
|
6913
6913
|
this.sourceValue = sourceValue;
|
|
6914
6914
|
this.sourceSlice = sourceSlice;
|
|
6915
|
+
this.preserveWhitespace = preserveWhitespace;
|
|
6915
6916
|
}
|
|
6916
6917
|
};
|
|
6917
|
-
function raw(code, sourceValue, sourceSlice) {
|
|
6918
|
-
return new RawCode(code, sourceValue, sourceSlice);
|
|
6918
|
+
function raw(code, sourceValue, sourceSlice, preserveWhitespace = false) {
|
|
6919
|
+
return new RawCode(code, sourceValue, sourceSlice, preserveWhitespace);
|
|
6919
6920
|
}
|
|
6920
6921
|
const SERIALIZED_SOURCE_ID = "__stately_source_id__";
|
|
6921
6922
|
function serializeJS(value, indent = 0, step = 2) {
|
|
@@ -6963,6 +6964,7 @@ function serializeObject(obj, indent, step) {
|
|
|
6963
6964
|
}
|
|
6964
6965
|
function preservesAuthoredWhitespace(value) {
|
|
6965
6966
|
if (isCodeExpression(value)) return true;
|
|
6967
|
+
if (value instanceof RawCode && value.preserveWhitespace) return true;
|
|
6966
6968
|
const sourceValue = value instanceof RawCode ? value.sourceValue : value;
|
|
6967
6969
|
return Boolean(sourceValue && typeof sourceValue === "object" && SERIALIZED_SOURCE_ID in sourceValue);
|
|
6968
6970
|
}
|
|
@@ -7057,7 +7059,7 @@ function resolveTransitionTarget(graph, sourceNode, targetNode) {
|
|
|
7057
7059
|
const keys = [];
|
|
7058
7060
|
let current = targetNode;
|
|
7059
7061
|
while (current) {
|
|
7060
|
-
keys.unshift(current.data.key);
|
|
7062
|
+
keys.unshift(current.data.key.replace(/\\/g, "\\\\").replace(/\./g, "\\."));
|
|
7061
7063
|
if (current.parentId === baseId) {
|
|
7062
7064
|
if (isRootSource) return `.${keys.join(".")}`;
|
|
7063
7065
|
return keys.join(".");
|
|
@@ -7142,13 +7144,13 @@ function deepSimplify(config) {
|
|
|
7142
7144
|
if (config.states && typeof config.states === "object") for (const stateConfig of Object.values(config.states)) deepSimplify(stateConfig);
|
|
7143
7145
|
return config;
|
|
7144
7146
|
}
|
|
7145
|
-
function buildMeta(meta, color) {
|
|
7147
|
+
function buildMeta(meta, color, showStatelyMeta = true) {
|
|
7146
7148
|
if (isCodeExpression(meta)) return meta;
|
|
7147
7149
|
const result = {};
|
|
7148
7150
|
if (meta) {
|
|
7149
|
-
for (const [k, v] of Object.entries(meta)) if (v !== void 0 && v !== null) result[k] = v;
|
|
7151
|
+
for (const [k, v] of Object.entries(meta)) if (v !== void 0 && v !== null && (showStatelyMeta || !k.startsWith("@statelyai"))) result[k] = v;
|
|
7150
7152
|
}
|
|
7151
|
-
if (color) result["@statelyai.color"] = color;
|
|
7153
|
+
if (color && showStatelyMeta) result["@statelyai.color"] = color;
|
|
7152
7154
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
7153
7155
|
}
|
|
7154
7156
|
/** Format event param — supports { type: string } (new) and plain string (legacy) */
|
|
@@ -7444,8 +7446,11 @@ function tagToString(tag) {
|
|
|
7444
7446
|
}
|
|
7445
7447
|
function graphToMachineConfig(graph, options = {}) {
|
|
7446
7448
|
const v6 = isXStateV6Profile(graph.data.profile);
|
|
7447
|
-
const { showDescriptions = true, showMeta = true, inlineGuardsAsTypeRef = false, keepChooseStructured = false } = options;
|
|
7448
|
-
const serializeAction = (action) =>
|
|
7449
|
+
const { showDescriptions = true, showMeta = true, showStatelyMeta = true, inlineGuardsAsTypeRef = false, keepChooseStructured = false, timerActionsAsTypeRef = false } = options;
|
|
7450
|
+
const serializeAction = (action) => timerActionsAsTypeRef && ["xstate.raise", "xstate.cancel"].includes(action.type) ? {
|
|
7451
|
+
type: action.type,
|
|
7452
|
+
params: action.params
|
|
7453
|
+
} : serializeActionItem(action, keepChooseStructured);
|
|
7449
7454
|
const config = {};
|
|
7450
7455
|
function getNodeConfig(node) {
|
|
7451
7456
|
const nodeConfig = node.parentId ? {} : config;
|
|
@@ -7458,7 +7463,15 @@ function graphToMachineConfig(graph, options = {}) {
|
|
|
7458
7463
|
"choice"
|
|
7459
7464
|
].includes(node.data.type) ? node.data.type : void 0;
|
|
7460
7465
|
const tags = node.data.tags;
|
|
7461
|
-
const stateMeta = showMeta ? buildMeta(
|
|
7466
|
+
const stateMeta = showMeta ? buildMeta({
|
|
7467
|
+
...node.data.meta,
|
|
7468
|
+
...node.data.assets?.length ? { "@statelyai.assets": node.data.assets.map(({ type, url, size }) => ({
|
|
7469
|
+
type,
|
|
7470
|
+
url,
|
|
7471
|
+
...size ? { size } : {}
|
|
7472
|
+
})) } : {},
|
|
7473
|
+
...node.data.appearance ? { "@statelyai.appearance": node.data.appearance } : {}
|
|
7474
|
+
}, node.data.color, showStatelyMeta) : void 0;
|
|
7462
7475
|
Object.assign(nodeConfig, {
|
|
7463
7476
|
id: resolvedNodeId,
|
|
7464
7477
|
type: nodeType === "normal" ? void 0 : nodeType ?? void 0,
|
|
@@ -7490,6 +7503,8 @@ function graphToMachineConfig(graph, options = {}) {
|
|
|
7490
7503
|
const edges = graph.edges.filter((edge) => edge.sourceId === node.id && !edge.data.temp);
|
|
7491
7504
|
if (edges.length > 0) {
|
|
7492
7505
|
const on = {};
|
|
7506
|
+
const transitionOrder = /* @__PURE__ */ new Map();
|
|
7507
|
+
const scxmlTransitions = [];
|
|
7493
7508
|
const after = {};
|
|
7494
7509
|
const alwaysArr = [];
|
|
7495
7510
|
const choiceArr = [];
|
|
@@ -7505,7 +7520,15 @@ function graphToMachineConfig(graph, options = {}) {
|
|
|
7505
7520
|
return additionalTarget ? [resolveTransitionTarget(graph, node, additionalTarget)] : [];
|
|
7506
7521
|
})].filter(Boolean);
|
|
7507
7522
|
const type = edge.data.eventType ?? "";
|
|
7508
|
-
const transitionMeta = showMeta ? buildMeta(
|
|
7523
|
+
const transitionMeta = showMeta ? buildMeta({
|
|
7524
|
+
...edge.data.meta,
|
|
7525
|
+
...edge.data.assets?.length ? { "@statelyai.assets": edge.data.assets.map(({ type, url, size }) => ({
|
|
7526
|
+
type,
|
|
7527
|
+
url,
|
|
7528
|
+
...size ? { size } : {}
|
|
7529
|
+
})) } : {},
|
|
7530
|
+
...edge.data.appearance ? { "@statelyai.appearance": edge.data.appearance } : {}
|
|
7531
|
+
}, edge.data.color, showStatelyMeta) : void 0;
|
|
7509
7532
|
const transitionObject = {
|
|
7510
7533
|
...edge.data.matches ? { matches: edge.data.matches } : void 0,
|
|
7511
7534
|
target: edge.data.transitionType === "targetless" ? void 0 : resolvedTargets.length > 1 ? resolvedTargets : `${resolvedTarget}`,
|
|
@@ -7514,9 +7537,10 @@ function graphToMachineConfig(graph, options = {}) {
|
|
|
7514
7537
|
...edge.data.context !== void 0 ? { context: edge.data.context } : void 0,
|
|
7515
7538
|
...edge.data.input !== void 0 ? { input: edge.data.input } : void 0,
|
|
7516
7539
|
actions: edge.data.actions?.length ? edge.data.actions.map(serializeAction) : void 0,
|
|
7517
|
-
description: edge.data.description ?? void 0,
|
|
7540
|
+
description: showDescriptions ? edge.data.description ?? void 0 : void 0,
|
|
7518
7541
|
...transitionMeta ? { meta: transitionMeta } : void 0
|
|
7519
7542
|
};
|
|
7543
|
+
transitionOrder.set(transitionObject, transitionOrder.size);
|
|
7520
7544
|
const pushOn = (key) => {
|
|
7521
7545
|
if (!on[key]) on[key] = [];
|
|
7522
7546
|
on[key].push(transitionObject);
|
|
@@ -7559,7 +7583,11 @@ function graphToMachineConfig(graph, options = {}) {
|
|
|
7559
7583
|
const delayKey = getDelayKeyFromEventType(type, edge.sourceId);
|
|
7560
7584
|
if (!after[delayKey]) after[delayKey] = [];
|
|
7561
7585
|
after[delayKey].push(transitionObject);
|
|
7562
|
-
} else if (
|
|
7586
|
+
} else if (edge.data.meta?.["@statelyai.scxml.eventDescriptor"]) scxmlTransitions.push({
|
|
7587
|
+
descriptor: type,
|
|
7588
|
+
transition: transitionObject
|
|
7589
|
+
});
|
|
7590
|
+
else if (type === "*") pushOn("*");
|
|
7563
7591
|
else if (type.startsWith("xstate.done.state")) {
|
|
7564
7592
|
if (!onDone[type]) onDone[type] = [];
|
|
7565
7593
|
onDone[type].push(transitionObject);
|
|
@@ -7570,6 +7598,16 @@ function graphToMachineConfig(graph, options = {}) {
|
|
|
7570
7598
|
else pushOn(type);
|
|
7571
7599
|
} else pushOn(type);
|
|
7572
7600
|
}
|
|
7601
|
+
const descriptorBase = (descriptor) => descriptor.replace(/\.\*$/, "");
|
|
7602
|
+
const scxmlKeys = new Set([...Object.keys(on), ...scxmlTransitions.flatMap(({ descriptor }) => descriptor === "*" ? ["*"] : descriptorBase(descriptor) ? [descriptorBase(descriptor), `${descriptorBase(descriptor)}.*`] : [])]);
|
|
7603
|
+
for (const key of scxmlKeys) {
|
|
7604
|
+
const base = descriptorBase(key);
|
|
7605
|
+
const matching = scxmlTransitions.filter(({ descriptor }) => {
|
|
7606
|
+
const prefix = descriptorBase(descriptor);
|
|
7607
|
+
return descriptor === "*" || base === prefix || base.startsWith(`${prefix}.`);
|
|
7608
|
+
}).map(({ transition }) => transition);
|
|
7609
|
+
on[key] = [...new Set([...on[key] ?? [], ...matching])].sort((a, b) => (transitionOrder.get(a) ?? 0) - (transitionOrder.get(b) ?? 0));
|
|
7610
|
+
}
|
|
7573
7611
|
if (Object.keys(on).length > 0) nodeConfig.on = singleOrArrayRecord(on);
|
|
7574
7612
|
if (Object.keys(after).length > 0) nodeConfig.after = singleOrArrayRecord(after);
|
|
7575
7613
|
if (alwaysArr.length > 0) nodeConfig.always = singleOrArray(alwaysArr);
|
|
@@ -8541,6 +8579,10 @@ function transitionFromValue(value, actions) {
|
|
|
8541
8579
|
}
|
|
8542
8580
|
if (!value || typeof value !== "object" || Array.isArray(value)) return actions.length ? { actions } : null;
|
|
8543
8581
|
const record = { ...value };
|
|
8582
|
+
if ((Array.isArray(record.target) ? record.target : [record.target]).some(isCodeExpression)) record.meta = {
|
|
8583
|
+
...record.meta,
|
|
8584
|
+
[XSTATE_V6_UNRESOLVED_TARGET_META]: true
|
|
8585
|
+
};
|
|
8544
8586
|
if (actions.length) record.actions = mergeActions(Array.isArray(record.actions) ? record.actions : record.actions ? [record.actions] : void 0, actions);
|
|
8545
8587
|
return record;
|
|
8546
8588
|
}
|
|
@@ -8864,7 +8906,7 @@ function omitIdentityTransitionContext(transition, identity) {
|
|
|
8864
8906
|
function normalizeFunctionTransition(fn, bindings, depth) {
|
|
8865
8907
|
if (fn.body && ts.isBlock(fn.body) && hasUnsafeVariableInitializer(fn.body)) return fallbackFunctionTransition(fn);
|
|
8866
8908
|
const branches = ts.isArrowFunction(fn) && !ts.isBlock(fn.body) ? expressionBranches(fn.body, bindings, depth + 1) : fn.body && ts.isBlock(fn.body) ? statementBranches(fn.body.statements, bindings, enqueueParamName(fn)) : [];
|
|
8867
|
-
if (branches.some((branch) => branch.unknown)) return fallbackFunctionTransition(fn);
|
|
8909
|
+
if (branches.some((branch) => branch.unknown || isCodeExpression(branch.result))) return fallbackFunctionTransition(fn);
|
|
8868
8910
|
const contextIdentity = transitionContextIdentity(fn);
|
|
8869
8911
|
const transitions = branches.map((branch) => {
|
|
8870
8912
|
let result = branch.result;
|
|
@@ -9300,6 +9342,7 @@ function expressionToValue(expression, bindings, context = {}, depth = 0) {
|
|
|
9300
9342
|
if (builtIn) return builtIn;
|
|
9301
9343
|
return inlineAction(node);
|
|
9302
9344
|
}
|
|
9345
|
+
if (context.v6 && context.transitionValue) return inlineCodeExpression(resolvedExpressionText(node, bindings));
|
|
9303
9346
|
const callee = node.expression.getText();
|
|
9304
9347
|
const type = callee.includes(".") ? callee.split(".").pop() : callee;
|
|
9305
9348
|
return { type: type === "assign" ? "xstate.assign" : type };
|
|
@@ -10107,8 +10150,9 @@ function mapV6MachineConfig(value, context = {}) {
|
|
|
10107
10150
|
result[key] = mapV6StatesMap(item);
|
|
10108
10151
|
continue;
|
|
10109
10152
|
}
|
|
10110
|
-
if (key === "choice") {
|
|
10111
|
-
|
|
10153
|
+
if (key === "choice" && value.type === "choice") {
|
|
10154
|
+
const choices = Array.isArray(item) ? item : [item];
|
|
10155
|
+
result[key] = choices.length === 1 && opaqueTransitionSource(choices[0]) !== void 0 ? toV6TransitionValue(item) : buildV6TransitionFunction(choices.map(withoutOpaqueTransitionMeta), true) ?? toV6TransitionValue(item);
|
|
10112
10156
|
continue;
|
|
10113
10157
|
}
|
|
10114
10158
|
if (key === "entry" || key === "exit" || key === "actions") {
|
|
@@ -10140,10 +10184,44 @@ function mapV6TransitionMap(value) {
|
|
|
10140
10184
|
for (const [key, item] of Object.entries(value)) result[key] = mapV6MachineConfig(item, { transitionValue: true });
|
|
10141
10185
|
return result;
|
|
10142
10186
|
}
|
|
10187
|
+
/**
|
|
10188
|
+
* The authored source of a transition function the importer could not
|
|
10189
|
+
* analyze. It projects to one opaque edge, so the source is still exactly what
|
|
10190
|
+
* the edge represents.
|
|
10191
|
+
*/
|
|
10192
|
+
function opaqueTransitionSource(value) {
|
|
10193
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
10194
|
+
const transition = value;
|
|
10195
|
+
const meta = transition.meta;
|
|
10196
|
+
const fnSource = meta?.[XSTATE_V6_FN_SOURCE_META];
|
|
10197
|
+
const hasGraphEdits = Object.entries(transition).some(([key, field]) => key !== "meta" && field !== void 0);
|
|
10198
|
+
return meta?.[XSTATE_V6_FN_TRANSITION_META] === true && typeof fnSource === "string" && !hasGraphEdits ? fnSource : void 0;
|
|
10199
|
+
}
|
|
10200
|
+
function withoutOpaqueTransitionMeta(value) {
|
|
10201
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
10202
|
+
const transition = value;
|
|
10203
|
+
const meta = transition.meta;
|
|
10204
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return value;
|
|
10205
|
+
const { [XSTATE_V6_FN_TRANSITION_META]: _fnTransition, [XSTATE_V6_FN_SOURCE_META]: _fnSource, ...publicMeta } = meta;
|
|
10206
|
+
if (_fnTransition === void 0 && _fnSource === void 0) return value;
|
|
10207
|
+
return {
|
|
10208
|
+
...transition,
|
|
10209
|
+
meta: Object.keys(publicMeta).length > 0 ? publicMeta : void 0
|
|
10210
|
+
};
|
|
10211
|
+
}
|
|
10143
10212
|
function toV6TransitionValue(value) {
|
|
10144
|
-
|
|
10213
|
+
const opaqueSource = opaqueTransitionSource(value);
|
|
10214
|
+
if (opaqueSource !== void 0) return raw(opaqueSource, value, void 0, true);
|
|
10215
|
+
if (Array.isArray(value)) {
|
|
10216
|
+
if (value.length === 1) {
|
|
10217
|
+
const onlyOpaqueSource = opaqueTransitionSource(value[0]);
|
|
10218
|
+
if (onlyOpaqueSource !== void 0) return raw(onlyOpaqueSource, value[0], void 0, true);
|
|
10219
|
+
}
|
|
10220
|
+
const transitions = value.map(withoutOpaqueTransitionMeta);
|
|
10221
|
+
return buildV6TransitionFunction(transitions) ?? transitions.map((item) => toV6TransitionValue(item));
|
|
10222
|
+
}
|
|
10145
10223
|
if (!value || typeof value !== "object") return value;
|
|
10146
|
-
const transition = value;
|
|
10224
|
+
const transition = withoutOpaqueTransitionMeta(value);
|
|
10147
10225
|
if (transition.matches !== void 0) return buildV6TransitionFunction([transition]) ?? mapV6MachineConfig(transition);
|
|
10148
10226
|
if (transition.guard) return buildV6TransitionFunction([transition]) ?? mapV6MachineConfig(transition);
|
|
10149
10227
|
if (transition.description || transition.input !== void 0 && !containsCodeExpression(transition.input)) return mapV6MachineConfig(transition);
|
|
@@ -10294,11 +10372,11 @@ function mergeV6FirstParam(authoredFirstParam, inferred) {
|
|
|
10294
10372
|
prelude: []
|
|
10295
10373
|
};
|
|
10296
10374
|
}
|
|
10297
|
-
function buildV6TransitionFunction(transitions) {
|
|
10375
|
+
function buildV6TransitionFunction(transitions, choice = false) {
|
|
10298
10376
|
const transitionObjects = transitions.every((item) => Boolean(item) && typeof item === "object" && !Array.isArray(item)) ? transitions : void 0;
|
|
10299
10377
|
if (!transitionObjects?.length) return;
|
|
10300
10378
|
const descriptions = transitionObjects.map((transition) => typeof transition.description === "string" ? transition.description : void 0);
|
|
10301
|
-
const hasBranchDescriptions = transitionObjects.some((transition) => Object.prototype.hasOwnProperty.call(transition.meta ?? {}, XSTATE_V6_BRANCH_DESCRIPTION_META)) || descriptions.some((description) => description !== descriptions[0]);
|
|
10379
|
+
const hasBranchDescriptions = choice && descriptions.some((description) => description !== void 0) || transitionObjects.some((transition) => Object.prototype.hasOwnProperty.call(transition.meta ?? {}, XSTATE_V6_BRANCH_DESCRIPTION_META)) || descriptions.some((description) => description !== descriptions[0]);
|
|
10302
10380
|
const branches = [];
|
|
10303
10381
|
let authoredFirstParam;
|
|
10304
10382
|
const commonDescription = descriptions[0];
|
|
@@ -10334,7 +10412,7 @@ function buildV6TransitionFunction(transitions) {
|
|
|
10334
10412
|
});
|
|
10335
10413
|
}
|
|
10336
10414
|
if (branches.length === 0) return;
|
|
10337
|
-
if (branches.slice(0, -1).some((branch) => branch.condition === "true")) return;
|
|
10415
|
+
if (!choice && branches.slice(0, -1).some((branch) => branch.condition === "true")) return;
|
|
10338
10416
|
const generated = branches.flatMap((branch) => [branch.condition, ...branch.body]).join("\n");
|
|
10339
10417
|
let renderedBranches = branches;
|
|
10340
10418
|
let merged = mergeV6FirstParam(authoredFirstParam, inferV6ArgBindings(generated));
|
|
@@ -10347,7 +10425,7 @@ function buildV6TransitionFunction(transitions) {
|
|
|
10347
10425
|
}
|
|
10348
10426
|
if (!merged) return;
|
|
10349
10427
|
const lines = merged.prelude.map((statement) => indentV6Code(statement, 2));
|
|
10350
|
-
for (const branch of renderedBranches) if (branch.condition === "true") lines.push(...branch.body.map((line) => indentV6Code(line, 2)));
|
|
10428
|
+
for (const [index, branch] of renderedBranches.entries()) if (branch.condition === "true" && index === renderedBranches.length - 1) lines.push(...branch.body.map((line) => indentV6Code(line, 2)));
|
|
10351
10429
|
else {
|
|
10352
10430
|
lines.push(indentV6Code(`if (${branch.condition}) {`, 2));
|
|
10353
10431
|
lines.push(...branch.body.map((line) => indentV6Code(line, 4)));
|
|
@@ -10937,6 +11015,51 @@ function isCompleteFunctionExpression(code) {
|
|
|
10937
11015
|
if (!expression) return false;
|
|
10938
11016
|
return ts.isFunctionExpression(expression) || ts.isArrowFunction(expression);
|
|
10939
11017
|
}
|
|
11018
|
+
function isMachineCode(value) {
|
|
11019
|
+
return !!value && typeof value === "object" && typeof value["@code"] === "string" && typeof value["@lang"] === "string";
|
|
11020
|
+
}
|
|
11021
|
+
function hasMachineCode(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
11022
|
+
if (isMachineCode(value)) return true;
|
|
11023
|
+
if (!value || typeof value !== "object" || seen.has(value)) return false;
|
|
11024
|
+
seen.add(value);
|
|
11025
|
+
return Object.values(value).some((child) => hasMachineCode(child, seen));
|
|
11026
|
+
}
|
|
11027
|
+
function parse$2(source) {
|
|
11028
|
+
return ts.createSourceFile("inspection.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
11029
|
+
}
|
|
11030
|
+
function expressionSource(source) {
|
|
11031
|
+
if (!parse$2(`const value = (${source});`).parseDiagnostics.length) return source;
|
|
11032
|
+
const methodFile = parse$2(`const value = {${source}};`);
|
|
11033
|
+
const statement = methodFile.statements[0];
|
|
11034
|
+
if (!methodFile.parseDiagnostics.length && statement && ts.isVariableStatement(statement)) {
|
|
11035
|
+
const initializer = statement.declarationList.declarations[0]?.initializer;
|
|
11036
|
+
const method = initializer && ts.isObjectLiteralExpression(initializer) ? initializer.properties[0] : void 0;
|
|
11037
|
+
if (method && ts.isMethodDeclaration(method) && method.body) return `${method.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) ? "async " : ""}function${method.asteriskToken ? "*" : ""}(${method.parameters.map((param) => param.getText(methodFile)).join(", ")}) ${method.body.getText(methodFile)}`;
|
|
11038
|
+
}
|
|
11039
|
+
return "() => __stately_inspection_unknown__()";
|
|
11040
|
+
}
|
|
11041
|
+
/** Project runtime MachineJSON code through the same static parser as authored v6 source. */
|
|
11042
|
+
function projectMachineJSON(config) {
|
|
11043
|
+
if (!hasMachineCode(config)) return config;
|
|
11044
|
+
function expressions(value) {
|
|
11045
|
+
if (isMachineCode(value)) return raw(["ts", "js"].includes(value["@lang"]) ? expressionSource(value["@code"]) : "() => __stately_inspection_unknown__()");
|
|
11046
|
+
if (Array.isArray(value)) return value.map(expressions);
|
|
11047
|
+
if (!value || typeof value !== "object") return value;
|
|
11048
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, expressions(item)]));
|
|
11049
|
+
}
|
|
11050
|
+
const projected = xstateSourceToConfig(`createMachine(${serializeJS(expressions(config))});`, { profile: "xstate-v6-alpha" });
|
|
11051
|
+
function restoreSchemas(original, parsed) {
|
|
11052
|
+
if (!original || !parsed || typeof original !== "object" || typeof parsed !== "object") return;
|
|
11053
|
+
const source = original;
|
|
11054
|
+
const result = parsed;
|
|
11055
|
+
if (Object.hasOwn(source, "schemas")) result.schemas = source.schemas;
|
|
11056
|
+
const states = source.states;
|
|
11057
|
+
const parsedStates = result.states;
|
|
11058
|
+
for (const key of Object.keys(states ?? {})) restoreSchemas(states[key], parsedStates?.[key]);
|
|
11059
|
+
}
|
|
11060
|
+
restoreSchemas(config, projected);
|
|
11061
|
+
return projected;
|
|
11062
|
+
}
|
|
10940
11063
|
/**
|
|
10941
11064
|
* A compound state node with no usable `initial` cannot be simulated (XState
|
|
10942
11065
|
* throws "No initial state specified for compound state node"). This walks a
|
|
@@ -11056,6 +11179,7 @@ function actorImplementationItems(value) {
|
|
|
11056
11179
|
}));
|
|
11057
11180
|
}
|
|
11058
11181
|
function machineConfigToGraph(config, options = {}) {
|
|
11182
|
+
if (isXStateV6Profile(options.profile)) config = projectMachineJSON(config);
|
|
11059
11183
|
const rootState = config;
|
|
11060
11184
|
const rootConfig = config;
|
|
11061
11185
|
const rootKey = String(rootState.id ?? "machine");
|
|
@@ -13027,31 +13151,9 @@ var ParseErrorCode;
|
|
|
13027
13151
|
function modify(text, path, value, options) {
|
|
13028
13152
|
return setProperty(text, path, value, options);
|
|
13029
13153
|
}
|
|
13030
|
-
/**
|
|
13031
|
-
* Applies edits to an input string.
|
|
13032
|
-
* @param text The input text
|
|
13033
|
-
* @param edits Edit operations following the format described in {@linkcode EditResult}.
|
|
13034
|
-
* @returns The text with the applied edits.
|
|
13035
|
-
* @throws An error if the edit operations are not well-formed as described in {@linkcode EditResult}.
|
|
13036
|
-
*/
|
|
13037
|
-
function applyEdits(text, edits) {
|
|
13038
|
-
let sortedEdits = edits.slice(0).sort((a, b) => {
|
|
13039
|
-
const diff = a.offset - b.offset;
|
|
13040
|
-
if (diff === 0) return a.length - b.length;
|
|
13041
|
-
return diff;
|
|
13042
|
-
});
|
|
13043
|
-
let lastModifiedOffset = text.length;
|
|
13044
|
-
for (let i = sortedEdits.length - 1; i >= 0; i--) {
|
|
13045
|
-
let e = sortedEdits[i];
|
|
13046
|
-
if (e.offset + e.length <= lastModifiedOffset) text = applyEdit(text, e);
|
|
13047
|
-
else throw new Error("Overlapping edit");
|
|
13048
|
-
lastModifiedOffset = e.offset;
|
|
13049
|
-
}
|
|
13050
|
-
return text;
|
|
13051
|
-
}
|
|
13052
13154
|
|
|
13053
13155
|
//#endregion
|
|
13054
|
-
//#region ../editor-sync/dist/adapters-
|
|
13156
|
+
//#region ../editor-sync/dist/adapters-Dt77BFUa.mjs
|
|
13055
13157
|
const sourceFileUris = /* @__PURE__ */ new WeakMap();
|
|
13056
13158
|
function collectXStateSourceLocations(sourceText, document, options = {}) {
|
|
13057
13159
|
const sourceFile = ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$2$1(document.fileName));
|
|
@@ -13237,11 +13339,21 @@ function addImportedStaticValueBindings(bindings, sourceFile, uri, fileName, opt
|
|
|
13237
13339
|
}, statement.moduleSpecifier.text);
|
|
13238
13340
|
if (!importedDocument) continue;
|
|
13239
13341
|
for (const element of namedBindings.elements) {
|
|
13240
|
-
const
|
|
13241
|
-
|
|
13242
|
-
|
|
13243
|
-
|
|
13244
|
-
|
|
13342
|
+
const importedName = element.propertyName?.text ?? element.name.text;
|
|
13343
|
+
const members = new Set([""]);
|
|
13344
|
+
const visit = (node) => {
|
|
13345
|
+
if (ts$1.isPropertyAccessExpression(node) && ts$1.isIdentifier(node.expression) && node.expression.text === element.name.text) members.add(`.${node.name.text}`);
|
|
13346
|
+
ts$1.forEachChild(node, visit);
|
|
13347
|
+
};
|
|
13348
|
+
visit(sourceFile);
|
|
13349
|
+
for (const member of members) {
|
|
13350
|
+
const binding = resolveExportedStaticValue(importedDocument, `${importedName}${member}`, resolver, /* @__PURE__ */ new Set());
|
|
13351
|
+
const symbol = `${element.name.text}${member}`;
|
|
13352
|
+
if (binding) bindings.set(symbol, {
|
|
13353
|
+
...binding,
|
|
13354
|
+
symbol
|
|
13355
|
+
});
|
|
13356
|
+
}
|
|
13245
13357
|
}
|
|
13246
13358
|
}
|
|
13247
13359
|
}
|
|
@@ -13254,15 +13366,21 @@ function resolveExportedStaticValue(document, exportName, resolver, visited) {
|
|
|
13254
13366
|
sourceFileUris.set(sourceFile, document.uri);
|
|
13255
13367
|
const localBindings = collectStaticValueBindings(sourceFile);
|
|
13256
13368
|
const localBinding = localBindings.get(exportName);
|
|
13257
|
-
|
|
13369
|
+
const [exportedSymbol] = exportName.split(".");
|
|
13370
|
+
const memberSuffix = exportName.slice(exportedSymbol.length);
|
|
13371
|
+
if (localBinding && sourceFile.statements.some((statement) => {
|
|
13372
|
+
if (!ts$1.isVariableStatement(statement) && !ts$1.isEnumDeclaration(statement)) return false;
|
|
13373
|
+
if (!statement.modifiers?.some((modifier) => modifier.kind === ts$1.SyntaxKind.ExportKeyword)) return false;
|
|
13374
|
+
return ts$1.isEnumDeclaration(statement) ? statement.name.text === exportedSymbol : statement.declarationList.declarations.some((declaration) => ts$1.isIdentifier(declaration.name) && declaration.name.text === exportName);
|
|
13375
|
+
})) return localBinding;
|
|
13258
13376
|
const exports = sourceFile.statements.filter(ts$1.isExportDeclaration);
|
|
13259
13377
|
for (const statement of exports) {
|
|
13260
13378
|
if (!statement.exportClause || !ts$1.isNamedExports(statement.exportClause)) continue;
|
|
13261
13379
|
const specifier = statement.moduleSpecifier && ts$1.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : null;
|
|
13262
13380
|
const exportedDocument = specifier?.startsWith(".") ? resolver.resolveImport(document, specifier) : null;
|
|
13263
13381
|
for (const element of statement.exportClause.elements) {
|
|
13264
|
-
if (element.name.text !==
|
|
13265
|
-
const localName = element.propertyName?.text ?? element.name.text
|
|
13382
|
+
if (element.name.text !== exportedSymbol) continue;
|
|
13383
|
+
const localName = `${element.propertyName?.text ?? element.name.text}${memberSuffix}`;
|
|
13266
13384
|
if (exportedDocument) {
|
|
13267
13385
|
const binding = resolveExportedStaticValue(exportedDocument, localName, resolver, visited);
|
|
13268
13386
|
return binding && {
|
|
@@ -13298,15 +13416,17 @@ function resolveExportedStaticValue(document, exportName, resolver, visited) {
|
|
|
13298
13416
|
}
|
|
13299
13417
|
}
|
|
13300
13418
|
function resolveImportedStaticValue(sourceFile, document, localName, resolver, visited) {
|
|
13419
|
+
const [localSymbol] = localName.split(".");
|
|
13420
|
+
const memberSuffix = localName.slice(localSymbol.length);
|
|
13301
13421
|
for (const statement of sourceFile.statements) {
|
|
13302
13422
|
if (!ts$1.isImportDeclaration(statement) || !ts$1.isStringLiteral(statement.moduleSpecifier) || !statement.moduleSpecifier.text.startsWith(".")) continue;
|
|
13303
13423
|
const namedBindings = statement.importClause?.namedBindings;
|
|
13304
13424
|
if (!namedBindings || !ts$1.isNamedImports(namedBindings)) continue;
|
|
13305
|
-
const imported = namedBindings.elements.find((element) => element.name.text ===
|
|
13425
|
+
const imported = namedBindings.elements.find((element) => element.name.text === localSymbol);
|
|
13306
13426
|
if (!imported) continue;
|
|
13307
13427
|
const importedDocument = resolver.resolveImport(document, statement.moduleSpecifier.text);
|
|
13308
13428
|
if (!importedDocument) return null;
|
|
13309
|
-
return resolveExportedStaticValue(importedDocument, imported.propertyName?.text ?? imported.name.text
|
|
13429
|
+
return resolveExportedStaticValue(importedDocument, `${imported.propertyName?.text ?? imported.name.text}${memberSuffix}`, resolver, visited);
|
|
13310
13430
|
}
|
|
13311
13431
|
return null;
|
|
13312
13432
|
}
|
|
@@ -14195,8 +14315,9 @@ async function applyMachineToSourceDocuments(machineConfig, document, options =
|
|
|
14195
14315
|
let semanticReplacements = semanticSplit?.replacements ?? [];
|
|
14196
14316
|
if (activePatches.length === 0) return finalize(semanticReplacements);
|
|
14197
14317
|
const transitionSplit = await tryCreateTransitionPatchSplitForDocuments(document, sourceFile, machineConfigNode, machineConfig, activePatches, prevGraph, nextGraph, activeSourceLocations, options.openTextDocument);
|
|
14198
|
-
|
|
14199
|
-
if (transitionSplit
|
|
14318
|
+
const transitionReplacements = transitionSplit ? combineSemanticAndTransitionReplacements(semanticReplacements, transitionSplit.replacements) : semanticReplacements;
|
|
14319
|
+
if (transitionSplit && transitionSplit.remainingPatches.length === 0) return finalize(transitionReplacements);
|
|
14320
|
+
if (transitionSplit) semanticReplacements = transitionReplacements;
|
|
14200
14321
|
const implementationSplit = tryCreateImplementationPatchSplit(document, sourceFile, transitionSplit?.remainingPatches ?? activePatches, nextGraph, options.machineIndex);
|
|
14201
14322
|
if (implementationSplit && implementationSplit.remainingPatches.length === 0) return finalize([...semanticReplacements, ...implementationSplit.replacements]);
|
|
14202
14323
|
if (implementationSplit) semanticReplacements = [...semanticReplacements, ...implementationSplit.replacements];
|
|
@@ -14673,7 +14794,17 @@ async function createTransitionReplacementForDocuments(document, sourceFile, mac
|
|
|
14673
14794
|
if (transitionSource && transitionTarget.previousEventType === transitionTarget.eventType) return [createPropertyValueReplacement(targetDocument, targetSourceFile, transitionSource.eventProperty, nextTransitionValue)];
|
|
14674
14795
|
if (transitionSource) return [createPropertyAssignmentReplacement(targetDocument, targetSourceFile, transitionSource.eventProperty, transitionTarget.eventType, nextTransitionValue)];
|
|
14675
14796
|
const onObject = getObjectLiteralProperty(stateObject, "on");
|
|
14676
|
-
if (onObject)
|
|
14797
|
+
if (onObject) {
|
|
14798
|
+
const nextOn = getStateConfigByPath(machineConfig, transitionTarget.sourcePath)?.on;
|
|
14799
|
+
if (isMachineConfig(nextOn) && !onObject.properties.some((property) => {
|
|
14800
|
+
const key = property.name && getPropertyNameText$2(property.name);
|
|
14801
|
+
return !key || nextOn[key] !== void 0;
|
|
14802
|
+
})) return [createObjectLiteralPropertiesInsertion(targetDocument, targetSourceFile, onObject, [{
|
|
14803
|
+
key: transitionTarget.eventType,
|
|
14804
|
+
config: nextTransitionValue
|
|
14805
|
+
}], false)];
|
|
14806
|
+
return createObjectLiteralPropertyInsertion(targetDocument, targetSourceFile, onObject, transitionTarget.eventType, nextTransitionValue);
|
|
14807
|
+
}
|
|
14677
14808
|
return createObjectLiteralPropertyInsertion(targetDocument, targetSourceFile, stateObject, "on", { [transitionTarget.eventType]: nextTransitionValue });
|
|
14678
14809
|
}
|
|
14679
14810
|
async function createV6BranchActionNameReplacementForDocuments(document, sourceFile, machineConfigNode, patch, transitionTarget, prevGraph, nextGraph, sourceLocations, openTextDocument) {
|
|
@@ -14820,7 +14951,10 @@ async function createStatePropertiesReplacementForDocuments(document, sourceFile
|
|
|
14820
14951
|
config: nextSlotValue
|
|
14821
14952
|
});
|
|
14822
14953
|
}
|
|
14823
|
-
if (insertedSlots.length > 0) replacements.push(createObjectLiteralPropertiesInsertion(targetDocument, targetSourceFile, existingMap, insertedSlots)
|
|
14954
|
+
if (insertedSlots.length > 0) replacements.push(createObjectLiteralPropertiesInsertion(targetDocument, targetSourceFile, existingMap, insertedSlots, existingMap.properties.some((property) => {
|
|
14955
|
+
const key = property.name && getPropertyNameText$2(property.name);
|
|
14956
|
+
return !key || !affectedSlots.has(key) || nextValue[key] !== void 0;
|
|
14957
|
+
})));
|
|
14824
14958
|
continue;
|
|
14825
14959
|
}
|
|
14826
14960
|
}
|
|
@@ -15499,7 +15633,7 @@ function createStateMembershipInitialReplacements(document, sourceFile, parentOb
|
|
|
15499
15633
|
config: nextInitial
|
|
15500
15634
|
}])];
|
|
15501
15635
|
}
|
|
15502
|
-
function createObjectLiteralPropertiesInsertion(document, sourceFile, objectLiteral, entries) {
|
|
15636
|
+
function createObjectLiteralPropertiesInsertion(document, sourceFile, objectLiteral, entries, hasRetainedProperties = objectLiteral.properties.length > 0) {
|
|
15503
15637
|
const formatting = getFormattingContext(document, sourceFile, objectLiteral);
|
|
15504
15638
|
const lineSeparator = formatting.newLineKind === ts$1.NewLineKind.CarriageReturnLineFeed ? "\r\n" : "\n";
|
|
15505
15639
|
const propertyTexts = entries.map((entry) => printObjectLiteralProperty(entry.key, entry.config, sourceFile, formatting));
|
|
@@ -15508,7 +15642,7 @@ function createObjectLiteralPropertiesInsertion(document, sourceFile, objectLite
|
|
|
15508
15642
|
const startOffset = existingProperties.length === 0 ? closeBraceOffset : existingProperties[existingProperties.length - 1].getEnd();
|
|
15509
15643
|
const start = document.positionAt(startOffset);
|
|
15510
15644
|
const end = document.positionAt(closeBraceOffset);
|
|
15511
|
-
const prefix =
|
|
15645
|
+
const prefix = hasRetainedProperties ? `,${lineSeparator}` : lineSeparator;
|
|
15512
15646
|
const suffix = `${lineSeparator}${formatting.baseIndent}`;
|
|
15513
15647
|
return {
|
|
15514
15648
|
uri: getDocumentUri(document),
|
|
@@ -16219,8 +16353,8 @@ function createStateKeyRenameReplacementsForTarget(document, sourceFile, parentO
|
|
|
16219
16353
|
}
|
|
16220
16354
|
const supportedScope = new Set([rename.parentPath.join("."), ...getDirectChildStatePaths(nodeKind === "statesObject" ? initialOwnerObject : parentObject, rename.parentPath).map((path) => path.join("."))]);
|
|
16221
16355
|
for (const target of targetLiterals) {
|
|
16222
|
-
if (!referencesRenamedState(target.
|
|
16223
|
-
if (!referencesRenamedAbsoluteState(target.
|
|
16356
|
+
if (!referencesRenamedState(target.value, rename)) continue;
|
|
16357
|
+
if (!referencesRenamedAbsoluteState(target.value, rename)) {
|
|
16224
16358
|
const initialSourcePaths = target.initialSourcePaths ?? [];
|
|
16225
16359
|
if (initialSourcePaths.length > 0) {
|
|
16226
16360
|
if (!target.sourcePaths.every((sourcePath) => arePathsEqual(sourcePath, rename.parentPath))) {
|
|
@@ -16232,7 +16366,7 @@ function createStateKeyRenameReplacementsForTarget(document, sourceFile, parentO
|
|
|
16232
16366
|
if (!(sourcePath.length === rename.parentPath.length || arePathsEqual(sourcePath.slice(0, -1), rename.parentPath)) || !supportedScope.has(sourceKey)) return null;
|
|
16233
16367
|
}
|
|
16234
16368
|
}
|
|
16235
|
-
const replacement = createStringLiteralReplacement(target.document, target.sourceFile, target.node, renameStateReference(target.
|
|
16369
|
+
const replacement = createStringLiteralReplacement(target.document, target.sourceFile, target.node, renameStateReference(target.value, rename));
|
|
16236
16370
|
replacements.push(replacement);
|
|
16237
16371
|
}
|
|
16238
16372
|
return replacements;
|
|
@@ -16367,21 +16501,25 @@ function getDirectChildStatePaths(stateObject, parentPath) {
|
|
|
16367
16501
|
return [[...parentPath, key]];
|
|
16368
16502
|
});
|
|
16369
16503
|
}
|
|
16370
|
-
function collectTargetStringLiterals(machineConfigNode) {
|
|
16504
|
+
function collectTargetStringLiterals(machineConfigNode, sourceLocations, documentUri) {
|
|
16371
16505
|
const literals = [];
|
|
16372
|
-
const bindings = collectTopLevelExpressionBindings(machineConfigNode.getSourceFile());
|
|
16506
|
+
const bindings = collectTopLevelExpressionBindings(machineConfigNode.getSourceFile(), sourceLocations, documentUri);
|
|
16373
16507
|
const visitStateObject = (stateObject, sourcePath) => {
|
|
16374
16508
|
collectInitialTargetStringLiterals(stateObject, sourcePath, literals, bindings);
|
|
16375
16509
|
for (const propertyName of [
|
|
16376
16510
|
"always",
|
|
16377
16511
|
"after",
|
|
16378
16512
|
"on",
|
|
16379
|
-
"onDone"
|
|
16513
|
+
"onDone",
|
|
16514
|
+
"onError",
|
|
16515
|
+
"onTimeout",
|
|
16516
|
+
"choice"
|
|
16380
16517
|
]) {
|
|
16381
16518
|
const property = getPropertyAssignment(stateObject, propertyName);
|
|
16382
16519
|
if (!property) continue;
|
|
16383
16520
|
collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals, bindings);
|
|
16384
16521
|
}
|
|
16522
|
+
collectInvokeTargetStringLiterals(stateObject, sourcePath, literals, bindings);
|
|
16385
16523
|
const statesObject = getObjectLiteralProperty(stateObject, "states");
|
|
16386
16524
|
if (!statesObject) return;
|
|
16387
16525
|
for (const property of statesObject.properties) {
|
|
@@ -16402,11 +16540,11 @@ function collectInitialTargetStringLiterals(stateObject, sourcePath, literals, b
|
|
|
16402
16540
|
if (ts$1.isObjectLiteralExpression(initializer)) {
|
|
16403
16541
|
const initialLiterals = [];
|
|
16404
16542
|
collectTargetStringLiteralsFromExpression(initializer, sourcePath, initialLiterals, bindings);
|
|
16405
|
-
for (const literal of initialLiterals) for (const literalSourcePath of literal.sourcePaths) addTargetLiteral(literals, literal.node, literalSourcePath, true);
|
|
16543
|
+
for (const literal of initialLiterals) for (const literalSourcePath of literal.sourcePaths) addTargetLiteral(literals, literal.node, literalSourcePath, true, literal.value);
|
|
16406
16544
|
}
|
|
16407
16545
|
}
|
|
16408
16546
|
async function collectMappedTargetStringLiterals(rootDocument, rootSourceFile, machineConfigNode, sourceLocations, openTextDocument) {
|
|
16409
|
-
const literals = collectTargetStringLiterals(machineConfigNode).map((target) => ({
|
|
16547
|
+
const literals = collectTargetStringLiterals(machineConfigNode, sourceLocations, getDocumentUri(rootDocument)).map((target) => ({
|
|
16410
16548
|
...target,
|
|
16411
16549
|
document: rootDocument,
|
|
16412
16550
|
sourceFile: rootSourceFile
|
|
@@ -16421,7 +16559,7 @@ async function collectMappedTargetStringLiterals(rootDocument, rootSourceFile, m
|
|
|
16421
16559
|
const stateObject = findObjectLiteralByRange(targetSourceFile, location.range);
|
|
16422
16560
|
if (!stateObject) continue;
|
|
16423
16561
|
const stateLiterals = [];
|
|
16424
|
-
collectTargetStringLiteralsFromStateObject(stateObject, location.path, stateLiterals, collectTopLevelExpressionBindings(targetSourceFile));
|
|
16562
|
+
collectTargetStringLiteralsFromStateObject(stateObject, location.path, stateLiterals, collectTopLevelExpressionBindings(targetSourceFile, sourceLocations, getDocumentUri(targetDocument)));
|
|
16425
16563
|
for (const target of stateLiterals) {
|
|
16426
16564
|
const key = getTargetLiteralReplacementKey(targetDocument, targetSourceFile, target.node);
|
|
16427
16565
|
if (seen.has(key)) {
|
|
@@ -16472,7 +16610,7 @@ async function collectMappedTargetStringLiterals(rootDocument, rootSourceFile, m
|
|
|
16472
16610
|
}
|
|
16473
16611
|
}
|
|
16474
16612
|
const functionLiterals = [];
|
|
16475
|
-
const bindings = collectTopLevelExpressionBindings(targetSourceFile);
|
|
16613
|
+
const bindings = collectTopLevelExpressionBindings(targetSourceFile, sourceLocations, getDocumentUri(targetDocument));
|
|
16476
16614
|
for (const sourcePath of location.sourcePaths) collectTargetStringLiteralsFromFunction(fn, sourcePath, functionLiterals, bindings, new Set([location.symbol]));
|
|
16477
16615
|
for (const target of functionLiterals) {
|
|
16478
16616
|
const key = getTargetLiteralReplacementKey(targetDocument, targetSourceFile, target.node);
|
|
@@ -16558,7 +16696,10 @@ function collectTransitionCallArgumentLiterals(machineConfigNode, symbol, target
|
|
|
16558
16696
|
"always",
|
|
16559
16697
|
"after",
|
|
16560
16698
|
"on",
|
|
16561
|
-
"onDone"
|
|
16699
|
+
"onDone",
|
|
16700
|
+
"onError",
|
|
16701
|
+
"onTimeout",
|
|
16702
|
+
"choice"
|
|
16562
16703
|
]) {
|
|
16563
16704
|
const property = getPropertyAssignment(stateObject, propertyName);
|
|
16564
16705
|
if (property) visitExpression(property.initializer, sourcePath);
|
|
@@ -16584,12 +16725,16 @@ function collectTargetStringLiteralsFromStateObject(stateObject, sourcePath, lit
|
|
|
16584
16725
|
"always",
|
|
16585
16726
|
"after",
|
|
16586
16727
|
"on",
|
|
16587
|
-
"onDone"
|
|
16728
|
+
"onDone",
|
|
16729
|
+
"onError",
|
|
16730
|
+
"onTimeout",
|
|
16731
|
+
"choice"
|
|
16588
16732
|
]) {
|
|
16589
16733
|
const property = getPropertyAssignment(stateObject, propertyName);
|
|
16590
16734
|
if (!property) continue;
|
|
16591
16735
|
collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals, bindings);
|
|
16592
16736
|
}
|
|
16737
|
+
collectInvokeTargetStringLiterals(stateObject, sourcePath, literals, bindings);
|
|
16593
16738
|
const statesObject = getObjectLiteralProperty(stateObject, "states");
|
|
16594
16739
|
if (!statesObject) return;
|
|
16595
16740
|
for (const property of statesObject.properties) {
|
|
@@ -16600,8 +16745,35 @@ function collectTargetStringLiteralsFromStateObject(stateObject, sourcePath, lit
|
|
|
16600
16745
|
collectTargetStringLiteralsFromStateObject(childState, [...sourcePath, key], literals, bindings);
|
|
16601
16746
|
}
|
|
16602
16747
|
}
|
|
16748
|
+
function collectInvokeTargetStringLiterals(stateObject, sourcePath, literals, bindings) {
|
|
16749
|
+
const invoke = getPropertyAssignment(stateObject, "invoke");
|
|
16750
|
+
if (!invoke) return;
|
|
16751
|
+
const visit = (expression, seen = /* @__PURE__ */ new Set()) => {
|
|
16752
|
+
const current = unwrapExpression$2(expression);
|
|
16753
|
+
if (ts$1.isIdentifier(current)) {
|
|
16754
|
+
const binding = bindings.get(current.text);
|
|
16755
|
+
if (binding && ts$1.isExpression(binding) && !seen.has(current.text)) visit(binding, new Set([...seen, current.text]));
|
|
16756
|
+
} else if (ts$1.isArrayLiteralExpression(current)) {
|
|
16757
|
+
for (const item of current.elements) if (ts$1.isExpression(item)) visit(item, seen);
|
|
16758
|
+
} else if (ts$1.isObjectLiteralExpression(current)) for (const name of [
|
|
16759
|
+
"onDone",
|
|
16760
|
+
"onError",
|
|
16761
|
+
"onSnapshot",
|
|
16762
|
+
"onTimeout"
|
|
16763
|
+
]) {
|
|
16764
|
+
const property = getPropertyAssignment(current, name);
|
|
16765
|
+
if (property) collectTargetStringLiteralsFromExpression(property.initializer, sourcePath, literals, bindings);
|
|
16766
|
+
}
|
|
16767
|
+
};
|
|
16768
|
+
visit(invoke.initializer);
|
|
16769
|
+
}
|
|
16603
16770
|
function collectTargetStringLiteralsFromExpression(expression, sourcePath, literals, bindings, seenBindings = /* @__PURE__ */ new Set()) {
|
|
16604
16771
|
const current = unwrapExpression$2(expression);
|
|
16772
|
+
const staticTarget = bindings.staticTargets?.get(`${current.getStart()}:${current.getEnd()}`);
|
|
16773
|
+
if (staticTarget !== void 0 && (ts$1.isIdentifier(current) || ts$1.isPropertyAccessExpression(current))) {
|
|
16774
|
+
addTargetLiteral(literals, current, sourcePath, false, staticTarget);
|
|
16775
|
+
return;
|
|
16776
|
+
}
|
|
16605
16777
|
if (ts$1.isStringLiteralLike(current)) {
|
|
16606
16778
|
addTargetLiteral(literals, current, sourcePath);
|
|
16607
16779
|
return;
|
|
@@ -16624,6 +16796,7 @@ function collectTargetStringLiteralsFromExpression(expression, sourcePath, liter
|
|
|
16624
16796
|
const binding = bindings.get(current.expression.text);
|
|
16625
16797
|
if (binding && isTransitionFunctionBinding(binding)) {
|
|
16626
16798
|
const scopedBindings = new Map(bindings);
|
|
16799
|
+
scopedBindings.staticTargets = bindings.staticTargets;
|
|
16627
16800
|
for (const [index, parameter] of binding.parameters.entries()) {
|
|
16628
16801
|
if (!ts$1.isIdentifier(parameter.name)) continue;
|
|
16629
16802
|
const argument = current.arguments[index];
|
|
@@ -16686,8 +16859,9 @@ function collectTargetStringLiteralsFromFunction(fn, sourcePath, literals, bindi
|
|
|
16686
16859
|
}
|
|
16687
16860
|
collectTargetStringLiteralsFromExpression(fn.body, sourcePath, literals, bindings, seenBindings);
|
|
16688
16861
|
}
|
|
16689
|
-
function collectTopLevelExpressionBindings(sourceFile) {
|
|
16862
|
+
function collectTopLevelExpressionBindings(sourceFile, sourceLocations, documentUri) {
|
|
16690
16863
|
const bindings = /* @__PURE__ */ new Map();
|
|
16864
|
+
bindings.staticTargets = new Map((sourceLocations?.staticValues ?? []).filter((location) => location.definitionUri && location.uri === documentUri).map((location) => [`${offsetAtRangePosition(sourceFile.text, location.range.startLine, location.range.startChar)}:${offsetAtRangePosition(sourceFile.text, location.range.endLine, location.range.endChar)}`, location.value]));
|
|
16691
16865
|
for (const statement of sourceFile.statements) {
|
|
16692
16866
|
if (ts$1.isFunctionDeclaration(statement) && statement.name) {
|
|
16693
16867
|
bindings.set(statement.name.text, statement);
|
|
@@ -16698,7 +16872,7 @@ function collectTopLevelExpressionBindings(sourceFile) {
|
|
|
16698
16872
|
}
|
|
16699
16873
|
return bindings;
|
|
16700
16874
|
}
|
|
16701
|
-
function addTargetLiteral(literals, node, sourcePath, isInitialTarget = false) {
|
|
16875
|
+
function addTargetLiteral(literals, node, sourcePath, isInitialTarget = false, value = node.text) {
|
|
16702
16876
|
const existing = literals.find((literal) => literal.node.getStart() === node.getStart() && literal.node.getEnd() === node.getEnd());
|
|
16703
16877
|
if (existing) {
|
|
16704
16878
|
mergeTargetSourcePaths(existing, [sourcePath]);
|
|
@@ -16707,6 +16881,7 @@ function addTargetLiteral(literals, node, sourcePath, isInitialTarget = false) {
|
|
|
16707
16881
|
}
|
|
16708
16882
|
literals.push({
|
|
16709
16883
|
node,
|
|
16884
|
+
value,
|
|
16710
16885
|
sourcePaths: [sourcePath],
|
|
16711
16886
|
...isInitialTarget ? { initialSourcePaths: [sourcePath] } : {}
|
|
16712
16887
|
});
|
|
@@ -16877,6 +17052,10 @@ function compareReplacementRangesDescending(a, b) {
|
|
|
16877
17052
|
function normalizeOverlappingReplacements(replacements) {
|
|
16878
17053
|
return planTextReplacements(replacements);
|
|
16879
17054
|
}
|
|
17055
|
+
function combineSemanticAndTransitionReplacements(semantic, transitions) {
|
|
17056
|
+
const compare = (leftLine, leftChar, rightLine, rightChar) => leftLine - rightLine || leftChar - rightChar;
|
|
17057
|
+
return [...semantic.filter((focused) => !transitions.some((owner) => owner.uri === focused.uri && compare(focused.range.startLine, focused.range.startChar, owner.range.startLine, owner.range.startChar) > 0 && compare(focused.range.endLine, focused.range.endChar, owner.range.endLine, owner.range.endChar) <= 0)), ...transitions];
|
|
17058
|
+
}
|
|
16880
17059
|
function appendWholeStateReplacement(replacements, wholeState) {
|
|
16881
17060
|
const compare = (leftLine, leftChar, rightLine, rightChar) => leftLine - rightLine || leftChar - rightChar;
|
|
16882
17061
|
for (let index = replacements.length - 1; index >= 0; index--) {
|
|
@@ -17065,6 +17244,138 @@ function stripPresentationPatches(patches) {
|
|
|
17065
17244
|
return [sourcePatch];
|
|
17066
17245
|
});
|
|
17067
17246
|
}
|
|
17247
|
+
const tokenKind = {
|
|
17248
|
+
comma: 5,
|
|
17249
|
+
lineComment: 12,
|
|
17250
|
+
blockComment: 13,
|
|
17251
|
+
lineBreak: 14,
|
|
17252
|
+
eof: 17
|
|
17253
|
+
};
|
|
17254
|
+
/** Move authored values and same-line comments together, retaining array trivia. */
|
|
17255
|
+
function reorderedActionArray(text, array, order, inserted = /* @__PURE__ */ new Map()) {
|
|
17256
|
+
const items = array.children ?? [];
|
|
17257
|
+
if (!items.length || order.some((index, position) => index < 0 ? !inserted.has(position) : !items[index])) return null;
|
|
17258
|
+
const prefixes = [text.slice(array.offset + 1, items[0].offset)];
|
|
17259
|
+
const comments = [];
|
|
17260
|
+
let closing = "";
|
|
17261
|
+
let trailingComma = false;
|
|
17262
|
+
for (let index = 0; index < items.length; index++) {
|
|
17263
|
+
const item = items[index];
|
|
17264
|
+
const end = items[index + 1]?.offset ?? array.offset + array.length - 1;
|
|
17265
|
+
const gap = text.slice(item.offset + item.length, end);
|
|
17266
|
+
const scanner = createScanner(gap, false);
|
|
17267
|
+
let comma = -1;
|
|
17268
|
+
let commentEnd = 0;
|
|
17269
|
+
let onSameLine = true;
|
|
17270
|
+
for (let token = scanner.scan(); token !== tokenKind.eof; token = scanner.scan()) {
|
|
17271
|
+
if (token === tokenKind.comma && comma < 0) comma = scanner.getTokenOffset();
|
|
17272
|
+
if (token === tokenKind.lineBreak) onSameLine = false;
|
|
17273
|
+
if (onSameLine && (token === tokenKind.lineComment || token === tokenKind.blockComment)) {
|
|
17274
|
+
commentEnd = scanner.getTokenOffset() + scanner.getTokenLength();
|
|
17275
|
+
if (scanner.getTokenValue().includes("\n")) onSameLine = false;
|
|
17276
|
+
}
|
|
17277
|
+
}
|
|
17278
|
+
const withoutComma = (value, offset) => comma >= offset && comma < offset + value.length ? value.slice(0, comma - offset) + value.slice(comma - offset + 1) : value;
|
|
17279
|
+
comments.push(withoutComma(gap.slice(0, commentEnd), 0));
|
|
17280
|
+
const remainder = withoutComma(gap.slice(commentEnd), commentEnd);
|
|
17281
|
+
if (index < items.length - 1) prefixes.push(remainder);
|
|
17282
|
+
else {
|
|
17283
|
+
closing = remainder;
|
|
17284
|
+
trailingComma = comma >= 0;
|
|
17285
|
+
}
|
|
17286
|
+
}
|
|
17287
|
+
const defaultPrefix = prefixes[0].match(/\r?\n[ \t]*$/)?.[0] ?? prefixes.find((prefix) => /^\s*$/.test(prefix)) ?? "";
|
|
17288
|
+
let interior = "";
|
|
17289
|
+
for (let index = 0; index < order.length; index++) {
|
|
17290
|
+
const oldIndex = order[index];
|
|
17291
|
+
const item = items[oldIndex];
|
|
17292
|
+
const ownPrefix = oldIndex > 0 ? prefixes[oldIndex] ?? defaultPrefix : defaultPrefix;
|
|
17293
|
+
let prefix = index === 0 ? prefixes[0] : ownPrefix;
|
|
17294
|
+
if (index === 0 && oldIndex > 0 && stripComments(ownPrefix) !== ownPrefix) prefix += ownPrefix.trimStart();
|
|
17295
|
+
interior += prefix + (item ? text.slice(item.offset, item.offset + item.length) : inserted.get(index));
|
|
17296
|
+
if (index < order.length - 1 || trailingComma) interior += ",";
|
|
17297
|
+
interior += comments[oldIndex] ?? "";
|
|
17298
|
+
}
|
|
17299
|
+
return {
|
|
17300
|
+
start: array.offset + 1,
|
|
17301
|
+
end: array.offset + array.length - 1,
|
|
17302
|
+
text: interior + closing
|
|
17303
|
+
};
|
|
17304
|
+
}
|
|
17305
|
+
/** Keep unchanged source spans as anchors while composing successive tree edits. */
|
|
17306
|
+
var PreservedText = class {
|
|
17307
|
+
pieces;
|
|
17308
|
+
constructor(original) {
|
|
17309
|
+
this.original = original;
|
|
17310
|
+
this.pieces = [{
|
|
17311
|
+
text: original,
|
|
17312
|
+
originalOffset: 0
|
|
17313
|
+
}];
|
|
17314
|
+
}
|
|
17315
|
+
replace(start, end, text) {
|
|
17316
|
+
const before = [];
|
|
17317
|
+
const after = [];
|
|
17318
|
+
let offset = 0;
|
|
17319
|
+
for (const piece of this.pieces) {
|
|
17320
|
+
const pieceEnd = offset + piece.text.length;
|
|
17321
|
+
if (offset < start) before.push({
|
|
17322
|
+
...piece,
|
|
17323
|
+
text: piece.text.slice(0, Math.min(start, pieceEnd) - offset)
|
|
17324
|
+
});
|
|
17325
|
+
if (pieceEnd > end) {
|
|
17326
|
+
const skip = Math.max(end - offset, 0);
|
|
17327
|
+
after.push({
|
|
17328
|
+
text: piece.text.slice(skip),
|
|
17329
|
+
originalOffset: piece.originalOffset === void 0 ? void 0 : piece.originalOffset + skip
|
|
17330
|
+
});
|
|
17331
|
+
}
|
|
17332
|
+
offset = pieceEnd;
|
|
17333
|
+
}
|
|
17334
|
+
this.pieces = [
|
|
17335
|
+
...before,
|
|
17336
|
+
...text ? [{ text }] : [],
|
|
17337
|
+
...after
|
|
17338
|
+
];
|
|
17339
|
+
}
|
|
17340
|
+
replacements(document) {
|
|
17341
|
+
const edits = [];
|
|
17342
|
+
let cursor = 0;
|
|
17343
|
+
let pending = "";
|
|
17344
|
+
const flush = (end) => {
|
|
17345
|
+
let start = cursor;
|
|
17346
|
+
let replacement = pending;
|
|
17347
|
+
while (start < end && replacement && this.original[start] === replacement[0]) {
|
|
17348
|
+
start++;
|
|
17349
|
+
replacement = replacement.slice(1);
|
|
17350
|
+
}
|
|
17351
|
+
while (end > start && replacement && this.original[end - 1] === replacement.at(-1)) {
|
|
17352
|
+
end--;
|
|
17353
|
+
replacement = replacement.slice(0, -1);
|
|
17354
|
+
}
|
|
17355
|
+
if (start !== end || replacement) {
|
|
17356
|
+
const from = document.positionAt(start);
|
|
17357
|
+
const to = document.positionAt(end);
|
|
17358
|
+
edits.push({
|
|
17359
|
+
range: {
|
|
17360
|
+
startLine: from.line,
|
|
17361
|
+
startChar: from.character,
|
|
17362
|
+
endLine: to.line,
|
|
17363
|
+
endChar: to.character
|
|
17364
|
+
},
|
|
17365
|
+
newText: replacement
|
|
17366
|
+
});
|
|
17367
|
+
}
|
|
17368
|
+
pending = "";
|
|
17369
|
+
};
|
|
17370
|
+
for (const piece of this.pieces) if (piece.originalOffset === void 0) pending += piece.text;
|
|
17371
|
+
else {
|
|
17372
|
+
flush(piece.originalOffset);
|
|
17373
|
+
cursor = piece.originalOffset + piece.text.length;
|
|
17374
|
+
}
|
|
17375
|
+
flush(this.original.length);
|
|
17376
|
+
return edits;
|
|
17377
|
+
}
|
|
17378
|
+
};
|
|
17068
17379
|
function isRecord$2(value) {
|
|
17069
17380
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
17070
17381
|
}
|
|
@@ -17128,6 +17439,36 @@ function collectPropertyRenames(previousGraph, nextGraph, patches) {
|
|
|
17128
17439
|
}
|
|
17129
17440
|
return renames;
|
|
17130
17441
|
}
|
|
17442
|
+
/** Recover authored IDs and discard retained implicit runtime IDs using the source. */
|
|
17443
|
+
function recoverSourceNodeIds(graph, previousGraph, source, authoredIdChanges = /* @__PURE__ */ new Set()) {
|
|
17444
|
+
const previousById = new Map(previousGraph.nodes.map((node) => [node.id, node]));
|
|
17445
|
+
const defaultIds = /* @__PURE__ */ new Map();
|
|
17446
|
+
const implicitIds = /* @__PURE__ */ new Map();
|
|
17447
|
+
const authoredIds = /* @__PURE__ */ new Map();
|
|
17448
|
+
const resolve = (id) => {
|
|
17449
|
+
const cached = defaultIds.get(id);
|
|
17450
|
+
if (cached !== void 0) return cached;
|
|
17451
|
+
const node = previousById.get(id);
|
|
17452
|
+
const authoredId = findNodeAtLocation(source, [...node.parentId ? [...statePath(previousGraph, id), node.data.key] : [], "id"]);
|
|
17453
|
+
const implicitId = node.parentId ? `${resolve(node.parentId)}.${node.data.key}` : "(machine)";
|
|
17454
|
+
const defaultId = !node.parentId && authoredId ? getNodeValue(authoredId) : implicitId;
|
|
17455
|
+
defaultIds.set(id, defaultId);
|
|
17456
|
+
if (authoredId) authoredIds.set(id, getNodeValue(authoredId));
|
|
17457
|
+
else implicitIds.set(id, implicitId);
|
|
17458
|
+
return defaultId;
|
|
17459
|
+
};
|
|
17460
|
+
for (const node of previousGraph.nodes) resolve(node.id);
|
|
17461
|
+
const updates = /* @__PURE__ */ new Map();
|
|
17462
|
+
for (const node of graph.nodes) {
|
|
17463
|
+
if (authoredIdChanges.has(node.id)) continue;
|
|
17464
|
+
if (node.data.nodeId == null && authoredIds.has(node.id)) updates.set(node.id, authoredIds.get(node.id));
|
|
17465
|
+
else if (node.data.nodeId != null && node.data.nodeId === implicitIds.get(node.id)) updates.set(node.id, void 0);
|
|
17466
|
+
}
|
|
17467
|
+
if (!updates.size) return graph;
|
|
17468
|
+
const normalized = structuredClone(graph);
|
|
17469
|
+
for (const node of normalized.nodes) if (updates.has(node.id)) node.data.nodeId = updates.get(node.id);
|
|
17470
|
+
return normalized;
|
|
17471
|
+
}
|
|
17131
17472
|
function onlyTargetChanged(previous, next) {
|
|
17132
17473
|
if (typeof previous.target !== "string" || typeof next.target !== "string") return false;
|
|
17133
17474
|
const { target: _previousTarget, ...previousRest } = previous;
|
|
@@ -17148,12 +17489,24 @@ function formattingOptions(text) {
|
|
|
17148
17489
|
};
|
|
17149
17490
|
}
|
|
17150
17491
|
/** Apply graph-level semantic changes to the source JSON tree, not to an export. */
|
|
17151
|
-
function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, patches, preserveStatelyMetadata) {
|
|
17492
|
+
function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, patches, preserveStatelyMetadata, authoredIdChanges) {
|
|
17152
17493
|
if (!isGraph$1(previousGraph) || !isGraph$1(nextGraph) || !isRecord$2(machineConfig)) return null;
|
|
17153
17494
|
const original = document.getText();
|
|
17154
17495
|
let text = original;
|
|
17155
|
-
const
|
|
17156
|
-
const
|
|
17496
|
+
const preservedText = new PreservedText(original);
|
|
17497
|
+
const replace = (start, end, value) => {
|
|
17498
|
+
preservedText.replace(start, end, value);
|
|
17499
|
+
text = text.slice(0, start) + value + text.slice(end);
|
|
17500
|
+
};
|
|
17501
|
+
const originalTree = parseTree(original, [], { allowTrailingComma: true });
|
|
17502
|
+
if (!originalTree) return null;
|
|
17503
|
+
const normalizedPrevious = recoverSourceNodeIds(previousGraph, previousGraph, originalTree);
|
|
17504
|
+
const previousIds = new Map(previousGraph.nodes.map((node) => [node.id, node.data.nodeId ?? null]));
|
|
17505
|
+
const intentionalIds = authoredIdChanges ?? nextGraph.nodes.filter((node) => previousIds.has(node.id) && previousIds.get(node.id) !== (node.data.nodeId ?? null)).map((node) => node.id);
|
|
17506
|
+
const normalizedNext = recoverSourceNodeIds(nextGraph, previousGraph, originalTree, new Set(intentionalIds));
|
|
17507
|
+
const previousConfig = preserveStatelyMetadata ? graphToMachineConfig(normalizedPrevious) : stripStatelyMetadata(graphToMachineConfig(normalizedPrevious));
|
|
17508
|
+
const nextMachineConfig = normalizedNext === nextGraph ? machineConfig : graphToMachineConfig(normalizedNext);
|
|
17509
|
+
const nextConfig = preserveStatelyMetadata ? nextMachineConfig : stripStatelyMetadata(nextMachineConfig);
|
|
17157
17510
|
const renames = collectPropertyRenames(previousGraph, nextGraph, patches);
|
|
17158
17511
|
const treeAt = (path) => {
|
|
17159
17512
|
const errors = [];
|
|
@@ -17163,12 +17516,39 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17163
17516
|
};
|
|
17164
17517
|
if (!treeAt([])) return null;
|
|
17165
17518
|
const setValue = (path, value) => {
|
|
17166
|
-
|
|
17519
|
+
let containerPath = path.slice(0, -1);
|
|
17520
|
+
let container = treeAt(containerPath);
|
|
17521
|
+
while (!container && containerPath.length) {
|
|
17522
|
+
containerPath = containerPath.slice(0, -1);
|
|
17523
|
+
container = treeAt(containerPath);
|
|
17524
|
+
}
|
|
17525
|
+
const compact = container && !text.slice(container.offset, container.offset + container.length).includes("\n");
|
|
17526
|
+
const edits = modify(text, path, value, { ...compact ? {} : { formattingOptions: formattingOptions(text) } });
|
|
17527
|
+
for (const edit of [...edits].sort((a, b) => b.offset - a.offset)) {
|
|
17528
|
+
let content = edit.content;
|
|
17529
|
+
if (compact && container) {
|
|
17530
|
+
const authored = text.slice(container.offset, container.offset + container.length);
|
|
17531
|
+
const colonSpace = authored.match(/"[^"\r\n]+"\s*:([ \t]*)/)?.[1] ?? "";
|
|
17532
|
+
const commaSpace = authored.match(/,([ \t]*)/)?.[1] ?? "";
|
|
17533
|
+
const scanner = createScanner(content, false);
|
|
17534
|
+
const insertions = [];
|
|
17535
|
+
for (let token = scanner.scan(); token !== 17; token = scanner.scan()) {
|
|
17536
|
+
const spacing = token === 6 ? colonSpace : token === 5 ? commaSpace : "";
|
|
17537
|
+
const offset = scanner.getTokenOffset() + scanner.getTokenLength();
|
|
17538
|
+
if (spacing && !/\s/.test(content[offset] ?? "")) insertions.push({
|
|
17539
|
+
offset,
|
|
17540
|
+
text: spacing
|
|
17541
|
+
});
|
|
17542
|
+
}
|
|
17543
|
+
for (const insertion of insertions.reverse()) content = content.slice(0, insertion.offset) + insertion.text + content.slice(insertion.offset);
|
|
17544
|
+
}
|
|
17545
|
+
replace(edit.offset, edit.offset + edit.length, content);
|
|
17546
|
+
}
|
|
17167
17547
|
};
|
|
17168
17548
|
const renameKey = (path, oldKey, newKey) => {
|
|
17169
17549
|
const keyNode = treeAt([...path, oldKey])?.parent?.children?.[0];
|
|
17170
17550
|
if (!keyNode || keyNode.type !== "string") return false;
|
|
17171
|
-
|
|
17551
|
+
replace(keyNode.offset, keyNode.offset + keyNode.length, JSON.stringify(newKey));
|
|
17172
17552
|
return true;
|
|
17173
17553
|
};
|
|
17174
17554
|
const removePropertyWithoutFormatting = (path, key) => {
|
|
@@ -17187,14 +17567,14 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17187
17567
|
const lineStart = text.lastIndexOf("\n", property.offset - 1) + 1;
|
|
17188
17568
|
const nextLineStart = text.lastIndexOf("\n", next.offset - 1) + 1;
|
|
17189
17569
|
if (nextLineStart <= lineStart || text.slice(lineStart, property.offset).trim() !== "" || !/^\s*,\s*$/.test(text.slice(propertyEnd, nextLineStart))) return false;
|
|
17190
|
-
|
|
17570
|
+
replace(lineStart, nextLineStart, "");
|
|
17191
17571
|
return true;
|
|
17192
17572
|
}
|
|
17193
17573
|
const previous = properties[index - 1];
|
|
17194
17574
|
if (!previous || trailingLine.trim() !== "") return false;
|
|
17195
17575
|
const previousEnd = previous.offset + previous.length;
|
|
17196
17576
|
if (!/^\s*,\s*$/.test(text.slice(previousEnd, property.offset))) return false;
|
|
17197
|
-
|
|
17577
|
+
replace(previousEnd, propertyEnd, "");
|
|
17198
17578
|
return true;
|
|
17199
17579
|
};
|
|
17200
17580
|
const removeArrayItem = (path, index) => {
|
|
@@ -17218,7 +17598,7 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17218
17598
|
const nextLineStart = next && text.lastIndexOf("\n", next.offset - 1) + 1;
|
|
17219
17599
|
const separatorOnNextLine = itemLineEnd >= 0 && nextLineStart !== void 0 && /^[ \t]*,[ \t]*\r?\n$/.test(text.slice(itemLineEnd + 1, nextLineStart));
|
|
17220
17600
|
if (next && next.offset > lineEnd && (/^\s*,\s*\/\//.test(inlineSuffix) || /^\s*\/\//.test(inlineSuffix) && separatorOnNextLine)) {
|
|
17221
|
-
|
|
17601
|
+
replace(itemLineStart, separatorOnNextLine ? nextLineStart : itemLineEnd < 0 ? lineEnd : lineEnd + 1, "");
|
|
17222
17602
|
return true;
|
|
17223
17603
|
}
|
|
17224
17604
|
} else {
|
|
@@ -17228,7 +17608,7 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17228
17608
|
const withoutComma = beforeItem.replace(/^(\s*),/, "$1");
|
|
17229
17609
|
if (previousEnd !== void 0 && itemLineEnd >= 0 && itemLineStart > previousEnd && withoutComma !== beforeItem && stripComments(withoutComma).trim() === "") {
|
|
17230
17610
|
const separator = /^\s*$/.test(withoutComma) ? formattingOptions(text).eol : withoutComma;
|
|
17231
|
-
|
|
17611
|
+
replace(previousEnd, itemLineEnd + 1, separator);
|
|
17232
17612
|
return true;
|
|
17233
17613
|
}
|
|
17234
17614
|
}
|
|
@@ -17255,7 +17635,7 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17255
17635
|
end = nextLineStart;
|
|
17256
17636
|
} else if (!text.slice(end, nextItem.offset).includes("\n") && text.slice(end, nextItem.offset).trim() === "") end = nextItem.offset;
|
|
17257
17637
|
} else end = item.offset + item.length;
|
|
17258
|
-
|
|
17638
|
+
replace(start, end, "");
|
|
17259
17639
|
return true;
|
|
17260
17640
|
};
|
|
17261
17641
|
const appendArrayItemWithoutFormatting = (path, value) => {
|
|
@@ -17275,7 +17655,7 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17275
17655
|
if (indentation.trim() !== "") return false;
|
|
17276
17656
|
separator = `,${formattingOptions(text).eol}${indentation}`;
|
|
17277
17657
|
}
|
|
17278
|
-
|
|
17658
|
+
replace(lastEnd, lastEnd, separator + serialized);
|
|
17279
17659
|
return true;
|
|
17280
17660
|
};
|
|
17281
17661
|
const authoredBranchText = (path, index) => {
|
|
@@ -17292,6 +17672,39 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17292
17672
|
}
|
|
17293
17673
|
return `${leadingText}${text.slice(branchNode.offset, branchNode.offset + branchNode.length)}`;
|
|
17294
17674
|
};
|
|
17675
|
+
const actionOrder = (previous, next, path) => {
|
|
17676
|
+
const group = path.at(-1);
|
|
17677
|
+
if (group !== "entry" && group !== "exit" && group !== "actions") return void 0;
|
|
17678
|
+
const owner = nextGraph.nodes.filter((node) => {
|
|
17679
|
+
return (node.parentId ? [...statePath(nextGraph, node.id), node.data.key] : []).every((key, index) => path[index] === key);
|
|
17680
|
+
}).sort((a, b) => (statePath(nextGraph, b.id)?.length ?? 0) - (statePath(nextGraph, a.id)?.length ?? 0))[0];
|
|
17681
|
+
if (!owner) return void 0;
|
|
17682
|
+
const previousNode = previousGraph.nodes.find((node) => node.id === owner.id);
|
|
17683
|
+
const serialize = (actions) => actions.map(({ type, params }) => ({
|
|
17684
|
+
type,
|
|
17685
|
+
...params && Object.keys(params).length ? { params } : {}
|
|
17686
|
+
}));
|
|
17687
|
+
const normalized = (values) => values.map((value) => typeof value === "string" ? { type: value } : value);
|
|
17688
|
+
const ownerPath = owner.parentId ? [...statePath(nextGraph, owner.id), owner.data.key] : [];
|
|
17689
|
+
const transitionPath = path.slice(ownerPath.length);
|
|
17690
|
+
const event = transitionPath[0] === "on" ? transitionPath[1] : transitionPath[0] === "always" ? "" : void 0;
|
|
17691
|
+
const matchingEdges = nextGraph.edges.filter((edge) => edge.sourceId === owner.id && (event === void 0 || edge.data.eventType === event));
|
|
17692
|
+
const branchIndex = typeof path.at(-2) === "number" ? path.at(-2) : 0;
|
|
17693
|
+
const edgeId = event === void 0 ? void 0 : matchingEdges[branchIndex]?.id;
|
|
17694
|
+
const matches = (group === "actions" ? previousGraph.edges.filter((edge) => edge.sourceId === owner.id && (event === void 0 || edge.id === edgeId)).map((edge) => ({
|
|
17695
|
+
previous: edge.data.actions ?? [],
|
|
17696
|
+
next: nextGraph.edges.find((candidate) => candidate.id === edge.id)?.data.actions ?? []
|
|
17697
|
+
})) : [{
|
|
17698
|
+
previous: previousNode?.data[group] ?? [],
|
|
17699
|
+
next: owner.data[group] ?? []
|
|
17700
|
+
}]).filter((candidate) => sameValue(serialize(candidate.previous), normalized(previous)) && sameValue(serialize(candidate.next), normalized(next)));
|
|
17701
|
+
if (matches.length !== 1) return void 0;
|
|
17702
|
+
const candidate = matches[0];
|
|
17703
|
+
const ids = candidate.previous.map((action) => action.id);
|
|
17704
|
+
if (ids.some((id) => !id) || new Set(ids).size !== ids.length) return void 0;
|
|
17705
|
+
const order = candidate.next.map((action) => ids.indexOf(action.id));
|
|
17706
|
+
return candidate.next.every((action) => action.id) ? order : void 0;
|
|
17707
|
+
};
|
|
17295
17708
|
const visit = (previous, next, path) => {
|
|
17296
17709
|
if (sameValue(previous, next)) return true;
|
|
17297
17710
|
const sourceNode = treeAt(path);
|
|
@@ -17311,10 +17724,15 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17311
17724
|
const authoredAction = Object.keys(next).length === 1 ? next.type : next;
|
|
17312
17725
|
if (text.slice(sourceNode.offset + 1, sourceNode.offset + sourceNode.length - 1) === "") {
|
|
17313
17726
|
const insertion = sourceNode.offset + 1;
|
|
17314
|
-
|
|
17727
|
+
replace(insertion, insertion, JSON.stringify(authoredAction));
|
|
17315
17728
|
} else setValue(path, [authoredAction]);
|
|
17316
17729
|
return true;
|
|
17317
17730
|
}
|
|
17731
|
+
if (sourceNode?.type === "array" && sourceNode.children?.length === 1 && isRecord$2(previous) && Array.isArray(next) && [
|
|
17732
|
+
"entry",
|
|
17733
|
+
"exit",
|
|
17734
|
+
"actions"
|
|
17735
|
+
].includes(String(path.at(-1)))) return visit([previous], next, path);
|
|
17318
17736
|
if (sourceNode?.type === "array" && sourceNode.children?.length === 1 && isRecord$2(previous) && isRecord$2(next)) return visit(previous, next, [...path, 0]);
|
|
17319
17737
|
if (isRecord$2(previous) && isRecord$2(next) && sourceNode?.type === "object") {
|
|
17320
17738
|
const handledOld = /* @__PURE__ */ new Set();
|
|
@@ -17375,14 +17793,14 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17375
17793
|
index
|
|
17376
17794
|
]);
|
|
17377
17795
|
if (!insertedNode) return false;
|
|
17378
|
-
|
|
17796
|
+
replace(insertedNode.offset, insertedNode.offset + insertedNode.length, authoredText);
|
|
17379
17797
|
}
|
|
17380
17798
|
continue;
|
|
17381
17799
|
}
|
|
17382
17800
|
if (!visit(previous[key], next[key], [...path, key])) return false;
|
|
17383
17801
|
} else {
|
|
17384
17802
|
const existing = key === "actions" ? treeAt([...path, key]) : void 0;
|
|
17385
|
-
if (existing?.type === "array")
|
|
17803
|
+
if (existing?.type === "array") replace(existing.offset, existing.offset + existing.length, "[]");
|
|
17386
17804
|
else if ((key === "entry" || key === "exit") && removePropertyWithoutFormatting(path, key)) {} else setValue([...path, key], void 0);
|
|
17387
17805
|
}
|
|
17388
17806
|
}
|
|
@@ -17395,11 +17813,33 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17395
17813
|
if (originalBranch !== void 0) {
|
|
17396
17814
|
const insertedNode = treeAt([...path, key]);
|
|
17397
17815
|
if (!insertedNode) return false;
|
|
17398
|
-
|
|
17816
|
+
replace(insertedNode.offset, insertedNode.offset + insertedNode.length, originalBranch);
|
|
17399
17817
|
}
|
|
17400
17818
|
}
|
|
17401
17819
|
return true;
|
|
17402
17820
|
}
|
|
17821
|
+
if (Array.isArray(previous) && sourceNode?.type === "array" && (Array.isArray(next) || isRecord$2(next))) {
|
|
17822
|
+
const nextValues = Array.isArray(next) ? next : [next];
|
|
17823
|
+
const order = actionOrder(previous, nextValues, path);
|
|
17824
|
+
const pureDeletion = previous.length === nextValues.length + 1 && previous.some((_, index) => sameValue(previous.filter((_, candidate) => candidate !== index), nextValues));
|
|
17825
|
+
const lastSourceItem = sourceNode.children?.at(-1);
|
|
17826
|
+
const sourceSuffix = lastSourceItem ? text.slice(lastSourceItem.offset + lastSourceItem.length, sourceNode.offset + sourceNode.length - 1) : "";
|
|
17827
|
+
const pureAppend = !(stripComments(sourceSuffix) !== sourceSuffix) && order && nextValues.length > previous.length && order.slice(0, previous.length).every((oldIndex, index) => oldIndex === index);
|
|
17828
|
+
if (order && !pureDeletion && !pureAppend && (previous.length !== nextValues.length || order.some((oldIndex, index) => oldIndex !== index))) {
|
|
17829
|
+
for (const [index, oldIndex] of order.entries()) if (oldIndex >= 0 && !visit(previous[oldIndex], nextValues[index], [...path, oldIndex])) return false;
|
|
17830
|
+
const array = treeAt(path);
|
|
17831
|
+
if (!array) return false;
|
|
17832
|
+
const inserted = new Map(order.flatMap((oldIndex, index) => {
|
|
17833
|
+
if (oldIndex >= 0) return [];
|
|
17834
|
+
const value = nextValues[index];
|
|
17835
|
+
return [[index, JSON.stringify(value)]];
|
|
17836
|
+
}));
|
|
17837
|
+
const edit = reorderedActionArray(text, array, order, inserted);
|
|
17838
|
+
if (!edit) return false;
|
|
17839
|
+
replace(edit.start, edit.end, edit.text);
|
|
17840
|
+
return true;
|
|
17841
|
+
}
|
|
17842
|
+
}
|
|
17403
17843
|
if (Array.isArray(previous) && isRecord$2(next) && sourceNode?.type === "array") {
|
|
17404
17844
|
if (previous.length === 1 && isRecord$2(previous[0])) return visit(previous[0], next, [...path, 0]);
|
|
17405
17845
|
const matches = previous.flatMap((value, index) => sameValue(value, next) ? [index] : []);
|
|
@@ -17431,25 +17871,7 @@ function preserveXStateJson(document, previousGraph, nextGraph, machineConfig, p
|
|
|
17431
17871
|
parseTree(text, errors, { allowTrailingComma: true });
|
|
17432
17872
|
if (errors.length) return null;
|
|
17433
17873
|
if (text === original) return [];
|
|
17434
|
-
|
|
17435
|
-
while (start < original.length && start < text.length && original[start] === text[start]) start++;
|
|
17436
|
-
let oldEnd = original.length;
|
|
17437
|
-
let newEnd = text.length;
|
|
17438
|
-
while (oldEnd > start && newEnd > start && original[oldEnd - 1] === text[newEnd - 1]) {
|
|
17439
|
-
oldEnd--;
|
|
17440
|
-
newEnd--;
|
|
17441
|
-
}
|
|
17442
|
-
const startPosition = document.positionAt(start);
|
|
17443
|
-
const endPosition = document.positionAt(oldEnd);
|
|
17444
|
-
return [{
|
|
17445
|
-
range: {
|
|
17446
|
-
startLine: startPosition.line,
|
|
17447
|
-
startChar: startPosition.character,
|
|
17448
|
-
endLine: endPosition.line,
|
|
17449
|
-
endChar: endPosition.character
|
|
17450
|
-
},
|
|
17451
|
-
newText: text.slice(start, newEnd)
|
|
17452
|
-
}];
|
|
17874
|
+
return preservedText.replacements(document);
|
|
17453
17875
|
}
|
|
17454
17876
|
const xstateAdapter = {
|
|
17455
17877
|
id: "xstate",
|
|
@@ -17538,7 +17960,7 @@ const xstateJsonAdapter = {
|
|
|
17538
17960
|
if (options?.sourceUpdateStrategy === "rewrite") return createSerializedDocumentReplacement(document, options, "xstate-json");
|
|
17539
17961
|
const patches = options?.preserveStatelyMetadata === false ? stripPresentationPatches(options.patches ?? []) : options?.patches ?? [];
|
|
17540
17962
|
if (!options || !patches.length) return [];
|
|
17541
|
-
return preserveXStateJson(document, options.prevGraph, options.nextGraph, machineConfig, patches, options.preserveStatelyMetadata ?? true) ?? [];
|
|
17963
|
+
return preserveXStateJson(document, options.prevGraph, options.nextGraph, machineConfig, patches, options.preserveStatelyMetadata ?? true, options.authoredIdChanges) ?? [];
|
|
17542
17964
|
}
|
|
17543
17965
|
};
|
|
17544
17966
|
const asyncAdapter = createSerializedExportAdapter("async", (document, text) => isJavaScriptOrTypeScriptFile(document.fileName) && looksLikeAsyncWorkflow(text));
|
|
@@ -17821,7 +18243,7 @@ function diagnosticKey$1(diagnostic) {
|
|
|
17821
18243
|
}
|
|
17822
18244
|
|
|
17823
18245
|
//#endregion
|
|
17824
|
-
//#region ../editor-sync/dist/localBackend-
|
|
18246
|
+
//#region ../editor-sync/dist/localBackend-DH1qEsOz.mjs
|
|
17825
18247
|
var LocalEditorSyncBackend = class {
|
|
17826
18248
|
constructor(access) {
|
|
17827
18249
|
this.access = access;
|
|
@@ -17960,7 +18382,7 @@ function toFileName(uriOrPath) {
|
|
|
17960
18382
|
}
|
|
17961
18383
|
|
|
17962
18384
|
//#endregion
|
|
17963
|
-
//#region ../editor-sync/dist/pushMerge-
|
|
18385
|
+
//#region ../editor-sync/dist/pushMerge-piN5M1Ej.mjs
|
|
17964
18386
|
const GEOMETRY_KEYS = [
|
|
17965
18387
|
"x",
|
|
17966
18388
|
"y",
|
|
@@ -17977,6 +18399,36 @@ const DEFAULT_ANNOTATION_SIZE = {
|
|
|
17977
18399
|
};
|
|
17978
18400
|
const NEW_NODE_GAP = 80;
|
|
17979
18401
|
const MAX_CONCURRENT_MERGE_ATTEMPTS = 3;
|
|
18402
|
+
/** Match presentation events independently of converter-specific entity IDs. */
|
|
18403
|
+
function presentationMatchingGraph(graph) {
|
|
18404
|
+
const nodes = new Map(graph.nodes.map((node) => [node.id, node]));
|
|
18405
|
+
return {
|
|
18406
|
+
...graph,
|
|
18407
|
+
edges: graph.edges.map((edge) => {
|
|
18408
|
+
let eventType = edge.data.eventType;
|
|
18409
|
+
if (typeof eventType !== "string") return edge;
|
|
18410
|
+
const sourceSuffix = `.${edge.sourceId}`;
|
|
18411
|
+
if (eventType.startsWith("xstate.after.") && eventType.endsWith(sourceSuffix)) eventType = eventType.slice(0, -sourceSuffix.length);
|
|
18412
|
+
else if (/^(?:@statelyai?\.state\.done\.|xstate\.done\.state(?:\.|$))/.test(eventType)) eventType = "xstate.done.state";
|
|
18413
|
+
else {
|
|
18414
|
+
const ref = /^@statelyai?\.invoke\.(done|error|snapshot|timeout)\.(.+)$/.exec(eventType);
|
|
18415
|
+
const literal = /^xstate\.(done|error|snapshot|timeout)\.actor\.(.+)$/.exec(eventType);
|
|
18416
|
+
const match = ref ?? literal;
|
|
18417
|
+
if (match) {
|
|
18418
|
+
const index = (nodes.get(edge.sourceId)?.data?.invokes ?? []).findIndex((invoke) => invoke.id === match[2] || "invocationId" in invoke && invoke.invocationId === match[2]);
|
|
18419
|
+
if (index >= 0) eventType = `@presentation.invoke.${match[1]}.${index}`;
|
|
18420
|
+
}
|
|
18421
|
+
}
|
|
18422
|
+
return {
|
|
18423
|
+
...edge,
|
|
18424
|
+
data: {
|
|
18425
|
+
...edge.data,
|
|
18426
|
+
eventType
|
|
18427
|
+
}
|
|
18428
|
+
};
|
|
18429
|
+
})
|
|
18430
|
+
};
|
|
18431
|
+
}
|
|
17980
18432
|
function indexBySemanticId(normalized, original) {
|
|
17981
18433
|
const bySemanticId = /* @__PURE__ */ new Map();
|
|
17982
18434
|
normalized.forEach((entity, index) => {
|
|
@@ -18014,6 +18466,7 @@ function restoreEdgeFields(edges, remoteEdgesById, remoteEdgeIdByLocalId) {
|
|
|
18014
18466
|
const remote = remoteId ? remoteEdgesById.get(remoteId) : void 0;
|
|
18015
18467
|
if (remote) {
|
|
18016
18468
|
if (remote.uniqueId !== void 0) edge.uniqueId = remote.uniqueId;
|
|
18469
|
+
edge.data.eventTypeData = structuredClone(remote.data.eventTypeData);
|
|
18017
18470
|
if (remote.data.assets !== void 0) edge.data.assets = structuredClone(remote.data.assets);
|
|
18018
18471
|
}
|
|
18019
18472
|
}
|
|
@@ -18058,7 +18511,7 @@ function mergePresentationIntoRemoteDefinition(editedDefinition, remoteDefinitio
|
|
|
18058
18511
|
remoteGraph.nodes = remoteGraph.nodes.filter((node) => !remoteAnnotationIds.has(node.id));
|
|
18059
18512
|
editedGraph.edges = editedGraph.edges.filter((edge) => !editedAnnotationIds.has(edge.sourceId) && !editedAnnotationIds.has(edge.targetId));
|
|
18060
18513
|
remoteGraph.edges = remoteGraph.edges.filter((edge) => !remoteAnnotationIds.has(edge.sourceId) && !remoteAnnotationIds.has(edge.targetId));
|
|
18061
|
-
const { base, compare } = diffGraphsSemantically(remoteGraph, editedGraph);
|
|
18514
|
+
const { base, compare } = diffGraphsSemantically(presentationMatchingGraph(remoteGraph), presentationMatchingGraph(editedGraph));
|
|
18062
18515
|
const remoteNodesBySemanticId = indexBySemanticId(base.nodes, remoteGraph.nodes);
|
|
18063
18516
|
const editedNodesBySemanticId = indexBySemanticId(compare.nodes, editedGraph.nodes);
|
|
18064
18517
|
const remoteEdgesBySemanticId = indexBySemanticId(base.edges, remoteGraph.edges);
|
|
@@ -18067,6 +18520,7 @@ function mergePresentationIntoRemoteDefinition(editedDefinition, remoteDefinitio
|
|
|
18067
18520
|
const mergedNodesById = collectDigraphNodes(merged.rootNode, /* @__PURE__ */ new Map());
|
|
18068
18521
|
const editedNodesById = collectDigraphNodes(editedDefinition.rootNode, /* @__PURE__ */ new Map());
|
|
18069
18522
|
const editedNodeIdToRemoteNodeId = /* @__PURE__ */ new Map();
|
|
18523
|
+
const editedEdgeIdToRemoteEdgeId = /* @__PURE__ */ new Map();
|
|
18070
18524
|
for (const [semanticId, remoteNode] of remoteNodesBySemanticId) {
|
|
18071
18525
|
const editedNode = editedNodesBySemanticId.get(semanticId);
|
|
18072
18526
|
const target = mergedNodesById.get(remoteNode.id);
|
|
@@ -18089,6 +18543,7 @@ function mergePresentationIntoRemoteDefinition(editedDefinition, remoteDefinitio
|
|
|
18089
18543
|
const target = mergedEdgesById.get(remoteEdge.id);
|
|
18090
18544
|
const source = editedEdge ? editedEdgesById.get(editedEdge.id) : void 0;
|
|
18091
18545
|
if (!editedEdge || !target || !source) continue;
|
|
18546
|
+
editedEdgeIdToRemoteEdgeId.set(editedEdge.id, remoteEdge.id);
|
|
18092
18547
|
for (const field of ["position", "size"]) replacePresentationField(target, source, field);
|
|
18093
18548
|
for (const field of ["color", "assets"]) replacePresentationField(target.data, source.data, field);
|
|
18094
18549
|
}
|
|
@@ -18097,7 +18552,10 @@ function mergePresentationIntoRemoteDefinition(editedDefinition, remoteDefinitio
|
|
|
18097
18552
|
collectAnnotations(editedDefinition.rootNode, null, editedAnnotations);
|
|
18098
18553
|
for (const annotation of editedAnnotations) {
|
|
18099
18554
|
const remoteParentId = annotation.parentId ? editedNodeIdToRemoteNodeId.get(annotation.parentId) : merged.rootNode.id;
|
|
18100
|
-
|
|
18555
|
+
const parent = remoteParentId ? mergedNodesById.get(remoteParentId) : void 0;
|
|
18556
|
+
const note = structuredClone(annotation.node);
|
|
18557
|
+
if (Array.isArray(note.data.data?.referenceIds)) note.data.data.referenceIds = note.data.data.referenceIds.map((id) => editedNodeIdToRemoteNodeId.get(id) ?? editedEdgeIdToRemoteEdgeId.get(id) ?? id);
|
|
18558
|
+
parent?.nodes.push(note);
|
|
18101
18559
|
}
|
|
18102
18560
|
return merged;
|
|
18103
18561
|
}
|
|
@@ -18141,7 +18599,7 @@ function mergeLocalGraphIntoRemoteDefinition(localGraph, remoteDefinition) {
|
|
|
18141
18599
|
const remoteGraph = fromStudioMachine(remoteDefinition);
|
|
18142
18600
|
remoteGraph.nodes = remoteGraph.nodes.filter((node) => !annotationIds.has(node.id));
|
|
18143
18601
|
remoteGraph.edges = remoteGraph.edges.filter((edge) => !annotationIds.has(edge.sourceId) && !annotationIds.has(edge.targetId));
|
|
18144
|
-
const { base, compare, summary } = diffGraphsSemantically(remoteGraph, localGraph);
|
|
18602
|
+
const { base, compare, summary } = diffGraphsSemantically(presentationMatchingGraph(remoteGraph), presentationMatchingGraph(localGraph));
|
|
18145
18603
|
const remoteNodesBySemanticId = indexBySemanticId(base.nodes, remoteGraph.nodes);
|
|
18146
18604
|
const remoteEdgesBySemanticId = indexBySemanticId(base.edges, remoteGraph.edges);
|
|
18147
18605
|
const merged = structuredClone(localGraph);
|
|
@@ -18165,7 +18623,10 @@ function mergeLocalGraphIntoRemoteDefinition(localGraph, remoteDefinition) {
|
|
|
18165
18623
|
});
|
|
18166
18624
|
const definition = toStudioMachine(merged);
|
|
18167
18625
|
restoreNodeFields(definition.rootNode, remoteNodesById, remoteNodeIdByLocalId);
|
|
18168
|
-
restoreEdgeFields(definition.edges, new Map(remoteDefinition.edges.map((edge) => [edge.id, edge])),
|
|
18626
|
+
restoreEdgeFields(definition.edges, new Map(remoteDefinition.edges.map((edge) => [edge.id, edge])), new Map(definition.edges.flatMap((edge, index) => {
|
|
18627
|
+
const remoteId = remoteEdgeIdByLocalId.get(merged.edges[index].id);
|
|
18628
|
+
return remoteId ? [[edge.id, remoteId]] : [];
|
|
18629
|
+
})));
|
|
18169
18630
|
ensureCompleteNodeGeometry(definition.rootNode);
|
|
18170
18631
|
return {
|
|
18171
18632
|
definition: {
|
|
@@ -18230,7 +18691,7 @@ async function updateMachineDefinition(client, machineId, localGraph) {
|
|
|
18230
18691
|
}
|
|
18231
18692
|
|
|
18232
18693
|
//#endregion
|
|
18233
|
-
//#region ../editor-sync/dist/presentationMetadata-
|
|
18694
|
+
//#region ../editor-sync/dist/presentationMetadata-YX6iRP4T.mjs
|
|
18234
18695
|
function createStudioPresentationMetadataStore(client, machineId) {
|
|
18235
18696
|
const load = async () => {
|
|
18236
18697
|
return {
|
|
@@ -18249,7 +18710,7 @@ function createStudioPresentationMetadataStore(client, machineId) {
|
|
|
18249
18710
|
},
|
|
18250
18711
|
async persist(_graph, context) {
|
|
18251
18712
|
const serialized = context?.serialized?.digraph;
|
|
18252
|
-
if (!serialized)
|
|
18713
|
+
if (!serialized) throw new Error("Studio presentation requires a serialized digraph. Presentation was not saved.");
|
|
18253
18714
|
const editedDefinition = JSON.parse(serialized);
|
|
18254
18715
|
const latest = await client.machines.get(machineId);
|
|
18255
18716
|
if (!latest.updatedAt) throw new Error(`Studio machine "${machineId}" did not provide an updatedAt guard. Presentation was not saved.`);
|
|
@@ -18310,10 +18771,29 @@ function createLocalPresentationMetadataRepository(file) {
|
|
|
18310
18771
|
};
|
|
18311
18772
|
} };
|
|
18312
18773
|
}
|
|
18313
|
-
function applyPresentationInitializer(initializer, current) {
|
|
18774
|
+
function applyPresentationInitializer(initializer, current, convertStudioDefinition = fromStudioMachine) {
|
|
18314
18775
|
if (initializer.type === "overlay") return applyPresentationMetadata(initializer.overlay, current);
|
|
18315
18776
|
if (!isGraph(current)) return current;
|
|
18316
|
-
|
|
18777
|
+
const presentationGraph = convertStudioDefinition(initializer.definition);
|
|
18778
|
+
if (!isGraph(presentationGraph)) return current;
|
|
18779
|
+
const overlay = createPresentationSnapshot(presentationGraph);
|
|
18780
|
+
const sourceIds = presentationIds(current);
|
|
18781
|
+
const studioIds = presentationIds(presentationGraph);
|
|
18782
|
+
const liveIds = /* @__PURE__ */ new Map();
|
|
18783
|
+
for (const kind of ["nodes", "edges"]) {
|
|
18784
|
+
const bySemanticId = new Map(current[kind].map((entity, index) => [sourceIds[kind][index], entity.id]));
|
|
18785
|
+
presentationGraph[kind].forEach((entity, index) => {
|
|
18786
|
+
const liveId = bySemanticId.get(studioIds[kind][index]);
|
|
18787
|
+
if (typeof liveId === "string") liveIds.set(entity.id, liveId);
|
|
18788
|
+
});
|
|
18789
|
+
}
|
|
18790
|
+
const sourceEntityIds = new Set([...current.nodes, ...current.edges].map((entity) => entity.id));
|
|
18791
|
+
overlay.annotations = (overlay.annotations ?? []).filter((annotation) => annotation.parentId == null || liveIds.has(annotation.parentId));
|
|
18792
|
+
for (const annotation of overlay.annotations) {
|
|
18793
|
+
annotation.parentId = liveIds.get(annotation.parentId) ?? annotation.parentId;
|
|
18794
|
+
if (Array.isArray(annotation.data?.referenceIds)) annotation.data.referenceIds = annotation.data.referenceIds.map((id) => liveIds.get(id) ?? id).filter((id) => sourceEntityIds.has(id));
|
|
18795
|
+
}
|
|
18796
|
+
return applyPresentationMetadata(overlay, current);
|
|
18317
18797
|
}
|
|
18318
18798
|
function applyPresentationMetadata(overlay, current) {
|
|
18319
18799
|
if (!isPresentationOverlay(overlay) || !isGraph(current)) return current;
|
|
@@ -18321,6 +18801,7 @@ function applyPresentationMetadata(overlay, current) {
|
|
|
18321
18801
|
const addedNodes = [];
|
|
18322
18802
|
const addedEdges = [];
|
|
18323
18803
|
const semanticIds = overlay.identity === "semantic-v1" ? presentationIds(result) : void 0;
|
|
18804
|
+
const legacyIds = semanticIds ? presentationIds(result, false) : void 0;
|
|
18324
18805
|
const renamedGuardPresentation = semanticIds ? matchUniqueGuardRenames(semanticIds.edges, overlay.edges ?? {}) : /* @__PURE__ */ new Map();
|
|
18325
18806
|
for (const [index, node] of result.nodes.entries()) {
|
|
18326
18807
|
normalizeCanonicalGeometry(node);
|
|
@@ -18331,7 +18812,7 @@ function applyPresentationMetadata(overlay, current) {
|
|
|
18331
18812
|
for (const [index, edge] of result.edges.entries()) {
|
|
18332
18813
|
normalizeCanonicalGeometry(edge);
|
|
18333
18814
|
const semanticId = semanticIds?.edges[index] ?? edge.id;
|
|
18334
|
-
const presentation = overlay.edges?.[semanticId] ?? renamedGuardPresentation.get(semanticId);
|
|
18815
|
+
const presentation = overlay.edges?.[semanticId] ?? overlay.edges?.[legacyIds?.edges[index] ?? edge.id] ?? renamedGuardPresentation.get(semanticId);
|
|
18335
18816
|
if (presentation) applyEntityPresentation(presentation, edge);
|
|
18336
18817
|
else addedEdges.push(edge);
|
|
18337
18818
|
}
|
|
@@ -18411,6 +18892,7 @@ function entityPresentationMap(entities, includeSourceSide, ids) {
|
|
|
18411
18892
|
const presentation = compactDefined({
|
|
18412
18893
|
...pick(canonicalGeometry(entity), GEOMETRY_FIELDS),
|
|
18413
18894
|
color: clone(entity.data?.color),
|
|
18895
|
+
layout: clone(entity.data?.layout),
|
|
18414
18896
|
assets: clone(entity.data?.assets),
|
|
18415
18897
|
sourceSide: includeSourceSide ? clone(entity.data?.sourceSide) : void 0
|
|
18416
18898
|
});
|
|
@@ -18418,7 +18900,8 @@ function entityPresentationMap(entities, includeSourceSide, ids) {
|
|
|
18418
18900
|
});
|
|
18419
18901
|
return entries.length > 0 ? Object.fromEntries(entries) : void 0;
|
|
18420
18902
|
}
|
|
18421
|
-
function presentationIds(graph) {
|
|
18903
|
+
function presentationIds(graph, canonicalEvents = true) {
|
|
18904
|
+
const matchingGraph = canonicalEvents ? presentationMatchingGraph(graph) : graph;
|
|
18422
18905
|
const normalized = normalizeGraphForSemanticDiff({
|
|
18423
18906
|
id: graph.id ?? "presentation",
|
|
18424
18907
|
nodes: graph.nodes.map((node) => ({
|
|
@@ -18426,7 +18909,7 @@ function presentationIds(graph) {
|
|
|
18426
18909
|
parentId: node.parentId,
|
|
18427
18910
|
data: { key: node.data?.key }
|
|
18428
18911
|
})),
|
|
18429
|
-
edges:
|
|
18912
|
+
edges: matchingGraph.edges.map((edge) => ({
|
|
18430
18913
|
id: edge.id,
|
|
18431
18914
|
sourceId: edge.sourceId,
|
|
18432
18915
|
targetId: edge.targetId,
|
|
@@ -18459,10 +18942,12 @@ function createAnnotationSnapshot(annotations) {
|
|
|
18459
18942
|
parentId: annotation.parentId,
|
|
18460
18943
|
content: clone(annotation.content),
|
|
18461
18944
|
...pick(geometry, GEOMETRY_FIELDS),
|
|
18945
|
+
...pick(annotation, ["width", "height"]),
|
|
18462
18946
|
data: compactDefined({
|
|
18463
18947
|
referenceIds: clone(annotation.data?.referenceIds),
|
|
18464
18948
|
color: clone(annotation.data?.color),
|
|
18465
|
-
textAlign: clone(annotation.data?.textAlign)
|
|
18949
|
+
textAlign: clone(annotation.data?.textAlign),
|
|
18950
|
+
placement: clone(annotation.data?.placement)
|
|
18466
18951
|
})
|
|
18467
18952
|
});
|
|
18468
18953
|
});
|
|
@@ -18481,7 +18966,8 @@ function applyEntityPresentation(presentation, entity) {
|
|
|
18481
18966
|
for (const field of [
|
|
18482
18967
|
"color",
|
|
18483
18968
|
"assets",
|
|
18484
|
-
"sourceSide"
|
|
18969
|
+
"sourceSide",
|
|
18970
|
+
"layout"
|
|
18485
18971
|
]) copyField(presentation, entity.data, field);
|
|
18486
18972
|
}
|
|
18487
18973
|
function placeAddedNodes(added, allNodes) {
|
|
@@ -19004,7 +19490,7 @@ const editorSyncApplyResponseSchema = z$1.object({ replacements: z$1.array(edito
|
|
|
19004
19490
|
const editorSyncAccessResponseSchema = z$1.object({ access: editorSyncAccessSchema });
|
|
19005
19491
|
|
|
19006
19492
|
//#endregion
|
|
19007
|
-
//#region ../editor-sync/dist/host-
|
|
19493
|
+
//#region ../editor-sync/dist/host-BX7mLyHj.mjs
|
|
19008
19494
|
let diagnosticSequence = 0;
|
|
19009
19495
|
function presentationsEqual(first, second) {
|
|
19010
19496
|
return JSON.stringify(createPresentationSnapshot(first)) === JSON.stringify(createPresentationSnapshot(second));
|
|
@@ -19031,6 +19517,12 @@ var EditorSyncError = class extends Error {
|
|
|
19031
19517
|
this.code = code;
|
|
19032
19518
|
}
|
|
19033
19519
|
};
|
|
19520
|
+
function isEditorSyncAuthenticationError(error) {
|
|
19521
|
+
return error instanceof Error && "status" in error && error.status === 401;
|
|
19522
|
+
}
|
|
19523
|
+
function authenticationRecoveryInstructions(recovery) {
|
|
19524
|
+
return recovery.host === "cli" ? "Run `npx statelyai login` in your terminal, then reload the editor." : "In the VS Code Command Palette, run “Stately: Sign In”, then reopen the visual editor.";
|
|
19525
|
+
}
|
|
19034
19526
|
async function fetchEditorSyncAccess(options) {
|
|
19035
19527
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
19036
19528
|
const url = new URL("/api/editor-sync/access", `${options.editorUrl.replace(/\/+$/, "")}/`);
|
|
@@ -19124,12 +19616,14 @@ var EditorHostSession = class {
|
|
|
19124
19616
|
await this.initialize();
|
|
19125
19617
|
} catch (error) {
|
|
19126
19618
|
const message = formatError(error, "Failed to initialize the visual editor.");
|
|
19619
|
+
const recovery = isEditorSyncAuthenticationError(error) ? this.options.authenticationRecovery : void 0;
|
|
19127
19620
|
this.options.send({
|
|
19128
19621
|
type: "@statelyai.error",
|
|
19129
19622
|
code: "initialization_failed",
|
|
19130
|
-
message
|
|
19623
|
+
message,
|
|
19624
|
+
...recovery ? { authenticationRecovery: recovery } : {}
|
|
19131
19625
|
});
|
|
19132
|
-
this.options.showError?.(message);
|
|
19626
|
+
this.options.showError?.(recovery ? `${message}\n${authenticationRecoveryInstructions(recovery)}` : message);
|
|
19133
19627
|
}
|
|
19134
19628
|
break;
|
|
19135
19629
|
case "@statelyai.loaded":
|
|
@@ -19330,7 +19824,7 @@ var EditorHostSession = class {
|
|
|
19330
19824
|
return;
|
|
19331
19825
|
}
|
|
19332
19826
|
const documents = await this.options.source.collectDocuments(sourceLocationUris(this.currentSourceLocations));
|
|
19333
|
-
const serialized = await this.getSerializedPayload();
|
|
19827
|
+
const serialized = await this.getSerializedPayload(message.serialized);
|
|
19334
19828
|
const response = await this.options.sync.apply({
|
|
19335
19829
|
rootUri: this.options.source.rootUri,
|
|
19336
19830
|
rootFileName: this.options.source.rootFileName,
|
|
@@ -19379,7 +19873,7 @@ var EditorHostSession = class {
|
|
|
19379
19873
|
});
|
|
19380
19874
|
}
|
|
19381
19875
|
async acknowledgeWithoutSourceChanges(message, serialized) {
|
|
19382
|
-
await this.persistPresentation(message.graph, serialized ?? await this.getSerializedPayload());
|
|
19876
|
+
await this.persistPresentation(message.graph, serialized ?? await this.getSerializedPayload(message.serialized));
|
|
19383
19877
|
this.currentGraph = message.graph;
|
|
19384
19878
|
this.lastPersistedGraph = message.graph;
|
|
19385
19879
|
this.options.send({
|
|
@@ -19477,11 +19971,12 @@ var EditorHostSession = class {
|
|
|
19477
19971
|
this.watchedSourceUris.clear();
|
|
19478
19972
|
for (const uri of sourceLocationUris(sourceLocations)) if (uri !== this.options.source.rootUri) this.watchedSourceUris.add(uri);
|
|
19479
19973
|
}
|
|
19480
|
-
async getSerializedPayload() {
|
|
19974
|
+
async getSerializedPayload(provided) {
|
|
19481
19975
|
const format = this.currentFormat;
|
|
19482
|
-
|
|
19976
|
+
const formats = [...new Set([...format && format !== "xstate" ? [format] : [], ...this.initialPresentation?.type === "studio" ? ["digraph"] : []])];
|
|
19977
|
+
if (formats.length === 0) return void 0;
|
|
19483
19978
|
try {
|
|
19484
|
-
return
|
|
19979
|
+
return Object.fromEntries(await Promise.all(formats.map(async (format) => [format, provided?.[format] ?? await this.requestSerialized(format)])));
|
|
19485
19980
|
} catch {
|
|
19486
19981
|
return;
|
|
19487
19982
|
}
|
|
@@ -19856,14 +20351,31 @@ async function assertSourceSaveMatchesGraph(input) {
|
|
|
19856
20351
|
const graph = convertMachineToGraph({
|
|
19857
20352
|
machine: parsed.machine,
|
|
19858
20353
|
format,
|
|
19859
|
-
|
|
20354
|
+
profile: input.profile ?? (format === "json" ? input.graph.data?.profile : void 0)
|
|
19860
20355
|
}).graph;
|
|
20356
|
+
if (format === "json" && graph.data.schemas && input.machineConfig?.schemas !== void 0) {
|
|
20357
|
+
const root = graph.nodes.find((node) => !node.parentId);
|
|
20358
|
+
if (root) root.data.schemas = graph.data.schemas;
|
|
20359
|
+
}
|
|
19861
20360
|
return graphToMachineConfig(graph);
|
|
19862
20361
|
};
|
|
19863
20362
|
const expectedConfig = comparableMachineConfig(stripStatelyMetadata(input.machineConfig));
|
|
19864
20363
|
const actualConfig = comparableMachineConfig(stripStatelyMetadata(projectConfig(documents)));
|
|
20364
|
+
const baselineConfig = comparableMachineConfig(stripStatelyMetadata(projectConfig(input.documents)));
|
|
20365
|
+
const schemaEvents = (config) => config?.schemas?.events;
|
|
20366
|
+
const expectedEvents = schemaEvents(expectedConfig);
|
|
20367
|
+
const eventOrigins = input.graph.data?.schemaMeta?.events;
|
|
20368
|
+
let removedAutoEvent = false;
|
|
20369
|
+
for (const [event, origin] of Object.entries(eventOrigins ?? {})) if (origin.origin === "auto" && expectedEvents && JSON.stringify(expectedEvents[event]) === JSON.stringify(comparableMachineConfig({
|
|
20370
|
+
type: "object",
|
|
20371
|
+
properties: {},
|
|
20372
|
+
required: []
|
|
20373
|
+
})) && !Object.hasOwn(schemaEvents(baselineConfig) ?? {}, event) && !Object.hasOwn(schemaEvents(actualConfig) ?? {}, event)) {
|
|
20374
|
+
delete expectedEvents[event];
|
|
20375
|
+
removedAutoEvent = true;
|
|
20376
|
+
}
|
|
20377
|
+
if (removedAutoEvent && expectedEvents && Object.keys(expectedEvents).length === 0) delete expectedConfig.schemas.events;
|
|
19865
20378
|
if (expectedConfig && typeof expectedConfig === "object" && !Array.isArray(expectedConfig) && actualConfig && typeof actualConfig === "object" && !Array.isArray(actualConfig) && !("id" in expectedConfig) && "id" in actualConfig) {
|
|
19866
|
-
const baselineConfig = comparableMachineConfig(stripStatelyMetadata(projectConfig(input.documents)));
|
|
19867
20379
|
if (baselineConfig && typeof baselineConfig === "object" && "id" in baselineConfig && actualConfig.id === baselineConfig.id) delete actualConfig.id;
|
|
19868
20380
|
}
|
|
19869
20381
|
if (JSON.stringify(expectedConfig) !== JSON.stringify(actualConfig)) throw new Error("The updated source does not match the requested machine.");
|
|
@@ -19945,7 +20457,7 @@ function sourceLocationUris(sourceLocations) {
|
|
|
19945
20457
|
|
|
19946
20458
|
//#endregion
|
|
19947
20459
|
//#region src/version.ts
|
|
19948
|
-
const CLI_VERSION = "0.12.
|
|
20460
|
+
const CLI_VERSION = "0.12.4";
|
|
19949
20461
|
|
|
19950
20462
|
//#endregion
|
|
19951
20463
|
//#region src/cliHost.ts
|
|
@@ -19986,11 +20498,21 @@ function rawDataToBuffer(data) {
|
|
|
19986
20498
|
var CliEditorSession = class {
|
|
19987
20499
|
session;
|
|
19988
20500
|
workspaceWatcher;
|
|
20501
|
+
readyMessage;
|
|
20502
|
+
loginPromise;
|
|
20503
|
+
loginController;
|
|
20504
|
+
disposed = false;
|
|
19989
20505
|
constructor(options, sendMessage) {
|
|
19990
20506
|
this.options = options;
|
|
20507
|
+
this.sendMessage = sendMessage;
|
|
20508
|
+
this.workspaceWatcher = createSharedWorkspaceWatcher(options.rootDir);
|
|
20509
|
+
this.session = this.createSession();
|
|
20510
|
+
}
|
|
20511
|
+
createSession() {
|
|
20512
|
+
const options = this.options;
|
|
19991
20513
|
const send = (message) => {
|
|
19992
20514
|
this.log("send", message.type, message);
|
|
19993
|
-
sendMessage(message);
|
|
20515
|
+
this.sendMessage(message);
|
|
19994
20516
|
};
|
|
19995
20517
|
const machines = options.machines ?? [{
|
|
19996
20518
|
id: `${options.rootUri}#0`,
|
|
@@ -20004,8 +20526,7 @@ var CliEditorSession = class {
|
|
|
20004
20526
|
baseUrl: options.studioUrl,
|
|
20005
20527
|
apiKey: options.apiKey
|
|
20006
20528
|
});
|
|
20007
|
-
|
|
20008
|
-
let access;
|
|
20529
|
+
let access = options.access ? Promise.resolve(options.access) : void 0;
|
|
20009
20530
|
const getAccess = () => {
|
|
20010
20531
|
if (!access) {
|
|
20011
20532
|
const request = fetchEditorSyncAccess({
|
|
@@ -20020,7 +20541,11 @@ var CliEditorSession = class {
|
|
|
20020
20541
|
}
|
|
20021
20542
|
return access;
|
|
20022
20543
|
};
|
|
20023
|
-
|
|
20544
|
+
return new EditorHostWorkspaceSession({
|
|
20545
|
+
authenticationRecovery: {
|
|
20546
|
+
host: "cli",
|
|
20547
|
+
canLogin: Boolean(options.onLogin)
|
|
20548
|
+
},
|
|
20024
20549
|
machines: machines.map((machine) => ({
|
|
20025
20550
|
id: machine.id,
|
|
20026
20551
|
name: machine.name,
|
|
@@ -20056,14 +20581,75 @@ var CliEditorSession = class {
|
|
|
20056
20581
|
showError: (message) => console.error(`Stately Editor: ${message}`)
|
|
20057
20582
|
});
|
|
20058
20583
|
}
|
|
20059
|
-
receiveMessage(message) {
|
|
20584
|
+
async receiveMessage(message) {
|
|
20060
20585
|
this.log("recv", message.type, message);
|
|
20586
|
+
if (this.disposed) return;
|
|
20587
|
+
if (message.type === "@statelyai.login") {
|
|
20588
|
+
if (!this.readyMessage || !this.options.onLogin) return;
|
|
20589
|
+
this.loginPromise ??= this.login().finally(() => {
|
|
20590
|
+
this.loginPromise = void 0;
|
|
20591
|
+
});
|
|
20592
|
+
return this.loginPromise;
|
|
20593
|
+
}
|
|
20594
|
+
if (this.loginPromise) {
|
|
20595
|
+
if (message.type !== "@statelyai.ready") return this.loginPromise;
|
|
20596
|
+
this.loginController?.abort();
|
|
20597
|
+
await this.loginPromise;
|
|
20598
|
+
if (this.disposed) return;
|
|
20599
|
+
}
|
|
20600
|
+
if (message.type === "@statelyai.ready") {
|
|
20601
|
+
this.readyMessage = message;
|
|
20602
|
+
try {
|
|
20603
|
+
const apiKey = this.options.getApiKey ? await this.options.getApiKey() : this.options.apiKey;
|
|
20604
|
+
if (this.disposed) return;
|
|
20605
|
+
if (apiKey !== this.options.apiKey) this.replaceCredential(apiKey);
|
|
20606
|
+
} catch (error) {
|
|
20607
|
+
this.reportLoginError(error);
|
|
20608
|
+
return;
|
|
20609
|
+
}
|
|
20610
|
+
}
|
|
20061
20611
|
return this.session.receive(message);
|
|
20062
20612
|
}
|
|
20063
20613
|
dispose() {
|
|
20614
|
+
this.disposed = true;
|
|
20615
|
+
this.loginController?.abort();
|
|
20064
20616
|
this.session.dispose();
|
|
20065
20617
|
this.workspaceWatcher.dispose();
|
|
20066
20618
|
}
|
|
20619
|
+
replaceCredential(apiKey) {
|
|
20620
|
+
this.session.dispose();
|
|
20621
|
+
this.options.apiKey = apiKey;
|
|
20622
|
+
this.options.access = void 0;
|
|
20623
|
+
this.session = this.createSession();
|
|
20624
|
+
}
|
|
20625
|
+
async login() {
|
|
20626
|
+
const controller = new AbortController();
|
|
20627
|
+
this.loginController = controller;
|
|
20628
|
+
try {
|
|
20629
|
+
const apiKey = await this.options.onLogin(controller.signal);
|
|
20630
|
+
if (this.disposed || controller.signal.aborted) return;
|
|
20631
|
+
this.replaceCredential(apiKey);
|
|
20632
|
+
await this.session.receive(this.readyMessage);
|
|
20633
|
+
} catch (error) {
|
|
20634
|
+
if (!this.disposed) this.reportLoginError(error);
|
|
20635
|
+
} finally {
|
|
20636
|
+
this.loginController = void 0;
|
|
20637
|
+
}
|
|
20638
|
+
}
|
|
20639
|
+
reportLoginError(error) {
|
|
20640
|
+
const message = error instanceof Error ? error.message : "Stately login failed. Try again.";
|
|
20641
|
+
const authenticationRecovery = {
|
|
20642
|
+
host: "cli",
|
|
20643
|
+
canLogin: Boolean(this.options.onLogin)
|
|
20644
|
+
};
|
|
20645
|
+
this.sendMessage({
|
|
20646
|
+
type: "@statelyai.error",
|
|
20647
|
+
code: "initialization_failed",
|
|
20648
|
+
message,
|
|
20649
|
+
authenticationRecovery
|
|
20650
|
+
});
|
|
20651
|
+
console.error(`Stately Editor: ${message}\n${authenticationRecoveryInstructions(authenticationRecovery)}`);
|
|
20652
|
+
}
|
|
20067
20653
|
log(direction, type, payload) {
|
|
20068
20654
|
if (this.options.debug) console.error(`[${direction}] ${type}`, redactDebugPayload(payload) ?? "");
|
|
20069
20655
|
}
|
|
@@ -20165,6 +20751,31 @@ function redactDebugPayload(payload) {
|
|
|
20165
20751
|
if (!payload || typeof payload !== "object") return payload;
|
|
20166
20752
|
return Object.fromEntries(Object.entries(payload).map(([key, value]) => [key, /^(?:apiKey|accessToken|refreshToken|token|authorization)$/i.test(key) ? "[REDACTED]" : redactDebugPayload(value)]));
|
|
20167
20753
|
}
|
|
20754
|
+
async function prepareEditorAuthentication(options) {
|
|
20755
|
+
const getAccess = (apiKey) => fetchEditorSyncAccess({
|
|
20756
|
+
editorUrl: options.editorUrl,
|
|
20757
|
+
apiKey,
|
|
20758
|
+
fetch: (input, init) => fetchEditorHost(input instanceof URL ? input : new URL(String(input)), init)
|
|
20759
|
+
});
|
|
20760
|
+
try {
|
|
20761
|
+
return {
|
|
20762
|
+
apiKey: options.apiKey,
|
|
20763
|
+
access: await getAccess(options.apiKey)
|
|
20764
|
+
};
|
|
20765
|
+
} catch (error) {
|
|
20766
|
+
if (!isEditorSyncAuthenticationError(error)) return { apiKey: options.apiKey };
|
|
20767
|
+
console.log("Log in to Stately to open this machine. Complete sign-in in your browser; the editor will open automatically.");
|
|
20768
|
+
const apiKey = await options.onLogin(new AbortController().signal);
|
|
20769
|
+
try {
|
|
20770
|
+
return {
|
|
20771
|
+
apiKey,
|
|
20772
|
+
access: await getAccess(apiKey)
|
|
20773
|
+
};
|
|
20774
|
+
} catch {
|
|
20775
|
+
return { apiKey };
|
|
20776
|
+
}
|
|
20777
|
+
}
|
|
20778
|
+
}
|
|
20168
20779
|
async function openEditor(options) {
|
|
20169
20780
|
const fileName = path$1.resolve(options.fileName);
|
|
20170
20781
|
const machines = (options.machines ?? [{
|
|
@@ -20177,6 +20788,11 @@ async function openEditor(options) {
|
|
|
20177
20788
|
}));
|
|
20178
20789
|
await Promise.all([...new Set(machines.map((machine) => machine.fileName))].map((target) => fsPromises.access(target)));
|
|
20179
20790
|
await assertEditorHostAvailable(options.editorUrl);
|
|
20791
|
+
if (options.shouldOpen && options.onLogin && process.stdin.isTTY && process.stdout.isTTY) Object.assign(options, await prepareEditorAuthentication({
|
|
20792
|
+
editorUrl: options.editorUrl,
|
|
20793
|
+
apiKey: options.apiKey,
|
|
20794
|
+
onLogin: options.onLogin
|
|
20795
|
+
}));
|
|
20180
20796
|
const rootUri = fileNameToUri(fileName);
|
|
20181
20797
|
const rootDir = path$1.resolve(options.rootDir ?? path$1.dirname(fileName));
|
|
20182
20798
|
let activeClient;
|
|
@@ -20196,6 +20812,10 @@ async function openEditor(options) {
|
|
|
20196
20812
|
socket.end("HTTP/1.1 404 Not Found\r\n\r\n");
|
|
20197
20813
|
return;
|
|
20198
20814
|
}
|
|
20815
|
+
if (request.headers.origin !== editorPageUrl || request.headers.host !== new URL(editorPageUrl).host) {
|
|
20816
|
+
socket.end("HTTP/1.1 403 Forbidden\r\n\r\n");
|
|
20817
|
+
return;
|
|
20818
|
+
}
|
|
20199
20819
|
webSocketServer.handleUpgrade(request, socket, head, (webSocket) => {
|
|
20200
20820
|
activeClient?.close();
|
|
20201
20821
|
session?.dispose();
|
|
@@ -20218,7 +20838,11 @@ async function openEditor(options) {
|
|
|
20218
20838
|
const editorPageUrl = `http://${options.host}:${port}`;
|
|
20219
20839
|
console.log(`Stately visual editor: ${editorPageUrl}`);
|
|
20220
20840
|
console.log(`Editing ${machines.length} machine${machines.length === 1 ? "" : "s"} in ${rootDir}`);
|
|
20221
|
-
if (options.shouldOpen)
|
|
20841
|
+
if (options.shouldOpen) try {
|
|
20842
|
+
await openBrowser(editorPageUrl);
|
|
20843
|
+
} catch {
|
|
20844
|
+
console.warn("Could not open a browser automatically. Open the editor URL above.");
|
|
20845
|
+
}
|
|
20222
20846
|
const shutdown = () => {
|
|
20223
20847
|
session?.dispose();
|
|
20224
20848
|
activeClient?.close();
|
|
@@ -20399,6 +21023,7 @@ function getCliWebviewContent(options) {
|
|
|
20399
21023
|
></iframe>
|
|
20400
21024
|
<script>
|
|
20401
21025
|
const iframe = document.getElementById('stately-editor');
|
|
21026
|
+
const editorOrigin = new URL(iframe.src).origin;
|
|
20402
21027
|
const socket = new WebSocket(
|
|
20403
21028
|
(location.protocol === 'https:' ? 'wss:' : 'ws:') + '//' + location.host + '/ws'
|
|
20404
21029
|
);
|
|
@@ -20419,10 +21044,13 @@ function getCliWebviewContent(options) {
|
|
|
20419
21044
|
});
|
|
20420
21045
|
|
|
20421
21046
|
socket.addEventListener('message', (event) => {
|
|
20422
|
-
iframe.contentWindow?.postMessage(JSON.parse(event.data),
|
|
21047
|
+
iframe.contentWindow?.postMessage(JSON.parse(event.data), editorOrigin);
|
|
20423
21048
|
});
|
|
20424
21049
|
|
|
20425
21050
|
window.addEventListener('message', (event) => {
|
|
21051
|
+
if (event.source !== iframe.contentWindow || event.origin !== editorOrigin) {
|
|
21052
|
+
return;
|
|
21053
|
+
}
|
|
20426
21054
|
if (!event.data?.type?.startsWith?.('@statelyai.')) {
|
|
20427
21055
|
return;
|
|
20428
21056
|
}
|
|
@@ -20455,8 +21083,8 @@ async function assertEditorHostAvailable(editorUrl) {
|
|
|
20455
21083
|
function formatEditorHostError(baseUrl, status, cause) {
|
|
20456
21084
|
return `Cannot reach a usable editor host at ${baseUrl}.${status ? ` HTTP ${status} from /embed.` : ""}${cause instanceof Error && cause.message ? ` ${cause.message}` : ""} The CLI loads editor URL defaults from your environment, including \`.env.local\`. Start the editor host, set \`STATELY_EDITOR_URL\`, or pass \`--editor-url <url>\`.`;
|
|
20457
21085
|
}
|
|
20458
|
-
function openBrowser(url) {
|
|
20459
|
-
spawn(process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open", process.platform === "win32" ? [
|
|
21086
|
+
async function openBrowser(url) {
|
|
21087
|
+
const child = spawn(process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open", process.platform === "win32" ? [
|
|
20460
21088
|
"/c",
|
|
20461
21089
|
"start",
|
|
20462
21090
|
"",
|
|
@@ -20464,7 +21092,12 @@ function openBrowser(url) {
|
|
|
20464
21092
|
] : [url], {
|
|
20465
21093
|
detached: true,
|
|
20466
21094
|
stdio: "ignore"
|
|
20467
|
-
})
|
|
21095
|
+
});
|
|
21096
|
+
child.unref();
|
|
21097
|
+
await new Promise((resolve, reject) => {
|
|
21098
|
+
child.once("spawn", resolve);
|
|
21099
|
+
child.once("error", reject);
|
|
21100
|
+
});
|
|
20468
21101
|
}
|
|
20469
21102
|
function fileNameToUri(fileName) {
|
|
20470
21103
|
return pathToFileURL(path$1.resolve(fileName)).toString();
|
|
@@ -20490,6 +21123,8 @@ async function createLocalOAuthCallbackServer(options) {
|
|
|
20490
21123
|
resolveCode = resolve;
|
|
20491
21124
|
rejectCode = reject;
|
|
20492
21125
|
});
|
|
21126
|
+
codePromise.catch(() => {});
|
|
21127
|
+
const cancel = () => rejectCode(/* @__PURE__ */ new Error("Stately sign-in was canceled."));
|
|
20493
21128
|
const server = http.createServer((req, res) => {
|
|
20494
21129
|
const requestUrl = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
20495
21130
|
const code = requestUrl.searchParams.get("code");
|
|
@@ -20517,12 +21152,17 @@ async function createLocalOAuthCallbackServer(options) {
|
|
|
20517
21152
|
});
|
|
20518
21153
|
const address = server.address();
|
|
20519
21154
|
if (!address || typeof address === "string") throw new Error("Could not start OAuth callback server.");
|
|
21155
|
+
options.signal?.addEventListener("abort", cancel, { once: true });
|
|
21156
|
+
if (options.signal?.aborted) cancel();
|
|
20520
21157
|
return {
|
|
20521
21158
|
redirectUri: `http://127.0.0.1:${address.port}/callback`,
|
|
20522
21159
|
waitForCode: () => codePromise,
|
|
20523
|
-
close: () =>
|
|
20524
|
-
|
|
20525
|
-
|
|
21160
|
+
close: () => {
|
|
21161
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
21162
|
+
return new Promise((resolve) => {
|
|
21163
|
+
server.close(() => resolve());
|
|
21164
|
+
});
|
|
21165
|
+
}
|
|
20526
21166
|
};
|
|
20527
21167
|
}
|
|
20528
21168
|
|
|
@@ -20918,7 +21558,7 @@ function getScriptKind$1(fileName) {
|
|
|
20918
21558
|
}
|
|
20919
21559
|
|
|
20920
21560
|
//#endregion
|
|
20921
|
-
//#region ../../node_modules/.pnpm/@statelyai+graph@2.1.0_@statelyai+layout@0.
|
|
21561
|
+
//#region ../../node_modules/.pnpm/@statelyai+graph@2.1.0_@statelyai+layout@0.3.0_cytoscape@3.34.0_d3-force@3.0.0_d3-hiera_7624816e5d9226bed30c68417318a8b7/node_modules/@statelyai/graph/dist/index.mjs
|
|
20922
21562
|
const LAYOUT_KEYS = {
|
|
20923
21563
|
node: [
|
|
20924
21564
|
"x",
|
|
@@ -21781,9 +22421,10 @@ function getOAuthExpiresAt(credential) {
|
|
|
21781
22421
|
function isTerminalOAuthRefreshError(error) {
|
|
21782
22422
|
return error instanceof Error && /Token refresh failed with HTTP (?:400|401|403)\b/.test(error.message);
|
|
21783
22423
|
}
|
|
22424
|
+
var ExpiredStatelyCredentialError = class extends Error {};
|
|
21784
22425
|
async function invalidateExpiredOAuthCredential() {
|
|
21785
22426
|
await deleteStoredApiKey();
|
|
21786
|
-
throw new
|
|
22427
|
+
throw new ExpiredStatelyCredentialError("Your Stately session expired. Run `npx statelyai login` to continue.");
|
|
21787
22428
|
}
|
|
21788
22429
|
async function refreshStoredOAuthCredential(credential, options) {
|
|
21789
22430
|
if (!credential.refreshToken) return invalidateExpiredOAuthCredential();
|
|
@@ -21817,7 +22458,7 @@ async function refreshStoredOAuthCredential(credential, options) {
|
|
|
21817
22458
|
}
|
|
21818
22459
|
}
|
|
21819
22460
|
async function resolveApiKey(options = {}) {
|
|
21820
|
-
const envApiKey = getEnvApiKey();
|
|
22461
|
+
const envApiKey = options.ignoreEnvironment ? void 0 : getEnvApiKey();
|
|
21821
22462
|
if (envApiKey) return {
|
|
21822
22463
|
apiKey: envApiKey.apiKey,
|
|
21823
22464
|
source: "env",
|
|
@@ -22043,22 +22684,32 @@ function formatStoredCredentialSource(storedCredential) {
|
|
|
22043
22684
|
return `Credential source: stored unknown (${describeCredentialBackend(storedCredential.backend, storedCredential.location)}).`;
|
|
22044
22685
|
}
|
|
22045
22686
|
async function runOAuthBrowserLogin(options) {
|
|
22687
|
+
options.signal?.throwIfAborted();
|
|
22046
22688
|
const state = crypto.randomBytes(16).toString("base64url");
|
|
22047
|
-
const callbackServer = await createLocalOAuthCallbackServer({
|
|
22689
|
+
const callbackServer = await createLocalOAuthCallbackServer({
|
|
22690
|
+
state,
|
|
22691
|
+
signal: options.signal
|
|
22692
|
+
});
|
|
22693
|
+
const loginFetch = (input, init) => fetch(input, {
|
|
22694
|
+
...init,
|
|
22695
|
+
signal: options.signal
|
|
22696
|
+
});
|
|
22048
22697
|
try {
|
|
22049
22698
|
const { authorizeUrl, codeVerifier, discovery } = await buildOAuthLoginStart({
|
|
22699
|
+
fetch: loginFetch,
|
|
22050
22700
|
baseUrl: options.baseUrl,
|
|
22051
22701
|
redirectUri: callbackServer.redirectUri,
|
|
22052
22702
|
state
|
|
22053
22703
|
});
|
|
22704
|
+
options.signal?.throwIfAborted();
|
|
22054
22705
|
options.log(`Opening browser for ${discovery.resourceUrl}`);
|
|
22055
|
-
options.log(authorizeUrl);
|
|
22056
22706
|
let openedBrowser = false;
|
|
22057
22707
|
try {
|
|
22058
|
-
openBrowser(authorizeUrl);
|
|
22708
|
+
await openBrowser(authorizeUrl);
|
|
22059
22709
|
openedBrowser = true;
|
|
22060
22710
|
} catch {
|
|
22061
22711
|
options.log("Could not open a browser automatically.");
|
|
22712
|
+
options.log(authorizeUrl);
|
|
22062
22713
|
}
|
|
22063
22714
|
const codePromise = callbackServer.waitForCode();
|
|
22064
22715
|
const pastedCodePromise = !openedBrowser && process.stdin.isTTY && process.stdout.isTTY ? promptForOAuthCallback().then((value) => {
|
|
@@ -22067,13 +22718,16 @@ async function runOAuthBrowserLogin(options) {
|
|
|
22067
22718
|
return callback.code;
|
|
22068
22719
|
}) : void 0;
|
|
22069
22720
|
const code = await (pastedCodePromise ? Promise.race([codePromise, pastedCodePromise]) : codePromise);
|
|
22070
|
-
|
|
22721
|
+
const tokenResponse = await exchangeCodeForToken({
|
|
22722
|
+
fetch: loginFetch,
|
|
22071
22723
|
tokenEndpoint: discovery.tokenEndpoint,
|
|
22072
22724
|
code,
|
|
22073
22725
|
codeVerifier,
|
|
22074
22726
|
redirectUri: callbackServer.redirectUri,
|
|
22075
22727
|
clientId: discovery.clientId
|
|
22076
|
-
})
|
|
22728
|
+
});
|
|
22729
|
+
options.signal?.throwIfAborted();
|
|
22730
|
+
return setStoredCredential(createOAuthCredential(tokenResponse, {
|
|
22077
22731
|
clientId: discovery.clientId,
|
|
22078
22732
|
tokenEndpoint: discovery.tokenEndpoint
|
|
22079
22733
|
}));
|
|
@@ -22986,7 +23640,16 @@ var OpenCommand = class OpenCommand extends Command {
|
|
|
22986
23640
|
};
|
|
22987
23641
|
async run() {
|
|
22988
23642
|
const { args, flags } = await this.parse(OpenCommand);
|
|
22989
|
-
|
|
23643
|
+
let hasLoggedIn = false;
|
|
23644
|
+
const getApiKey = async () => {
|
|
23645
|
+
try {
|
|
23646
|
+
return (await resolveApiKey({ ignoreEnvironment: hasLoggedIn })).apiKey;
|
|
23647
|
+
} catch (error) {
|
|
23648
|
+
if (error instanceof ExpiredStatelyCredentialError) return void 0;
|
|
23649
|
+
throw error;
|
|
23650
|
+
}
|
|
23651
|
+
};
|
|
23652
|
+
const apiKey = await getApiKey();
|
|
22990
23653
|
const cwd = process.cwd();
|
|
22991
23654
|
const discovered = args.file ? await discoverMachinesInFile(path.resolve(args.file)) : await scanProjectMachines({ cwd });
|
|
22992
23655
|
if (discovered.length === 0) throw new Error(args.file ? `No machines found in ${path.resolve(args.file)}.` : `No machines found in ${cwd}.`);
|
|
@@ -23019,7 +23682,19 @@ var OpenCommand = class OpenCommand extends Command {
|
|
|
23019
23682
|
sourceUpdateStrategy: flags["source-update"] ?? configuredSourceUpdateStrategy ?? "preserve",
|
|
23020
23683
|
apiKey,
|
|
23021
23684
|
studioUrl: resolveApiBaseUrl(configuredStudioUrl),
|
|
23022
|
-
debug: flags.debug
|
|
23685
|
+
debug: flags.debug,
|
|
23686
|
+
getApiKey,
|
|
23687
|
+
onLogin: async (signal) => {
|
|
23688
|
+
const stored = await runOAuthBrowserLogin({
|
|
23689
|
+
baseUrl: flags["editor-url"] ?? getDefaultEditorUrl(),
|
|
23690
|
+
log: (message) => this.log(message),
|
|
23691
|
+
signal
|
|
23692
|
+
});
|
|
23693
|
+
if (stored.credential?.type !== "oauth") throw new Error("Stately login did not return an OAuth credential.");
|
|
23694
|
+
hasLoggedIn = true;
|
|
23695
|
+
this.log("Logged in to Stately. Loading your machine…");
|
|
23696
|
+
return stored.credential.accessToken;
|
|
23697
|
+
}
|
|
23023
23698
|
});
|
|
23024
23699
|
}
|
|
23025
23700
|
};
|