cst
Version:
JavaScript CST Implementation
758 lines (646 loc) • 28.8 kB
JavaScript
'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