mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
6bd846a780
Moves to using a minimal System loader for bundles generated by Deno. TypeScript in 3.8 will be able to output TLA for modules, and the loader is written to take advantage of that as soon as we update Deno to TS 3.8. System also allows us to support `import.meta` and provide more ESM aligned assignment of exports, as well as there is better handling of circular imports. The loader is also very terse versus to try to save overhead. Also, fixed an issue where abstract classes were not being re-exported. Fixes #2553 Fixes #3559 Fixes #3751 Fixes #3825 Refs #3301
98 lines
3.5 KiB
TypeScript
98 lines
3.5 KiB
TypeScript
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
|
|
import { SYSTEM_LOADER } from "./compiler_bootstrap.ts";
|
|
import {
|
|
assert,
|
|
commonPath,
|
|
normalizeString,
|
|
CHAR_FORWARD_SLASH
|
|
} from "./util.ts";
|
|
|
|
/** Local state of what the root exports are of a root module. */
|
|
let rootExports: string[] | undefined;
|
|
|
|
/** Take a URL and normalize it, resolving relative path parts. */
|
|
function normalizeUrl(rootName: string): string {
|
|
const match = /^(\S+:\/{2,3})(.+)$/.exec(rootName);
|
|
if (match) {
|
|
const [, protocol, path] = match;
|
|
return `${protocol}${normalizeString(
|
|
path,
|
|
false,
|
|
"/",
|
|
code => code === CHAR_FORWARD_SLASH
|
|
)}`;
|
|
} else {
|
|
return rootName;
|
|
}
|
|
}
|
|
|
|
/** Given a root name, contents, and source files, enrich the data of the
|
|
* bundle with a loader and re-export the exports of the root name. */
|
|
export function buildBundle(
|
|
rootName: string,
|
|
data: string,
|
|
sourceFiles: readonly ts.SourceFile[]
|
|
): string {
|
|
// when outputting to AMD and a single outfile, TypeScript makes up the module
|
|
// specifiers which are used to define the modules, and doesn't expose them
|
|
// publicly, so we have to try to replicate
|
|
const sources = sourceFiles.map(sf => sf.fileName);
|
|
const sharedPath = commonPath(sources);
|
|
rootName = normalizeUrl(rootName)
|
|
.replace(sharedPath, "")
|
|
.replace(/\.\w+$/i, "");
|
|
let instantiate: string;
|
|
if (rootExports && rootExports.length) {
|
|
instantiate = `const __exp = await __inst("${rootName}");\n`;
|
|
for (const rootExport of rootExports) {
|
|
if (rootExport === "default") {
|
|
instantiate += `export default __exp["${rootExport}"];\n`;
|
|
} else {
|
|
instantiate += `export const ${rootExport} = __exp["${rootExport}"];\n`;
|
|
}
|
|
}
|
|
} else {
|
|
instantiate = `await __inst("${rootName}");\n`;
|
|
}
|
|
return `${SYSTEM_LOADER}\n${data}\n${instantiate}`;
|
|
}
|
|
|
|
/** Set the rootExports which will by the `emitBundle()` */
|
|
export function setRootExports(program: ts.Program, rootModule: string): void {
|
|
// get a reference to the type checker, this will let us find symbols from
|
|
// the AST.
|
|
const checker = program.getTypeChecker();
|
|
// get a reference to the main source file for the bundle
|
|
const mainSourceFile = program.getSourceFile(rootModule);
|
|
assert(mainSourceFile);
|
|
// retrieve the internal TypeScript symbol for this AST node
|
|
const mainSymbol = checker.getSymbolAtLocation(mainSourceFile);
|
|
if (!mainSymbol) {
|
|
return;
|
|
}
|
|
rootExports = checker
|
|
.getExportsOfModule(mainSymbol)
|
|
// .getExportsOfModule includes type only symbols which are exported from
|
|
// the module, so we need to try to filter those out. While not critical
|
|
// someone looking at the bundle would think there is runtime code behind
|
|
// that when there isn't. There appears to be no clean way of figuring that
|
|
// out, so inspecting SymbolFlags that might be present that are type only
|
|
.filter(
|
|
sym =>
|
|
sym.flags & ts.SymbolFlags.Class ||
|
|
!(
|
|
sym.flags & ts.SymbolFlags.Interface ||
|
|
sym.flags & ts.SymbolFlags.TypeLiteral ||
|
|
sym.flags & ts.SymbolFlags.Signature ||
|
|
sym.flags & ts.SymbolFlags.TypeParameter ||
|
|
sym.flags & ts.SymbolFlags.TypeAlias ||
|
|
sym.flags & ts.SymbolFlags.Type ||
|
|
sym.flags & ts.SymbolFlags.Namespace ||
|
|
sym.flags & ts.SymbolFlags.InterfaceExcludes ||
|
|
sym.flags & ts.SymbolFlags.TypeParameterExcludes ||
|
|
sym.flags & ts.SymbolFlags.TypeAliasExcludes
|
|
)
|
|
)
|
|
.map(sym => sym.getName());
|
|
}
|