fix(fig): omit populated instance children on export

- Match Figma files where INSTANCE node changes carry symbol refs, not child nodes
- Prevent exported roundtrips from expanding every populated instance subtree
- Tighten glyph blob preservation now that instance children are omitted
This commit is contained in:
Danila Poyarkov 2026-05-20 19:10:23 +03:00
parent 1c655f34ce
commit 68ebef5f9b
3 changed files with 14 additions and 5 deletions

View file

@ -279,7 +279,10 @@ export function sceneNodeToKiwiWithContext(
}
const result: KiwiNodeChange[] = [nc]
const children = context.graph.getChildren(node.id).filter((child) => !child.internalOnly)
const children =
node.type === 'INSTANCE'
? []
: context.graph.getChildren(node.id).filter((child) => !child.internalOnly)
for (let i = 0; i < children.length; i++) {
result.push(...context.sceneNodeToKiwi(children[i], guid, i, localIdCounter, context))
}

View file

@ -56,9 +56,8 @@ describe('roundtrip: text glyph blobs', () => {
const output = countGlyphBlobs(exported)
expect(input.glyphsWithBlob).toBeGreaterThan(0)
expect(output.glyphsWithBlob).toBeGreaterThan(0)
expect(output.uniqueGlyphBlobs).toBeLessThan(output.glyphsWithBlob / 100)
expect(output.uniqueGlyphBlobs).toBeLessThanOrEqual(input.uniqueGlyphBlobs + 20)
expect(output.glyphsWithBlob).toBe(input.glyphsWithBlob)
expect(output.uniqueGlyphBlobs).toBeLessThanOrEqual(input.uniqueGlyphBlobs)
})
test('deduplicates generated glyph blobs across repeated text', async () => {

View file

@ -56,7 +56,7 @@ describe('export subgraph extraction', () => {
expect(extracted.graph.getNode(libraryPage.id)?.type).toBe('CANVAS')
})
test('fig page export preserves valid instance component references', async () => {
test('fig page export preserves valid instance component references without serializing instance children', async () => {
await initCodec()
const graph = new SceneGraph()
const page = graph.getPages()[0]
@ -79,5 +79,12 @@ describe('export subgraph extraction', () => {
expect(parsedInstance?.type).toBe('INSTANCE')
expect(parsedInstance?.componentId).toBeTruthy()
expect(parsed.getNode(parsedInstance?.componentId ?? '')?.type).toBe('COMPONENT')
const exportedAgain = await exportFigFile(extracted.graph)
const reparsed = await parseFigFile(exportedAgain.buffer as ArrayBuffer)
const reparsedInstance = [...reparsed.getAllNodes()].find(
(node) => node.type === 'INSTANCE' && node.name === instance.name
)
expect(reparsedInstance?.childIds).toEqual([])
})
})