UNPKG

cst

Version:

JavaScript CST Implementation

592 lines (490 loc) 17.3 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _keys = require('babel-runtime/core-js/object/keys'); var _keys2 = _interopRequireDefault(_keys); var _typeof2 = require('babel-runtime/helpers/typeof'); var _typeof3 = _interopRequireDefault(_typeof2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Element assertion class. * Used in specific Node types to check children for syntax correctness. * */ var ElementAssert = function () { /** * @param {Element[]} elements */ function ElementAssert(elements) { (0, _classCallCheck3.default)(this, ElementAssert); this._elements = elements; if (elements.length > 0) { this._navigate(0); } } (0, _createClass3.default)(ElementAssert, [{ key: 'assertToken', /** * Asserts that the current element is a token. * Can also check for token type and value. * * @param {String} [tokenType] * @param {String|Object} [tokenValue] if object is given, checks if value of token exists as object key. */ value: function assertToken(tokenType, tokenValue) { var _ref = this.currentElement || {}, isToken = _ref.isToken, type = _ref.type, value = _ref.value; if (!isToken) { throw new Error('Token expected but "' + type + '" found'); } if (arguments.length > 0 && type !== tokenType) { throw new Error('Expected token type "' + tokenType + '" but "' + type + '" found'); } if (arguments.length === 2) { if ((typeof tokenValue === 'undefined' ? 'undefined' : (0, _typeof3.default)(tokenValue)) === 'object' && tokenValue !== null) { if (!tokenValue[value]) { throw new Error('Expected token value (' + (0, _keys2.default)(tokenValue).join(', ') + ') but ' + value + ' found'); } } else if (tokenValue !== value) { throw new Error('Expected token value "' + tokenValue + '" but ' + value + ' found'); } } } /** * Asserts that the current element is a node. * Can also check for node type. * * @param {String} nodeType */ }, { key: 'assertNode', value: function assertNode(nodeType) { var _ref2 = this.currentElement || {}, isNode = _ref2.isNode, type = _ref2.type; if (!isNode) { throw new Error('Node expected but "' + type + '" found'); } if (arguments.length > 0 && type !== nodeType) { throw new Error('Expected node type "' + nodeType + '" but "' + type + '" found'); } } /** * Asserts that the current element is a node. * Can also check if any of the node type are satisfied. * * @param {Array} nodeTypes */ }, { key: 'assertOneOfNode', value: function assertOneOfNode(nodeTypes) { var _ref3 = this.currentElement || {}, isNode = _ref3.isNode, type = _ref3.type; if (!isNode) { throw new Error('Node expected but "' + type + '" found'); } if (arguments.length > 0 && nodeTypes.indexOf(type) === -1) { throw new Error('Expected one of node types "' + nodeTypes + '" but "' + type + '" found'); } } /** * Asserts that the current element is an expression. */ }, { key: 'assertExpression', value: function assertExpression() { var _ref4 = this.currentElement || {}, isExpression = _ref4.isExpression, type = _ref4.type; if (!isExpression) { throw new Error('Expression expected but "' + type + '" found'); } } /** * Asserts that the current element is an assignment. */ }, { key: 'assertAssignable', value: function assertAssignable() { var _ref5 = this.currentElement || {}, isAssignable = _ref5.isAssignable, type = _ref5.type; if (!isAssignable) { throw new Error('Expected assignable expression but ' + type + ' found.'); } } /** * Asserts that the current element is a pattern. */ }, { key: 'assertPattern', value: function assertPattern() { var _ref6 = this.currentElement || {}, isPattern = _ref6.isPattern, type = _ref6.type; if (!isPattern) { throw new Error('Expected pattern but ' + type + ' found.'); } } /** * Asserts that the current element is a statement. */ }, { key: 'assertStatement', value: function assertStatement() { var _ref7 = this.currentElement || {}, isStatement = _ref7.isStatement, type = _ref7.type; if (!isStatement) { throw new Error('Statement expected but "' + type + '" found'); } } /** * Asserts that the current element is a statement. */ }, { key: 'assertModuleSpecifier', value: function assertModuleSpecifier() { var _ref8 = this.currentElement || {}, isModuleSpecifier = _ref8.isModuleSpecifier, type = _ref8.type; if (!isModuleSpecifier) { throw new Error('ModuleSpecifier expected but "' + type + '" found'); } } /** * Asserts that the end of child list was reached. */ }, { key: 'assertEnd', value: function assertEnd() { if (this.currentElement !== undefined) { var _ref9 = this.currentElement || {}, type = _ref9.type; throw new Error('Expected end of node list but "' + type + '" found'); } } /** * Checks if the current element is a token. * Can also check for token type and value. * * @param {String} [tokenType] * @param {String|Object} [tokenValue] if object is given, checks if value of token exists as object key. * @returns {Boolean} */ }, { key: 'isToken', value: function isToken(tokenType, tokenValue) { var _ref10 = this.currentElement || {}, isToken = _ref10.isToken, type = _ref10.type, value = _ref10.value; if (!isToken || arguments.length > 0 && type !== tokenType) { return false; } if (arguments.length === 2) { if ((typeof tokenValue === 'undefined' ? 'undefined' : (0, _typeof3.default)(tokenValue)) === 'object' && tokenValue !== null) { return Boolean(tokenValue[value]); } return tokenValue === value; } return true; } /** * Checks if the current element is a node. * Can also check for token type and value. * * @param {String} [nodeType] * @returns {Boolean} */ }, { key: 'isNode', value: function isNode(nodeType) { var _ref11 = this.currentElement || {}, isNode = _ref11.isNode, type = _ref11.type; return !(!isNode || arguments.length > 0 && type !== nodeType); } /** * Checks if the current element is a statement. * * @returns {Boolean} */ }, { key: 'isStatement', value: function isStatement() { var _ref12 = this.currentElement || {}, isStatement = _ref12.isStatement; return isStatement; } /** * Checks if current element is token (can also check type and value), * returns current element and move pointer to the next element. * * @param {String} [tokenType] * @param {String|Object} [tokenValue] * @returns {Element|null} */ }, { key: 'passToken', value: function passToken(tokenType, tokenValue) { this.assertToken.apply(this, arguments); var token = this.currentElement; this.moveNext(); return token; } /** * Checks if current element is a node (can also check type), * returns current element and move pointer to the next element. * * @param {String} [nodeType] * @returns {Element|null} */ }, { key: 'passNode', value: function passNode(nodeType) { this.assertNode.apply(this, arguments); var node = this.currentElement; this.moveNext(); return node; } /** * Checks if current element is a node (can also check if any types are satisfied), * returns current element and move pointer to the next element. * * @param {Array} [nodeTypes] * @returns {Element|null} */ }, { key: 'passOneOfNode', value: function passOneOfNode(nodeTypes) { this.assertOneOfNode(nodeTypes); var node = this.currentElement; this.moveNext(); return node; } /** * Checks if current element is an expression, * returns current element and move pointer to the next element. * Ignores parentheses. * * @returns {Element} */ }, { key: 'passExpression', value: function passExpression() { return this._passExpressionInParens(function (expression) { return expression.isExpression; }); } /** * Checks if current element is an expression or whitespace * returns current element and move pointer to the next element. * Ignores parentheses. * * @returns {Element} */ }, { key: 'passExpressionOrWhitespace', value: function passExpressionOrWhitespace() { return this._passExpressionInParens(function (expression) { return expression.isExpression || expression.isWhitespace; }); } /** * Checks if current element is an expression or super, * returns current element and move pointer to the next element. * Ignores parentheses. * * @returns {Element} */ }, { key: 'passExpressionOrSuper', value: function passExpressionOrSuper() { return this._passExpressionInParens(function (expression) { return expression.isExpression || expression.type === 'Super'; }); } /** * Checks if current element is an expression or SpreadElement, * returns current element and move pointer to the next element. * Ignores parentheses. * * @returns {Element} */ }, { key: 'passExpressionOrSpreadElement', value: function passExpressionOrSpreadElement() { return this._passExpressionInParens(function (expression) { return expression.isExpression || expression.type === 'SpreadElement'; }); } /** * Passes expression ignoring parentheses, returns element and move pointer to the next element. * * @param {Function} assertCallback * @returns {Element} * @private */ }, { key: '_passExpressionInParens', value: function _passExpressionInParens(assertCallback) { var openParens = 0; while (this.currentElement.type === 'Punctuator' && this.currentElement.value === '(') { openParens++; this.moveNext(); this.skipNonCode(); } var expression = this.currentElement; if (!expression) { throw new Error('Could not match an expression'); } if (!assertCallback(expression)) { throw new Error('Expression expected but "' + expression.type + '" found'); } this.moveNext(); while (openParens--) { this.skipNonCode(); this.assertToken('Punctuator', ')'); this.moveNext(); } return expression; } /** * Checks if current element is an assignable, returns current element and move pointer to the next element. * Ignores parentheses. * * @returns {Element} */ }, { key: 'passAssignable', value: function passAssignable() { return this._passExpressionInParens(function (expression) { return expression.isAssignable; }); } /** * Checks if current element is a statement, * returns current element and move pointer to the next element. * * @returns {Element} */ }, { key: 'passStatement', value: function passStatement() { this.assertStatement(); var result = this.currentElement; this.moveNext(); if (!result) { throw new Error('Could not match statement'); } return result; } /** * Checks if current element is a pattern, * returns current element and move pointer to the next element. * * @returns {Element|null} */ }, { key: 'passPattern', value: function passPattern() { this.assertPattern(); var result = this.currentElement; this.moveNext(); if (!result) { throw new Error('Could not match pattern'); } return result; } /** * Checks if current element is a module specifier, * returns current element and move pointer to the next element. * * @returns {Element|null} */ }, { key: 'passModuleSpecifier', value: function passModuleSpecifier() { this.assertModuleSpecifier(); var result = this.currentElement; this.moveNext(); return result; } /** * Skips comments and whitespace. */ }, { key: 'skipNonCode', value: function skipNonCode() { while (true) { var _ref13 = this.currentElement || {}, isCode = _ref13.isCode; if (isCode !== false) { break; } this.moveNext(); } } /** * Skips comments and whitespace on the same line. */ }, { key: 'skipSameLineNonCode', value: function skipSameLineNonCode() { while (true) { var _ref14 = this.currentElement || {}, isCode = _ref14.isCode; if (isCode !== false) { break; } if (this.currentElement && this.currentElement.getNewlineCount() > 0) { break; } this.moveNext(); } } /** * Skips a semicolon. */ }, { key: 'skipSemicolon', value: function skipSemicolon() { if (this.currentElement && this.currentElement.type === 'Punctuator' && this.currentElement.value === ';') { this.moveNext(); } } /** * Moves pointer (currentElement) to next element. */ }, { key: 'moveNext', value: function moveNext() { this._navigate(this._position + 1); } /** * Navigates to specified child position. * * @param {Number} position * @private */ }, { key: '_navigate', value: function _navigate(position) { this._position = position; this.currentElement = this._elements[position]; this.isEnd = this.currentElement === undefined; } }]); return ElementAssert; }(); exports.default = ElementAssert; //# sourceMappingURL=ElementAssert.js.map