From 516b80af4ac9eb0790bf91fa45c50f4699993792 Mon Sep 17 00:00:00 2001 From: Aziz Abdullaev Date: Mon, 31 Oct 2022 12:35:59 -0400 Subject: [PATCH] [Refactor] `namespace`, `no-deprecated`: extract a helper function --- src/core/namespaceValidator.js | 45 ++++++++++++++++++++++++++++++++ src/rules/namespace.js | 47 +++++++++++++++++----------------- src/rules/no-deprecated.js | 40 ++++++++++++++--------------- 3 files changed, 88 insertions(+), 44 deletions(-) create mode 100644 src/core/namespaceValidator.js diff --git a/src/core/namespaceValidator.js b/src/core/namespaceValidator.js new file mode 100644 index 000000000..1624a05df --- /dev/null +++ b/src/core/namespaceValidator.js @@ -0,0 +1,45 @@ +import Exports from '../ExportMap'; + +export default function namespaceValidator( + node, + namespaces, + onComputed, + { + onNamespaceNotFound = undefined, + onDeprecation = undefined, + } = {}, +) { + // go deep + let namespace = namespaces.get(node.object.name); + const namepath = [node.object.name]; + + const sentinel = { __proto__: null }; // callbacks return this value if they want THIS function to stop executing + + // while property is namespace and parent is member expression, keep validating + while (namespace instanceof Exports && node.type === 'MemberExpression') { + if (node.computed) { + if (onComputed(node, sentinel) === sentinel) { + return; + } + } + + if (onNamespaceNotFound) { + if (onNamespaceNotFound(node, namespace, namepath, sentinel) === sentinel) { + return; + } + } + + const exported = namespace.get(node.property.name); + if (!exported) { + return; + } + + if (onDeprecation) { + onDeprecation(node, exported); + } + + namepath.push(node.property.name); + namespace = exported.namespace; + node = node.parent; + } +} diff --git a/src/rules/namespace.js b/src/rules/namespace.js index 3b6019da8..1fc4453fb 100644 --- a/src/rules/namespace.js +++ b/src/rules/namespace.js @@ -2,6 +2,7 @@ import declaredScope from 'eslint-module-utils/declaredScope'; import Exports from '../ExportMap'; import importDeclaration from '../importDeclaration'; import docsUrl from '../docsUrl'; +import namespaceValidator from '../core/namespaceValidator'; function processBodyStatement(context, namespaces, declaration) { if (declaration.type !== 'ImportDeclaration') return; @@ -118,37 +119,37 @@ module.exports = { ); } - // go deep - let namespace = namespaces.get(dereference.object.name); - const namepath = [dereference.object.name]; - // while property is namespace and parent is member expression, keep validating - while (namespace instanceof Exports && dereference.type === 'MemberExpression') { - if (dereference.computed) { + function onComputed(context, allowComputed){ + return function innerOnComputed(node, returnChecker) { if (!allowComputed) { context.report( - dereference.property, + node.property, `Unable to validate computed reference to imported namespace '${dereference.object.name}'.`, ); } - return; - } + return returnChecker; + }; + } - if (!namespace.has(dereference.property.name)) { - context.report( - dereference.property, - makeMessage(dereference.property, namepath), - ); - break; - } + function onNamespaceNotFound(context) { + return function inner(node, namespace, namepath, returnChecker) { + if (!namespace.has(node.property.name)) { + context.report( + node.property, + makeMessage(node.property, namepath), + ); + return returnChecker; + } + }; + } - const exported = namespace.get(dereference.property.name); - if (exported == null) return; + namespaceValidator( + dereference, + namespaces, + onComputed(context, allowComputed), + { onNamespaceNotFound: onNamespaceNotFound(context) }, + ); - // stash and pop - namepath.push(dereference.property.name); - namespace = exported.namespace; - dereference = dereference.parent; - } }, VariableDeclarator({ id, init }) { diff --git a/src/rules/no-deprecated.js b/src/rules/no-deprecated.js index 7a35a8e67..2ff53a9df 100644 --- a/src/rules/no-deprecated.js +++ b/src/rules/no-deprecated.js @@ -1,6 +1,7 @@ import declaredScope from 'eslint-module-utils/declaredScope'; import Exports from '../ExportMap'; import docsUrl from '../docsUrl'; +import namespaceValidator from '../core/namespaceValidator'; function message(deprecation) { return 'Deprecated' + (deprecation.description ? ': ' + deprecation.description : '.'); @@ -111,30 +112,27 @@ module.exports = { if (declaredScope(context, dereference.object.name) !== 'module') return; - // go deep - let namespace = namespaces.get(dereference.object.name); - const namepath = [dereference.object.name]; - // while property is namespace and parent is member expression, keep validating - while (namespace instanceof Exports && - dereference.type === 'MemberExpression') { + function onDeprecation(context){ + return function inner(node, exported) { + const deprecation = getDeprecation(exported); - // ignore computed parts for now - if (dereference.computed) return; - - const metadata = namespace.get(dereference.property.name); - - if (!metadata) break; - const deprecation = getDeprecation(metadata); - - if (deprecation) { - context.report({ node: dereference.property, message: message(deprecation) }); - } + if (deprecation) { + context.report({ node: node.property, message: message(deprecation) }); + } + }; + } - // stash and pop - namepath.push(dereference.property.name); - namespace = metadata.namespace; - dereference = dereference.parent; + function onComputed() { + // ignore computed parts for now + return arguments[2]; } + + namespaceValidator( + dereference, + namespaces, + onComputed, + { onDeprecation: onDeprecation(context) }, + ); }, }; },