UNPKG

canonical

Version:

Canonical code style linter and formatter for JavaScript, SCSS and CSS.

115 lines (94 loc) 3.38 kB
import Exports from '../core/getExports' import importDeclaration from '../importDeclaration' module.exports = function (context) { const namespaces = new Map() function getImportsAndReport(namespace) { var declaration = importDeclaration(context) var imports = Exports.get(declaration.source.value, context) if (imports == null) return null if (imports.errors.length) { context.report({ node: declaration.source, message: `Parse errors in imported module ` + `'${declaration.source.value}'.`, }) return } if (!imports.hasNamed) { context.report(namespace, `No exported names found in module '${declaration.source.value}'.`) } return imports } function message(identifier, namespace) { return '\'' + identifier.name + '\' not found in imported namespace ' + namespace.name + '.' } function declaredScope(name) { let references = context.getScope().references , i for (i = 0; i < references.length; i++) { if (references[i].identifier.name === name) { break } } if (!references[i]) return undefined return references[i].resolved.scope.type } return { 'ImportNamespaceSpecifier': function (namespace) { const imports = getImportsAndReport(namespace) if (imports == null) return namespaces.set(namespace.local.name, imports.named) }, // same as above, but does not add names to local map 'ExportNamespaceSpecifier': function (namespace) { getImportsAndReport(namespace) }, // 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}'.`) } if (dereference.computed) { context.report(dereference.property, 'Unable to validate computed reference to imported namespace \'' + dereference.object.name + '\'.') return } var namespace = namespaces.get(dereference.object.name) if (!namespace.has(dereference.property.name)) { context.report( dereference.property , message(dereference.property, dereference.object) ) } }, 'VariableDeclarator': function ({ id, init }) { if (init == null) return if (id.type !== 'ObjectPattern') return if (init.type !== 'Identifier') return if (!namespaces.has(init.name)) return // check for redefinition in intermediate scopes if (declaredScope(init.name) !== 'module') return const namespace = namespaces.get(init.name) for (let property of id.properties) { if (property.key.type !== 'Identifier') { context.report({ node: property, message: 'Only destructure top-level names.', }) } else if (!namespace.has(property.key.name)) { context.report({ node: property, message: message(property.key, init), }) } } }, } }