refactor: consolidate authoring binding copies

This commit is contained in:
lda
2026-08-29 21:23:50 +07:00 Verified
parent 0570ef8a78
commit f64e843c3d
4 changed files with 31 additions and 34 deletions
@@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useConsoleWorkspace } from "../context.js";
import {
createDraftAuthoringClient,
copyInputBinding,
copyStepInputBinding,
type DraftAuthoringClient,
} from "../domain/draft-authoring-client.js";
@@ -193,26 +194,7 @@ const copyOutputBindings = (
const copyWorkflowOutputBindings = (
bindings: ReadonlyArray<InputBinding>,
): ReadonlyArray<InputBinding> => bindings.map((binding) => (
"path" in binding
? {
path:
typeof binding.path === "string"
? binding.path
: { root: binding.path.root, parts: [...binding.path.parts] },
target:
typeof binding.target === "string"
? binding.target
: { root: binding.target.root, parts: [...binding.target.parts] },
}
: {
value: copyJson(binding.value),
target:
typeof binding.target === "string"
? binding.target
: { root: binding.target.root, parts: [...binding.target.parts] },
}
));
): ReadonlyArray<InputBinding> => bindings.map(copyInputBinding);
const copyContractPatch = (patch: WorkflowContractPatch): WorkflowContractPatch => ({
...(patch.inputSchema !== undefined
@@ -18,7 +18,7 @@ import {
type SetWorkflowStartInput,
type UpdateCapabilityStepInput,
} from "./draft-workspace-models.js";
import { createDraftAuthoringClient } from "./draft-authoring-client.js";
import { copyInputBinding, createDraftAuthoringClient } from "./draft-authoring-client.js";
import type { ConsoleWriteExecutor } from "./write-executor.js";
const canonicalWorkspace = {
@@ -65,6 +65,19 @@ const createExecutor = () => {
};
describe("DraftAuthoringClient", () => {
it("copies workflow-compatible input bindings without sharing nested paths", () => {
const binding = {
path: { root: "state" as const, parts: ["report"] },
target: { root: "local" as const, parts: ["text"] },
} satisfies InputBinding;
const copied = copyInputBinding(binding);
expect(copied).not.toBe(binding);
if (!("path" in copied)) throw new Error("expected a path binding");
expect(copied.path).not.toBe(binding.path);
expect(copied.target).not.toBe(binding.target);
});
it("lowers all six authoring operations and decodes canonical workspaces", async () => {
const { executor: writeExecutor, run } = createExecutor();
const client = createDraftAuthoringClient(writeExecutor);
@@ -5,6 +5,7 @@ import {
type CreateEmptyDraftInput,
type CreateFromCapabilityInput,
type DraftWorkspace,
type InputBinding,
type JsonValue,
type InputExpression,
type InputPath,
@@ -112,27 +113,31 @@ export const copyInputExpression = (
}
};
export const copyStepInputBinding = (
binding: StepInputBinding,
): StepInputBinding => {
export const copyInputBinding = (binding: InputBinding): InputBinding => {
if ("path" in binding) {
return {
path: copyInputPath(binding.path),
target: copyLocalInputPath(binding.target),
};
}
if ("value" in binding) {
return {
target: copyLocalInputPath(binding.target),
value: copyJsonValue(binding.value),
};
}
return {
target: copyLocalInputPath(binding.target),
expression: copyInputExpression(binding.expression),
value: copyJsonValue(binding.value),
};
};
export const copyStepInputBinding = (
binding: StepInputBinding,
): StepInputBinding => {
if ("expression" in binding) {
return {
target: copyLocalInputPath(binding.target),
expression: copyInputExpression(binding.expression),
};
}
return copyInputBinding(binding);
};
const copyOutputBinding = (binding: OutputBinding): OutputBinding => ({
source:
typeof binding.source === "string"