Skip to content

Commit

Permalink
check named exports on destructured require
Browse files Browse the repository at this point in the history
  • Loading branch information
vikr01 committed Oct 26, 2018
1 parent b4a2f11 commit 2a3153c
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 1 deletion.
72 changes: 72 additions & 0 deletions src/rules/named.js
Expand Up @@ -7,9 +7,22 @@ module.exports = {
docs: {
url: docsUrl('named'),
},
schema: [
{
type: 'object',
properties: {
commonjs: {
type: 'boolean',
},
},
additionalProperties: false,
},
],
},

create: function (context) {
const options = context.options[0] || {}

function checkSpecifiers(key, type, node) {
// ignore local exports and type imports
if (node.source == null || node.importKind === 'type') return
Expand Down Expand Up @@ -51,6 +64,63 @@ module.exports = {
})
}

function checkRequire(node) {
if(!options.commonjs) return

if(node.type !== 'VariableDeclarator') return

if(!node.id || node.id.type !== 'ObjectPattern' || node.id.properties.length === 0) {
// return if it's not an object destructure or it's an empty object destructure
return
}

if(!node.init || node.init.type !== 'CallExpression') {
// return if there is no call expression on the right side
return
}

const call = node.init
const source = call.arguments[0]
const variableImports = node.id.properties
const variableExports = Exports.get(source.value, context)

// return if it's not a commonjs require statement
if (call.callee.type !== 'Identifier') return
if (call.callee.name !== 'require') return
if (call.arguments.length !== 1) return

// return if it's not a string source
if(source.type !== 'Literal') return

if (variableExports == null) return

if (variableExports.errors.length) {
variableExports.reportErrors(context, node)
return
}

variableImports.forEach(function (im) {
if (im.type !== 'Property') return
if (!im.key || im.key.type !== 'Identifier') return

const deepLookup = variableExports.hasDeep(im.key.name)

if (!deepLookup.found) {
if (deepLookup.path.length > 1) {
const deepPath = deepLookup.path
.map(i => path.relative(path.dirname(context.getFilename()), i.path))
.join(' -> ')

context.report(im.key,
`${im.key.name} not found via ${deepPath}`)
} else {
context.report(im.key,
im.key.name + ' not found in \'' + source.value + '\'')
}
}
})
}

return {
'ImportDeclaration': checkSpecifiers.bind( null
, 'imported'
Expand All @@ -61,6 +131,8 @@ module.exports = {
, 'local'
, 'ExportSpecifier'
),

'VariableDeclarator': checkRequire,
}

},
Expand Down
50 changes: 49 additions & 1 deletion tests/src/rules/named.js
Expand Up @@ -178,6 +178,37 @@ ruleTester.run('named', rule, {
code: 'import { common } from "./re-export-default"',
}),

// destructured requires with commonjs option
test({
code: 'const { destructuredProp } = require("./named-exports")',
options: [{commonjs: true}],
}),
test({
code: 'let { arrayKeyProp } = require("./named-exports")',
options: [{commonjs: true}],
}),
test({
code: 'const { deepProp } = require("./named-exports")',
options: [{commonjs: true}],
}),

test({
code: 'const { foo,'
+' bar } = requrie("./re-export-names")',
options: [{commonjs: true}],
}),

test({
code: 'const { baz } = require("./bar")',
errors: [error('baz', './bar')],
}),

test({
code: 'const { baz } = require("./bar")',
errors: [error('baz', './bar')],
options: [{commonjs: false}],
}),

...SYNTAX_CASES,
],

Expand Down Expand Up @@ -207,7 +238,6 @@ ruleTester.run('named', rule, {

test({
code: 'import { a } from "./re-export-names"',
options: [2, 'es6-only'],
errors: [error('a', './re-export-names')],
}),

Expand All @@ -234,6 +264,24 @@ ruleTester.run('named', rule, {
errors: ["baz not found via broken-trampoline.js -> named-exports.js"],
}),

test({
code: 'const { baz } = require("./bar")',
errors: [error('baz', './bar')],
options: [{commonjs: true}],
}),

test({
code: 'let { baz } = require("./bar")',
errors: [error('baz', './bar')],
options: [{commonjs: true}],
}),

test({
code: 'const { baz: bar, bop } = require("./bar"), { a } = require("./re-export-names")',
errors: [error('baz', './bar'), error('bop', './bar'), error('a', './re-export-names')],
options: [{commonjs: true}],
}),

// parse errors
// test({
// code: "import { a } from './test.coffee';",
Expand Down

0 comments on commit 2a3153c

Please sign in to comment.