91 lines
2.6 KiB
TypeScript
91 lines
2.6 KiB
TypeScript
/**
|
|
* Automation2 Flow Editor - Data reference format and helpers.
|
|
* All dynamic values use structured ref/value objects, not plain strings.
|
|
*/
|
|
|
|
/** Structured reference to another node's output (path = JSON path segments) */
|
|
export interface DataRef {
|
|
type: 'ref';
|
|
nodeId: string;
|
|
path: (string | number)[];
|
|
}
|
|
|
|
/** Explicit static value wrapper */
|
|
export interface DataValue {
|
|
type: 'value';
|
|
value: unknown;
|
|
}
|
|
|
|
/** Union: either a reference or a static value */
|
|
export type DynamicValue = DataRef | DataValue;
|
|
|
|
/** Type guards */
|
|
export function isRef(v: unknown): v is DataRef {
|
|
return (
|
|
typeof v === 'object' &&
|
|
v !== null &&
|
|
(v as DataRef).type === 'ref' &&
|
|
typeof (v as DataRef).nodeId === 'string' &&
|
|
Array.isArray((v as DataRef).path)
|
|
);
|
|
}
|
|
|
|
export function isValue(v: unknown): v is DataValue {
|
|
return (
|
|
typeof v === 'object' &&
|
|
v !== null &&
|
|
(v as DataValue).type === 'value'
|
|
);
|
|
}
|
|
|
|
export function isDynamicValue(v: unknown): v is DynamicValue {
|
|
return isRef(v) || isValue(v);
|
|
}
|
|
|
|
/** Create a reference object */
|
|
export function createRef(nodeId: string, path: (string | number)[] = []): DataRef {
|
|
return { type: 'ref', nodeId, path };
|
|
}
|
|
|
|
/** Create a value wrapper */
|
|
export function createValue(value: unknown): DataValue {
|
|
return { type: 'value', value };
|
|
}
|
|
|
|
/** Resolve a ref against nodeOutputsPreview for UI preview; returns resolved value or undefined if missing */
|
|
export function resolvePreview(
|
|
ref: DataRef,
|
|
nodeOutputsPreview: Record<string, unknown>
|
|
): unknown {
|
|
const root = nodeOutputsPreview[ref.nodeId];
|
|
if (root === undefined) return undefined;
|
|
let current: unknown = root;
|
|
for (const seg of ref.path) {
|
|
if (current == null) return undefined;
|
|
const key = typeof seg === 'number' ? String(seg) : seg;
|
|
if (Array.isArray(current) && /^\d+$/.test(key)) {
|
|
const idx = parseInt(key, 10);
|
|
if (idx >= 0 && idx < current.length) current = current[idx];
|
|
else return undefined;
|
|
} else if (typeof current === 'object' && key in current) {
|
|
current = (current as Record<string, unknown>)[key];
|
|
} else return undefined;
|
|
}
|
|
return current;
|
|
}
|
|
|
|
/** Format a ref for human display: "Node Title → path.segment" */
|
|
export function formatRefLabel(
|
|
ref: DataRef,
|
|
nodes: Array<{ id: string; title?: string }>,
|
|
nodeLabelFallback?: (nodeId: string) => string
|
|
): string {
|
|
const node = nodes.find((n) => n.id === ref.nodeId);
|
|
const nodeLabel =
|
|
node?.title?.trim() ||
|
|
nodeLabelFallback?.(ref.nodeId) ||
|
|
ref.nodeId;
|
|
if (ref.path.length === 0) return nodeLabel;
|
|
const pathStr = ref.path.map((p) => String(p)).join(' → ');
|
|
return `${nodeLabel} → ${pathStr}`;
|
|
}
|