UNPKG

luhn-generator

Version:

A generator of numbers that passes the validation of Luhn algorithm or Luhn formula, also known as the 'modulus 10' or 'mod 10' algorithm

347 lines (291 loc) 8.92 kB
"use strict"; const t = require("@babel/types"); const requireFromESLint = require("./require-from-eslint"); const escope = requireFromESLint("eslint-scope"); const Definition = requireFromESLint("eslint-scope/lib/definition").Definition; const OriginalPatternVisitor = requireFromESLint( "eslint-scope/lib/pattern-visitor" ); const OriginalReferencer = requireFromESLint("eslint-scope/lib/referencer"); const fallback = require("eslint-visitor-keys").getKeys; const childVisitorKeys = require("./visitor-keys"); const flowFlippedAliasKeys = t.FLIPPED_ALIAS_KEYS.Flow.concat([ "ArrayPattern", "ClassDeclaration", "ClassExpression", "FunctionDeclaration", "FunctionExpression", "Identifier", "ObjectPattern", "RestElement", ]); const visitorKeysMap = Object.keys(t.VISITOR_KEYS).reduce(function(acc, key) { const value = t.VISITOR_KEYS[key]; if (flowFlippedAliasKeys.indexOf(value) === -1) { acc[key] = value; } return acc; }, {}); const propertyTypes = { // loops callProperties: { type: "loop", values: ["value"] }, indexers: { type: "loop", values: ["key", "value"] }, properties: { type: "loop", values: ["argument", "value"] }, types: { type: "loop" }, params: { type: "loop" }, // single property argument: { type: "single" }, elementType: { type: "single" }, qualification: { type: "single" }, rest: { type: "single" }, returnType: { type: "single" }, // others typeAnnotation: { type: "typeAnnotation" }, typeParameters: { type: "typeParameters" }, id: { type: "id" }, }; class PatternVisitor extends OriginalPatternVisitor { ArrayPattern(node) { node.elements.forEach(this.visit, this); } ObjectPattern(node) { node.properties.forEach(this.visit, this); } } class Referencer extends OriginalReferencer { // inherits. visitPattern(node, options, callback) { if (!node) { return; } // Visit type annotations. this._checkIdentifierOrVisit(node.typeAnnotation); if (t.isAssignmentPattern(node)) { this._checkIdentifierOrVisit(node.left.typeAnnotation); } // Overwrite `super.visitPattern(node, options, callback)` in order to not visit `ArrayPattern#typeAnnotation` and `ObjectPattern#typeAnnotation`. if (typeof options === "function") { callback = options; options = { processRightHandNodes: false }; } const visitor = new PatternVisitor(this.options, node, callback); visitor.visit(node); // Process the right hand nodes recursively. if (options.processRightHandNodes) { visitor.rightHandNodes.forEach(this.visit, this); } } // inherits. visitClass(node) { // Decorators. this._visitArray(node.decorators); // Flow type parameters. const typeParamScope = this._nestTypeParamScope(node); // Flow super types. this._visitTypeAnnotation(node.implements); this._visitTypeAnnotation( node.superTypeParameters && node.superTypeParameters.params ); // Basic. super.visitClass(node); // Close the type parameter scope. if (typeParamScope) { this.close(node); } } // inherits. visitFunction(node) { const typeParamScope = this._nestTypeParamScope(node); // Flow return types. this._checkIdentifierOrVisit(node.returnType); // Basic. super.visitFunction(node); // Close the type parameter scope. if (typeParamScope) { this.close(node); } } // inherits. visitProperty(node) { if (node.value && node.value.type === "TypeCastExpression") { this._visitTypeAnnotation(node.value); } this._visitArray(node.decorators); super.visitProperty(node); } InterfaceDeclaration(node) { this._createScopeVariable(node, node.id); const typeParamScope = this._nestTypeParamScope(node); // TODO: Handle mixins this._visitArray(node.extends); this.visit(node.body); if (typeParamScope) { this.close(node); } } EnumDeclaration(node) { this._createScopeVariable(node, node.id); } TypeAlias(node) { this._createScopeVariable(node, node.id); const typeParamScope = this._nestTypeParamScope(node); this.visit(node.right); if (typeParamScope) { this.close(node); } } ClassProperty(node) { this._visitClassProperty(node); } ClassPrivateProperty(node) { this._visitClassProperty(node); } DeclareModule(node) { this._visitDeclareX(node); } DeclareFunction(node) { this._visitDeclareX(node); } DeclareVariable(node) { this._visitDeclareX(node); } DeclareClass(node) { this._visitDeclareX(node); } // visit OptionalMemberExpression as a MemberExpression. OptionalMemberExpression(node) { super.MemberExpression(node); } _visitClassProperty(node) { this._visitTypeAnnotation(node.typeAnnotation); this.visitProperty(node); } _visitDeclareX(node) { if (node.id) { this._createScopeVariable(node, node.id); } const typeParamScope = this._nestTypeParamScope(node); if (typeParamScope) { this.close(node); } } _createScopeVariable(node, name) { this.currentScope().variableScope.__define( name, new Definition("Variable", name, node, null, null, null) ); } _nestTypeParamScope(node) { if (!node.typeParameters) { return null; } const parentScope = this.scopeManager.__currentScope; const scope = new escope.Scope( this.scopeManager, "type-parameters", parentScope, node, false ); this.scopeManager.__nestScope(scope); for (let j = 0; j < node.typeParameters.params.length; j++) { const name = node.typeParameters.params[j]; scope.__define(name, new Definition("TypeParameter", name, name)); if (name.typeAnnotation) { this._checkIdentifierOrVisit(name); } } scope.__define = function() { return parentScope.__define.apply(parentScope, arguments); }; return scope; } _visitTypeAnnotation(node) { if (!node) { return; } if (Array.isArray(node)) { node.forEach(this._visitTypeAnnotation, this); return; } // get property to check (params, id, etc...) const visitorValues = visitorKeysMap[node.type]; if (!visitorValues) { return; } // can have multiple properties for (let i = 0; i < visitorValues.length; i++) { const visitorValue = visitorValues[i]; const propertyType = propertyTypes[visitorValue]; const nodeProperty = node[visitorValue]; // check if property or type is defined if (propertyType == null || nodeProperty == null) { continue; } if (propertyType.type === "loop") { for (let j = 0; j < nodeProperty.length; j++) { if (Array.isArray(propertyType.values)) { for (let k = 0; k < propertyType.values.length; k++) { const loopPropertyNode = nodeProperty[j][propertyType.values[k]]; if (loopPropertyNode) { this._checkIdentifierOrVisit(loopPropertyNode); } } } else { this._checkIdentifierOrVisit(nodeProperty[j]); } } } else if (propertyType.type === "single") { this._checkIdentifierOrVisit(nodeProperty); } else if (propertyType.type === "typeAnnotation") { this._visitTypeAnnotation(node.typeAnnotation); } else if (propertyType.type === "typeParameters") { for (let l = 0; l < node.typeParameters.params.length; l++) { this._checkIdentifierOrVisit(node.typeParameters.params[l]); } } else if (propertyType.type === "id") { if (node.id.type === "Identifier") { this._checkIdentifierOrVisit(node.id); } else { this._visitTypeAnnotation(node.id); } } } } _checkIdentifierOrVisit(node) { if (node && node.typeAnnotation) { this._visitTypeAnnotation(node.typeAnnotation); } else if (node && node.type === "Identifier") { this.visit(node); } else { this._visitTypeAnnotation(node); } } _visitArray(nodeList) { if (nodeList) { for (const node of nodeList) { this.visit(node); } } } } module.exports = function(ast, parserOptions) { const options = { ignoreEval: true, optimistic: false, directive: false, nodejsScope: ast.sourceType === "script" && (parserOptions.ecmaFeatures && parserOptions.ecmaFeatures.globalReturn) === true, impliedStrict: false, sourceType: ast.sourceType, ecmaVersion: parserOptions.ecmaVersion || 2018, fallback, }; options.childVisitorKeys = childVisitorKeys; const scopeManager = new escope.ScopeManager(options); const referencer = new Referencer(options, scopeManager); referencer.visit(ast); return scopeManager; };