refactor(kiwi): move FIG GUID helpers

This commit is contained in:
Danila Poyarkov 2026-06-06 15:59:48 +03:00
parent 6bf930e9e9
commit f6a8bd8580
10 changed files with 42 additions and 9 deletions

View file

@ -3,7 +3,7 @@ import { DEFAULT_FONT_FAMILY, DEFAULT_STROKE_MITER_LIMIT } from '#core/constants
import { parseVariantName } from '#core/scene-graph/variant-name' import { parseVariantName } from '#core/scene-graph/variant-name'
import { styleToWeight } from '#core/text/fonts' import { styleToWeight } from '#core/text/fonts'
import { guidToString } from './guid' import { guidToString } from '@open-pencil/kiwi/fig/guid'
import { convertEffects, convertFills, convertStrokes } from './paint' import { convertEffects, convertFills, convertStrokes } from './paint'
import { importStyleRuns } from './style-runs' import { importStyleRuns } from './style-runs'
export { importStyleRuns } from './style-runs' export { importStyleRuns } from './style-runs'
@ -52,7 +52,7 @@ import type {
} from '#core/scene-graph' } from '#core/scene-graph'
import type { GUID } from '#core/types' import type { GUID } from '#core/types'
export { guidToString, stringToGuid } from './guid' export { guidToString, stringToGuid } from '@open-pencil/kiwi/fig/guid'
export const VARIABLE_BINDING_FIELDS: Record<string, string> = { export const VARIABLE_BINDING_FIELDS: Record<string, string> = {
// Corner radius // Corner radius

View file

@ -5,7 +5,7 @@ import { bytesToHex } from '#core/bytes/hex'
import type { SceneGraph, SceneNode } from '#core/scene-graph' import type { SceneGraph, SceneNode } from '#core/scene-graph'
import type { Color, GUID, Matrix, Vector } from '#core/types' import type { Color, GUID, Matrix, Vector } from '#core/types'
import { stringToGuid } from './guid' import { stringToGuid } from '@open-pencil/kiwi/fig/guid'
import { import {
applyExportSettingsPluginData, applyExportSettingsPluginData,
mergePluginData, mergePluginData,

View file

@ -1,7 +1,7 @@
import type { Paint, Effect as KiwiEffect } from '@open-pencil/kiwi/fig/codec' import type { Paint, Effect as KiwiEffect } from '@open-pencil/kiwi/fig/codec'
import { guidToString } from '@open-pencil/kiwi/fig/guid'
import { normalizeColor } from '#core/color' import { normalizeColor } from '#core/color'
import { guidToString } from '#core/kiwi/fig/node-change/guid'
import type { import type {
Fill, Fill,
FillType, FillType,

View file

@ -1,6 +1,5 @@
import type { GUID, NodeChange } from '@open-pencil/kiwi/fig/codec' import type { GUID, NodeChange } from '@open-pencil/kiwi/fig/codec'
import { guidToString } from '@open-pencil/kiwi/fig/guid'
import { guidToString } from '#core/kiwi/fig/node-change/guid'
const TEXT_STYLE_FIELDS = [ const TEXT_STYLE_FIELDS = [
'fontSize', 'fontSize',

View file

@ -34,6 +34,12 @@
"import": "./dist/fig/container.js", "import": "./dist/fig/container.js",
"default": "./dist/fig/container.js" "default": "./dist/fig/container.js"
}, },
"./fig/guid": {
"types": "./dist/src/fig/guid.d.ts",
"bun": "./src/fig/guid.ts",
"import": "./dist/fig/guid.js",
"default": "./dist/fig/guid.js"
},
"./fig/parse": { "./fig/parse": {
"types": "./dist/src/fig/parse.d.ts", "types": "./dist/src/fig/parse.d.ts",
"bun": "./src/fig/parse.ts", "bun": "./src/fig/parse.ts",

View file

@ -1,5 +1,6 @@
import { getSchemaBytes, initCodec, isCodecReady } from '../dist/fig/codec.js' import { getSchemaBytes, initCodec, isCodecReady } from '../dist/fig/codec.js'
import { buildFigKiwi, parseFigKiwiChunks } from '../dist/fig/container.js' import { buildFigKiwi, parseFigKiwiChunks } from '../dist/fig/container.js'
import { guidToString } from '../dist/fig/guid.js'
import { parseFigKiwiContainer } from '../dist/fig/parse.js' import { parseFigKiwiContainer } from '../dist/fig/parse.js'
import { figmaSchema, getKiwiMessageType, parseSchema, validateSchema } from '../dist/index.js' import { figmaSchema, getKiwiMessageType, parseSchema, validateSchema } from '../dist/index.js'
@ -33,3 +34,7 @@ const figKiwi = buildFigKiwi(new Uint8Array([1]), new Uint8Array([2]))
if (parseFigKiwiChunks(figKiwi)?.length !== 2) { if (parseFigKiwiChunks(figKiwi)?.length !== 2) {
throw new Error('Failed to read built FIG Kiwi container chunks') throw new Error('Failed to read built FIG Kiwi container chunks')
} }
if (guidToString({ sessionID: 1, localID: 2 }) !== '1:2') {
throw new Error('Failed to format built FIG GUID helper')
}

View file

@ -1,4 +1,4 @@
import type { GUID } from '@open-pencil/kiwi/fig/codec' import type { GUID } from './types'
export function guidToString(guid: GUID): string { export function guidToString(guid: GUID): string {
return `${guid.sessionID}:${guid.localID}` return `${guid.sessionID}:${guid.localID}`
@ -6,8 +6,9 @@ export function guidToString(guid: GUID): string {
export function stringToGuid(str: string): GUID { export function stringToGuid(str: string): GUID {
const match = str.match(/^(?:VariableID:|VariableCollectionId:)?(\d+):(\d+)$/) const match = str.match(/^(?:VariableID:|VariableCollectionId:)?(\d+):(\d+)$/)
if (match) if (match) {
return { sessionID: Number.parseInt(match[1], 10), localID: Number.parseInt(match[2], 10) } return { sessionID: Number.parseInt(match[1], 10), localID: Number.parseInt(match[2], 10) }
}
const [session, local] = str.split(':') const [session, local] = str.split(':')
return { sessionID: Number.parseInt(session, 10), localID: Number.parseInt(local, 10) } return { sessionID: Number.parseInt(session, 10), localID: Number.parseInt(local, 10) }
} }

View file

@ -0,0 +1,21 @@
import { describe, expect, test } from 'bun:test'
import { guidToString, stringToGuid } from '../src/fig/guid'
describe('Figma GUID helpers', () => {
test('formats GUID structs as Figma IDs', () => {
expect(guidToString({ sessionID: 12, localID: 34 })).toBe('12:34')
})
test('parses plain Figma IDs', () => {
expect(stringToGuid('12:34')).toEqual({ sessionID: 12, localID: 34 })
})
test('parses variable-prefixed Figma IDs', () => {
expect(stringToGuid('VariableID:12:34')).toEqual({ sessionID: 12, localID: 34 })
expect(stringToGuid('VariableCollectionId:56:78')).toEqual({
sessionID: 56,
localID: 78
})
})
})

View file

@ -22,6 +22,7 @@ export default defineConfig({
fig: './src/fig/index.ts', fig: './src/fig/index.ts',
'fig/codec': './src/fig/codec.ts', 'fig/codec': './src/fig/codec.ts',
'fig/container': './src/fig/container.ts', 'fig/container': './src/fig/container.ts',
'fig/guid': './src/fig/guid.ts',
'fig/parse': './src/fig/parse.ts' 'fig/parse': './src/fig/parse.ts'
}, },
plugins: [rawText()], plugins: [rawText()],

View file

@ -3,8 +3,8 @@ import { readFileSync } from 'node:fs'
import { exportFigFile, extractExportGraph, parseFigFile } from '@open-pencil/core/io' import { exportFigFile, extractExportGraph, parseFigFile } from '@open-pencil/core/io'
import { initCodec } from '@open-pencil/core/kiwi' import { initCodec } from '@open-pencil/core/kiwi'
import { guidToString } from '@open-pencil/core/kiwi/fig/node-change/guid'
import { SceneGraph } from '@open-pencil/core/scene-graph' import { SceneGraph } from '@open-pencil/core/scene-graph'
import { guidToString } from '@open-pencil/kiwi/fig/guid'
import { parseFigBuffer } from '@open-pencil/kiwi/fig/parse' import { parseFigBuffer } from '@open-pencil/kiwi/fig/parse'
describe('export subgraph extraction', () => { describe('export subgraph extraction', () => {