refactor(fig): own archive assembly
- Add public writeFigArchive API for canvas, thumbnail, metadata, and image entries\n- Reduce core compression to a compatibility re-export\n- Exercise archive writing through package-local and packed smoke tests
This commit is contained in:
parent
f9e2588b84
commit
f0d10edf69
|
|
@ -1,23 +1 @@
|
|||
import { zipSync, type Zippable } from 'fflate'
|
||||
|
||||
import { buildFigKiwi } from '#core/kiwi/fig/node-change/serialize'
|
||||
|
||||
export function compressFigDataSync(
|
||||
schemaDeflated: Uint8Array,
|
||||
kiwiData: Uint8Array,
|
||||
thumbnailPng: Uint8Array,
|
||||
metaJson: string,
|
||||
imageEntries: Array<{ name: string; data: Uint8Array }>,
|
||||
figKiwiVersion?: number
|
||||
): Uint8Array {
|
||||
const canvasData = buildFigKiwi(schemaDeflated, kiwiData, figKiwiVersion)
|
||||
const zipEntries: Zippable = {
|
||||
'canvas.fig': [canvasData, { level: 0 }],
|
||||
'thumbnail.png': [thumbnailPng, { level: 0 }],
|
||||
'meta.json': new TextEncoder().encode(metaJson)
|
||||
}
|
||||
for (const entry of imageEntries) {
|
||||
zipEntries[entry.name] = [entry.data, { level: 0 }]
|
||||
}
|
||||
return zipSync(zipEntries)
|
||||
}
|
||||
export { compressFigDataSync } from '@open-pencil/fig'
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ SceneGraph conversion policy. Production SceneGraph read/write remains available
|
|||
Current ownership:
|
||||
|
||||
- Complete `.fig` archive parsing through `parseFigBuffer()`
|
||||
- Canvas payload and image resource discovery
|
||||
- `.fig` archive assembly through `writeFigArchive()`
|
||||
- Canvas payload and image resource handling
|
||||
- `readFigContainer()` / `writeFigContainer()` helpers for raw `fig-kiwi` payloads
|
||||
- `.fig` source and archive result types
|
||||
|
||||
Planned ownership:
|
||||
|
||||
- `.fig` archive assembly
|
||||
- SceneGraph ⇄ Figma `NodeChange` conversion
|
||||
- Raw Figma metadata precedence and invalidation policy
|
||||
- Component and instance interpretation
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@ export {}
|
|||
|
||||
const mod = await import('../dist/index.js')
|
||||
|
||||
if (mod.FIG_PACKAGE_STATUS !== 'archive-api' || typeof mod.parseFigBuffer !== 'function') {
|
||||
if (
|
||||
mod.FIG_PACKAGE_STATUS !== 'archive-api' ||
|
||||
typeof mod.parseFigBuffer !== 'function' ||
|
||||
typeof mod.writeFigArchive !== 'function'
|
||||
) {
|
||||
throw new Error('Expected @open-pencil/fig archive API exports')
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,23 @@
|
|||
import { unzipSync } from 'fflate'
|
||||
import { unzipSync, zipSync, type Zippable } from 'fflate'
|
||||
|
||||
import type { NodeChange } from '@open-pencil/kiwi/fig/codec'
|
||||
import { buildFigKiwi } from '@open-pencil/kiwi/fig/container'
|
||||
import { decodeFigKiwiCanvas } from '@open-pencil/kiwi/fig/parse'
|
||||
|
||||
export interface FigImageEntry {
|
||||
name: string
|
||||
data: Uint8Array
|
||||
}
|
||||
|
||||
export interface WriteFigArchiveInput {
|
||||
schemaDeflated: Uint8Array
|
||||
kiwiData: Uint8Array
|
||||
thumbnailPng: Uint8Array
|
||||
metaJson: string
|
||||
images?: FigImageEntry[]
|
||||
figKiwiVersion?: number
|
||||
}
|
||||
|
||||
export interface FigParseResult {
|
||||
nodeChanges: NodeChange[]
|
||||
blobs: Uint8Array[]
|
||||
|
|
@ -51,3 +66,34 @@ export function parseFigBuffer(buffer: ArrayBuffer): FigParseResult {
|
|||
|
||||
return { ...decoded, images }
|
||||
}
|
||||
|
||||
/** Assemble a complete zipped `.fig` archive from an encoded Kiwi message and resources. */
|
||||
export function writeFigArchive(input: WriteFigArchiveInput): Uint8Array {
|
||||
const canvasData = buildFigKiwi(input.schemaDeflated, input.kiwiData, input.figKiwiVersion)
|
||||
const entries: Zippable = {
|
||||
'canvas.fig': [canvasData, { level: 0 }],
|
||||
'thumbnail.png': [input.thumbnailPng, { level: 0 }],
|
||||
'meta.json': new TextEncoder().encode(input.metaJson)
|
||||
}
|
||||
for (const image of input.images ?? []) entries[image.name] = [image.data, { level: 0 }]
|
||||
return zipSync(entries)
|
||||
}
|
||||
|
||||
/** Compatibility signature used by core while archive assembly migrates to this package. */
|
||||
export function compressFigDataSync(
|
||||
schemaDeflated: Uint8Array,
|
||||
kiwiData: Uint8Array,
|
||||
thumbnailPng: Uint8Array,
|
||||
metaJson: string,
|
||||
imageEntries: FigImageEntry[],
|
||||
figKiwiVersion?: number
|
||||
): Uint8Array {
|
||||
return writeFigArchive({
|
||||
schemaDeflated,
|
||||
kiwiData,
|
||||
thumbnailPng,
|
||||
metaJson,
|
||||
images: imageEntries,
|
||||
figKiwiVersion
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
export { parseFigBuffer, type FigParseResult } from './archive'
|
||||
export {
|
||||
compressFigDataSync,
|
||||
parseFigBuffer,
|
||||
writeFigArchive,
|
||||
type FigImageEntry,
|
||||
type FigParseResult,
|
||||
type WriteFigArchiveInput
|
||||
} from './archive'
|
||||
|
||||
import {
|
||||
FIG_KIWI_DEFAULT_VERSION,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { beforeAll, describe, expect, it } from 'bun:test'
|
||||
|
||||
import { deflateSync, zipSync } from 'fflate'
|
||||
import { deflateSync } from 'fflate'
|
||||
|
||||
import {
|
||||
createNodeChangesMessage,
|
||||
|
|
@ -14,6 +14,7 @@ import {
|
|||
assertFigPackageReady,
|
||||
parseFigBuffer,
|
||||
readFigContainer,
|
||||
writeFigArchive,
|
||||
writeFigContainer
|
||||
} from '../src/index'
|
||||
|
||||
|
|
@ -40,9 +41,9 @@ describe('@open-pencil/fig package API', () => {
|
|||
})
|
||||
|
||||
it('parses complete .fig archives and image resources', () => {
|
||||
const canvas = writeFigContainer({
|
||||
const bytes = writeFigArchive({
|
||||
schemaDeflated: deflateSync(getSchemaBytes()),
|
||||
dataRaw: encodeMessage(
|
||||
kiwiData: encodeMessage(
|
||||
createNodeChangesMessage(0, 0, [
|
||||
{
|
||||
guid: { sessionID: 0, localID: 0 },
|
||||
|
|
@ -52,11 +53,9 @@ describe('@open-pencil/fig package API', () => {
|
|||
}
|
||||
])
|
||||
),
|
||||
source: { fileName: 'fixture.fig' }
|
||||
})
|
||||
const bytes = zipSync({
|
||||
'canvas.fig': canvas,
|
||||
'images/hash': new Uint8Array([9, 8, 7])
|
||||
thumbnailPng: new Uint8Array([1]),
|
||||
metaJson: '{}',
|
||||
images: [{ name: 'images/hash', data: new Uint8Array([9, 8, 7]) }]
|
||||
})
|
||||
const parsed = parseFigBuffer(bytes.buffer as ArrayBuffer)
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ try {
|
|||
tempDir
|
||||
)
|
||||
nodeEval(
|
||||
"const { FIG_PACKAGE_STATUS, parseFigBuffer, readFigContainer, writeFigContainer } = await import('@open-pencil/fig'); if (FIG_PACKAGE_STATUS !== 'archive-api' || typeof parseFigBuffer !== 'function') throw new Error('Fig package status smoke failed'); const document = readFigContainer(writeFigContainer({ schemaDeflated: new Uint8Array([1]), dataRaw: new Uint8Array([2]) })); if (document.dataRaw[0] !== 2) throw new Error('Fig container smoke failed')",
|
||||
"const { FIG_PACKAGE_STATUS, parseFigBuffer, writeFigArchive, readFigContainer, writeFigContainer } = await import('@open-pencil/fig'); if (FIG_PACKAGE_STATUS !== 'archive-api' || typeof parseFigBuffer !== 'function' || typeof writeFigArchive !== 'function') throw new Error('Fig package status smoke failed'); const document = readFigContainer(writeFigContainer({ schemaDeflated: new Uint8Array([1]), dataRaw: new Uint8Array([2]) })); if (document.dataRaw[0] !== 2) throw new Error('Fig container smoke failed')",
|
||||
tempDir
|
||||
)
|
||||
nodeEval(
|
||||
|
|
|
|||
Loading…
Reference in a new issue