UNPKG

cst

Version:

JavaScript CST Implementation

243 lines (202 loc) 8.09 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildElementTree = buildElementTree; exports.buildTokenList = buildTokenList; var _babylon = require('babylon'); var babylon = _interopRequireWildcard(_babylon); var _visitorKeys = require('./visitorKeys'); var _visitorKeys2 = _interopRequireDefault(_visitorKeys); var _elementIndex = require('./elements/elementIndex'); var _elementIndex2 = _interopRequireDefault(_elementIndex); var _Token = require('./elements/Token'); var _Token2 = _interopRequireDefault(_Token); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } /** * Creates CST using AST and token list. * * @param {Object} ast * @param {Array} tokens * @returns {Program} */ function buildElementTree(ast, tokens) { var firstToken = tokens[0]; ast.start = firstToken.start; ast.end = tokens[tokens.length - 1].end; return buildElementTreeItem(ast, { tokens: tokens, token: firstToken, pos: 0 }); } /** * @param {Object} ast * @param {{tokens: Array, token: Object, pos: Number}} state * @returns {Element} */ function buildElementTreeItem(ast, state) { var elementType = ast.type; var childProps = _visitorKeys2.default[elementType]; // Skip first `Identifier` for ({ test = 1 } = {}) // since it is already used in `AssignmentPattern` // Need to fix this one day (See https://github.com/babel/babylon/issues/49) if (ast.type === 'ObjectProperty' && ast.value.type === 'AssignmentPattern') { delete ast.key; } if (!childProps) { var error = new SyntaxError('Cannot iterate using ' + elementType); error.loc = ast.loc.start; throw error; } var childElements = []; for (var i = 0; i < childProps.length; i++) { var childAst = ast[childProps[i]]; if (!childAst) { continue; } if (Array.isArray(childAst)) { for (var j = 0; j < childAst.length; j++) { if (childAst[j] === null) { continue; } childElements[childElements.length] = childAst[j]; } } else { childElements[childElements.length] = childAst; } } childElements.sort(function (ast1, ast2) { return ast1.start < ast2.start ? -1 : ast1.start > ast2.start ? 1 : 0; }); var NodeClass = _elementIndex2.default[elementType]; if (!NodeClass) { throw new Error('Cannot create ' + elementType + ' instance'); } var children = []; var childElementIndex = 0; var childElement = childElements[0]; var end = ast.end; do { if (childElement && state.token.start === childElement.start) { if (state.token.end > childElement.end) { var EmptyNodeClass = _elementIndex2.default[childElement.type]; if (!EmptyNodeClass) { throw new Error('Cannot create ' + childElement.type + ' instance'); } children[children.length] = new EmptyNodeClass([]); childElement = childElements[++childElementIndex]; } else { children[children.length] = buildElementTreeItem(childElement, state); childElement = childElements[++childElementIndex]; if (!state.token || state.token.start === end && (state.token.end !== end || elementType !== 'Program')) { return new NodeClass(children); } } } else { var endOfAstReached = state.token.end === end; var addedTokenType = state.token.type; if (endOfAstReached && ast.type === 'Identifier' && addedTokenType === 'Keyword') { state.token.type = addedTokenType = 'Identifier'; } children[children.length] = _Token2.default.createFromToken(state.token); state.pos++; state.token = state.tokens[state.pos]; if (elementType === 'Program' && addedTokenType !== 'EOF') { continue; } if (endOfAstReached) { return new NodeClass(children); } } } while (state.token); } /** * Build single token list using code tokens, comments and whitespace. * * @param {Array} codeTokens * @param {String} code * @returns {Array} */ function buildTokenList(codeTokens, code) { var prevPos = 0; var result = []; for (var i = 0; i < codeTokens.length; i++) { var _token = processToken(codeTokens[i], code); var _pos = _token.start; if (prevPos !== _pos) { var _value = code.substring(prevPos, _pos); result[result.length] = { type: 'Whitespace', value: _value, sourceCode: _value, start: prevPos, end: _pos }; } result[result.length] = _token; prevPos = _token.end; } return result; } /** * Babylon token types. */ var tt = babylon.tokTypes; /** * Transforms Babylon-style token to Esprima-style token. * * @param {Object} token * @param {String} source */ function processToken(token, source) { var type = token.type; if (type === tt.name) { token.type = 'Identifier'; } else if (type === tt.semi || type === tt.comma || type === tt.parenL || type === tt.parenR || type === tt.braceL || type === tt.braceR || type === tt.slash || type === tt.dot || type === tt.bracketL || type === tt.bracketR || type === tt.ellipsis || type === tt.arrow || type === tt.star || type === tt.incDec || type === tt.colon || type === tt.question || type === tt.backQuote || type === tt.dollarBraceL || type === tt.at || type === tt.logicalOR || type === tt.logicalAND || type === tt.bitwiseOR || type === tt.bitwiseXOR || type === tt.bitwiseAND || type === tt.equality || type === tt.relational || type === tt.bitShift || type === tt.plusMin || type === tt.modulo || type === tt.exponent || type === tt.prefix || type === tt.doubleColon || type.isAssign) { token.type = 'Punctuator'; if (!token.value) { token.sourceCode = token.value = type.label; } } else if (type === tt.template) { token.type = 'Template'; token.sourceCode = token.value; } else if (type === tt.jsxTagStart) { token.type = 'Punctuator'; token.sourceCode = token.value = '<'; } else if (type === tt.jsxTagEnd) { token.type = 'Punctuator'; token.sourceCode = token.value = '>'; } else if (type === tt.jsxName) { token.type = 'JSXIdentifier'; } else if (type === tt.jsxText) { token.type = 'JSXText'; } else if (type.keyword === 'null') { token.type = 'Null'; token.value = null; } else if (type.keyword === 'false' || type.keyword === 'true') { token.type = 'Boolean'; token.value = type.keyword === 'true'; } else if (type.keyword) { token.type = 'Keyword'; } else if (type === tt.num) { token.type = 'Numeric'; } else if (type === tt.string) { token.type = 'String'; } else if (type === tt.regexp) { token.type = 'RegularExpression'; } else if (type === 'CommentLine') { token.sourceCode = '//' + token.value; } else if (type === 'CommentBlock') { token.sourceCode = '/*' + token.value + '*/'; } else if (type === tt.eof) { token.type = 'EOF'; token.sourceCode = token.value = ''; } if (!('sourceCode' in token)) { token.sourceCode = source.slice(token.start, token.end); } return token; } //# sourceMappingURL=elementTree.js.map