This repository has been archived by the owner on May 22, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 35
/
traverse.ts
113 lines (95 loc) · 3.1 KB
/
traverse.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { promises as fs } from 'fs'
import { dirname } from 'path'
import { nonNullable } from '../../../../utils/non_nullable'
import { getModuleName } from '../../utils/module'
import { PackageJson } from '../../utils/package_json'
import { TraversalCache } from '../../utils/traversal_cache'
import { getNestedDependencies, handleModuleNotFound } from './nested'
import { getPublishedFiles } from './published'
import { resolvePackage } from './resolve'
import { getSideFiles } from './side_files'
const EXCLUDED_MODULES = new Set(['aws-sdk'])
// When a file requires a module, we find its path inside `node_modules` and
// use all its published files. We also recurse on the module's dependencies.
const getDependencyPathsForDependency = async function ({
dependency,
basedir,
state,
packageJson,
pluginsModulesPath,
}: {
dependency: string
basedir: string
state: TraversalCache
packageJson: PackageJson
pluginsModulesPath?: string
}): Promise<string[]> {
const moduleName = getModuleName(dependency)
// Happens when doing require("@scope") (not "@scope/name") or other oddities
// Ignore those.
if (moduleName === null) {
return []
}
try {
return await getDependenciesForModuleName({ moduleName, basedir, state, pluginsModulesPath })
} catch (error) {
return handleModuleNotFound({ error, moduleName, packageJson })
}
}
const getDependenciesForModuleName = async function ({
moduleName,
basedir,
state,
pluginsModulesPath,
}: {
moduleName: string
basedir: string
state: TraversalCache
pluginsModulesPath?: string
}): Promise<string[]> {
if (isExcludedModule(moduleName)) {
return []
}
// Find the Node.js module directory path
const packagePath = await resolvePackage(moduleName, [basedir, pluginsModulesPath].filter(nonNullable))
if (packagePath === undefined) {
return []
}
const modulePath = dirname(packagePath)
if (state.modulePaths.has(modulePath)) {
return []
}
state.moduleNames.add(moduleName)
state.modulePaths.add(modulePath)
// The path depends on the user's build, i.e. must be dynamic
const packageJson = JSON.parse(await fs.readFile(packagePath, 'utf8'))
const [publishedFiles, sideFiles, depsPaths] = await Promise.all([
getPublishedFiles(modulePath),
getSideFiles(modulePath, moduleName),
getNestedModules({ modulePath, state, packageJson, pluginsModulesPath }),
])
return [...publishedFiles, ...sideFiles, ...depsPaths]
}
const isExcludedModule = function (moduleName: string): boolean {
return EXCLUDED_MODULES.has(moduleName) || moduleName.startsWith('@types/')
}
const getNestedModules = async function ({
modulePath,
state,
packageJson,
pluginsModulesPath,
}: {
modulePath: string
state: TraversalCache
packageJson: PackageJson
pluginsModulesPath?: string
}) {
const dependencies = getNestedDependencies(packageJson)
const depsPaths = await Promise.all(
dependencies.map((dependency) =>
getDependencyPathsForDependency({ dependency, basedir: modulePath, state, packageJson, pluginsModulesPath }),
),
)
return depsPaths.flat()
}
export { getDependencyPathsForDependency }