UNPKG

cst

Version:

JavaScript CST Implementation

758 lines (646 loc) 28.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _map = require('babel-runtime/core-js/map'); var _map2 = _interopRequireDefault(_map); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _Token = require('../../elements/Token'); var _Token2 = _interopRequireDefault(_Token); var _Node = require('../../elements/Node'); var _Node2 = _interopRequireDefault(_Node); var _Program = require('../../elements/types/Program'); var _Program2 = _interopRequireDefault(_Program); var _BlockStatement = require('../../elements/types/BlockStatement'); var _BlockStatement2 = _interopRequireDefault(_BlockStatement); var _Identifier = require('../../elements/types/Identifier'); var _Identifier2 = _interopRequireDefault(_Identifier); var _Scope = require('./Scope'); var _Scope2 = _interopRequireDefault(_Scope); var _AssignmentPattern = require('../../elements/types/AssignmentPattern'); var _AssignmentPattern2 = _interopRequireDefault(_AssignmentPattern); var _FunctionExpression = require('../../elements/types/FunctionExpression'); var _FunctionExpression2 = _interopRequireDefault(_FunctionExpression); var _FunctionDeclaration = require('../../elements/types/FunctionDeclaration'); var _FunctionDeclaration2 = _interopRequireDefault(_FunctionDeclaration); var _ArrowFunctionExpression = require('../../elements/types/ArrowFunctionExpression'); var _ArrowFunctionExpression2 = _interopRequireDefault(_ArrowFunctionExpression); var _VariableDeclarator = require('../../elements/types/VariableDeclarator'); var _VariableDeclarator2 = _interopRequireDefault(_VariableDeclarator); var _VariableDeclaration = require('../../elements/types/VariableDeclaration'); var _VariableDeclaration2 = _interopRequireDefault(_VariableDeclaration); var _AssignmentExpression = require('../../elements/types/AssignmentExpression'); var _AssignmentExpression2 = _interopRequireDefault(_AssignmentExpression); var _UpdateExpression = require('../../elements/types/UpdateExpression'); var _UpdateExpression2 = _interopRequireDefault(_UpdateExpression); var _ForOfStatement = require('../../elements/types/ForOfStatement'); var _ForOfStatement2 = _interopRequireDefault(_ForOfStatement); var _ForInStatement = require('../../elements/types/ForInStatement'); var _ForInStatement2 = _interopRequireDefault(_ForInStatement); var _MemberExpression = require('../../elements/types/MemberExpression'); var _MemberExpression2 = _interopRequireDefault(_MemberExpression); var _ObjectProperty = require('../../elements/types/ObjectProperty'); var _ObjectProperty2 = _interopRequireDefault(_ObjectProperty); var _ObjectMethod = require('../../elements/types/ObjectMethod'); var _ObjectMethod2 = _interopRequireDefault(_ObjectMethod); var _ImportDefaultSpecifier = require('../../elements/types/ImportDefaultSpecifier'); var _ImportDefaultSpecifier2 = _interopRequireDefault(_ImportDefaultSpecifier); var _ImportNamespaceSpecifier = require('../../elements/types/ImportNamespaceSpecifier'); var _ImportNamespaceSpecifier2 = _interopRequireDefault(_ImportNamespaceSpecifier); var _ImportSpecifier = require('../../elements/types/ImportSpecifier'); var _ImportSpecifier2 = _interopRequireDefault(_ImportSpecifier); var _ThisExpression = require('../../elements/types/ThisExpression'); var _ThisExpression2 = _interopRequireDefault(_ThisExpression); var _Super = require('../../elements/types/Super'); var _Super2 = _interopRequireDefault(_Super); var _CatchClause = require('../../elements/types/CatchClause'); var _CatchClause2 = _interopRequireDefault(_CatchClause); var _LabeledStatement = require('../../elements/types/LabeledStatement'); var _LabeledStatement2 = _interopRequireDefault(_LabeledStatement); var _BreakStatement = require('../../elements/types/BreakStatement'); var _BreakStatement2 = _interopRequireDefault(_BreakStatement); var _ContinueStatement = require('../../elements/types/ContinueStatement'); var _ContinueStatement2 = _interopRequireDefault(_ContinueStatement); var _ClassExpression = require('../../elements/types/ClassExpression'); var _ClassExpression2 = _interopRequireDefault(_ClassExpression); var _ClassDeclaration = require('../../elements/types/ClassDeclaration'); var _ClassDeclaration2 = _interopRequireDefault(_ClassDeclaration); var _ClassMethod = require('../../elements/types/ClassMethod'); var _ClassMethod2 = _interopRequireDefault(_ClassMethod); var _JSXIdentifier = require('../../elements/types/JSXIdentifier'); var _JSXIdentifier2 = _interopRequireDefault(_JSXIdentifier); var _JSXAttribute = require('../../elements/types/JSXAttribute'); var _JSXAttribute2 = _interopRequireDefault(_JSXAttribute); var _JSXMemberExpression = require('../../elements/types/JSXMemberExpression'); var _JSXMemberExpression2 = _interopRequireDefault(_JSXMemberExpression); var _JSXNamespacedName = require('../../elements/types/JSXNamespacedName'); var _JSXNamespacedName2 = _interopRequireDefault(_JSXNamespacedName); var _Definition = require('./Definition'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var scopedBlocks = { 'ForStatement': true, 'ForInStatement': true, 'ForOfStatement': true, 'SwitchStatement': true, 'CatchClause': true }; var ScopesApi = function () { function ScopesApi(program) { var _this = this; (0, _classCallCheck3.default)(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 _map2.default(); this._program = program; this._addElement(program); this.acquire(this._program); } (0, _createClass3.default)(ScopesApi, [{ key: '_addElement', value: function _addElement(element) { if (element instanceof _Node2.default) { var nodes = buildNodeList(element); for (var i = 0; i < nodes.length; i++) { this._addNode(nodes[i]); } } this._updateTokenIfNecessary(element); } }, { key: '_removeElement', value: function _removeElement(element) { if (element instanceof _Node2.default) { var nodes = buildNodeList(element); for (var i = 0; i < nodes.length; i++) { this._removeNode(nodes[i]); } } this._updateTokenIfNecessary(element); } }, { key: '_updateTokenIfNecessary', value: function _updateTokenIfNecessary(element) { if (element instanceof _Token2.default) { var parentElement = element.parentElement; if (parentElement) { if (element.type === 'Identifier') { this._removeElement(parentElement); this._addElement(parentElement); return; } if (element.type === 'Punctuator' && element.value === ':' && parentElement instanceof _ObjectProperty2.default) { this._removeElement(parentElement); this._addElement(parentElement); return; } } } } }, { key: '_addNode', value: function _addNode(node) { if (node instanceof _Program2.default) { return this._addProgram(node); } if (node instanceof _FunctionExpression2.default) { return this._addFunctionExpression(node); } if (node instanceof _FunctionDeclaration2.default) { return this._addFunctionDeclaration(node); } if (node instanceof _ArrowFunctionExpression2.default) { return this._addArrowFunctionExpression(node); } if (node instanceof _ObjectMethod2.default) { return this._addObjectMethod(node); } if (node instanceof _ClassDeclaration2.default) { return this._addClassDeclaration(node); } if (node instanceof _ClassExpression2.default) { return this._addClassExpression(node); } if (node instanceof _ClassMethod2.default) { return this._addClassMethod(node); } if (node.type in scopedBlocks) { return this._addScopedBlock(node); } if (node instanceof _BlockStatement2.default) { return this._addBlockStatement(node); } if (node instanceof _ThisExpression2.default) { return this._addThisExpression(node); } if (node instanceof _Super2.default) { return this._addSuper(node); } if (node instanceof _Identifier2.default) { return this._addIdentifier(node); } if (node instanceof _JSXIdentifier2.default) { return this._addJSXIdentifier(node); } } }, { key: '_addProgram', value: function _addProgram(node) { this._programScope = this._addScope({ node: node, parentScope: undefined, isFunctionScope: true, isProgramScope: true }); } }, { key: '_addClassExpression', value: function _addClassExpression(node) { this._addScope({ node: node, parentScope: this._getParentScopeFor(node), isClassScope: true }); } }, { key: '_addClassDeclaration', value: function _addClassDeclaration(node) { this._addScope({ node: node, parentScope: this._getParentScopeFor(node), isClassScope: true }); } }, { key: '_addClassMethod', value: function _addClassMethod(node) { this._addScope({ node: node, parentScope: this._getParentScopeFor(node), isFunctionScope: true }); } }, { key: '_addFunctionExpression', value: function _addFunctionExpression(node) { this._addScope({ node: node, parentScope: this._getParentScopeFor(node), isFunctionScope: true }); } }, { key: '_addObjectMethod', value: function _addObjectMethod(node) { this._addScope({ node: node, parentScope: this._getParentScopeFor(node), isFunctionScope: true }); } }, { key: '_addFunctionDeclaration', value: function _addFunctionDeclaration(node) { this._addScope({ node: node, parentScope: this._getParentScopeFor(node), isFunctionScope: true }); } }, { key: '_addArrowFunctionExpression', value: function _addArrowFunctionExpression(node) { this._addScope({ node: node, parentScope: this._getParentScopeFor(node), isFunctionScope: true, isArrowFunctionScope: true }); } }, { key: '_addScopedBlock', value: function _addScopedBlock(node) { this._addScope({ 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._addScope({ node: node, parentScope: this._getScopeFor(parentElement) }); } }, { key: '_removeBlockStatement', value: function _removeBlockStatement(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; } var scope = this._scopesMap.get(node); if (scope) { scope.destroy(); this._scopesMap.delete(node); } } }, { 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 _JSXAttribute2.default) { if (node === parentElement.name) { return; } } if (parentElement instanceof _JSXMemberExpression2.default) { if (node === parentElement.property) { return; } } if (parentElement instanceof _JSXNamespacedName2.default) { if (node === parentElement.name) { return; } } this._addReferenceToScope(scope, { 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 _ObjectProperty2.default && parentElement.parentElement) { if (node === parentElement.key && !parentElement.shorthand) { if (parentElement.computed) { this._addReferenceToScope(scope, { node: node, name: name, read: true, write: false }); } return; } } var topLevelPattern = node; while (topLevelPattern.parentElement) { if (topLevelPattern.parentElement instanceof _ObjectProperty2.default) { if (topLevelPattern.parentElement.parentElement.isPattern) { topLevelPattern = topLevelPattern.parentElement.parentElement; continue; } } if (topLevelPattern.parentElement instanceof _AssignmentPattern2.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 _ClassMethod2.default || container instanceof _ObjectMethod2.default || container instanceof _FunctionExpression2.default || container instanceof _FunctionDeclaration2.default || container instanceof _ArrowFunctionExpression2.default) { if (container.params.indexOf(topLevelPattern) !== -1) { this._addDefinitionToScope(scope, { node: node, name: name, type: _Definition.types.Parameter }); if (topLevelPattern instanceof _AssignmentPattern2.default) { this._addReferenceToScope(scope, { node: node, name: name, read: false, write: true, type: _Definition.types.Parameter }); } return; } } if (container instanceof _VariableDeclarator2.default) { if (container.id === topLevelPattern) { var type = _Definition.types.Variable; var variableDeclaration = container.parentElement; if (variableDeclaration && variableDeclaration instanceof _VariableDeclaration2.default) { if (variableDeclaration.kind === 'let') { type = _Definition.types.LetVariable; } if (variableDeclaration.kind === 'const') { type = _Definition.types.Constant; } this._addDefinitionToScope(scope, { node: node, name: name, type: type }); var write = container.init || variableDeclaration.parentElement instanceof _ForOfStatement2.default || variableDeclaration.parentElement instanceof _ForInStatement2.default; if (write) { this._addReferenceToScope(scope, { node: node, name: name, read: false, write: true, type: type }); } } return; } } if (container instanceof _CatchClause2.default) { if (container.param === topLevelPattern) { this._addDefinitionToScope(scope, { node: node, name: name, type: _Definition.types.CatchClauseError }); return; } } if (container instanceof _AssignmentExpression2.default) { if (container.left === topLevelPattern) { this._addReferenceToScope(scope, { node: node, name: name, read: container.operator !== '=', write: true }); return; } } if (container instanceof _UpdateExpression2.default) { if (container.argument === topLevelPattern) { this._addReferenceToScope(scope, { node: node, name: name, read: true, write: true }); return; } } if (container instanceof _MemberExpression2.default) { if (node === container.property && !container.computed) { return; } } if (container instanceof _ObjectMethod2.default) { if (node === container.key && !container.computed && !container.shorthand) { return; } } if (container instanceof _ClassMethod2.default) { if (node === container.key && !container.computed) { return; } } if (container instanceof _ImportDefaultSpecifier2.default) { this._addDefinitionToScope(scope, { node: node, name: name, type: _Definition.types.ImportBinding }); return; } if (container instanceof _ImportNamespaceSpecifier2.default) { this._addDefinitionToScope(scope, { node: node, name: name, type: _Definition.types.ImportBinding }); return; } if (container instanceof _ImportSpecifier2.default) { if (container.local === node) { this._addDefinitionToScope(scope, { node: node, name: name, type: _Definition.types.ImportBinding }); } return; } if (container instanceof _ClassExpression2.default) { if (container.id === node) { this._addDefinitionToScope(scope, { node: node, name: name, type: _Definition.types.SelfReference }); this._addReferenceToScope(scope, { node: node, name: node.name, read: false, write: true, type: _Definition.types.SelfReference }); return; } } if (container instanceof _ClassDeclaration2.default) { if (container.id === node) { var parentScope = this._getParentScopeFor(container); if (parentScope) { this._addDefinitionToScope(parentScope, { node: node, name: name, type: _Definition.types.LetVariable }); this._addReferenceToScope(parentScope, { node: node, name: node.name, read: false, write: true, type: _Definition.types.LetVariable }); return; } } } if (container instanceof _FunctionDeclaration2.default) { if (node === container.id) { var _parentScope = this._getParentScopeFor(container); if (_parentScope) { this._addDefinitionToScope(_parentScope, { node: node, name: node.name, type: _Definition.types.LetVariable }); this._addReferenceToScope(_parentScope, { node: node, name: node.name, read: false, write: true, type: _Definition.types.LetVariable }); } return; } } if (container instanceof _FunctionExpression2.default) { if (node === container.id) { this._addDefinitionToScope(scope, { node: node, name: node.name, type: _Definition.types.SelfReference }); this._addReferenceToScope(scope, { node: node, name: node.name, read: false, write: true, type: _Definition.types.SelfReference }); return; } } if (container instanceof _LabeledStatement2.default) { if (node === container.label) { return; } } if (container instanceof _BreakStatement2.default || container instanceof _ContinueStatement2.default) { return; } this._addReferenceToScope(scope, { node: node, name: name, read: true, write: false }); } }, { key: '_addThisExpression', value: function _addThisExpression(node) { var scope = this._getScopeFor(node); if (scope) { this._addReferenceToScope(scope, { node: node, name: 'this', read: true, write: false }); } } }, { key: '_addSuper', value: function _addSuper(node) { var scope = this._getScopeFor(node); if (scope) { this._addReferenceToScope(scope, { node: node, name: 'super', read: true, write: false }); } } }, { key: '_removeNode', value: function _removeNode(node) { if (node instanceof _FunctionExpression2.default || node instanceof _FunctionDeclaration2.default || node instanceof _ArrowFunctionExpression2.default || node instanceof _ClassDeclaration2.default || node instanceof _ClassExpression2.default || node.type in scopedBlocks) { var scope = this._scopesMap.get(node); if (scope) { scope.destroy(); this._scopesMap.delete(node); } } if (node instanceof _BlockStatement2.default) { return this._removeBlockStatement(node); } if (node instanceof _ThisExpression2.default || node instanceof _Super2.default || node instanceof _Identifier2.default || node instanceof _JSXIdentifier2.default) { var reference = this._programScope._programReferences.get(node); if (reference) { reference.scope._removeReference(reference); } var definition = this._programScope._programDefinitions.get(node); if (definition) { definition.scope._removeDefinition(definition); } } } }, { key: '_addReferenceToScope', value: function _addReferenceToScope(scope, referenceInfo) { var reference = this._programScope._programReferences.get(referenceInfo.node); if (!reference) { scope._addReference(referenceInfo); } } }, { key: '_addDefinitionToScope', value: function _addDefinitionToScope(scope, definitionInfo) { var definition = this._programScope._programDefinitions.get(definitionInfo.node); if (!definition) { scope._addDefinition(definitionInfo); } } }, { key: '_addScope', value: function _addScope(scopeInfo) { var scope = this._scopesMap.get(scopeInfo.node); if (!scope) { scope = new _Scope2.default(scopeInfo); this._scopesMap.set(scopeInfo.node, scope); } return scope; } }, { 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); } }, { key: 'findReference', value: function findReference(node) { return this._programScope._programReferences.get(node); } }, { key: 'findDefinition', value: function findDefinition(node) { return this._programScope._programDefinitions.get(node); } }, { key: 'findVariable', value: function findVariable(node) { var reference = this._programScope._programReferences.get(node); if (reference) { return reference.variable; } var definition = this._programScope._programDefinitions.get(node); if (definition) { return definition.variable; } } }]); 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; for (var i = 0; i < childElements.length; i++) { var element = childElements[i]; if (element instanceof _Node2.default) { result.push(element); nodesToProcess.push(element); } } } return result; } //# sourceMappingURL=ScopesApi.js.map