Home Reference Source Repository

src/fromJson.js

import {
	AssignmentProperty, ArrayExpression, ArrayPattern, ArrowFunctionExpression,
	AssignmentExpression, BinaryExpression, BlockStatement, BreakStatement, CallExpression,
	CatchClause, ClassBody, ClassDeclaration, ClassExpression, ConditionalExpression,
	ContinueStatement, DebuggerStatement, DoWhileStatement, EmptyStatement, ExpressionStatement,
	ExportSpecifier, ExportNamedDeclaration, ExportDefaultDeclaration, ExportAllDeclaration,
	ForStatement, ForInStatement, ForOfStatement, FunctionDeclaration, FunctionExpression,
	Identifier, IfStatement, ImportDeclaration, ImportSpecifier, ImportDefaultSpecifier,
	ImportNamespaceSpecifier, LabeledStatement, Literal, LogicalExpression, MemberExpression,
	MethodDefinition, NewExpression, ObjectExpression, ObjectPattern, Program, Property,
	RestElement, ReturnStatement, SequenceExpression, SpreadElement, SwitchCase, SwitchStatement,
	TaggedTemplateExpression, TemplateElement, TemplateLiteral, ThisExpression, ThrowStatement,
	TryStatement, UpdateExpression, UnaryExpression, VariableDeclarator, VariableDeclaration,
	WhileStatement, YieldExpression} from './ast'
import Loc, {Pos} from './Loc'

/** Converts a plain object to a {@link Node}. */
export default function fromObject(_) {
	switch (_.type) {
		case 'Program':
			return loc(_, new Program(_.body.map(fromStatement)))
		case 'Identifier':
			return fromIdentifier(_)
		case 'VariableDeclarator':
			return fromVariableDeclarator(_)
		case 'VariableDeclaration':
			return loc(_,
				new VariableDeclaration(_.kind, _.declarations.map(fromVariableDeclarator)))
		case 'EmptyStatement':
			return loc(_, new EmptyStatement())
		case 'BlockStatement':
			return loc(_, fromBlockStatement(_))
		case 'ExpressionStatement':
			return loc(_, new ExpressionStatement(fromExpression(_.expression)))
		case 'IfStatement':
			return loc(_, new IfStatement(
				fromExpression(_.test),
				fromStatement(_.consequent),
				op(fromStatement, _.alternate)))
		case 'LabeledStatement':
			return loc(_, new LabeledStatement(fromIdentifier(_.label), fromStatement(_.body)))
		case 'BreakStatement':
			return loc(_, new BreakStatement(op(fromIdentifier, _.label)))
		case 'ContinueStatement':
			return loc(_, new ContinueStatement(op(fromIdentifier, _.label)))
		case 'SwitchCase':
			return fromSwitchCase(_)
		case 'SwitchStatement':
			return loc(_, new SwitchStatement(
				fromExpression(_.discriminant),
				_.cases.map(fromSwitchCase)))
		case 'ReturnStatement':
			return loc(_, new ReturnStatement(op(fromExpression, _.argument)))
		case 'ThrowStatement':
			return loc(_, new ThrowStatement(fromExpression(_.argument)))
		case 'CatchClause':
			return fromCatchClause(_)
		case 'TryStatement':
			return loc(_, new TryStatement(
				fromBlockStatement(_.block),
				op(fromCatchClause, _.handler),
				op(fromBlockStatement, _.finalizer)))
		case 'WhileStatement':
			return loc(_, new WhileStatement(fromExpression(_.test), fromStatement(_.body)))
		case 'DoWhileStatement':
			return loc(_, new DoWhileStatement(fromStatement(_.body), fromExpression(_.test)))
		case 'ForStatement':
			return loc(_, new ForStatement(
				op(fromExpressionOrVariableDeclaration, _.init),
				op(fromExpression, _.test),
				op(fromStatement, _.update),
				fromStatement(_.body)))
		case 'ForInStatement':
			return loc(_, new ForInStatement(
				fromExpressionOrVariableDeclaration(_.left),
				fromExpression(_.right),
				fromStatement(_.body)))
		case 'ForOfStatement':
			return loc(_, new ForOfStatement(
				fromExpressionOrVariableDeclaration(_.left),
				fromExpression(_.right),
				fromStatement(_.body)))
		case 'DebuggerStatement':
			return loc(_, new DebuggerStatement())
		case 'FunctionDeclaration':
			return loc(_, new FunctionDeclaration(
				fromIdentifier(_.id),
				_.params.map(fromIdentifier),
				fromBlockStatement(_.body),
				_.generator))
		case 'Literal':
			return loc(_, new Literal(_.value))
		case 'ThisExpression':
			return loc(_, new ThisExpression())
		case 'ArrayExpression':
			return loc(_, new ArrayExpression(_.elements.map(_ => op(fromExpression, _))))
		case 'Property':
			return fromProperty(_)
		case 'ObjectExpression':
			return loc(_, new ObjectExpression(_.properties.map(fromProperty)))
		case 'FunctionExpression':
			return fromFunctionExpression(_)
		case 'ArrowFunctionExpression':
			return loc(_, new ArrowFunctionExpression(
				_.params.map(fromPattern),
				fromBlockStatementOrExpression(_.body)))
		case 'SequenceExpression':
			return loc(_, new SequenceExpression(_.expressions.map(fromExpression)))
		case 'UnaryExpression':
			return loc(_, new UnaryExpression(_.operator, fromExpression(_.argument)))
		case 'BinaryExpression':
			return loc(_, new BinaryExpression(
				_.operator,
				fromExpression(_.left),
				fromExpression(_.right)))
		case 'AssignmentExpression':
			return loc(_, new AssignmentExpression(
				_.operator,
				fromPattern(_.left),
				fromExpression(_.right)))
		case 'UpdateExpression':
			return loc(_, new UpdateExpression(_.operator, fromExpression(_.argument), _.prefix))
		case 'LogicalExpression':
			return loc(_, new LogicalExpression(
				_.operator,
				fromExpression(_.left),
				fromExpression(_.right)))
		case 'ConditionalExpression':
			return loc(_, new ConditionalExpression(
				fromExpression(_.test),
				fromExpression(_.consequent),
				fromExpression(_.alternate)))
		case 'NewExpression':
			return loc(_, new NewExpression(
				fromExpression(_.callee),
				_.arguments.map(fromExpression)))
		case 'CallExpression':
			return loc(_, new CallExpression(
				fromExpression(_.callee),
				_.arguments.map(fromExpression)))
		case 'SpreadElement':
			return loc(_, new SpreadElement(fromExpression(_.argument)))
		case 'MemberExpression':
			return loc(_, new MemberExpression(
				fromExpression(_.object),
				fromExpression(_.property)))
		case 'YieldExpression':
			return loc(_, new YieldExpression(fromExpression(_.argument), _.delegate))
		case 'TemplateElement':
			return fromTemplateElement(_)
		case 'TemplateLiteral':
			return fromTemplateLiteral(_)
		case 'TaggedTemplateExpression':
			return loc(_, new TaggedTemplateExpression(
				fromExpression(_.tag),
				fromTemplateLiteral(_.quasi)))
		case 'AssignmentProperty':
			return fromAssignmentProperty(_)
		case 'ObjectPattern':
			return loc(_, new ObjectPattern(_.properties.map(fromAssignmentProperty)))
		case 'ArrayPattern':
			return loc(_, new ArrayPattern(_.elements.map(e => op(fromPattern, e))))
		case 'RestElement':
			return loc(_, new RestElement(fromExpression(_.argument)))
		case 'MethodDefinition':
			return fromMethodDefinition(_)
		case 'ClassBody':
			return fromClassBody(_)
		case 'ClassDeclaration':
			return loc(_, new ClassDeclaration(
				fromIdentifier(_.id),
				op(fromExpression, _.superClass),
				fromClassBody(_.body)))
		case 'ClassExpression':
			return loc(_, new ClassExpression(
				op(fromIdentifier, _.id),
				op(fromExpression, _.superClass),
				fromClassBody(_.body)))
		case 'ImportDeclaration':
			return loc(_, new ImportDeclaration(
				_.specifiers.map(fromImportSpecifierAbstract),
				fromLiteralString(_.source)))
		case 'ImportSpecifier':
			return loc(_, new ImportSpecifier(fromIdentifier(_.imported), fromIdentifier(_.local)))
		case 'ImportDefaultSpecifier':
			return loc(_, new ImportDefaultSpecifier(fromIdentifier(_.local)))
		case 'ImportNamespaceSpecifier':
			return loc(_, new ImportNamespaceSpecifier(fromIdentifier(_.local)))
		case 'ExportSpeciifer':
			return fromExportSpecifier(_)
		case 'ExportNamedDeclaration':
			return loc(_, new ExportNamedDeclaration(
				op(fromDeclaration, _.declaration),
				_.specifiers.map(fromExportSpecifier),
				op(fromLiteralString, _.source)))
		case 'ExportDefaultDeclaration':
			return loc(_, new ExportDefaultDeclaration(fromExpressionOrDeclaration(_.declaration)))
		case 'ExportAllDeclaration':
			return loc(_, new ExportAllDeclaration(fromLiteralString(_.source)))
		default: throw new Error(`Bad type: ${_.type}`)
	}
}

const
	op = (func, optional) =>
		optional == null ? null : func(optional),
	loc = (object, ast) => {
		const loc = object.loc
		if (loc !== undefined)
			ast.loc = new Loc(
				new Pos(loc.start.line, loc.start.column),
				new Pos(loc.end.line, loc.end.column))
		return ast
	}

const
	fromIdentifier = _ =>
		loc(_, new Identifier(_.name)),
	fromVariableDeclarator = _ =>
		loc(_, new VariableDeclarator(fromPattern(_.id), op(fromExpression, _.init))),
	fromSwitchCase = _ =>
		loc(_, new SwitchCase(op(fromExpression, _.test), _.consequent.map(fromStatement))),
	fromBlockStatement = _ =>
		loc(_, new BlockStatement(_.body.map(fromStatement))),
	fromCatchClause = _ =>
		loc(_, new CatchClause(fromPattern(_.param), fromBlockStatement(_.body))),
	fromTemplateElement = _ =>
		loc(_, new TemplateElement(_.tail, _.value)),
	fromTemplateLiteral = _ =>
		loc(_, new TemplateLiteral(
			_.quasis.map(fromTemplateElement),
			_.expressions.map(fromExpression))),
	fromAssignmentProperty = _ => {
		if (!(_.kind === 'init' && !_.method && _.shorthand && !_.computed))
			throw new Error(`AssignmentProperty has unusual value: ${JSON.stringify(_)}`)
		return loc(_, new AssignmentProperty(fromIdentifier(_.key), fromPattern(_.value)))
	},
	fromProperty = _ =>
		loc(_, new Property(
			_.kind,
			fromIdentifierOrLiteral(_.key),
			fromExpression(_.value),
			_.method,
			_.shorthand,
			_.computed)),
	fromMethodDefinition =_ =>
		loc(_, new MethodDefinition(
			fromIdentifierOrLiteral(_.key),
			fromFunctionExpression(_.value),
			_.kind,
			_.static,
			_.computed)),
	fromClassBody = _ =>
		loc(_, new ClassBody(_.body.map(fromMethodDefinition))),
	fromFunctionExpression = _ =>
		loc(_, new FunctionExpression(
			op(fromIdentifier, _.id),
			_.params.map(fromPattern),
			fromBlockStatement(_.body),
			_.generator)),
	fromExportSpecifier = _ =>
		loc(_, new ExportSpecifier(fromIdentifier(_.exported), fromIdentifier(_.local)))

const
	fromBlockStatementOrExpression = fromObject,
	fromDeclaration = fromObject,
	fromExpression = fromObject,
	fromExpressionOrDeclaration = fromObject,
	fromExpressionOrVariableDeclaration = fromObject,
	fromIdentifierOrLiteral = fromObject,
	fromImportSpecifierAbstract = fromObject,
	fromLiteralString = fromObject,
	fromPattern = fromObject,
	fromStatement = fromObject