All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.shapesecurity.bandolier.es2017.ImportExportTransformer Maven / Gradle / Ivy

There is a newer version: 3.5.1
Show newest version
/*
 * Copyright 2016 Shape Security, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.shapesecurity.bandolier.es2017;

import com.shapesecurity.functional.data.ImmutableList;
import com.shapesecurity.functional.data.Maybe;
import com.shapesecurity.shift.es2017.ast.AssignmentExpression;
import com.shapesecurity.shift.es2017.ast.BindingIdentifier;
import com.shapesecurity.shift.es2017.ast.CallExpression;
import com.shapesecurity.shift.es2017.ast.ClassDeclaration;
import com.shapesecurity.shift.es2017.ast.ComputedMemberAssignmentTarget;
import com.shapesecurity.shift.es2017.ast.ComputedMemberExpression;
import com.shapesecurity.shift.es2017.ast.Export;
import com.shapesecurity.shift.es2017.ast.ExportAllFrom;
import com.shapesecurity.shift.es2017.ast.ExportDeclaration;
import com.shapesecurity.shift.es2017.ast.ExportDefault;
import com.shapesecurity.shift.es2017.ast.ExportFrom;
import com.shapesecurity.shift.es2017.ast.ExportFromSpecifier;
import com.shapesecurity.shift.es2017.ast.ExportLocalSpecifier;
import com.shapesecurity.shift.es2017.ast.ExportLocals;
import com.shapesecurity.shift.es2017.ast.Expression;
import com.shapesecurity.shift.es2017.ast.ExpressionStatement;
import com.shapesecurity.shift.es2017.ast.ForInStatement;
import com.shapesecurity.shift.es2017.ast.FunctionDeclaration;
import com.shapesecurity.shift.es2017.ast.FunctionDeclarationClassDeclarationExpression;
import com.shapesecurity.shift.es2017.ast.FunctionDeclarationClassDeclarationVariableDeclaration;
import com.shapesecurity.shift.es2017.ast.FunctionExpression;
import com.shapesecurity.shift.es2017.ast.IdentifierExpression;
import com.shapesecurity.shift.es2017.ast.Import;
import com.shapesecurity.shift.es2017.ast.ImportDeclaration;
import com.shapesecurity.shift.es2017.ast.ImportDeclarationExportDeclarationStatement;
import com.shapesecurity.shift.es2017.ast.ImportNamespace;
import com.shapesecurity.shift.es2017.ast.ImportSpecifier;
import com.shapesecurity.shift.es2017.ast.LiteralStringExpression;
import com.shapesecurity.shift.es2017.ast.Module;
import com.shapesecurity.shift.es2017.ast.Script;
import com.shapesecurity.shift.es2017.ast.SpreadElementExpression;
import com.shapesecurity.shift.es2017.ast.Statement;
import com.shapesecurity.shift.es2017.ast.VariableDeclaration;
import com.shapesecurity.shift.es2017.ast.VariableDeclarationKind;
import com.shapesecurity.shift.es2017.ast.VariableDeclarationStatement;
import com.shapesecurity.shift.es2017.ast.VariableDeclarator;

/**
 * ImportExportTransformer applies the transformations necessary for reducing a {@link Module} to a
 * {@link Script}.
 */
public class ImportExportTransformer {
	static public Module transformModule(Module module) {
		ImmutableList statementItems =
			module.items.bind(ImportExportTransformer::transformImportDeclarationExportDeclarationStatement);

		ImmutableList items =
			statementItems.map(x -> (ImportDeclarationExportDeclarationStatement) x);

		return new Module(module.directives, items);
	}

	static private ImmutableList transformImportDeclarationExportDeclarationStatement(
		ImportDeclarationExportDeclarationStatement statement) {
		if (statement instanceof ImportDeclaration) {
			return transformImportDeclaration((ImportDeclaration) statement);
		} else if (statement instanceof ExportDeclaration) {
			return transformExportDeclaration((ExportDeclaration) statement);
		} else {
			return ImmutableList.of((Statement) statement); // do not transform other statements
		}
	}

	static private ImmutableList transformImportDeclaration(ImportDeclaration declaration) {
		if (declaration instanceof Import) {
			return transformImport((Import) declaration);
		} else if (declaration instanceof ImportNamespace) {
			return transformImportNamespace((ImportNamespace) declaration);
		} else {
			return ImmutableList.empty(); //This should never happen!
		}
	}

	static private ImmutableList transformImport(Import statement) {
		String resolver = "__resolver";

		Statement requireStatement =
			statement.namedImports.isEmpty() && statement.defaultBinding.isNothing() ?
				makeRequireStatement(statement.moduleSpecifier) :
				makeRequireStatement(resolver, statement.moduleSpecifier);

		ImmutableList variableDeclarationStatements =
			statement.namedImports.map(x -> (Statement) makeNamedImportStatement(resolver, x));

		if (statement.defaultBinding.isJust()) {
			variableDeclarationStatements = variableDeclarationStatements.cons(
				makeDefaultBindingStatement(resolver, statement.defaultBinding.fromJust()));
		}

		return variableDeclarationStatements.cons(requireStatement);
	}

	static private ImmutableList transformImportNamespace(ImportNamespace statement) {
		String resolver = "__resolver";

		Statement requireStatement = makeRequireStatement(resolver, statement.moduleSpecifier);

		ImmutableList variableDeclarationStatements =
			ImmutableList.of(makeNameSpaceBindingStatement(resolver, statement.namespaceBinding));

		if (statement.defaultBinding.isJust()) {
			variableDeclarationStatements = variableDeclarationStatements.cons(
				makeDefaultBindingStatement(resolver, statement.defaultBinding.fromJust()));
		}

		return variableDeclarationStatements.cons(requireStatement);
	}


	static private ImmutableList transformExportDeclaration(ExportDeclaration declaration) {
		if (declaration instanceof Export) {
			return transformExport((Export) declaration);
		} else if (declaration instanceof ExportAllFrom) {
			return transformExportAllFrom((ExportAllFrom) declaration);
		} else if (declaration instanceof ExportDefault) {
			return transformExportDefault((ExportDefault) declaration);
		} else if (declaration instanceof ExportFrom) {
			return transformExportFrom((ExportFrom) declaration);
		} else if (declaration instanceof ExportLocals) {
			return transformExportLocals((ExportLocals) declaration);
		} else {
			return ImmutableList.empty(); //This should never happen
		}
	}


	static private ImmutableList transformExport(Export statement) {
		FunctionDeclarationClassDeclarationVariableDeclaration declaration = statement.declaration;
		if (declaration instanceof FunctionDeclaration) {
			return transformExportFunctionDeclaration((FunctionDeclaration) declaration);
		} else if (declaration instanceof ClassDeclaration) {
			return transformExportClassDeclaration((ClassDeclaration) declaration);
		} else if (declaration instanceof VariableDeclaration) {
			return transformExportVariableDeclaration((VariableDeclaration) declaration);
		} else {
			return ImmutableList.empty(); //This should never happen
		}
	}

	static private ImmutableList transformExportFunctionDeclaration(FunctionDeclaration declaration) {
		return ImmutableList.of(declaration,
			makeNamedExportStatement(new ExportLocalSpecifier(new IdentifierExpression(declaration.name.name), Maybe.empty())));
	}

	static private ImmutableList transformExportClassDeclaration(ClassDeclaration declaration) {
		return ImmutableList.of(declaration,
			makeNamedExportStatement(new ExportLocalSpecifier(new IdentifierExpression(declaration.name.name), Maybe.empty())));
	}

	static private ImmutableList transformExportVariableDeclaration(VariableDeclaration declaration) {
		ImmutableList exportStatements =
			declaration.declarators.map(x -> {
				BindingIdentifier temp = (BindingIdentifier) x.binding;
				return makeNamedExportStatement(new ExportLocalSpecifier(new IdentifierExpression(temp.name), Maybe.empty()));
			});
		return exportStatements.cons(new VariableDeclarationStatement(declaration));
	}

	static private ImmutableList transformExportAllFrom(ExportAllFrom statement) {
		String resolver = "__resolver";

		Statement requireStatement = makeRequireStatement(resolver, statement.moduleSpecifier);
		Statement enumerateExports = makeEnumerateExports(resolver);

		return ImmutableList.of(requireStatement, enumerateExports);
	}

	static private ImmutableList transformExportDefault(ExportDefault statement) {
		FunctionDeclarationClassDeclarationExpression body = statement.body;
		if (body instanceof FunctionDeclaration) {
			return transformExportDefaultFunctionDeclaration((FunctionDeclaration) body);
		} else if (body instanceof ClassDeclaration) {
			return transformExportDefaultClassDeclaration((ClassDeclaration) body);
		} else if (body instanceof Expression) {
			return transformExportDefaultExpression((Expression) body);
		} else {
			return ImmutableList.empty(); //This should never happen
		}
	}

	static private ImmutableList transformExportDefaultFunctionDeclaration(FunctionDeclaration declaration) {
		String functionName = declaration.name.name;
		if (functionName.equals("*default*")) {
			IdentifierExpression exportsIden = new IdentifierExpression("exports");
			ComputedMemberAssignmentTarget compMem = new ComputedMemberAssignmentTarget(exportsIden, new LiteralStringExpression("default"));

			AssignmentExpression assignmentExpression =
				new AssignmentExpression(compMem, new FunctionExpression(false, false, Maybe.empty(),
					declaration.params, declaration.body));
			return ImmutableList.of(new ExpressionStatement(assignmentExpression));
		} else {
			return ImmutableList.of(declaration,
									  makeExportDefaultStatement(new ExportLocalSpecifier(new IdentifierExpression(declaration.name.name), Maybe.empty())));
		}
	}

	static private ImmutableList transformExportDefaultClassDeclaration(ClassDeclaration declaration) {
		return ImmutableList.of(declaration,
			makeExportDefaultStatement(new ExportLocalSpecifier(new IdentifierExpression(declaration.name.name), Maybe.empty())));
	}

	static private ImmutableList transformExportDefaultExpression(Expression expression) {
		IdentifierExpression exportsIden = new IdentifierExpression("exports");
		ComputedMemberAssignmentTarget staticMem = new ComputedMemberAssignmentTarget(exportsIden, new LiteralStringExpression("default"));

		AssignmentExpression assignmentExpression =
			new AssignmentExpression(staticMem, expression);
		return ImmutableList.of(new ExpressionStatement(assignmentExpression));
	}

	static private ImmutableList transformExportLocals(ExportLocals declaration) {
		return declaration.namedExports.map(x -> (Statement) makeNamedExportStatement(x));
	}

	static private ImmutableList transformExportFrom(ExportFrom statement) {
		String resolver = "__resolver";

		String moduleSpecifier = statement.moduleSpecifier;
		ImmutableList statements = statement.namedExports.map(x -> (Statement) makeNamedExportStatement(resolver, x));

		return statements.cons(makeRequireStatement(resolver, moduleSpecifier));
	}

	// e.g., exports.x = x;
	static private ExpressionStatement makeNamedExportStatement(ExportLocalSpecifier specifier) {
		IdentifierExpression exportsIden = new IdentifierExpression("exports");
		ComputedMemberAssignmentTarget staticMem = new ComputedMemberAssignmentTarget(exportsIden, new LiteralStringExpression(specifier.exportedName.orJust(specifier.name.name)));

		IdentifierExpression exportVar = makeExportVar(specifier);

		AssignmentExpression assignmentExpression = new AssignmentExpression(staticMem, exportVar);

		return new ExpressionStatement(assignmentExpression);
	}

	// e.g., exports.default = x;
	static private ExpressionStatement makeExportDefaultStatement(ExportLocalSpecifier specifier) {
		IdentifierExpression exportsIden = new IdentifierExpression("exports");
		ComputedMemberAssignmentTarget staticMem = new ComputedMemberAssignmentTarget(exportsIden, new LiteralStringExpression("default"));

		IdentifierExpression exportVar = makeExportVar(specifier);

		AssignmentExpression assignmentExpression = new AssignmentExpression(staticMem, exportVar);

		return new ExpressionStatement(assignmentExpression);
	}

	// e.g., exports.x = __resolver.x
	static private ExpressionStatement makeNamedExportStatement(String resolver, ExportFromSpecifier specifier) {
		IdentifierExpression exportsIden = new IdentifierExpression("exports");
		ComputedMemberAssignmentTarget staticMem = new ComputedMemberAssignmentTarget(exportsIden, new LiteralStringExpression(specifier.exportedName.orJust(specifier.name)));

		ComputedMemberExpression exportVar = makeExportVar(resolver, specifier);

		AssignmentExpression assignmentExpression = new AssignmentExpression(staticMem, exportVar);

		return new ExpressionStatement(assignmentExpression);
	}

	// e.g., __resolver.x
	static private ComputedMemberExpression makeExportVar(String resolver, ExportFromSpecifier specifier) {
		String property = specifier.name;

		return new ComputedMemberExpression(new IdentifierExpression(resolver), new LiteralStringExpression(property));
	}

	// e.g., x
	static private IdentifierExpression makeExportVar(ExportLocalSpecifier specifier) {
		return new IdentifierExpression(specifier.name.name);
	}

	// e.g., require('lib');
	static private ExpressionStatement makeRequireStatement(String moduleSpecifier) {
		return new ExpressionStatement(makeRequireCallExpression(moduleSpecifier));
	}

	// e.g., var __resolver = require('lib');
	static private VariableDeclarationStatement makeRequireStatement(String resolver, String moduleSpecifier) {
		BindingIdentifier resolverIden = new BindingIdentifier(resolver); // e.g. _resolver = require(...);
		CallExpression callExp = makeRequireCallExpression(moduleSpecifier);

		ImmutableList declarators =
			ImmutableList.of(new VariableDeclarator(resolverIden, Maybe.of(callExp)));

		VariableDeclaration declaration = new VariableDeclaration(VariableDeclarationKind.Var, declarators);

		return new VariableDeclarationStatement(declaration);
	}

	// e.g., require('lib')
	static private CallExpression makeRequireCallExpression(String moduleSpecifier) {
		IdentifierExpression require = new IdentifierExpression("require"); // function require

		LiteralStringExpression module = new LiteralStringExpression(moduleSpecifier); // e.g. 'lib.js'
		IdentifierExpression secondParam = new IdentifierExpression("module"); // the second parameter to require

		ImmutableList requireArguments =
			ImmutableList.of(module, secondParam); // parameters to pass to require

		return new CallExpression(require, requireArguments);
	}

	// e.g., d = _resolver.default;
	static private VariableDeclarationStatement makeDefaultBindingStatement(String resolver, BindingIdentifier binding) {
		IdentifierExpression resolverIden = new IdentifierExpression(resolver);
		ComputedMemberExpression staticMem = new ComputedMemberExpression(resolverIden, new LiteralStringExpression("default"));

		ImmutableList declarators =
			ImmutableList.of(new VariableDeclarator(binding, Maybe.of(staticMem)));

		VariableDeclaration declaration = new VariableDeclaration(VariableDeclarationKind.Var, declarators);

		return new VariableDeclarationStatement(declaration);
	}


	// e.g., m = __resolver;
	static private VariableDeclarationStatement makeNameSpaceBindingStatement(String resolver, BindingIdentifier binding) {
		IdentifierExpression resolverIden = new IdentifierExpression(resolver);

		ImmutableList declarators =
			ImmutableList.of(new VariableDeclarator(binding, Maybe.of(resolverIden)));

		VariableDeclaration declaration = new VariableDeclaration(VariableDeclarationKind.Var, declarators);

		return new VariableDeclarationStatement(declaration);
	}

	// e.g., x = __resolver.y or x = __resolver.x
	static private VariableDeclarationStatement makeNamedImportStatement(String resolver, ImportSpecifier specifier) {
		IdentifierExpression resolverIden = new IdentifierExpression(resolver);
		ComputedMemberExpression staticMem = specifier.name.isJust() ?
			new ComputedMemberExpression(resolverIden, new LiteralStringExpression(specifier.name.fromJust())) :
			new ComputedMemberExpression(resolverIden, new LiteralStringExpression(specifier.binding.name));

		ImmutableList declarators =
			ImmutableList.of(new VariableDeclarator(specifier.binding, Maybe.of(staticMem)));

		VariableDeclaration declaration = new VariableDeclaration(VariableDeclarationKind.Var, declarators);

		return new VariableDeclarationStatement(declaration);
	}

	// e.g., for(var i in __resolver) exports[k] = __resolver[k];
	static private ForInStatement makeEnumerateExports(String resolver) {
		BindingIdentifier itemIden = new BindingIdentifier("i");
		VariableDeclarator itemDeclarator = new VariableDeclarator(itemIden, Maybe.empty());
		VariableDeclaration itemDeclaration =
			new VariableDeclaration(VariableDeclarationKind.Var, ImmutableList.of(itemDeclarator));
		IdentifierExpression resolverIden = new IdentifierExpression(resolver);

		IdentifierExpression itemIdenExp = new IdentifierExpression("i");
		IdentifierExpression exportsIden = new IdentifierExpression("exports");
		ComputedMemberAssignmentTarget exportsItem = new ComputedMemberAssignmentTarget(exportsIden, itemIdenExp);

		ComputedMemberExpression resolverItem = new ComputedMemberExpression(resolverIden, itemIdenExp);

		AssignmentExpression assignment = new AssignmentExpression(exportsItem, resolverItem);


		return new ForInStatement(itemDeclaration, resolverIden, new ExpressionStatement(assignment));
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy