UNPKG

4.69 kBJavaScriptView Raw
1const path = require('path')
2const fs = require('fs')
3const packList = require('npm-packlist')
4const precinct = require('precinct')
5const resolve = require('resolve')
6const readPkgUp = require('read-pkg-up')
7const requirePackageName = require('require-package-name')
8const alwaysIgnored = new Set(['aws-sdk'])
9const debug = require('debug')('netlify-dev-plugin:src/utils/finders')
10
11const ignoredExtensions = new Set([
12 '.log',
13 '.lock',
14 '.html',
15 '.md',
16 '.map',
17 '.ts',
18 '.png',
19 '.jpeg',
20 '.jpg',
21 '.gif',
22 '.css',
23 '.patch'
24])
25
26function ignoreMissing(dependency, optional) {
27 return alwaysIgnored.has(dependency) || (optional && dependency in optional)
28}
29
30function includeModuleFile(packageJson, moduleFilePath) {
31 if (packageJson.files) {
32 return true
33 }
34
35 return !ignoredExtensions.has(path.extname(moduleFilePath))
36}
37
38function getDependencies(filename, basedir) {
39 const servicePath = basedir
40
41 const filePaths = new Set()
42 const modulePaths = new Set()
43 const pkgs = {}
44
45 const modulesToProcess = []
46 const localFilesToProcess = [filename]
47
48 function handle(name, basedir, optionalDependencies) {
49 const moduleName = requirePackageName(name.replace(/\\/g, '/'))
50
51 if (alwaysIgnored.has(moduleName)) {
52 return
53 }
54
55 try {
56 const pathToModule = resolve.sync(path.join(moduleName, 'package.json'), {
57 basedir
58 })
59 const pkg = readPkgUp.sync({ cwd: pathToModule })
60
61 if (pkg) {
62 modulesToProcess.push(pkg)
63 }
64 } catch (e) {
65 if (e.code === 'MODULE_NOT_FOUND') {
66 if (ignoreMissing(moduleName, optionalDependencies)) {
67 debug(`WARNING missing optional dependency: ${moduleName}`)
68 return null
69 }
70 try {
71 // this resolves the requested import also against any set up NODE_PATH extensions, etc.
72 const resolved = require.resolve(name)
73 localFilesToProcess.push(resolved)
74 return
75 } catch (e) {
76 throw new Error(`Could not find "${moduleName}" module in file: ${filename.replace(
77 path.dirname(basedir),
78 ''
79 )}.
80
81Please ensure "${moduleName}" is installed in the project.`)
82 }
83 }
84 throw e
85 }
86 }
87
88 while (localFilesToProcess.length) {
89 const currentLocalFile = localFilesToProcess.pop()
90
91 if (filePaths.has(currentLocalFile)) {
92 continue
93 }
94
95 filePaths.add(currentLocalFile)
96 precinct.paperwork(currentLocalFile, { includeCore: false }).forEach(dependency => {
97 if (dependency.indexOf('.') === 0) {
98 const abs = resolve.sync(dependency, {
99 basedir: path.dirname(currentLocalFile)
100 })
101 localFilesToProcess.push(abs)
102 } else {
103 handle(dependency, servicePath)
104 }
105 })
106 }
107
108 while (modulesToProcess.length) {
109 const currentModule = modulesToProcess.pop()
110 const currentModulePath = path.join(currentModule.path, '..')
111 const packageJson = currentModule.pkg
112
113 if (modulePaths.has(currentModulePath)) {
114 continue
115 }
116 modulePaths.add(currentModulePath)
117 pkgs[currentModulePath] = packageJson
118 ;['dependencies', 'peerDependencies', 'optionalDependencies'].forEach(key => {
119 const dependencies = packageJson[key]
120
121 if (dependencies) {
122 Object.keys(dependencies).forEach(dependency => {
123 handle(dependency, currentModulePath, packageJson.optionalDependencies)
124 })
125 }
126 })
127 }
128
129 modulePaths.forEach(modulePath => {
130 const packageJson = pkgs[modulePath]
131 let moduleFilePaths
132
133 moduleFilePaths = packList.sync({ path: modulePath })
134
135 moduleFilePaths.forEach(moduleFilePath => {
136 if (includeModuleFile(packageJson, moduleFilePath)) {
137 filePaths.add(path.join(modulePath, moduleFilePath))
138 }
139 })
140 })
141
142 // TODO: get rid of this
143 const sizes = {}
144 filePaths.forEach(filepath => {
145 const stat = fs.lstatSync(filepath)
146 const ext = path.extname(filepath)
147 sizes[ext] = (sizes[ext] || 0) + stat.size
148 })
149 debug('Sizes per extension: ', sizes)
150
151 return [...filePaths]
152}
153
154function findModuleDir(dir) {
155 let basedir = dir
156 while (!fs.existsSync(path.join(basedir, 'package.json'))) {
157 const newBasedir = path.dirname(basedir)
158 if (newBasedir === basedir) {
159 return null
160 }
161 basedir = newBasedir
162 }
163 return basedir
164}
165
166function findHandler(functionPath) {
167 if (fs.lstatSync(functionPath).isFile()) {
168 return functionPath
169 }
170
171 const handlerPath = path.join(functionPath, `${path.basename(functionPath)}.js`)
172 if (!fs.existsSync(handlerPath)) {
173 return
174 }
175 return handlerPath
176}
177
178module.exports = { getDependencies, findModuleDir, findHandler }