You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(superdoc): make Document API and layout contract types resolvable for consumers (SD-2842) (#3022)
* fix(superdoc): make Document API and layout contract types resolvable for consumers (SD-2842)
Three changes that, together, eliminate the remaining type-collapse class:
1. Add the Document API surface that customers reach for to the public re-export list. DocumentApi, BlocksListResult and BookmarkInfo are re-exported from super-editor; superdoc's JSDoc typedef block adds the matching entries so `import type { DocumentApi } from 'superdoc'` resolves to the real interface. Previously these names triggered TS2305 from a strict-mode consumer because they were not on the flat re-export list, even though `editor.doc: DocumentApi` worked through the existing relocation pipeline.
2. Copy hand-written `.d.ts` files from super-editor source into dist before the rewrite passes run. The dts plugin only generates declarations from `.ts`/`.js` and silently skips standalone `.d.ts` files, so paths like `core/commands/core-command-map.d.ts` (used by the command-map type augmentation) were missing in dist. That broke the EditorCommands and CanObject types, which compiled against a missing module reference and fell through to any.
3. Extend the SD-2815 relocation pattern to @superdoc/contracts. Layout, LayoutPage, FlowBlock and friends now emit into superdoc's published dist, the bare specifier in emitted declarations rewrites to a relative path the consumer can resolve, and the package no longer appears in the internal shim file. Same pattern as document-api: tsconfig include, vite-plugin-dts include, ensure-types rewrite plus shim-skip list.
Verified via a fresh strict-mode consumer (skipLibCheck:false, strict:true) importing 18 representative public types and asserting via @ts-expect-error that none collapse to any. Before: 3 missing exports, 5 collapses. After: zero of either. Positive test confirms `editor.doc.blocks.list()` returns a real BlocksListResult and FlowBlock is a real union with discriminant.
* fix(superdoc): relocate layout/painter types and add full public-surface typecheck (SD-2842)
Generalizes the relocation pattern introduced for `@superdoc/document-api` and `@superdoc/contracts` so it scales: a small `RELOCATION_RULES` table in the postbuild script drives both the rewrite logic and the shim-skip predicate. Adds two more entries that close the remaining type leaks on the public surface: `@superdoc/layout-bridge` (PositionHit) and `@superdoc/painter-dom` (PaintSnapshot, LayoutMode). Their declarations now emit into `dist/layout-engine/...`, the bare specifiers in published `.d.ts` rewrite to local relative paths, and the internal shim file no longer carries blocks for these packages.
Adds a permanent `tests/consumer-typecheck/src/all-public-types.ts` test that exercises every public type mined from `superdoc/src/index.js`'s `@typedef` block (105 types). Each type passes through an `AssertNotAny<T>` check that resolves to `never` when the type is `any`, so the assertion fails to compile if a regression collapses one of them. Two matrix scenarios (bundler + node16) wire it as `mustPass: true`. Together with the SD-2832 audit gate, this closes the loop: the audit catches private specifiers in declarations; this test catches when a private type is removed but the consumer-facing alias still resolves to `any`.
The new strict types surfaced six pre-existing bugs in template-builder where the previous `any`-typed editor.commands API silently allowed wrong arguments. Three call sites passed `id: string | number` to commands that take `string` (coerced via `String(id)`). Two call sites passed a `text` field to `insertStructuredContentBlock` that the runtime ignores (block insert uses `html`/`json`/selection content, not `text`). One call site passed a loosely-typed `presetContent.json` to a parameter that requires a real `ProseMirrorJSON` (cast at the boundary). All six were silent failures before; the strict types make them visible.
Verified with the full repo type-check, the consumer matrix (14 scenarios, all green), superdoc unit tests (931 tests, all pass), super-editor unit tests (12,064 tests, all pass), and downstream package builds (react type-check, template-builder build, both clean).
* test(consumer-typecheck): assert shim-leak regression net + add editor.doc smoke (SD-2842)
Two small additions strengthening the regression net around the type relocation work.
The postbuild script now asserts at the end of the run that no relocated package (currently `@superdoc/document-api`, `@superdoc/contracts`, `@superdoc/layout-bridge`, `@superdoc/painter-dom`) appears in `_internal-shims.d.ts`. If a future change breaks the include glob, the rewrite rule, or the shim-skip predicate for one of these packages, the build fails with a clear message pointing at where to look. Runs every time someone packs, so the regression cannot land silently.
Adds an end-to-end smoke test on the runtime entry point: `editor.doc` is typed `DocumentApi` (not any), `editor.doc.blocks.list()` returns a real `BlocksListResult`, calling a method that does not exist on the API is rejected at compile time, and passing the wrong shape to `doc.bookmarks.get(...)` fails type-checking. The flat all-public-types test catches type-level regressions; this catches getter-level regressions where a named export still resolves but the live API surface is typed loosely.
Matrix is now 15/15 required (was 14/14).
* test(consumer-typecheck): use selection-based track-changes variants in customer scenario (SD-2842)
The `customer-scenario.ts` test was calling `acceptTrackedChange()` and `rejectTrackedChange()` with no arguments. Both commands take a required `TrackedChangeOptions` payload at runtime (the runtime destructures `{ trackedChange }` from the first arg), so this was a silent crash waiting to happen, allowed only because the previous `EditorCommands` type was `any`. The new strict types catch it at compile time.
Switched to the `acceptTrackedChangeBySelection` / `rejectTrackedChangeOnSelection` variants, which need no arguments and are what consumer code typically reaches for in toolbar / context-menu flows.
* test(template-builder): drop assertion of no-op text fallback for block insert (SD-2842)
The previous test asserted that a `text: defaultValue` field was passed to `insertStructuredContentBlock`, but `StructuredContentBlockInsert` does not accept `text` and the runtime never used it. The block-insert API takes its content from `html`, `json`, or the current selection. The mock-based test had been passing because it only verified the call argument, not the visible result; a real customer using this code path saw an empty block regardless of `defaultValue`.
The strict types now reject the unknown property, so the call site no longer passes it. Updated the test to assert the new (and only honored) shape: no `text` field on a block-insert call without presetContent. The test name now describes what is actually checked.
Inline insertion is unaffected; `StructuredContentInlineInsert` does accept `text`.
console.error(`[ensure-types] ✗ ${pkg} appears in _internal-shims.d.ts. Its types should resolve via the relocation rewrite, not via an ambient any shim. Investigate the include glob, the rewrite rule, and the shim-skip predicate for this package.`);
430
+
process.exit(1);
431
+
}
432
+
}
433
+
console.log(`[ensure-types] ✓ Verified ${SHIM_FORBIDDEN.length} relocated packages do not appear in shim file`);
434
+
334
435
console.log('[ensure-types] ✓ Verified type entry points');
0 commit comments