2020-01-21 09:01:55 -06:00
|
|
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
2020-01-09 01:17:44 +11:00
|
|
|
|
2020-03-11 10:53:06 +01:00
|
|
|
import { MediaType, SourceFile, SourceFileJson } from "./sourcefile.ts";
|
|
|
|
import { assert } from "../util.ts";
|
|
|
|
import * as util from "../util.ts";
|
|
|
|
import * as compilerOps from "../ops/compiler.ts";
|
2020-01-09 01:17:44 +11:00
|
|
|
|
|
|
|
function resolveSpecifier(specifier: string, referrer: string): string {
|
2020-05-04 09:39:40 -04:00
|
|
|
// The resolveModules op only handles fully qualified URLs for referrer.
|
|
|
|
// However we will have cases where referrer is "/foo.ts". We add this dummy
|
|
|
|
// prefix "file://" in order to use the op.
|
|
|
|
// TODO(ry) Maybe we should perhaps ModuleSpecifier::resolve_import() to
|
|
|
|
// handle this situation.
|
|
|
|
let dummyPrefix = false;
|
|
|
|
const prefix = "file://";
|
|
|
|
if (referrer.startsWith("/")) {
|
|
|
|
dummyPrefix = true;
|
|
|
|
referrer = prefix + referrer;
|
|
|
|
}
|
|
|
|
let r = resolveModules([specifier], referrer)[0];
|
|
|
|
if (dummyPrefix) {
|
|
|
|
r = r.replace(prefix, "");
|
2020-01-09 01:17:44 +11:00
|
|
|
}
|
2020-05-04 09:39:40 -04:00
|
|
|
return r;
|
2020-01-09 01:17:44 +11:00
|
|
|
}
|
|
|
|
|
2020-05-04 09:39:40 -04:00
|
|
|
// TODO(ry) Remove. Unnecessary redirection to compilerOps.resolveModules.
|
2020-01-09 01:17:44 +11:00
|
|
|
export function resolveModules(
|
|
|
|
specifiers: string[],
|
|
|
|
referrer?: string
|
|
|
|
): string[] {
|
|
|
|
util.log("compiler_imports::resolveModules", { specifiers, referrer });
|
2020-03-08 13:09:22 +01:00
|
|
|
return compilerOps.resolveModules(specifiers, referrer);
|
2020-01-09 01:17:44 +11:00
|
|
|
}
|
|
|
|
|
2020-05-04 09:39:40 -04:00
|
|
|
// TODO(ry) Remove. Unnecessary redirection to compilerOps.fetchSourceFiles.
|
2020-01-09 01:17:44 +11:00
|
|
|
function fetchSourceFiles(
|
|
|
|
specifiers: string[],
|
|
|
|
referrer?: string
|
|
|
|
): Promise<SourceFileJson[]> {
|
|
|
|
util.log("compiler_imports::fetchSourceFiles", { specifiers, referrer });
|
2020-03-08 13:09:22 +01:00
|
|
|
return compilerOps.fetchSourceFiles(specifiers, referrer);
|
2020-01-09 01:17:44 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
function getMediaType(filename: string): MediaType {
|
|
|
|
const maybeExtension = /\.([a-zA-Z]+)$/.exec(filename);
|
|
|
|
if (!maybeExtension) {
|
|
|
|
util.log(`!!! Could not identify valid extension: "${filename}"`);
|
|
|
|
return MediaType.Unknown;
|
|
|
|
}
|
|
|
|
const [, extension] = maybeExtension;
|
|
|
|
switch (extension.toLowerCase()) {
|
|
|
|
case "js":
|
|
|
|
return MediaType.JavaScript;
|
|
|
|
case "jsx":
|
|
|
|
return MediaType.JSX;
|
|
|
|
case "ts":
|
|
|
|
return MediaType.TypeScript;
|
|
|
|
case "tsx":
|
|
|
|
return MediaType.TSX;
|
|
|
|
case "wasm":
|
|
|
|
return MediaType.Wasm;
|
|
|
|
default:
|
|
|
|
util.log(`!!! Unknown extension: "${extension}"`);
|
|
|
|
return MediaType.Unknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function processLocalImports(
|
|
|
|
sources: Record<string, string>,
|
|
|
|
specifiers: Array<[string, string]>,
|
2020-02-20 14:58:05 +11:00
|
|
|
referrer?: string,
|
2020-03-03 08:18:27 +11:00
|
|
|
processJsImports = false
|
2020-01-09 01:17:44 +11:00
|
|
|
): string[] {
|
|
|
|
if (!specifiers.length) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
const moduleNames = specifiers.map(
|
|
|
|
referrer
|
|
|
|
? ([, specifier]): string => resolveSpecifier(specifier, referrer)
|
|
|
|
: ([, specifier]): string => specifier
|
|
|
|
);
|
|
|
|
for (let i = 0; i < moduleNames.length; i++) {
|
|
|
|
const moduleName = moduleNames[i];
|
|
|
|
assert(moduleName in sources, `Missing module in sources: "${moduleName}"`);
|
|
|
|
const sourceFile =
|
|
|
|
SourceFile.get(moduleName) ||
|
|
|
|
new SourceFile({
|
|
|
|
url: moduleName,
|
|
|
|
filename: moduleName,
|
|
|
|
sourceCode: sources[moduleName],
|
2020-03-29 04:03:49 +11:00
|
|
|
mediaType: getMediaType(moduleName),
|
2020-01-09 01:17:44 +11:00
|
|
|
});
|
|
|
|
sourceFile.cache(specifiers[i][0], referrer);
|
|
|
|
if (!sourceFile.processed) {
|
2020-02-20 14:58:05 +11:00
|
|
|
processLocalImports(
|
|
|
|
sources,
|
2020-03-03 08:18:27 +11:00
|
|
|
sourceFile.imports(processJsImports),
|
2020-02-20 14:58:05 +11:00
|
|
|
sourceFile.url,
|
2020-03-03 08:18:27 +11:00
|
|
|
processJsImports
|
2020-02-20 14:58:05 +11:00
|
|
|
);
|
2020-01-09 01:17:44 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return moduleNames;
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function processImports(
|
|
|
|
specifiers: Array<[string, string]>,
|
2020-02-20 14:58:05 +11:00
|
|
|
referrer?: string,
|
2020-03-03 08:18:27 +11:00
|
|
|
processJsImports = false
|
2020-01-09 01:17:44 +11:00
|
|
|
): Promise<string[]> {
|
|
|
|
if (!specifiers.length) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
const sources = specifiers.map(([, moduleSpecifier]) => moduleSpecifier);
|
|
|
|
const resolvedSources = resolveModules(sources, referrer);
|
|
|
|
const sourceFiles = await fetchSourceFiles(resolvedSources, referrer);
|
|
|
|
assert(sourceFiles.length === specifiers.length);
|
|
|
|
for (let i = 0; i < sourceFiles.length; i++) {
|
|
|
|
const sourceFileJson = sourceFiles[i];
|
|
|
|
const sourceFile =
|
|
|
|
SourceFile.get(sourceFileJson.url) || new SourceFile(sourceFileJson);
|
|
|
|
sourceFile.cache(specifiers[i][0], referrer);
|
|
|
|
if (!sourceFile.processed) {
|
2020-02-20 14:58:05 +11:00
|
|
|
await processImports(
|
2020-03-03 08:18:27 +11:00
|
|
|
sourceFile.imports(processJsImports),
|
2020-02-20 14:58:05 +11:00
|
|
|
sourceFile.url,
|
2020-03-03 08:18:27 +11:00
|
|
|
processJsImports
|
2020-02-20 14:58:05 +11:00
|
|
|
);
|
2020-01-09 01:17:44 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return resolvedSources;
|
|
|
|
}
|