@davidwells/extract-deps 0.0.4 → 0.0.6
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/.claude/settings.local.json +7 -1
- package/examples/verify-basic.js +45 -0
- package/examples/verify-build-graph.js +58 -0
- package/examples/verify-build-order.js +113 -0
- package/examples/verify-find-dependents.js +74 -0
- package/examples/verify-impact-analysis.js +97 -0
- package/examples/verify-package-entries.js +74 -0
- package/package.json +6 -2
- package/src/dep-graph.js +337 -0
- package/src/get-cjs-exports.js +112 -7
- package/src/get-imports.js +1 -0
- package/src/utils.js +1 -1
- package/src/vendor/inspect-parameters-declaration.js +282 -0
- package/src/verify-package-entries.js +228 -0
- package/tests/dep-graph.test.js +358 -0
- package/tests/fixtures/cjs-broken-example/index.js +8 -0
- package/tests/fixtures/cjs-broken-example/one.js +9 -0
- package/tests/fixtures/cjs-broken-example/package.json +7 -0
- package/tests/fixtures/cjs-broken-example/sub-folder/sub-sub-folder/three.js +6 -0
- package/tests/fixtures/cjs-broken-example/sub-folder/two.js +8 -0
- package/tests/fixtures/cjs-deep-example/d-one.js +10 -0
- package/tests/fixtures/cjs-deep-example/d-sub-folder/d-sub-sub-folder/d-three.js +7 -0
- package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two-a.js +8 -0
- package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two-b.js +8 -0
- package/tests/fixtures/cjs-deep-example/d-sub-folder/d-two.js +8 -0
- package/tests/fixtures/cjs-deep-example/index.js +8 -0
- package/tests/fixtures/cjs-deep-example/package.json +15 -0
- package/tests/fixtures/cjs-example/index.js +8 -0
- package/tests/fixtures/cjs-example/one.js +9 -0
- package/tests/fixtures/cjs-example/package.json +7 -0
- package/tests/fixtures/cjs-example/sub-folder/sub-sub-folder/three.js +6 -0
- package/tests/fixtures/cjs-example/sub-folder/two.js +8 -0
- package/tests/fixtures/cjs-parent.js +5 -0
- package/tests/fixtures/esm-broken-fixture/index.js +8 -0
- package/tests/fixtures/esm-broken-fixture/one.js +9 -0
- package/tests/fixtures/esm-broken-fixture/package.json +15 -0
- package/tests/fixtures/esm-broken-fixture/sub-folder/sub-sub-folder/three.js +6 -0
- package/tests/fixtures/esm-broken-fixture/sub-folder/sub-sub-folder-two/deep.js +6 -0
- package/tests/fixtures/esm-broken-fixture/sub-folder/sub-sub-folder-two/even-deeper/wow-deep.js +5 -0
- package/tests/fixtures/esm-broken-fixture/sub-folder/two.js +8 -0
- package/tests/fixtures/esm-broken-fixture/valid.js +7 -0
- package/tests/fixtures/esm-fixture/index.js +8 -0
- package/tests/fixtures/esm-fixture/one.js +9 -0
- package/tests/fixtures/esm-fixture/package.json +11 -0
- package/tests/fixtures/esm-fixture/sub-folder/sub-sub-folder/three.js +6 -0
- package/tests/fixtures/esm-fixture/sub-folder/two.js +8 -0
- package/tests/get-cjs-exports.test.js +171 -0
- package/tests/get-imports.test.js +4 -1
- package/tests/manual/broken-cjs.js +38 -0
- package/tests/manual/broken-esm.js +37 -0
- package/tests/verify-package-entries.test.js +272 -0
- package/types/dep-graph.d.ts +22 -0
- package/types/dep-graph.d.ts.map +1 -0
- package/types/get-cjs-exports.d.ts +35 -0
- package/types/get-cjs-exports.d.ts.map +1 -0
- package/types/get-exports.d.ts +3 -1
- package/types/get-exports.d.ts.map +1 -1
- package/types/index.d.ts +7 -3
- package/types/index.d.ts.map +1 -1
- package/types/utils.d.ts +2 -1
- package/types/utils.d.ts.map +1 -1
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
// Vendored from inspect-parameters-declaration@0.1.0 to avoid vulnerable transitive deps
|
|
2
|
+
// Original packages: split-skip, unpack-string, stringify-parameters, inspect-parameters-declaration
|
|
3
|
+
|
|
4
|
+
'use strict'
|
|
5
|
+
|
|
6
|
+
// split-skip@0.0.2
|
|
7
|
+
function splitSkip(str, separator, skipState) {
|
|
8
|
+
const result = []
|
|
9
|
+
|
|
10
|
+
if (!str) {
|
|
11
|
+
return [str]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let indexStart = 0
|
|
15
|
+
let indexEnd = 0
|
|
16
|
+
let state = { skip: 0 }
|
|
17
|
+
|
|
18
|
+
for (let i = 0; i < str.length; i++) {
|
|
19
|
+
const char = separator.length === 1 ? str[i] : str.substr(i, separator.length)
|
|
20
|
+
|
|
21
|
+
state = skipState ? skipState(state, char, i) : state
|
|
22
|
+
const compareSeparator = char === separator
|
|
23
|
+
|
|
24
|
+
if ((!state.skip && compareSeparator) || i === str.length - 1) {
|
|
25
|
+
indexEnd = i === str.length - 1 ? i + 1 : i
|
|
26
|
+
result.push(str.substring(indexStart, indexEnd))
|
|
27
|
+
indexStart = indexEnd + separator.length
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return result
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// unpack-string@0.0.2
|
|
35
|
+
function unpackString(str, openingChar, closingChar) {
|
|
36
|
+
let knownOpeningChars = '([{<'
|
|
37
|
+
let knownClosingChars = ')]}>'
|
|
38
|
+
|
|
39
|
+
let indexStart
|
|
40
|
+
let indexEnd
|
|
41
|
+
let skip = 0
|
|
42
|
+
|
|
43
|
+
for (let i = 0; i < str.length; i++) {
|
|
44
|
+
const char = str[i]
|
|
45
|
+
|
|
46
|
+
if (!openingChar) {
|
|
47
|
+
if (knownOpeningChars.indexOf(char) < 0) {
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
openingChar = char
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
closingChar = closingChar || knownClosingChars[knownOpeningChars.indexOf(openingChar)]
|
|
54
|
+
|
|
55
|
+
let matchOpeningChar = char === openingChar
|
|
56
|
+
let matchClosingChar = char === closingChar
|
|
57
|
+
|
|
58
|
+
if (typeof(indexStart) === 'undefined' && matchOpeningChar) {
|
|
59
|
+
indexStart = i
|
|
60
|
+
continue
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (matchOpeningChar) {
|
|
64
|
+
skip += 1
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (skip && matchClosingChar) {
|
|
69
|
+
skip -= 1
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (matchClosingChar) {
|
|
74
|
+
indexEnd = i
|
|
75
|
+
break
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return str.substring(indexStart + 1, indexEnd)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// stringify-parameters@0.0.7
|
|
83
|
+
function stringifyParameters(fn) {
|
|
84
|
+
const asyncFunctionConstructor = Object.getPrototypeOf(async function(){}).constructor
|
|
85
|
+
if (!fn || (fn.constructor !== String && fn.constructor !== Function && fn.constructor !== asyncFunctionConstructor)) {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let fnString = fn.toString().replace(/^\s+|\s+$/g, '')
|
|
90
|
+
if (!fnString) {
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const isDeclaredWithFunctionKeyword = /^function/i
|
|
95
|
+
const isNotArrowFunction = /^[^\s=>]+\(/i
|
|
96
|
+
|
|
97
|
+
// Arrow function with param declared without parenthesis and no default value
|
|
98
|
+
if (!isDeclaredWithFunctionKeyword.test(fnString) && !isNotArrowFunction.test(fnString)) {
|
|
99
|
+
let arrowWithoutParenthesis = fnString.match(/^(.*?)=>/)
|
|
100
|
+
if (arrowWithoutParenthesis) {
|
|
101
|
+
return unpackString(arrowWithoutParenthesis[1]).replace(/^\s+|\s+$/g, '')
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return unpackString(fnString).replace(/^\s+|\s+$/g, '')
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// inspect-parameters-declaration@0.1.0
|
|
109
|
+
const isArrayLike = p => p.match(/^\[+/)
|
|
110
|
+
const isObjectLike = p => p.match(/^{+/)
|
|
111
|
+
const matchObjectProperty = p => p.match(/^([^{]+):(.*)/)
|
|
112
|
+
|
|
113
|
+
function splitSkipBrackets(string, delimiter) {
|
|
114
|
+
return splitSkip(string, delimiter, (state, char, i) => {
|
|
115
|
+
if ('{[('.indexOf(char) >= 0) {
|
|
116
|
+
state.skip += 1
|
|
117
|
+
}
|
|
118
|
+
if ('}])'.indexOf(char) >= 0) {
|
|
119
|
+
state.skip -= 1
|
|
120
|
+
}
|
|
121
|
+
return state
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function getParameterSpec(param) {
|
|
126
|
+
if (!param) {
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const [parameter, defaultValue] = splitSkipBrackets(param, '=').map(item => item.trim().replace(/^["']|["']$/g, ''))
|
|
131
|
+
const parameterSpec = { parameter }
|
|
132
|
+
|
|
133
|
+
if (defaultValue) {
|
|
134
|
+
parameterSpec.defaultValue = defaultValue
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const expectsDestructuring = !!isArrayLike(param) || !!isObjectLike(param)
|
|
138
|
+
if (expectsDestructuring) {
|
|
139
|
+
parameterSpec.expectsDestructuring = true
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const isRestParameter = parameterSpec.parameter.match(/^\.{3}/)
|
|
143
|
+
if (isRestParameter) {
|
|
144
|
+
parameterSpec.parameter = parameterSpec.parameter.replace(/^\.{3}/, '')
|
|
145
|
+
parameterSpec.isRestParameter = true
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
parameterSpec.declaration = param
|
|
149
|
+
return parameterSpec
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function getParametersArray(paramsString) {
|
|
153
|
+
if (!paramsString) {
|
|
154
|
+
return []
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
paramsString = paramsString.trim()
|
|
158
|
+
const result = splitSkipBrackets(paramsString, ',')
|
|
159
|
+
return result.map(item => item.trim()).filter(item => !!item)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function destructureParametersFromArray(param, parameters = []) {
|
|
163
|
+
let parametersArray = getParametersArray(unpackString(param))
|
|
164
|
+
|
|
165
|
+
parametersArray.forEach(param => {
|
|
166
|
+
if (isArrayLike(param) || isObjectLike(param)) {
|
|
167
|
+
return destructureParameter(param, parameters)
|
|
168
|
+
}
|
|
169
|
+
parameters.push(getParameterSpec(param))
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
return parameters
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function destructureParametersFromObject(param, parameters = []) {
|
|
176
|
+
let parametersArray = getParametersArray(unpackString(param))
|
|
177
|
+
|
|
178
|
+
parametersArray.forEach(param => {
|
|
179
|
+
let objectProperty = matchObjectProperty(param)
|
|
180
|
+
if (objectProperty) {
|
|
181
|
+
let [, key, value] = objectProperty.map(v => v.trim())
|
|
182
|
+
if (isArrayLike(value) || isObjectLike(value)) {
|
|
183
|
+
return destructureParameter(value, parameters)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
parameters.push(getParameterSpec(param))
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
return parameters
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function destructureParameter(parameter, parameters) {
|
|
193
|
+
if (isArrayLike(parameter)) {
|
|
194
|
+
return destructureParametersFromArray(parameter, parameters)
|
|
195
|
+
}
|
|
196
|
+
if (isObjectLike(parameter)) {
|
|
197
|
+
return destructureParametersFromObject(parameter, parameters)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function destructureParameters(param) {
|
|
202
|
+
const parametersArray = getParametersArray(param)
|
|
203
|
+
|
|
204
|
+
return parametersArray.reduce((parameters, parameter) => {
|
|
205
|
+
if (isArrayLike(parameter)) {
|
|
206
|
+
return parameters.concat(destructureParametersFromArray(parameter))
|
|
207
|
+
}
|
|
208
|
+
if (isObjectLike(parameter)) {
|
|
209
|
+
return parameters.concat(destructureParametersFromObject(parameter))
|
|
210
|
+
}
|
|
211
|
+
return parameters.concat(getParameterSpec(parameter))
|
|
212
|
+
}, [])
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function inspectParameterFromString(parameter) {
|
|
216
|
+
const parameterSpec = getParameterSpec(parameter)
|
|
217
|
+
if (!parameterSpec || (!parameterSpec.parameter && !parameterSpec.declaration)) {
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (parameterSpec.expectsDestructuring) {
|
|
222
|
+
parameterSpec.destructuredParameters = destructureParameters(parameter)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return parameterSpec
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function inspectParametersFromString(parameters) {
|
|
229
|
+
const parametersArray = getParametersArray(parameters)
|
|
230
|
+
|
|
231
|
+
const inspectedParameters = parametersArray.reduce((result, parameter) => {
|
|
232
|
+
const parameterSpec = inspectParameterFromString(parameter)
|
|
233
|
+
return result.concat(parameterSpec)
|
|
234
|
+
}, [])
|
|
235
|
+
|
|
236
|
+
return inspectedParameters
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function inspectParametersFromFunction(fn) {
|
|
240
|
+
const parametersStringified = stringifyParameters(fn)
|
|
241
|
+
return inspectParametersFromString(parametersStringified)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function getAllInspectedParametersNames(inspectedParameters) {
|
|
245
|
+
if (!inspectedParameters) {
|
|
246
|
+
return []
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
inspectedParameters = inspectedParameters.constructor === Array ? inspectedParameters : [inspectedParameters]
|
|
250
|
+
return inspectedParameters.reduce((result, item) => {
|
|
251
|
+
if (item.expectsDestructuring) {
|
|
252
|
+
return result.concat(item.destructuredParameters.map(item => item.parameter))
|
|
253
|
+
}
|
|
254
|
+
return result.concat(item.parameter)
|
|
255
|
+
}, [])
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function getParametersNames(source) {
|
|
259
|
+
const inspectedParameters = inspectParameters(source)
|
|
260
|
+
return getAllInspectedParametersNames(inspectedParameters)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function getParametersNamesFromInspection(inspectedParameters) {
|
|
264
|
+
return getAllInspectedParametersNames(inspectedParameters)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function inspectParameters(source) {
|
|
268
|
+
if (!source) {
|
|
269
|
+
return
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const asyncFunctionConstructor = Object.getPrototypeOf(async function(){}).constructor
|
|
273
|
+
if (source.constructor === Function || source.constructor === asyncFunctionConstructor) {
|
|
274
|
+
return inspectParametersFromFunction(source)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (source.constructor === String) {
|
|
278
|
+
return inspectParametersFromString(source)
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
module.exports = { inspectParameters, getParametersNames, getParametersNamesFromInspection }
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// Verify package.json entry points and their dependencies
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const { depGraph, resolveDepPaths } = require('./dep-graph')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Extract all entry points from package.json
|
|
8
|
+
* @param {string} packageJsonPath - Path to package.json
|
|
9
|
+
* @returns {Array<{field: string, path: string, resolvedPath: string}>} - Array of entry point objects
|
|
10
|
+
*/
|
|
11
|
+
function getPackageEntryPoints(packageJsonPath) {
|
|
12
|
+
const packageDir = path.dirname(packageJsonPath)
|
|
13
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
|
14
|
+
|
|
15
|
+
return collectEntryPoints(packageJson, packageDir)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function collectEntryPoints(packageJson, packageDir) {
|
|
19
|
+
const entryPoints = []
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Add entry point if it's a valid JS file
|
|
23
|
+
* @param {string} field - Field name from package.json
|
|
24
|
+
* @param {string} filePath - Relative file path
|
|
25
|
+
*/
|
|
26
|
+
function addEntryPoint(field, filePath) {
|
|
27
|
+
if (!filePath) return
|
|
28
|
+
|
|
29
|
+
// Skip .d.ts files
|
|
30
|
+
if (filePath.endsWith('.d.ts')) return
|
|
31
|
+
|
|
32
|
+
// Skip .json files
|
|
33
|
+
if (filePath.endsWith('.json')) return
|
|
34
|
+
|
|
35
|
+
const resolvedPath = path.resolve(packageDir, filePath)
|
|
36
|
+
entryPoints.push({
|
|
37
|
+
field,
|
|
38
|
+
path: filePath,
|
|
39
|
+
resolvedPath
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Handle main, module, browser, types
|
|
44
|
+
if (packageJson.main) {
|
|
45
|
+
addEntryPoint('main', packageJson.main)
|
|
46
|
+
}
|
|
47
|
+
if (packageJson.module) {
|
|
48
|
+
addEntryPoint('module', packageJson.module)
|
|
49
|
+
}
|
|
50
|
+
if (packageJson.browser) {
|
|
51
|
+
if (typeof packageJson.browser === 'string') {
|
|
52
|
+
addEntryPoint('browser', packageJson.browser)
|
|
53
|
+
}
|
|
54
|
+
// browser can also be an object mapping, skip for now
|
|
55
|
+
}
|
|
56
|
+
if (packageJson.types) {
|
|
57
|
+
// Skip .d.ts files
|
|
58
|
+
if (!packageJson.types.endsWith('.d.ts')) {
|
|
59
|
+
addEntryPoint('types', packageJson.types)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Handle bin
|
|
64
|
+
if (packageJson.bin) {
|
|
65
|
+
if (typeof packageJson.bin === 'string') {
|
|
66
|
+
addEntryPoint('bin', packageJson.bin)
|
|
67
|
+
} else if (typeof packageJson.bin === 'object') {
|
|
68
|
+
for (const [binName, binPath] of Object.entries(packageJson.bin)) {
|
|
69
|
+
addEntryPoint(`bin.${binName}`, binPath)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Handle exports
|
|
75
|
+
if (packageJson.exports) {
|
|
76
|
+
extractExportsEntryPoints(packageJson.exports, 'exports', addEntryPoint)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return entryPoints
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Recursively extract entry points from exports field
|
|
84
|
+
* @param {any} exportsValue - Value from exports field
|
|
85
|
+
* @param {string} fieldPrefix - Current field path
|
|
86
|
+
* @param {Function} addEntryPoint - Callback to add entry point
|
|
87
|
+
*/
|
|
88
|
+
function extractExportsEntryPoints(exportsValue, fieldPrefix, addEntryPoint) {
|
|
89
|
+
if (typeof exportsValue === 'string') {
|
|
90
|
+
addEntryPoint(fieldPrefix, exportsValue)
|
|
91
|
+
} else if (typeof exportsValue === 'object' && exportsValue !== null) {
|
|
92
|
+
for (const [key, value] of Object.entries(exportsValue)) {
|
|
93
|
+
// Build field name with bracket notation for paths that start with . or contain special chars
|
|
94
|
+
const needsBrackets = key.startsWith('.') || key.startsWith('/')
|
|
95
|
+
const newFieldPrefix = needsBrackets ? `${fieldPrefix}["${key}"]` : `${fieldPrefix}.${key}`
|
|
96
|
+
|
|
97
|
+
// Handle conditional exports (import, require, browser, types, etc.)
|
|
98
|
+
if (key === 'import' || key === 'require' || key === 'browser' || key === 'default') {
|
|
99
|
+
if (typeof value === 'string') {
|
|
100
|
+
addEntryPoint(newFieldPrefix, value)
|
|
101
|
+
}
|
|
102
|
+
} else if (key === 'types') {
|
|
103
|
+
// Skip .d.ts files
|
|
104
|
+
if (typeof value === 'string' && !value.endsWith('.d.ts')) {
|
|
105
|
+
addEntryPoint(newFieldPrefix, value)
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
// Recurse for nested exports
|
|
109
|
+
extractExportsEntryPoints(value, newFieldPrefix, addEntryPoint)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Verify all package.json entry points and collect dependencies
|
|
117
|
+
* @param {string} packagePath - Path to package.json
|
|
118
|
+
* @param {object} options - Options
|
|
119
|
+
* @param {boolean} [options.collectDeps] - If true, collect dependency paths for each entry point. Default: true
|
|
120
|
+
* @param {boolean} [options.verifyGraph] - If true, verify imports/exports. Default: true
|
|
121
|
+
* @param {boolean} [options.throwIfErrors] - If true, throw an error if there are any errors. Default: false
|
|
122
|
+
* @returns {{entryPoints: Array, sourceFiles: Set, errors: Array}} - Verification results
|
|
123
|
+
*/
|
|
124
|
+
function verifyPackageEntries(packagePath, options = {}) {
|
|
125
|
+
const { collectDeps = true, verifyGraph = true } = options
|
|
126
|
+
|
|
127
|
+
const entryPoints = getPackageEntryPoints(packagePath)
|
|
128
|
+
const sourceFilesSet = new Set()
|
|
129
|
+
const allErrors = []
|
|
130
|
+
const results = []
|
|
131
|
+
|
|
132
|
+
for (const entryPoint of entryPoints) {
|
|
133
|
+
const result = {
|
|
134
|
+
field: entryPoint.field,
|
|
135
|
+
path: entryPoint.path,
|
|
136
|
+
resolvedPath: entryPoint.resolvedPath,
|
|
137
|
+
valid: false,
|
|
138
|
+
sourceFiles: [],
|
|
139
|
+
error: undefined
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
// Check if file exists
|
|
144
|
+
if (!fs.existsSync(entryPoint.resolvedPath)) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`package.json "${entryPoint.field}" points to non-existent file: "${entryPoint.resolvedPath}"`
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (collectDeps) {
|
|
151
|
+
// Collect dependencies using resolveDepPaths
|
|
152
|
+
const relativeDeps = resolveDepPaths(entryPoint.resolvedPath, { verifyGraph, verifyNodeModules: true })
|
|
153
|
+
result.sourceFiles = relativeDeps
|
|
154
|
+
|
|
155
|
+
// Add to sourceFiles set
|
|
156
|
+
relativeDeps.forEach(dep => sourceFilesSet.add(dep))
|
|
157
|
+
} else if (verifyGraph) {
|
|
158
|
+
// Just verify without collecting deps
|
|
159
|
+
depGraph(entryPoint.resolvedPath, { buildGraph: false, verifyGraph: true })
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
result.valid = true
|
|
163
|
+
} catch (error) {
|
|
164
|
+
result.error = error
|
|
165
|
+
allErrors.push({
|
|
166
|
+
packagePath,
|
|
167
|
+
field: entryPoint.field,
|
|
168
|
+
path: entryPoint.path,
|
|
169
|
+
errorMsg: error.message,
|
|
170
|
+
error: error
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
results.push(result)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (options.throwIfErrors && allErrors.length) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Found ${allErrors.length} validation error${allErrors.length === 1 ? '' : 's'}:
|
|
180
|
+
${JSON.stringify(allErrors, null, 2)}`
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
entryPoints: results,
|
|
186
|
+
sourceFiles: sourceFilesSet,
|
|
187
|
+
errors: allErrors
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (require.main === module) {
|
|
192
|
+
let pkgPath = path.resolve(__dirname, '../tests/fixtures/esm-broken-fixture/package.json')
|
|
193
|
+
//pkgPath = path.resolve(__dirname, '../tests/fixtures/cjs-broken-example/package.json')
|
|
194
|
+
console.log('=== Package Entry Points ===\n')
|
|
195
|
+
const entryPoints = getPackageEntryPoints(pkgPath)
|
|
196
|
+
entryPoints.forEach(ep => {
|
|
197
|
+
console.log(`${ep.field}: ${ep.path}`)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
console.log('\n=== Verification Results ===\n')
|
|
201
|
+
const throwIfErrors = false
|
|
202
|
+
const results = verifyPackageEntries(pkgPath, { throwIfErrors })
|
|
203
|
+
console.log('results', results)
|
|
204
|
+
|
|
205
|
+
results.entryPoints.forEach(ep => {
|
|
206
|
+
|
|
207
|
+
console.log(`\nField "${ep.field}": ${ep.valid ? '' : ''}`)
|
|
208
|
+
if (ep.sourceFiles) {
|
|
209
|
+
console.log(` - Dependencies: ${ep.sourceFiles.length} files`)
|
|
210
|
+
ep.sourceFiles.forEach(sf => {
|
|
211
|
+
console.log(`- ${sf}`)
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
if (ep.error) {
|
|
215
|
+
console.log(`- Error: ${ep.error.message}`)
|
|
216
|
+
}
|
|
217
|
+
console.log('───────────────────────────────')
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
console.log(`\nTotal unique dependencies: ${results.sourceFiles.size}`)
|
|
221
|
+
console.log(`Total errors: ${results.errors.length}`)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
module.exports = {
|
|
225
|
+
getPackageEntryPoints,
|
|
226
|
+
verifyPackageEntries,
|
|
227
|
+
collectEntryPoints
|
|
228
|
+
}
|