UNPKG

decaffeinate-parser

Version:

A better AST for CoffeeScript, inspired by CoffeeScriptRedux.

224 lines (223 loc) 10.3 kB
"use strict"; /* eslint-disable @typescript-eslint/camelcase */ var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; exports.__esModule = true; var SourceType_1 = require("coffee-lex/dist/SourceType"); var nodes_1 = require("decaffeinate-coffeescript2/lib/coffeescript/nodes"); var expandToIncludeParens_1 = require("./expandToIncludeParens"); var fixInvalidLocationData_1 = require("./fixInvalidLocationData"); var locationDataFromSourceRange_1 = require("./locationDataFromSourceRange"); var locationWithLastPosition_1 = require("./locationWithLastPosition"); var mergeLocations_1 = require("./mergeLocations"); var rangeOfBracketTokensForIndexNode_1 = require("./rangeOfBracketTokensForIndexNode"); var sourceRangeFromLocationData_1 = require("./sourceRangeFromLocationData"); function fixLocations(context, node) { var linesAndColumns = context.linesAndColumns, source = context.source; node.eachChild(function (child) { if (child && child.locationData) { fixLocations(context, child); } return undefined; }); node.locationData = fixInvalidLocationData_1["default"](node.locationData, context.linesAndColumns); if (node instanceof nodes_1.Value) { var lastChild = node.properties[node.properties.length - 1] || node.base; if (lastChild) { node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } } if (node instanceof nodes_1.Index || node instanceof nodes_1.Slice) { var rangeOfBrackets = rangeOfBracketTokensForIndexNode_1["default"](context, node); var lbracket = context.sourceTokens.tokenAtIndex(rangeOfBrackets[0]); if (lbracket === null) { throw new Error('Expected to find left-bracket token.'); } var lbracketLoc = linesAndColumns.locationForIndex(lbracket.start); if (lbracketLoc === null) { throw new Error('Expected to find a location for the left-bracket token.'); } var rbracketIndex = rangeOfBrackets[1].previous(); if (rbracketIndex === null) { throw new Error('Expected to find a non-null right-bracket token index.'); } var rbracket = context.sourceTokens.tokenAtIndex(rbracketIndex); if (rbracket === null) { throw new Error('Expected to find right-bracket token.'); } var rbracketLoc = linesAndColumns.locationForIndex(rbracket.start); if (rbracketLoc === null) { throw new Error('Expected to find a location for the right-bracket token.'); } node.locationData = { first_line: lbracketLoc.line, first_column: lbracketLoc.column, last_line: rbracketLoc.line, last_column: rbracketLoc.column }; } if (node instanceof nodes_1.Obj) { var loc = node.locationData; var start = linesAndColumns.indexForLocation({ line: loc.first_line, column: loc.first_column }); if (start === null) { throw new Error('Expected to find a start index for object.'); } var end = linesAndColumns.indexForLocation({ line: loc.last_line, column: loc.last_column }); if (end === null) { throw new Error('Expected to find an end index for object.'); } var isImplicitObject = source[start] !== '{'; if (isImplicitObject && source[end] !== ',') { var lastChild = node.properties[node.properties.length - 1]; node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } } if (node instanceof nodes_1.Op) { var lastChild = node.second; if (lastChild) { node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } } if (node instanceof nodes_1.Assign) { var lastChild = node.value; node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } if (node instanceof nodes_1.In) { var lastChild = node.array; node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } if (node instanceof nodes_1.Call) { if (node.variable && !node["do"] && !node.csx) { // `super` won't have a callee (i.e. `node.variable`) var calleeLoc = node.variable.locationData; var calleeEnd = linesAndColumns.indexForLocation({ line: calleeLoc.last_line, column: calleeLoc.last_column }); if (calleeEnd === null) { throw new Error('Expected to find index for callee end.'); } calleeEnd++; // Account for soaked calls, e.g. `a?()`. if (source[calleeEnd] === '?') { calleeEnd += 1; } var isImplicitCall = source[calleeEnd] !== '('; if (isImplicitCall) { var lastChild = node.args[node.args.length - 1] || node.variable; if (lastChild) { node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } } } } if (node instanceof nodes_1.Block) { var lastChild = node.expressions[node.expressions.length - 1]; if (lastChild) { node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } else { // Shorten range (usually length 1, the shortest range expressible by the CoffeeScript parser) to length 0. var sourceRange = sourceRangeFromLocationData_1["default"](context, node.locationData); node.locationData = locationDataFromSourceRange_1["default"](context, { start: sourceRange.end, end: sourceRange.end }); } // Blocks can sometimes end one index before their terminating semicolon // when really they should end exactly at that semicolon. var blockEnd = linesAndColumns.indexForLocation({ line: node.locationData.last_line, column: node.locationData.last_column }); if (blockEnd === null) { throw new Error('Expected to find index for block end.'); } if (source[blockEnd + 1] === ';') { blockEnd++; var loc = linesAndColumns.locationForIndex(blockEnd); if (loc === null) { throw new Error('Expected to find location for block end.'); } node.locationData.last_line = loc.line; node.locationData.last_column = loc.column; } // The CS2 AST doesn't include the surrounding parens in a block, which can cause trouble with // things like postfix loops with parenthesized bodies. Expand every block to include any // surrounding parens. node.locationData = expandToIncludeParens_1["default"](context, node.locationData); } if (node instanceof nodes_1.If) { var lastChild = node.elseBody || node.body; node.locationData = mergeLocations_1["default"](node.locationData, lastChild.locationData); } if (node instanceof nodes_1.For || node instanceof nodes_1.While) { var lastChild = node.body; if (lastChild) { node.locationData = mergeLocations_1["default"](node.locationData, lastChild.locationData); } } if (node instanceof nodes_1.Param) { if (!node.splat) { var lastChild = node.value || node.name; node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } } if (node instanceof nodes_1.Code) { if (node.body) { node.locationData = locationWithLastPosition_1["default"](node.locationData, node.body.locationData); } } if (node instanceof nodes_1.Class) { var lastChild = node.body; node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } if (node instanceof nodes_1.Switch) { var lastChild = node.otherwise || node.cases[node.cases.length - 1][1]; node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } if (node instanceof nodes_1.Try) { var lastChild = node.ensure || node.recovery || node.errorVariable || node.attempt; if (lastChild) { node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } } if (node instanceof nodes_1.Extends) { var lastChild = node.parent; node.locationData = locationWithLastPosition_1["default"](node.locationData, lastChild.locationData); } if (node instanceof nodes_1.Literal) { // Heregexp flags have an incorrect location, so detect that case and adjust // the end location to be correct. var endIndex = linesAndColumns.indexForLocation({ line: node.locationData.last_line, column: node.locationData.last_column }); if (endIndex !== null) { var tokenIndex = context.sourceTokens.indexOfTokenNearSourceIndex(endIndex); var token = context.sourceTokens.tokenAtIndex(tokenIndex); if (token && token.type === SourceType_1["default"].HEREGEXP_END) { var location = linesAndColumns.locationForIndex(token.end - 1); if (location) { node.locationData = __assign(__assign({}, node.locationData), { last_line: location.line, last_column: location.column }); } } } } } exports["default"] = fixLocations;