Merge pull request #651 from open-pencil/adapt-pr-645

fix: handle nested CLI import outputs and stale oracle imports
This commit is contained in:
Danila Poyarkov 2026-09-06 19:14:16 +03:00 committed by GitHub
commit 5ab13032ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 59 additions and 51 deletions

View file

@ -1,5 +1,5 @@
import { readFile, writeFile } from 'node:fs/promises'
import { basename, extname, resolve } from 'node:path'
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { basename, dirname, extname, resolve } from 'node:path'
import { defineCommand } from 'citty'
@ -91,6 +91,8 @@ async function writeOutput(
const format = args.format.toLowerCase()
const output = args.output ? resolve(args.output) : defaultOutput(requireFile(args.file), format)
await mkdir(dirname(output), { recursive: true })
if (format === 'json') {
await writeFile(output, `${JSON.stringify(document, null, 2)}\n`)
return output

View file

@ -52,33 +52,36 @@ function findNode(nodes: Iterable<SceneNode>, name: string): SceneNode | undefin
}
}
test('import CLI writes DesignDOM JSON output', async () => {
const { htmlPath, cssPath, dir } = await createFixture()
const output = join(dir, 'card.json')
test.each(['card.json', 'missing/nested/card.json'])(
'import CLI writes DesignDOM JSON output to %s',
async (relativeOutput) => {
const { htmlPath, cssPath, dir } = await createFixture()
const output = join(dir, relativeOutput)
const { stdout, stderr, exitCode } = await runOpenPencilCLI([
'import',
htmlPath,
'--css',
cssPath,
'--format',
'json',
'--output',
output,
'--json'
])
const { stdout, stderr, exitCode } = await runOpenPencilCLI([
'import',
htmlPath,
'--css',
cssPath,
'--format',
'json',
'--output',
output,
'--json'
])
expect(stderr).toBe('')
expect(exitCode).toBe(0)
expect(stderr).toBe('')
expect(exitCode).toBe(0)
const summary = JSON.parse(stdout)
expect(summary).toMatchObject({ format: 'json', output, pages: 1, rootElements: 1 })
const summary = JSON.parse(stdout)
expect(summary).toMatchObject({ format: 'json', output, pages: 1, rootElements: 1 })
const document = JSON.parse(await Bun.file(output).text())
expect(document.children[0].tagName).toBe('article')
expect(document.children[0].computedStyle.display).toBe('flex')
expect(document.children[0].computedStyle.width).toBe('240px')
})
const document = JSON.parse(await Bun.file(output).text())
expect(document.children[0].tagName).toBe('article')
expect(document.children[0].computedStyle.display).toBe('flex')
expect(document.children[0].computedStyle.width).toBe('240px')
}
)
test('import CLI reads embedded HTML styles without a sidecar CSS file', async () => {
const dir = await mkdtemp(join(tmpdir(), 'open-pencil-import-cli-embedded-'))
@ -118,34 +121,37 @@ test('import CLI reads embedded HTML styles without a sidecar CSS file', async (
expect(document.children[0].computedStyle.gap).toBe('10px')
})
test('import CLI writes a .fig that core IO can import', async () => {
const { htmlPath, cssPath, dir } = await createFixture()
const output = join(dir, 'card.fig')
test.each(['card.fig', 'missing/nested/card.fig'])(
'import CLI writes a .fig that core IO can import to %s',
async (relativeOutput) => {
const { htmlPath, cssPath, dir } = await createFixture()
const output = join(dir, relativeOutput)
const { stdout, stderr, exitCode } = await runOpenPencilCLI([
'import',
htmlPath,
'--css',
cssPath,
'--output',
output,
'--json'
])
const { stdout, stderr, exitCode } = await runOpenPencilCLI([
'import',
htmlPath,
'--css',
cssPath,
'--output',
output,
'--json'
])
expect(stderr).toBe('')
expect(exitCode).toBe(0)
expect(JSON.parse(stdout)).toMatchObject({ format: 'fig', output, pages: 1, rootElements: 1 })
expect(stderr).toBe('')
expect(exitCode).toBe(0)
expect(JSON.parse(stdout)).toMatchObject({ format: 'fig', output, pages: 1, rootElements: 1 })
const bytes = new Uint8Array(await Bun.file(output).arrayBuffer())
const graph = await parseFigFile(bytes)
const nodes = [...graph.nodes.values()]
const card = findNode(nodes, 'card')
const title = findNode(nodes, 'DOM/CSS card')
const bytes = new Uint8Array(await Bun.file(output).arrayBuffer())
const graph = await parseFigFile(bytes)
const nodes = [...graph.nodes.values()]
const card = findNode(nodes, 'card')
const title = findNode(nodes, 'DOM/CSS card')
expect(graph.getPages()).toHaveLength(1)
expect(card?.type).toBe('FRAME')
expect(title?.type).toBe('TEXT')
})
expect(graph.getPages()).toHaveLength(1)
expect(card?.type).toBe('FRAME')
expect(title?.type).toBe('TEXT')
}
)
test('import CLI compiles Tailwind candidates before import', async () => {
const dir = await mkdtemp(join(tmpdir(), 'open-pencil-import-cli-tailwind-'))

View file

@ -9,7 +9,7 @@ import { $ } from 'bun'
import { parseColor } from '@open-pencil/core/color'
import { headlessRenderNodes, initCanvasKit, parseFigFile } from '@open-pencil/core/io'
import { computeAllLayouts } from '@open-pencil/core/layout'
import type { SceneGraph } from '@open-pencil/core/scene-graph'
import type { SceneGraph } from '@open-pencil/scene-graph'
interface DiffMetrics {
mean: number

View file

@ -23,8 +23,8 @@ import { SkiaRenderer } from '@open-pencil/core/canvas'
import { importClipboardNodes, parseFigmaClipboard } from '@open-pencil/core/clipboard'
import { renderNodesToImage, initCanvasKit } from '@open-pencil/core/io'
import { computeAllLayouts } from '@open-pencil/core/layout'
import { SceneGraph } from '@open-pencil/core/scene-graph'
import { fontManager } from '@open-pencil/core/text'
import { SceneGraph } from '@open-pencil/scene-graph'
const { values: opts } = parseArgs({
options: {