@api-extractor-tools/eslint-plugin 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +183 -0
- package/api-extractor.json +10 -0
- package/dist/configs/index.d.ts +6 -0
- package/dist/configs/index.d.ts.map +1 -0
- package/dist/configs/index.js +11 -0
- package/dist/configs/index.js.map +1 -0
- package/dist/configs/recommended.d.ts +31 -0
- package/dist/configs/recommended.d.ts.map +1 -0
- package/dist/configs/recommended.js +45 -0
- package/dist/configs/recommended.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +68 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/index.d.ts +14 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +20 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/missing-release-tag.d.ts +8 -0
- package/dist/rules/missing-release-tag.d.ts.map +1 -0
- package/dist/rules/missing-release-tag.js +148 -0
- package/dist/rules/missing-release-tag.js.map +1 -0
- package/dist/rules/override-keyword.d.ts +8 -0
- package/dist/rules/override-keyword.d.ts.map +1 -0
- package/dist/rules/override-keyword.js +106 -0
- package/dist/rules/override-keyword.js.map +1 -0
- package/dist/rules/package-documentation.d.ts +8 -0
- package/dist/rules/package-documentation.d.ts.map +1 -0
- package/dist/rules/package-documentation.js +70 -0
- package/dist/rules/package-documentation.js.map +1 -0
- package/dist/types.d.ts +90 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/config-loader.d.ts +47 -0
- package/dist/utils/config-loader.d.ts.map +1 -0
- package/dist/utils/config-loader.js +163 -0
- package/dist/utils/config-loader.js.map +1 -0
- package/dist/utils/entry-point.d.ts +56 -0
- package/dist/utils/entry-point.d.ts.map +1 -0
- package/dist/utils/entry-point.js +198 -0
- package/dist/utils/entry-point.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +21 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/tsdoc-parser.d.ts +58 -0
- package/dist/utils/tsdoc-parser.d.ts.map +1 -0
- package/dist/utils/tsdoc-parser.js +137 -0
- package/dist/utils/tsdoc-parser.js.map +1 -0
- package/package.json +44 -0
- package/src/configs/index.ts +6 -0
- package/src/configs/recommended.ts +46 -0
- package/src/index.ts +111 -0
- package/src/rules/index.ts +18 -0
- package/src/rules/missing-release-tag.ts +203 -0
- package/src/rules/override-keyword.ts +139 -0
- package/src/rules/package-documentation.ts +90 -0
- package/src/types.ts +104 -0
- package/src/utils/config-loader.ts +194 -0
- package/src/utils/entry-point.ts +247 -0
- package/src/utils/index.ts +17 -0
- package/src/utils/tsdoc-parser.ts +163 -0
- package/temp/eslint-plugin.api.md +118 -0
- package/test/index.test.ts +66 -0
- package/test/rules/missing-release-tag.test.ts +184 -0
- package/test/rules/override-keyword.test.ts +171 -0
- package/test/rules/package-documentation.test.ts +152 -0
- package/test/tsconfig.json +11 -0
- package/test/utils/config-loader.test.ts +199 -0
- package/test/utils/entry-point.test.ts +172 -0
- package/test/utils/tsdoc-parser.test.ts +113 -0
- package/tsconfig.json +12 -0
- package/vitest.config.mts +25 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the API Extractor ESLint plugin.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Log levels supported by API Extractor message configuration.
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
export type ApiExtractorLogLevel = 'error' | 'warning' | 'none'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration for a single message type in API Extractor.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export interface MessageConfig {
|
|
18
|
+
logLevel: ApiExtractorLogLevel
|
|
19
|
+
addToApiReportFile?: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The messages configuration section from api-extractor.json.
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export interface ApiExtractorMessagesConfig {
|
|
27
|
+
compilerMessageReporting?: {
|
|
28
|
+
default?: MessageConfig
|
|
29
|
+
[messageId: string]: MessageConfig | undefined
|
|
30
|
+
}
|
|
31
|
+
extractorMessageReporting?: {
|
|
32
|
+
default?: MessageConfig
|
|
33
|
+
'ae-missing-release-tag'?: MessageConfig
|
|
34
|
+
'ae-forgotten-export'?: MessageConfig
|
|
35
|
+
'ae-internal-missing-underscore'?: MessageConfig
|
|
36
|
+
'ae-incompatible-release-tags'?: MessageConfig
|
|
37
|
+
[messageId: string]: MessageConfig | undefined
|
|
38
|
+
}
|
|
39
|
+
tsdocMessageReporting?: {
|
|
40
|
+
default?: MessageConfig
|
|
41
|
+
[messageId: string]: MessageConfig | undefined
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Partial representation of api-extractor.json relevant for this plugin.
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
export interface ApiExtractorConfig {
|
|
50
|
+
extends?: string
|
|
51
|
+
mainEntryPointFilePath?: string
|
|
52
|
+
messages?: ApiExtractorMessagesConfig
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Release tags recognized by API Extractor.
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
export type ReleaseTag = 'public' | 'beta' | 'alpha' | 'internal'
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* All valid release tags.
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export const RELEASE_TAGS: readonly ReleaseTag[] = [
|
|
66
|
+
'public',
|
|
67
|
+
'beta',
|
|
68
|
+
'alpha',
|
|
69
|
+
'internal',
|
|
70
|
+
] as const
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Options for the missing-release-tag rule.
|
|
74
|
+
* @public
|
|
75
|
+
*/
|
|
76
|
+
export interface MissingReleaseTagRuleOptions {
|
|
77
|
+
configPath?: string
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Options for the override-keyword rule.
|
|
82
|
+
* @public
|
|
83
|
+
*/
|
|
84
|
+
export interface OverrideKeywordRuleOptions {
|
|
85
|
+
configPath?: string
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Options for the package-documentation rule.
|
|
90
|
+
* @public
|
|
91
|
+
*/
|
|
92
|
+
export interface PackageDocumentationRuleOptions {
|
|
93
|
+
configPath?: string
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resolved entry points from package.json.
|
|
98
|
+
* @public
|
|
99
|
+
*/
|
|
100
|
+
export interface ResolvedEntryPoints {
|
|
101
|
+
main?: string
|
|
102
|
+
types?: string
|
|
103
|
+
exports: string[]
|
|
104
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for discovering and loading API Extractor configuration.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from 'fs'
|
|
7
|
+
import * as path from 'path'
|
|
8
|
+
import type {
|
|
9
|
+
ApiExtractorConfig,
|
|
10
|
+
ApiExtractorLogLevel,
|
|
11
|
+
ApiExtractorMessagesConfig,
|
|
12
|
+
} from '../types'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Default message configuration when no api-extractor.json is found.
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_MESSAGES_CONFIG: ApiExtractorMessagesConfig = {
|
|
18
|
+
extractorMessageReporting: {
|
|
19
|
+
default: { logLevel: 'warning' },
|
|
20
|
+
'ae-missing-release-tag': { logLevel: 'warning' },
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Cache for loaded configurations to avoid repeated file reads.
|
|
26
|
+
*/
|
|
27
|
+
const configCache = new Map<string, ApiExtractorConfig | null>()
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Searches upward from the given directory to find api-extractor.json.
|
|
31
|
+
*
|
|
32
|
+
* @param startDir - Directory to start searching from
|
|
33
|
+
* @returns Path to api-extractor.json if found, undefined otherwise
|
|
34
|
+
*/
|
|
35
|
+
export function findApiExtractorConfig(startDir: string): string | undefined {
|
|
36
|
+
let currentDir = path.resolve(startDir)
|
|
37
|
+
const root = path.parse(currentDir).root
|
|
38
|
+
|
|
39
|
+
while (currentDir !== root) {
|
|
40
|
+
const configPath = path.join(currentDir, 'api-extractor.json')
|
|
41
|
+
if (fs.existsSync(configPath)) {
|
|
42
|
+
return configPath
|
|
43
|
+
}
|
|
44
|
+
currentDir = path.dirname(currentDir)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return undefined
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Loads and parses an api-extractor.json file.
|
|
52
|
+
*
|
|
53
|
+
* @param configPath - Path to the api-extractor.json file
|
|
54
|
+
* @returns Parsed configuration or null if file cannot be read
|
|
55
|
+
*/
|
|
56
|
+
export function loadApiExtractorConfig(
|
|
57
|
+
configPath: string,
|
|
58
|
+
): ApiExtractorConfig | null {
|
|
59
|
+
// Check cache first
|
|
60
|
+
const cached = configCache.get(configPath)
|
|
61
|
+
if (cached !== undefined) {
|
|
62
|
+
return cached
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const content = fs.readFileSync(configPath, 'utf-8')
|
|
67
|
+
// Remove comments (api-extractor.json supports JSON with comments)
|
|
68
|
+
const jsonContent = content.replace(/\/\/.*$|\/\*[\s\S]*?\*\//gm, '')
|
|
69
|
+
const config = JSON.parse(jsonContent) as ApiExtractorConfig
|
|
70
|
+
|
|
71
|
+
// Handle extends
|
|
72
|
+
if (config.extends) {
|
|
73
|
+
const baseConfigPath = path.resolve(
|
|
74
|
+
path.dirname(configPath),
|
|
75
|
+
config.extends,
|
|
76
|
+
)
|
|
77
|
+
const baseConfig = loadApiExtractorConfig(baseConfigPath)
|
|
78
|
+
if (baseConfig) {
|
|
79
|
+
// Merge base config with current config
|
|
80
|
+
const merged = mergeConfigs(baseConfig, config)
|
|
81
|
+
configCache.set(configPath, merged)
|
|
82
|
+
return merged
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
configCache.set(configPath, config)
|
|
87
|
+
return config
|
|
88
|
+
} catch {
|
|
89
|
+
configCache.set(configPath, null)
|
|
90
|
+
return null
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Merges two API Extractor configurations, with the override taking precedence.
|
|
96
|
+
*/
|
|
97
|
+
function mergeConfigs(
|
|
98
|
+
base: ApiExtractorConfig,
|
|
99
|
+
override: ApiExtractorConfig,
|
|
100
|
+
): ApiExtractorConfig {
|
|
101
|
+
return {
|
|
102
|
+
...base,
|
|
103
|
+
...override,
|
|
104
|
+
messages: {
|
|
105
|
+
compilerMessageReporting: {
|
|
106
|
+
...base.messages?.compilerMessageReporting,
|
|
107
|
+
...override.messages?.compilerMessageReporting,
|
|
108
|
+
},
|
|
109
|
+
extractorMessageReporting: {
|
|
110
|
+
...base.messages?.extractorMessageReporting,
|
|
111
|
+
...override.messages?.extractorMessageReporting,
|
|
112
|
+
},
|
|
113
|
+
tsdocMessageReporting: {
|
|
114
|
+
...base.messages?.tsdocMessageReporting,
|
|
115
|
+
...override.messages?.tsdocMessageReporting,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Gets the log level for a specific message ID from the configuration.
|
|
123
|
+
*
|
|
124
|
+
* @param config - API Extractor configuration
|
|
125
|
+
* @param messageId - The message ID (e.g., 'ae-missing-release-tag')
|
|
126
|
+
* @returns The configured log level, or 'warning' as default
|
|
127
|
+
*/
|
|
128
|
+
export function getMessageLogLevel(
|
|
129
|
+
config: ApiExtractorConfig | null,
|
|
130
|
+
messageId: string,
|
|
131
|
+
): ApiExtractorLogLevel {
|
|
132
|
+
if (!config?.messages?.extractorMessageReporting) {
|
|
133
|
+
return (
|
|
134
|
+
DEFAULT_MESSAGES_CONFIG.extractorMessageReporting?.default?.logLevel ??
|
|
135
|
+
'warning'
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const reporting = config.messages.extractorMessageReporting
|
|
140
|
+
const messageConfig = reporting[messageId]
|
|
141
|
+
|
|
142
|
+
if (messageConfig?.logLevel) {
|
|
143
|
+
return messageConfig.logLevel
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return reporting.default?.logLevel ?? 'warning'
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Resolves configuration for a file, using auto-discovery or explicit path.
|
|
151
|
+
*
|
|
152
|
+
* @param filePath - Path to the file being linted
|
|
153
|
+
* @param explicitConfigPath - Optional explicit path to api-extractor.json
|
|
154
|
+
* @returns The resolved configuration or null
|
|
155
|
+
*/
|
|
156
|
+
export function resolveConfig(
|
|
157
|
+
filePath: string,
|
|
158
|
+
explicitConfigPath?: string,
|
|
159
|
+
): ApiExtractorConfig | null {
|
|
160
|
+
if (explicitConfigPath) {
|
|
161
|
+
return loadApiExtractorConfig(explicitConfigPath)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const discovered = findApiExtractorConfig(path.dirname(filePath))
|
|
165
|
+
if (discovered) {
|
|
166
|
+
return loadApiExtractorConfig(discovered)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return null
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Maps API Extractor log level to ESLint severity.
|
|
174
|
+
*
|
|
175
|
+
* @param logLevel - API Extractor log level
|
|
176
|
+
* @returns ESLint severity (0 = off, 1 = warn, 2 = error)
|
|
177
|
+
*/
|
|
178
|
+
export function logLevelToSeverity(logLevel: ApiExtractorLogLevel): 0 | 1 | 2 {
|
|
179
|
+
switch (logLevel) {
|
|
180
|
+
case 'error':
|
|
181
|
+
return 2
|
|
182
|
+
case 'warning':
|
|
183
|
+
return 1
|
|
184
|
+
case 'none':
|
|
185
|
+
return 0
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Clears the configuration cache. Useful for testing.
|
|
191
|
+
*/
|
|
192
|
+
export function clearConfigCache(): void {
|
|
193
|
+
configCache.clear()
|
|
194
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for resolving package.json entry points.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from 'fs'
|
|
7
|
+
import * as path from 'path'
|
|
8
|
+
import type { ResolvedEntryPoints } from '../types'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents the relevant fields from package.json.
|
|
12
|
+
*/
|
|
13
|
+
interface PackageJson {
|
|
14
|
+
main?: string
|
|
15
|
+
types?: string
|
|
16
|
+
typings?: string
|
|
17
|
+
module?: string
|
|
18
|
+
exports?: PackageExports
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Package.json exports field can be complex.
|
|
23
|
+
*/
|
|
24
|
+
type PackageExports =
|
|
25
|
+
| string
|
|
26
|
+
| { [key: string]: PackageExports | string | undefined }
|
|
27
|
+
| undefined
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Cache for package.json lookups.
|
|
31
|
+
*/
|
|
32
|
+
const packageJsonCache = new Map<string, PackageJson | null>()
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Finds the nearest package.json by searching upward from a directory.
|
|
36
|
+
*
|
|
37
|
+
* @param startDir - Directory to start searching from
|
|
38
|
+
* @returns Path to package.json if found, undefined otherwise
|
|
39
|
+
*/
|
|
40
|
+
export function findPackageJson(startDir: string): string | undefined {
|
|
41
|
+
let currentDir = path.resolve(startDir)
|
|
42
|
+
const root = path.parse(currentDir).root
|
|
43
|
+
|
|
44
|
+
while (currentDir !== root) {
|
|
45
|
+
const pkgPath = path.join(currentDir, 'package.json')
|
|
46
|
+
if (fs.existsSync(pkgPath)) {
|
|
47
|
+
return pkgPath
|
|
48
|
+
}
|
|
49
|
+
currentDir = path.dirname(currentDir)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return undefined
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Loads and parses a package.json file.
|
|
57
|
+
*
|
|
58
|
+
* @param pkgPath - Path to the package.json file
|
|
59
|
+
* @returns Parsed package.json or null if file cannot be read
|
|
60
|
+
*/
|
|
61
|
+
export function loadPackageJson(pkgPath: string): PackageJson | null {
|
|
62
|
+
const cached = packageJsonCache.get(pkgPath)
|
|
63
|
+
if (cached !== undefined) {
|
|
64
|
+
return cached
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const content = fs.readFileSync(pkgPath, 'utf-8')
|
|
69
|
+
const pkg = JSON.parse(content) as PackageJson
|
|
70
|
+
packageJsonCache.set(pkgPath, pkg)
|
|
71
|
+
return pkg
|
|
72
|
+
} catch {
|
|
73
|
+
packageJsonCache.set(pkgPath, null)
|
|
74
|
+
return null
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Extracts all entry point paths from package.json exports field.
|
|
80
|
+
*
|
|
81
|
+
* @param exports - The exports field value
|
|
82
|
+
* @param results - Array to collect results
|
|
83
|
+
*/
|
|
84
|
+
function extractExportPaths(exports: PackageExports, results: string[]): void {
|
|
85
|
+
if (typeof exports === 'string') {
|
|
86
|
+
results.push(exports)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (exports && typeof exports === 'object') {
|
|
91
|
+
for (const value of Object.values(exports)) {
|
|
92
|
+
if (value !== undefined) {
|
|
93
|
+
extractExportPaths(value, results)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Resolves all entry points from a package.json.
|
|
101
|
+
*
|
|
102
|
+
* @param pkgPath - Path to the package.json file
|
|
103
|
+
* @returns Resolved entry points with absolute paths
|
|
104
|
+
*/
|
|
105
|
+
export function resolveEntryPoints(pkgPath: string): ResolvedEntryPoints {
|
|
106
|
+
const pkg = loadPackageJson(pkgPath)
|
|
107
|
+
const pkgDir = path.dirname(pkgPath)
|
|
108
|
+
const result: ResolvedEntryPoints = { exports: [] }
|
|
109
|
+
|
|
110
|
+
if (!pkg) {
|
|
111
|
+
return result
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Resolve main entry point
|
|
115
|
+
if (pkg.main) {
|
|
116
|
+
result.main = path.resolve(pkgDir, pkg.main)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Resolve types entry point
|
|
120
|
+
if (pkg.types) {
|
|
121
|
+
result.types = path.resolve(pkgDir, pkg.types)
|
|
122
|
+
} else if (pkg.typings) {
|
|
123
|
+
result.types = path.resolve(pkgDir, pkg.typings)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Resolve exports
|
|
127
|
+
if (pkg.exports) {
|
|
128
|
+
const exportPaths: string[] = []
|
|
129
|
+
extractExportPaths(pkg.exports, exportPaths)
|
|
130
|
+
result.exports = exportPaths.map((p) => path.resolve(pkgDir, p))
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return result
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Checks if a file is a package entry point.
|
|
138
|
+
*
|
|
139
|
+
* @param filePath - Absolute path to the file being checked
|
|
140
|
+
* @param pkgPath - Path to the package.json
|
|
141
|
+
* @returns True if the file is an entry point
|
|
142
|
+
*/
|
|
143
|
+
export function isEntryPoint(filePath: string, pkgPath: string): boolean {
|
|
144
|
+
const entryPoints = resolveEntryPoints(pkgPath)
|
|
145
|
+
const absoluteFilePath = path.resolve(filePath)
|
|
146
|
+
|
|
147
|
+
// Check main
|
|
148
|
+
if (
|
|
149
|
+
entryPoints.main &&
|
|
150
|
+
normalizeForComparison(entryPoints.main) ===
|
|
151
|
+
normalizeForComparison(absoluteFilePath)
|
|
152
|
+
) {
|
|
153
|
+
return true
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Check types
|
|
157
|
+
if (
|
|
158
|
+
entryPoints.types &&
|
|
159
|
+
normalizeForComparison(entryPoints.types) ===
|
|
160
|
+
normalizeForComparison(absoluteFilePath)
|
|
161
|
+
) {
|
|
162
|
+
return true
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Check exports
|
|
166
|
+
for (const exportPath of entryPoints.exports) {
|
|
167
|
+
if (
|
|
168
|
+
normalizeForComparison(exportPath) ===
|
|
169
|
+
normalizeForComparison(absoluteFilePath)
|
|
170
|
+
) {
|
|
171
|
+
return true
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Also check if the TypeScript source file corresponds to the entry point
|
|
176
|
+
// e.g., src/index.ts -> dist/index.js
|
|
177
|
+
const sourceEquivalents = getSourceEquivalents(absoluteFilePath)
|
|
178
|
+
for (const sourcePath of sourceEquivalents) {
|
|
179
|
+
if (
|
|
180
|
+
entryPoints.main &&
|
|
181
|
+
normalizeForComparison(entryPoints.main) ===
|
|
182
|
+
normalizeForComparison(sourcePath)
|
|
183
|
+
) {
|
|
184
|
+
return true
|
|
185
|
+
}
|
|
186
|
+
if (
|
|
187
|
+
entryPoints.types &&
|
|
188
|
+
normalizeForComparison(entryPoints.types) ===
|
|
189
|
+
normalizeForComparison(sourcePath)
|
|
190
|
+
) {
|
|
191
|
+
return true
|
|
192
|
+
}
|
|
193
|
+
for (const exportPath of entryPoints.exports) {
|
|
194
|
+
if (
|
|
195
|
+
normalizeForComparison(exportPath) ===
|
|
196
|
+
normalizeForComparison(sourcePath)
|
|
197
|
+
) {
|
|
198
|
+
return true
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return false
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Normalizes a path for comparison by removing extension variations.
|
|
208
|
+
*/
|
|
209
|
+
function normalizeForComparison(filePath: string): string {
|
|
210
|
+
// Remove common extensions and normalize
|
|
211
|
+
return filePath
|
|
212
|
+
.replace(/\.(js|ts|mjs|cjs|mts|cts|d\.ts|d\.mts|d\.cts)$/, '')
|
|
213
|
+
.replace(/\/index$/, '')
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Gets potential source file equivalents for a dist file.
|
|
218
|
+
*/
|
|
219
|
+
function getSourceEquivalents(filePath: string): string[] {
|
|
220
|
+
const equivalents: string[] = []
|
|
221
|
+
const dir = path.dirname(filePath)
|
|
222
|
+
const base = path.basename(filePath).replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, '')
|
|
223
|
+
|
|
224
|
+
// Try common source directory patterns
|
|
225
|
+
const sourcePatterns = [
|
|
226
|
+
dir.replace('/dist/', '/src/').replace('\\dist\\', '\\src\\'),
|
|
227
|
+
dir.replace('/build/', '/src/').replace('\\build\\', '\\src\\'),
|
|
228
|
+
dir.replace('/lib/', '/src/').replace('\\lib\\', '\\src\\'),
|
|
229
|
+
]
|
|
230
|
+
|
|
231
|
+
for (const sourceDir of sourcePatterns) {
|
|
232
|
+
if (sourceDir !== dir) {
|
|
233
|
+
equivalents.push(path.join(sourceDir, `${base}.ts`))
|
|
234
|
+
equivalents.push(path.join(sourceDir, `${base}.tsx`))
|
|
235
|
+
equivalents.push(path.join(sourceDir, `${base}.js`))
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return equivalents
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Clears the package.json cache. Useful for testing.
|
|
244
|
+
*/
|
|
245
|
+
export function clearPackageJsonCache(): void {
|
|
246
|
+
packageJsonCache.clear()
|
|
247
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility module exports.
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { resolveConfig, getMessageLogLevel } from './config-loader'
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
parseTSDocComment,
|
|
10
|
+
extractReleaseTag,
|
|
11
|
+
hasOverrideTag,
|
|
12
|
+
hasPackageDocumentation,
|
|
13
|
+
getLeadingTSDocComment,
|
|
14
|
+
findAllTSDocComments,
|
|
15
|
+
} from './tsdoc-parser'
|
|
16
|
+
|
|
17
|
+
export { findPackageJson, isEntryPoint } from './entry-point'
|