diff --git a/bun.lock b/bun.lock index accfd2386..3a7e47b51 100644 --- a/bun.lock +++ b/bun.lock @@ -165,6 +165,7 @@ "tailwindcss": "^4.2.1", }, "devDependencies": { + "@types/bun": "^1.3.14", "tsdown": "^0.21.7", "typescript": "~5.8.3", }, @@ -2951,6 +2952,8 @@ "@multiformats/dns/@libp2p/interface": ["@libp2p/interface@3.1.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^13.0.1", "main-event": "^1.0.1", "multiformats": "^13.4.0", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-RE7/XyvC47fQBe1cHxhMvepYKa5bFCUyFrrpj8PuM0E7JtzxU7F+Du5j4VXbg2yLDcToe0+j8mB7jvwE2AThYw=="], + "@open-pencil/dom-css/@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="], + "@open-pencil/mcp/@types/node": ["@types/node@22.19.15", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg=="], "@rollup/plugin-node-resolve/@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], @@ -3167,6 +3170,8 @@ "@multiformats/dns/@libp2p/interface/@multiformats/multiaddr": ["@multiformats/multiaddr@13.0.1", "", { "dependencies": { "@chainsafe/is-ip": "^2.0.1", "multiformats": "^13.0.0", "uint8-varint": "^2.0.1", "uint8arrays": "^5.0.0" } }, "sha512-XToN915cnfr6Lr9EdGWakGJbPT0ghpg/850HvdC+zFX8XvpLZElwa8synCiwa8TuvKNnny6m8j8NVBNCxhIO3g=="], + "@open-pencil/dom-css/@types/bun/bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], + "@open-pencil/mcp/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], "@vue-macros/common/ast-kit/@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="], diff --git a/package.json b/package.json index ce25eb300..137c634d7 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,8 @@ "preview": "vite preview", "tauri": "tauri", "lint": "bun run lint:structure && oxlint -c oxlint.json --type-aware --type-check src/ packages/core/src/ packages/vue/src/ packages/cli/src/ packages/mcp/src/ packages/dom-css/src/", - "lint:structure": "oxlint -c oxlint.json vite.config.ts vite/ src/ packages/core/src/ packages/vue/src/ packages/cli/src/ packages/mcp/src/ packages/dom-css/src/ packages/dom-css/tests/ tests/ scripts/ tools/", - "format": "oxfmt --write .oxfmtrc.json vite.config.ts vite/ src/ packages/core/src/ packages/cli/src/ packages/mcp/src/ packages/vue/src/ packages/dom-css/src/ packages/dom-css/tests/ tests scripts/ tools/", + "lint:structure": "oxlint -c oxlint.json vite.config.ts vite/ src/ packages/core/src/ packages/vue/src/ packages/cli/src/ packages/mcp/src/ packages/dom-css/src/ packages/dom-css/tests/ packages/dom-css/scripts/ tests/ scripts/ tools/", + "format": "oxfmt --write .oxfmtrc.json vite.config.ts vite/ src/ packages/core/src/ packages/cli/src/ packages/mcp/src/ packages/vue/src/ packages/dom-css/src/ packages/dom-css/tests/ packages/dom-css/scripts/ tests scripts/ tools/", "format:check": "bun run format && status=$(git status --porcelain -uall) && test -z \"$status\" || (echo \"$status\" && exit 1)", "check": "bun run build:packages && bun run lint && tsgo --noEmit && bun run check:vue && bun run check:i18n && bun run check:packages && bun run check:arch && bun run test:type-shapes && bun run test:tools && bun run test:dupes", "check:i18n": "bun tools/i18n/src/check-locales.ts", diff --git a/packages/dom-css/README.md b/packages/dom-css/README.md index f341c2573..379f784b4 100644 --- a/packages/dom-css/README.md +++ b/packages/dom-css/README.md @@ -4,15 +4,33 @@ DOM and CSS projection utilities for OpenPencil. This package is the compatibility layer between OpenPencil's scene graph and DOM-shaped design documents. It is intentionally separate from `@open-pencil/core` so browser/CSS parser integrations can evolve without adding DOM dependencies to the renderer and editor core. -## Testing +## Installation -This package has a package-local test suite so it can be validated independently from the app shell: +```sh +bun add @open-pencil/dom-css @open-pencil/core +``` + +`@open-pencil/core` is a peer dependency because `@open-pencil/dom-css` projects to and from OpenPencil scene graphs. Consumers that only parse/serialize DesignDOM still need the peer installed for the package entrypoint. + +## Package-local checks + +This package can be validated independently from the app shell: ```sh cd packages/dom-css bun run test +bun run typecheck +bun run check ``` +Package scripts: + +- `bun run test` — package-local Bun tests for runtime, conversion, and Tailwind APIs +- `bun run typecheck` — type-checks `src`, tests, and package scripts +- `bun run build` — builds the distributable `dist` entrypoint +- `bun run smoke:dist` — imports the built `dist` bundle and exercises the public API +- `bun run check` — runs typecheck, tests, build, and dist smoke in sequence + The repository also keeps integration/oracle coverage under `tests/engine/dom-css` and `tests/e2e/dom-css`. The package-local suite focuses on the library's public API, while the repo-level E2E suite verifies browser `getComputedStyle()` parity through Playwright. ## Runtime model diff --git a/packages/dom-css/package.json b/packages/dom-css/package.json index 5768dedf5..3d2fbc156 100644 --- a/packages/dom-css/package.json +++ b/packages/dom-css/package.json @@ -27,8 +27,11 @@ ], "scripts": { "build": "bunx tsdown --config tsdown.config.ts", + "check": "bun run typecheck && bun run test && bun run build && bun run smoke:dist", "prepack": "bun run build", - "test": "bun test tests" + "smoke:dist": "bun scripts/smoke-dist.ts", + "test": "bun test tests", + "typecheck": "bunx tsc --noEmit -p tsconfig.test.json" }, "repository": { "type": "git", @@ -43,6 +46,7 @@ "@open-pencil/core": "workspace:*" }, "devDependencies": { + "@types/bun": "^1.3.14", "tsdown": "^0.21.7", "typescript": "~5.8.3" }, diff --git a/packages/dom-css/scripts/smoke-dist.ts b/packages/dom-css/scripts/smoke-dist.ts new file mode 100644 index 000000000..efc892058 --- /dev/null +++ b/packages/dom-css/scripts/smoke-dist.ts @@ -0,0 +1,39 @@ +import { + compileTailwindCSS, + createHeadlessCSSRuntime, + htmlToSceneGraph, + serializeHTML, + type DesignDocument +} from '../dist/index.js' + +const document: DesignDocument = { + type: 'document', + children: [ + { + type: 'element', + tagName: 'article', + attrs: { class: 'card' }, + children: [{ type: 'text', text: 'OpenPencil' }] + } + ] +} + +const html = serializeHTML(document) +if (!html.includes('OpenPencil')) { + throw new Error('Expected built serializeHTML() to emit document text') +} + +const css = await compileTailwindCSS(['flex', 'w-80']) +if (!css.includes('.w-80')) { + throw new Error('Expected built compileTailwindCSS() to emit Tailwind utility CSS') +} + +const graph = await htmlToSceneGraph('
OpenPencil
', { + cssText: '.card { display: flex; width: 320px; }', + runtime: createHeadlessCSSRuntime() +}) +const page = graph.getPages()[0] +const card = page ? graph.getChildren(page.id)[0] : undefined +if (card?.type !== 'FRAME' || card.width !== 320) { + throw new Error('Expected built htmlToSceneGraph() to produce a sized frame') +} diff --git a/packages/dom-css/tsconfig.json b/packages/dom-css/tsconfig.json index 2be6a3b13..1d2b189ea 100644 --- a/packages/dom-css/tsconfig.json +++ b/packages/dom-css/tsconfig.json @@ -12,11 +12,9 @@ "skipLibCheck": true, "esModuleInterop": true, "resolveJsonModule": true, + "types": ["bun"], "paths": { - "#dom-css/*": ["./src/*"], - "#core/*": ["../core/src/*"], - "@open-pencil/core": ["../core/src/index.ts"], - "@open-pencil/core/*": ["../core/src/*"] + "#dom-css/*": ["./src/*"] } }, "include": ["src/**/*.ts", "src/**/*.d.ts"], diff --git a/packages/dom-css/tsconfig.test.json b/packages/dom-css/tsconfig.test.json new file mode 100644 index 000000000..5c81eab53 --- /dev/null +++ b/packages/dom-css/tsconfig.test.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": true + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "tests/**/*.ts", "scripts/**/*.ts"], + "exclude": ["node_modules", "dist"] +}