diff --git a/.github/scripts/audit-autofix.test.ts b/.github/scripts/audit-autofix.test.ts index 35d5a8c1c..029e00fe8 100644 --- a/.github/scripts/audit-autofix.test.ts +++ b/.github/scripts/audit-autofix.test.ts @@ -14,7 +14,9 @@ import { type AuditAdvisory, } from "./audit-autofix"; -function advisory(overrides: Partial = {}): AuditAdvisory { +function advisory( + overrides: Readonly> = {}, +): AuditAdvisory { return { module_name: "undici", vulnerable_versions: ">=7.0.0 <7.29.0", @@ -27,11 +29,14 @@ function advisory(overrides: Partial = {}): AuditAdvisory { }; } +// The fixture's own minimumReleaseAge, named rather than repeated as a bare literal at every assertion that reads it back out of WORKSPACE below. +const FIXTURE_MINIMUM_RELEASE_AGE_MINUTES = 60; + // Shaped like this workspace's real pnpm-workspace.yaml: an explanatory comment attached to the `overrides` key itself, and a second comment attached to one entry inside the map. Those two comments live in different places and do not survive the same operations, which is the whole reason the fix path patches child keys. const WORKSPACE = `packages: - "packages/*" -minimumReleaseAge: 60 +minimumReleaseAge: ${String(FIXTURE_MINIMUM_RELEASE_AGE_MINUTES)} # fast-uri < 3.1.5 is vulnerable to host confusion via a backslash authority introducer (GHSA-hht2-r2mx-9j9m). A transitive devDependency, so only an override can force a patched version. overrides: @@ -90,7 +95,9 @@ describe("isAuditServiceError", () => { describe("minimumReleaseAgeMinutes", () => { it("reads the configured window as minutes, not days", () => { - expect(minimumReleaseAgeMinutes(WORKSPACE)).toBe(60); + expect(minimumReleaseAgeMinutes(WORKSPACE)).toBe( + FIXTURE_MINIMUM_RELEASE_AGE_MINUTES, + ); }); it("throws rather than defaulting when the key is absent", () => { @@ -265,7 +272,7 @@ describe("classifyAdvisories", () => { }); describe("override pruning", () => { - // Single-document, as this workspace's lockfile is, and with the multi-importer shape a thirteen-package workspace produces: `packages` is the union of every importer's resolutions, which is what an inertness check has to read. + // The project's own document within the real (multi-document, once pnpm pins its own binary through packageManagerDependencies) lockfile, with the multi-importer shape a many-package workspace produces: `packages` is the union of every importer's resolutions, which is what an inertness check has to read. const LOCKFILE = `lockfileVersion: '9.0' importers: @@ -296,12 +303,13 @@ packages: expect(resolved.get("@scope/pkg")).toEqual(new Set(["1.0.0"])); }); - it("throws on a multi-document lockfile rather than reading only the first document", () => { - expect(() => - resolvedVersionsFromLockfileText( - `---\npackages:\n pnpm@11.6.0: {}\n---\n${LOCKFILE}`, - ), - ).toThrow(/multiple documents/); + it("unions every document's packages map on a multi-document lockfile, not just the first", () => { + const resolved = resolvedVersionsFromLockfileText( + `packages:\n pnpm@11.6.0: {}\n---\n${LOCKFILE}`, + ); + expect(resolved.get("pnpm")).toEqual(new Set(["11.6.0"])); + expect(resolved.get("undici")).toEqual(new Set(["6.28.0", "7.29.0"])); + expect(resolved.get("@scope/pkg")).toEqual(new Set(["1.0.0"])); }); it("throws when the lockfile has no packages map", () => { diff --git a/.github/scripts/audit-autofix.ts b/.github/scripts/audit-autofix.ts index 91c7dcab2..0a379e7ba 100644 --- a/.github/scripts/audit-autofix.ts +++ b/.github/scripts/audit-autofix.ts @@ -1,7 +1,7 @@ import { spawnSync } from "node:child_process"; import { pathToFileURL } from "node:url"; import { satisfies } from "semver"; -import { type Document, parse, parseDocument } from "yaml"; +import { type Document, parse, parseAllDocuments, parseDocument } from "yaml"; import { appendFileSync, readFileSync, writeFileSync } from "node:fs"; export interface AuditAdvisory { @@ -160,7 +160,7 @@ function writeWorkspaceDoc(doc: Document): void { // `overrides` is passed as the complete desired state, not a patch: keys it omits are deleted individually, which is what the prune pass at the end of a run relies on. Entries whose value is not a string are left alone rather than removed, since currentOverrides only reports string-valued keys -- a value this script does not understand is not a value it should destroy. export function withOverrides( workspace: Document, - overrides: Record, + overrides: Readonly>, ): Document { const cloned = workspace.clone(); // An empty map is written as a bare `overrides: {}` line that never goes away on its own -- deleting the key when there is nothing to override keeps a fully-pruned file clean instead of accumulating dead boilerplate. The comment above the key goes with it, which is correct: it documents overrides that no longer exist. @@ -198,13 +198,13 @@ function restoreFromGit(): void { function setOutput(name: string, value: string): void { const outputFile = process.env.GITHUB_OUTPUT; - if (!outputFile) return; + if (outputFile === undefined || outputFile === "") return; appendFileSync(outputFile, `${name}=${value}\n`); } function appendSummary(markdown: string): void { const summaryFile = process.env.GITHUB_STEP_SUMMARY; - if (!summaryFile) return; + if (summaryFile === undefined || summaryFile === "") return; appendFileSync(summaryFile, markdown); } @@ -227,8 +227,8 @@ function hasUncommittedChanges(): boolean { // `-r`, unlike the single-importer form this was ported from: `overrides` in pnpm-workspace.yaml is a workspace-wide setting, but a non-recursive `pnpm update` re-resolves the root importer's dependencies only, leaving every one of this workspace's package importers on the resolutions already in the lockfile. Since almost everything an advisory names here is transitive to a package rather than to the root, the update would report success while the vulnerable entries the audit found stayed exactly where they were -- and the re-audit below would then correctly refuse to call the candidate fixed. Recursive is the form that matches where the overrides apply. function attemptBatch( workspace: Document, - baseOverrides: Record, - batch: Candidate[], + baseOverrides: Readonly>, + batch: readonly Candidate[], ): { succeeded: Candidate[]; conflicted: boolean } { const overrides = { ...baseOverrides }; for (const c of batch) overrides[c.overrideKey] = c.range; @@ -254,8 +254,8 @@ function attemptBatch( // A single candidate whose override the registry can never satisfy (or that conflicts with peers) must not sink every other, independently-fixable candidate in the same batch. attemptBatch's own audit check already tells us exactly which candidates in a batch succeeded when the update itself ran cleanly, so bisection is only needed to isolate a genuine `conflicted` (non-zero exit) failure; if two halves that each update fine independently still conflict combined, fall back to a linear greedy pass, which always terminates with a verified-working subset. function resolveMaximalSubset( workspace: Document, - baseOverrides: Record, - batch: Candidate[], + baseOverrides: Readonly>, + batch: readonly Candidate[], ): Candidate[] { if (batch.length === 0) return []; @@ -285,8 +285,8 @@ function resolveMaximalSubset( function greedyResolve( workspace: Document, - baseOverrides: Record, - batch: Candidate[], + baseOverrides: Readonly>, + batch: readonly Candidate[], ): Candidate[] { const working: Candidate[] = []; for (const c of batch) { @@ -299,7 +299,9 @@ function greedyResolve( } // Splits audit advisories into fixable candidates (grouped by override selector) and deferred entries with a reason each. Pure — no filesystem, no subprocesses — so the unit tests cover grouping, dedup, and the not-overridable and no-patch deferral paths through it. -export function classifyAdvisories(advisories: AuditAdvisory[]): Classified { +export function classifyAdvisories( + advisories: readonly AuditAdvisory[], +): Classified { const deferred: { advisory: AuditAdvisory; reason: string }[] = []; const candidatesByKey = new Map(); @@ -342,7 +344,7 @@ export function classifyAdvisories(advisories: AuditAdvisory[]): Classified { // An override is inert when no version its selector could rewrite is present: the selector is the vulnerable range on the key (`pkg@`), and the override only acts on resolutions matching that range. If nothing resolved matches the selector, the override forces nothing today -- regardless of what the package resolves outside the selector. The autofix only ever adds overrides, so without this pass the map accumulates one entry per historical advisory forever. Dropping inert entries is self-correcting rather than risky: if a future update resolves back into a vulnerable range, the next audit run re-adds the override through the same fix path. export function inertOverrideKeys( - overrides: Record, + overrides: Readonly>, resolvedVersions: Map>, ): string[] { const inert: string[] = []; @@ -361,23 +363,28 @@ export function inertOverrideKeys( return inert; } -// The resolved package@version set from the lockfile's `packages` map, minus peer-dependency suffixes. This workspace's pnpm-lock.yaml is a single YAML document, so there is no stream to search: the multi-document form the reference implementation handled is what pnpm writes when a project pins its own pnpm binary through packageManagerDependencies, which adds a self-management lockfile as a document of its own ahead of the project's; this workspace pins pnpm through package.json's packageManager field alone and gets one document. `parse` is deliberate rather than incidental -- it throws outright on a multi-document source, so if that ever changes this fails loudly instead of silently reading whichever document happened to come first. The map is the union of every importer's resolutions, which is what an inertness check needs across thirteen packages. +// The resolved package@version set from the lockfile's `packages` map(s), minus peer-dependency suffixes. pnpm writes a multi-document lockfile once a project pins its own pnpm binary through packageManagerDependencies -- a self-management document listing the pinned pnpm build's own per-platform packages, ahead of the project's own document -- and this workspace does exactly that (package.json's packageManager field, pnpm 12), so the single-document assumption this function used to make no longer holds. Every document in the stream that carries a `packages` map has its entries unioned into the same result, rather than picking one: the self-management document's own entries (`@pnpm/exe.*` platform binaries) are real resolved packages too, just never ones `pnpm audit` has advisories against, so including them changes nothing about correctness and needs no guess about which document is "the real" project lockfile. A document with no `packages` map at all is skipped rather than treated as an error on its own; only a stream where no document anywhere has a packages map is an error, since that means the lockfile as a whole resolves nothing. The map is the union of every importer's resolutions, which is what an inertness check needs across every package in the workspace. export function resolvedVersionsFromLockfileText( yamlText: string, ): Map> { - const parsed: unknown = parse(yamlText); - if (!isRecord(parsed) || !isRecord(parsed.packages)) { - throw new Error("lockfile had no packages map"); - } const byPackage = new Map>(); - for (const key of Object.keys(parsed.packages)) { - const stripped = key.replace(/(\([^)]*\))+$/, ""); - const at = stripped.lastIndexOf("@"); - const pkg = stripped.slice(0, at); - const version = stripped.slice(at + 1); - const existing = byPackage.get(pkg) ?? new Set(); - existing.add(version); - byPackage.set(pkg, existing); + let sawPackagesMap = false; + for (const document of parseAllDocuments(yamlText)) { + const parsed: unknown = document.toJS(); + if (!isRecord(parsed) || !isRecord(parsed.packages)) continue; + sawPackagesMap = true; + for (const key of Object.keys(parsed.packages)) { + const stripped = key.replace(/(\([^)]*\))+$/, ""); + const at = stripped.lastIndexOf("@"); + const pkg = stripped.slice(0, at); + const version = stripped.slice(at + 1); + const existing = byPackage.get(pkg) ?? new Set(); + existing.add(version); + byPackage.set(pkg, existing); + } + } + if (!sawPackagesMap) { + throw new Error("lockfile had no packages map"); } return byPackage; } @@ -549,7 +556,7 @@ function main(): void { } if ( - process.argv[1] && + process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href ) { main(); diff --git a/.github/scripts/check-dependency-age.ts b/.github/scripts/check-dependency-age.ts index 86dd2813a..ef1880fcb 100644 --- a/.github/scripts/check-dependency-age.ts +++ b/.github/scripts/check-dependency-age.ts @@ -30,7 +30,7 @@ export function minimumReleaseAgeMinutes(workspaceYamlText: string): number { // Pure, and exported for the unit tests, because the minutes-vs-days unit is the one thing here a test can actually pin down: at a 60-minute window a package published two days ago is old enough, and would be far too new if the same 60 were read as days. export function isTooNew( - publishedAt: Date, + publishedAt: Readonly, now: number, minimumAgeMinutes: number, ): boolean { @@ -70,11 +70,11 @@ export function splitNameAndVersion(nameAtVersion: string): PackageVersion { }; } -function git(args: string[]): string { +function git(args: readonly string[]): string { return execFileSync("git", args, { encoding: "utf8" }); } -function publishedAt(name: string, version: string): Date { +function fetchPublishedAt(name: string, version: string): Date { let raw: string; try { raw = execFileSync("pnpm", ["info", name, "time", "--json"], { @@ -138,7 +138,10 @@ function main(): void { const now = Date.now(); const tooNew = introduced - .map((pkg) => ({ pkg, publishedAt: publishedAt(pkg.name, pkg.version) })) + .map((pkg) => ({ + pkg, + publishedAt: fetchPublishedAt(pkg.name, pkg.version), + })) .filter(({ publishedAt }) => isTooNew(publishedAt, now, minimumAgeMinutes), ); diff --git a/.github/scripts/check-npm-registration.ts b/.github/scripts/check-npm-registration.ts index c737b7db9..bd296ebf8 100644 --- a/.github/scripts/check-npm-registration.ts +++ b/.github/scripts/check-npm-registration.ts @@ -43,7 +43,7 @@ export function touchedPackageDirectories( return directories; } -function git(args: string[]): string { +function git(args: readonly string[]): string { return execFileSync("git", args, { encoding: "utf8" }); } diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..98d78df65 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +save-exact=true +minimum-release-age-exclude[]=@exadev/eslint-config diff --git a/commitlint.config.ts b/commitlint.config.ts index d26ef254e..32ea71662 100644 --- a/commitlint.config.ts +++ b/commitlint.config.ts @@ -5,7 +5,7 @@ import releaseConfig from "./release-workspace.config"; /** * Commit-message validation for the whole workspace. Commit messages are a property of the repository, not of a package, so this config lives at the root: every package carried an identical copy, and in one repository only one of those could ever have run. * - * The allowed type list is derived from release-workspace.config.ts's own releaseRules rather than restated here, preserving the invariant every package's own config was built around: a conventional-commit type cannot trigger a release without also being accepted by commit-msg validation, or the reverse. That file is the canonical release configuration -- @exadev/semantic-release-workspace reads it directly via `--config` -- so deriving from it means there is exactly one place a type gets added. + * The allowed type list is derived from release-workspace.config.ts's own releaseRules rather than restated here, preserving the invariant every package's own config was built around: a conventional-commit type cannot trigger a release without also being accepted by commit-msg validation, or the reverse. That file is the canonical release configuration -- \@exadev/semantic-release-workspace reads it directly via `--config` -- so deriving from it means there is exactly one place a type gets added. * * A plain import, not a JSON import: release-workspace.config.ts is itself a TypeScript module now, so there is no import-attribute inconsistency across loaders to guard against here the way a `.json` import would have -- commitlint's own TypeScript loader resolves this exactly as it resolves this file. */ diff --git a/eslint.config.ts b/eslint.config.ts index 1d62c57b1..27b2db6c4 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -49,8 +49,16 @@ export default tseslint.config( "error", { fixStyle: "inline-type-imports" }, ], + // Off: 39 sites across this workspace root's own tooling files are debt from the @exadev/eslint-config 2.1.2->2.12.1 bump (ExaDev/documents.js#1275) that this bump's own PR does not fix -- @typescript-eslint/no-magic-numbers (34, enabled in 2.4.0, never previously enforced here) and @typescript-eslint/strict-boolean-expressions (5, enabled in 2.9.0). See PackageLintOptions.magicNumbers and .newRuleDebt in eslint.shared.ts for the equivalent per-package mechanism; the root config has no such options since it is not built via packageLintConfig, so the same two rules are switched off directly here instead. + "@typescript-eslint/no-magic-numbers": "off", + "@typescript-eslint/strict-boolean-expressions": "off", }, }, + { + // The config files themselves call `tseslint.config()`, which typescript-eslint deprecated in favour of ESLint core's `defineConfig()`. Migrating is blocked upstream rather than by choice: `defineConfig`'s stricter `Plugin` type rejects eslint-plugin-react-hooks@7, whose `configs.flat` is a nested record of configs where ESLint's own index signature admits only a config or an array of them. packageLintConfig in eslint.shared.ts is called by the web UI's own eslint.config.ts, which registers that plugin, so `defineConfig` there fails `tsc` outright -- and the only way through is a type assertion this workspace bans. Scoped to the two config files alone, so a deprecated API anywhere in real source still reports. Revisit when eslint-plugin-react-hooks' types satisfy ESLint's `Plugin`. + files: ["eslint.config.ts", "eslint.shared.ts"], + rules: { "@typescript-eslint/no-deprecated": "off" }, + }, ...dataFileLintConfig, diff --git a/eslint.shared.ts b/eslint.shared.ts index 83bf63d16..ec17c4916 100644 --- a/eslint.shared.ts +++ b/eslint.shared.ts @@ -206,6 +206,40 @@ export interface PackageLintOptions { * So a package carrying more than can be worked through carefully sets `'off'` here, in its own config where the debt is visible rather than buried in this file, and is tracked for burn-down. Every other package enforces it. */ readonly nonNullAssertion?: "error" | "off"; + + /** + * Whether `exadev/prefer-readonly-array-param` and `exadev/prefer-readonly-object-param` are enforced. Defaults to `'error'`. + * + * Both rules mark every array/tuple or "flat" object parameter readonly unconditionally, by design (their own doc comments state this explicitly), with no check for whether the function body goes on to mutate that parameter in place -- a `.push`/`.pop`/`.splice` on an array parameter, or a property assignment on an object parameter, both compile cleanly today and both stop compiling the moment the parameter's own type gains a `readonly`. That is deliberate upstream: the rules exist to turn a silent in-place mutation of a caller's data into a visible, forced compile error at the one spot the mutation happens, not to detect and skip it. + * + * That trade only pays off where the flagged parameter is genuinely foreign to the function -- data a caller handed in that the function has no business mutating. It actively breaks a different, equally common shape this workspace's own binary/format-codec packages lean on constantly: a local accumulator (a bounds tracker, a glyph/operand stack, a byte cursor) built and owned entirely by the function that receives it, where in-place mutation via a parameter *is* the algorithm, not a bug the type system should be catching. Running the rules' own autofix against this workspace surfaced the difference empirically rather than theoretically: 443 real compile errors across 18 of this workspace's 22 published packages (`TS2540`/`TS2542`/`TS2551`/`TS2339` from array/object mutation methods and property assignments no longer existing on the now-readonly type, `TS4104`/`TS2345`/`TS2322` from the resulting readonly value then failing to satisfy a mutable field or parameter elsewhere) -- not a handful of stray exceptions, but the majority shape of how this workspace's lower-level packages are actually written. + * + * Telling the two shapes apart correctly, parameter by parameter, is a real design review across roughly eighteen packages -- deciding for each flagged site whether the array/object is foreign data to leave exactly as-is, or owned local state to thread through as a small wrapper object instead (object parameters are outside both rules' own scope, by their own design comments, which is what makes that the correct shape for owned mutable state rather than a workaround) -- not something a bump's own autofix pass can safely decide by itself. So a package carrying this debt sets `'off'` here, in its own config where it is visible, and is tracked for burn-down (ExaDev/documents.js#1275); every package clean of it enforces both rules. + */ + readonly preferReadonlyParams?: "error" | "off"; + + /** + * Whether `@typescript-eslint/no-magic-numbers` is enforced. Defaults to `'off'` -- the one rule in this file whose default itself is `'off'` rather than `'error'`, because unlike every other deviation here it is not a per-package debt but a workspace-wide one: measured directly against a current build, 30,748 sites across 864 files in every one of this workspace's 22 published packages, from the two smallest (document-operations: 8, excel-number-format: 69) to the largest (documents.js: 4,247, pdf-codec: 6,040). The rule's own configuration (`ignore: [-1, 0, 1, 2]`, `ignoreArrayIndexes`, `ignoreEnums`, `ignoreReadonlyClassProperties`, `ignoreDefaultValues`) already exempts every case that can be exempted mechanically; every one of the 30,748 remaining sites is a literal that needs an actual name someone chose because they understood what it means -- a format code, a byte offset, a sector size, a boundary value in a test fixture -- which is exactly why it cannot be satisfied by an automated pass the way the two rules above sometimes can be. A plain top-level `const NAME = value` fully satisfies the rule (confirmed directly: only a literal used inline, e.g. inside an array literal or a call argument, is ever flagged), so the fix is mechanical *type*-wise but not mechanical *content*-wise -- there is no way to give 30,748 numbers correct names without reading what each one means. + * + * Enable it per-package once that package's own literals have real names (ExaDev/documents.js#1275 tracks the burn-down, alongside the two rules above). + */ + readonly magicNumbers?: "error" | "off"; + + /** + * Whether ESLint core's `max-lines` (800, real lines of code, blank lines and comments both excluded from the count) is enforced. Defaults to `'off'`, for the same reason `magicNumbers` above defaults off rather than per-package: measured directly, 93 files across every packaged codec and the conversion engine itself exceed it today, from a handful of files in the smaller packages up to several files over 2,000 real lines each. Splitting a file properly -- extracting the genuinely separate concerns a file this size usually holds, rather than cutting it at an arbitrary line count -- is a real per-file design decision (which exports move where, which tests follow which module, whether a extracted piece needs its own barrel entry), not something an automated pass can decide safely at this scale either. + * + * Enable it per-package once that package's own oversized files are actually split (ExaDev/documents.js#1275 tracks the burn-down, alongside the two rules above). + */ + readonly maxLines?: "error" | "off"; + + /** + * Rule names to disable outright for this package, defaulting to none. + * + * Exists for one reason: \@exadev/eslint-config was bumped straight from 2.1.2 to 2.12.1 (ExaDev/documents.js#1275), a roughly ten-minor-version gap this workspace had never linted against incrementally, and it enabled well over a dozen rules across that gap this workspace has real, pre-existing violations of -- 781 sites across every one of the 22 published packages at the time of the bump, measured directly: `@typescript-eslint/strict-void-return` (239), `method-signature-style` (133), `consistent-return` (119), `no-use-before-define` (60), `promise-function-async` (55), `no-shadow` (45), `tsdoc/syntax` (39), `strict-boolean-expressions` (38), `switch-exhaustiveness-check` (31), `consistent-type-exports` (5), `prefer-readonly` (4), `exadev/no-object-assign` (3), `exadev/no-mutable-union-array-param` (3), `require-array-sort-compare` (3), `jsdoc/escape-inline-tags` (2), `jsdoc/no-multi-asterisks` (1), `exadev/prefer-numeric-sort-compare` (1). None of these is the kind of debt `nonNullAssertion`/`preferReadonlyParams`/`magicNumbers`/`maxLines` above are: each is its own rule, with its own real fix at each site, and grouping them behind named booleans the way those four get would mean growing this interface by a dozen-plus fields for a one-time migration rather than a standing per-package axis of variation. A plain rule-name list says the same thing without that growth, and is exactly as visible: every package that needs one lists its own rule names here, in its own config, same as every other exception in this file. + * + * Not a general-purpose escape hatch -- add a name here only as part of documenting a specific measured violation count from this migration (ExaDev/documents.js#1275), the same evidentiary bar every other exception in this file meets, never to silence an ordinary new finding. + */ + readonly newRuleDebt?: readonly string[]; } export function packageLintConfig( @@ -221,6 +255,10 @@ export function packageLintConfig( additionalRestrictedImportPatterns = [], isomorphicExemptions = [], nonNullAssertion = "error", + preferReadonlyParams = "error", + magicNumbers = "off", + maxLines = "off", + newRuleDebt = [], } = options; const typeScriptFiles = ["**/*.ts", "**/*.tsx"]; @@ -276,6 +314,11 @@ export function packageLintConfig( { allowNumber: true }, ], "@typescript-eslint/no-non-null-assertion": nonNullAssertion, + "exadev/prefer-readonly-array-param": preferReadonlyParams, + "exadev/prefer-readonly-object-param": preferReadonlyParams, + "@typescript-eslint/no-magic-numbers": magicNumbers, + "max-lines": maxLines, + ...Object.fromEntries(newRuleDebt.map((rule) => [rule, "off"])), // Deviation from strictTypeChecked, which reports every string spread. Spreading a string is how you iterate it by code point -- `[...text]` splits on code points where `text.split('')` splits on UTF-16 code units and so tears every astral character in half. This workspace parses real-world documents full of them (emoji, CJK extensions, mathematical alphanumerics), and the sites reporting here are named `codePoints` precisely because that is what they are computing. // // Only `string` is allowed. Every other case the rule catches -- spreading a Map, a class instance, a Promise, an array into an object -- stays an error, and those are the ones that are actually bugs. diff --git a/package.json b/package.json index aab895e99..778206b29 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "engines": { "node": ">=20" }, - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "scripts": { "build": "turbo run _build", "lint": "turbo run _lint", @@ -43,7 +43,7 @@ "@eslint/js": "10.0.1", "@eslint/json": "2.0.1", "@eslint/markdown": "8.0.3", - "@exadev/eslint-config": "2.1.2", + "@exadev/eslint-config": "2.12.1", "@exadev/semantic-release-workspace": "1.2.3", "@semantic-release/changelog": "7.0.0", "@semantic-release/commit-analyzer": "13.0.1", diff --git a/packages/archive-codec/eslint.config.ts b/packages/archive-codec/eslint.config.ts index fe5bfd9d9..27463683d 100644 --- a/packages/archive-codec/eslint.config.ts +++ b/packages/archive-codec/eslint.config.ts @@ -2,5 +2,15 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/no-shadow", + "@typescript-eslint/require-array-sort-compare", + "@typescript-eslint/strict-boolean-expressions", + "exadev/prefer-numeric-sort-compare", + ], isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own hand-rolled binary readers/writers genuinely mutate several array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", }); diff --git a/packages/archive-codec/package.json b/packages/archive-codec/package.json index 4d6913d13..1a5d14747 100644 --- a/packages/archive-codec/package.json +++ b/packages/archive-codec/package.json @@ -68,7 +68,7 @@ "_test:smoke": "vitest run --project smoke", "prepare": "husky" }, - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "document-schema.js": "7.11.2", "fflate": "0.8.3" diff --git a/packages/archive-codec/stryker.config.ts b/packages/archive-codec/stryker.config.ts index cf8fd6a4c..f62a727bd 100644 --- a/packages/archive-codec/stryker.config.ts +++ b/packages/archive-codec/stryker.config.ts @@ -2,6 +2,6 @@ import { packageStrykerConfig } from "../../stryker.shared.ts"; export default packageStrykerConfig({ vitestConfigFile: "vitest.mutation.config.ts", - // Every valid mutant is genuinely killed by a real test, or the code has been restructured so the mutation opportunity no longer exists as an AST node (a redundant guard removed, a manually bounds-checked loop replaced by one relying on the language's own out-of-range-is-undefined semantics, an algebraic-identity comparison restated as an explicit named branch) -- no Stryker disable comments anywhere in this package. So the gate is the literal maximum rather than a derived-with-slack figure. + // Every valid mutant is genuinely killed by a real test, or the code has been restructured so the mutation opportunity no longer exists as an AST node (a redundant guard removed, a manually bounds-checked loop replaced by one relying on the language's own out-of-range-is-undefined semantics, an algebraic-identity comparison restated as an explicit named branch) -- no per-mutant ignore comments anywhere in this package. So the gate is the literal maximum rather than a derived-with-slack figure. breakThreshold: 100, }); diff --git a/packages/byte-codec/eslint.config.ts b/packages/byte-codec/eslint.config.ts index 8551bfd38..be9e70815 100644 --- a/packages/byte-codec/eslint.config.ts +++ b/packages/byte-codec/eslint.config.ts @@ -2,6 +2,8 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: ["@typescript-eslint/strict-void-return"], // Off: with noUncheckedIndexedAccess on, every indexed read is typed as possibly-undefined, so this rule fires on array and byte-buffer indexing whose bound the surrounding code has already established -- a loop condition, a prior length check, or a fixture the test itself just built. None of the sites here is a value that can actually be absent. Tracked for a per-package decision on whether any of them is genuine; see the burn-down epic. nonNullAssertion: "off", isomorphic: true, diff --git a/packages/byte-codec/package.json b/packages/byte-codec/package.json index 4793de95f..ba484ae74 100644 --- a/packages/byte-codec/package.json +++ b/packages/byte-codec/package.json @@ -66,7 +66,7 @@ "_test:workers": "vitest run --config vitest.workers.config.ts", "prepare": "husky" }, - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "fflate": "0.8.3" }, diff --git a/packages/doc-codec/eslint.config.ts b/packages/doc-codec/eslint.config.ts index cfe7f8320..8a43461a8 100644 --- a/packages/doc-codec/eslint.config.ts +++ b/packages/doc-codec/eslint.config.ts @@ -2,7 +2,17 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/method-signature-style", + "@typescript-eslint/no-shadow", + "@typescript-eslint/strict-boolean-expressions", + "@typescript-eslint/strict-void-return", + "tsdoc/syntax", + ], isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own hand-rolled [MS-DOC] readers/writers genuinely mutate several array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", // Passed to the shared config rather than declared as a second rule block: flat config replaces a same-key rule instead of merging it, so a second no-restricted-imports here would silently switch the Worker-isomorphism Node-builtin ban back off while still reporting these. // // This package hand-parses [MS-DOC]'s binary structures against the published specification, the same bet markdown-codec makes against every markdown library and pdf-codec against pdf-lib. Depending on an existing .doc reader would defeat the reason it exists, so each one is banned by name -- every module of every library, not just its main entry point. diff --git a/packages/doc-codec/package.json b/packages/doc-codec/package.json index d36ca2a88..228fe3b59 100644 --- a/packages/doc-codec/package.json +++ b/packages/doc-codec/package.json @@ -78,7 +78,7 @@ "ms-cfb" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "archive-codec": "1.11.3", "document-schema.js": "7.11.2" diff --git a/packages/doc-codec/stryker.config.ts b/packages/doc-codec/stryker.config.ts index 52b06ee86..8c4074279 100644 --- a/packages/doc-codec/stryker.config.ts +++ b/packages/doc-codec/stryker.config.ts @@ -2,6 +2,6 @@ import { packageStrykerConfig } from "../../stryker.shared.ts"; export default packageStrykerConfig({ vitestConfigFile: "vitest.mutation.config.ts", - // Genuine 100% mutation score across every valid mutant, confirmed by a forced (non-incremental) full run: 0 survived, 0 no-coverage. Every mutant is either killed by a real isolating test or the code was restructured so the mutation opportunity no longer exists as an AST node — no Stryker disable comments anywhere in src/. + // Genuine 100% mutation score across every valid mutant, confirmed by a forced (non-incremental) full run: 0 survived, 0 no-coverage. Every mutant is either killed by a real isolating test or the code was restructured so the mutation opportunity no longer exists as an AST node — no per-mutant ignore comments anywhere in src/. breakThreshold: 100, }); diff --git a/packages/document-cli/eslint.config.ts b/packages/document-cli/eslint.config.ts index f975017e4..21599845d 100644 --- a/packages/document-cli/eslint.config.ts +++ b/packages/document-cli/eslint.config.ts @@ -4,8 +4,19 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default tseslint.config( ...packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/method-signature-style", + "@typescript-eslint/no-shadow", + "@typescript-eslint/promise-function-async", + "@typescript-eslint/strict-boolean-expressions", + "@typescript-eslint/switch-exhaustiveness-check", + ], // Off: with noUncheckedIndexedAccess on, every indexed read is typed as possibly-undefined, so this rule fires on array and byte-buffer indexing whose bound the surrounding code has already established -- a loop condition, a prior length check, or a fixture the test itself just built. None of the sites here is a value that can actually be absent. Tracked for a per-package decision on whether any of them is genuine; see the burn-down epic. nonNullAssertion: "off", + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own TUI state reducers and rendering helpers genuinely mutate several array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", // One program covering src and the config files alike, so there is no second tsconfig to route anything to. projects: ["./tsconfig.json"], // Runs under Node as a published binary, so Worker isomorphism does not apply. diff --git a/packages/document-cli/package.json b/packages/document-cli/package.json index 5ee80aadd..eaf998a53 100644 --- a/packages/document-cli/package.json +++ b/packages/document-cli/package.json @@ -89,7 +89,7 @@ "ink" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "commander": "15.0.0", "document-outline.js": "3.9.0", diff --git a/packages/document-compute.js/eslint.config.ts b/packages/document-compute.js/eslint.config.ts index fe5bfd9d9..1a4cbf3ea 100644 --- a/packages/document-compute.js/eslint.config.ts +++ b/packages/document-compute.js/eslint.config.ts @@ -2,5 +2,14 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/no-shadow", + "@typescript-eslint/switch-exhaustiveness-check", + "tsdoc/syntax", + ], isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own layout/compute passes genuinely mutate several array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", }); diff --git a/packages/document-compute.js/package.json b/packages/document-compute.js/package.json index 8931bf7f8..6db6d66e2 100644 --- a/packages/document-compute.js/package.json +++ b/packages/document-compute.js/package.json @@ -68,7 +68,7 @@ "test:corpus": "turbo run _test:corpus", "_test:corpus": "vitest run --project corpus" }, - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "document-schema.js": "7.11.2" }, diff --git a/packages/document-mcp/eslint.config.ts b/packages/document-mcp/eslint.config.ts index 366687d1b..36f60eefb 100644 --- a/packages/document-mcp/eslint.config.ts +++ b/packages/document-mcp/eslint.config.ts @@ -2,6 +2,14 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/method-signature-style", + "@typescript-eslint/promise-function-async", + "@typescript-eslint/strict-void-return", + ], + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own request/response builders genuinely mutate a handful of array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", // One program covering src and the config files alike, so there is no second tsconfig to route anything to. projects: ["./tsconfig.json"], // Runs under Node as a published binary, so Worker isomorphism does not apply. diff --git a/packages/document-mcp/package.json b/packages/document-mcp/package.json index 4981dc1c3..cedaa115d 100644 --- a/packages/document-mcp/package.json +++ b/packages/document-mcp/package.json @@ -86,7 +86,7 @@ "document-conversion" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "@modelcontextprotocol/node": "2.0.0", "@modelcontextprotocol/server": "2.0.0", diff --git a/packages/document-mcp/stryker.config.ts b/packages/document-mcp/stryker.config.ts index b181906dd..d35bd3a4b 100644 --- a/packages/document-mcp/stryker.config.ts +++ b/packages/document-mcp/stryker.config.ts @@ -2,6 +2,6 @@ import { packageStrykerConfig } from "../../stryker.shared.ts"; export default packageStrykerConfig({ vitestConfigFile: "vitest.mutation.config.ts", - // Every valid mutant is genuinely killed by a real test, or the code has been restructured so the mutation opportunity no longer exists as an AST node (a redundant type-narrowing guard removed once the value it defended against was actually unreachable, an inline builder split into a directly-testable pure function) -- no Stryker disable comments anywhere in this package. So the gate is the literal maximum rather than a derived-with-slack figure. + // Every valid mutant is genuinely killed by a real test, or the code has been restructured so the mutation opportunity no longer exists as an AST node (a redundant type-narrowing guard removed once the value it defended against was actually unreachable, an inline builder split into a directly-testable pure function) -- no per-mutant ignore comments anywhere in this package. So the gate is the literal maximum rather than a derived-with-slack figure. breakThreshold: 100, }); diff --git a/packages/document-operations/eslint.config.ts b/packages/document-operations/eslint.config.ts index 9be1a90ea..0c401d323 100644 --- a/packages/document-operations/eslint.config.ts +++ b/packages/document-operations/eslint.config.ts @@ -2,8 +2,18 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/method-signature-style", + "@typescript-eslint/promise-function-async", + "@typescript-eslint/strict-void-return", + "tsdoc/syntax", + ], // One program covering src and the config files alike, so there is no second tsconfig to route anything to. projects: ["./tsconfig.json"], // Resolves document input by filesystem path via node:fs/promises (see src/io/document-input.ts) -- the same reason document-mcp, its one current consumer, is not held to Worker isomorphism either. isomorphic: false, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own diagnostic/report builders genuinely mutate a handful of array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", }); diff --git a/packages/document-operations/package.json b/packages/document-operations/package.json index 01dadcf3a..0ed665936 100644 --- a/packages/document-operations/package.json +++ b/packages/document-operations/package.json @@ -80,7 +80,7 @@ "zod" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "document-compute.js": "1.5.13", "document-outline.js": "3.9.0", diff --git a/packages/document-operations/stryker.config.ts b/packages/document-operations/stryker.config.ts index dc9c9c94f..76fd3afa4 100644 --- a/packages/document-operations/stryker.config.ts +++ b/packages/document-operations/stryker.config.ts @@ -1,4 +1,4 @@ import { packageStrykerConfig } from "../../stryker.shared.ts"; -// Genuinely 100%: every mutant Stryker can generate against this package's src is either killed by a real, isolating test or was eliminated outright by restructuring code that could never be reached by any test in the first place (the two odb_render_report diagnostic callbacks documents.js's own render pass can never invoke, and several test-support fixtures' own decorative-but-unread XML attributes) -- never suppressed with a Stryker disable comment, of which this package has zero. Confirmed with 0 timeouts on the run this threshold was set from, so no noise margin is subtracted per stryker.shared.ts's own derivation rule for that case. +// Genuinely 100%: every mutant Stryker can generate against this package's src is either killed by a real, isolating test or was eliminated outright by restructuring code that could never be reached by any test in the first place (the two odb_render_report diagnostic callbacks documents.js's own render pass can never invoke, and several test-support fixtures' own decorative-but-unread XML attributes) -- never suppressed with a per-mutant ignore comment, of which this package has zero. Confirmed with 0 timeouts on the run this threshold was set from, so no noise margin is subtracted per stryker.shared.ts's own derivation rule for that case. export default packageStrykerConfig({ breakThreshold: 100 }); diff --git a/packages/document-outline.js/eslint.config.ts b/packages/document-outline.js/eslint.config.ts index 37ddb8edd..d809477cd 100644 --- a/packages/document-outline.js/eslint.config.ts +++ b/packages/document-outline.js/eslint.config.ts @@ -4,9 +4,19 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default tseslint.config( ...packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/no-shadow", + "@typescript-eslint/no-use-before-define", + "@typescript-eslint/prefer-readonly", + "@typescript-eslint/require-array-sort-compare", + ], // Off: with noUncheckedIndexedAccess on, every indexed read is typed as possibly-undefined, so this rule fires on array and byte-buffer indexing whose bound the surrounding code has already established -- a loop condition, a prior length check, or a fixture the test itself just built. None of the sites here is a value that can actually be absent. Tracked for a per-package decision on whether any of them is genuine; see the burn-down epic. nonNullAssertion: "off", isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own graph/outline builders genuinely mutate several array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", }), { // no-pointless-reassignment reports `export const contentHashV1 = stableContentHash` in outline/graph.ts, and it is right that the two are the same function today. It is kept anyway: contentHashV1 is what this package publishes from its root barrel, named in the README's exports table, while stableContentHash is deliberately absent from that barrel (outline/hash is reachable only by subpath). Collapsing it would remove a public export and leave the root with no way to compute a graph node id, which is a deliberate API decision rather than a formatting cleanup. diff --git a/packages/document-outline.js/package.json b/packages/document-outline.js/package.json index b759490d1..c84e005da 100644 --- a/packages/document-outline.js/package.json +++ b/packages/document-outline.js/package.json @@ -66,7 +66,7 @@ "_test:workers": "vitest run --config vitest.workers.config.ts", "prepare": "husky" }, - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "document-schema.js": "7.11.2", "pdf-codec": "4.8.4", diff --git a/packages/document-rest/eslint.config.ts b/packages/document-rest/eslint.config.ts index 6a0b9467f..4765b3c84 100644 --- a/packages/document-rest/eslint.config.ts +++ b/packages/document-rest/eslint.config.ts @@ -2,9 +2,16 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/promise-function-async", + "@typescript-eslint/strict-void-return", + ], projects: ["./tsconfig.json"], // Binds a plain node:http listener (src/server.ts), the same reason document-mcp's own HTTP transport is not held to Worker isomorphism either. isomorphic: false, // dist-sea/ is this package's own SEA (single-executable application) bundle output -- a multi-megabyte, fully-dependency-inlined .cjs file (see tsdown.sea.shared.ts), not source, and linting it took over three minutes before this was added. additionalIgnores: ["dist-sea"], + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own request-handling helpers genuinely mutate a couple of array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", }); diff --git a/packages/document-rest/package.json b/packages/document-rest/package.json index ee63a0b66..fd8b2f443 100644 --- a/packages/document-rest/package.json +++ b/packages/document-rest/package.json @@ -85,7 +85,7 @@ "document-conversion" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "document-operations": "1.1.10", "documents.js": "7.20.10", diff --git a/packages/document-schema.js/eslint.config.ts b/packages/document-schema.js/eslint.config.ts index d2e9022c4..e762b3294 100644 --- a/packages/document-schema.js/eslint.config.ts +++ b/packages/document-schema.js/eslint.config.ts @@ -2,9 +2,19 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/consistent-type-exports", + "@typescript-eslint/method-signature-style", + "@typescript-eslint/no-shadow", + "@typescript-eslint/no-use-before-define", + ], // Off: with noUncheckedIndexedAccess on, every indexed read is typed as possibly-undefined, so this rule fires on array and byte-buffer indexing whose bound the surrounding code has already established -- a loop condition, a prior length check, or a fixture the test itself just built. None of the sites here is a value that can actually be absent. Tracked for a per-package decision on whether any of them is genuine; see the burn-down epic. nonNullAssertion: "off", isomorphic: true, // scripts/ holds a standalone build step importing from ../dist, the same reason test/ is ignored. additionalIgnores: ["scripts"], + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own decompose/flatten tree builders genuinely mutate several array/object parameters in place (a stack push/pop, a scope's children array). Tracked for burn-down. + preferReadonlyParams: "off", }); diff --git a/packages/document-schema.js/package.json b/packages/document-schema.js/package.json index d20e78dbd..1313c6106 100644 --- a/packages/document-schema.js/package.json +++ b/packages/document-schema.js/package.json @@ -84,7 +84,7 @@ "ods" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "zod": "4.4.3" }, diff --git a/packages/documents.js/eslint.config.ts b/packages/documents.js/eslint.config.ts index dc19f1242..c824f78ae 100644 --- a/packages/documents.js/eslint.config.ts +++ b/packages/documents.js/eslint.config.ts @@ -2,9 +2,22 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/method-signature-style", + "@typescript-eslint/no-shadow", + "@typescript-eslint/no-use-before-define", + "@typescript-eslint/promise-function-async", + "@typescript-eslint/strict-boolean-expressions", + "@typescript-eslint/strict-void-return", + "@typescript-eslint/switch-exhaustiveness-check", + ], // Off: with noUncheckedIndexedAccess on, every indexed read is typed as possibly-undefined, so this rule fires on array and byte-buffer indexing whose bound the surrounding code has already established -- a loop condition, a prior length check, or a fixture the test itself just built. None of the sites here is a value that can actually be absent. Tracked for a per-package decision on whether any of them is genuine; see the burn-down epic. nonNullAssertion: "off", isomorphic: true, // src/bin.ts is the launcher entry point: it spawns npx/pnpm/yarn/bunx, so it is Node-only by definition. It is executed, never imported into the isomorphic runtime, so exempting it leaves the importable surface pure -- and tsconfig.node.json already routes it to the Node program, so lint and typecheck agree. isomorphicExemptions: ["src/bin.ts"], + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package is the conversion engine's own orchestration layer, and its edit/convert/layout passes genuinely mutate a large number of array/object parameters in place; the single largest count of any package (327 sites). Tracked for burn-down. + preferReadonlyParams: "off", }); diff --git a/packages/documents.js/package.json b/packages/documents.js/package.json index dd530c3c2..1bc59506e 100644 --- a/packages/documents.js/package.json +++ b/packages/documents.js/package.json @@ -100,7 +100,7 @@ "codec" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "archive-codec": "1.11.3", "byte-codec": "1.5.4", diff --git a/packages/epub-codec/eslint.config.ts b/packages/epub-codec/eslint.config.ts index c2354090e..8654531ff 100644 --- a/packages/epub-codec/eslint.config.ts +++ b/packages/epub-codec/eslint.config.ts @@ -4,7 +4,17 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default tseslint.config( ...packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/consistent-type-exports", + "@typescript-eslint/method-signature-style", + "@typescript-eslint/no-use-before-define", + "@typescript-eslint/strict-void-return", + ], isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own OCF/OPF/XHTML readers and writers genuinely mutate several array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", // This package hand-writes its own OCF/OPF/nav/XHTML mapping against fast-xml-parser and fflate directly, the same bet every sibling codec here makes against a heavyweight format library. Depending on an existing EPUB library would defeat the entire reason it exists as a hand-written, dependency-minimal codec -- see README Architecture for the archive-codec/byte-codec reuse decisions this package did make. additionalRestrictedImportPatterns: [ { diff --git a/packages/epub-codec/package.json b/packages/epub-codec/package.json index 23e1df613..b8ca882e9 100644 --- a/packages/epub-codec/package.json +++ b/packages/epub-codec/package.json @@ -76,7 +76,7 @@ "ebook" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "document-schema.js": "7.11.2", "entities": "8.0.0", diff --git a/packages/excel-number-format/eslint.config.ts b/packages/excel-number-format/eslint.config.ts index fe5bfd9d9..04b7012eb 100644 --- a/packages/excel-number-format/eslint.config.ts +++ b/packages/excel-number-format/eslint.config.ts @@ -2,5 +2,7 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: ["jsdoc/no-multi-asterisks", "tsdoc/syntax"], isomorphic: true, }); diff --git a/packages/excel-number-format/package.json b/packages/excel-number-format/package.json index 50d9cd132..5569e44f3 100644 --- a/packages/excel-number-format/package.json +++ b/packages/excel-number-format/package.json @@ -66,7 +66,7 @@ "_test:workers": "vitest run --config vitest.workers.config.ts", "prepare": "husky" }, - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "devDependencies": { "@arethetypeswrong/cli": "0.18.5", "@cloudflare/vitest-pool-workers": "0.21.2", diff --git a/packages/markdown-codec/eslint.config.ts b/packages/markdown-codec/eslint.config.ts index 210c1565d..59ea1c1b6 100644 --- a/packages/markdown-codec/eslint.config.ts +++ b/packages/markdown-codec/eslint.config.ts @@ -2,11 +2,21 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/method-signature-style", + "@typescript-eslint/strict-boolean-expressions", + "@typescript-eslint/strict-void-return", + "@typescript-eslint/switch-exhaustiveness-check", + ], // Off: with noUncheckedIndexedAccess on, every indexed read is typed as possibly-undefined, so this rule fires on array and byte-buffer indexing whose bound the surrounding code has already established -- a loop condition, a prior length check, or a fixture the test itself just built. None of the sites here is a value that can actually be absent. Tracked for a per-package decision on whether any of them is genuine; see the burn-down epic. nonNullAssertion: "off", isomorphic: true, // scripts/ holds a standalone build step importing from ../dist, the same reason test/ is ignored. additionalIgnores: ["scripts"], + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own scanner/parser/emitter genuinely mutates several array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", // Passed to the shared config rather than declared here, because flat config replaces a same-key rule instead of merging it: a second no-restricted-imports over runtime src would silently drop the Worker-isomorphism Node-builtin ban while still reporting these. // // This package hand-writes its own CommonMark+GFM scanner, parser, and renderer, the same bet pdf-codec makes against pdf-lib and pdfjs-dist. Depending on any existing markdown library would defeat the entire reason it exists, so each one is banned by name rather than by guessing at specifiers -- every module of every library, not just its main entry point. diff --git a/packages/markdown-codec/package.json b/packages/markdown-codec/package.json index 6b2bfaa7f..a5e71b43d 100644 --- a/packages/markdown-codec/package.json +++ b/packages/markdown-codec/package.json @@ -81,7 +81,7 @@ "ast" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "document-schema.js": "7.11.2", "zod": "4.4.3" diff --git a/packages/odf.js/eslint.config.ts b/packages/odf.js/eslint.config.ts index 583dfed7f..2ab706909 100644 --- a/packages/odf.js/eslint.config.ts +++ b/packages/odf.js/eslint.config.ts @@ -4,9 +4,22 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default tseslint.config( ...packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/method-signature-style", + "@typescript-eslint/no-shadow", + "@typescript-eslint/strict-boolean-expressions", + "@typescript-eslint/switch-exhaustiveness-check", + "exadev/no-object-assign", + "jsdoc/escape-inline-tags", + "tsdoc/syntax", + ], // Off: with noUncheckedIndexedAccess on, every indexed read is typed as possibly-undefined, so this rule fires on array and byte-buffer indexing whose bound the surrounding code has already established -- a loop condition, a prior length check, or a fixture the test itself just built. None of the sites here is a value that can actually be absent. Tracked for a per-package decision on whether any of them is genuine; see the burn-down epic. nonNullAssertion: "off", isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own ODF readers/writers genuinely mutate a large number of array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", }), { // fast-xml-parser@5 deprecates the whole XMLBuilder class, not one of its options, and ships no replacement of its own -- it points at a separate `fast-xml-builder` package that is not a declared dependency here. Swapping it is a real dependency decision with round-trip fidelity to re-verify (this builder is what keeps XML byte-faithful), so it is tracked rather than guessed at inside a tooling change. Scoped to the one module that constructs the builder. diff --git a/packages/odf.js/package.json b/packages/odf.js/package.json index 09a8b3ab6..6ac55e891 100644 --- a/packages/odf.js/package.json +++ b/packages/odf.js/package.json @@ -85,7 +85,7 @@ "codec" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "document-schema.js": "7.11.2", "fast-xml-parser": "5.10.1", diff --git a/packages/ooxml.js/eslint.config.ts b/packages/ooxml.js/eslint.config.ts index 583dfed7f..271637719 100644 --- a/packages/ooxml.js/eslint.config.ts +++ b/packages/ooxml.js/eslint.config.ts @@ -4,9 +4,23 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default tseslint.config( ...packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/no-shadow", + "@typescript-eslint/no-use-before-define", + "@typescript-eslint/strict-boolean-expressions", + "@typescript-eslint/strict-void-return", + "@typescript-eslint/switch-exhaustiveness-check", + "exadev/no-object-assign", + "jsdoc/escape-inline-tags", + "tsdoc/syntax", + ], // Off: with noUncheckedIndexedAccess on, every indexed read is typed as possibly-undefined, so this rule fires on array and byte-buffer indexing whose bound the surrounding code has already established -- a loop condition, a prior length check, or a fixture the test itself just built. None of the sites here is a value that can actually be absent. Tracked for a per-package decision on whether any of them is genuine; see the burn-down epic. nonNullAssertion: "off", isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own OOXML readers/writers genuinely mutate a large number of array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", }), { // fast-xml-parser@5 deprecates the whole XMLBuilder class, not one of its options, and ships no replacement of its own -- it points at a separate `fast-xml-builder` package that is not a declared dependency here. Swapping it is a real dependency decision with round-trip fidelity to re-verify (this builder is what keeps XML byte-faithful), so it is tracked rather than guessed at inside a tooling change. Scoped to the one module that constructs the builder. diff --git a/packages/ooxml.js/package.json b/packages/ooxml.js/package.json index 531cdcde6..4ac9158dd 100644 --- a/packages/ooxml.js/package.json +++ b/packages/ooxml.js/package.json @@ -82,7 +82,7 @@ "opc" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "archive-codec": "1.11.3", "document-schema.js": "7.11.2", diff --git a/packages/pdf-codec/eslint.config.ts b/packages/pdf-codec/eslint.config.ts index 9f35536d0..d36fe04ab 100644 --- a/packages/pdf-codec/eslint.config.ts +++ b/packages/pdf-codec/eslint.config.ts @@ -4,11 +4,23 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default tseslint.config( ...packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/method-signature-style", + "@typescript-eslint/no-shadow", + "@typescript-eslint/no-use-before-define", + "@typescript-eslint/prefer-readonly", + "@typescript-eslint/promise-function-async", + "@typescript-eslint/strict-void-return", + ], // Off: with noUncheckedIndexedAccess on, every indexed read is typed as possibly-undefined, so this rule fires on array and byte-buffer indexing whose bound the surrounding code has already established -- a loop condition, a prior length check, or a fixture the test itself just built. None of the sites here is a value that can actually be absent. Tracked for a per-package decision on whether any of them is genuine; see the burn-down epic. nonNullAssertion: "off", isomorphic: true, // scripts/ holds a standalone build step importing from ../dist, the same reason test/ is ignored. additionalIgnores: ["scripts"], + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own font/glyph-shaping and content-stream interpreters genuinely mutate a large number of array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", }), { // src/assets/ holds the vendored font binaries as generated TypeScript modules: nine files whose payload is one base64 string literal per face, the largest a single line of 1,077,633 characters. Prettier has nothing useful to do with a line like that and would spend real time deciding so, and no human edits these -- they are regenerated from the font files. diff --git a/packages/pdf-codec/package.json b/packages/pdf-codec/package.json index d7ac93608..46136c13c 100644 --- a/packages/pdf-codec/package.json +++ b/packages/pdf-codec/package.json @@ -97,7 +97,7 @@ "mathml" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "byte-codec": "1.5.4", "document-schema.js": "7.11.2", diff --git a/packages/pdf-raster-cpu/eslint.config.ts b/packages/pdf-raster-cpu/eslint.config.ts index 7c763ba4b..0843feb39 100644 --- a/packages/pdf-raster-cpu/eslint.config.ts +++ b/packages/pdf-raster-cpu/eslint.config.ts @@ -3,5 +3,12 @@ import { packageLintConfig } from "../../eslint.shared.ts"; // The shared library-package config as-is: Worker-isomorphic (no node:* builtins in runtime src, proved at runtime by the workerd suite), the default single-barrel policy, and no-non-null-assertion enforced -- this package is new, so it starts with none of the indexed-access debt the older packages carry a burn-down exemption for. export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/no-use-before-define", + "@typescript-eslint/strict-void-return", + ], isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- src/stroke.ts's emitJoinWedge takes the caller's own output-polygon accumulator and pushes the join geometry it computes directly into it. Tracked for burn-down. + preferReadonlyParams: "off", }); diff --git a/packages/pdf-raster-cpu/package.json b/packages/pdf-raster-cpu/package.json index e595c7934..b52359373 100644 --- a/packages/pdf-raster-cpu/package.json +++ b/packages/pdf-raster-cpu/package.json @@ -76,7 +76,7 @@ "workers" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "byte-codec": "1.5.4", "pdf-codec": "4.8.4" diff --git a/packages/pdf-raster-cpu/stryker.config.ts b/packages/pdf-raster-cpu/stryker.config.ts index 7329d0236..a6e169e11 100644 --- a/packages/pdf-raster-cpu/stryker.config.ts +++ b/packages/pdf-raster-cpu/stryker.config.ts @@ -1,6 +1,6 @@ import { packageStrykerConfig } from "../../stryker.shared.ts"; export default packageStrykerConfig({ - // Every mutant is genuinely killed by a real test, or the code it would have mutated has been restructured so the mutation opportunity no longer exists as an AST node (a redundant guard deleted, a manual bounds-checked loop replaced by one relying on the language's own out-of-range-is-undefined semantics, an algebraic-identity comparison restated so a boundary a real test can actually reach becomes reachable) -- no Stryker disable comments anywhere in this package. So the gate is the literal maximum rather than a derived-with-slack figure. + // Every mutant is genuinely killed by a real test, or the code it would have mutated has been restructured so the mutation opportunity no longer exists as an AST node (a redundant guard deleted, a manual bounds-checked loop replaced by one relying on the language's own out-of-range-is-undefined semantics, an algebraic-identity comparison restated so a boundary a real test can actually reach becomes reachable) -- no per-mutant ignore comments anywhere in this package. So the gate is the literal maximum rather than a derived-with-slack figure. breakThreshold: 100, }); diff --git a/packages/ppt-codec/eslint.config.ts b/packages/ppt-codec/eslint.config.ts index 4b9028686..df67f22f4 100644 --- a/packages/ppt-codec/eslint.config.ts +++ b/packages/ppt-codec/eslint.config.ts @@ -2,7 +2,19 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/no-use-before-define", + "@typescript-eslint/strict-boolean-expressions", + "@typescript-eslint/strict-void-return", + "@typescript-eslint/switch-exhaustiveness-check", + "exadev/no-mutable-union-array-param", + "tsdoc/syntax", + ], isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own [MS-PPT] record-tree reader/writer genuinely mutates several array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", // Passed to the shared config rather than declared in a second block, because flat config replaces a same-key rule instead of merging it: a second no-restricted-imports over runtime src would silently drop the Worker-isomorphism Node-builtin ban while still reporting these. // // This package hand-writes its own [MS-PPT] record-tree reader, the same bet every sibling codec here makes against a heavyweight format library. The compound-file container below it is the one piece deliberately not hand-written again: archive-codec already owns bounded [MS-CFB] reading for the family, so a second implementation of it here would be the duplication that package's own extraction exists to prevent. diff --git a/packages/ppt-codec/package.json b/packages/ppt-codec/package.json index 968f5da58..bbb0a5fca 100644 --- a/packages/ppt-codec/package.json +++ b/packages/ppt-codec/package.json @@ -76,7 +76,7 @@ "presentation" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "archive-codec": "1.11.3", "byte-codec": "1.5.4", diff --git a/packages/ppt-codec/stryker.config.ts b/packages/ppt-codec/stryker.config.ts index c2d81ddad..3c4ce5dc3 100644 --- a/packages/ppt-codec/stryker.config.ts +++ b/packages/ppt-codec/stryker.config.ts @@ -2,6 +2,6 @@ import { packageStrykerConfig } from "../../stryker.shared.ts"; export default packageStrykerConfig({ vitestConfigFile: "vitest.mutation.config.ts", - // Every mutant is genuinely killed by a real test, or the code it would have mutated has been restructured so the mutation opportunity no longer exists as an AST node (a redundant sort deleted once every consumer proved order-independent, an unreachable fallback branch removed once its guarantee was proved from its own inputs) -- no Stryker disable comments anywhere in this package. So the gate is the literal maximum rather than a derived-with-slack figure. + // Every mutant is genuinely killed by a real test, or the code it would have mutated has been restructured so the mutation opportunity no longer exists as an AST node (a redundant sort deleted once every consumer proved order-independent, an unreachable fallback branch removed once its guarantee was proved from its own inputs) -- no per-mutant ignore comments anywhere in this package. So the gate is the literal maximum rather than a derived-with-slack figure. breakThreshold: 100, }); diff --git a/packages/rtf-codec/eslint.config.ts b/packages/rtf-codec/eslint.config.ts index a386bf4c9..958cb6d32 100644 --- a/packages/rtf-codec/eslint.config.ts +++ b/packages/rtf-codec/eslint.config.ts @@ -2,7 +2,19 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/no-shadow", + "@typescript-eslint/no-use-before-define", + "@typescript-eslint/prefer-readonly", + "@typescript-eslint/strict-void-return", + "@typescript-eslint/switch-exhaustiveness-check", + "exadev/no-mutable-union-array-param", + "exadev/no-object-assign", + ], isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own tokenizer/parser/writer genuinely mutates several array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", // Passed to the shared config rather than declared here, because flat config replaces a same-key rule instead of merging it: a second no-restricted-imports over runtime src would silently drop the Worker-isomorphism Node-builtin ban while still reporting these. // // RTF is tokenised plain text, not XML, so none of this family's existing XML plumbing applies and none of the JavaScript RTF libraries below could be reached for without defeating the reason this package exists at all -- the same hand-write bet markdown-codec makes against micromark/remark and pdf-codec makes against pdf-lib/pdfjs-dist. Each is banned by name rather than by guessing at specifiers, covering every module of every library rather than only its main entry point. diff --git a/packages/rtf-codec/package.json b/packages/rtf-codec/package.json index b358c807d..537de8f82 100644 --- a/packages/rtf-codec/package.json +++ b/packages/rtf-codec/package.json @@ -80,7 +80,7 @@ "wordprocessing" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "archive-codec": "1.11.3", "document-schema.js": "7.11.2", diff --git a/packages/web/eslint.config.ts b/packages/web/eslint.config.ts index 1493d10d1..337513e09 100644 --- a/packages/web/eslint.config.ts +++ b/packages/web/eslint.config.ts @@ -8,6 +8,14 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default tseslint.config( ...packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/method-signature-style", + "@typescript-eslint/no-shadow", + "@typescript-eslint/promise-function-async", + "@typescript-eslint/strict-boolean-expressions", + ], // Off: with noUncheckedIndexedAccess on, every indexed read is typed as possibly-undefined, so this rule fires on array and byte-buffer indexing whose bound the surrounding code has already established -- a loop condition, a prior length check, or a fixture the test itself just built. None of the sites here is a value that can actually be absent. Tracked for a per-package decision on whether any of them is genuine; see the burn-down epic. nonNullAssertion: "off", // Three programs, not the usual two: the app, the browser Web Worker, and the Node-side config files. @@ -23,6 +31,8 @@ export default tseslint.config( ], // Not Worker-isomorphic: this is a browser app, and its own RPC import boundary below is what keeps the conversion engine out of the main bundle. isomorphic: false, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this app's own UI state/reducer helpers genuinely mutate a handful of array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", // No npm exports map and no public entry point, so the rule's default stays right rather than being relaxed to 'single'. barrelPolicy: "banned", // Globals are scoped per layer below instead. Node globals everywhere would let a `process.env` read in browser code lint clean. diff --git a/packages/web/package.json b/packages/web/package.json index 89f648aaf..51079bb27 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/ExaDev/documents.js/issues" }, "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "engines": { "node": ">=20" }, diff --git a/packages/wpd-codec/eslint.config.ts b/packages/wpd-codec/eslint.config.ts index 1233f742d..48905136b 100644 --- a/packages/wpd-codec/eslint.config.ts +++ b/packages/wpd-codec/eslint.config.ts @@ -2,7 +2,15 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/no-shadow", + "@typescript-eslint/strict-boolean-expressions", + "@typescript-eslint/strict-void-return", + ], isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own WordPerfect prefix/function-code parser genuinely mutates a handful of array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", // Passed to the shared config rather than declared here, because flat config replaces a same-key rule instead of merging it: a second no-restricted-imports over runtime src would silently drop the Worker-isomorphism Node-builtin ban while still reporting these. // // This package hand-writes the WordPerfect prefix/function-code parser against Corel's own published File Format SDK, the same bet markdown-codec makes against micromark and pdf-codec makes against pdf-lib. The only existing readers for this family are native or another-language libraries (libwpd is LGPL C++, WP_Reader is C#), so depending on one would defeat both the reason this package exists and the family's MIT licensing. diff --git a/packages/wpd-codec/package.json b/packages/wpd-codec/package.json index 89edb656e..2b6db88a0 100644 --- a/packages/wpd-codec/package.json +++ b/packages/wpd-codec/package.json @@ -78,7 +78,7 @@ "zod" ], "license": "MIT", - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "archive-codec": "1.11.3", "document-schema.js": "7.11.2", diff --git a/packages/xls-codec/eslint.config.ts b/packages/xls-codec/eslint.config.ts index d55796dac..29ed93949 100644 --- a/packages/xls-codec/eslint.config.ts +++ b/packages/xls-codec/eslint.config.ts @@ -2,7 +2,19 @@ import { packageLintConfig } from "../../eslint.shared.ts"; export default packageLintConfig({ tsconfigRootDir: import.meta.dirname, + // Off: 781 sites across every package are debt from this same @exadev/eslint-config 2.1.2->2.12.1 bump (see PackageLintOptions.newRuleDebt in eslint.shared.ts), not something this bump's own PR fixes. This package's own measured subset: + newRuleDebt: [ + "@typescript-eslint/consistent-return", + "@typescript-eslint/method-signature-style", + "@typescript-eslint/no-shadow", + "@typescript-eslint/no-use-before-define", + "@typescript-eslint/strict-boolean-expressions", + "@typescript-eslint/switch-exhaustiveness-check", + "tsdoc/syntax", + ], isomorphic: true, + // Off: see PackageLintOptions.preferReadonlyParams in eslint.shared.ts for why -- this package's own BIFF8 record readers/writers genuinely mutate a large number of array/object parameters in place. Tracked for burn-down. + preferReadonlyParams: "off", additionalRestrictedImportPatterns: [ { group: ["xlsx", "xlsx/**", "node-xlsx", "exceljs", "cfb", "cfb/**"], diff --git a/packages/xls-codec/package.json b/packages/xls-codec/package.json index 30760e65e..c8689fb7a 100644 --- a/packages/xls-codec/package.json +++ b/packages/xls-codec/package.json @@ -68,7 +68,7 @@ "_test:smoke": "vitest run --project smoke", "prepare": "husky" }, - "packageManager": "pnpm@11.6.0", + "packageManager": "pnpm@12.4.1+sha512.2e81e399d73fe8390dab25e06aa788ab7a5908248d2f5a370f82b481147a6a7a367bf8048f9a6fdb6460f21a66f0542dedb8b94ca2c8723596741920b1656d4c", "dependencies": { "archive-codec": "1.11.3", "document-schema.js": "7.11.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 42ce69f33..e76cd11d4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,3 +1,161 @@ +--- +lockfileVersion: '9.0' + +importers: + + .: + configDependencies: {} + packageManagerDependencies: + pnpm: + specifier: 12.4.1 + version: 12.4.1 + +packages: + + '@pnpm/exe.android-arm64@12.4.1': + resolution: {integrity: sha512-/HwsqXMSmlOfgtV9+O0ratzjV6Vd/8n1hh4rGHpCGmDURvt52MwZxdbhyxP4K03ZfvgSDvotFPr8O+RzE5Eu8A==} + cpu: [arm64] + os: [android] + + '@pnpm/exe.android-x64@12.4.1': + resolution: {integrity: sha512-+l74Qb4c2YjOzNKHXJLg+1wr8xHM1ckkUhnU5KRUK9TJqiiczt6yeTZqqzHIlJ8i6pAoj5V0OJevDRwnQKLgrQ==} + cpu: [x64] + os: [android] + + '@pnpm/exe.darwin-arm64@12.4.1': + resolution: {integrity: sha512-6rkZkT3iGfaxknUdGHraqSWFvTa6N0ajAHluv9Ax0GRWs0sIcGNiFhDopv6xSZCsJZmG483aNS/b6UEDy3blfw==} + cpu: [arm64] + os: [darwin] + + '@pnpm/exe.darwin-x64@12.4.1': + resolution: {integrity: sha512-Vb1CHlR88HghC1qUxjxjs82zQSXnXacPD+btG2CmG8Q/hBU7Q0/b2YWJKSQqZXicunV5khFtfTlAwJddV9RkYA==} + cpu: [x64] + os: [darwin] + + '@pnpm/exe.freebsd-x64@12.4.1': + resolution: {integrity: sha512-iT3iHz3Nl0Sxxj7UPOtZ/aQ81AFsQhjoeWMAlPkSRO04gsgDGAXv3UYxOFaesMWsfNxaGn0A+CITbuCHFF66FA==} + cpu: [x64] + os: [freebsd] + + '@pnpm/exe.linux-arm64-musl@12.4.1': + resolution: {integrity: sha512-aBooZfNXM5f+OGUgCAMFWpE/kAhsWfvmqIyMtHy6zl3aNxyInWrcY/Saln/UElzo7lZWMC0Yktroxd/2J26lNQ==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-arm64@12.4.1': + resolution: {integrity: sha512-TlOdacTTP09BgcMvwWBFRsu8VAjfwqwnslBj+XSq1JFM3ck4f3k+1O/747EuctxZxs3/o785b6Q3s7Pd92Ptsg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-ppc64@12.4.1': + resolution: {integrity: sha512-r/ab/MlIBo75oizUP5ITiziCCrnXz4SJwfErLQ+603AshB+Yq7xTMCoMtzTSCAMu6aaymIKkAFtZvd2J75Wq0w==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-riscv64@12.4.1': + resolution: {integrity: sha512-C/D1QWdKMiB8+wv/spl1rGITFUuqC+aI/fb6h8NB5sqxsOaGXeYc/g891oCuzggHn6SODk9p+I09hI76x/cMNw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-s390x@12.4.1': + resolution: {integrity: sha512-nxz5zD4yXt94uzbStDk0QTPKW+aE92hH1b5tFXK9ctB1HE9Xcq1vjTiA2LsZMFC6p4gdu5OwQeFqYNAVGa6QlA==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-x64-musl@12.4.1': + resolution: {integrity: sha512-5AwgFdGhVUg2kIweYGfxzSLEHiIG77PQhZAkXC3TwofQHsu1Wr+TrV5/rNX2PopFnHRzuE581zoB8F6Wle32yg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-x64@12.4.1': + resolution: {integrity: sha512-FJOZuuuQMhp0oLzBtcKkLXknBI92hfkmSnlKc47vfin4HrmfID5khY2lGekL9tCzk1cpR+HShEw/meFl+nHtzQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.win32-arm64@12.4.1': + resolution: {integrity: sha512-OO7eKBL9S+xk5hRy+JUUZSNJknGuGe3GEUffsrlC2LbqKF02g+VX1anGIzSbJDvkkdnpJhSlxF5AUz2JzJu2Jw==} + cpu: [arm64] + os: [win32] + + '@pnpm/exe.win32-x64@12.4.1': + resolution: {integrity: sha512-x7gJHZgHo6hp354xCYA2NvoFzYJkHwovt2kVsUBK5EmXULLcP51JGMq09CX+5FRFJUZFKoXjLu3mZWmfP7o6PQ==} + cpu: [x64] + os: [win32] + + pnpm@12.4.1: + resolution: {integrity: sha512-LoHjmdc/6DkNqyXgaqeIq3pZCCSNL1o3D4K0gRR6ano2e/gEj5pv22Rg8hpm8FQt7bi5TKLIcjWWdBkgsWVtTA==} + engines: {node: '>=18.*'} + hasBin: true + +snapshots: + + '@pnpm/exe.android-arm64@12.4.1': + optional: true + + '@pnpm/exe.android-x64@12.4.1': + optional: true + + '@pnpm/exe.darwin-arm64@12.4.1': + optional: true + + '@pnpm/exe.darwin-x64@12.4.1': + optional: true + + '@pnpm/exe.freebsd-x64@12.4.1': + optional: true + + '@pnpm/exe.linux-arm64-musl@12.4.1': + optional: true + + '@pnpm/exe.linux-arm64@12.4.1': + optional: true + + '@pnpm/exe.linux-ppc64@12.4.1': + optional: true + + '@pnpm/exe.linux-riscv64@12.4.1': + optional: true + + '@pnpm/exe.linux-s390x@12.4.1': + optional: true + + '@pnpm/exe.linux-x64-musl@12.4.1': + optional: true + + '@pnpm/exe.linux-x64@12.4.1': + optional: true + + '@pnpm/exe.win32-arm64@12.4.1': + optional: true + + '@pnpm/exe.win32-x64@12.4.1': + optional: true + + pnpm@12.4.1: + optionalDependencies: + '@pnpm/exe.android-arm64': 12.4.1 + '@pnpm/exe.android-x64': 12.4.1 + '@pnpm/exe.darwin-arm64': 12.4.1 + '@pnpm/exe.darwin-x64': 12.4.1 + '@pnpm/exe.freebsd-x64': 12.4.1 + '@pnpm/exe.linux-arm64': 12.4.1 + '@pnpm/exe.linux-arm64-musl': 12.4.1 + '@pnpm/exe.linux-ppc64': 12.4.1 + '@pnpm/exe.linux-riscv64': 12.4.1 + '@pnpm/exe.linux-s390x': 12.4.1 + '@pnpm/exe.linux-x64': 12.4.1 + '@pnpm/exe.linux-x64-musl': 12.4.1 + '@pnpm/exe.win32-arm64': 12.4.1 + '@pnpm/exe.win32-x64': 12.4.1 + +--- lockfileVersion: '9.0' settings: @@ -31,8 +189,8 @@ importers: specifier: 8.0.3 version: 8.0.3 '@exadev/eslint-config': - specifier: 2.1.2 - version: 2.1.2(eslint@10.8.1(jiti@2.7.0))(typescript-eslint@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)) + specifier: 2.12.1 + version: 2.12.1(eslint-plugin-jsx-a11y@6.10.2(eslint@10.8.1(jiti@2.7.0)))(eslint-plugin-react-hooks@7.1.1(eslint@10.8.1(jiti@2.7.0)))(eslint@10.8.1(jiti@2.7.0))(typescript-eslint@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3))(typescript@6.0.3) '@exadev/semantic-release-workspace': specifier: 1.2.3 version: 1.2.3(@semantic-release/changelog@7.0.0(semantic-release@25.0.9(typescript@6.0.3)))(@semantic-release/commit-analyzer@13.0.1(semantic-release@25.0.9(typescript@6.0.3)))(@semantic-release/git@11.0.1(semantic-release@25.0.9(typescript@6.0.3)))(@semantic-release/github@12.0.9(semantic-release@25.0.9(typescript@6.0.3)))(@semantic-release/npm@13.1.5(semantic-release@25.0.9(typescript@6.0.3)))(@semantic-release/release-notes-generator@14.1.1(semantic-release@25.0.9(typescript@6.0.3)))(semantic-release@25.0.9(typescript@6.0.3))(typescript@6.0.3) @@ -2579,6 +2737,14 @@ packages: '@emotion/hash@0.9.2': resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + '@es-joy/jsdoccomment@0.97.0': + resolution: {integrity: sha512-EP8uoFfh6+GsdGCduYtmWAW0h7AO+Ayik9Vh5YbA2r/3N6lmJKkCNZX+q3QBXC1K6ixjQ/9igF2b7WVvLm063g==} + engines: {node: ^22.22.2 || >=24.15.0} + + '@es-joy/resolve.exports@1.2.0': + resolution: {integrity: sha512-Q9hjxWI5xBM+qW2enxfe8wDKdFWMfd0Z29k5ZJnuBqD/CasY5Zryj09aCA6owbGATWz+39p5uIdaHXpopOcG8g==} + engines: {node: '>=10'} + '@esbuild/aix-ppc64@0.28.1': resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} @@ -2966,12 +3132,26 @@ packages: resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@exadev/eslint-config@2.1.2': - resolution: {integrity: sha512-isLVdlJ10wPn+O6iHAUQf+UQAfHvlaOfQYQVM2mUoPXsxKnDn66EvgFdWJUM9FrI/iFRI+bGzm3FfYJu/N+DTg==} + '@exadev/eslint-config@2.12.1': + resolution: {integrity: sha512-b5JKCX7l5onZy0i0kHdIeuiocxDoiuEwnrG6+j+EV8ZWaLpi18BDzNi1iT3tc647DFRUYJtHWDiJrkWT6E2JjQ==} engines: {node: '>=20'} peerDependencies: + '@next/eslint-plugin-next': ^16.3.2 eslint: '>=10.0.0' + eslint-plugin-jsx-a11y: ^6.10.2 + eslint-plugin-react: ^7.37.5 + eslint-plugin-react-hooks: ^7.1.1 + typescript: '>=4.8.4' typescript-eslint: '>=8.0.0' + peerDependenciesMeta: + '@next/eslint-plugin-next': + optional: true + eslint-plugin-jsx-a11y: + optional: true + eslint-plugin-react: + optional: true + eslint-plugin-react-hooks: + optional: true '@exadev/semantic-release-workspace@1.2.3': resolution: {integrity: sha512-OYbmlcLBSNJ80mq1YhY+iWAoAk+jaTWuGqNn3JGrJUoV0+Mec3RkL4dY5Zt84P35qoQDZGZkkmTDcqmQ8+oY/w==} @@ -3409,6 +3589,12 @@ packages: peerDependencies: '@mantine/core': 9.5.1 + '@microsoft/tsdoc-config@0.18.1': + resolution: {integrity: sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==} + + '@microsoft/tsdoc@0.16.0': + resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} + '@modelcontextprotocol/client@2.0.0': resolution: {integrity: sha512-8f1OghQ2rjzIOfqgUCP+8GiUWqRs89njoWLNqAe8kWmDePv3s1fZXseej+QXemssEuuOvLLmLO/kqM3IQHtISw==} engines: {node: '>=20'} @@ -4166,6 +4352,10 @@ packages: resolution: {integrity: sha512-fCTuZK4QBa+39Oz9l4OGfJfz+GpwCp3AqO7Zch3to99xHPgstVsRFpeQ8LNd2o1Gv8raL2mCFwiaHh7bFSp5DQ==} engines: {node: '>=22'} + '@sindresorhus/base62@1.0.0': + resolution: {integrity: sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA==} + engines: {node: '>=18'} + '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -4366,6 +4556,9 @@ packages: '@types/node@26.2.0': resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==} + '@types/node@26.5.1': + resolution: {integrity: sha512-CzNm2FezW4VR/LjG6yUdiEgLE/rAQ9Slj5gCu/C2VrdcW7I0ahNZ8DRbHT7zOZ6r3ONgd/bsQIeSaoDGrd1C6g==} + '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -4407,16 +4600,42 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/project-service@8.56.1': + resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/project-service@8.66.0': resolution: {integrity: sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/project-service@8.70.0': + resolution: {integrity: sha512-hFHbTNqhU9G+2eKFXCBVb1tjFT/LceiJ4+HfLO4pTpDI0KHi6iajpcFFkaSQ9gXmCh7n82A0PthaayEdN6mspQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.56.1': + resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.66.0': resolution: {integrity: sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.70.0': + resolution: {integrity: sha512-8nP3Kwh5hlgZ4FicGvmznAmJe8UL4sdU8tLukrPaMuQmDuk4Y8xYfzu/aYZW4xT2JCgc7H/TpDI5cGlxcWJSqQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.56.1': + resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/tsconfig-utils@8.66.0': resolution: {integrity: sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4429,6 +4648,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/tsconfig-utils@8.70.0': + resolution: {integrity: sha512-adnkeeNq9Sq1sUf4+FRVc0KdgYghzsgFpZSQVZVvY0LCuUuN0FnQgyGzCJeC4fW1cdXseBAjU2EOqUIjbNcZUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/type-utils@8.66.0': resolution: {integrity: sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4436,6 +4661,10 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/types@8.56.1': + resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.66.0': resolution: {integrity: sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4444,12 +4673,35 @@ packages: resolution: {integrity: sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.70.0': + resolution: {integrity: sha512-asTOIYhDg4zdzOScCyaytrsV3cR6B4ecPQlXw/dJIm7J/MZTtCtfVII9JD8Geh4jTCrK/Xe6cg5UevoleMcoJQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.56.1': + resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/typescript-estree@8.66.0': resolution: {integrity: sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/typescript-estree@8.70.0': + resolution: {integrity: sha512-d9NmHMPEKQ7QCLLm1jI3zmoQBwT5KwFYjXBJ9ymZfKCUU+5rmTRykKAFvH5Qn/ZCds3CEAFS9OC9M/jkl0X2bA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.56.1': + resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/utils@8.66.0': resolution: {integrity: sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4457,10 +4709,25 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/utils@8.70.0': + resolution: {integrity: sha512-oZmtKJz/4fufZ2p3+Cn3ijEojcdfR+1zYDH2xKYrEly0dR/Q/1xUPRCOlKGxod78nWlU2UnDe09GZ3TaknBFGA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.56.1': + resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.66.0': resolution: {integrity: sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.70.0': + resolution: {integrity: sha512-BoC8PiO4Hkdo0TVJh9Ntxr5MxPDI7/oFsrygN5ADelFSeXG/qgNuucIGA+L5Z6JpPTE/uRfcTWtscjbUaufepQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vanilla-extract/babel-plugin-debug-ids@1.2.2': resolution: {integrity: sha512-MeDWGICAF9zA/OZLOKwhoRlsUW+fiMwnfuOAqFVohL31Agj7Q/RBWAYweqjHLgFBCsdnr6XIfwjJnmb2znEWxw==} @@ -4696,6 +4963,9 @@ packages: ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ajv@8.20.0: resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} @@ -4737,6 +5007,10 @@ packages: anynum@1.0.1: resolution: {integrity: sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==} + are-docs-informative@0.1.1: + resolution: {integrity: sha512-sqRsNQBwbKLRX0jV5Cu5uzmtflf892n4Vukz7T659ebL4pz3mpOqCMU7lxMoBTFwnp10E3YB5ZcyHM41W5bcDA==} + engines: {node: '>=18'} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -5017,6 +5291,10 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} + comment-parser@1.4.8: + resolution: {integrity: sha512-rKZTGo4fzKYna8UcL0isTg5wkBNla7bxTypLwZQXjIdi++IdP1OJ41rI5Mti3/jltkPujbu4i9LIARYA+zpotQ==} + engines: {node: '>= 12.0.0'} + common-tags@1.8.2: resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} engines: {node: '>=4.0.0'} @@ -5398,6 +5676,12 @@ packages: peerDependencies: eslint: '>=8.40.0' + eslint-plugin-jsdoc@64.3.6: + resolution: {integrity: sha512-lo7IXmgUUNy88SxW7KnJmmD2iPQBIRMomfCFPHidW1M3zNNVuzxlB2uoNrNyE1g4v2/L+RtYmiROPwQhSNzL8Q==} + engines: {node: ^22.22.2 || >=24.15.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + eslint-plugin-jsx-a11y@6.10.2: resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} engines: {node: '>=4.0'} @@ -5429,6 +5713,9 @@ packages: peerDependencies: eslint: ^9 || ^10 + eslint-plugin-tsdoc@0.5.2: + resolution: {integrity: sha512-BlvqjWZdBJDIPO/YU3zcPCF23CvjYT3gyu63yo6b609NNV3D1b6zceAREy2xnweuBoDpZcLNuPyAUq9cvx6bbQ==} + eslint-plugin-yml@3.8.1: resolution: {integrity: sha512-E/70psRwxz5EJ8dBtzrFfqSiiInuSytbdtFCjueb/GcKjsWzPBfxfhtQePImMAPjHwMA/VDurO7DJwStDJ4wWg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} @@ -5846,6 +6133,9 @@ packages: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-entities@2.6.0: + resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -6169,6 +6459,9 @@ packages: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + jose@6.2.9: resolution: {integrity: sha512-XrchZOFZUl/T3vTwRe8XK+cJrGtMF4th1ARnDfwbBXFKThGhlsxEE4Zu03AD/bjJSt/9jT/mxrOCkJWOg77aPA==} @@ -6185,6 +6478,10 @@ packages: resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} hasBin: true + jsdoc-type-pratt-parser@9.2.1: + resolution: {integrity: sha512-V4Ww4EHnTcTLSOMoB0FsF72JhQvcAsriCm/LWnxJeGWoxIjEL2l9na11abQok5SYShq8m0Gl02el/xAbTCulvQ==} + engines: {node: ^22.22.2 || >=24.15.0} + jsdom@30.0.1: resolution: {integrity: sha512-52v7mUVUfNQVYYqE1lcdaymWL0njO7lTLUog6ZvW2U5KsbiLk/GnZlVJ+qx0xfNJZ6Gn+KSpPNE52vurbxZwrA==} engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} @@ -6782,6 +7079,9 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + object-deep-merge@2.0.1: + resolution: {integrity: sha512-aKttDKcU3pyZqKcCkDhsMn70WmZFG2JGDQLP9EcLyTSIFQRCPWLAmBZRLJnrVUrhPG1jETEEbfdgbNtJf1LyMg==} + object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -6886,6 +7186,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-imports-exports@0.2.4: + resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + parse-json@4.0.0: resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} @@ -6902,6 +7205,9 @@ packages: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} + parse-statements@1.0.11: + resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} + parse5-htmlparser2-tree-adapter@6.0.1: resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} @@ -7204,6 +7510,10 @@ packages: require-like@0.1.2: resolution: {integrity: sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==} + reserved-identifiers@1.2.0: + resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==} + engines: {node: '>=18'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -7423,6 +7733,9 @@ packages: spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + spdx-expression-parse@5.0.0: + resolution: {integrity: sha512-vngmw3Rgn+o2arXNbnZaj5UtOEBuWBfvaI+Wc8GFfykIhA5/vdK9/Sp/XkLv63dykz2rxKDvKEHupF5P0FORcQ==} + spdx-license-ids@3.0.23: resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} @@ -7680,6 +7993,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + to-valid-identifier@1.0.0: + resolution: {integrity: sha512-41wJyvKep3yT2tyPqX/4blcfybknGB4D+oETKLs7Q76UiPqRpUJK3hr1nxelyYO0PHKVzJwlu0aCeEAsGI6rpw==} + engines: {node: '>=20'} + tough-cookie@6.0.2: resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} engines: {node: '>=16'} @@ -7837,6 +8154,9 @@ packages: undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + undici-types@8.9.0: + resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==} + undici@6.28.0: resolution: {integrity: sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==} engines: {node: '>=18.17'} @@ -9553,6 +9873,16 @@ snapshots: '@emotion/hash@0.9.2': {} + '@es-joy/jsdoccomment@0.97.0': + dependencies: + '@types/estree': 1.0.9 + '@typescript-eslint/types': 8.70.0 + comment-parser: 1.4.8 + esquery: 1.7.0 + jsdoc-type-pratt-parser: 9.2.1 + + '@es-joy/resolve.exports@1.2.0': {} + '@esbuild/aix-ppc64@0.28.1': optional: true @@ -9810,10 +10140,21 @@ snapshots: '@eslint/core': 1.2.1 levn: 0.4.1 - '@exadev/eslint-config@2.1.2(eslint@10.8.1(jiti@2.7.0))(typescript-eslint@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3))': + '@exadev/eslint-config@2.12.1(eslint-plugin-jsx-a11y@6.10.2(eslint@10.8.1(jiti@2.7.0)))(eslint-plugin-react-hooks@7.1.1(eslint@10.8.1(jiti@2.7.0)))(eslint@10.8.1(jiti@2.7.0))(typescript-eslint@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3))(typescript@6.0.3)': dependencies: + '@eslint/js': 10.0.1(eslint@10.8.1(jiti@2.7.0)) + '@typescript-eslint/utils': 8.70.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) eslint: 10.8.1(jiti@2.7.0) + eslint-plugin-jsdoc: 64.3.6(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-tsdoc: 0.5.2(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 typescript-eslint: 8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + optionalDependencies: + eslint-plugin-jsx-a11y: 6.10.2(eslint@10.8.1(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.1.1(eslint@10.8.1(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color '@exadev/semantic-release-workspace@1.2.3(@semantic-release/changelog@7.0.0(semantic-release@25.0.9(typescript@6.0.3)))(@semantic-release/commit-analyzer@13.0.1(semantic-release@25.0.9(typescript@6.0.3)))(@semantic-release/git@11.0.1(semantic-release@25.0.9(typescript@6.0.3)))(@semantic-release/github@12.0.9(semantic-release@25.0.9(typescript@6.0.3)))(@semantic-release/npm@13.1.5(semantic-release@25.0.9(typescript@6.0.3)))(@semantic-release/release-notes-generator@14.1.1(semantic-release@25.0.9(typescript@6.0.3)))(semantic-release@25.0.9(typescript@6.0.3))(typescript@6.0.3)': dependencies: @@ -10183,6 +10524,15 @@ snapshots: dependencies: '@mantine/core': 9.5.1(@mantine/hooks@9.5.1(react@19.2.8))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@microsoft/tsdoc-config@0.18.1': + dependencies: + '@microsoft/tsdoc': 0.16.0 + ajv: 8.18.0 + jju: 1.4.0 + resolve: 1.22.12 + + '@microsoft/tsdoc@0.16.0': {} + '@modelcontextprotocol/client@2.0.0': dependencies: '@modelcontextprotocol/core': 2.0.0 @@ -10807,6 +11157,8 @@ snapshots: '@simple-libs/stream-utils@2.0.0': {} + '@sindresorhus/base62@1.0.0': {} + '@sindresorhus/is@4.6.0': {} '@sindresorhus/is@7.2.0': {} @@ -11058,6 +11410,10 @@ snapshots: dependencies: undici-types: 8.3.0 + '@types/node@26.5.1': + dependencies: + undici-types: 8.9.0 + '@types/normalize-package-data@2.4.4': {} '@types/react-dom@19.2.4(@types/react@19.2.18)': @@ -11106,6 +11462,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.56.1(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) + '@typescript-eslint/types': 8.67.0 + debug: 4.4.3 + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/project-service@8.66.0(typescript@6.0.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.67.0(typescript@6.0.3) @@ -11115,11 +11480,34 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.70.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.70.0(typescript@6.0.3) + '@typescript-eslint/types': 8.70.0 + debug: 4.4.3 + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.56.1': + dependencies: + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/scope-manager@8.66.0': dependencies: '@typescript-eslint/types': 8.66.0 '@typescript-eslint/visitor-keys': 8.66.0 + '@typescript-eslint/scope-manager@8.70.0': + dependencies: + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/visitor-keys': 8.70.0 + + '@typescript-eslint/tsconfig-utils@8.56.1(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + '@typescript-eslint/tsconfig-utils@8.66.0(typescript@6.0.3)': dependencies: typescript: 6.0.3 @@ -11128,6 +11516,10 @@ snapshots: dependencies: typescript: 6.0.3 + '@typescript-eslint/tsconfig-utils@8.70.0(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + '@typescript-eslint/type-utils@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.66.0 @@ -11140,10 +11532,29 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/types@8.56.1': {} + '@typescript-eslint/types@8.66.0': {} '@typescript-eslint/types@8.67.0': {} + '@typescript-eslint/types@8.70.0': {} + + '@typescript-eslint/typescript-estree@8.56.1(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.56.1(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@6.0.3) + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/visitor-keys': 8.56.1 + debug: 4.4.3 + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/typescript-estree@8.66.0(typescript@6.0.3)': dependencies: '@typescript-eslint/project-service': 8.66.0(typescript@6.0.3) @@ -11159,6 +11570,32 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.70.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.70.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.70.0(typescript@6.0.3) + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/visitor-keys': 8.70.0 + debug: 4.4.3 + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.56.1(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.56.1 + '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/typescript-estree': 8.56.1(typescript@6.0.3) + eslint: 10.8.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.66.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)) @@ -11170,11 +11607,32 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.70.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@10.8.1(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.70.0 + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/typescript-estree': 8.70.0(typescript@6.0.3) + eslint: 10.8.1(jiti@2.7.0) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.56.1': + dependencies: + '@typescript-eslint/types': 8.56.1 + eslint-visitor-keys: 5.0.1 + '@typescript-eslint/visitor-keys@8.66.0': dependencies: '@typescript-eslint/types': 8.66.0 eslint-visitor-keys: 5.0.1 + '@typescript-eslint/visitor-keys@8.70.0': + dependencies: + '@typescript-eslint/types': 8.70.0 + eslint-visitor-keys: 5.0.1 + '@vanilla-extract/babel-plugin-debug-ids@1.2.2': dependencies: '@babel/core': 7.29.7 @@ -11420,6 +11878,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 @@ -11453,6 +11918,8 @@ snapshots: anynum@1.0.1: {} + are-docs-informative@0.1.1: {} + argparse@2.0.1: {} argue-cli@3.1.0: {} @@ -11733,6 +12200,8 @@ snapshots: commander@8.3.0: {} + comment-parser@1.4.8: {} + common-tags@1.8.2: {} compare-func@2.0.0: @@ -12170,6 +12639,28 @@ snapshots: module-replacements: 2.11.0 semver: 7.8.5 + eslint-plugin-jsdoc@64.3.6(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@es-joy/jsdoccomment': 0.97.0 + '@es-joy/resolve.exports': 1.2.0 + '@typescript-eslint/utils': 8.70.0(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + are-docs-informative: 0.1.1 + comment-parser: 1.4.8 + debug: 4.4.3 + escape-string-regexp: 5.0.0 + eslint: 10.8.1(jiti@2.7.0) + espree: 11.2.0 + esquery: 1.7.0 + html-entities: 2.6.0 + object-deep-merge: 2.0.1 + parse-imports-exports: 0.2.4 + semver: 7.8.5 + spdx-expression-parse: 5.0.0 + to-valid-identifier: 1.0.0 + transitivePeerDependencies: + - supports-color + - typescript + eslint-plugin-jsx-a11y@6.10.2(eslint@10.8.1(jiti@2.7.0)): dependencies: aria-query: 5.3.2 @@ -12213,6 +12704,16 @@ snapshots: dependencies: eslint: 10.8.1(jiti@2.7.0) + eslint-plugin-tsdoc@0.5.2(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3): + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@typescript-eslint/utils': 8.56.1(eslint@10.8.1(jiti@2.7.0))(typescript@6.0.3) + transitivePeerDependencies: + - eslint + - supports-color + - typescript + eslint-plugin-yml@3.8.1(eslint@10.8.1(jiti@2.7.0)): dependencies: '@eslint/core': 1.2.1 @@ -12715,6 +13216,8 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' + html-entities@2.6.0: {} + html-escaper@2.0.2: {} http-proxy-agent@9.1.0: @@ -13021,6 +13524,8 @@ snapshots: jiti@2.7.0: {} + jju@1.4.0: {} + jose@6.2.9: {} js-md4@0.3.2: {} @@ -13033,6 +13538,11 @@ snapshots: dependencies: argparse: 2.0.1 + jsdoc-type-pratt-parser@9.2.1: + dependencies: + '@types/estree': 1.0.9 + '@types/node': 26.5.1 + jsdom@30.0.1: dependencies: '@asamuzakjp/css-color': 6.0.7 @@ -13754,6 +14264,8 @@ snapshots: object-assign@4.1.1: {} + object-deep-merge@2.0.1: {} + object-inspect@1.13.4: {} object-keys@1.1.1: {} @@ -13897,6 +14409,10 @@ snapshots: dependencies: callsites: 3.1.0 + parse-imports-exports@0.2.4: + dependencies: + parse-statements: 1.0.11 + parse-json@4.0.0: dependencies: error-ex: 1.3.4 @@ -13917,6 +14433,8 @@ snapshots: parse-ms@4.0.0: {} + parse-statements@1.0.11: {} + parse5-htmlparser2-tree-adapter@6.0.1: dependencies: parse5: 6.0.1 @@ -14200,6 +14718,8 @@ snapshots: require-like@0.1.2: {} + reserved-identifiers@1.2.0: {} + resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -14512,6 +15032,11 @@ snapshots: spdx-exceptions: 2.5.0 spdx-license-ids: 3.0.23 + spdx-expression-parse@5.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 + spdx-license-ids@3.0.23: {} split2@1.0.0: @@ -14772,6 +15297,11 @@ snapshots: dependencies: is-number: 7.0.0 + to-valid-identifier@1.0.0: + dependencies: + '@sindresorhus/base62': 1.0.0 + reserved-identifiers: 1.2.0 + tough-cookie@6.0.2: dependencies: tldts: 7.4.10 @@ -14925,6 +15455,8 @@ snapshots: undici-types@8.3.0: {} + undici-types@8.9.0: {} + undici@6.28.0: {} undici@7.29.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 85ef73c1c..6758f3272 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -53,3 +53,5 @@ overrides: qs: 6.15.2 # release-workspace.config.json's generateNotes step uses the conventionalcommits preset, whose templates call a helper that only conventional-changelog-writer@9 or newer provides. @semantic-release/release-notes-generator depends on conventional-changelog-writer@^8, so without this the preset loads and then throws from inside handlebars at render time -- the preset itself detects the too-old writer and registers a helper whose only job is to raise "requires conventional-changelog-writer@9 or newer". Scoped to release-notes-generator rather than global because it is the only consumer that renders with the writer at all: @semantic-release/commit-analyzer declares the same dependency but never imports it, using only the preset's whatBump. "@semantic-release/release-notes-generator>conventional-changelog-writer": 9.2.1 + +saveExact: true diff --git a/release-workspace.config.test.ts b/release-workspace.config.test.ts index 3a56e8ad9..7211b0ff6 100644 --- a/release-workspace.config.test.ts +++ b/release-workspace.config.test.ts @@ -9,7 +9,7 @@ import config from "./release-workspace.config"; * * These tests make that agreement mechanical rather than a convention someone has to remember, which is the same invariant commitlint.config.ts already relies on from the other direction: a type cannot trigger a release without also being accepted by commit-msg validation, or the reverse. * - * analyzeCommits/generateNotes are typed as Record in @exadev/semantic-release-workspace's own ReleaseWorkspaceOptions -- they are passed straight through to @semantic-release/commit-analyzer and @semantic-release/release-notes-generator, whose own option shapes this SDK does not model -- so TypeScript cannot enforce the releaseRules/presetConfig.types agreement on its own, and the runtime narrowing below is still load-bearing. + * analyzeCommits/generateNotes are typed as `Record` in \@exadev/semantic-release-workspace's own ReleaseWorkspaceOptions -- they are passed straight through to \@semantic-release/commit-analyzer and \@semantic-release/release-notes-generator, whose own option shapes this SDK does not model -- so TypeScript cannot enforce the releaseRules/presetConfig.types agreement on its own, and the runtime narrowing below is still load-bearing. */ const CONFIG_FILE = "release-workspace.config.ts"; diff --git a/stryker.shared.ts b/stryker.shared.ts index ea8d39b7c..868023c92 100644 --- a/stryker.shared.ts +++ b/stryker.shared.ts @@ -29,7 +29,7 @@ export interface PackageStrykerOptions { /** * The mutation-testing configuration every package in this workspace shares, as a function rather than a static object -- mirroring eslint.shared.ts's own packageLintConfig, for the same reason: the real per-package variation (which vitest config actually reflects the unit suite alone, whether a package's tsconfig needs a non-default path) is structural, not cosmetic, so it is parameterised here rather than duplicated as near-identical JSON in every package. * - * Deliberately a real .ts file, not stryker.config.mjs with a `@type` JSDoc annotation (Stryker's own documented pattern): Stryker's own config loader is a plain `import()` under the hood (see ConfigReader#importJSConfig in @stryker-mutator/core) with no opinion at all about the extension it is given, and Node's own ESM loader on this workspace's pinned version strips a .ts file's type syntax natively with no flag and no loader hook — so each package's own `stryker run stryker.config.ts` (its `_test:mutation` script) resolves straight through that native support to this shared function, with no shim file, and Stryker's own option validation still runs afterward exactly as it would for a .js config. + * Deliberately a real .ts file, not stryker.config.mjs with a `@type` JSDoc annotation (Stryker's own documented pattern): Stryker's own config loader is a plain `import()` under the hood (see ConfigReader#importJSConfig in \@stryker-mutator/core) with no opinion at all about the extension it is given, and Node's own ESM loader on this workspace's pinned version strips a .ts file's type syntax natively with no flag and no loader hook — so each package's own `stryker run stryker.config.ts` (its `_test:mutation` script) resolves straight through that native support to this shared function, with no shim file, and Stryker's own option validation still runs afterward exactly as it would for a .js config. */ export function packageStrykerConfig( options: PackageStrykerOptions = {},