From ad65ec4761c8bc214923526cc0fcf404fdeaf799 Mon Sep 17 00:00:00 2001 From: Caio Pizzol <97641911+caio-pizzol@users.noreply.github.com> Date: Wed, 18 Mar 2026 12:52:44 -0300 Subject: [PATCH] =?UTF-8?q?Revert=20"fix(types):=20fix=20broken=20.d.ts=20?= =?UTF-8?q?imports=20in=20published=20superdoc=20package=20(S=E2=80=A6"=20?= =?UTF-8?q?(#2443)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 77807e5cce8763267ba9ed28f21a9fd92949c16b. --- .github/workflows/ci-superdoc.yml | 3 - packages/super-editor/src/index.d.ts | 8 +- packages/superdoc/scripts/ensure-types.cjs | 287 ------------------ packages/superdoc/tests/consumer-types/run.sh | 38 --- .../superdoc/tests/consumer-types/test.ts | 23 -- .../tests/consumer-types/tsconfig.json | 12 - 6 files changed, 3 insertions(+), 368 deletions(-) delete mode 100755 packages/superdoc/tests/consumer-types/run.sh delete mode 100644 packages/superdoc/tests/consumer-types/test.ts delete mode 100644 packages/superdoc/tests/consumer-types/tsconfig.json diff --git a/.github/workflows/ci-superdoc.yml b/.github/workflows/ci-superdoc.yml index 8aae48586a..70a317319d 100644 --- a/.github/workflows/ci-superdoc.yml +++ b/.github/workflows/ci-superdoc.yml @@ -77,9 +77,6 @@ jobs: - name: Run slow tests run: pnpm test:slow - - name: Consumer typecheck (skipLibCheck off) - run: bash packages/superdoc/tests/consumer-types/run.sh - - name: Install Playwright for UMD smoke test run: pnpm --filter @superdoc/umd-smoke-test exec playwright install --with-deps chromium diff --git a/packages/super-editor/src/index.d.ts b/packages/super-editor/src/index.d.ts index 273822b4cf..41a294ce88 100644 --- a/packages/super-editor/src/index.d.ts +++ b/packages/super-editor/src/index.d.ts @@ -3,11 +3,9 @@ * This file provides TypeScript types for the JavaScript exports in index.js */ -// Re-export prosemirror types for consumers AND import for local use -import type { EditorView } from 'prosemirror-view'; -import type { EditorState, Transaction } from 'prosemirror-state'; -import type { Schema } from 'prosemirror-model'; -export type { EditorView, EditorState, Transaction, Schema }; +export type { EditorView } from 'prosemirror-view'; +export type { EditorState, Transaction } from 'prosemirror-state'; +export type { Schema } from 'prosemirror-model'; // ============================================ // COMMAND TYPES (inlined from ChainedCommands.ts) diff --git a/packages/superdoc/scripts/ensure-types.cjs b/packages/superdoc/scripts/ensure-types.cjs index a3f4a7f236..aa6a6e253e 100644 --- a/packages/superdoc/scripts/ensure-types.cjs +++ b/packages/superdoc/scripts/ensure-types.cjs @@ -58,291 +58,4 @@ if (hadWorkspaceImport) { console.log('[ensure-types] ✓ Inlined @superdoc/common types'); } -// --------------------------------------------------------------------------- -// Fix pnpm node_modules paths in ALL .d.ts files (SD-2227) -// -// vite-plugin-dts resolves bare specifiers like 'prosemirror-view' to physical -// pnpm paths like '../../node_modules/.pnpm/prosemirror-view@1.41.5/node_modules/prosemirror-view/dist/index.js'. -// Consumers don't have these paths — rewrite them back to bare specifiers. -// --------------------------------------------------------------------------- - -/** - * Recursively find all .d.ts files under a directory. - */ -function findDtsFiles(dir) { - const results = []; - for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { - const fullPath = path.join(dir, entry.name); - if (entry.isDirectory()) { - results.push(...findDtsFiles(fullPath)); - } else if (entry.name.endsWith('.d.ts')) { - results.push(fullPath); - } - } - return results; -} - -// Match pnpm node_modules paths in both `from '...'` and `import('...')` contexts. -// Captures the bare package name from the pnpm structure: -// .../node_modules/.pnpm/@/node_modules//dist/index.js -// ^^^^^ capture this -const PNPM_PATH_RE = /(['"])([^'"]*\/node_modules\/\.pnpm\/[^/]+\/node_modules\/(@[^/]+\/[^/]+|[^/]+)\/dist\/index\.js)\1/g; - -// Match broken absolute-looking paths like 'packages/superdoc/src/types.js' -// that vite-plugin-dts sometimes emits from path alias resolution. -const BAD_ABSOLUTE_PATH_RE = /(['"])packages\/superdoc\/src\/([^'"]+)\1/g; - -// vite-plugin-dts incorrectly resolves subpath exports (e.g. @superdoc/super-editor/types) -// by appending the subpath to the main entry: '../../super-editor/src/index.js/types' -// Fix: rewrite index.js/.js -const BAD_SUBPATH_RE = /(['"])([^'"]*\/index\.js)(\/[^'"]+)\1/g; - -let fixedFiles = 0; -let totalReplacements = 0; - -const dtsFiles = findDtsFiles(distRoot); -for (const filePath of dtsFiles) { - let fileContent = fs.readFileSync(filePath, 'utf8'); - let changed = false; - - // Fix pnpm node_modules paths → bare specifiers - fileContent = fileContent.replace(PNPM_PATH_RE, (match, quote, _fullPath, packageName) => { - changed = true; - totalReplacements++; - return `${quote}${packageName}${quote}`; - }); - - // Fix broken absolute-looking paths → relative paths - const relDir = path.relative(path.dirname(filePath), path.join(distRoot, 'superdoc/src')); - fileContent = fileContent.replace(BAD_ABSOLUTE_PATH_RE, (match, quote, rest) => { - changed = true; - totalReplacements++; - let relativePath = path.posix.join( - relDir.split(path.sep).join('/'), - rest, - ); - // Ensure relative paths start with ./ (bare names are treated as package specifiers) - if (!relativePath.startsWith('.') && !relativePath.startsWith('/')) { - relativePath = './' + relativePath; - } - return `${quote}${relativePath}${quote}`; - }); - - // Fix broken subpath exports (index.js/types → types.js) - fileContent = fileContent.replace(BAD_SUBPATH_RE, (match, quote, basePath, subpath) => { - changed = true; - totalReplacements++; - // Replace 'foo/index.js/types' with 'foo/types.js' - const dir = basePath.replace(/\/index\.js$/, ''); - return `${quote}${dir}${subpath}.js${quote}`; - }); - - - if (changed) { - fs.writeFileSync(filePath, fileContent); - fixedFiles++; - } -} - -if (fixedFiles > 0) { - console.log(`[ensure-types] ✓ Fixed ${totalReplacements} import paths in ${fixedFiles} .d.ts files`); -} - -// --------------------------------------------------------------------------- -// Generate ambient module declarations for private workspace packages (SD-2227) -// -// Internal .d.ts files reference @superdoc/* workspace packages that consumers -// can't install. Generate a shim so TypeScript can resolve these imports. -// Also shim prosemirror peer deps that are bundled (not in consumer node_modules). -// --------------------------------------------------------------------------- - -// Collect @superdoc/* workspace module specifiers and their named imports from -// all .d.ts files. These are private packages consumers can't install — we -// generate ambient `declare module` shims for them. External packages -// (prosemirror, vue, yjs, etc.) are handled by the hand-written shims below. -const workspaceImports = new Map(); // module → Set - -for (const filePath of dtsFiles) { - const fileContent = fs.readFileSync(filePath, 'utf8'); - - // Match: import { Foo, Bar } from '...' and import type { Foo } from '...' - const namedImports = fileContent.matchAll(/import\s+(?:type\s+)?\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g); - for (const m of namedImports) { - const mod = m[2]; - - // Skip relative imports and already-handled packages - if (mod.startsWith('.') || mod.startsWith('@superdoc/common') || mod.startsWith('@superdoc/super-editor')) continue; - - if (mod.startsWith('@superdoc/')) { - if (!workspaceImports.has(mod)) workspaceImports.set(mod, new Set()); - const names = m[1].split(',').map(n => n.trim().split(/\s+as\s+/)[0].trim()).filter(Boolean); - for (const name of names) workspaceImports.get(mod).add(name); - } - } - - // Match: import('...').SomeName — dynamic import type references - const dynamicImports = fileContent.matchAll(/import\(['"]([^'"]+)['"]\)\.(\w+)/g); - for (const m of dynamicImports) { - const mod = m[1]; - if (mod.startsWith('.') || mod.startsWith('@superdoc/common') || mod.startsWith('@superdoc/super-editor')) continue; - - if (mod.startsWith('@superdoc/')) { - if (!workspaceImports.has(mod)) workspaceImports.set(mod, new Set()); - workspaceImports.get(mod).add(m[2]); - } - } - - // Match bare @superdoc/* module references - const bareRefs = fileContent.matchAll(/['"](@superdoc\/[^'"]+)['"]/g); - for (const m of bareRefs) { - const mod = m[1]; - if (mod.startsWith('@superdoc/common') || mod.startsWith('@superdoc/super-editor')) continue; - if (!workspaceImports.has(mod)) workspaceImports.set(mod, new Set()); - } -} - -// --------------------------------------------------------------------------- -// Write _internal-shims.d.ts -// -// Two sections: -// 1. Hand-written shims for external packages (prosemirror-*, vue, yjs, -// eventemitter3, @hocuspocus/provider). See KNOWN LIMITATION note in the -// generated file about ambient shims overriding real package types. -// 2. Auto-generated shims for @superdoc/* workspace packages. -// --------------------------------------------------------------------------- - -const shimLines = [ - '// Auto-generated ambient declarations for internal/bundled packages.', - '// These packages are bundled into superdoc or are internal workspace packages.', - '// Consumers do not need to install them. This file prevents TypeScript errors', - '// when skipLibCheck is false.', - '//', - '// KNOWN LIMITATION: ambient `declare module` with `export type X = any`', - '// overrides real package types when both are present. This affects:', - '// - vue, eventemitter3: direct deps of superdoc — ALWAYS in consumer', - '// node_modules, so real types are always replaced by `any`.', - '// - yjs, @hocuspocus/provider: peer deps — affected when installed.', - '// - prosemirror-*: bundled (not in consumer node_modules) — no conflict.', - '// The proper fix is adding prosemirror-* as peerDependencies and removing', - '// shims for packages consumers already have installed.', - '//', - '// NOTE: This is a script file (no exports), so `declare module` creates', - '// global ambient declarations and top-level declarations are global.', - '', - '// --- Well-known external packages (hand-written for correctness) ---', - '', - "declare module 'prosemirror-model' {", - ' export type DOMOutputSpec = any;', - ' export type Fragment = any;', - ' export type Mark = any;', - ' export type MarkType = any;', - ' export type Node = any;', - ' export type NodeType = any;', - ' export type ParseRule = any;', - ' export type ResolvedPos = any;', - ' export type Schema = any;', - ' export type Slice = any;', - '}', - '', - "declare module 'prosemirror-state' {", - ' export type EditorState = any;', - ' export type Plugin = any;', - ' export type PluginKey = any;', - ' export type TextSelection = any;', - ' export type Transaction = any;', - '}', - '', - "declare module 'prosemirror-transform' {", - ' export type Mapping = any;', - ' export type ReplaceAroundStep = any;', - ' export type ReplaceStep = any;', - ' export type Step = any;', - '}', - '', - "declare module 'prosemirror-view' {", - ' export type Decoration = any;', - ' export type DecorationSet = any;', - ' export type DecorationSource = any;', - ' export type EditorProps = any;', - ' export type EditorView = any;', - ' export type NodeView = any;', - '}', - '', - "declare module 'eventemitter3' {", - ' export class EventEmitter {', - ' on(event: EventTypes, fn: (...args: any[]) => void, context?: Context): this;', - ' off(event: EventTypes, fn: (...args: any[]) => void, context?: Context): this;', - ' emit(event: EventTypes, ...args: any[]): boolean;', - ' removeAllListeners(event?: EventTypes): this;', - ' }', - ' export default EventEmitter;', - '}', - '', - "declare module 'vue' {", - ' export type App = any;', - ' export type ComponentOptionsBase

= any;', - ' export type ComponentOptionsMixin = any;', - ' export type ComponentProvideOptions = any;', - ' export type ComponentPublicInstance

= any;', - ' export type ComputedRef = any;', - ' export type CreateComponentPublicInstanceWithMixins = any;', - ' export type DefineComponent

= any;', - ' export type ExtractPropTypes = any;', - ' export type GlobalComponents = any;', - ' export type GlobalDirectives = any;', - ' export type PublicProps = any;', - ' export type Ref = any;', - ' export type RendererElement = any;', - ' export type RendererNode = any;', - ' export type ShallowRef = any;', - ' export type VNode = any;', - '}', - '', - "declare module 'yjs' {", - ' export type Doc = any;', - ' export type XmlFragment = any;', - ' export type RelativePosition = any;', - '}', - '', - "declare module '@hocuspocus/provider' {", - ' export type HocuspocusProvider = any;', - '}', - '', -]; - -// --- Auto-generated @superdoc/* workspace package shims --- - -let wsCount = 0; -if (workspaceImports.size > 0) { - shimLines.push('// --- Internal workspace packages (auto-generated) ---'); - shimLines.push(''); - for (const [mod, names] of [...workspaceImports.entries()].sort((a, b) => a[0].localeCompare(b[0]))) { - wsCount++; - const sortedNames = [...names].sort(); - const exportLines = sortedNames - .map(n => ` export type ${n} = any;`); - if (exportLines.length > 0) { - shimLines.push(`declare module '${mod}' {\n${exportLines.join('\n')}\n}`); - } else { - shimLines.push(`declare module '${mod}' { const _: any; export default _; }`); - } - } -} -shimLines.push(''); - -const shimPath = path.join(distRoot, '_internal-shims.d.ts'); -fs.writeFileSync(shimPath, shimLines.join('\n')); - -// Add reference directive to entry points so TypeScript includes the shims -const shimRef = '/// \n'; -for (const entry of requiredEntryPoints) { - const entryPath = path.join(distRoot, entry); - const entryContent = fs.readFileSync(entryPath, 'utf8'); - if (!entryContent.includes('_internal-shims.d.ts')) { - fs.writeFileSync(entryPath, shimRef + entryContent); - } -} - -console.log(`[ensure-types] ✓ Generated ambient shims for ${wsCount} workspace + 8 external modules`); - console.log('[ensure-types] ✓ Verified type entry points'); diff --git a/packages/superdoc/tests/consumer-types/run.sh b/packages/superdoc/tests/consumer-types/run.sh deleted file mode 100755 index 05c3eda4f4..0000000000 --- a/packages/superdoc/tests/consumer-types/run.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -# Consumer typecheck integration test (SD-2227). -# -# Packs the built superdoc package into a tarball and type-checks a minimal -# consumer project with skipLibCheck: false. This catches broken .d.ts imports -# (pnpm paths, workspace refs, missing ambient types) that internal type-check -# doesn't detect because it runs inside the monorepo. -# -# Prerequisites: `pnpm run build` must have run first (dist/ must exist). - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -PKG_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" -WORK_DIR="$(mktemp -d)" - -cleanup() { rm -rf "$WORK_DIR"; } -trap cleanup EXIT - -echo "==> Packing superdoc..." -TARBALL=$(cd "$PKG_DIR" && npm pack --pack-destination "$WORK_DIR" --quiet) - -echo "==> Setting up consumer project..." -cp "$SCRIPT_DIR/test.ts" "$WORK_DIR/test.ts" -cp "$SCRIPT_DIR/tsconfig.json" "$WORK_DIR/tsconfig.json" - -# Install typescript and @types/node first -npm install --prefix "$WORK_DIR" typescript @types/node --save-dev --silent - -# Extract superdoc AFTER npm install (so npm doesn't wipe it) -mkdir -p "$WORK_DIR/node_modules/superdoc" -tar xzf "$WORK_DIR/$TARBALL" -C "$WORK_DIR/node_modules/superdoc" --strip-components=1 - -echo "==> Running tsc --noEmit (skipLibCheck: false)..." -cd "$WORK_DIR" -npx tsc --noEmit - -echo "==> Consumer typecheck passed (0 errors)" diff --git a/packages/superdoc/tests/consumer-types/test.ts b/packages/superdoc/tests/consumer-types/test.ts deleted file mode 100644 index bbf568afda..0000000000 --- a/packages/superdoc/tests/consumer-types/test.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Consumer typecheck smoke test (SD-2227). - * - * This file is compiled with `tsc --noEmit` against the packed superdoc - * tarball to verify that published .d.ts files are valid for consumers - * with skipLibCheck: false. - * - * It is NOT executed at runtime — only type-checked. - */ - -// Main entry point -import type { SuperDoc } from 'superdoc'; - -// Super-editor entry point -import type { EditorView, EditorState, Transaction, Schema } from 'superdoc/super-editor'; - -// Types entry point -import type { ProseMirrorJSON, NodeConfig, MarkConfig } from 'superdoc/types'; - -// Verify the types are usable (not just importable) -type _AssertSuperDoc = SuperDoc extends object ? true : never; -type _AssertEditorView = EditorView extends object ? true : never; -type _AssertJSON = ProseMirrorJSON extends object ? true : never; diff --git a/packages/superdoc/tests/consumer-types/tsconfig.json b/packages/superdoc/tests/consumer-types/tsconfig.json deleted file mode 100644 index a1226b08eb..0000000000 --- a/packages/superdoc/tests/consumer-types/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "strict": true, - "noEmit": true, - "skipLibCheck": false, - "moduleResolution": "bundler", - "module": "ESNext", - "target": "ES2020", - "types": ["node"] - }, - "include": ["test.ts"] -}