From 0b278dd96ee272e2f3295237c9848b5d47edba00 Mon Sep 17 00:00:00 2001 From: Christopher Pruijsen Date: Thu, 10 Sep 2026 21:37:15 +0100 Subject: [PATCH 1/3] fix(eslint-plugin-tsdoc): declare eslint as a peer dependency Published typings import from 'eslint', so consumers under pnpm and Yarn PnP need it declared for TypeScript to resolve against the consumer's ESLint. --- .../fix-issue-479_2026-09-10-21-24.json | 10 ++++ eslint-plugin/package.json | 3 ++ eslint-plugin/src/tests/package.test.ts | 49 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 common/changes/eslint-plugin-tsdoc/fix-issue-479_2026-09-10-21-24.json create mode 100644 eslint-plugin/src/tests/package.test.ts diff --git a/common/changes/eslint-plugin-tsdoc/fix-issue-479_2026-09-10-21-24.json b/common/changes/eslint-plugin-tsdoc/fix-issue-479_2026-09-10-21-24.json new file mode 100644 index 00000000..a468348b --- /dev/null +++ b/common/changes/eslint-plugin-tsdoc/fix-issue-479_2026-09-10-21-24.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "eslint-plugin-tsdoc", + "comment": "Declare `eslint` as a peer dependency so published typings resolve against the consumer's ESLint under non-hoisted installers.", + "type": "patch" + } + ], + "packageName": "eslint-plugin-tsdoc" +} diff --git a/eslint-plugin/package.json b/eslint-plugin/package.json index c8273c9d..89117582 100644 --- a/eslint-plugin/package.json +++ b/eslint-plugin/package.json @@ -31,6 +31,9 @@ "@microsoft/tsdoc": "workspace:*", "@typescript-eslint/utils": "~8.56.0" }, + "peerDependencies": { + "eslint": ">=7" + }, "devDependencies": { "tsdoc-build-rig": "workspace:*", "@rushstack/heft": "1.2.7", diff --git a/eslint-plugin/src/tests/package.test.ts b/eslint-plugin/src/tests/package.test.ts new file mode 100644 index 00000000..63ae04cc --- /dev/null +++ b/eslint-plugin/src/tests/package.test.ts @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +interface IPackageJson { + dependencies?: { [name: string]: string }; + peerDependencies?: { [name: string]: string }; +} + +function getPackageName(moduleSpecifier: string): string { + if (moduleSpecifier.startsWith('@')) { + return moduleSpecifier.split('/').slice(0, 2).join('/'); + } + return moduleSpecifier.split('/')[0]; +} + +function collectImportedPackageNames(sourceText: string): string[] { + const importRegExp: RegExp = /(?:from|import)\s+['"]([^'"]+)['"]/g; + const packageNames: string[] = []; + for (const regExpMatch of sourceText.matchAll(importRegExp)) { + const moduleSpecifier: string | undefined = regExpMatch[1]; + if (!moduleSpecifier || moduleSpecifier.startsWith('.') || moduleSpecifier.startsWith('node:')) { + continue; + } + packageNames.push(getPackageName(moduleSpecifier)); + } + return packageNames; +} + +test('published typings import only packages declared as dependencies or peerDependencies', () => { + const packageJsonPath: string = path.join(__dirname, '..', '..', 'package.json'); + const packageJsonText: string = fs.readFileSync(packageJsonPath, { encoding: 'utf8' }); + const packageJson: IPackageJson = JSON.parse(packageJsonText) as IPackageJson; + + const declaredPackageNames: Set = new Set([ + ...Object.keys(packageJson.dependencies ?? {}), + ...Object.keys(packageJson.peerDependencies ?? {}) + ]); + + const typingsPath: string = path.join(__dirname, '..', 'index.d.ts'); + const typingsText: string = fs.readFileSync(typingsPath, { encoding: 'utf8' }); + const missingPackageNames: string[] = collectImportedPackageNames(typingsText).filter( + (packageName: string) => !declaredPackageNames.has(packageName) + ); + + expect(missingPackageNames).toEqual([]); +}); From 32f3eba7488126027ab4362716dd262e26e3df11 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Mon, 14 Sep 2026 14:43:36 -0400 Subject: [PATCH 2/3] Make the peerDependency optional. Co-authored-by: Ian Clanton-Thuon --- .../fix-issue-479_2026-09-10-21-24.json | 2 +- eslint-plugin/package.json | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/common/changes/eslint-plugin-tsdoc/fix-issue-479_2026-09-10-21-24.json b/common/changes/eslint-plugin-tsdoc/fix-issue-479_2026-09-10-21-24.json index a468348b..52f4235c 100644 --- a/common/changes/eslint-plugin-tsdoc/fix-issue-479_2026-09-10-21-24.json +++ b/common/changes/eslint-plugin-tsdoc/fix-issue-479_2026-09-10-21-24.json @@ -2,7 +2,7 @@ "changes": [ { "packageName": "eslint-plugin-tsdoc", - "comment": "Declare `eslint` as a peer dependency so published typings resolve against the consumer's ESLint under non-hoisted installers.", + "comment": "Declare `eslint` as an optional peer dependency so published typings resolve against the consumer's ESLint under non-hoisted installers.", "type": "patch" } ], diff --git a/eslint-plugin/package.json b/eslint-plugin/package.json index 89117582..5d1583a9 100644 --- a/eslint-plugin/package.json +++ b/eslint-plugin/package.json @@ -31,6 +31,13 @@ "@microsoft/tsdoc": "workspace:*", "@typescript-eslint/utils": "~8.56.0" }, + "peerDependencies": { + "eslint": ">=7" + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + }, "peerDependencies": { "eslint": ">=7" }, From 2b96595dfcbc0fbbed280429a140b65924ef7003 Mon Sep 17 00:00:00 2001 From: Ian Clanton-Thuon Date: Mon, 14 Sep 2026 12:04:36 -0700 Subject: [PATCH 3/3] Apply suggestion from @iclanton --- eslint-plugin/package.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/eslint-plugin/package.json b/eslint-plugin/package.json index 5d1583a9..3ece523a 100644 --- a/eslint-plugin/package.json +++ b/eslint-plugin/package.json @@ -31,8 +31,6 @@ "@microsoft/tsdoc": "workspace:*", "@typescript-eslint/utils": "~8.56.0" }, - "peerDependencies": { - "eslint": ">=7" "peerDependenciesMeta": { "eslint": { "optional": true