mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
Enforce media types
This commit is contained in:
parent
c0492ef061
commit
8ef7da2611
22 changed files with 472 additions and 83 deletions
110
js/compiler.ts
110
js/compiler.ts
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||||
import * as ts from "typescript";
|
import * as ts from "typescript";
|
||||||
|
import { MediaType } from "gen/msg_generated";
|
||||||
import { assetSourceCode } from "./assets";
|
import { assetSourceCode } from "./assets";
|
||||||
// tslint:disable-next-line:no-circular-imports
|
// tslint:disable-next-line:no-circular-imports
|
||||||
import * as deno from "./deno";
|
import * as deno from "./deno";
|
||||||
|
@ -85,6 +86,7 @@ export class ModuleMetaData implements ts.IScriptSnapshot {
|
||||||
constructor(
|
constructor(
|
||||||
public readonly moduleId: ModuleId,
|
public readonly moduleId: ModuleId,
|
||||||
public readonly fileName: ModuleFileName,
|
public readonly fileName: ModuleFileName,
|
||||||
|
public readonly mediaType: MediaType,
|
||||||
public readonly sourceCode: SourceCode = "",
|
public readonly sourceCode: SourceCode = "",
|
||||||
public outputCode: OutputCode = ""
|
public outputCode: OutputCode = ""
|
||||||
) {
|
) {
|
||||||
|
@ -107,6 +109,23 @@ export class ModuleMetaData implements ts.IScriptSnapshot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getExtension(
|
||||||
|
fileName: ModuleFileName,
|
||||||
|
mediaType: MediaType
|
||||||
|
): ts.Extension | undefined {
|
||||||
|
switch (mediaType) {
|
||||||
|
case MediaType.JavaScript:
|
||||||
|
return ts.Extension.Js;
|
||||||
|
case MediaType.TypeScript:
|
||||||
|
return fileName.endsWith(".d.ts") ? ts.Extension.Dts : ts.Extension.Ts;
|
||||||
|
case MediaType.Json:
|
||||||
|
return ts.Extension.Json;
|
||||||
|
case MediaType.Unknown:
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** A singleton class that combines the TypeScript Language Service host API
|
/** A singleton class that combines the TypeScript Language Service host API
|
||||||
* with Deno specific APIs to provide an interface for compiling and running
|
* with Deno specific APIs to provide an interface for compiling and running
|
||||||
* TypeScript and JavaScript modules.
|
* TypeScript and JavaScript modules.
|
||||||
|
@ -319,17 +338,6 @@ export class DenoCompiler
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resolve the `fileName` for a given `moduleSpecifier` and
|
|
||||||
* `containingFile`
|
|
||||||
*/
|
|
||||||
private _resolveModuleName(
|
|
||||||
moduleSpecifier: ModuleSpecifier,
|
|
||||||
containingFile: ContainingFile
|
|
||||||
): ModuleFileName | undefined {
|
|
||||||
const moduleMetaData = this.resolveModule(moduleSpecifier, containingFile);
|
|
||||||
return moduleMetaData ? moduleMetaData.fileName : undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Caches the resolved `fileName` in relationship to the `moduleSpecifier`
|
/** Caches the resolved `fileName` in relationship to the `moduleSpecifier`
|
||||||
* and `containingFile` in order to reduce calls to the privileged side
|
* and `containingFile` in order to reduce calls to the privileged side
|
||||||
* to retrieve the contents of a module.
|
* to retrieve the contents of a module.
|
||||||
|
@ -479,9 +487,10 @@ export class DenoCompiler
|
||||||
if (fileName && this._moduleMetaDataMap.has(fileName)) {
|
if (fileName && this._moduleMetaDataMap.has(fileName)) {
|
||||||
return this._moduleMetaDataMap.get(fileName)!;
|
return this._moduleMetaDataMap.get(fileName)!;
|
||||||
}
|
}
|
||||||
let moduleId: ModuleId;
|
let moduleId: ModuleId | undefined;
|
||||||
let sourceCode: SourceCode;
|
let mediaType = MediaType.Unknown;
|
||||||
let outputCode: OutputCode | null;
|
let sourceCode: SourceCode | undefined;
|
||||||
|
let outputCode: OutputCode | undefined;
|
||||||
if (
|
if (
|
||||||
moduleSpecifier.startsWith(ASSETS) ||
|
moduleSpecifier.startsWith(ASSETS) ||
|
||||||
containingFile.startsWith(ASSETS)
|
containingFile.startsWith(ASSETS)
|
||||||
|
@ -492,6 +501,7 @@ export class DenoCompiler
|
||||||
moduleId = moduleSpecifier.split("/").pop()!;
|
moduleId = moduleSpecifier.split("/").pop()!;
|
||||||
const assetName = moduleId.includes(".") ? moduleId : `${moduleId}.d.ts`;
|
const assetName = moduleId.includes(".") ? moduleId : `${moduleId}.d.ts`;
|
||||||
assert(assetName in assetSourceCode, `No such asset "${assetName}"`);
|
assert(assetName in assetSourceCode, `No such asset "${assetName}"`);
|
||||||
|
mediaType = MediaType.TypeScript;
|
||||||
sourceCode = assetSourceCode[assetName];
|
sourceCode = assetSourceCode[assetName];
|
||||||
fileName = `${ASSETS}/${assetName}`;
|
fileName = `${ASSETS}/${assetName}`;
|
||||||
outputCode = "";
|
outputCode = "";
|
||||||
|
@ -499,25 +509,38 @@ export class DenoCompiler
|
||||||
// We query Rust with a CodeFetch message. It will load the sourceCode,
|
// We query Rust with a CodeFetch message. It will load the sourceCode,
|
||||||
// and if there is any outputCode cached, will return that as well.
|
// and if there is any outputCode cached, will return that as well.
|
||||||
const fetchResponse = this._os.codeFetch(moduleSpecifier, containingFile);
|
const fetchResponse = this._os.codeFetch(moduleSpecifier, containingFile);
|
||||||
moduleId = fetchResponse.moduleName!;
|
moduleId = fetchResponse.moduleName;
|
||||||
fileName = fetchResponse.filename!;
|
fileName = fetchResponse.filename;
|
||||||
sourceCode = fetchResponse.sourceCode!;
|
mediaType = fetchResponse.mediaType;
|
||||||
outputCode = fetchResponse.outputCode!;
|
sourceCode = fetchResponse.sourceCode;
|
||||||
|
outputCode = fetchResponse.outputCode;
|
||||||
}
|
}
|
||||||
assert(sourceCode!.length > 0);
|
assert(moduleId != null, "No module ID.");
|
||||||
this._log("resolveModule sourceCode length:", sourceCode.length);
|
assert(fileName != null, "No file name.");
|
||||||
this._log("resolveModule has outputCode:", outputCode! != null);
|
assert(sourceCode ? sourceCode.length > 0 : false, "No source code.");
|
||||||
this._setFileName(moduleSpecifier, containingFile, fileName);
|
assert(
|
||||||
|
mediaType !== MediaType.Unknown,
|
||||||
|
`Unknown media type for: "${moduleSpecifier}" from "${containingFile}".`
|
||||||
|
);
|
||||||
|
this._log(
|
||||||
|
"resolveModule sourceCode length:",
|
||||||
|
sourceCode && sourceCode.length
|
||||||
|
);
|
||||||
|
this._log("resolveModule has outputCode:", outputCode != null);
|
||||||
|
this._log("resolveModule has media type:", MediaType[mediaType]);
|
||||||
|
// fileName is asserted above, but TypeScript does not track so not null
|
||||||
|
this._setFileName(moduleSpecifier, containingFile, fileName!);
|
||||||
if (fileName && this._moduleMetaDataMap.has(fileName)) {
|
if (fileName && this._moduleMetaDataMap.has(fileName)) {
|
||||||
return this._moduleMetaDataMap.get(fileName)!;
|
return this._moduleMetaDataMap.get(fileName)!;
|
||||||
}
|
}
|
||||||
const moduleMetaData = new ModuleMetaData(
|
const moduleMetaData = new ModuleMetaData(
|
||||||
moduleId,
|
moduleId!,
|
||||||
fileName,
|
fileName!,
|
||||||
|
mediaType,
|
||||||
sourceCode,
|
sourceCode,
|
||||||
outputCode
|
outputCode
|
||||||
);
|
);
|
||||||
this._moduleMetaDataMap.set(fileName, moduleMetaData);
|
this._moduleMetaDataMap.set(fileName!, moduleMetaData);
|
||||||
return moduleMetaData;
|
return moduleMetaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,17 +586,21 @@ export class DenoCompiler
|
||||||
|
|
||||||
getScriptKind(fileName: ModuleFileName): ts.ScriptKind {
|
getScriptKind(fileName: ModuleFileName): ts.ScriptKind {
|
||||||
this._log("getScriptKind()", fileName);
|
this._log("getScriptKind()", fileName);
|
||||||
const suffix = fileName.substr(fileName.lastIndexOf(".") + 1);
|
const moduleMetaData = this._getModuleMetaData(fileName);
|
||||||
switch (suffix) {
|
if (moduleMetaData) {
|
||||||
case "ts":
|
switch (moduleMetaData.mediaType) {
|
||||||
|
case MediaType.TypeScript:
|
||||||
return ts.ScriptKind.TS;
|
return ts.ScriptKind.TS;
|
||||||
case "js":
|
case MediaType.JavaScript:
|
||||||
return ts.ScriptKind.JS;
|
return ts.ScriptKind.JS;
|
||||||
case "json":
|
case MediaType.Json:
|
||||||
return ts.ScriptKind.JSON;
|
return ts.ScriptKind.JSON;
|
||||||
default:
|
default:
|
||||||
return this._options.allowJs ? ts.ScriptKind.JS : ts.ScriptKind.TS;
|
return this._options.allowJs ? ts.ScriptKind.JS : ts.ScriptKind.TS;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return this._options.allowJs ? ts.ScriptKind.JS : ts.ScriptKind.TS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getScriptVersion(fileName: ModuleFileName): string {
|
getScriptVersion(fileName: ModuleFileName): string {
|
||||||
|
@ -619,17 +646,17 @@ export class DenoCompiler
|
||||||
resolveModuleNames(
|
resolveModuleNames(
|
||||||
moduleNames: ModuleSpecifier[],
|
moduleNames: ModuleSpecifier[],
|
||||||
containingFile: ContainingFile
|
containingFile: ContainingFile
|
||||||
): ts.ResolvedModule[] {
|
): Array<ts.ResolvedModuleFull | ts.ResolvedModule> {
|
||||||
this._log("resolveModuleNames()", { moduleNames, containingFile });
|
this._log("resolveModuleNames()", { moduleNames, containingFile });
|
||||||
return moduleNames.map(name => {
|
return moduleNames.map(name => {
|
||||||
let resolvedFileName;
|
let moduleMetaData: ModuleMetaData;
|
||||||
if (name === "deno") {
|
if (name === "deno") {
|
||||||
// builtin modules are part of the runtime lib
|
// builtin modules are part of the runtime lib
|
||||||
resolvedFileName = this._resolveModuleName(LIB_RUNTIME, ASSETS);
|
moduleMetaData = this.resolveModule(LIB_RUNTIME, ASSETS);
|
||||||
} else if (name === "typescript") {
|
} else if (name === "typescript") {
|
||||||
resolvedFileName = this._resolveModuleName("typescript.d.ts", ASSETS);
|
moduleMetaData = this.resolveModule("typescript.d.ts", ASSETS);
|
||||||
} else {
|
} else {
|
||||||
resolvedFileName = this._resolveModuleName(name, containingFile);
|
moduleMetaData = this.resolveModule(name, containingFile);
|
||||||
}
|
}
|
||||||
// According to the interface we shouldn't return `undefined` but if we
|
// According to the interface we shouldn't return `undefined` but if we
|
||||||
// fail to return the same length of modules to those we cannot resolve
|
// fail to return the same length of modules to those we cannot resolve
|
||||||
|
@ -638,12 +665,15 @@ export class DenoCompiler
|
||||||
// TODO: all this does is push the problem downstream, and TypeScript
|
// TODO: all this does is push the problem downstream, and TypeScript
|
||||||
// will complain it can't identify the type of the file and throw
|
// will complain it can't identify the type of the file and throw
|
||||||
// a runtime exception, so we need to handle missing modules better
|
// a runtime exception, so we need to handle missing modules better
|
||||||
resolvedFileName = resolvedFileName || "";
|
const resolvedFileName = moduleMetaData.fileName || "";
|
||||||
// This flags to the compiler to not go looking to transpile functional
|
// This flags to the compiler to not go looking to transpile functional
|
||||||
// code, anything that is in `/$asset$/` is just library code
|
// code, anything that is in `/$asset$/` is just library code
|
||||||
const isExternalLibraryImport = resolvedFileName.startsWith(ASSETS);
|
const isExternalLibraryImport = resolvedFileName.startsWith(ASSETS);
|
||||||
// TODO: we should be returning a ts.ResolveModuleFull
|
return {
|
||||||
return { resolvedFileName, isExternalLibraryImport };
|
resolvedFileName,
|
||||||
|
isExternalLibraryImport,
|
||||||
|
extension: getExtension(resolvedFileName, moduleMetaData.mediaType)
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,9 +692,7 @@ export class DenoCompiler
|
||||||
|
|
||||||
private static _instance: DenoCompiler | undefined;
|
private static _instance: DenoCompiler | undefined;
|
||||||
|
|
||||||
/**
|
/** Returns the instance of `DenoCompiler` or creates a new instance. */
|
||||||
* Returns the instance of `DenoCompiler` or creates a new instance.
|
|
||||||
*/
|
|
||||||
static instance(): DenoCompiler {
|
static instance(): DenoCompiler {
|
||||||
return (
|
return (
|
||||||
DenoCompiler._instance || (DenoCompiler._instance = new DenoCompiler())
|
DenoCompiler._instance || (DenoCompiler._instance = new DenoCompiler())
|
||||||
|
|
|
@ -11,6 +11,7 @@ const { DenoCompiler } = (deno as any)._compiler;
|
||||||
interface ModuleInfo {
|
interface ModuleInfo {
|
||||||
moduleName: string | null;
|
moduleName: string | null;
|
||||||
filename: string | null;
|
filename: string | null;
|
||||||
|
mediaType: MediaType | null;
|
||||||
sourceCode: string | null;
|
sourceCode: string | null;
|
||||||
outputCode: string | null;
|
outputCode: string | null;
|
||||||
}
|
}
|
||||||
|
@ -27,15 +28,24 @@ const originals = {
|
||||||
_window: (compilerInstance as any)._window
|
_window: (compilerInstance as any)._window
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum MediaType {
|
||||||
|
JavaScript = 0,
|
||||||
|
TypeScript = 1,
|
||||||
|
Json = 2,
|
||||||
|
Unknown = 3
|
||||||
|
}
|
||||||
|
|
||||||
function mockModuleInfo(
|
function mockModuleInfo(
|
||||||
moduleName: string | null,
|
moduleName: string | null,
|
||||||
filename: string | null,
|
filename: string | null,
|
||||||
|
mediaType: MediaType | null,
|
||||||
sourceCode: string | null,
|
sourceCode: string | null,
|
||||||
outputCode: string | null
|
outputCode: string | null
|
||||||
): ModuleInfo {
|
): ModuleInfo {
|
||||||
return {
|
return {
|
||||||
moduleName,
|
moduleName,
|
||||||
filename,
|
filename,
|
||||||
|
mediaType,
|
||||||
sourceCode,
|
sourceCode,
|
||||||
outputCode
|
outputCode
|
||||||
};
|
};
|
||||||
|
@ -61,6 +71,7 @@ export class A {
|
||||||
const modAModuleInfo = mockModuleInfo(
|
const modAModuleInfo = mockModuleInfo(
|
||||||
"modA",
|
"modA",
|
||||||
"/root/project/modA.ts",
|
"/root/project/modA.ts",
|
||||||
|
MediaType.TypeScript,
|
||||||
modASource,
|
modASource,
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
@ -75,6 +86,7 @@ export class B {
|
||||||
const modBModuleInfo = mockModuleInfo(
|
const modBModuleInfo = mockModuleInfo(
|
||||||
"modB",
|
"modB",
|
||||||
"/root/project/modB.ts",
|
"/root/project/modB.ts",
|
||||||
|
MediaType.TypeScript,
|
||||||
modBSource,
|
modBSource,
|
||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
|
@ -107,21 +119,31 @@ const moduleMap: {
|
||||||
"foo/bar.ts": mockModuleInfo(
|
"foo/bar.ts": mockModuleInfo(
|
||||||
"/root/project/foo/bar.ts",
|
"/root/project/foo/bar.ts",
|
||||||
"/root/project/foo/bar.ts",
|
"/root/project/foo/bar.ts",
|
||||||
|
MediaType.TypeScript,
|
||||||
fooBarTsSource,
|
fooBarTsSource,
|
||||||
null
|
null
|
||||||
),
|
),
|
||||||
"foo/baz.ts": mockModuleInfo(
|
"foo/baz.ts": mockModuleInfo(
|
||||||
"/root/project/foo/baz.ts",
|
"/root/project/foo/baz.ts",
|
||||||
"/root/project/foo/baz.ts",
|
"/root/project/foo/baz.ts",
|
||||||
|
MediaType.TypeScript,
|
||||||
fooBazTsSource,
|
fooBazTsSource,
|
||||||
fooBazTsOutput
|
fooBazTsOutput
|
||||||
),
|
),
|
||||||
"modA.ts": modAModuleInfo
|
"modA.ts": modAModuleInfo,
|
||||||
|
"some.txt": mockModuleInfo(
|
||||||
|
"/root/project/some.txt",
|
||||||
|
"/root/project/some.text",
|
||||||
|
MediaType.Unknown,
|
||||||
|
"console.log();",
|
||||||
|
null
|
||||||
|
)
|
||||||
},
|
},
|
||||||
"/root/project/foo/baz.ts": {
|
"/root/project/foo/baz.ts": {
|
||||||
"./bar.ts": mockModuleInfo(
|
"./bar.ts": mockModuleInfo(
|
||||||
"/root/project/foo/bar.ts",
|
"/root/project/foo/bar.ts",
|
||||||
"/root/project/foo/bar.ts",
|
"/root/project/foo/bar.ts",
|
||||||
|
MediaType.TypeScript,
|
||||||
fooBarTsSource,
|
fooBarTsSource,
|
||||||
fooBarTsOutput
|
fooBarTsOutput
|
||||||
)
|
)
|
||||||
|
@ -131,6 +153,43 @@ const moduleMap: {
|
||||||
},
|
},
|
||||||
"/root/project/modB.ts": {
|
"/root/project/modB.ts": {
|
||||||
"./modA.ts": modAModuleInfo
|
"./modA.ts": modAModuleInfo
|
||||||
|
},
|
||||||
|
"/moduleKinds": {
|
||||||
|
"foo.ts": mockModuleInfo(
|
||||||
|
"foo",
|
||||||
|
"/moduleKinds/foo.ts",
|
||||||
|
MediaType.TypeScript,
|
||||||
|
"console.log('foo');",
|
||||||
|
undefined
|
||||||
|
),
|
||||||
|
"foo.d.ts": mockModuleInfo(
|
||||||
|
"foo",
|
||||||
|
"/moduleKinds/foo.d.ts",
|
||||||
|
MediaType.TypeScript,
|
||||||
|
"console.log('foo');",
|
||||||
|
undefined
|
||||||
|
),
|
||||||
|
"foo.js": mockModuleInfo(
|
||||||
|
"foo",
|
||||||
|
"/moduleKinds/foo.js",
|
||||||
|
MediaType.JavaScript,
|
||||||
|
"console.log('foo');",
|
||||||
|
undefined
|
||||||
|
),
|
||||||
|
"foo.json": mockModuleInfo(
|
||||||
|
"foo",
|
||||||
|
"/moduleKinds/foo.json",
|
||||||
|
MediaType.Json,
|
||||||
|
"console.log('foo');",
|
||||||
|
undefined
|
||||||
|
),
|
||||||
|
"foo.txt": mockModuleInfo(
|
||||||
|
"foo",
|
||||||
|
"/moduleKinds/foo.txt",
|
||||||
|
MediaType.JavaScript,
|
||||||
|
"console.log('foo');",
|
||||||
|
undefined
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -180,6 +239,7 @@ const osMock = {
|
||||||
moduleCache[fileName] = mockModuleInfo(
|
moduleCache[fileName] = mockModuleInfo(
|
||||||
fileName,
|
fileName,
|
||||||
fileName,
|
fileName,
|
||||||
|
MediaType.TypeScript,
|
||||||
sourceCode,
|
sourceCode,
|
||||||
outputCode
|
outputCode
|
||||||
);
|
);
|
||||||
|
@ -192,7 +252,7 @@ const osMock = {
|
||||||
return moduleMap[containingFile][moduleSpecifier];
|
return moduleMap[containingFile][moduleSpecifier];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mockModuleInfo(null, null, null, null);
|
return mockModuleInfo(null, null, null, null, null);
|
||||||
},
|
},
|
||||||
exit(code: number): never {
|
exit(code: number): never {
|
||||||
throw new Error(`os.exit(${code})`);
|
throw new Error(`os.exit(${code})`);
|
||||||
|
@ -405,6 +465,23 @@ test(function compilerResolveModule() {
|
||||||
teardown();
|
teardown();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(function compilerResolveModuleUnknownMediaType() {
|
||||||
|
setup();
|
||||||
|
let didThrow = false;
|
||||||
|
try {
|
||||||
|
compilerInstance.resolveModule("some.txt", "/root/project");
|
||||||
|
} catch (e) {
|
||||||
|
assert(e instanceof Error);
|
||||||
|
assertEqual(
|
||||||
|
e.message,
|
||||||
|
`Unknown media type for: "some.txt" from "/root/project".`
|
||||||
|
);
|
||||||
|
didThrow = true;
|
||||||
|
}
|
||||||
|
assert(didThrow);
|
||||||
|
teardown();
|
||||||
|
});
|
||||||
|
|
||||||
test(function compilerGetModuleDependencies() {
|
test(function compilerGetModuleDependencies() {
|
||||||
setup();
|
setup();
|
||||||
const bazDeps = ["require", "exports", "./bar.ts"];
|
const bazDeps = ["require", "exports", "./bar.ts"];
|
||||||
|
@ -484,11 +561,33 @@ test(function compilerRecompileFlag() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test(function compilerGetScriptKind() {
|
test(function compilerGetScriptKind() {
|
||||||
assertEqual(compilerInstance.getScriptKind("foo.ts"), ts.ScriptKind.TS);
|
setup();
|
||||||
assertEqual(compilerInstance.getScriptKind("foo.d.ts"), ts.ScriptKind.TS);
|
compilerInstance.resolveModule("foo.ts", "/moduleKinds");
|
||||||
assertEqual(compilerInstance.getScriptKind("foo.js"), ts.ScriptKind.JS);
|
compilerInstance.resolveModule("foo.d.ts", "/moduleKinds");
|
||||||
assertEqual(compilerInstance.getScriptKind("foo.json"), ts.ScriptKind.JSON);
|
compilerInstance.resolveModule("foo.js", "/moduleKinds");
|
||||||
assertEqual(compilerInstance.getScriptKind("foo.txt"), ts.ScriptKind.JS);
|
compilerInstance.resolveModule("foo.json", "/moduleKinds");
|
||||||
|
compilerInstance.resolveModule("foo.txt", "/moduleKinds");
|
||||||
|
assertEqual(
|
||||||
|
compilerInstance.getScriptKind("/moduleKinds/foo.ts"),
|
||||||
|
ts.ScriptKind.TS
|
||||||
|
);
|
||||||
|
assertEqual(
|
||||||
|
compilerInstance.getScriptKind("/moduleKinds/foo.d.ts"),
|
||||||
|
ts.ScriptKind.TS
|
||||||
|
);
|
||||||
|
assertEqual(
|
||||||
|
compilerInstance.getScriptKind("/moduleKinds/foo.js"),
|
||||||
|
ts.ScriptKind.JS
|
||||||
|
);
|
||||||
|
assertEqual(
|
||||||
|
compilerInstance.getScriptKind("/moduleKinds/foo.json"),
|
||||||
|
ts.ScriptKind.JSON
|
||||||
|
);
|
||||||
|
assertEqual(
|
||||||
|
compilerInstance.getScriptKind("/moduleKinds/foo.txt"),
|
||||||
|
ts.ScriptKind.JS
|
||||||
|
);
|
||||||
|
teardown();
|
||||||
});
|
});
|
||||||
|
|
||||||
test(function compilerGetScriptVersion() {
|
test(function compilerGetScriptVersion() {
|
||||||
|
|
22
js/os.ts
22
js/os.ts
|
@ -1,11 +1,18 @@
|
||||||
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||||
import { ModuleInfo } from "./types";
|
|
||||||
import * as msg from "gen/msg_generated";
|
import * as msg from "gen/msg_generated";
|
||||||
import { assert } from "./util";
|
import { assert } from "./util";
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
import * as flatbuffers from "./flatbuffers";
|
import * as flatbuffers from "./flatbuffers";
|
||||||
import { sendSync } from "./dispatch";
|
import { sendSync } from "./dispatch";
|
||||||
|
|
||||||
|
interface CodeInfo {
|
||||||
|
moduleName: string | undefined;
|
||||||
|
filename: string | undefined;
|
||||||
|
mediaType: msg.MediaType;
|
||||||
|
sourceCode: string | undefined;
|
||||||
|
outputCode: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
/** Exit the Deno process with optional exit code. */
|
/** Exit the Deno process with optional exit code. */
|
||||||
export function exit(exitCode = 0): never {
|
export function exit(exitCode = 0): never {
|
||||||
const builder = flatbuffers.createBuilder();
|
const builder = flatbuffers.createBuilder();
|
||||||
|
@ -20,7 +27,7 @@ export function exit(exitCode = 0): never {
|
||||||
export function codeFetch(
|
export function codeFetch(
|
||||||
moduleSpecifier: string,
|
moduleSpecifier: string,
|
||||||
containingFile: string
|
containingFile: string
|
||||||
): ModuleInfo {
|
): CodeInfo {
|
||||||
util.log("os.ts codeFetch", moduleSpecifier, containingFile);
|
util.log("os.ts codeFetch", moduleSpecifier, containingFile);
|
||||||
// Send CodeFetch message
|
// Send CodeFetch message
|
||||||
const builder = flatbuffers.createBuilder();
|
const builder = flatbuffers.createBuilder();
|
||||||
|
@ -38,11 +45,14 @@ export function codeFetch(
|
||||||
);
|
);
|
||||||
const codeFetchRes = new msg.CodeFetchRes();
|
const codeFetchRes = new msg.CodeFetchRes();
|
||||||
assert(baseRes!.inner(codeFetchRes) != null);
|
assert(baseRes!.inner(codeFetchRes) != null);
|
||||||
|
// flatbuffers returns `null` for an empty value, this does not fit well with
|
||||||
|
// idiomatic TypeScript under strict null checks, so converting to `undefined`
|
||||||
return {
|
return {
|
||||||
moduleName: codeFetchRes.moduleName(),
|
moduleName: codeFetchRes.moduleName() || undefined,
|
||||||
filename: codeFetchRes.filename(),
|
filename: codeFetchRes.filename() || undefined,
|
||||||
sourceCode: codeFetchRes.sourceCode(),
|
mediaType: codeFetchRes.mediaType(),
|
||||||
outputCode: codeFetchRes.outputCode()
|
sourceCode: codeFetchRes.sourceCode() || undefined,
|
||||||
|
outputCode: codeFetchRes.outputCode() || undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||||
export type TypedArray = Uint8Array | Float32Array | Int32Array;
|
export type TypedArray = Uint8Array | Float32Array | Int32Array;
|
||||||
|
|
||||||
// @internal
|
|
||||||
export interface ModuleInfo {
|
|
||||||
moduleName: string | null;
|
|
||||||
filename: string | null;
|
|
||||||
sourceCode: string | null;
|
|
||||||
outputCode: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tslint:disable:max-line-length
|
// tslint:disable:max-line-length
|
||||||
// Following definitions adapted from:
|
// Following definitions adapted from:
|
||||||
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/index.d.ts
|
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/index.d.ts
|
||||||
|
|
178
src/deno_dir.rs
178
src/deno_dir.rs
|
@ -5,6 +5,7 @@ use errors::DenoResult;
|
||||||
use errors::ErrorKind;
|
use errors::ErrorKind;
|
||||||
use fs as deno_fs;
|
use fs as deno_fs;
|
||||||
use http_util;
|
use http_util;
|
||||||
|
use msg;
|
||||||
use ring;
|
use ring;
|
||||||
use std;
|
use std;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
@ -109,21 +110,28 @@ impl DenoDir {
|
||||||
self: &DenoDir,
|
self: &DenoDir,
|
||||||
module_name: &str,
|
module_name: &str,
|
||||||
filename: &str,
|
filename: &str,
|
||||||
) -> DenoResult<String> {
|
) -> DenoResult<(String, msg::MediaType)> {
|
||||||
let p = Path::new(filename);
|
let p = Path::new(filename);
|
||||||
|
// We write a special ".mime" file into the `.deno/deps` directory along side the
|
||||||
|
// cached file, containing just the media type.
|
||||||
|
let mut media_type_filename = filename.to_string();
|
||||||
|
media_type_filename.push_str(".mime");
|
||||||
|
let mt = Path::new(&media_type_filename);
|
||||||
|
|
||||||
let src = if self.reload || !p.exists() {
|
let src = if self.reload || !p.exists() {
|
||||||
println!("Downloading {}", module_name);
|
println!("Downloading {}", module_name);
|
||||||
let source = http_util::fetch_sync_string(module_name)?;
|
let (source, content_type) = http_util::fetch_sync_string(module_name)?;
|
||||||
match p.parent() {
|
match p.parent() {
|
||||||
Some(ref parent) => fs::create_dir_all(parent),
|
Some(ref parent) => fs::create_dir_all(parent),
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
}?;
|
}?;
|
||||||
deno_fs::write_file(&p, source.as_bytes(), 0o666)?;
|
deno_fs::write_file(&p, source.as_bytes(), 0o666)?;
|
||||||
source
|
deno_fs::write_file(&mt, content_type.as_bytes(), 0o666)?;
|
||||||
|
(source, map_content_type(&p, Some(&content_type)))
|
||||||
} else {
|
} else {
|
||||||
let source = fs::read_to_string(&p)?;
|
let source = fs::read_to_string(&p)?;
|
||||||
source
|
let content_type = fs::read_to_string(&mt)?;
|
||||||
|
(source, map_content_type(&p, Some(&content_type)))
|
||||||
};
|
};
|
||||||
Ok(src)
|
Ok(src)
|
||||||
}
|
}
|
||||||
|
@ -141,18 +149,20 @@ impl DenoDir {
|
||||||
let use_extension = |ext| {
|
let use_extension = |ext| {
|
||||||
let module_name = format!("{}{}", module_name, ext);
|
let module_name = format!("{}{}", module_name, ext);
|
||||||
let filename = format!("{}{}", filename, ext);
|
let filename = format!("{}{}", filename, ext);
|
||||||
let source_code = if is_module_remote {
|
let (source_code, media_type) = if is_module_remote {
|
||||||
self.fetch_remote_source(&module_name, &filename)?
|
self.fetch_remote_source(&module_name, &filename)?
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
module_name, filename,
|
module_name, filename,
|
||||||
"if a module isn't remote, it should have the same filename"
|
"if a module isn't remote, it should have the same filename"
|
||||||
);
|
);
|
||||||
fs::read_to_string(Path::new(&filename))?
|
let path = Path::new(&filename);
|
||||||
|
(fs::read_to_string(path)?, map_content_type(path, None))
|
||||||
};
|
};
|
||||||
return Ok(CodeFetchOutput {
|
return Ok(CodeFetchOutput {
|
||||||
module_name: module_name.to_string(),
|
module_name: module_name.to_string(),
|
||||||
filename: filename.to_string(),
|
filename: filename.to_string(),
|
||||||
|
media_type,
|
||||||
source_code,
|
source_code,
|
||||||
maybe_output_code: None,
|
maybe_output_code: None,
|
||||||
});
|
});
|
||||||
|
@ -215,6 +225,7 @@ impl DenoDir {
|
||||||
Ok(output_code) => Ok(CodeFetchOutput {
|
Ok(output_code) => Ok(CodeFetchOutput {
|
||||||
module_name: out.module_name,
|
module_name: out.module_name,
|
||||||
filename: out.filename,
|
filename: out.filename,
|
||||||
|
media_type: out.media_type,
|
||||||
source_code: out.source_code,
|
source_code: out.source_code,
|
||||||
maybe_output_code: Some(output_code),
|
maybe_output_code: Some(output_code),
|
||||||
}),
|
}),
|
||||||
|
@ -324,6 +335,7 @@ fn test_get_cache_filename() {
|
||||||
pub struct CodeFetchOutput {
|
pub struct CodeFetchOutput {
|
||||||
pub module_name: String,
|
pub module_name: String,
|
||||||
pub filename: String,
|
pub filename: String,
|
||||||
|
pub media_type: msg::MediaType,
|
||||||
pub source_code: String,
|
pub source_code: String,
|
||||||
pub maybe_output_code: Option<String>,
|
pub maybe_output_code: Option<String>,
|
||||||
}
|
}
|
||||||
|
@ -646,3 +658,157 @@ fn parse_local_or_remote(p: &str) -> Result<url::Url, url::ParseError> {
|
||||||
Url::from_file_path(p).map_err(|_err| url::ParseError::IdnaError)
|
Url::from_file_path(p).map_err(|_err| url::ParseError::IdnaError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn map_file_extension(path: &Path) -> msg::MediaType {
|
||||||
|
match path.extension() {
|
||||||
|
None => msg::MediaType::Unknown,
|
||||||
|
Some(os_str) => match os_str.to_str() {
|
||||||
|
Some("ts") => msg::MediaType::TypeScript,
|
||||||
|
Some("js") => msg::MediaType::JavaScript,
|
||||||
|
Some("json") => msg::MediaType::Json,
|
||||||
|
_ => msg::MediaType::Unknown,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_map_file_extension() {
|
||||||
|
assert_eq!(
|
||||||
|
map_file_extension(Path::new("foo/bar.ts")),
|
||||||
|
msg::MediaType::TypeScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_file_extension(Path::new("foo/bar.d.ts")),
|
||||||
|
msg::MediaType::TypeScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_file_extension(Path::new("foo/bar.js")),
|
||||||
|
msg::MediaType::JavaScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_file_extension(Path::new("foo/bar.json")),
|
||||||
|
msg::MediaType::Json
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_file_extension(Path::new("foo/bar.txt")),
|
||||||
|
msg::MediaType::Unknown
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_file_extension(Path::new("foo/bar")),
|
||||||
|
msg::MediaType::Unknown
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert a ContentType string into a enumerated MediaType
|
||||||
|
fn map_content_type(path: &Path, content_type: Option<&str>) -> msg::MediaType {
|
||||||
|
match content_type {
|
||||||
|
Some(content_type) => {
|
||||||
|
// sometimes there is additional data after the media type in
|
||||||
|
// Content-Type so we have to do a bit of manipulation so we are only
|
||||||
|
// dealing with the actual media type
|
||||||
|
let ct_vector: Vec<&str> = content_type.split(";").collect();
|
||||||
|
let ct: &str = ct_vector.first().unwrap();
|
||||||
|
match ct.to_lowercase().as_ref() {
|
||||||
|
"application/typescript"
|
||||||
|
| "text/typescript"
|
||||||
|
| "video/vnd.dlna.mpeg-tts"
|
||||||
|
| "video/mp2t" => msg::MediaType::TypeScript,
|
||||||
|
"application/javascript"
|
||||||
|
| "text/javascript"
|
||||||
|
| "application/ecmascript"
|
||||||
|
| "text/ecmascript"
|
||||||
|
| "application/x-javascript" => msg::MediaType::JavaScript,
|
||||||
|
"application/json" | "text/json" => msg::MediaType::Json,
|
||||||
|
"text/plain" => map_file_extension(path),
|
||||||
|
_ => {
|
||||||
|
debug!("unknown content type: {}", content_type);
|
||||||
|
msg::MediaType::Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => map_file_extension(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_map_content_type() {
|
||||||
|
// Extension only
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar.ts"), None),
|
||||||
|
msg::MediaType::TypeScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar.d.ts"), None),
|
||||||
|
msg::MediaType::TypeScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar.js"), None),
|
||||||
|
msg::MediaType::JavaScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar.json"), None),
|
||||||
|
msg::MediaType::Json
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar.txt"), None),
|
||||||
|
msg::MediaType::Unknown
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), None),
|
||||||
|
msg::MediaType::Unknown
|
||||||
|
);
|
||||||
|
|
||||||
|
// Media Type
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("application/typescript")),
|
||||||
|
msg::MediaType::TypeScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("text/typescript")),
|
||||||
|
msg::MediaType::TypeScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("video/vnd.dlna.mpeg-tts")),
|
||||||
|
msg::MediaType::TypeScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("video/mp2t")),
|
||||||
|
msg::MediaType::TypeScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("application/javascript")),
|
||||||
|
msg::MediaType::JavaScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("text/javascript")),
|
||||||
|
msg::MediaType::JavaScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("application/ecmascript")),
|
||||||
|
msg::MediaType::JavaScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("text/ecmascript")),
|
||||||
|
msg::MediaType::JavaScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("application/x-javascript")),
|
||||||
|
msg::MediaType::JavaScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("application/json")),
|
||||||
|
msg::MediaType::Json
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar"), Some("text/json")),
|
||||||
|
msg::MediaType::Json
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar.ts"), Some("text/plain")),
|
||||||
|
msg::MediaType::TypeScript
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
map_content_type(Path::new("foo/bar.ts"), Some("foo/bar")),
|
||||||
|
msg::MediaType::Unknown
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -4,9 +4,10 @@ use errors::{DenoError, DenoResult};
|
||||||
use tokio_util;
|
use tokio_util;
|
||||||
|
|
||||||
use futures::future::{loop_fn, Loop};
|
use futures::future::{loop_fn, Loop};
|
||||||
use futures::{Future, Stream};
|
use futures::{future, Future, Stream};
|
||||||
use hyper;
|
use hyper;
|
||||||
use hyper::client::{Client, HttpConnector};
|
use hyper::client::{Client, HttpConnector};
|
||||||
|
use hyper::header::CONTENT_TYPE;
|
||||||
use hyper::Uri;
|
use hyper::Uri;
|
||||||
use hyper_rustls;
|
use hyper_rustls;
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ pub fn get_client() -> Client<Connector, hyper::Body> {
|
||||||
|
|
||||||
// The CodeFetch message is used to load HTTP javascript resources and expects a
|
// The CodeFetch message is used to load HTTP javascript resources and expects a
|
||||||
// synchronous response, this utility method supports that.
|
// synchronous response, this utility method supports that.
|
||||||
pub fn fetch_sync_string(module_name: &str) -> DenoResult<String> {
|
pub fn fetch_sync_string(module_name: &str) -> DenoResult<(String, String)> {
|
||||||
let url = module_name.parse::<Uri>().unwrap();
|
let url = module_name.parse::<Uri>().unwrap();
|
||||||
let client = get_client();
|
let client = get_client();
|
||||||
// TODO(kevinkassimo): consider set a max redirection counter
|
// TODO(kevinkassimo): consider set a max redirection counter
|
||||||
|
@ -63,11 +64,18 @@ pub fn fetch_sync_string(module_name: &str) -> DenoResult<String> {
|
||||||
Ok(Loop::Break(response))
|
Ok(Loop::Break(response))
|
||||||
})
|
})
|
||||||
}).and_then(|response| {
|
}).and_then(|response| {
|
||||||
response
|
let content_type = response
|
||||||
|
.headers()
|
||||||
|
.get(CONTENT_TYPE)
|
||||||
|
.map(|content_type| content_type.to_str().unwrap().to_string());
|
||||||
|
let body = response
|
||||||
.into_body()
|
.into_body()
|
||||||
.concat2()
|
.concat2()
|
||||||
.map(|body| String::from_utf8(body.to_vec()).unwrap())
|
.map(|body| String::from_utf8(body.to_vec()).unwrap())
|
||||||
.map_err(|err| DenoError::from(err))
|
.map_err(|err| DenoError::from(err));
|
||||||
|
body.join(future::ok(content_type))
|
||||||
|
}).and_then(|(body_string, maybe_content_type)| {
|
||||||
|
future::ok((body_string, maybe_content_type.unwrap()))
|
||||||
});
|
});
|
||||||
|
|
||||||
tokio_util::block_on(fetch_future)
|
tokio_util::block_on(fetch_future)
|
||||||
|
@ -77,9 +85,11 @@ pub fn fetch_sync_string(module_name: &str) -> DenoResult<String> {
|
||||||
fn test_fetch_sync_string() {
|
fn test_fetch_sync_string() {
|
||||||
// Relies on external http server. See tools/http_server.py
|
// Relies on external http server. See tools/http_server.py
|
||||||
tokio_util::init(|| {
|
tokio_util::init(|| {
|
||||||
let p = fetch_sync_string("http://127.0.0.1:4545/package.json").unwrap();
|
let (p, m) =
|
||||||
|
fetch_sync_string("http://127.0.0.1:4545/package.json").unwrap();
|
||||||
println!("package.json len {}", p.len());
|
println!("package.json len {}", p.len());
|
||||||
assert!(p.len() > 1);
|
assert!(p.len() > 1);
|
||||||
|
assert!(m == "application/json")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,8 +97,10 @@ fn test_fetch_sync_string() {
|
||||||
fn test_fetch_sync_string_with_redirect() {
|
fn test_fetch_sync_string_with_redirect() {
|
||||||
// Relies on external http server. See tools/http_server.py
|
// Relies on external http server. See tools/http_server.py
|
||||||
tokio_util::init(|| {
|
tokio_util::init(|| {
|
||||||
let p = fetch_sync_string("http://127.0.0.1:4546/package.json").unwrap();
|
let (p, m) =
|
||||||
|
fetch_sync_string("http://127.0.0.1:4546/package.json").unwrap();
|
||||||
println!("package.json len {}", p.len());
|
println!("package.json len {}", p.len());
|
||||||
assert!(p.len() > 1);
|
assert!(p.len() > 1);
|
||||||
|
assert!(m == "application/json")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,13 @@ table CwdRes {
|
||||||
cwd: string;
|
cwd: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum MediaType: byte {
|
||||||
|
JavaScript = 0,
|
||||||
|
TypeScript,
|
||||||
|
Json,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
|
||||||
table Base {
|
table Base {
|
||||||
cmd_id: uint32;
|
cmd_id: uint32;
|
||||||
sync: bool = true; // TODO(ry) Change default to false.
|
sync: bool = true; // TODO(ry) Change default to false.
|
||||||
|
@ -137,6 +144,7 @@ table CodeFetchRes {
|
||||||
// is the location of the locally downloaded source code.
|
// is the location of the locally downloaded source code.
|
||||||
module_name: string;
|
module_name: string;
|
||||||
filename: string;
|
filename: string;
|
||||||
|
media_type: MediaType;
|
||||||
source_code: string;
|
source_code: string;
|
||||||
output_code: string; // Non-empty only if cached.
|
output_code: string; // Non-empty only if cached.
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,6 +253,7 @@ fn op_code_fetch(
|
||||||
let mut msg_args = msg::CodeFetchResArgs {
|
let mut msg_args = msg::CodeFetchResArgs {
|
||||||
module_name: Some(builder.create_string(&out.module_name)),
|
module_name: Some(builder.create_string(&out.module_name)),
|
||||||
filename: Some(builder.create_string(&out.filename)),
|
filename: Some(builder.create_string(&out.filename)),
|
||||||
|
media_type: out.media_type,
|
||||||
source_code: Some(builder.create_string(&out.source_code)),
|
source_code: Some(builder.create_string(&out.source_code)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
23
tests/019_media_types.ts
Normal file
23
tests/019_media_types.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// When run against the test HTTP server, it will serve different media types
|
||||||
|
// based on the URL containing `.t#.` strings, which exercises the different
|
||||||
|
// mapping of media types end to end.
|
||||||
|
|
||||||
|
// tslint:disable:max-line-length
|
||||||
|
import { loaded as loadedTs1 } from "http://localhost:4545/tests/subdir/mt_text_typescript.t1.ts";
|
||||||
|
import { loaded as loadedTs2 } from "http://localhost:4545/tests/subdir/mt_video_vdn.t2.ts";
|
||||||
|
import { loaded as loadedTs3 } from "http://localhost:4545/tests/subdir/mt_video_mp2t.t3.ts";
|
||||||
|
import { loaded as loadedJs1 } from "http://localhost:4545/tests/subdir/mt_text_javascript.j1.js";
|
||||||
|
import { loaded as loadedJs2 } from "http://localhost:4545/tests/subdir/mt_application_ecmascript.j2.js";
|
||||||
|
import { loaded as loadedJs3 } from "http://localhost:4545/tests/subdir/mt_text_ecmascript.j3.js";
|
||||||
|
import { loaded as loadedJs4 } from "http://localhost:4545/tests/subdir/mt_application_x_javascript.j4.js";
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
"success",
|
||||||
|
loadedTs1,
|
||||||
|
loadedTs2,
|
||||||
|
loadedTs3,
|
||||||
|
loadedJs1,
|
||||||
|
loadedJs2,
|
||||||
|
loadedJs3,
|
||||||
|
loadedJs4
|
||||||
|
);
|
8
tests/019_media_types.ts.out
Normal file
8
tests/019_media_types.ts.out
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Downloading http://localhost:4545/tests/subdir/mt_text_typescript.t1.ts
|
||||||
|
Downloading http://localhost:4545/tests/subdir/mt_video_vdn.t2.ts
|
||||||
|
Downloading http://localhost:4545/tests/subdir/mt_video_mp2t.t3.ts
|
||||||
|
Downloading http://localhost:4545/tests/subdir/mt_text_javascript.j1.js
|
||||||
|
Downloading http://localhost:4545/tests/subdir/mt_application_ecmascript.j2.js
|
||||||
|
Downloading http://localhost:4545/tests/subdir/mt_text_ecmascript.j3.js
|
||||||
|
Downloading http://localhost:4545/tests/subdir/mt_application_x_javascript.j4.js
|
||||||
|
success true true true true true true true
|
|
@ -4,8 +4,8 @@ NotFound: Cannot resolve module "bad-module.ts" from "[WILDCARD]/tests/error_004
|
||||||
at sendSync ([WILDCARD]/js/dispatch.ts:[WILDCARD])
|
at sendSync ([WILDCARD]/js/dispatch.ts:[WILDCARD])
|
||||||
at Object.codeFetch ([WILDCARD]/js/os.ts:[WILDCARD])
|
at Object.codeFetch ([WILDCARD]/js/os.ts:[WILDCARD])
|
||||||
at DenoCompiler.resolveModule ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
at DenoCompiler.resolveModule ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
||||||
at DenoCompiler._resolveModuleName ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
|
||||||
at moduleNames.map.name ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
at moduleNames.map.name ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
||||||
at Array.map (<anonymous>)
|
at Array.map (<anonymous>)
|
||||||
at DenoCompiler.resolveModuleNames ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
at DenoCompiler.resolveModuleNames ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
||||||
at Object.compilerHost.resolveModuleNames ([WILDCARD]/third_party/node_modules/typescript/lib/typescript.js:[WILDCARD])
|
at Object.compilerHost.resolveModuleNames ([WILDCARD]/third_party/node_modules/typescript/lib/typescript.js:[WILDCARD])
|
||||||
|
at resolveModuleNamesWorker ([WILDCARD]/third_party/node_modules/typescript/lib/typescript.js:[WILDCARD])
|
||||||
|
|
|
@ -4,8 +4,8 @@ NotFound: Cannot resolve module "bad-module.ts" from "[WILDCARD]/tests/error_005
|
||||||
at sendSync ([WILDCARD]/js/dispatch.ts:[WILDCARD])
|
at sendSync ([WILDCARD]/js/dispatch.ts:[WILDCARD])
|
||||||
at Object.codeFetch ([WILDCARD]/js/os.ts:[WILDCARD])
|
at Object.codeFetch ([WILDCARD]/js/os.ts:[WILDCARD])
|
||||||
at DenoCompiler.resolveModule ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
at DenoCompiler.resolveModule ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
||||||
at DenoCompiler._resolveModuleName ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
|
||||||
at moduleNames.map.name ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
at moduleNames.map.name ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
||||||
at Array.map (<anonymous>)
|
at Array.map (<anonymous>)
|
||||||
at DenoCompiler.resolveModuleNames ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
at DenoCompiler.resolveModuleNames ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
||||||
at Object.compilerHost.resolveModuleNames ([WILDCARD]/third_party/node_modules/typescript/lib/typescript.js:[WILDCARD])
|
at Object.compilerHost.resolveModuleNames ([WILDCARD]/third_party/node_modules/typescript/lib/typescript.js:[WILDCARD])
|
||||||
|
at resolveModuleNamesWorker ([WILDCARD]/third_party/node_modules/typescript/lib/typescript.js:[WILDCARD])
|
||||||
|
|
|
@ -4,8 +4,8 @@ NotFound: Cannot resolve module "./non-existent" from "[WILDCARD]/tests/error_00
|
||||||
at sendSync ([WILDCARD]/js/dispatch.ts:[WILDCARD])
|
at sendSync ([WILDCARD]/js/dispatch.ts:[WILDCARD])
|
||||||
at Object.codeFetch ([WILDCARD]/js/os.ts:[WILDCARD])
|
at Object.codeFetch ([WILDCARD]/js/os.ts:[WILDCARD])
|
||||||
at DenoCompiler.resolveModule ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
at DenoCompiler.resolveModule ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
||||||
at DenoCompiler._resolveModuleName ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
|
||||||
at moduleNames.map.name ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
at moduleNames.map.name ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
||||||
at Array.map (<anonymous>)
|
at Array.map (<anonymous>)
|
||||||
at DenoCompiler.resolveModuleNames ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
at DenoCompiler.resolveModuleNames ([WILDCARD]/js/compiler.ts:[WILDCARD])
|
||||||
at Object.compilerHost.resolveModuleNames ([WILDCARD]/third_party/node_modules/typescript/lib/typescript.js:[WILDCARD])
|
at Object.compilerHost.resolveModuleNames ([WILDCARD]/third_party/node_modules/typescript/lib/typescript.js:[WILDCARD])
|
||||||
|
at resolveModuleNamesWorker ([WILDCARD]/third_party/node_modules/typescript/lib/typescript.js:[WILDCARD])
|
||||||
|
|
3
tests/subdir/mt_application_ecmascript.j2.js
Normal file
3
tests/subdir/mt_application_ecmascript.j2.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
define(["exports"], function(exports) {
|
||||||
|
exports.loaded = true;
|
||||||
|
});
|
3
tests/subdir/mt_application_x_javascript.j4.js
Normal file
3
tests/subdir/mt_application_x_javascript.j4.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
define(["exports"], function(exports) {
|
||||||
|
exports.loaded = true;
|
||||||
|
});
|
3
tests/subdir/mt_javascript.js
Normal file
3
tests/subdir/mt_javascript.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
define(["exports"], function(exports) {
|
||||||
|
exports.loaded = true;
|
||||||
|
});
|
3
tests/subdir/mt_text_ecmascript.j3.js
Normal file
3
tests/subdir/mt_text_ecmascript.j3.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
define(["exports"], function(exports) {
|
||||||
|
exports.loaded = true;
|
||||||
|
});
|
3
tests/subdir/mt_text_javascript.j1.js
Normal file
3
tests/subdir/mt_text_javascript.j1.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
define(["exports"], function(exports) {
|
||||||
|
exports.loaded = true;
|
||||||
|
});
|
1
tests/subdir/mt_text_typescript.t1.ts
Normal file
1
tests/subdir/mt_text_typescript.t1.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const loaded = true;
|
1
tests/subdir/mt_video_mp2t.t3.ts
Normal file
1
tests/subdir/mt_video_mp2t.t3.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const loaded = true;
|
1
tests/subdir/mt_video_vdn.t2.ts
Normal file
1
tests/subdir/mt_video_vdn.t2.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const loaded = true;
|
|
@ -14,9 +14,33 @@ PORT = 4545
|
||||||
REDIRECT_PORT = 4546
|
REDIRECT_PORT = 4546
|
||||||
|
|
||||||
|
|
||||||
|
class ContentTypeHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||||
|
def guess_type(self, path):
|
||||||
|
if ".t1." in path:
|
||||||
|
return "text/typescript"
|
||||||
|
if ".t2." in path:
|
||||||
|
return "video/vnd.dlna.mpeg-tts"
|
||||||
|
if ".t3." in path:
|
||||||
|
return "video/mp2t"
|
||||||
|
if ".j1." in path:
|
||||||
|
return "text/javascript"
|
||||||
|
if ".j2." in path:
|
||||||
|
return "application/ecmascript"
|
||||||
|
if ".j3." in path:
|
||||||
|
return "text/ecmascript"
|
||||||
|
if ".j4." in path:
|
||||||
|
return "application/x-javascript"
|
||||||
|
return SimpleHTTPServer.SimpleHTTPRequestHandler.guess_type(self, path)
|
||||||
|
|
||||||
|
|
||||||
def server():
|
def server():
|
||||||
os.chdir(root_path) # Hopefully the main thread doesn't also chdir.
|
os.chdir(root_path) # Hopefully the main thread doesn't also chdir.
|
||||||
Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
|
Handler = ContentTypeHandler
|
||||||
|
Handler.extensions_map.update({
|
||||||
|
".ts": "application/typescript",
|
||||||
|
".js": "application/javascript",
|
||||||
|
".json": "application/json",
|
||||||
|
})
|
||||||
SocketServer.TCPServer.allow_reuse_address = True
|
SocketServer.TCPServer.allow_reuse_address = True
|
||||||
s = SocketServer.TCPServer(("", PORT), Handler)
|
s = SocketServer.TCPServer(("", PORT), Handler)
|
||||||
print "Deno test server http://localhost:%d/" % PORT
|
print "Deno test server http://localhost:%d/" % PORT
|
||||||
|
|
Loading…
Add table
Reference in a new issue