UNPKG

js-slang

Version:

Javascript-based implementations of Source, written in Typescript

88 lines 5.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path_1 = require("path"); const typeGuards_1 = require("../../utils/ast/typeGuards"); const assert_1 = require("../../utils/assert"); const helpers_1 = require("../../utils/ast/helpers"); const utils_1 = require("../utils"); const transformProgramToFunctionDeclaration_1 = require("./transformers/transformProgramToFunctionDeclaration"); const filePaths_1 = require("./filePaths"); const contextSpecificConstructors_1 = require("./constructors/contextSpecificConstructors"); const hoistAndMergeImports_1 = require("./transformers/hoistAndMergeImports"); const removeExports_1 = require("./transformers/removeExports"); const getSourceModuleImports = (programs) => { return Object.values(programs).flatMap(program => { return program.body.filter((stmt) => { if (!(0, typeGuards_1.isImportDeclaration)(stmt)) return false; const importSource = (0, helpers_1.getModuleDeclarationSource)(stmt); return (0, utils_1.isSourceModule)(importSource); }); }); }; const defaultBundler = (programs, entrypointFilePath, topoOrder) => { // We want to operate on the entrypoint program to get the eventual // preprocessed program. const entrypointProgram = programs[entrypointFilePath]; const entrypointDirPath = path_1.posix.resolve(entrypointFilePath, '..'); // Create variables to hold the imported statements. const entrypointProgramModuleDeclarations = entrypointProgram.body.filter(typeGuards_1.isModuleDeclaration); const entrypointProgramInvokedFunctionResultVariableNameToImportSpecifiersMap = (0, transformProgramToFunctionDeclaration_1.getInvokedFunctionResultVariableNameToImportSpecifiersMap)(entrypointProgramModuleDeclarations, entrypointDirPath); const entrypointProgramAccessImportStatements = (0, transformProgramToFunctionDeclaration_1.createAccessImportStatements)(entrypointProgramInvokedFunctionResultVariableNameToImportSpecifiersMap); // Transform all programs into their equivalent function declaration // except for the entrypoint program. const functionDeclarations = {}; for (const [filePath, program] of Object.entries(programs)) { // The entrypoint program does not need to be transformed into its // function declaration equivalent as its enclosing environment is // simply the overall program's (constructed program's) environment. if (filePath === entrypointFilePath) { continue; } const functionDeclaration = (0, transformProgramToFunctionDeclaration_1.transformProgramToFunctionDeclaration)(program, filePath); const functionName = functionDeclaration.id?.name; (0, assert_1.default)(functionName !== undefined, 'A transformed function declaration is missing its name. This should never happen.'); functionDeclarations[functionName] = functionDeclaration; } // Invoke each of the transformed functions and store the result in a variable. const invokedFunctionResultVariableDeclarations = []; topoOrder.forEach((filePath) => { // As mentioned above, the entrypoint program does not have a function // declaration equivalent, so there is no need to process it. if (filePath === entrypointFilePath) { return; } const functionName = (0, filePaths_1.transformFilePathToValidFunctionName)(filePath); const invokedFunctionResultVariableName = (0, filePaths_1.transformFunctionNameToInvokedFunctionResultVariableName)(functionName); const functionDeclaration = functionDeclarations[functionName]; const functionParams = functionDeclaration.params.filter(typeGuards_1.isIdentifier); (0, assert_1.default)(functionParams.length === functionDeclaration.params.length, 'Function declaration contains non-Identifier AST nodes as params. This should never happen.'); const invokedFunctionResultVariableDeclaration = (0, contextSpecificConstructors_1.createInvokedFunctionResultVariableDeclaration)(functionName, invokedFunctionResultVariableName, functionParams); invokedFunctionResultVariableDeclarations.push(invokedFunctionResultVariableDeclaration); }); // Get all Source module imports across the entrypoint program & all imported programs. const sourceModuleImports = getSourceModuleImports(programs); // Re-assemble the program. const preprocessedProgram = { ...entrypointProgram, body: [ ...sourceModuleImports, ...Object.values(functionDeclarations), ...invokedFunctionResultVariableDeclarations, ...entrypointProgramAccessImportStatements, ...entrypointProgram.body ] }; // We need to hoist all remaining imports to the top of the // program. These imports should be source module imports since // non-Source module imports would have already been handled. As part // of this step, we also merge imports from the same module so as to // import each unique name per module only once. (0, hoistAndMergeImports_1.default)(preprocessedProgram); // After this pre-processing step, all export-related nodes in the AST // are no longer needed and are thus removed. (0, removeExports_1.default)(preprocessedProgram); return preprocessedProgram; }; exports.default = defaultBundler; //# sourceMappingURL=bundler.js.map