UNPKG

decaffeinate-parser

Version:

A better AST for CoffeeScript, inspired by CoffeeScriptRedux.

80 lines (79 loc) 4.02 kB
import { SourceType } from 'coffee-lex'; import { Assign, Obj, Value } from 'decaffeinate-coffeescript2/lib/coffeescript/nodes'; import { inspect } from 'util'; import { AssignOp, Block, BoundAsyncFunction, BoundFunction, BoundGeneratorFunction, ClassProtoAssignOp, Constructor, Identifier, MemberAccessOp, This } from '../nodes'; import getLocation from '../util/getLocation'; import isCommentOnlyNode from '../util/isCommentOnlyNode'; import mapAny from './mapAny'; export default function mapBlock(context, node) { var childContext = context; if (context.parseState.isInClassBody()) { // Replicate a bug in CoffeeScript: at any block where we see an // object-style proto assignment, stop considering proto assignments in any // sub-traversals. This is taken from the walkBody implementation. var hasProtoAssignChild = node.expressions.some(function (child) { return child instanceof Value && child.isObject(true); }); if (hasProtoAssignChild) { childContext = childContext.updateState(function (s) { return s.dropCurrentClass(); }); } } var _a = getLocation(context, node), line = _a.line, column = _a.column, start = _a.start, end = _a.end, raw = _a.raw; var previousTokenIndex = context.sourceTokens .indexOfTokenNearSourceIndex(start) .previous(); var previousToken = previousTokenIndex ? context.sourceTokens.tokenAtIndex(previousTokenIndex) : null; var inline = previousToken ? previousToken.type !== SourceType.NEWLINE : false; return new Block(line, column, start, end, raw, node.expressions .filter(function (expression) { return !isCommentOnlyNode(expression); }) .map(function (expression) { return mapChild(context, childContext, expression); }) .reduce(function (arr, current) { return arr.concat(current); }, []), inline); } function mapChild(blockContext, childContext, node) { if (blockContext.parseState.isInClassBody() && node instanceof Value && node.isObject(true)) { var obj = node.base; if (!(obj instanceof Obj)) { throw new Error('Expected isObject node to be an object.'); } var statements = []; for (var _i = 0, _a = obj.properties; _i < _a.length; _i++) { var property = _a[_i]; if (isCommentOnlyNode(property)) { continue; } if (property instanceof Assign) { var _b = getLocation(childContext, property), line = _b.line, column = _b.column, start = _b.start, end = _b.end, raw = _b.raw; var key = mapAny(childContext, property.variable); var value = mapAny(childContext, property.value); var Node_1 = ClassProtoAssignOp; if (key instanceof Identifier && key.data === 'constructor') { Node_1 = Constructor; } else if (key instanceof MemberAccessOp && key.expression instanceof This) { Node_1 = AssignOp; } var assignment = new Node_1(line, column, start, end, raw, key, value); statements.push(assignment); if (assignment instanceof ClassProtoAssignOp && (assignment.expression instanceof BoundFunction || assignment.expression instanceof BoundGeneratorFunction || assignment.expression instanceof BoundAsyncFunction)) { blockContext.parseState.recordBoundMethod(assignment); } if (assignment instanceof Constructor) { blockContext.parseState.recordConstructor(assignment); } } else { throw new Error("unexpected class assignment: " + inspect(property)); } } return statements; } return [mapAny(childContext, node)]; }