UNPKG

cst

Version:

JavaScript CST Implementation

626 lines (523 loc) 25.6 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var _elementsNode = require('../../elements/Node'); var _elementsNode2 = _interopRequireDefault(_elementsNode); var _elementsTypesProgram = require('../../elements/types/Program'); var _elementsTypesProgram2 = _interopRequireDefault(_elementsTypesProgram); var _elementsTypesBlockStatement = require('../../elements/types/BlockStatement'); var _elementsTypesBlockStatement2 = _interopRequireDefault(_elementsTypesBlockStatement); var _elementsTypesIdentifier = require('../../elements/types/Identifier'); var _elementsTypesIdentifier2 = _interopRequireDefault(_elementsTypesIdentifier); var _Scope = require('./Scope'); var _Scope2 = _interopRequireDefault(_Scope); var _elementsTypesAssignmentPattern = require('../../elements/types/AssignmentPattern'); var _elementsTypesAssignmentPattern2 = _interopRequireDefault(_elementsTypesAssignmentPattern); var _elementsTypesFunctionExpression = require('../../elements/types/FunctionExpression'); var _elementsTypesFunctionExpression2 = _interopRequireDefault(_elementsTypesFunctionExpression); var _elementsTypesFunctionDeclaration = require('../../elements/types/FunctionDeclaration'); var _elementsTypesFunctionDeclaration2 = _interopRequireDefault(_elementsTypesFunctionDeclaration); var _elementsTypesArrowFunctionExpression = require('../../elements/types/ArrowFunctionExpression'); var _elementsTypesArrowFunctionExpression2 = _interopRequireDefault(_elementsTypesArrowFunctionExpression); var _elementsTypesVariableDeclarator = require('../../elements/types/VariableDeclarator'); var _elementsTypesVariableDeclarator2 = _interopRequireDefault(_elementsTypesVariableDeclarator); var _elementsTypesVariableDeclaration = require('../../elements/types/VariableDeclaration'); var _elementsTypesVariableDeclaration2 = _interopRequireDefault(_elementsTypesVariableDeclaration); var _elementsTypesAssignmentExpression = require('../../elements/types/AssignmentExpression'); var _elementsTypesAssignmentExpression2 = _interopRequireDefault(_elementsTypesAssignmentExpression); var _elementsTypesUpdateExpression = require('../../elements/types/UpdateExpression'); var _elementsTypesUpdateExpression2 = _interopRequireDefault(_elementsTypesUpdateExpression); var _elementsTypesForOfStatement = require('../../elements/types/ForOfStatement'); var _elementsTypesForOfStatement2 = _interopRequireDefault(_elementsTypesForOfStatement); var _elementsTypesForInStatement = require('../../elements/types/ForInStatement'); var _elementsTypesForInStatement2 = _interopRequireDefault(_elementsTypesForInStatement); var _elementsTypesMemberExpression = require('../../elements/types/MemberExpression'); var _elementsTypesMemberExpression2 = _interopRequireDefault(_elementsTypesMemberExpression); var _elementsTypesProperty = require('../../elements/types/Property'); var _elementsTypesProperty2 = _interopRequireDefault(_elementsTypesProperty); var _elementsTypesMethodDefinition = require('../../elements/types/MethodDefinition'); var _elementsTypesMethodDefinition2 = _interopRequireDefault(_elementsTypesMethodDefinition); var _elementsTypesImportDefaultSpecifier = require('../../elements/types/ImportDefaultSpecifier'); var _elementsTypesImportDefaultSpecifier2 = _interopRequireDefault(_elementsTypesImportDefaultSpecifier); var _elementsTypesImportNamespaceSpecifier = require('../../elements/types/ImportNamespaceSpecifier'); var _elementsTypesImportNamespaceSpecifier2 = _interopRequireDefault(_elementsTypesImportNamespaceSpecifier); var _elementsTypesImportSpecifier = require('../../elements/types/ImportSpecifier'); var _elementsTypesImportSpecifier2 = _interopRequireDefault(_elementsTypesImportSpecifier); var _elementsTypesThisExpression = require('../../elements/types/ThisExpression'); var _elementsTypesThisExpression2 = _interopRequireDefault(_elementsTypesThisExpression); var _elementsTypesSuper = require('../../elements/types/Super'); var _elementsTypesSuper2 = _interopRequireDefault(_elementsTypesSuper); var _elementsTypesCatchClause = require('../../elements/types/CatchClause'); var _elementsTypesCatchClause2 = _interopRequireDefault(_elementsTypesCatchClause); var _elementsTypesLabeledStatement = require('../../elements/types/LabeledStatement'); var _elementsTypesLabeledStatement2 = _interopRequireDefault(_elementsTypesLabeledStatement); var _elementsTypesBreakStatement = require('../../elements/types/BreakStatement'); var _elementsTypesBreakStatement2 = _interopRequireDefault(_elementsTypesBreakStatement); var _elementsTypesContinueStatement = require('../../elements/types/ContinueStatement'); var _elementsTypesContinueStatement2 = _interopRequireDefault(_elementsTypesContinueStatement); var _elementsTypesClassExpression = require('../../elements/types/ClassExpression'); var _elementsTypesClassExpression2 = _interopRequireDefault(_elementsTypesClassExpression); var _elementsTypesClassDeclaration = require('../../elements/types/ClassDeclaration'); var _elementsTypesClassDeclaration2 = _interopRequireDefault(_elementsTypesClassDeclaration); var _elementsTypesJSXIdentifier = require('../../elements/types/JSXIdentifier'); var _elementsTypesJSXIdentifier2 = _interopRequireDefault(_elementsTypesJSXIdentifier); var _elementsTypesJSXAttribute = require('../../elements/types/JSXAttribute'); var _elementsTypesJSXAttribute2 = _interopRequireDefault(_elementsTypesJSXAttribute); var _elementsTypesJSXElement = require('../../elements/types/JSXElement'); var _elementsTypesJSXElement2 = _interopRequireDefault(_elementsTypesJSXElement); var _elementsTypesJSXMemberExpression = require('../../elements/types/JSXMemberExpression'); var _elementsTypesJSXMemberExpression2 = _interopRequireDefault(_elementsTypesJSXMemberExpression); var _elementsTypesJSXNamespacedName = require('../../elements/types/JSXNamespacedName'); var _elementsTypesJSXNamespacedName2 = _interopRequireDefault(_elementsTypesJSXNamespacedName); var _Definition = require('./Definition'); var scopedBlocks = { 'ForStatement': true, 'ForInStatement': true, 'ForOfStatement': true, 'SwitchStatement': true, 'CatchClause': true }; var ScopesApi = (function () { function ScopesApi(program) { var _this = this; _classCallCheck(this, ScopesApi); program.on('elements-add', function (elements) { elements.map(_this._addElement, _this); }); program.on('elements-remove', function (elements) { elements.map(_this._removeElement, _this); }); this._scopesMap = new Map(); this._program = program; this._addElement(program); } _createClass(ScopesApi, [{ key: '_addElement', value: function _addElement(element) { if (element instanceof _elementsNode2['default']) { var nodes = buildNodeList(element); for (var i = 0; i < nodes.length; i++) { this._addNode(nodes[i]); } } } }, { key: '_removeElement', value: function _removeElement(element) { if (element instanceof _elementsNode2['default']) { var nodes = buildNodeList(element); for (var i = 0; i < nodes.length; i++) { this._removeNode(nodes[i]); } } } }, { key: '_addNode', value: function _addNode(node) { if (node instanceof _elementsTypesProgram2['default']) { return this._addProgram(node); } if (node instanceof _elementsTypesFunctionExpression2['default']) { return this._addFunctionExpression(node); } if (node instanceof _elementsTypesFunctionDeclaration2['default']) { return this._addFunctionDeclaration(node); } if (node instanceof _elementsTypesArrowFunctionExpression2['default']) { return this._addArrowFunctionExpression(node); } if (node instanceof _elementsTypesClassDeclaration2['default']) { return this._addClassDeclaration(node); } if (node instanceof _elementsTypesClassExpression2['default']) { return this._addClassExpression(node); } if (node.type in scopedBlocks) { return this._addScopedBlock(node); } if (node instanceof _elementsTypesBlockStatement2['default']) { return this._addBlockStatement(node); } if (node instanceof _elementsTypesThisExpression2['default']) { return this._addThisExpression(node); } if (node instanceof _elementsTypesSuper2['default']) { return this._addSuper(node); } if (node instanceof _elementsTypesIdentifier2['default']) { return this._addIdentifier(node); } if (node instanceof _elementsTypesJSXIdentifier2['default']) { return this._addJSXIdentifier(node); } } }, { key: '_addProgram', value: function _addProgram(node) { this._scopesMap.set(node, new _Scope2['default']({ node: node, parentScope: undefined, isFunctionScope: true })); } }, { key: '_addClassExpression', value: function _addClassExpression(node) { this._scopesMap.set(node, new _Scope2['default']({ node: node, parentScope: this._getParentScopeFor(node), isClassScope: true })); } }, { key: '_addClassDeclaration', value: function _addClassDeclaration(node) { this._scopesMap.set(node, new _Scope2['default']({ node: node, parentScope: this._getParentScopeFor(node), isClassScope: true })); } }, { key: '_addFunctionExpression', value: function _addFunctionExpression(node) { this._scopesMap.set(node, new _Scope2['default']({ node: node, parentScope: this._getParentScopeFor(node), isFunctionScope: true })); } }, { key: '_addFunctionDeclaration', value: function _addFunctionDeclaration(node) { this._scopesMap.set(node, new _Scope2['default']({ node: node, parentScope: this._getParentScopeFor(node), isFunctionScope: true })); } }, { key: '_addArrowFunctionExpression', value: function _addArrowFunctionExpression(node) { this._scopesMap.set(node, new _Scope2['default']({ node: node, parentScope: this._getParentScopeFor(node), isFunctionScope: true, isArrowFunctionScope: true })); } }, { key: '_addScopedBlock', value: function _addScopedBlock(node) { this._scopesMap.set(node, new _Scope2['default']({ node: node, parentScope: this._getParentScopeFor(node) })); } }, { key: '_addBlockStatement', value: function _addBlockStatement(node) { var parentElement = node.parentElement; if (parentElement && (parentElement.type === 'ForStatement' || parentElement.type === 'ForInStatement' || parentElement.type === 'ForOfStatement' || parentElement.type === 'CatchClause' || parentElement.type === 'ArrowFunctionExpression' || parentElement.type === 'FunctionExpression' || parentElement.type === 'FunctionDeclaration')) { return; } this._scopesMap.set(node, new _Scope2['default']({ node: node, parentScope: this._getScopeFor(parentElement) })); } }, { key: '_addJSXIdentifier', value: function _addJSXIdentifier(node) { var name = node.name; var scope = this._getScopeFor(node); var parentElement = node.parentElement; if (!scope || !parentElement) { return; } if (parentElement instanceof _elementsTypesJSXAttribute2['default']) { if (node === parentElement.name) { return; } } if (parentElement instanceof _elementsTypesJSXMemberExpression2['default']) { if (node === parentElement.property) { return; } } if (parentElement instanceof _elementsTypesJSXNamespacedName2['default']) { if (node === parentElement.name) { return; } } scope._addReference({ node: node, name: name, read: true, write: false }); } }, { key: '_addIdentifier', value: function _addIdentifier(node) { var scope = this._getScopeFor(node); var parentElement = node.parentElement; if (!scope || !parentElement) { return; } var name = node.name; if (parentElement instanceof _elementsTypesProperty2['default'] && parentElement.parentElement) { if (node === parentElement.key && !parentElement.shorthand) { if (parentElement.computed) { scope._addReference({ node: node, name: name, read: true, write: false }); } return; } } var topLevelPattern = node; while (topLevelPattern.parentElement) { if (topLevelPattern.parentElement instanceof _elementsTypesProperty2['default']) { if (topLevelPattern.parentElement.parentElement.isPattern) { topLevelPattern = topLevelPattern.parentElement.parentElement; continue; } } if (topLevelPattern.parentElement instanceof _elementsTypesAssignmentPattern2['default']) { if (topLevelPattern === topLevelPattern.parentElement.right) { break; } } if (!topLevelPattern.parentElement.isPattern) { break; } topLevelPattern = topLevelPattern.parentElement; } var container = topLevelPattern.parentElement; if (!container) { return; } if (container instanceof _elementsTypesFunctionExpression2['default'] || container instanceof _elementsTypesFunctionDeclaration2['default'] || container instanceof _elementsTypesArrowFunctionExpression2['default']) { if (container.params.indexOf(topLevelPattern) !== -1) { scope._addDefinition({ node: node, name: name, type: _Definition.types.Parameter }); if (topLevelPattern instanceof _elementsTypesAssignmentPattern2['default']) { scope._addReference({ node: node, name: name, read: false, write: true }); } return; } } if (container instanceof _elementsTypesVariableDeclarator2['default']) { var type = _Definition.types.Variable; var variableDeclaration = container.parentElement; if (variableDeclaration && variableDeclaration instanceof _elementsTypesVariableDeclaration2['default']) { if (variableDeclaration.kind === 'let') { type = _Definition.types.LetVariable; } if (variableDeclaration.kind === 'const') { type = _Definition.types.Constant; } scope._addDefinition({ node: node, name: name, type: type }); var write = container.init || variableDeclaration.parentElement instanceof _elementsTypesForOfStatement2['default'] || variableDeclaration.parentElement instanceof _elementsTypesForInStatement2['default']; if (write) { scope._addReference({ node: node, name: name, read: false, write: true }); } } return; } if (container instanceof _elementsTypesCatchClause2['default']) { if (container.param === topLevelPattern) { scope._addDefinition({ node: node, name: name, type: _Definition.types.CatchClauseError }); return; } } if (container instanceof _elementsTypesAssignmentExpression2['default']) { if (container.left === topLevelPattern) { scope._addReference({ node: node, name: name, read: container.operator !== '=', write: true }); return; } } if (container instanceof _elementsTypesUpdateExpression2['default']) { if (container.argument === topLevelPattern) { scope._addReference({ node: node, name: name, read: true, write: true }); return; } } if (container instanceof _elementsTypesMemberExpression2['default']) { if (node === container.property && !container.computed) { return; } } if (container instanceof _elementsTypesProperty2['default']) { if (node === container.key && !container.computed && !container.shorthand) { return; } } if (container instanceof _elementsTypesMethodDefinition2['default']) { if (node === container.key && !container.computed) { return; } } if (container instanceof _elementsTypesImportDefaultSpecifier2['default']) { scope._addDefinition({ node: node, name: name, type: _Definition.types.ImportBinding }); return; } if (container instanceof _elementsTypesImportNamespaceSpecifier2['default']) { scope._addDefinition({ node: node, name: name, type: _Definition.types.ImportBinding }); return; } if (container instanceof _elementsTypesImportSpecifier2['default']) { if (container.local === node) { scope._addDefinition({ node: node, name: name, type: _Definition.types.ImportBinding }); } return; } if (container instanceof _elementsTypesClassExpression2['default']) { if (container.id === node) { scope._addDefinition({ node: node, name: name, type: _Definition.types.SelfReference }); scope._addReference({ node: node, name: node.name, read: false, write: true }); return; } } if (container instanceof _elementsTypesClassDeclaration2['default']) { if (container.id === node) { var parentScope = this._getParentScopeFor(container); if (parentScope) { parentScope._addDefinition({ node: node, name: name, type: _Definition.types.LetVariable }); parentScope._addReference({ node: node, name: node.name, read: false, write: true }); return; } } } if (container instanceof _elementsTypesFunctionDeclaration2['default']) { if (node === container.id) { var parentScope = this._getParentScopeFor(container); if (parentScope) { parentScope._addDefinition({ node: node, name: node.name, type: _Definition.types.LetVariable }); parentScope._addReference({ node: node, name: node.name, read: false, write: true }); } return; } } if (container instanceof _elementsTypesFunctionExpression2['default']) { if (node === container.id) { scope._addDefinition({ node: node, name: node.name, type: _Definition.types.SelfReference }); scope._addReference({ node: node, name: node.name, read: false, write: true }); return; } } if (container instanceof _elementsTypesLabeledStatement2['default']) { if (node === container.label) { return; } } if (container instanceof _elementsTypesBreakStatement2['default'] || container instanceof _elementsTypesContinueStatement2['default']) { return; } scope._addReference({ node: node, name: name, read: true, write: false }); } }, { key: '_addThisExpression', value: function _addThisExpression(node) { var scope = this._getScopeFor(node); if (scope) { scope._addReference({ node: node, name: 'this', read: true, write: false }); } } }, { key: '_addSuper', value: function _addSuper(node) { var scope = this._getScopeFor(node); if (scope) { scope._addReference({ node: node, name: 'super', read: true, write: false }); } } }, { key: '_removeNode', value: function _removeNode(node) {} }, { key: '_getParentScopeFor', value: function _getParentScopeFor(element) { return this._getScopeFor(element.parentElement); } }, { key: '_getScopeFor', value: function _getScopeFor(element) { while (element) { var scope = this._scopesMap.get(element); if (scope) { return scope; } element = element.parentElement; } return null; } }, { key: 'acquire', value: function acquire(element) { return this._scopesMap.get(element); } }]); return ScopesApi; })(); exports['default'] = ScopesApi; function buildNodeList(parentNode) { var result = [parentNode]; var nodesToProcess = [parentNode]; while (nodesToProcess.length > 0) { var node = nodesToProcess.shift(); var childElements = node.childElements; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = childElements[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var element = _step.value; if (element instanceof _elementsNode2['default']) { result.push(element); nodesToProcess.push(element); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator['return']) { _iterator['return'](); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } return result; } module.exports = exports['default'];