* chore: prefer es-toolkit helpers and lint the mechanical cases
AGENTS.md now names the es-toolkit helpers to reach for instead of hand-written equivalents, and the exceptions: a single clear native call or a measured hot path. The new open-pencil/prefer-es-toolkit rule rejects filter(Boolean) and Set round trips on arrays, the two cases that need no type information, and the existing 45 sites use compact and uniq. tools/ci/policy runs before dependencies are installed, so the rule is off there.
* refactor: deduplicate diagnostic categories with uniq
* fix: keep es-toolkit out of serialized Playwright callbacks
The codemod rewrote a filter(Boolean) inside a page.evaluate callback, which Playwright runs in the page where the compact import does not exist. The spec filters there again, and the rule now skips callbacks passed to evaluate, $eval, $$eval, evaluateHandle, addInitScript and waitForFunction, and filter calls on iterators from values, keys, entries and matchAll, which compact cannot take.
* test: write the prefer-es-toolkit cases like the other rule tests
Short standalone snippets, as in the base64 and JSON rule tests, instead of a declaration prefix on every case and inline object types.
* feat(demo): rebuild the first page as a component library with staged loading
The demo generated its document behind an empty canvas with no progress,
and the first page still carried a legacy library in a dark section that
matched neither the current showcase nor the rest of the demo.
Drive the existing editor preparation from demo generation so the canvas
overlay and tab indicator report the real phases and progress, and rebuild
the first page around a component library authored in the current style:
a Button component set with two variants, linked instances, text and
boolean component properties, and the variable collections. The deleted
effects, typography, and app-preview examples are already covered by pages
02 and 03.
* fix(demo): record demo generation failures as preparation failures
Demo generation reported a thrown error as a cancellation, because the catch
only warned and the trailing finally always cancelled the handle. Report the
failure through the preparation handle so diagnostics distinguish a broken
demo build from an abandoned one.
The finally needs no failure guard: failing clears the handle, so the
following cancel already returns early, as the preparation controller test
asserts.
* fix(demo): roll back an abandoned demo build
A preparation that superseded the demo's handle — a page switch, a font
retry, or a closed tab — left the document half-built: the first page stayed
renamed, the extra pages and sections remained, and the one-page precondition
then blocked any later attempt in that session.
Track what the build creates and remove it whenever the build does not
finish, restoring the original page name and clearing the variables it added.
The cleanup is guarded by graph identity because node and page IDs are only
unique within one graph, so a document that replaced the demo is never touched.
Splitting the build into its own function keeps the entry point to
orchestration and stays within the complexity budget.
- useEditorSetup() / useEditorSetupWithClear() in tests/e2e/fixtures.ts
- Migrated 17 specs to shared fixture, removing ~300 lines of boilerplate
- Moved getSelectedNode/getSelectedNodes to shared store helpers
- Replaced inline getSelectedNode in 4 specs with shared import
- Test duplication: 329 → 308 clones (10.12% → 9.08%)
- Expose window.openPencil.getStore() instead of a direct store property
- Update E2E helpers and specs to use the bridge getter
- Add lint coverage preventing direct window.openPencil.store access
- Route browser globals through src/app/window-api.ts instead of private __OPEN_PENCIL fields
- Move E2E tests to the public window.openPencil test API
- Add an oxlint rule banning direct window.__OPEN_PENCIL* access
- Replace low-count E2E non-null assertions with store guards and optional expectations
- Use expectDefined for tool adapter and XPath node lookups
- Validate affected engine and E2E tests
- Remove stale imports and unused locals from split engine and e2e tests
- Drop the targeted no-unused-vars test allowances
- Keep check and affected test suites warning-free
- Configure oxfmt custom import groups for workspace, app, package, and test aliases
- Keep type imports grouped with their matching source category instead of one global tail group
- Expand the format script to cover formatter config, Vite files, and scripts
- Move top-level engine and e2e prefixed test files under domain folders
- Update fixture path helpers after moving render and pen tests
- Add lint coverage to prevent new top-level prefixed test files
- Refresh testing docs for the new fig and layout paths