cst
Version:
JavaScript CST Implementation
626 lines (523 loc) • 25.6 kB
JavaScript
'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'];