UNPKG

@amplitude/ampli

Version:

Amplitude CLI

105 lines (104 loc) 4.05 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const babelParser = require("@babel/parser"); const traverse_1 = require("@babel/traverse"); const base_1 = require("../base"); const BABEL_PARSER_OPTIONS = { sourceType: 'unambiguous', plugins: [ `flow`, `jsx`, `asyncGenerators`, `bigInt`, `classProperties`, `classPrivateProperties`, `classPrivateMethods`, [`decorators`, { decoratorsBeforeExport: true }], `doExpressions`, `dynamicImport`, `exportDefaultFrom`, `exportNamespaceFrom`, `functionBind`, `functionSent`, `importMeta`, `nullishCoalescingOperator`, `numericSeparator`, `objectRestSpread`, `optionalCatchBinding`, `optionalChaining`, [`pipelineOperator`, { proposal: 'minimal' }], `throwExpressions`, ], }; class JavaScriptVerifier extends base_1.Verifier { constructor(ampliInstanceNames = ['itly'], fileExtensionPattern = 'js{x,}', fileFilter = null) { super(fileExtensionPattern, ampliInstanceNames.map(name => `${name}.`), fileFilter, ['node_modules']); this.ampliInstanceNames = ampliInstanceNames; } async doVerify(eventNames, workingDirs) { return this.verifyEach(this.verifyFile.bind(this), workingDirs); } verifyFile(filePath, fileContents, addReference) { if (!fileContents) { return; } const ast = babelParser.parse(fileContents, BABEL_PARSER_OPTIONS); traverse_1.default(ast, { Identifier: path => { if (!path.parent || path.parent.type !== 'NewExpression') return; const { node } = path; if (node) { const { name, loc } = node; if (name && loc) { addReference({ filePath, name: this.getReferenceName(name), row: loc.start.line, column: loc.start.column, }); } } }, }); this.ampliInstanceNames.forEach(instanceName => { const nameParts = instanceName.split('.'); traverse_1.default(ast, { MemberExpression: path => JavaScriptVerifier.visitMemberExpression(path, filePath, nameParts, addReference), OptionalMemberExpression: path => JavaScriptVerifier.visitMemberExpression(path, filePath, nameParts, addReference), }); }); } static visitMemberExpression(path, filePath, nameParts, addReference) { let node = path.node; if (!path.parent || (path.parent.type !== 'CallExpression' && path.parent.type !== 'OptionalCallExpression')) return; const { name, loc } = node.property; let optional = path.parent.type === 'OptionalCallExpression'; node = node.object; for (let i = nameParts.length - 1; node && i >= 0; i -= 1) { if (node.type === 'Identifier') { if (`${node.name}${optional ? '?' : ''}` !== nameParts[i]) { return; } optional = false; } else if (node.type === 'MemberExpression') { if (`${node.property.name}${optional ? '?' : ''}` !== nameParts[i]) { return; } optional = false; node = node.object; } else if (node.type === 'OptionalMemberExpression') { if (`${node.property.name}${optional ? '?' : ''}` !== nameParts[i]) { return; } optional = true; node = node.object; } } addReference({ filePath, name, row: loc.start.line, column: loc.start.column }); } } exports.default = JavaScriptVerifier;