openpencil/tests/engine/figma/api/helpers.ts
Danila Poyarkov 105032153e
feat(core): name the node type createInstance and detachInstance return (#918)
Both factories know what they built, but returned the bare proxy, so a
caller reading componentProperties, setProperties or isExposedInstance
had to narrow first — the instance surface is only spelled out on the
node types. Two test suites had each grown their own cast for it.

FigmaInstanceNode joins the other node types and is exported, and the
compatibility check names it instead of respelling the intersection.

Narrowing a return type is not a breaking change: a caller that held
the result as a FigmaNodeProxy still compiles.
2026-10-06 09:35:03 +00:00

59 lines
1.8 KiB
TypeScript

import { FigmaAPI, SceneGraph } from '@open-pencil/core'
import type { FigmaNodeProxy } from '@open-pencil/core'
import type { Color, Fill, Stroke } from '@open-pencil/scene-graph'
export function createAPI(): FigmaAPI {
return new FigmaAPI(new SceneGraph())
}
/** Reads a proxy through Figma's `TextNode` surface, which `wrapNode()` cannot name. */
export function asTextNode(node: FigmaNodeProxy): FigmaNodeProxy & TextNode {
return node as FigmaNodeProxy & TextNode
}
/**
* Names a proxy a component, including where a rejection path is handed one and the runtime
* guard, not the type, is what the test exercises.
*/
export function asComponentNode(node: FigmaNodeProxy): FigmaNodeProxy & ComponentNode {
return node as FigmaNodeProxy & ComponentNode
}
/**
* Names `api.currentPage` as a page. The boolean-operation entry points only take Figma's node
* types, while the current-page proxy is typed by its selection alone.
*/
export function asPageNode(
page: FigmaNodeProxy & { selection: FigmaNodeProxy[] }
): FigmaNodeProxy & PageNode {
return page as FigmaNodeProxy & PageNode
}
/**
* A solid paint that satisfies both the OpenPencil `Fill` and the Figma `SolidPaint` shape, as the
* node proxies expose the intersection of the two.
*/
export function solidFill(
color: Color,
overrides: { opacity?: number; visible?: boolean } = {}
): Fill & SolidPaint {
return {
type: 'SOLID',
color,
opacity: overrides.opacity ?? 1,
visible: overrides.visible ?? true
}
}
/** The stroke counterpart of {@link solidFill}. */
export function solidStroke(
color: Color,
stroke: { weight: number; align: Stroke['align']; opacity?: number; visible?: boolean }
): Stroke & SolidPaint {
return {
...solidFill(color, stroke),
weight: stroke.weight,
align: stroke.align
}
}