@@ -6,6 +6,19 @@ import type { LiteralNodeValue, PluginSettings, RuleContext } from '../types.js'
6
6
import { getContextPackagePath } from './package-path.js'
7
7
import { resolve } from './resolve.js'
8
8
9
+ /**
10
+ * Returns the base module name.
11
+ *
12
+ * @example
13
+ * '@scope/package' => '@scope/package'
14
+ * '@scope/package/subpath' => '@scope/package'
15
+ * 'package' => 'package'
16
+ * 'package/subpath' => 'package'
17
+ * 'package/subpath/index.js' => 'package'
18
+ *
19
+ * @param name The name of the module to check
20
+ * @returns The base module name
21
+ */
9
22
function baseModule ( name : string ) {
10
23
if ( isScoped ( name ) ) {
11
24
const [ scope , pkg ] = name . split ( '/' )
@@ -15,21 +28,53 @@ function baseModule(name: string) {
15
28
return pkg
16
29
}
17
30
31
+ /**
32
+ * Check if the name is an internal module.
33
+ *
34
+ * An internal module is declared by `import-x/internal-regex` via settings.
35
+ *
36
+ * @param name The name of the module to check
37
+ * @param settings The settings of the plugin
38
+ * @returns `true` if the name is an internal module, otherwise `false`
39
+ */
18
40
function isInternalRegexMatch ( name : string , settings : PluginSettings ) {
19
41
const internalScope = settings ?. [ 'import-x/internal-regex' ]
20
42
return internalScope && new RegExp ( internalScope ) . test ( name )
21
43
}
22
44
45
+ /**
46
+ * Check if the name is an absolute path.
47
+ *
48
+ * @param name The name of the module to check
49
+ * @returns `true` if the name is an absolute path, otherwise `false`
50
+ */
23
51
export function isAbsolute ( name ?: LiteralNodeValue ) {
24
52
return typeof name === 'string' && path . isAbsolute ( name )
25
53
}
26
54
27
- // path is defined only when a resolver resolves to a non-standard path
55
+ /**
56
+ * Check if the name is a built-in module.
57
+ *
58
+ * A built-in module is a module that is included in Node.js by default.
59
+ *
60
+ * If `import-x/core-modules` are defined in the settings, it will also check
61
+ * against those.
62
+ *
63
+ * @example
64
+ * 'node:fs'
65
+ * 'path'
66
+ *
67
+ * @param name The name of the module to check
68
+ * @param settings The settings of the plugin
69
+ * @param modulePath The path of the module to check
70
+ * @returns `true` if the name is a built-in module, otherwise `false`
71
+ */
28
72
export function isBuiltIn (
29
73
name : string ,
30
74
settings : PluginSettings ,
31
75
modulePath ?: string | null ,
32
76
) {
77
+ // path is defined only when a resolver resolves to a non-standard path
33
78
if ( modulePath || ! name ) {
34
79
return false
35
80
}
@@ -66,6 +111,24 @@ export function isExternalModuleMain(
66
111
67
112
const moduleRegExp = / ^ \w /
68
113
114
+ /**
115
+ * Check if the name could be a module name.
116
+ *
117
+ * This is a loose check that only checks if the name contains letters, numbers,
118
+ * and underscores. It does not check if the name is a valid module name.
119
+ *
120
+ * @example
121
+ * 'package' => true
122
+ *
123
+ * '@scope/package' => false
124
+ * 'package/subpath' => false
125
+ * './package' => false
126
+ * 'package-name' => false
127
+ *
128
+ * @param name The name of the module to check
129
+ * @returns `true` if the name only contains letters, numbers, and underscores,
130
+ * otherwise `false`
131
+ */
69
132
function isModule ( name : string ) {
70
133
return ! ! name && moduleRegExp . test ( name )
71
134
}
@@ -78,6 +141,17 @@ function isModuleMain(name: string) {
78
141
79
142
const scopedRegExp = / ^ @ [ ^ / ] + \/ ? [ ^ / ] + /
80
143
144
+ /**
145
+ * Check if the name could be a scoped module name.
146
+ *
147
+ * @example
148
+ * '@scope/package' => true
149
+ *
150
+ * '@/components/buttons' => false
151
+ *
152
+ * @param name The name of the module to check
153
+ * @returns `true` if the name is a scoped module name, otherwise `false`
154
+ */
81
155
export function isScoped ( name : string ) {
82
156
return ! ! name && scopedRegExp . test ( name )
83
157
}
@@ -88,20 +162,72 @@ export function isScopedMain(name: string) {
88
162
return ! ! name && scopedMainRegExp . test ( name )
89
163
}
90
164
165
+ /**
166
+ * Check if the name is a relative path to the parent module.
167
+ *
168
+ * @example
169
+ * '..' => true
170
+ * '../package' => true
171
+ *
172
+ * './package' => false
173
+ * 'package' => false
174
+ * '@scope/package' => false
175
+ *
176
+ * @param name The name of the module to check
177
+ * @returns `true` if the name is a relative path to the parent module,
178
+ * otherwise `false`
179
+ */
91
180
function isRelativeToParent ( name : string ) {
92
181
return / ^ \. \. $ | ^ \. \. [ / \\ ] / . test ( name )
93
182
}
94
183
95
184
const indexFiles = new Set ( [ '.' , './' , './index' , './index.js' ] )
96
185
186
+ /**
187
+ * Check if the name is an index file.
188
+ *
189
+ * @example
190
+ * '.' => true
191
+ * './' => true
192
+ * './index' => true
193
+ * './index.js' => true
194
+ *
195
+ * otherwise => false
196
+ *
197
+ * @param name The name of the module to check
198
+ * @returns `true` if the name is an index file, otherwise `false`
199
+ */
97
200
function isIndex ( name : string ) {
98
201
return indexFiles . has ( name )
99
202
}
100
203
204
+ /**
205
+ * Check if the name is a relative path to a sibling module.
206
+ *
207
+ * @example
208
+ * './file.js' => true
209
+ *
210
+ * '../file.js' => false
211
+ * 'file.js' => false
212
+ *
213
+ * @param name The name of the module to check
214
+ * @returns `true` if the name is a relative path to a sibling module, otherwise
215
+ * `false`
216
+ */
101
217
function isRelativeToSibling ( name : string ) {
102
218
return / ^ \. [ / \\ ] / . test ( name )
103
219
}
104
220
221
+ /**
222
+ * Check if the path is an external path.
223
+ *
224
+ * An external path is a path that is outside of the package directory or the
225
+ * `import-x/external-module-folders` settings.
226
+ *
227
+ * @param filepath The path to check
228
+ * @param context The context of the rule
229
+ * @returns `true` if the path is an external path, otherwise `false`
230
+ */
105
231
function isExternalPath (
106
232
filepath : string | null | undefined ,
107
233
context : RuleContext ,
@@ -127,6 +253,15 @@ function isExternalPath(
127
253
} )
128
254
}
129
255
256
+ /**
257
+ * Check if the path is an internal path.
258
+ *
259
+ * An internal path is a path that is inside the package directory.
260
+ *
261
+ * @param filepath The path to check
262
+ * @param context The context of the rule
263
+ * @returns `true` if the path is an internal path, otherwise `false`
264
+ */
130
265
function isInternalPath (
131
266
filepath : string | null | undefined ,
132
267
context : RuleContext ,
@@ -138,10 +273,28 @@ function isInternalPath(
138
273
return ! path . relative ( packagePath , filepath ) . startsWith ( '../' )
139
274
}
140
275
276
+ /**
277
+ * Check if the name is an external looking name.
278
+ *
279
+ * @example
280
+ * 'glob' => true
281
+ * '@scope/package' => true
282
+ *
283
+ * @param name The name of the module to check
284
+ * @returns `true` if the name is an external looking name, otherwise `false`
285
+ */
141
286
function isExternalLookingName ( name : string ) {
142
287
return isModule ( name ) || isScoped ( name )
143
288
}
144
289
290
+ /**
291
+ * Returns the type of the module.
292
+ *
293
+ * @param name The name of the module to check
294
+ * @param context The context of the rule
295
+ * @param path The path of the module to check
296
+ * @returns The type of the module
297
+ */
145
298
function typeTest (
146
299
name : LiteralNodeValue ,
147
300
context : RuleContext ,
@@ -180,6 +333,13 @@ function typeTest(
180
333
return 'unknown'
181
334
}
182
335
336
+ /**
337
+ * Returns the type of the module.
338
+ *
339
+ * @param name The name of the module to check
340
+ * @param context The context of the rule
341
+ * @returns The type of the module
342
+ */
183
343
export function importType ( name : LiteralNodeValue , context : RuleContext ) {
184
344
return typeTest (
185
345
name ,
0 commit comments