1+ import type { NodeContext } from '../types'
2+ import { checkAssetNode } from '../utils/check-asset-node'
3+ import { getPageNode } from '../utils/get-page-node'
4+ import { isPageRoot } from '../utils/is-page-root'
15import { perfEnd , perfStart } from '../utils/perf'
26import { getAutoLayoutProps } from './auto-layout'
37import { getBackgroundProps } from './background'
@@ -12,14 +16,28 @@ import { getMaxLineProps } from './max-line'
1216import { getObjectFitProps } from './object-fit'
1317import { getOverflowProps } from './overflow'
1418import { getPaddingProps } from './padding'
15- import { getPositionProps } from './position'
19+ import { canBeAbsolute , getPositionProps } from './position'
1620import { getReactionProps } from './reaction'
1721import { getTextAlignProps } from './text-align'
1822import { getTextShadowProps } from './text-shadow'
1923import { getTextStrokeProps } from './text-stroke'
2024import { getTransformProps } from './transform'
2125import { getVisibilityProps } from './visibility'
2226
27+ export function computeNodeContext ( node : SceneNode ) : NodeContext {
28+ const asset = checkAssetNode ( node )
29+ const pageNode = getPageNode (
30+ node as BaseNode & ChildrenMixin ,
31+ ) as SceneNode | null
32+ const pageRoot = isPageRoot ( node )
33+ return {
34+ isAsset : asset ,
35+ canBeAbsolute : canBeAbsolute ( node ) ,
36+ isPageRoot : pageRoot ,
37+ pageNode,
38+ }
39+ }
40+
2341// Cache getProps() results keyed by node.id to avoid redundant computation.
2442// Figma returns new JS wrapper objects for the same node on each property access,
2543// so object-reference keys don't work — node.id is the stable identifier.
@@ -56,6 +74,9 @@ export async function getProps(
5674 const promise = ( async ( ) => {
5775 const isText = node . type === 'TEXT'
5876
77+ // Compute cross-cutting node context ONCE for all sync getters that need it.
78+ const ctx = computeNodeContext ( node )
79+
5980 // PHASE 1: Fire all async prop getters — initiates Figma IPC calls immediately.
6081 // These return Promises that resolve when IPC completes.
6182 const tBorder = perfStart ( )
@@ -72,9 +93,9 @@ export async function getProps(
7293 // Compute sync results eagerly; they'll be interleaved in the original merge
7394 // order below to preserve "last-key-wins" semantics.
7495 const tSync = perfStart ( )
75- const autoLayoutProps = getAutoLayoutProps ( node )
96+ const autoLayoutProps = getAutoLayoutProps ( node , ctx )
7697 const minMaxProps = getMinMaxProps ( node )
77- const layoutProps = getLayoutProps ( node )
98+ const layoutProps = getLayoutProps ( node , ctx )
7899 const borderRadiusProps = getBorderRadiusProps ( node )
79100 const blendProps = getBlendProps ( node )
80101 const paddingProps = getPaddingProps ( node )
@@ -85,9 +106,9 @@ export async function getProps(
85106 const tEffect = perfStart ( )
86107 const effectProps = getEffectProps ( node )
87108 perfEnd ( 'getProps.effect' , tEffect )
88- const positionProps = getPositionProps ( node )
109+ const positionProps = getPositionProps ( node , ctx )
89110 const gridChildProps = getGridChildProps ( node )
90- const transformProps = getTransformProps ( node )
111+ const transformProps = getTransformProps ( node , ctx )
91112 const overflowProps = getOverflowProps ( node )
92113 const tTextShadow = perfStart ( )
93114 const textShadowProps = isText ? getTextShadowProps ( node ) : undefined
0 commit comments