UNPKG

jstransform

Version:

A simple AST visitor-based JS transformer

191 lines (168 loc) 6.07 kB
/** * Copyright 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ var esprima = require('esprima-fb'); var utils = require('../src/utils'); var Syntax = esprima.Syntax; function _isFunctionNode(node) { return node.type === Syntax.FunctionDeclaration || node.type === Syntax.FunctionExpression || node.type === Syntax.ArrowFunctionExpression; } function visitClassProperty(traverse, node, path, state) { utils.catchup(node.range[0], state); utils.catchupWhiteOut(node.range[1], state); return false; } visitClassProperty.test = function(node, path, state) { return node.type === Syntax.ClassProperty; }; function visitTypeAlias(traverse, node, path, state) { utils.catchupWhiteOut(node.range[1], state); return false; } visitTypeAlias.test = function(node, path, state) { return node.type === Syntax.TypeAlias; }; function visitTypeCast(traverse, node, path, state) { path.unshift(node); traverse(node.expression, path, state); path.shift(); utils.catchup(node.typeAnnotation.range[0], state); utils.catchupWhiteOut(node.typeAnnotation.range[1], state); return false; } visitTypeCast.test = function(node, path, state) { return node.type === Syntax.TypeCastExpression; }; function visitInterfaceDeclaration(traverse, node, path, state) { utils.catchupWhiteOut(node.range[1], state); return false; } visitInterfaceDeclaration.test = function(node, path, state) { return node.type === Syntax.InterfaceDeclaration; }; function visitDeclare(traverse, node, path, state) { utils.catchupWhiteOut(node.range[1], state); return false; } visitDeclare.test = function(node, path, state) { switch (node.type) { case Syntax.DeclareVariable: case Syntax.DeclareFunction: case Syntax.DeclareClass: case Syntax.DeclareModule: return true; } return false; }; function visitFunctionParametricAnnotation(traverse, node, path, state) { utils.catchup(node.range[0], state); utils.catchupWhiteOut(node.range[1], state); return false; } visitFunctionParametricAnnotation.test = function(node, path, state) { return node.type === Syntax.TypeParameterDeclaration && path[0] && _isFunctionNode(path[0]) && node === path[0].typeParameters; }; function visitFunctionReturnAnnotation(traverse, node, path, state) { utils.catchup(node.range[0], state); utils.catchupWhiteOut(node.range[1], state); return false; } visitFunctionReturnAnnotation.test = function(node, path, state) { return path[0] && _isFunctionNode(path[0]) && node === path[0].returnType; }; function visitOptionalFunctionParameterAnnotation(traverse, node, path, state) { utils.catchup(node.range[0] + node.name.length, state); utils.catchupWhiteOut(node.range[1], state); return false; } visitOptionalFunctionParameterAnnotation.test = function(node, path, state) { return node.type === Syntax.Identifier && node.optional && path[0] && _isFunctionNode(path[0]); }; function visitTypeAnnotatedIdentifier(traverse, node, path, state) { utils.catchup(node.typeAnnotation.range[0], state); utils.catchupWhiteOut(node.typeAnnotation.range[1], state); return false; } visitTypeAnnotatedIdentifier.test = function(node, path, state) { return node.type === Syntax.Identifier && node.typeAnnotation; }; function visitTypeAnnotatedObjectOrArrayPattern(traverse, node, path, state) { utils.catchup(node.typeAnnotation.range[0], state); utils.catchupWhiteOut(node.typeAnnotation.range[1], state); return false; } visitTypeAnnotatedObjectOrArrayPattern.test = function(node, path, state) { var rightType = node.type === Syntax.ObjectPattern || node.type === Syntax.ArrayPattern; return rightType && node.typeAnnotation; }; /** * Methods cause trouble, since esprima parses them as a key/value pair, where * the location of the value starts at the method body. For example * { bar(x:number,...y:Array<number>):number {} } * is parsed as * { bar: function(x: number, ...y:Array<number>): number {} } * except that the location of the FunctionExpression value is 40-something, * which is the location of the function body. This means that by the time we * visit the params, rest param, and return type organically, we've already * catchup()'d passed them. */ function visitMethod(traverse, node, path, state) { path.unshift(node); traverse(node.key, path, state); path.unshift(node.value); traverse(node.value.params, path, state); node.value.rest && traverse(node.value.rest, path, state); node.value.returnType && traverse(node.value.returnType, path, state); traverse(node.value.body, path, state); path.shift(); path.shift(); return false; } visitMethod.test = function(node, path, state) { return (node.type === "Property" && (node.method || node.kind === "set" || node.kind === "get")) || (node.type === "MethodDefinition"); }; function visitImportType(traverse, node, path, state) { utils.catchupWhiteOut(node.range[1], state); return false; } visitImportType.test = function(node, path, state) { return node.type === 'ImportDeclaration' && (node.importKind === 'type' || node.importKind === 'typeof'); }; function visitExportType(traverse, node, path, state) { utils.catchupWhiteOut(node.range[1], state); } visitExportType.test = function(node, path, state) { return node.type === 'ExportDeclaration' && node.declaration.type === 'TypeAlias'; }; exports.visitorList = [ visitClassProperty, visitDeclare, visitExportType, visitImportType, visitInterfaceDeclaration, visitFunctionParametricAnnotation, visitFunctionReturnAnnotation, visitMethod, visitOptionalFunctionParameterAnnotation, visitTypeAlias, visitTypeCast, visitTypeAnnotatedIdentifier, visitTypeAnnotatedObjectOrArrayPattern ];