193 lines
21 KiB
JavaScript
193 lines
21 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
var _ExportMap = require('../ExportMap');
|
||
|
|
||
|
var _ExportMap2 = _interopRequireDefault(_ExportMap);
|
||
|
|
||
|
var _importDeclaration = require('../importDeclaration');
|
||
|
|
||
|
var _importDeclaration2 = _interopRequireDefault(_importDeclaration);
|
||
|
|
||
|
var _declaredScope = require('eslint-module-utils/declaredScope');
|
||
|
|
||
|
var _declaredScope2 = _interopRequireDefault(_declaredScope);
|
||
|
|
||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
|
||
|
module.exports = {
|
||
|
meta: {
|
||
|
schema: [{
|
||
|
'type': 'object',
|
||
|
'properties': {
|
||
|
'allowComputed': {
|
||
|
'description': 'If `false`, will report computed (and thus, un-lintable) references ' + 'to namespace members.',
|
||
|
'type': 'boolean',
|
||
|
'default': false
|
||
|
}
|
||
|
},
|
||
|
'additionalProperties': false
|
||
|
}]
|
||
|
},
|
||
|
|
||
|
create: function namespaceRule(context) {
|
||
|
|
||
|
// read options
|
||
|
var _ref = context.options[0] || {},
|
||
|
_ref$allowComputed = _ref.allowComputed;
|
||
|
|
||
|
const allowComputed = _ref$allowComputed === undefined ? false : _ref$allowComputed;
|
||
|
|
||
|
|
||
|
const namespaces = new Map();
|
||
|
|
||
|
function makeMessage(last, namepath) {
|
||
|
return `'${last.name}' not found in` + (namepath.length > 1 ? ' deeply ' : ' ') + `imported namespace '${namepath.join('.')}'.`;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
|
||
|
// pick up all imports at body entry time, to properly respect hoisting
|
||
|
'Program': function (_ref2) {
|
||
|
let body = _ref2.body;
|
||
|
|
||
|
function processBodyStatement(declaration) {
|
||
|
if (declaration.type !== 'ImportDeclaration') return;
|
||
|
|
||
|
if (declaration.specifiers.length === 0) return;
|
||
|
|
||
|
const imports = _ExportMap2.default.get(declaration.source.value, context);
|
||
|
if (imports == null) return null;
|
||
|
|
||
|
if (imports.errors.length) {
|
||
|
imports.reportErrors(context, declaration);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (let specifier of declaration.specifiers) {
|
||
|
switch (specifier.type) {
|
||
|
case 'ImportNamespaceSpecifier':
|
||
|
if (!imports.size) {
|
||
|
context.report(specifier, `No exported names found in module '${declaration.source.value}'.`);
|
||
|
}
|
||
|
namespaces.set(specifier.local.name, imports);
|
||
|
break;
|
||
|
case 'ImportDefaultSpecifier':
|
||
|
case 'ImportSpecifier':
|
||
|
{
|
||
|
const meta = imports.get(
|
||
|
// default to 'default' for default http://i.imgur.com/nj6qAWy.jpg
|
||
|
specifier.imported ? specifier.imported.name : 'default');
|
||
|
if (!meta || !meta.namespace) break;
|
||
|
namespaces.set(specifier.local.name, meta.namespace);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
body.forEach(processBodyStatement);
|
||
|
},
|
||
|
|
||
|
// same as above, but does not add names to local map
|
||
|
'ExportNamespaceSpecifier': function (namespace) {
|
||
|
var declaration = (0, _importDeclaration2.default)(context);
|
||
|
|
||
|
var imports = _ExportMap2.default.get(declaration.source.value, context);
|
||
|
if (imports == null) return null;
|
||
|
|
||
|
if (imports.errors.length) {
|
||
|
imports.reportErrors(context, declaration);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!imports.size) {
|
||
|
context.report(namespace, `No exported names found in module '${declaration.source.value}'.`);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// todo: check for possible redefinition
|
||
|
|
||
|
'MemberExpression': function (dereference) {
|
||
|
if (dereference.object.type !== 'Identifier') return;
|
||
|
if (!namespaces.has(dereference.object.name)) return;
|
||
|
|
||
|
if (dereference.parent.type === 'AssignmentExpression' && dereference.parent.left === dereference) {
|
||
|
context.report(dereference.parent, `Assignment to member of namespace '${dereference.object.name}'.`);
|
||
|
}
|
||
|
|
||
|
// go deep
|
||
|
var namespace = namespaces.get(dereference.object.name);
|
||
|
var namepath = [dereference.object.name];
|
||
|
// while property is namespace and parent is member expression, keep validating
|
||
|
while (namespace instanceof _ExportMap2.default && dereference.type === 'MemberExpression') {
|
||
|
|
||
|
if (dereference.computed) {
|
||
|
if (!allowComputed) {
|
||
|
context.report(dereference.property, 'Unable to validate computed reference to imported namespace \'' + dereference.object.name + '\'.');
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!namespace.has(dereference.property.name)) {
|
||
|
context.report(dereference.property, makeMessage(dereference.property, namepath));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
const exported = namespace.get(dereference.property.name);
|
||
|
if (exported == null) return;
|
||
|
|
||
|
// stash and pop
|
||
|
namepath.push(dereference.property.name);
|
||
|
namespace = exported.namespace;
|
||
|
dereference = dereference.parent;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
'VariableDeclarator': function (_ref3) {
|
||
|
let id = _ref3.id,
|
||
|
init = _ref3.init;
|
||
|
|
||
|
if (init == null) return;
|
||
|
if (init.type !== 'Identifier') return;
|
||
|
if (!namespaces.has(init.name)) return;
|
||
|
|
||
|
// check for redefinition in intermediate scopes
|
||
|
if ((0, _declaredScope2.default)(context, init.name) !== 'module') return;
|
||
|
|
||
|
// DFS traverse child namespaces
|
||
|
function testKey(pattern, namespace) {
|
||
|
let path = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [init.name];
|
||
|
|
||
|
if (!(namespace instanceof _ExportMap2.default)) return;
|
||
|
|
||
|
if (pattern.type !== 'ObjectPattern') return;
|
||
|
|
||
|
for (let property of pattern.properties) {
|
||
|
|
||
|
if (property.key.type !== 'Identifier') {
|
||
|
context.report({
|
||
|
node: property,
|
||
|
message: 'Only destructure top-level names.'
|
||
|
});
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!namespace.has(property.key.name)) {
|
||
|
context.report({
|
||
|
node: property,
|
||
|
message: makeMessage(property.key, path)
|
||
|
});
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
path.push(property.key.name);
|
||
|
testKey(property.value, namespace.get(property.key.name).namespace, path);
|
||
|
path.pop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
testKey(id, namespaces.get(init.name));
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInJ1bGVzL25hbWVzcGFjZS5qcyJdLCJuYW1lcyI6WyJtb2R1bGUiLCJleHBvcnRzIiwibWV0YSIsInNjaGVtYSIsImNyZWF0ZSIsIm5hbWVzcGFjZVJ1bGUiLCJjb250ZXh0Iiwib3B0aW9ucyIsImFsbG93Q29tcHV0ZWQiLCJuYW1lc3BhY2VzIiwiTWFwIiwibWFrZU1lc3NhZ2UiLCJsYXN0IiwibmFtZXBhdGgiLCJuYW1lIiwibGVuZ3RoIiwiam9pbiIsImJvZHkiLCJwcm9jZXNzQm9keVN0YXRlbWVudCIsImRlY2xhcmF0aW9uIiwidHlwZSIsInNwZWNpZmllcnMiLCJpbXBvcnRzIiwiZ2V0Iiwic291cmNlIiwidmFsdWUiLCJlcnJvcnMiLCJyZXBvcnRFcnJvcnMiLCJzcGVjaWZpZXIiLCJzaXplIiwicmVwb3J0Iiwic2V0IiwibG9jYWwiLCJpbXBvcnRlZCIsIm5hbWVzcGFjZSIsImZvckVhY2giLCJkZXJlZmVyZW5jZSIsIm9iamVjdCIsImhhcyIsInBhcmVudCIsImxlZnQiLCJjb21wdXRlZCIsInByb3BlcnR5IiwiZXhwb3J0ZWQiLCJwdXNoIiwiaWQiLCJpbml0IiwidGVzdEtleSIsInBhdHRlcm4iLCJwYXRoIiwicHJvcGVydGllcyIsImtleSIsIm5vZGUiLCJtZXNzYWdlIiwicG9wIl0sIm1hcHBpbmdzIjoiOztBQUFBOzs7O0FBQ0E7Ozs7QUFDQTs7Ozs7O0FBRUFBLE9BQU9DLE9BQVAsR0FBaUI7QUFDZkMsUUFBTTtBQUNKQyxZQUFRLENBQ047QUFDRSxjQUFRLFFBRFY7QUFFRSxvQkFBYztBQUNaLHlCQUFpQjtBQUNmLHlCQUNFLHlFQUNBLHVCQUhhO0FBSWYsa0JBQVEsU0FKTztBQUtmLHFCQUFXO0FBTEk7QUFETCxPQUZoQjtBQVdFLDhCQUF3QjtBQVgxQixLQURNO0FBREosR0FEUzs7QUFtQmZDLFVBQVEsU0FBU0MsYUFBVCxDQUF1QkMsT0FBdkIsRUFBZ0M7O0FBRXRDO0FBRnNDLGVBS2xDQSxRQUFRQyxPQUFSLENBQWdCLENBQWhC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
|