diff --git a/docs/cookbook/adding-a-package.md b/docs/cookbook/adding-a-package.md index b52761baf1..991db3be60 100644 --- a/docs/cookbook/adding-a-package.md +++ b/docs/cookbook/adding-a-package.md @@ -15,7 +15,7 @@ packages// README.md # service API, events, extension points, design notes ``` -package.json invariants (enforced by `pnpm run constraints` / `scripts/check-workspace-constraints.ts`): `private: true`, `version: 0.0.1`, `type: module`, `main: "lib/index.js"`, `types: "lib/types/index.d.ts"`, `exports["."].types: "./lib/types/index.d.ts"`, `exports["."].default: "./lib/index.js"`, `cordis` in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. `schemastery` goes in `dependencies` (it is a runtime validator), matching agent-loop. The `files` list is precise: `lib/index.js`, `lib/types/**/*.d.ts`, `lib/types/**/*.d.ts.map`, and `src`; do not publish `lib/types` JS or JS-map intermediates or stale root declaration files. +package.json invariants (enforced by `pnpm run constraints` / `scripts/check-workspace-constraints.ts`): `private: true`, `version: 0.0.1`, `type: module`, `main: "lib/index.js"`, `types: "lib/types/index.d.ts"`, `exports["."].types: "./lib/types/index.d.ts"`, `exports["."].default: "./lib/index.js"`, `cordis` in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. `schemastery` goes in `dependencies` (it is a runtime validator), matching agent-loop. The `files` list is precise: `lib/index.js`, `lib/types/**/*.d.ts`, `lib/types/**/*.d.ts.map`, and `src`; do not publish `lib/types` JS or JS-map intermediates or stale root declaration files. CLI app packages with a package `bin` include `lib/bin.js` immediately after `lib/index.js` in `files`. ## 2. Register it in the root configs diff --git a/docs/rfc/README.md b/docs/rfc/README.md index 08a5dae8f6..f46cb3495f 100644 --- a/docs/rfc/README.md +++ b/docs/rfc/README.md @@ -125,7 +125,7 @@ Do NOT write one for a mechanical or local choice (a variable name, a one-file r | [tsdown for JS bundling instead of dumble](implemented/process/2026-06-11-tsdown-over-dumble.md) | 2026-06-11 | | [Doc-sync enforcement](implemented/process/2026-06-11-doc-sync-enforcement.md) | 2026-06-11 | | [pnpm as the package manager instead of Yarn 4](implemented/process/2026-06-16-pnpm-over-yarn.md) | 2026-06-16 | -| [TSC-first build and one tsconfig](implemented/2026-06-17-ts-build-config.md) | 2026-06-17 | +| [TSC-first build and one tsconfig](implemented/process/2026-06-17-ts-build-config.md) | 2026-06-17 | | [Markdown cross-link validity linting](implemented/process/2026-06-18-markdown-cross-link-lint.md) | 2026-06-18 | | [Core-data-structures catalog and the `ts type-equiv` drift gate](implemented/process/2026-06-20-core-data-structures-catalog.md) | 2026-06-20 | | [Generated cordis events + services catalog](implemented/process/2026-06-20-generated-cordis-catalog.md) | 2026-06-20 | diff --git a/docs/rfc/implemented/2026-06-17-ts-build-config.md b/docs/rfc/implemented/process/2026-06-17-ts-build-config.md similarity index 100% rename from docs/rfc/implemented/2026-06-17-ts-build-config.md rename to docs/rfc/implemented/process/2026-06-17-ts-build-config.md diff --git a/eslint.config.mjs b/eslint.config.mjs index df7570c89e..52236e5d64 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -36,7 +36,7 @@ export default tseslint.config( ], languageOptions: { parserOptions: { - project: ['./packages/*/tsconfig.json', './tsconfig.json'], + project: ['./packages/*/*/tsconfig.json', './tsconfig.json'], tsconfigRootDir: import.meta.dirname, }, }, diff --git a/scripts/check-workspace-constraints.ts b/scripts/check-workspace-constraints.ts index 940de45f81..a669a8572d 100644 --- a/scripts/check-workspace-constraints.ts +++ b/scripts/check-workspace-constraints.ts @@ -35,12 +35,15 @@ interface PackageManifest { type?: string main?: string types?: string - exports?: { - '.'?: { + bin?: string | Record + exports?: Record< + string, + | { types?: string default?: string } - } + | undefined + > files?: string[] peerDependencies?: Record devDependencies?: Record @@ -89,10 +92,22 @@ const dshPackageFiles = [ 'src', ] as const +const dshBinPackageFiles = [ + 'lib/index.js', + 'lib/bin.js', + 'lib/types/**/*.d.ts', + 'lib/types/**/*.d.ts.map', + 'src', +] as const + function sameStringList(actual: readonly string[] | undefined, expected: readonly string[]): boolean { return !!actual && actual.length === expected.length && actual.every((value, index) => value === expected[index]) } +function expectedDshPackageFiles(manifest: PackageManifest): readonly string[] { + return manifest.bin ? dshBinPackageFiles : dshPackageFiles +} + function checkWorkspace({ dir, manifest }: WorkspaceManifest): string[] { const errors: string[] = [] const label = manifest.name ?? dir @@ -132,8 +147,9 @@ function checkWorkspace({ dir, manifest }: WorkspaceManifest): string[] { if (manifest.exports?.['.']?.default !== './lib/index.js') { errors.push(`${label}: package.json exports["."].default must be "./lib/index.js"`) } - if (!sameStringList(manifest.files, dshPackageFiles)) { - errors.push(`${label}: package.json files must be ${JSON.stringify(dshPackageFiles)}`) + const expectedFiles = expectedDshPackageFiles(manifest) + if (!sameStringList(manifest.files, expectedFiles)) { + errors.push(`${label}: package.json files must be ${JSON.stringify(expectedFiles)}`) } }