Files
orca/config/scripts/undeclared-dependency-resolution.test.ts
T
Neil 51530bb86c build: declare dependencies that only hoisting supplied (#30225)
* build: declare dependencies that only hoisting supplied

Under pnpm's global virtual store each package sees only its declared
dependencies. Several published packages relied on hoisting:

- jest-dom's vitest matcher augmentation could not find vitest (1645
  TS2339 errors in tc:web), and react libraries' .d.ts could not find
  @types/react, so lucide-react, dnd-kit, cmdk, sonner and others typed
  as `any`. Other .d.ts phantoms (electron, vfile, prosemirror-model,
  d3-selection, type-fest) degraded silently the same way.
- electron-vite resolves electron/package.json and the binary itself.

packageExtensions declares these, which also holds in the hoisted
layout. The markdown alias now resolves decode-named-character-reference
through mdast-util-from-markdown, the package that actually declares it.

* build: let addMissingPeerTypes supply @types/react to react peers

pnpm 12.12 links a peer's @types package next to every package that
peer-depends on it, which replaces the hand-listed @types/react peers.
The regression test now reads pnpm-workspace.yaml, so it checks every
packageExtensions entry instead of a hand-picked seven.
2026-10-18 19:54:51 -07:00

74 lines
2.7 KiB
TypeScript

import { existsSync, readFileSync, realpathSync } from 'node:fs'
import { createRequire } from 'node:module'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'
import { parse } from 'yaml'
import { z } from 'zod'
import { markdownParserAliases } from '../build-plugins/markdown-parser-exports'
const repoRoot = join(import.meta.dirname, '../..')
const repoNodeModules = join(repoRoot, 'node_modules')
const dependencyMap = z.record(z.string(), z.string()).optional()
const workspace = z
.object({
packageExtensions: z
.record(
z.string(),
z.object({ dependencies: dependencyMap, peerDependencies: dependencyMap })
)
.optional(),
addMissingPeerTypes: z.boolean().optional()
})
.parse(parse(readFileSync(join(repoRoot, 'pnpm-workspace.yaml'), 'utf8')))
// Every dependency pnpm-workspace.yaml adds, so a new entry is covered without editing this file.
const extensionPairs = Object.entries(workspace.packageExtensions ?? {}).flatMap(
([owner, extension]) =>
[
...Object.keys(extension.dependencies ?? {}),
...Object.keys(extension.peerDependencies ?? {})
].map((dependency) => [owner, dependency] as const)
)
// These peer on react and ship .d.ts that import it; addMissingPeerTypes supplies @types/react.
const peerTypePairs = [
'@dnd-kit/core',
'@dnd-kit/sortable',
'@dnd-kit/utilities',
'@monaco-editor/react',
'cmdk',
'emoji-picker-react',
'lucide-react',
'react-colorful',
'react-i18next',
'sonner'
].map((owner) => [owner, '@types/react'] as const)
// Node's own lookup from the package's real location, without tripping over "exports" maps.
function isVisibleFrom(owner: string, dependency: string): boolean {
const ownerDir = realpathSync(join(repoNodeModules, owner))
const lookupDirs = createRequire(join(ownerDir, 'package.json')).resolve.paths(dependency) ?? []
return lookupDirs.some((dir) => existsSync(join(dir, dependency, 'package.json')))
}
describe('undeclared dependency resolution', () => {
it('covers every packageExtensions entry', () => {
const owners = new Set(extensionPairs.map(([owner]) => owner))
expect([...owners].sort()).toEqual(Object.keys(workspace.packageExtensions ?? {}).sort())
expect(workspace.addMissingPeerTypes).toBe(true)
})
// Why: the global virtual store links only declared deps; pnpm-workspace.yaml supplies these.
it.each([...extensionPairs, ...peerTypePairs])(
'%s sees %s from its own install location',
(owner, dependency) => {
expect(isVisibleFrom(owner, dependency)).toBe(true)
}
)
it('aliases the DOM-free decode-named-character-reference entry', () => {
expect(markdownParserAliases['decode-named-character-reference']).toMatch(/[\\/]index\.js$/)
})
})