@workbench-kit/shell-react 0.0.2-prototype.0.2.26 → 0.0.2-prototype.0.2.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +18 -2
  2. package/package.json +10 -10
  3. package/src/chat/command-policy.ts +3 -17
  4. package/src/commands/use-command-descriptors.ts +2 -30
  5. package/src/commands/use-context-key-revision.ts +12 -12
  6. package/src/commands/use-extension-registry-command-descriptors.ts +46 -0
  7. package/src/devtools/use-workbench-devtools-snapshot.ts +1 -1
  8. package/src/editor/pane-visibility.ts +0 -23
  9. package/src/editor/view-providers.tsx +0 -7
  10. package/src/explorer/reveal.ts +1 -12
  11. package/src/extensions/builtin/commands/src/command-inspector-editor-host.ts +1 -19
  12. package/src/extensions/builtin/commands/src/index.ts +2 -2
  13. package/src/field-remap/convert-note-editor.tsx +2 -4
  14. package/src/field-remap/convert-palette.tsx +17 -20
  15. package/src/field-remap/flow-adapter.ts +21 -57
  16. package/src/field-remap/flow-ops.ts +0 -24
  17. package/src/field-remap/index.ts +0 -1
  18. package/src/field-remap/io-class-browse.tsx +29 -6
  19. package/src/field-remap/jsonata-transform.ts +9 -39
  20. package/src/field-remap/shape-io-editor.tsx +1 -1
  21. package/src/field-remap/transform-options-editor.tsx +1 -2
  22. package/src/field-remap/view.css +4 -29
  23. package/src/index.ts +1 -10
  24. package/src/jdw/widget-form-view.tsx +3 -20
  25. package/src/jdw/widget-preview-view.tsx +2 -20
  26. package/src/management/use-command-management.ts +22 -7
  27. package/src/management/use-keybinding-management.ts +1 -10
  28. package/src/shell/provider.tsx +19 -9
  29. package/src/shell/shell.tsx +11 -4
  30. package/src/workbench/command-host.tsx +46 -7
  31. package/src/workbench/command-palette.ts +12 -45
  32. package/src/workbench/workspace-view-state.ts +18 -1
  33. package/src/field-remap/graph.tsx +0 -559
  34. package/src/field-remap/table-mapping-adapter.ts +0 -59
  35. package/src/field-remap/tree.tsx +0 -404
package/README.md CHANGED
@@ -17,6 +17,7 @@ Peer: React 19.
17
17
  ## Quick start
18
18
 
19
19
  ```tsx
20
+ import { AppIcon } from '@workbench-kit/react/primitives';
20
21
  import { BUILTIN_WORKBENCH_EXTENSIONS } from '@workbench-kit/shell-react';
21
22
  import { EditorArea } from '@workbench-kit/shell-react';
22
23
  import { WorkbenchProvider } from '@workbench-kit/shell-react/provider';
@@ -25,7 +26,12 @@ import { WorkbenchShell } from '@workbench-kit/shell-react/shell';
25
26
  export function App() {
26
27
  return (
27
28
  <WorkbenchProvider availableExtensions={BUILTIN_WORKBENCH_EXTENSIONS}>
28
- <WorkbenchShell title="Workbench" primarySidebar={<aside />} editorArea={<EditorArea />} />
29
+ <WorkbenchShell
30
+ appIcon={<AppIcon alt="" src="/app-icon.svg" />}
31
+ title="Workbench"
32
+ primarySidebar={<aside />}
33
+ editorArea={<EditorArea />}
34
+ />
29
35
  </WorkbenchProvider>
30
36
  );
31
37
  }
@@ -40,7 +46,9 @@ host wants the Kit editor, or omit it for a product-owned editor region.
40
46
 
41
47
  Performance-sensitive hosts should import orchestration from the focused
42
48
  `provider`, `host-shell`, `shell`, `command-host`, `command-palette`, and
43
- `command-descriptors` subpaths. The root barrel remains the discovery surface,
49
+ `command-descriptors` subpaths. Hosts that already own the canonical extension
50
+ registry can use `registry-command-descriptors` without importing Provider
51
+ context into that leaf bundle. The root barrel remains the discovery surface,
44
52
  not the default runtime import graph.
45
53
 
46
54
  Use `host-shell` when the product owns sidebar, editor, panel, and overlay content.
@@ -53,6 +61,14 @@ layout-only chrome without host services, start from
53
61
  `@workbench-kit/react/workbench/shell` — see
54
62
  [Getting Started](../../docs/guides/getting-started.md).
55
63
 
64
+ ## Host-owned branding
65
+
66
+ The default title bar does not embed a product mark. Pass the host-owned mark through
67
+ `appIcon`, omit it for a text-only identity, or replace the complete `titleBar` surface.
68
+ The shell wraps `appIcon` as decorative content, so interactive controls do not belong
69
+ in this slot. `AppIcon` from `@workbench-kit/react/primitives` is the optional sizing
70
+ and image-fit helper; it does not include fallback artwork.
71
+
56
72
  ## Field Remap embed (slim subpath)
57
73
 
58
74
  Hosts that only need the Field Remap mapper UI can import the slim subpath instead
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workbench-kit/shell-react",
3
- "version": "0.0.2-prototype.0.2.26",
3
+ "version": "0.0.2-prototype.0.2.28",
4
4
  "private": false,
5
5
  "sideEffects": [
6
6
  "**/*.css"
@@ -9,6 +9,7 @@
9
9
  "exports": {
10
10
  ".": "./src/index.ts",
11
11
  "./command-descriptors": "./src/commands/use-command-descriptors.ts",
12
+ "./registry-command-descriptors": "./src/commands/use-extension-registry-command-descriptors.ts",
12
13
  "./command-host": "./src/workbench/command-host.tsx",
13
14
  "./command-palette": "./src/workbench/command-palette.ts",
14
15
  "./field-remap": "./src/field-remap/index.ts",
@@ -30,15 +31,14 @@
30
31
  "@radix-ui/react-slot": "^1.3.0",
31
32
  "@xyflow/react": "^12.11.2",
32
33
  "jsonata": "^2.2.0",
33
- "react-table-mapping": "^1.0.3",
34
- "@workbench-kit/field-remap": "0.0.2-prototype.0.2.26",
35
- "@workbench-kit/tokens": "0.0.2-prototype.0.2.26",
36
- "@workbench-kit/workbench-config": "0.0.2-prototype.0.2.26",
37
- "@workbench-kit/workbench-extension-sdk": "0.0.2-prototype.0.2.26",
38
- "@workbench-kit/workbench-core": "0.0.2-prototype.0.2.26",
39
- "@workbench-kit/workspace": "0.0.2-prototype.0.2.26",
40
- "@workbench-kit/platform": "0.0.2-prototype.0.2.26",
41
- "@workbench-kit/react": "0.0.2-prototype.0.2.26"
34
+ "@workbench-kit/react": "0.0.2-prototype.0.2.28",
35
+ "@workbench-kit/tokens": "0.0.2-prototype.0.2.28",
36
+ "@workbench-kit/field-remap": "0.0.2-prototype.0.2.28",
37
+ "@workbench-kit/workbench-config": "0.0.2-prototype.0.2.28",
38
+ "@workbench-kit/workbench-extension-sdk": "0.0.2-prototype.0.2.28",
39
+ "@workbench-kit/platform": "0.0.2-prototype.0.2.28",
40
+ "@workbench-kit/workspace": "0.0.2-prototype.0.2.28",
41
+ "@workbench-kit/workbench-core": "0.0.2-prototype.0.2.28"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "react": "^19.0.0",
@@ -1,6 +1,6 @@
1
- import type {
2
- ResolveWorkbenchCommandExecutionPolicyInput,
3
- WorkbenchCommandExecutionPolicy,
1
+ import {
2
+ isWorkbenchCommandExecutionPolicy,
3
+ type ResolveWorkbenchCommandExecutionPolicyInput,
4
4
  } from '@workbench-kit/react/workbench';
5
5
  import type { WorkbenchStorageReader } from '@workbench-kit/workbench-core';
6
6
 
@@ -8,12 +8,6 @@ import { readPersistedLocalPreferences } from '../management/preference-settings
8
8
 
9
9
  export const WORKBENCH_AI_CHAT_COMMAND_DEFAULT_POLICY_KEY = 'workbench.chat.aiCommandDefaultPolicy';
10
10
 
11
- function isWorkbenchCommandExecutionPolicy(
12
- value: unknown,
13
- ): value is WorkbenchCommandExecutionPolicy {
14
- return value === 'auto-allow' || value === 'approval-required' || value === 'auto-deny';
15
- }
16
-
17
11
  export function readWorkbenchAiChatCommandPolicyInput(
18
12
  storageKey?: string,
19
13
  storage?: WorkbenchStorageReader,
@@ -29,14 +23,6 @@ export function readWorkbenchAiChatCommandPolicyInput(
29
23
  };
30
24
  }
31
25
 
32
- export function createWorkbenchAiChatCommandPolicyById(
33
- entries: Readonly<Record<string, WorkbenchCommandExecutionPolicy>>,
34
- ): ResolveWorkbenchCommandExecutionPolicyInput {
35
- return {
36
- policyByCommandId: entries,
37
- };
38
- }
39
-
40
26
  export function mergeWorkbenchAiChatCommandPolicyInput(
41
27
  ...inputs: readonly ResolveWorkbenchCommandExecutionPolicyInput[]
42
28
  ): ResolveWorkbenchCommandExecutionPolicyInput {
@@ -1,12 +1,7 @@
1
- import { useEffect, useMemo, useReducer } from 'react';
2
1
  import type { WorkbenchCommandDescriptor } from '@workbench-kit/react/workbench';
3
2
 
4
3
  import { useWorkbench } from '../shell/provider.js';
5
- import {
6
- collectExtensionCommandFeaturesById,
7
- extensionCommandToDescriptor,
8
- mergeWorkbenchCommandDescriptors,
9
- } from '../workbench/command-palette.js';
4
+ import { useExtensionRegistryCommandDescriptors } from './use-extension-registry-command-descriptors.js';
10
5
 
11
6
  const EMPTY_COMMAND_DESCRIPTORS: readonly WorkbenchCommandDescriptor[] = [];
12
7
 
@@ -14,28 +9,5 @@ export function useWorkbenchCommandDescriptors(
14
9
  additionalCommands: readonly WorkbenchCommandDescriptor[] = EMPTY_COMMAND_DESCRIPTORS,
15
10
  ) {
16
11
  const { extensionRegistry } = useWorkbench();
17
- const [refreshToken, refreshCommands] = useReducer((count: number) => count + 1, 0);
18
-
19
- useEffect(() => {
20
- const disposable = extensionRegistry.commands.onDidRegisterCommand(() => {
21
- refreshCommands();
22
- });
23
-
24
- return () => {
25
- disposable.dispose();
26
- };
27
- }, [extensionRegistry.commands]);
28
-
29
- return useMemo(() => {
30
- const commandFeaturesById = collectExtensionCommandFeaturesById(extensionRegistry);
31
-
32
- return mergeWorkbenchCommandDescriptors(
33
- extensionRegistry.commands
34
- .getCommands()
35
- .map((command) =>
36
- extensionCommandToDescriptor(command, commandFeaturesById.get(command.id)),
37
- ),
38
- [...additionalCommands],
39
- );
40
- }, [additionalCommands, extensionRegistry, refreshToken]);
12
+ return useExtensionRegistryCommandDescriptors(extensionRegistry, additionalCommands);
41
13
  }
@@ -1,18 +1,18 @@
1
- import { useEffect, useState } from 'react';
1
+ import { useCallback, useSyncExternalStore } from 'react';
2
2
  import type { ContextKeyService } from '@workbench-kit/platform';
3
3
 
4
4
  export function useContextKeyRevision(contextKeyService: ContextKeyService): number {
5
- const [revision, setRevision] = useState(0);
5
+ const subscribe = useCallback(
6
+ (onStoreChange: () => void) => {
7
+ const disposable = contextKeyService.onDidChangeContext(onStoreChange);
6
8
 
7
- useEffect(() => {
8
- const disposable = contextKeyService.onDidChangeContext(() => {
9
- setRevision((current) => current + 1);
10
- });
9
+ return () => {
10
+ disposable.dispose();
11
+ };
12
+ },
13
+ [contextKeyService],
14
+ );
15
+ const getSnapshot = useCallback(() => contextKeyService.getRevision(), [contextKeyService]);
11
16
 
12
- return () => {
13
- disposable.dispose();
14
- };
15
- }, [contextKeyService]);
16
-
17
- return revision;
17
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
18
18
  }
@@ -0,0 +1,46 @@
1
+ import type { WorkbenchCommandDescriptor } from '@workbench-kit/react/workbench';
2
+ import type { ExtensionRegistry } from '@workbench-kit/workbench-core';
3
+ import { useEffect, useMemo, useReducer } from 'react';
4
+
5
+ import {
6
+ collectExtensionCommandFeaturesById,
7
+ extensionCommandToDescriptor,
8
+ mergeWorkbenchCommandDescriptors,
9
+ } from '../workbench/command-palette.js';
10
+
11
+ const EMPTY_COMMAND_DESCRIPTORS: readonly WorkbenchCommandDescriptor[] = [];
12
+
13
+ /**
14
+ * Resolves command descriptors from a host-owned registry without importing
15
+ * WorkbenchProvider. Use this leaf hook when the host already owns the
16
+ * canonical registry instance or when bundler context isolation matters.
17
+ */
18
+ export function useExtensionRegistryCommandDescriptors(
19
+ extensionRegistry: ExtensionRegistry,
20
+ additionalCommands: readonly WorkbenchCommandDescriptor[] = EMPTY_COMMAND_DESCRIPTORS,
21
+ ): readonly WorkbenchCommandDescriptor[] {
22
+ const [refreshToken, refreshCommands] = useReducer((count: number) => count + 1, 0);
23
+
24
+ useEffect(() => {
25
+ const disposable = extensionRegistry.commands.onDidChangeCommands(() => {
26
+ refreshCommands();
27
+ });
28
+
29
+ return () => {
30
+ disposable.dispose();
31
+ };
32
+ }, [extensionRegistry.commands]);
33
+
34
+ return useMemo(() => {
35
+ const commandFeaturesById = collectExtensionCommandFeaturesById(extensionRegistry);
36
+
37
+ return mergeWorkbenchCommandDescriptors(
38
+ extensionRegistry.commands
39
+ .getCommands()
40
+ .map((command) =>
41
+ extensionCommandToDescriptor(command, commandFeaturesById.get(command.id)),
42
+ ),
43
+ [...additionalCommands],
44
+ );
45
+ }, [additionalCommands, extensionRegistry, refreshToken]);
46
+ }
@@ -35,7 +35,7 @@ export function useWorkbenchDevtoolsSnapshot(): WorkbenchDevtoolsSnapshot {
35
35
  editorService.onDidChangeEditors(() => {
36
36
  notifyChange(onStoreChange);
37
37
  }),
38
- extensionRegistry.commands.onDidRegisterCommand(() => {
38
+ extensionRegistry.commands.onDidChangeCommands(() => {
39
39
  notifyChange(onStoreChange);
40
40
  }),
41
41
  extensionRegistry.menus.onDidRegisterMenuItem(() => {
@@ -71,29 +71,6 @@ export function countVisibleEditorPanes(visibility: EditorPaneVisibility): numbe
71
71
  return Number(visibility.code) + Number(visibility.form) + Number(visibility.preview);
72
72
  }
73
73
 
74
- export function toggleEditorPaneVisibility(
75
- visibility: EditorPaneVisibility,
76
- pane: EditorPaneKind,
77
- ): EditorPaneVisibility {
78
- const nextValue = !visibility[pane];
79
-
80
- if (!nextValue && countVisibleEditorPanes(visibility) <= 1) {
81
- return visibility;
82
- }
83
-
84
- return {
85
- ...visibility,
86
- [pane]: nextValue,
87
- };
88
- }
89
-
90
- export function sanitizeEditorPaneVisibility(
91
- visibility: EditorPaneVisibility,
92
- options: { formEligible: boolean; previewEligible: boolean },
93
- ): EditorPaneVisibility {
94
- return resolveEffectiveEditorPaneVisibility(visibility, options);
95
- }
96
-
97
74
  export function resolveEffectiveEditorPaneVisibility(
98
75
  preference: EditorPaneVisibility,
99
76
  options: { formEligible: boolean; previewEligible: boolean },
@@ -38,13 +38,6 @@ export interface ResolvedEditorDocumentViews {
38
38
  }
39
39
 
40
40
  export const JSON_FORM_PROVIDER_ID = 'workbench-kit.editor.form.json' as const;
41
- /** @deprecated Prefer `workbench-kit.samples.jdw.widget-form` from samples.jdw. */
42
- export const JDW_WIDGET_FORM_PROVIDER_ID = 'workbench-kit.samples.jdw.widget-form' as const;
43
- /** @deprecated Prefer `workbench-kit.samples.jdw.widget-preview` from samples.jdw. */
44
- export const JDW_PREVIEW_PROVIDER_ID = 'workbench-kit.samples.jdw.widget-preview' as const;
45
- /** @deprecated Prefer `workbench-kit.builtin.editor.markdown-preview` from builtin.editor. */
46
- export const MARKDOWN_PREVIEW_PROVIDER_ID =
47
- 'workbench-kit.builtin.editor.markdown-preview' as const;
48
41
 
49
42
  /**
50
43
  * Opt-in shallow top-level JSON object form.
@@ -1,3 +1,4 @@
1
+ import { workspaceExplorerParentPaths } from '@workbench-kit/react/workbench/workspace';
1
2
  import type { WorkspaceSelectionState } from '@workbench-kit/workspace';
2
3
 
3
4
  import {
@@ -69,18 +70,6 @@ export function applyExplorerPathReveal(
69
70
  });
70
71
  }
71
72
 
72
- function workspaceExplorerParentPaths(path: string): string[] {
73
- const segments = path.split('/').filter(Boolean);
74
- return segments.slice(0, -1).map((_, index) => segments.slice(0, index + 1).join('/'));
75
- }
76
-
77
- export function isExplorerHostCommand(commandId: string): boolean {
78
- return (
79
- commandId === BUILTIN_EXPLORER_REVEAL_COMMAND_ID ||
80
- commandId === BUILTIN_EXPLORER_FOCUS_COMMAND_ID
81
- );
82
- }
83
-
84
73
  export async function runExplorerHostCommandSideEffects(
85
74
  commandId: string,
86
75
  args: readonly unknown[],
@@ -1,7 +1,6 @@
1
+ import { parseCommandInspectorUri } from '@workbench-kit/react/workbench/management';
1
2
  import type { EditorHost } from '@workbench-kit/workbench-extension-sdk';
2
3
 
3
- const COMMAND_INSPECTOR_URI_PREFIX = 'workbench://command/inspect/' as const;
4
-
5
4
  export const COMMAND_INSPECTOR_EDITOR_ID = 'workbench-kit.builtin.commands.inspector' as const;
6
5
  export const COMMAND_INSPECTOR_EDITOR_HOST_RENDER_KIND =
7
6
  'workbench-kit.builtin.commands/inspector' as const;
@@ -46,23 +45,6 @@ export class CommandInspectorEditorHost implements EditorHost {
46
45
  }
47
46
  }
48
47
 
49
- export function parseCommandInspectorUri(resourceUri: string): string | undefined {
50
- if (!resourceUri.startsWith(COMMAND_INSPECTOR_URI_PREFIX)) {
51
- return undefined;
52
- }
53
-
54
- const encodedId = resourceUri.slice(COMMAND_INSPECTOR_URI_PREFIX.length);
55
- if (!encodedId) {
56
- return undefined;
57
- }
58
-
59
- try {
60
- return decodeURIComponent(encodedId);
61
- } catch {
62
- return undefined;
63
- }
64
- }
65
-
66
48
  export function isCommandInspectorEditorHostRenderData(
67
49
  value: unknown,
68
50
  ): value is CommandInspectorEditorHostRenderData {
@@ -1,9 +1,9 @@
1
+ import { parseCommandInspectorUri } from '@workbench-kit/react/workbench/management';
1
2
  import type { ExtensionContext } from '@workbench-kit/workbench-extension-sdk';
2
3
 
3
4
  import {
4
5
  COMMAND_INSPECTOR_EDITOR_ID,
5
6
  CommandInspectorEditorHost,
6
- parseCommandInspectorUri,
7
7
  } from './command-inspector-editor-host.js';
8
8
 
9
9
  export const EXTENSION_ID = 'workbench-kit.builtin.commands' as const;
@@ -21,9 +21,9 @@ export {
21
21
  COMMAND_INSPECTOR_EDITOR_ID,
22
22
  CommandInspectorEditorHost,
23
23
  isCommandInspectorEditorHostRenderData,
24
- parseCommandInspectorUri,
25
24
  type CommandInspectorEditorHostRenderData,
26
25
  } from './command-inspector-editor-host.js';
26
+ export { parseCommandInspectorUri };
27
27
 
28
28
  export function activate(context: ExtensionContext): void {
29
29
  context.editorResolvers.registerResolver({
@@ -57,10 +57,8 @@ export function ConvertNoteEditor({
57
57
  if (!transformId) {
58
58
  return {};
59
59
  }
60
- return (
61
- resolveOptionSteps(chain, edge.transformOptionSteps, edge.transformOptions)[stepIndex] ?? {}
62
- );
63
- }, [chain, edge.transformOptionSteps, edge.transformOptions, stepIndex, transformId]);
60
+ return resolveOptionSteps(chain, edge.transformOptionSteps)[stepIndex] ?? {};
61
+ }, [chain, edge.transformOptionSteps, stepIndex, transformId]);
64
62
 
65
63
  const replaceCatalog = listCompatibleTransforms({
66
64
  registry: transforms,
@@ -1,4 +1,5 @@
1
1
  import type { JSX } from 'react';
2
+ import { SideBarList, SideBarListItem } from '@workbench-kit/react/layout';
2
3
  import { Button } from '@workbench-kit/react/primitives';
3
4
  import type { ValueTransformRegistry } from '@workbench-kit/field-remap';
4
5
 
@@ -59,7 +60,7 @@ export function FieldRemapConvertPalette({
59
60
  </Button>
60
61
  </div>
61
62
 
62
- <ul
63
+ <SideBarList
63
64
  className="workbench-field-remap-convert-palette__list"
64
65
  role="listbox"
65
66
  aria-label={chromeLabels.convertsListAriaLabel}
@@ -67,27 +68,23 @@ export function FieldRemapConvertPalette({
67
68
  {catalog.map((definition) => {
68
69
  const selected = definition.id === selectedTransformId;
69
70
  return (
70
- <li key={definition.id}>
71
- <button
72
- type="button"
73
- role="option"
74
- aria-selected={selected}
75
- className={
76
- selected
77
- ? 'workbench-field-remap-convert-palette__item is-selected'
78
- : 'workbench-field-remap-convert-palette__item'
79
- }
80
- data-testid={`field-remap-palette-item-${definition.id}`}
81
- onClick={() => onSelectedTransformIdChange(definition.id)}
82
- onDoubleClick={() => onPlaceDraft(definition.id)}
83
- >
84
- <strong>{definition.label}</strong>
85
- <code>{definition.id}</code>
86
- </button>
87
- </li>
71
+ <SideBarListItem
72
+ key={definition.id}
73
+ aria-selected={selected}
74
+ data-testid={`field-remap-palette-item-${definition.id}`}
75
+ role="option"
76
+ selected={selected}
77
+ variant="stacked"
78
+ wrapperProps={{ role: 'presentation' }}
79
+ onClick={() => onSelectedTransformIdChange(definition.id)}
80
+ onDoubleClick={() => onPlaceDraft(definition.id)}
81
+ >
82
+ <strong>{definition.label}</strong>
83
+ <code title={definition.id}>{definition.id}</code>
84
+ </SideBarListItem>
88
85
  );
89
86
  })}
90
- </ul>
87
+ </SideBarList>
91
88
 
92
89
  {onAddCombine || onAddSplit ? (
93
90
  <div
@@ -14,14 +14,6 @@ import {
14
14
  type ValueTransformRegistry,
15
15
  } from '@workbench-kit/field-remap';
16
16
 
17
- export type FieldRemapFlowNodeKind =
18
- | 'source-object'
19
- | 'target-object'
20
- | 'transform'
21
- | 'draft-transform'
22
- | 'combine-operator'
23
- | 'split-operator';
24
-
25
17
  export type FieldRemapPort = {
26
18
  fieldId: string;
27
19
  label: string;
@@ -106,14 +98,6 @@ const TRANSFORM_X = 320;
106
98
  const TARGET_X = 620;
107
99
  const TRANSFORM_ROW_GAP = 72;
108
100
 
109
- export function sourceObjectNodeId(): string {
110
- return SOURCE_OBJECT_NODE_ID;
111
- }
112
-
113
- export function targetObjectNodeId(): string {
114
- return TARGET_OBJECT_NODE_ID;
115
- }
116
-
117
101
  /** Handle id for a field/slot port on an object node. */
118
102
  export function portHandleId(fieldOrSlotId: string): string {
119
103
  return fieldOrSlotId;
@@ -478,28 +462,21 @@ function resolveConnectionPortIds(connection: {
478
462
  return {};
479
463
  }
480
464
 
481
- let sourceFieldId: string | undefined;
482
- let targetSlotId: string | undefined;
483
-
484
- if (source === SOURCE_OBJECT_NODE_ID && connection.sourceHandle) {
485
- sourceFieldId = connection.sourceHandle;
486
- } else if (source.startsWith('src:')) {
487
- sourceFieldId = source.slice('src:'.length);
488
- }
489
-
490
- if (target === TARGET_OBJECT_NODE_ID && connection.targetHandle) {
491
- targetSlotId = connection.targetHandle;
492
- } else if (target.startsWith('tgt:')) {
493
- targetSlotId = target.slice('tgt:'.length);
494
- }
495
-
496
- return { sourceFieldId, targetSlotId };
465
+ return {
466
+ sourceFieldId:
467
+ source === SOURCE_OBJECT_NODE_ID && connection.sourceHandle
468
+ ? connection.sourceHandle
469
+ : undefined,
470
+ targetSlotId:
471
+ target === TARGET_OBJECT_NODE_ID && connection.targetHandle
472
+ ? connection.targetHandle
473
+ : undefined,
474
+ };
497
475
  }
498
476
 
499
477
  /**
500
478
  * Supported connect matrix for state-changing canvas drags:
501
479
  * - source-object port → target-object port (creates / replaces a `MappingEdge`)
502
- * - legacy `src:*` → `tgt:*` single-field node ids (tests / older graphs)
503
480
  * - source-object port → `draft:*` (bind draft input)
504
481
  * - `draft:*` → target-object port (bind draft output; finalize when both ends set)
505
482
  * - source-object port → `xf:*` `in` (rebind source; splice off earlier steps)
@@ -656,13 +633,10 @@ export function isValidFieldRemapFlowConnection(
656
633
  });
657
634
  }
658
635
 
659
- let topologyOk = false;
660
- if (source === SOURCE_OBJECT_NODE_ID && target === TARGET_OBJECT_NODE_ID) {
661
- topologyOk = Boolean(connection.sourceHandle && connection.targetHandle);
662
- } else if (source.startsWith('src:') && target.startsWith('tgt:')) {
663
- // Legacy single-field node ids (older graphs / tests).
664
- topologyOk = true;
665
- }
636
+ const topologyOk =
637
+ source === SOURCE_OBJECT_NODE_ID &&
638
+ target === TARGET_OBJECT_NODE_ID &&
639
+ Boolean(connection.sourceHandle && connection.targetHandle);
666
640
 
667
641
  if (!topologyOk) {
668
642
  return false;
@@ -696,7 +670,7 @@ export type FieldRemapFlowConnectResult = {
696
670
  readonly removeEdgeIds?: readonly string[];
697
671
  };
698
672
 
699
- /** Parse React Flow connection (object ports or legacy) into a kit MappingEdge. */
673
+ /** Parse a React Flow object-port connection into a kit MappingEdge. */
700
674
  export function connectionToMappingEdge(input: {
701
675
  readonly sourceNodeId: string;
702
676
  readonly targetNodeId: string;
@@ -704,21 +678,12 @@ export function connectionToMappingEdge(input: {
704
678
  readonly targetHandle?: string | null;
705
679
  readonly existing: readonly MappingEdge[];
706
680
  }): MappingEdge | null {
707
- let sourceFieldId: string | undefined;
708
- let targetSlotId: string | undefined;
709
-
710
- if (input.sourceNodeId === SOURCE_OBJECT_NODE_ID && input.sourceHandle) {
711
- sourceFieldId = input.sourceHandle;
712
- } else if (input.sourceNodeId.startsWith('src:')) {
713
- // Legacy single-field node ids (older graphs / tests).
714
- sourceFieldId = input.sourceNodeId.slice('src:'.length);
715
- }
716
-
717
- if (input.targetNodeId === TARGET_OBJECT_NODE_ID && input.targetHandle) {
718
- targetSlotId = input.targetHandle;
719
- } else if (input.targetNodeId.startsWith('tgt:')) {
720
- targetSlotId = input.targetNodeId.slice('tgt:'.length);
721
- }
681
+ const { sourceFieldId, targetSlotId } = resolveConnectionPortIds({
682
+ source: input.sourceNodeId,
683
+ target: input.targetNodeId,
684
+ sourceHandle: input.sourceHandle,
685
+ targetHandle: input.targetHandle,
686
+ });
722
687
 
723
688
  if (!sourceFieldId || !targetSlotId) {
724
689
  return null;
@@ -827,7 +792,6 @@ export function applyFieldRemapFlowConnection(input: {
827
792
  itemEdges: undefined,
828
793
  itemTransformIds: undefined,
829
794
  itemTransformOptionSteps: undefined,
830
- itemTransformOptions: undefined,
831
795
  },
832
796
  removeEdgeIds: [edgeA.id],
833
797
  };
@@ -7,7 +7,6 @@ import {
7
7
  findTargetSlot,
8
8
  isTransformChainCompatible,
9
9
  optionFieldsForStep,
10
- patchOptionStep,
11
10
  resizeOptionSteps,
12
11
  sanitizeOptionRecord,
13
12
  type CombineMappingOperator,
@@ -214,29 +213,6 @@ export function removeTransformStepFromEdge(edge: MappingEdge, stepIndex: number
214
213
  };
215
214
  }
216
215
 
217
- export function patchTransformStepOptionOnEdge(
218
- edge: MappingEdge,
219
- stepIndex: number,
220
- key: string,
221
- value: unknown,
222
- ): MappingEdge {
223
- const length = edge.transformIds?.length ?? 0;
224
- if (stepIndex < 0 || stepIndex >= length) {
225
- return edge;
226
- }
227
- return {
228
- ...edge,
229
- transformOptionSteps: patchOptionStep(
230
- edge.transformOptionSteps,
231
- length,
232
- stepIndex,
233
- key,
234
- value,
235
- edge.transformOptions,
236
- ),
237
- };
238
- }
239
-
240
216
  export function replaceTransformStepOptionsOnEdge(
241
217
  edge: MappingEdge,
242
218
  stepIndex: number,
@@ -47,7 +47,6 @@ export {
47
47
  createJsonataValueTransform,
48
48
  jsonataValueTransform,
49
49
  type CreateJsonataValueTransformOptions,
50
- type JsonataTransformErrorPolicy,
51
50
  } from './jsonata-transform.js';
52
51
  export {
53
52
  addTransformStepToEdge,