UNPKG

@lifi/compose-spec

Version:

Public wire-format types and schemas for Compose flows

67 lines (57 loc) 2.17 kB
import type { Ref } from "./flowSchema.js"; export type ParsedRef = | { readonly scope: "input"; readonly port: string } | { readonly scope: "output"; readonly node: string; readonly port: string } | { readonly scope: "context"; readonly key: ContextKey }; export type RefScope = ParsedRef["scope"]; export type ContextKey = "sender" | "executionAddress"; export const isContextKey = (key: string): key is ContextKey => key === "sender" || key === "executionAddress"; /** * Ref prefixes that parseRef intercepts before the fallback `output` scope. * A node whose id matches one of these would produce ambiguous refs * (e.g. `context.sender` could be a context ref or node-output ref). * Validation must reject these as node ids. */ export const RESERVED_REF_SCOPES: ReadonlySet<string> = new Set([ "input", "context", "literal", ]); export const isRef = (v: unknown): v is Ref => typeof v === "object" && v !== null && "$ref" in v && typeof (v as { $ref: unknown }).$ref === "string"; export const parseRef = (ref: Ref): ParsedRef => { const dot = ref.$ref.indexOf("."); if (dot === -1) throw new Error(`Invalid ref: "${ref.$ref}" (must contain a dot)`); const prefix = ref.$ref.slice(0, dot); const suffix = ref.$ref.slice(dot + 1); if (prefix === "input") return { scope: "input", port: suffix }; if (prefix === "context") { if (!isContextKey(suffix)) throw new Error(`Unknown context key: "${suffix}"`); return { scope: "context", key: suffix }; } return { scope: "output", node: prefix, port: suffix }; }; export const foldRef = <R>( ref: ParsedRef, cases: { readonly input: (port: string) => R; readonly context: (key: ContextKey) => R; readonly output: (node: string, port: string) => R; } ): R => { if (ref.scope === "input") return cases.input(ref.port); if (ref.scope === "context") return cases.context(ref.key); return cases.output(ref.node, ref.port); }; export const refKey = (ref: Ref): string => foldRef(parseRef(ref), { input: (port) => `input:${port}`, context: (key) => `context:${key}`, output: (node, port) => `output:${node}:${port}`, });