@flex-development/mlly 1.0.0-alpha.15 → 1.0.0-alpha.16

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.
Files changed (239) hide show
  1. package/CHANGELOG.md +181 -0
  2. package/README.md +1 -0
  3. package/dist/enums/assert-type.mjs +1 -7
  4. package/dist/enums/format.mjs +1 -10
  5. package/dist/enums/index.mjs +0 -1
  6. package/dist/enums/kind-specifier-syntax.mjs +1 -7
  7. package/dist/enums/kind-specifier.mjs +1 -8
  8. package/dist/enums/kind-statement-syntax.mjs +1 -15
  9. package/dist/enums/kind-statement.mjs +1 -8
  10. package/dist/index.mjs.map +5 -2
  11. package/dist/interfaces/import-dynamic.d.mts +1 -3
  12. package/dist/interfaces/import-static.d.mts +1 -3
  13. package/dist/interfaces/index.mjs +0 -1
  14. package/dist/interfaces/options-find-subpath.d.mts +4 -3
  15. package/dist/interfaces/options-get-format.d.mts +7 -7
  16. package/dist/interfaces/options-get-source.d.mts +5 -4
  17. package/dist/interfaces/options-parse-module-id.d.mts +4 -3
  18. package/dist/interfaces/options-parse-subpath.d.mts +4 -3
  19. package/dist/interfaces/options-resolve-alias.d.mts +5 -5
  20. package/dist/interfaces/options-resolve-module.d.mts +6 -6
  21. package/dist/internal/dequote.d.mts +14 -0
  22. package/dist/internal/dequote.mjs +6 -0
  23. package/dist/internal/format-type-map.d.mts +2 -0
  24. package/dist/internal/format-type-map.mjs +0 -1
  25. package/dist/internal/get-specifier-kind.d.mts +2 -0
  26. package/dist/internal/get-specifier-kind.mjs +3 -7
  27. package/dist/internal/get-subpaths.d.mts +5 -2
  28. package/dist/internal/get-subpaths.mjs +2 -5
  29. package/dist/internal/regex-encoded-sep.d.mts +2 -0
  30. package/dist/internal/regex-encoded-sep.mjs +0 -1
  31. package/dist/internal/regex-internal-specifier.d.mts +2 -0
  32. package/dist/internal/regex-internal-specifier.mjs +0 -1
  33. package/dist/internal/regex-invalid-segment.d.mts +2 -0
  34. package/dist/internal/regex-invalid-segment.mjs +4 -7
  35. package/dist/internal/regex-package-name.d.mts +2 -0
  36. package/dist/internal/regex-package-name.mjs +0 -1
  37. package/dist/internal/regex-package-path.d.mts +2 -0
  38. package/dist/internal/regex-package-path.mjs +0 -1
  39. package/dist/internal/resolver.d.mts +5 -3
  40. package/dist/internal/resolver.mjs +115 -130
  41. package/dist/internal/validate-array-set.d.mts +7 -5
  42. package/dist/internal/validate-array-set.mjs +5 -5
  43. package/dist/internal/validate-boolean.d.mts +4 -2
  44. package/dist/internal/validate-boolean.mjs +3 -3
  45. package/dist/internal/validate-map.d.mts +10 -7
  46. package/dist/internal/validate-map.mjs +5 -5
  47. package/dist/internal/validate-object.d.mts +9 -9
  48. package/dist/internal/validate-object.mjs +3 -3
  49. package/dist/internal/validate-set.d.mts +7 -5
  50. package/dist/internal/validate-set.mjs +5 -5
  51. package/dist/internal/validate-string.d.mts +5 -2
  52. package/dist/internal/validate-string.mjs +3 -3
  53. package/dist/internal/validate-url-string.d.mts +4 -2
  54. package/dist/internal/validate-url-string.mjs +3 -3
  55. package/dist/types/fn-change-ext.d.mts +7 -4
  56. package/dist/types/index.mjs +0 -1
  57. package/dist/utils/compare-subpaths.mjs +5 -10
  58. package/dist/utils/compare-subpaths.mjs.map +6 -3
  59. package/dist/utils/conditions.mjs.map +5 -2
  60. package/dist/utils/detect-syntax.mjs +1 -2
  61. package/dist/utils/detect-syntax.mjs.map +6 -3
  62. package/dist/utils/extension-format-map.mjs.map +5 -2
  63. package/dist/utils/extract-statements.mjs +6 -7
  64. package/dist/utils/extract-statements.mjs.map +6 -3
  65. package/dist/utils/fill-modules.mjs +43 -46
  66. package/dist/utils/fill-modules.mjs.map +9 -4
  67. package/dist/utils/find-dynamic-imports.mjs +23 -26
  68. package/dist/utils/find-dynamic-imports.mjs.map +9 -4
  69. package/dist/utils/find-exports.mjs +15 -20
  70. package/dist/utils/find-exports.mjs.map +9 -4
  71. package/dist/utils/find-requires.mjs +5 -5
  72. package/dist/utils/find-requires.mjs.map +9 -4
  73. package/dist/utils/find-static-imports.mjs +17 -21
  74. package/dist/utils/find-static-imports.mjs.map +9 -4
  75. package/dist/utils/find-subpath.d.mts +3 -3
  76. package/dist/utils/find-subpath.mjs +52 -74
  77. package/dist/utils/find-subpath.mjs.map +10 -4
  78. package/dist/utils/get-format.mjs +18 -33
  79. package/dist/utils/get-format.mjs.map +9 -4
  80. package/dist/utils/get-source.d.mts +3 -2
  81. package/dist/utils/get-source.mjs +10 -19
  82. package/dist/utils/get-source.mjs.map +6 -3
  83. package/dist/utils/has-cjs-syntax.mjs.map +5 -2
  84. package/dist/utils/has-esm-syntax.mjs.map +5 -2
  85. package/dist/utils/index.d.mts +2 -0
  86. package/dist/utils/index.mjs +46 -42
  87. package/dist/utils/index.mjs.map +9 -4
  88. package/dist/utils/is-absolute-specifier.mjs +5 -6
  89. package/dist/utils/is-absolute-specifier.mjs.map +6 -3
  90. package/dist/utils/is-bare-specifier.mjs +2 -4
  91. package/dist/utils/is-bare-specifier.mjs.map +6 -3
  92. package/dist/utils/is-directory.mjs +14 -0
  93. package/dist/utils/is-directory.mjs.map +9 -0
  94. package/dist/utils/is-exports-sugar.d.mts +3 -2
  95. package/dist/utils/is-exports-sugar.mjs +16 -13
  96. package/dist/utils/is-exports-sugar.mjs.map +6 -3
  97. package/dist/utils/is-file.mjs +14 -0
  98. package/dist/utils/is-file.mjs.map +9 -0
  99. package/dist/utils/is-relative-specifier.d.mts +0 -1
  100. package/dist/utils/is-relative-specifier.mjs +2 -4
  101. package/dist/utils/is-relative-specifier.mjs.map +6 -3
  102. package/dist/utils/lookup-package-scope.d.mts +1 -1
  103. package/dist/utils/lookup-package-scope.mjs +4 -8
  104. package/dist/utils/lookup-package-scope.mjs.map +6 -3
  105. package/dist/utils/parse-data-url.mjs +4 -4
  106. package/dist/utils/parse-data-url.mjs.map +6 -3
  107. package/dist/utils/parse-module-id.mjs +22 -24
  108. package/dist/utils/parse-module-id.mjs.map +10 -4
  109. package/dist/utils/parse-subpath.d.mts +3 -2
  110. package/dist/utils/parse-subpath.mjs +40 -55
  111. package/dist/utils/parse-subpath.mjs.map +9 -4
  112. package/dist/utils/pattern-character.mjs.map +5 -2
  113. package/dist/utils/read-package-json.mjs +12 -9
  114. package/dist/utils/read-package-json.mjs.map +6 -3
  115. package/dist/utils/resolve-alias.mjs +28 -34
  116. package/dist/utils/resolve-alias.mjs.map +10 -4
  117. package/dist/utils/resolve-aliases.mjs +15 -17
  118. package/dist/utils/resolve-aliases.mjs.map +6 -3
  119. package/dist/utils/resolve-extensions.mjs.map +5 -2
  120. package/dist/utils/resolve-module.mjs +10 -26
  121. package/dist/utils/resolve-module.mjs.map +6 -3
  122. package/dist/utils/resolve-modules.mjs +12 -15
  123. package/dist/utils/resolve-modules.mjs.map +6 -3
  124. package/dist/utils/to-absolute-specifier.mjs.map +5 -2
  125. package/dist/utils/to-bare-specifier.mjs +18 -38
  126. package/dist/utils/to-bare-specifier.mjs.map +6 -3
  127. package/dist/utils/to-data-url.mjs +1 -5
  128. package/dist/utils/to-data-url.mjs.map +6 -3
  129. package/dist/utils/to-node-url.mjs +1 -4
  130. package/dist/utils/to-node-url.mjs.map +6 -3
  131. package/dist/utils/to-relative-specifier.mjs +2 -16
  132. package/dist/utils/to-relative-specifier.mjs.map +6 -3
  133. package/dist/utils/to-url.mjs +1 -5
  134. package/dist/utils/to-url.mjs.map +6 -3
  135. package/dist/utils/validate-assertions.d.mts +2 -2
  136. package/dist/utils/validate-assertions.mjs +14 -21
  137. package/dist/utils/validate-assertions.mjs.map +9 -4
  138. package/dist/utils/validate-exports.d.mts +3 -2
  139. package/dist/utils/validate-exports.mjs +25 -24
  140. package/dist/utils/validate-exports.mjs.map +6 -3
  141. package/package.json +89 -81
  142. package/src/interfaces/import-dynamic.ts +1 -3
  143. package/src/interfaces/import-static.ts +1 -5
  144. package/src/interfaces/options-find-subpath.ts +4 -3
  145. package/src/interfaces/options-get-format.ts +7 -7
  146. package/src/interfaces/options-get-source.ts +5 -4
  147. package/src/interfaces/options-parse-module-id.ts +4 -3
  148. package/src/interfaces/options-parse-subpath.ts +4 -3
  149. package/src/interfaces/options-resolve-alias.ts +5 -5
  150. package/src/interfaces/options-resolve-module.ts +6 -6
  151. package/src/internal/dequote.ts +18 -0
  152. package/src/internal/format-type-map.ts +2 -0
  153. package/src/internal/get-specifier-kind.ts +7 -4
  154. package/src/internal/get-subpaths.ts +7 -5
  155. package/src/internal/regex-encoded-sep.ts +2 -0
  156. package/src/internal/regex-internal-specifier.ts +2 -0
  157. package/src/internal/regex-invalid-segment.ts +2 -0
  158. package/src/internal/regex-package-name.ts +2 -0
  159. package/src/internal/regex-package-path.ts +2 -0
  160. package/src/internal/resolver.ts +71 -49
  161. package/src/internal/validate-array-set.ts +10 -7
  162. package/src/internal/validate-boolean.ts +6 -3
  163. package/src/internal/validate-map.ts +12 -9
  164. package/src/internal/validate-object.ts +10 -10
  165. package/src/internal/validate-set.ts +9 -9
  166. package/src/internal/validate-string.ts +7 -3
  167. package/src/internal/validate-url-string.ts +6 -3
  168. package/src/types/fn-change-ext.ts +7 -7
  169. package/src/utils/extract-statements.ts +11 -7
  170. package/src/utils/fill-modules.ts +70 -62
  171. package/src/utils/find-dynamic-imports.ts +6 -6
  172. package/src/utils/find-exports.ts +19 -29
  173. package/src/utils/find-requires.ts +6 -6
  174. package/src/utils/find-static-imports.ts +11 -14
  175. package/src/utils/find-subpath.ts +140 -139
  176. package/src/utils/get-format.ts +27 -21
  177. package/src/utils/get-source.ts +5 -5
  178. package/src/utils/index.ts +2 -0
  179. package/src/utils/is-bare-specifier.ts +2 -1
  180. package/src/{internal → utils}/is-directory.ts +1 -1
  181. package/src/utils/is-exports-sugar.ts +16 -9
  182. package/src/{internal → utils}/is-file.ts +1 -1
  183. package/src/utils/is-relative-specifier.ts +5 -6
  184. package/src/utils/lookup-package-scope.ts +2 -2
  185. package/src/utils/parse-data-url.ts +3 -3
  186. package/src/utils/parse-module-id.ts +16 -8
  187. package/src/utils/parse-subpath.ts +32 -19
  188. package/src/utils/read-package-json.ts +13 -6
  189. package/src/utils/resolve-alias.ts +19 -15
  190. package/src/utils/resolve-aliases.ts +25 -25
  191. package/src/utils/resolve-module.ts +4 -5
  192. package/src/utils/resolve-modules.ts +19 -21
  193. package/src/utils/to-bare-specifier.ts +12 -7
  194. package/src/utils/to-relative-specifier.ts +2 -1
  195. package/src/utils/validate-assertions.ts +12 -7
  196. package/src/utils/validate-exports.ts +25 -18
  197. package/dist/enums/assert-type.mjs.map +0 -6
  198. package/dist/enums/format.mjs.map +0 -6
  199. package/dist/enums/index.mjs.map +0 -6
  200. package/dist/enums/kind-specifier-syntax.mjs.map +0 -6
  201. package/dist/enums/kind-specifier.mjs.map +0 -6
  202. package/dist/enums/kind-statement-syntax.mjs.map +0 -6
  203. package/dist/enums/kind-statement.mjs.map +0 -6
  204. package/dist/interfaces/index.mjs.map +0 -6
  205. package/dist/internal/escape-reg-exp.d.mts +0 -16
  206. package/dist/internal/escape-reg-exp.mjs +0 -10
  207. package/dist/internal/escape-reg-exp.mjs.map +0 -6
  208. package/dist/internal/format-type-map.mjs.map +0 -6
  209. package/dist/internal/get-specifier-kind.mjs.map +0 -6
  210. package/dist/internal/get-subpaths.mjs.map +0 -6
  211. package/dist/internal/is-array-index.d.mts +0 -15
  212. package/dist/internal/is-array-index.mjs +0 -9
  213. package/dist/internal/is-array-index.mjs.map +0 -6
  214. package/dist/internal/is-directory.mjs +0 -16
  215. package/dist/internal/is-directory.mjs.map +0 -6
  216. package/dist/internal/is-file.mjs +0 -16
  217. package/dist/internal/is-file.mjs.map +0 -6
  218. package/dist/internal/is-function.d.mts +0 -12
  219. package/dist/internal/is-function.mjs +0 -8
  220. package/dist/internal/is-function.mjs.map +0 -6
  221. package/dist/internal/regex-encoded-sep.mjs.map +0 -6
  222. package/dist/internal/regex-internal-specifier.mjs.map +0 -6
  223. package/dist/internal/regex-invalid-segment.mjs.map +0 -6
  224. package/dist/internal/regex-package-name.mjs.map +0 -6
  225. package/dist/internal/regex-package-path.mjs.map +0 -6
  226. package/dist/internal/resolver.mjs.map +0 -6
  227. package/dist/internal/validate-array-set.mjs.map +0 -6
  228. package/dist/internal/validate-boolean.mjs.map +0 -6
  229. package/dist/internal/validate-map.mjs.map +0 -6
  230. package/dist/internal/validate-object.mjs.map +0 -6
  231. package/dist/internal/validate-set.mjs.map +0 -6
  232. package/dist/internal/validate-string.mjs.map +0 -6
  233. package/dist/internal/validate-url-string.mjs.map +0 -6
  234. package/dist/types/index.mjs.map +0 -6
  235. package/src/internal/escape-reg-exp.ts +0 -24
  236. package/src/internal/is-array-index.ts +0 -28
  237. package/src/internal/is-function.ts +0 -16
  238. /package/dist/{internal → utils}/is-directory.d.mts +0 -0
  239. /package/dist/{internal → utils}/is-file.d.mts +0 -0
@@ -12,7 +12,18 @@ import validateURLString from '#src/internal/validate-url-string'
12
12
  import type { NodeError } from '@flex-development/errnode'
13
13
  import pathe from '@flex-development/pathe'
14
14
  import type { Exports, Imports } from '@flex-development/pkg-types'
15
- import { isNIL, type Nullable } from '@flex-development/tutils'
15
+ import {
16
+ DOT,
17
+ cast,
18
+ isArray,
19
+ isNIL,
20
+ isObjectCurly,
21
+ isString,
22
+ sort,
23
+ type Nilable,
24
+ type Nullable,
25
+ type Optional
26
+ } from '@flex-development/tutils'
16
27
  import { URL } from 'node:url'
17
28
  import compareSubpaths from './compare-subpaths'
18
29
  import CONDITIONS from './conditions'
@@ -37,14 +48,14 @@ import toURL from './to-url'
37
48
  * @see https://nodejs.org/api/packages.html#subpath-imports
38
49
  *
39
50
  * @param {string} target - Package target to find in `context`
40
- * @param {Exports | Imports | undefined} context - Package context
51
+ * @param {Nilable<Exports | Imports>} context - Package context
41
52
  * @param {FindSubpathOptions} options - Search options
42
53
  * @return {Nullable<string>} Subpath defined in `context` or `null`
43
54
  * @throws {NodeError<Error | TypeError>}
44
55
  */
45
56
  const findSubpath = (
46
57
  target: string,
47
- context: Exports | Imports | undefined,
58
+ context: Nilable<Exports | Imports>,
48
59
  options: FindSubpathOptions
49
60
  ): Nullable<string> => {
50
61
  const {
@@ -62,9 +73,9 @@ const findSubpath = (
62
73
  validateString(target, 'target')
63
74
 
64
75
  // exit early if target is an exactish match
65
- if (typeof context === 'string') {
76
+ if (isString(context)) {
66
77
  if (target === context || target === pathe.changeExt(context, '')) {
67
- return '.'
78
+ return DOT
68
79
  }
69
80
  }
70
81
 
@@ -85,14 +96,14 @@ const findSubpath = (
85
96
  * [2]: https://nodejs.org/api/packages.html#imports
86
97
  *
87
98
  * @param {string} target - Package target to find in `context`
88
- * @param {Exports | Imports | undefined} context - Package context
89
- * @param {string} [key='.'] - Subpath in `context` being checked
99
+ * @param {Nilable<Exports | Imports>} context - Package context
100
+ * @param {string} [key=DOT] - Subpath in `context` being checked
90
101
  * @return {Nullable<string>} Subpath defined in `context` or `null`
91
102
  */
92
103
  const find = (
93
104
  target: string,
94
- context: Exports | Imports | undefined,
95
- key: string = '.'
105
+ context: Nilable<Exports | Imports>,
106
+ key: string = DOT
96
107
  ): Nullable<string> => {
97
108
  /**
98
109
  * Subpath defined in {@linkcode context} that maps to {@linkcode target}.
@@ -102,143 +113,133 @@ const findSubpath = (
102
113
  let subpath: Nullable<string> = null
103
114
 
104
115
  // match target to subpath
105
- switch (true) {
106
- case !isNIL(context) && typeof context === 'object':
107
- case typeof context === 'string':
116
+ if (isArray(context) || isObjectCurly(context) || isString(context)) {
117
+ /**
118
+ * URL of directory containing relevant `package.json` file.
119
+ *
120
+ * @const {string} pkgdir
121
+ */
122
+ const pkgdir: string = toURL(dir).href.replace(/\/$/, '') + pathe.sep
123
+
124
+ /**
125
+ * URL of relevant `package.json` file.
126
+ *
127
+ * @const {URL} pkg
128
+ */
129
+ const pkg: URL = new URL('package.json', pkgdir)
130
+
131
+ // convert package context to object if using exports sugar
132
+ if (!internal && isExportsSugar(context, pkg, parent)) {
133
+ context = cast<Record<string, Exports>>({ [key]: context })
134
+ }
135
+
136
+ // context is now an object
137
+ context = cast<Record<string, Exports>>(context)
138
+
139
+ /**
140
+ * Subpaths defined in {@linkcode context}.
141
+ *
142
+ * **Note**: Sorted from least to greatest.
143
+ *
144
+ * @see {@linkcode compareSubpaths}
145
+ *
146
+ * @const {string[]} keys
147
+ */
148
+ const subpaths: string[] = sort(
149
+ getSubpaths(context, internal, pkg, parent),
150
+ (s1, s2) => compareSubpaths(s1, s2) * -1
151
+ )
152
+
153
+ // match target to subpath defined in context
154
+ for (const pkgsubpath of subpaths) {
108
155
  /**
109
- * URL of directory containing relevant `package.json` file.
156
+ * Current package target being checked.
110
157
  *
111
- * @const {string} pkgdir
158
+ * @var {Optional<Exports>} tar
112
159
  */
113
- const pkgdir: string = toURL(dir).href.replace(/\/$/, '') + pathe.sep
114
-
115
- /**
116
- * URL of relevant `package.json` file.
117
- *
118
- * @const {URL} pkg
119
- */
120
- const pkg: URL = new URL('package.json', pkgdir)
121
-
122
- // convert package context to object if using exports sugar
123
- if (!internal && isExportsSugar(context, pkg, parent)) {
124
- context = { [key]: context } as Record<string, Exports>
125
- }
126
-
127
- // context is now an object
128
- context = context as Record<string, Exports>
129
-
130
- /**
131
- * Subpaths defined in {@linkcode context}.
132
- *
133
- * **Note**: Sorted from least to greatest.
134
- *
135
- * @see {@linkcode compareSubpaths}
136
- *
137
- * @const {string[]} keys
138
- */
139
- const subpaths: string[] = getSubpaths(
140
- context,
141
- internal,
142
- pkg,
143
- parent
144
- ).sort((s1, s2) => compareSubpaths(s1, s2) * -1)
145
-
146
- // match target to subpath defined in context
147
- for (const pkgsubpath of subpaths) {
148
- /**
149
- * Current package target being checked.
150
- *
151
- * @var {Exports} tar
152
- */
153
- let tar: Exports = context[pkgsubpath]!
154
-
155
- // find subpath
156
- switch (true) {
157
- case Array.isArray(tar):
158
- tar = tar as string[]
159
-
160
- // try matching target based first match in target array
161
- for (const item of tar) {
162
- subpath = find(target, item, pkgsubpath)
160
+ let tar: Optional<Exports> = context[pkgsubpath]
161
+
162
+ // find subpath
163
+ switch (true) {
164
+ case isArray(tar):
165
+ // try matching target based first match in target array
166
+ for (const item of cast<string[]>(tar)) {
167
+ subpath = find(target, item, pkgsubpath)
168
+ if (subpath) break
169
+ }
170
+
171
+ break
172
+ case isObjectCurly(tar):
173
+ tar = cast<Record<string, Exports>>(tar)
174
+
175
+ // try matching target based on export conditions
176
+ for (const property of Object.getOwnPropertyNames(tar)) {
177
+ if (property === condition || conditions.has(property)) {
178
+ subpath = find(target, tar[property], pkgsubpath)
163
179
  if (subpath) break
164
180
  }
165
-
166
- break
167
- case typeof tar === 'object' && !isNIL(tar):
168
- tar = tar as Record<string, Exports>
169
-
170
- // try matching target based on export conditions
171
- for (const prop of Object.getOwnPropertyNames(tar)) {
172
- if (prop === condition || conditions.has(prop)) {
173
- subpath = find(target, tar[prop], pkgsubpath)
174
- if (subpath) break
175
- }
176
- }
177
-
178
- break
179
- case typeof tar === 'string':
180
- tar = tar as string
181
-
182
- /**
183
- * {@linkcode tar} without file extension.
184
- *
185
- * @const {string} tar_ne
186
- */
187
- const tar_ne: string = pathe.changeExt(tar, '')
188
-
189
- /**
190
- * {@linkcode tar_ne} without `'/index'`.
191
- *
192
- * @const {string} tar_ni
193
- */
194
- const tar_ni: string = tar_ne.replace(/\/index$/, '')
195
-
196
- /**
197
- * Index of {@linkcode PATTERN_CHARACTER} in {@linkcode tar}.
198
- *
199
- * @const {number} pattern
200
- */
201
- const pattern: number = tar.indexOf(PATTERN_CHARACTER)
202
-
203
- switch (true) {
204
- // target is an exactish match
205
- case target === tar:
206
- case target === tar_ne:
207
- case target === tar_ni && tar_ne.endsWith('/index'):
208
- case pattern === -1 && (target === tar || target === tar_ne):
209
- subpath = pkgsubpath
210
- break
211
- // pattern character => try finding best match for target
212
- case pattern !== -1 && target.startsWith(tar.slice(0, pattern)):
213
- /**
214
- * Boolean indicating if {@linkcode target} ends with the
215
- * characters after the pattern character (`*`) in
216
- * {@linkcode tar}.
217
- *
218
- * @const {boolean} match
219
- */
220
- const match: boolean =
221
- target.length >= tar.length &&
222
- tar.lastIndexOf(PATTERN_CHARACTER) === pattern &&
223
- (target.endsWith(tar.slice(pattern + 1)) ||
224
- target.endsWith(tar_ne.slice(pattern + 1)))
225
-
226
- // set subpath if match was found
227
- if (match) subpath = pkgsubpath
228
-
229
- break
230
- }
231
-
232
- break
233
- }
234
-
235
- // stop searching for subpath if subpath has been found
236
- if (subpath) break
181
+ }
182
+
183
+ break
184
+ case isString(tar):
185
+ tar = cast<string>(tar)
186
+
187
+ /**
188
+ * {@linkcode tar} without file extension.
189
+ *
190
+ * @const {string} tar_ne
191
+ */
192
+ const tar_ne: string = pathe.changeExt(tar, '')
193
+
194
+ /**
195
+ * {@linkcode tar_ne} without `'/index'`.
196
+ *
197
+ * @const {string} tar_ni
198
+ */
199
+ const tar_ni: string = tar_ne.replace(/\/index$/, '')
200
+
201
+ /**
202
+ * Index of {@linkcode PATTERN_CHARACTER} in {@linkcode tar}.
203
+ *
204
+ * @const {number} pattern
205
+ */
206
+ const pattern: number = tar.indexOf(PATTERN_CHARACTER)
207
+
208
+ switch (true) {
209
+ // target is an exactish match
210
+ case target === tar:
211
+ case target === tar_ne:
212
+ case target === tar_ni && tar_ne.endsWith('/index'):
213
+ case pattern === -1 && (target === tar || target === tar_ne):
214
+ subpath = pkgsubpath
215
+ break
216
+ // pattern character => try finding best match for target
217
+ case pattern !== -1 && target.startsWith(tar.slice(0, pattern)):
218
+ /**
219
+ * Boolean indicating if {@linkcode target} ends with the
220
+ * characters after the pattern character (`*`) in
221
+ * {@linkcode tar}.
222
+ *
223
+ * @const {boolean} match
224
+ */
225
+ const match: boolean =
226
+ target.length >= tar.length &&
227
+ tar.lastIndexOf(PATTERN_CHARACTER) === pattern &&
228
+ (target.endsWith(tar.slice(pattern + 1)) ||
229
+ target.endsWith(tar_ne.slice(pattern + 1)))
230
+
231
+ // set subpath if match was found
232
+ if (match) subpath = pkgsubpath
233
+
234
+ break
235
+ }
236
+
237
+ break
237
238
  }
238
239
 
239
- break
240
- default:
241
- break
240
+ // stop searching for subpath if subpath has been found
241
+ if (subpath) break
242
+ }
242
243
  }
243
244
 
244
245
  return subpath
@@ -16,10 +16,12 @@ import {
16
16
  import { isBuiltin } from '@flex-development/is-builtin'
17
17
  import pathe, { type Ext } from '@flex-development/pathe'
18
18
  import {
19
+ isEmptyString,
19
20
  isUndefined,
20
21
  type EmptyString,
21
22
  type Nilable,
22
- type Nullable
23
+ type Nullable,
24
+ type Optional
23
25
  } from '@flex-development/tutils'
24
26
  import type { URL } from 'node:url'
25
27
  import EXTENSION_FORMAT_MAP from './extension-format-map'
@@ -189,30 +191,34 @@ const getFormat = async (
189
191
  *
190
192
  * [1]: https://nodejs.org/api/errors.html#err_unknown_file_extension
191
193
  *
192
- * @var {string?} suggestion
194
+ * @var {Optional<string>} suggestion
193
195
  */
194
- let suggestion: string | undefined
196
+ let suggestion: Optional<string>
195
197
 
196
198
  // add recommended fix for ERR_UNKNOWN_FILE_EXTENSION if package is
197
199
  // esm-only and module id does not include file extension
198
- if (scope && scope.pkgjson.type === Format.MODULE && ext === '') {
199
- const { pkg } = scope
200
-
201
- /**
202
- * Basename of {@linkcode url.pathname}
203
- *
204
- * @const {string} basename
205
- */
206
- const basename: string = pathe.basename(url.pathname)
207
-
208
- /**
209
- * Relative path from {@linkcode pkg} to {@linkcode url.pathname}.
210
- *
211
- * @const {string} relative
212
- */
213
- const relative: string = pathe.relative(pkg, url.pathname).slice(1)
214
-
215
- suggestion = `Loading extensionless files is not supported inside of "type":"module" package.json contexts. The package.json file ${pkg} caused this "type":"module" context. Try changing ${url.pathname} to have a file extension. Note the "bin" field of package.json can point to a file with an extension, for example {"type":"module","bin":{"${basename}":"${relative}.js"}}`
200
+ if (scope && scope.pkgjson.type === Format.MODULE) {
201
+ if (isEmptyString(ext)) {
202
+ const { pkg } = scope
203
+
204
+ /**
205
+ * Basename of {@linkcode url.pathname}
206
+ *
207
+ * @const {string} basename
208
+ */
209
+ const basename: string = pathe.basename(url.pathname)
210
+
211
+ /**
212
+ * Relative path from {@linkcode pkg} to {@linkcode url.pathname}.
213
+ *
214
+ * @const {string} relative
215
+ */
216
+ const relative: string = pathe
217
+ .relative(pkg, url.pathname)
218
+ .slice(1)
219
+
220
+ suggestion = `Loading extensionless files is not supported inside of "type":"module" package.json contexts. The package.json file ${pkg} caused this "type":"module" context. Try changing ${url.pathname} to have a file extension. Note the "bin" field of package.json can point to a file with an extension, for example {"type":"module","bin":{"${basename}":"${relative}.js"}}`
221
+ }
216
222
  }
217
223
 
218
224
  throw new ERR_UNKNOWN_FILE_EXTENSION(ext, url.pathname, suggestion)
@@ -13,7 +13,7 @@ import {
13
13
  ERR_UNSUPPORTED_ESM_URL_SCHEME,
14
14
  type NodeError
15
15
  } from '@flex-development/errnode'
16
- import { isUndefined } from '@flex-development/tutils'
16
+ import { isUndefined, type Optional } from '@flex-development/tutils'
17
17
  import fs from 'node:fs/promises'
18
18
  import os from 'node:os'
19
19
  import type { URL } from 'node:url'
@@ -39,13 +39,13 @@ import toURL from './to-url'
39
39
  *
40
40
  * @param {ModuleId} id - Module id to evaluate
41
41
  * @param {GetSourceOptions?} [options={}] - Source code retrieval options
42
- * @return {Promise<Uint8Array | string | undefined>} Source code for `id`
42
+ * @return {Promise<Optional<Uint8Array | string>>} Source code for `id`
43
43
  * @throws {NodeError} If unsupported URL scheme is encountered
44
44
  */
45
45
  const getSource = async (
46
46
  id: ModuleId,
47
47
  options: GetSourceOptions = {}
48
- ): Promise<Uint8Array | string | undefined> => {
48
+ ): Promise<Optional<Uint8Array | string>> => {
49
49
  const {
50
50
  experimental_network_imports: network_imports = false,
51
51
  format,
@@ -80,9 +80,9 @@ const getSource = async (
80
80
  /**
81
81
  * Source code for {@linkcode id}.
82
82
  *
83
- * @var {Uint8Array | string | undefined} source
83
+ * @var {Optional<Uint8Array | string>} source
84
84
  */
85
- let source: Uint8Array | string | undefined = ''
85
+ let source: Optional<Uint8Array | string> = ''
86
86
 
87
87
  // get source code based on url protocol
88
88
  switch (url.protocol) {
@@ -20,7 +20,9 @@ export { default as hasCJSSyntax } from './has-cjs-syntax'
20
20
  export { default as hasESMSyntax } from './has-esm-syntax'
21
21
  export { default as isAbsoluteSpecifier } from './is-absolute-specifier'
22
22
  export { default as isBareSpecifier } from './is-bare-specifier'
23
+ export { default as isDirectory } from './is-directory'
23
24
  export { default as isExportsSugar } from './is-exports-sugar'
25
+ export { default as isFile } from './is-file'
24
26
  export { default as isRelativeSpecifier } from './is-relative-specifier'
25
27
  export { default as lookupPackageScope } from './lookup-package-scope'
26
28
  export { default as parseDataURL } from './parse-data-url'
@@ -5,6 +5,7 @@
5
5
 
6
6
  import validateString from '#src/internal/validate-string'
7
7
  import type { NodeError } from '@flex-development/errnode'
8
+ import { trim } from '@flex-development/tutils'
8
9
  import isAbsoluteSpecifier from './is-absolute-specifier'
9
10
  import isRelativeSpecifier from './is-relative-specifier'
10
11
 
@@ -26,7 +27,7 @@ const isBareSpecifier = (specifier: string): boolean => {
26
27
  validateString(specifier, 'specifier')
27
28
 
28
29
  return (
29
- specifier.trim().length > 0 &&
30
+ !!trim(specifier).length &&
30
31
  !isAbsoluteSpecifier(specifier) &&
31
32
  !isRelativeSpecifier(specifier)
32
33
  )
@@ -3,9 +3,9 @@
3
3
  * @module mlly/internal/isDirectory
4
4
  */
5
5
 
6
+ import validateURLString from '#src/internal/validate-url-string'
6
7
  import type { ModuleId } from '#src/types'
7
8
  import fs from 'node:fs'
8
- import validateURLString from './validate-url-string'
9
9
 
10
10
  /**
11
11
  * Checks if a directory exists at the given module `id`.
@@ -6,7 +6,15 @@
6
6
  import type { ModuleId } from '#src/types'
7
7
  import type { NodeError } from '@flex-development/errnode'
8
8
  import type { Exports } from '@flex-development/pkg-types'
9
- import { isNIL } from '@flex-development/tutils'
9
+ import {
10
+ at,
11
+ cast,
12
+ DOT,
13
+ isArray,
14
+ isObjectCurly,
15
+ isString,
16
+ type Nilable
17
+ } from '@flex-development/tutils'
10
18
  import validateExports from './validate-exports'
11
19
 
12
20
  /**
@@ -18,7 +26,7 @@ import validateExports from './validate-exports'
18
26
  * @see {@linkcode Exports}
19
27
  * @see {@linkcode ModuleId}
20
28
  *
21
- * @param {Exports | undefined} exports - Package `exports`
29
+ * @param {Nilable<Exports>} exports - Package `exports`
22
30
  * @param {ModuleId} pkg - URL of relevant `package.json` file
23
31
  * @param {ModuleId} parent - URL of module to resolve from
24
32
  * @return {boolean} `true` if `exports` is using exports sugar
@@ -27,7 +35,7 @@ import validateExports from './validate-exports'
27
35
  * schema is invalid
28
36
  */
29
37
  const isExportsSugar = (
30
- exports: Exports | undefined,
38
+ exports: Nilable<Exports>,
31
39
  pkg: ModuleId,
32
40
  parent: ModuleId
33
41
  ): boolean => {
@@ -42,16 +50,15 @@ const isExportsSugar = (
42
50
 
43
51
  // check if exports sugar is being used
44
52
  switch (true) {
45
- case Array.isArray(exports):
46
- case typeof exports === 'string':
53
+ case isArray(exports):
54
+ case isString(exports):
47
55
  sugar = true
48
56
  break
49
- case isNIL(exports):
50
- case typeof exports !== 'object':
57
+ case !isObjectCurly(exports):
51
58
  sugar = false
52
59
  break
53
60
  default:
54
- exports = exports as Record<string, Exports>
61
+ exports = cast<Record<string, Exports>>(exports)
55
62
 
56
63
  /*
57
64
  * Validate exports object configuration.
@@ -65,7 +72,7 @@ const isExportsSugar = (
65
72
  validateExports(exports, pkg, parent)
66
73
 
67
74
  // check for exports sugar
68
- sugar = !(Object.getOwnPropertyNames(exports)[0]?.startsWith('.') ?? true)
75
+ sugar = !at(Object.getOwnPropertyNames(exports), 0, DOT).startsWith(DOT)
69
76
  }
70
77
 
71
78
  return sugar
@@ -3,9 +3,9 @@
3
3
  * @module mlly/internal/isFile
4
4
  */
5
5
 
6
+ import validateURLString from '#src/internal/validate-url-string'
6
7
  import type { ModuleId } from '#src/types'
7
8
  import fs from 'node:fs'
8
- import validateURLString from './validate-url-string'
9
9
 
10
10
  /**
11
11
  * Checks if a file exists at the given module `id`.
@@ -4,8 +4,8 @@
4
4
  */
5
5
 
6
6
  import validateString from '#src/internal/validate-string'
7
- import type { NodeError } from '@flex-development/errnode'
8
7
  import pathe from '@flex-development/pathe'
8
+ import { DOT, at } from '@flex-development/tutils'
9
9
 
10
10
  /**
11
11
  * Checks if the given `specifier` is a relative specifier.
@@ -19,16 +19,15 @@ import pathe from '@flex-development/pathe'
19
19
  *
20
20
  * @param {string} specifier - Specifier to evaluate
21
21
  * @return {boolean} `true` if `specifier` is relative specifier
22
- * @throws {NodeError<TypeError>} If `specifier` is not a string
23
22
  */
24
23
  const isRelativeSpecifier = (specifier: string): boolean => {
25
24
  validateString(specifier, 'specifier')
26
25
 
27
- return specifier.startsWith('.')
28
- ? specifier.length === 1 || specifier[1] === pathe.sep
26
+ return specifier.startsWith(DOT)
27
+ ? specifier.length === 1 || at(specifier, 1) === pathe.sep
29
28
  ? true
30
- : specifier[1] === '.' &&
31
- (specifier.length === 2 || specifier[2] === pathe.sep)
29
+ : at(specifier, 1) === DOT &&
30
+ (specifier.length === 2 || at(specifier, 2) === pathe.sep)
32
31
  : false
33
32
  }
34
33
 
@@ -9,7 +9,7 @@ import type { ModuleId } from '#src/types'
9
9
  import type { NodeError } from '@flex-development/errnode'
10
10
  import pathe from '@flex-development/pathe'
11
11
  import type { PackageJson } from '@flex-development/pkg-types'
12
- import type { Nullable } from '@flex-development/tutils'
12
+ import { DOT, type Nullable } from '@flex-development/tutils'
13
13
  import { pathToFileURL } from 'node:url'
14
14
  import readPackageJson from './read-package-json'
15
15
  import toURL from './to-url'
@@ -60,7 +60,7 @@ const lookupPackageScope = (
60
60
  // search for package.json
61
61
  while (dir && !dir.endsWith('node_modules')) {
62
62
  // stop search if outside of endpoint
63
- if (pathe.relative(stopdir, dir).startsWith('../')) break
63
+ if (pathe.relative(stopdir, dir).startsWith(DOT.repeat(2) + '/')) break
64
64
 
65
65
  /**
66
66
  * Possible `package.json` object.
@@ -9,7 +9,7 @@ import {
9
9
  type ErrInvalidUrl,
10
10
  type NodeError
11
11
  } from '@flex-development/errnode'
12
- import type { Nullable } from '@flex-development/tutils'
12
+ import { cast, trim, type Nullable } from '@flex-development/tutils'
13
13
  import type { URL } from 'node:url'
14
14
  import toURL from './to-url'
15
15
 
@@ -60,11 +60,11 @@ const parseDataURL = (url: URL | string): ParsedDataUrl => {
60
60
 
61
61
  return {
62
62
  base64: !!base64,
63
- data: data.trim(),
63
+ data: trim(data),
64
64
  href: url.href,
65
65
  mime,
66
66
  pathname: url.pathname,
67
- protocol: url.protocol as ParsedDataUrl['protocol']
67
+ protocol: cast(url.protocol)
68
68
  }
69
69
  }
70
70