|
| 1 | +import fs from 'fs' |
| 2 | +import pkgUp from 'pkg-up' |
| 3 | +import importType from '../core/importType' |
| 4 | +import isStaticRequire from '../core/staticRequire' |
| 5 | + |
| 6 | +function getDependencies(context) { |
| 7 | + const filepath = pkgUp.sync(context.getFilename()) |
| 8 | + if (!filepath) { |
| 9 | + return null |
| 10 | + } |
| 11 | + |
| 12 | + try { |
| 13 | + const packageContent = JSON.parse(fs.readFileSync(filepath, 'utf8')) |
| 14 | + return { |
| 15 | + dependencies: packageContent.dependencies || {}, |
| 16 | + devDependencies: packageContent.devDependencies || {}, |
| 17 | + } |
| 18 | + } catch (e) { |
| 19 | + return null |
| 20 | + } |
| 21 | +} |
| 22 | + |
| 23 | +function missingErrorMessage(packageName) { |
| 24 | + return `'${packageName}' is not listed in the project's dependencies. ` + |
| 25 | + `Run 'npm i -S ${packageName}' to add it` |
| 26 | +} |
| 27 | + |
| 28 | +function devDepErrorMessage(packageName) { |
| 29 | + return `'${packageName}' is not listed in the project's dependencies, not devDependencies.` |
| 30 | +} |
| 31 | + |
| 32 | +function reportIfMissing(context, deps, allowDevDeps, node, name) { |
| 33 | + if (importType(name, context) !== 'external') { |
| 34 | + return |
| 35 | + } |
| 36 | + const packageName = name.split('/')[0] |
| 37 | + |
| 38 | + if (deps.dependencies[packageName] === undefined) { |
| 39 | + if (!allowDevDeps) { |
| 40 | + context.report(node, devDepErrorMessage(packageName)) |
| 41 | + } else if (deps.devDependencies[packageName] === undefined) { |
| 42 | + context.report(node, missingErrorMessage(packageName)) |
| 43 | + } |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +module.exports = function (context) { |
| 48 | + const options = context.options[0] || {} |
| 49 | + const allowDevDeps = options.devDependencies !== false |
| 50 | + const deps = getDependencies(context) |
| 51 | + |
| 52 | + if (!deps) { |
| 53 | + return {} |
| 54 | + } |
| 55 | + |
| 56 | + // todo: use module visitor from module-utils core |
| 57 | + return { |
| 58 | + ImportDeclaration: function (node) { |
| 59 | + reportIfMissing(context, deps, allowDevDeps, node, node.source.value) |
| 60 | + }, |
| 61 | + CallExpression: function handleRequires(node) { |
| 62 | + if (isStaticRequire(node)) { |
| 63 | + reportIfMissing(context, deps, allowDevDeps, node, node.arguments[0].value) |
| 64 | + } |
| 65 | + }, |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +module.exports.schema = [ |
| 70 | + { |
| 71 | + 'type': 'object', |
| 72 | + 'properties': { |
| 73 | + 'devDependencies': { 'type': 'boolean' }, |
| 74 | + }, |
| 75 | + 'additionalProperties': false, |
| 76 | + }, |
| 77 | +] |
0 commit comments