mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
Import ts file from prototype without change
From commit 559453cf6c
Excluding v8worker.d.ts, main.ts, and deno.d.ts.
Updates tslint.json to be original settings.
This commit is contained in:
parent
21e1425656
commit
fe404dfce9
16 changed files with 1374 additions and 73 deletions
124
js/console.ts
Normal file
124
js/console.ts
Normal file
|
@ -0,0 +1,124 @@
|
|||
const print = V8Worker2.print;
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
type ConsoleContext = Set<any>;
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
function getClassInstanceName(instance: any): string {
|
||||
if (typeof instance !== "object") {
|
||||
return "";
|
||||
}
|
||||
if (instance && instance.__proto__ && instance.__proto__.constructor) {
|
||||
return instance.__proto__.constructor.name; // could be "Object" or "Array"
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
function stringify(ctx: ConsoleContext, value: any): string {
|
||||
switch (typeof value) {
|
||||
case "string":
|
||||
return value;
|
||||
case "number":
|
||||
case "boolean":
|
||||
case "undefined":
|
||||
case "symbol":
|
||||
return String(value);
|
||||
case "function":
|
||||
if (value.name && value.name !== "anonymous") {
|
||||
// from MDN spec
|
||||
return `[Function: ${value.name}]`;
|
||||
}
|
||||
return "[Function]";
|
||||
case "object":
|
||||
if (value === null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (ctx.has(value)) {
|
||||
return "[Circular]";
|
||||
}
|
||||
|
||||
ctx.add(value);
|
||||
const entries: string[] = [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
for (const el of value) {
|
||||
entries.push(stringify(ctx, el));
|
||||
}
|
||||
|
||||
ctx.delete(value);
|
||||
|
||||
if (entries.length === 0) {
|
||||
return "[]";
|
||||
}
|
||||
return `[ ${entries.join(", ")} ]`;
|
||||
} else {
|
||||
let baseString = "";
|
||||
|
||||
const className = getClassInstanceName(value);
|
||||
let shouldShowClassName = false;
|
||||
if (className && className !== "Object" && className !== "anonymous") {
|
||||
shouldShowClassName = true;
|
||||
}
|
||||
|
||||
for (const key of Object.keys(value)) {
|
||||
entries.push(`${key}: ${stringify(ctx, value[key])}`);
|
||||
}
|
||||
|
||||
ctx.delete(value);
|
||||
|
||||
if (entries.length === 0) {
|
||||
baseString = "{}";
|
||||
} else {
|
||||
baseString = `{ ${entries.join(", ")} }`;
|
||||
}
|
||||
|
||||
if (shouldShowClassName) {
|
||||
baseString = `${className} ${baseString}`;
|
||||
}
|
||||
|
||||
return baseString;
|
||||
}
|
||||
default:
|
||||
return "[Not Implemented]";
|
||||
}
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
function stringifyArgs(args: any[]): string {
|
||||
const out: string[] = [];
|
||||
for (const a of args) {
|
||||
if (typeof a === "string") {
|
||||
out.push(a);
|
||||
} else {
|
||||
// tslint:disable-next-line:no-any
|
||||
out.push(stringify(new Set<any>(), a));
|
||||
}
|
||||
}
|
||||
return out.join(" ");
|
||||
}
|
||||
|
||||
export class Console {
|
||||
// tslint:disable-next-line:no-any
|
||||
log(...args: any[]): void {
|
||||
print(stringifyArgs(args));
|
||||
}
|
||||
|
||||
debug = this.log;
|
||||
info = this.log;
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
warn(...args: any[]): void {
|
||||
print(`ERROR: ${stringifyArgs(args)}`);
|
||||
}
|
||||
|
||||
error = this.warn;
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
assert(condition: boolean, ...args: any[]): void {
|
||||
if (!condition) {
|
||||
throw new Error(`Assertion failed: ${stringifyArgs(args)}`);
|
||||
}
|
||||
}
|
||||
}
|
6
js/deno.ts
Normal file
6
js/deno.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
// Public deno module.
|
||||
// TODO get rid of deno.d.ts
|
||||
export { pub, sub } from "./dispatch";
|
||||
export { readFileSync, writeFileSync } from "./os";
|
73
js/dispatch.ts
Normal file
73
js/dispatch.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
import { typedArrayToArrayBuffer } from "./util";
|
||||
import { _global } from "./globals";
|
||||
import { deno as pb } from "./msg.pb";
|
||||
|
||||
export type MessageCallback = (msg: Uint8Array) => void;
|
||||
//type MessageStructCallback = (msg: pb.IMsg) => void;
|
||||
|
||||
const send = V8Worker2.send;
|
||||
const channels = new Map<string, MessageCallback[]>();
|
||||
|
||||
export function sub(channel: string, cb: MessageCallback): void {
|
||||
let subscribers = channels.get(channel);
|
||||
if (!subscribers) {
|
||||
subscribers = [];
|
||||
channels.set(channel, subscribers);
|
||||
}
|
||||
subscribers.push(cb);
|
||||
}
|
||||
|
||||
/*
|
||||
export function subMsg(channel: string, cb: MessageStructCallback): void {
|
||||
sub(channel, (payload: Uint8Array) => {
|
||||
const msg = pb.Msg.decode(payload);
|
||||
if (msg.error != null) {
|
||||
f.onError(new Error(msg.error));
|
||||
} else {
|
||||
cb(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
export function pub(channel: string, payload: Uint8Array): null | ArrayBuffer {
|
||||
const msg = pb.BaseMsg.fromObject({ channel, payload });
|
||||
const ui8 = pb.BaseMsg.encode(msg).finish();
|
||||
const ab = typedArrayToArrayBuffer(ui8);
|
||||
return send(ab);
|
||||
}
|
||||
|
||||
// Internal version of "pub".
|
||||
// TODO add internal version of "sub"
|
||||
export function pubInternal(channel: string, obj: pb.IMsg): null | pb.Msg {
|
||||
const msg = pb.Msg.fromObject(obj);
|
||||
const ui8 = pb.Msg.encode(msg).finish();
|
||||
const resBuf = pub(channel, ui8);
|
||||
if (resBuf != null && resBuf.byteLength > 0) {
|
||||
const res = pb.Msg.decode(new Uint8Array(resBuf));
|
||||
if (res != null && res.error != null && res.error.length > 0) {
|
||||
throw Error(res.error);
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
V8Worker2.recv((ab: ArrayBuffer) => {
|
||||
const msg = pb.BaseMsg.decode(new Uint8Array(ab));
|
||||
const subscribers = channels.get(msg.channel);
|
||||
if (subscribers == null) {
|
||||
throw Error(`No subscribers for channel "${msg.channel}".`);
|
||||
}
|
||||
|
||||
for (const subscriber of subscribers) {
|
||||
subscriber(msg.payload);
|
||||
}
|
||||
});
|
||||
|
||||
// Delete the V8Worker2 from the global object, so that no one else can receive
|
||||
// messages.
|
||||
_global["V8Worker2"] = null;
|
146
js/fetch.ts
Normal file
146
js/fetch.ts
Normal file
|
@ -0,0 +1,146 @@
|
|||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
import {
|
||||
assert,
|
||||
log,
|
||||
createResolvable,
|
||||
Resolvable,
|
||||
typedArrayToArrayBuffer
|
||||
} from "./util";
|
||||
import { pubInternal, sub } from "./dispatch";
|
||||
import { deno as pb } from "./msg.pb";
|
||||
|
||||
export function initFetch() {
|
||||
sub("fetch", (payload: Uint8Array) => {
|
||||
const msg = pb.Msg.decode(payload);
|
||||
assert(msg.command === pb.Msg.Command.FETCH_RES);
|
||||
const id = msg.fetchResId;
|
||||
const f = fetchRequests.get(id);
|
||||
assert(f != null, `Couldn't find FetchRequest id ${id}`);
|
||||
|
||||
f.onMsg(msg);
|
||||
});
|
||||
}
|
||||
|
||||
const fetchRequests = new Map<number, FetchRequest>();
|
||||
|
||||
class FetchResponse implements Response {
|
||||
readonly url: string;
|
||||
body: null;
|
||||
bodyUsed = false; // TODO
|
||||
status: number;
|
||||
statusText = "FIXME"; // TODO
|
||||
readonly type = "basic"; // TODO
|
||||
redirected = false; // TODO
|
||||
headers: null; // TODO
|
||||
//private bodyChunks: Uint8Array[] = [];
|
||||
private first = true;
|
||||
|
||||
constructor(readonly req: FetchRequest) {
|
||||
this.url = req.url;
|
||||
}
|
||||
|
||||
bodyWaiter: Resolvable<ArrayBuffer>;
|
||||
arrayBuffer(): Promise<ArrayBuffer> {
|
||||
this.bodyWaiter = createResolvable();
|
||||
return this.bodyWaiter;
|
||||
}
|
||||
|
||||
blob(): Promise<Blob> {
|
||||
throw Error("not implemented");
|
||||
}
|
||||
|
||||
formData(): Promise<FormData> {
|
||||
throw Error("not implemented");
|
||||
}
|
||||
|
||||
async json(): Promise<object> {
|
||||
const text = await this.text();
|
||||
return JSON.parse(text);
|
||||
}
|
||||
|
||||
async text(): Promise<string> {
|
||||
const ab = await this.arrayBuffer();
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
return decoder.decode(ab);
|
||||
}
|
||||
|
||||
get ok(): boolean {
|
||||
return 200 <= this.status && this.status < 300;
|
||||
}
|
||||
|
||||
clone(): Response {
|
||||
throw Error("not implemented");
|
||||
}
|
||||
|
||||
onHeader: (res: Response) => void;
|
||||
onError: (error: Error) => void;
|
||||
|
||||
onMsg(msg: pb.Msg) {
|
||||
if (msg.error !== null && msg.error !== "") {
|
||||
//throw new Error(msg.error)
|
||||
this.onError(new Error(msg.error));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.first) {
|
||||
this.first = false;
|
||||
this.status = msg.fetchResStatus;
|
||||
this.onHeader(this);
|
||||
} else {
|
||||
// Body message. Assuming it all comes in one message now.
|
||||
const ab = typedArrayToArrayBuffer(msg.fetchResBody);
|
||||
this.bodyWaiter.resolve(ab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let nextFetchId = 0;
|
||||
//TODO implements Request
|
||||
class FetchRequest {
|
||||
private readonly id: number;
|
||||
response: FetchResponse;
|
||||
constructor(readonly url: string) {
|
||||
this.id = nextFetchId++;
|
||||
fetchRequests.set(this.id, this);
|
||||
this.response = new FetchResponse(this);
|
||||
}
|
||||
|
||||
onMsg(msg: pb.Msg) {
|
||||
this.response.onMsg(msg);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
fetchRequests.delete(this.id);
|
||||
}
|
||||
|
||||
start() {
|
||||
log("dispatch FETCH_REQ", this.id, this.url);
|
||||
const res = pubInternal("fetch", {
|
||||
command: pb.Msg.Command.FETCH_REQ,
|
||||
fetchReqId: this.id,
|
||||
fetchReqUrl: this.url
|
||||
});
|
||||
assert(res == null);
|
||||
}
|
||||
}
|
||||
|
||||
export function fetch(
|
||||
input?: Request | string,
|
||||
init?: RequestInit
|
||||
): Promise<Response> {
|
||||
const fetchReq = new FetchRequest(input as string);
|
||||
const response = fetchReq.response;
|
||||
return new Promise((resolve, reject) => {
|
||||
// tslint:disable-next-line:no-any
|
||||
response.onHeader = (response: any) => {
|
||||
log("onHeader");
|
||||
resolve(response);
|
||||
};
|
||||
response.onError = (error: Error) => {
|
||||
log("onError", error);
|
||||
reject(error);
|
||||
};
|
||||
fetchReq.start();
|
||||
});
|
||||
}
|
32
js/globals.ts
Normal file
32
js/globals.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
import * as timer from "./timers";
|
||||
|
||||
// If you use the eval function indirectly, by invoking it via a reference
|
||||
// other than eval, as of ECMAScript 5 it works in the global scope rather than
|
||||
// the local scope. This means, for instance, that function declarations create
|
||||
// global functions, and that the code being evaluated doesn't have access to
|
||||
// local variables within the scope where it's being called.
|
||||
export const globalEval = eval;
|
||||
|
||||
// A reference to the global object.
|
||||
// TODO The underscore is because it's conflicting with @types/node.
|
||||
export const _global = globalEval("this");
|
||||
|
||||
_global["window"] = _global; // Create a window object.
|
||||
import "./url";
|
||||
|
||||
_global["setTimeout"] = timer.setTimeout;
|
||||
_global["setInterval"] = timer.setInterval;
|
||||
_global["clearTimeout"] = timer.clearTimer;
|
||||
_global["clearInterval"] = timer.clearTimer;
|
||||
|
||||
import { Console } from "./console";
|
||||
_global["console"] = new Console();
|
||||
|
||||
import { fetch } from "./fetch";
|
||||
_global["fetch"] = fetch;
|
||||
|
||||
import { TextEncoder, TextDecoder } from "text-encoding";
|
||||
_global["TextEncoder"] = TextEncoder;
|
||||
_global["TextDecoder"] = TextDecoder;
|
|
@ -25,9 +25,9 @@ window["denoMain"] = () => {
|
|||
|
||||
const argv: string[] = [];
|
||||
for (let i = 0; i < msg.startArgvLength(); i++) {
|
||||
const arg = msg.startArgv(i);
|
||||
deno.print(`argv[${i}] ${arg}`);
|
||||
argv.push(msg.startArgv(i));
|
||||
}
|
||||
deno.print(`argv ${argv}`);
|
||||
};
|
||||
|
||||
function typedArrayToArrayBuffer(ta: Uint8Array): ArrayBuffer {
|
||||
|
|
65
js/os.ts
Normal file
65
js/os.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
import { ModuleInfo } from "./types";
|
||||
import { pubInternal } from "./dispatch";
|
||||
import { deno as pb } from "./msg.pb";
|
||||
import { assert } from "./util";
|
||||
|
||||
export function exit(exitCode = 0): void {
|
||||
pubInternal("os", {
|
||||
command: pb.Msg.Command.EXIT,
|
||||
exitCode
|
||||
});
|
||||
}
|
||||
|
||||
export function codeFetch(
|
||||
moduleSpecifier: string,
|
||||
containingFile: string
|
||||
): ModuleInfo {
|
||||
const res = pubInternal("os", {
|
||||
command: pb.Msg.Command.CODE_FETCH,
|
||||
codeFetchModuleSpecifier: moduleSpecifier,
|
||||
codeFetchContainingFile: containingFile
|
||||
});
|
||||
assert(res.command === pb.Msg.Command.CODE_FETCH_RES);
|
||||
return {
|
||||
moduleName: res.codeFetchResModuleName,
|
||||
filename: res.codeFetchResFilename,
|
||||
sourceCode: res.codeFetchResSourceCode,
|
||||
outputCode: res.codeFetchResOutputCode
|
||||
};
|
||||
}
|
||||
|
||||
export function codeCache(
|
||||
filename: string,
|
||||
sourceCode: string,
|
||||
outputCode: string
|
||||
): void {
|
||||
pubInternal("os", {
|
||||
command: pb.Msg.Command.CODE_CACHE,
|
||||
codeCacheFilename: filename,
|
||||
codeCacheSourceCode: sourceCode,
|
||||
codeCacheOutputCode: outputCode
|
||||
});
|
||||
}
|
||||
|
||||
export function readFileSync(filename: string): Uint8Array {
|
||||
const res = pubInternal("os", {
|
||||
command: pb.Msg.Command.READ_FILE_SYNC,
|
||||
readFileSyncFilename: filename
|
||||
});
|
||||
return res.readFileSyncData;
|
||||
}
|
||||
|
||||
export function writeFileSync(
|
||||
filename: string,
|
||||
data: Uint8Array,
|
||||
perm: number
|
||||
): void {
|
||||
pubInternal("os", {
|
||||
command: pb.Msg.Command.WRITE_FILE_SYNC,
|
||||
writeFileSyncFilename: filename,
|
||||
writeFileSyncData: data,
|
||||
writeFileSyncPerm: perm
|
||||
});
|
||||
}
|
339
js/runtime.ts
Normal file
339
js/runtime.ts
Normal file
|
@ -0,0 +1,339 @@
|
|||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
// Glossary
|
||||
// outputCode = generated javascript code
|
||||
// sourceCode = typescript code (or input javascript code)
|
||||
// moduleName = a resolved module name
|
||||
// fileName = an unresolved raw fileName.
|
||||
// for http modules , its the path to the locally downloaded
|
||||
// version.
|
||||
|
||||
import * as ts from "typescript";
|
||||
import * as util from "./util";
|
||||
import { log } from "./util";
|
||||
import * as os from "./os";
|
||||
import * as sourceMaps from "./v8_source_maps";
|
||||
import { _global, globalEval } from "./globals";
|
||||
import * as deno from "./deno";
|
||||
|
||||
const EOL = "\n";
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
export type AmdFactory = (...args: any[]) => undefined | object;
|
||||
export type AmdDefine = (deps: string[], factory: AmdFactory) => void;
|
||||
|
||||
// Uncaught exceptions are sent to window.onerror by v8worker2.
|
||||
// https://git.io/vhOsf
|
||||
window.onerror = (message, source, lineno, colno, error) => {
|
||||
// TODO Currently there is a bug in v8_source_maps.ts that causes a segfault
|
||||
// if it is used within window.onerror. To workaround we uninstall the
|
||||
// Error.prepareStackTrace handler. Users will get unmapped stack traces on
|
||||
// uncaught exceptions until this issue is fixed.
|
||||
Error.prepareStackTrace = null;
|
||||
console.log(error.message, error.stack);
|
||||
os.exit(1);
|
||||
};
|
||||
|
||||
export function setup(mainJs: string, mainMap: string): void {
|
||||
sourceMaps.install({
|
||||
installPrepareStackTrace: true,
|
||||
getGeneratedContents: (filename: string): string => {
|
||||
if (filename === "/main.js") {
|
||||
return mainJs;
|
||||
} else if (filename === "/main.map") {
|
||||
return mainMap;
|
||||
} else {
|
||||
const mod = FileModule.load(filename);
|
||||
if (!mod) {
|
||||
console.error("getGeneratedContents cannot find", filename);
|
||||
}
|
||||
return mod.outputCode;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// This class represents a module. We call it FileModule to make it explicit
|
||||
// that each module represents a single file.
|
||||
// Access to FileModule instances should only be done thru the static method
|
||||
// FileModule.load(). FileModules are NOT executed upon first load, only when
|
||||
// compileAndRun is called.
|
||||
export class FileModule {
|
||||
scriptVersion: string;
|
||||
readonly exports = {};
|
||||
|
||||
private static readonly map = new Map<string, FileModule>();
|
||||
constructor(
|
||||
readonly fileName: string,
|
||||
readonly sourceCode = "",
|
||||
public outputCode = ""
|
||||
) {
|
||||
util.assert(
|
||||
!FileModule.map.has(fileName),
|
||||
`FileModule.map already has ${fileName}`
|
||||
);
|
||||
FileModule.map.set(fileName, this);
|
||||
if (outputCode !== "") {
|
||||
this.scriptVersion = "1";
|
||||
}
|
||||
}
|
||||
|
||||
compileAndRun(): void {
|
||||
if (!this.outputCode) {
|
||||
// If there is no cached outputCode, then compile the code.
|
||||
util.assert(
|
||||
this.sourceCode != null && this.sourceCode.length > 0,
|
||||
`Have no source code from ${this.fileName}`
|
||||
);
|
||||
const compiler = Compiler.instance();
|
||||
this.outputCode = compiler.compile(this.fileName);
|
||||
os.codeCache(this.fileName, this.sourceCode, this.outputCode);
|
||||
}
|
||||
util.log("compileAndRun", this.sourceCode);
|
||||
execute(this.fileName, this.outputCode);
|
||||
}
|
||||
|
||||
static load(fileName: string): FileModule {
|
||||
return this.map.get(fileName);
|
||||
}
|
||||
|
||||
static getScriptsWithSourceCode(): string[] {
|
||||
const out = [];
|
||||
for (const fn of this.map.keys()) {
|
||||
const m = this.map.get(fn);
|
||||
if (m.sourceCode) {
|
||||
out.push(fn);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
export function makeDefine(fileName: string): AmdDefine {
|
||||
const localDefine = (deps: string[], factory: AmdFactory): void => {
|
||||
const localRequire = (x: string) => {
|
||||
log("localRequire", x);
|
||||
};
|
||||
const currentModule = FileModule.load(fileName);
|
||||
const localExports = currentModule.exports;
|
||||
log("localDefine", fileName, deps, localExports);
|
||||
const args = deps.map(dep => {
|
||||
if (dep === "require") {
|
||||
return localRequire;
|
||||
} else if (dep === "exports") {
|
||||
return localExports;
|
||||
} else if (dep === "typescript") {
|
||||
return ts;
|
||||
} else if (dep === "deno") {
|
||||
return deno;
|
||||
} else {
|
||||
const resolved = resolveModuleName(dep, fileName);
|
||||
const depModule = FileModule.load(resolved);
|
||||
depModule.compileAndRun();
|
||||
return depModule.exports;
|
||||
}
|
||||
});
|
||||
factory(...args);
|
||||
};
|
||||
return localDefine;
|
||||
}
|
||||
|
||||
export function resolveModule(
|
||||
moduleSpecifier: string,
|
||||
containingFile: string
|
||||
): null | FileModule {
|
||||
//util.log("resolveModule", { moduleSpecifier, containingFile });
|
||||
util.assert(moduleSpecifier != null && moduleSpecifier.length > 0);
|
||||
// We ask golang to sourceCodeFetch. It will load the sourceCode and if
|
||||
// there is any outputCode cached, it will return that as well.
|
||||
let fetchResponse;
|
||||
try {
|
||||
fetchResponse = os.codeFetch(moduleSpecifier, containingFile);
|
||||
} catch (e) {
|
||||
// TODO Only catch "no such file or directory" errors. Need error codes.
|
||||
return null;
|
||||
}
|
||||
const { filename, sourceCode, outputCode } = fetchResponse;
|
||||
if (sourceCode.length === 0) {
|
||||
return null;
|
||||
}
|
||||
util.log("resolveModule sourceCode length ", sourceCode.length);
|
||||
const m = FileModule.load(filename);
|
||||
if (m != null) {
|
||||
return m;
|
||||
} else {
|
||||
return new FileModule(filename, sourceCode, outputCode);
|
||||
}
|
||||
}
|
||||
|
||||
function resolveModuleName(
|
||||
moduleSpecifier: string,
|
||||
containingFile: string
|
||||
): string | undefined {
|
||||
const mod = resolveModule(moduleSpecifier, containingFile);
|
||||
if (mod) {
|
||||
return mod.fileName;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function execute(fileName: string, outputCode: string): void {
|
||||
util.assert(outputCode && outputCode.length > 0);
|
||||
_global["define"] = makeDefine(fileName);
|
||||
outputCode += `\n//# sourceURL=${fileName}`;
|
||||
globalEval(outputCode);
|
||||
_global["define"] = null;
|
||||
}
|
||||
|
||||
// This is a singleton class. Use Compiler.instance() to access.
|
||||
class Compiler {
|
||||
options: ts.CompilerOptions = {
|
||||
allowJs: true,
|
||||
module: ts.ModuleKind.AMD,
|
||||
outDir: "$deno$",
|
||||
inlineSourceMap: true,
|
||||
lib: ["es2017"],
|
||||
inlineSources: true,
|
||||
target: ts.ScriptTarget.ES2017
|
||||
};
|
||||
/*
|
||||
allowJs: true,
|
||||
module: ts.ModuleKind.AMD,
|
||||
noEmit: false,
|
||||
outDir: '$deno$',
|
||||
*/
|
||||
private service: ts.LanguageService;
|
||||
|
||||
private constructor() {
|
||||
const host = new TypeScriptHost(this.options);
|
||||
this.service = ts.createLanguageService(host);
|
||||
}
|
||||
|
||||
private static _instance: Compiler;
|
||||
static instance(): Compiler {
|
||||
return this._instance || (this._instance = new this());
|
||||
}
|
||||
|
||||
compile(fileName: string): string {
|
||||
const output = this.service.getEmitOutput(fileName);
|
||||
|
||||
// Get the relevant diagnostics - this is 3x faster than
|
||||
// `getPreEmitDiagnostics`.
|
||||
const diagnostics = this.service
|
||||
.getCompilerOptionsDiagnostics()
|
||||
.concat(this.service.getSyntacticDiagnostics(fileName))
|
||||
.concat(this.service.getSemanticDiagnostics(fileName));
|
||||
if (diagnostics.length > 0) {
|
||||
const errMsg = ts.formatDiagnosticsWithColorAndContext(
|
||||
diagnostics,
|
||||
formatDiagnosticsHost
|
||||
);
|
||||
console.log(errMsg);
|
||||
os.exit(1);
|
||||
}
|
||||
|
||||
util.assert(!output.emitSkipped);
|
||||
|
||||
const outputCode = output.outputFiles[0].text;
|
||||
// let sourceMapCode = output.outputFiles[0].text;
|
||||
return outputCode;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the compiler host for type checking.
|
||||
class TypeScriptHost implements ts.LanguageServiceHost {
|
||||
constructor(readonly options: ts.CompilerOptions) {}
|
||||
|
||||
getScriptFileNames(): string[] {
|
||||
const keys = FileModule.getScriptsWithSourceCode();
|
||||
util.log("getScriptFileNames", keys);
|
||||
return keys;
|
||||
}
|
||||
|
||||
getScriptVersion(fileName: string): string {
|
||||
util.log("getScriptVersion", fileName);
|
||||
const m = FileModule.load(fileName);
|
||||
return m.scriptVersion;
|
||||
}
|
||||
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined {
|
||||
util.log("getScriptSnapshot", fileName);
|
||||
const m = resolveModule(fileName, ".");
|
||||
if (m == null) {
|
||||
util.log("getScriptSnapshot", fileName, "NOT FOUND");
|
||||
return undefined;
|
||||
}
|
||||
//const m = resolveModule(fileName, ".");
|
||||
util.assert(m.sourceCode.length > 0);
|
||||
return ts.ScriptSnapshot.fromString(m.sourceCode);
|
||||
}
|
||||
|
||||
fileExists(fileName: string): boolean {
|
||||
const m = resolveModule(fileName, ".");
|
||||
const exists = m != null;
|
||||
util.log("fileExist", fileName, exists);
|
||||
return exists;
|
||||
}
|
||||
|
||||
readFile(path: string, encoding?: string): string | undefined {
|
||||
util.log("readFile", path);
|
||||
throw Error("not implemented");
|
||||
}
|
||||
|
||||
getNewLine() {
|
||||
return EOL;
|
||||
}
|
||||
|
||||
getCurrentDirectory() {
|
||||
util.log("getCurrentDirectory");
|
||||
return ".";
|
||||
}
|
||||
|
||||
getCompilationSettings() {
|
||||
util.log("getCompilationSettings");
|
||||
return this.options;
|
||||
}
|
||||
|
||||
getDefaultLibFileName(options: ts.CompilerOptions): string {
|
||||
const fn = ts.getDefaultLibFileName(options);
|
||||
util.log("getDefaultLibFileName", fn);
|
||||
const m = resolveModule(fn, "/$asset$/");
|
||||
return m.fileName;
|
||||
}
|
||||
|
||||
resolveModuleNames(
|
||||
moduleNames: string[],
|
||||
containingFile: string,
|
||||
reusedNames?: string[]
|
||||
): Array<ts.ResolvedModule | undefined> {
|
||||
//util.log("resolveModuleNames", { moduleNames, reusedNames });
|
||||
return moduleNames.map((name: string) => {
|
||||
let resolvedFileName;
|
||||
if (name === "deno") {
|
||||
resolvedFileName = resolveModuleName("deno.d.ts", "/$asset$/");
|
||||
} else if (name === "typescript") {
|
||||
resolvedFileName = resolveModuleName("typescript.d.ts", "/$asset$/");
|
||||
} else {
|
||||
resolvedFileName = resolveModuleName(name, containingFile);
|
||||
if (resolvedFileName == null) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
const isExternalLibraryImport = false;
|
||||
return { resolvedFileName, isExternalLibraryImport };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const formatDiagnosticsHost: ts.FormatDiagnosticsHost = {
|
||||
getCurrentDirectory(): string {
|
||||
return ".";
|
||||
},
|
||||
getCanonicalFileName(fileName: string): string {
|
||||
return fileName;
|
||||
},
|
||||
getNewLine(): string {
|
||||
return EOL;
|
||||
}
|
||||
};
|
126
js/tests.ts
Normal file
126
js/tests.ts
Normal file
|
@ -0,0 +1,126 @@
|
|||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
// This test is executed as part of integration_test.go
|
||||
// But it can also be run manually:
|
||||
// ./deno tests.ts
|
||||
// There must also be a static file http server running on localhost:4545
|
||||
// serving the deno project directory. Try this:
|
||||
// http-server -p 4545 --cors .
|
||||
import { test, assert, assertEqual } from "./testing/testing.ts";
|
||||
import { readFileSync, writeFileSync } from "deno";
|
||||
|
||||
test(async function tests_test() {
|
||||
assert(true);
|
||||
});
|
||||
|
||||
test(async function tests_fetch() {
|
||||
const response = await fetch("http://localhost:4545/package.json");
|
||||
const json = await response.json();
|
||||
assertEqual(json.name, "deno");
|
||||
});
|
||||
|
||||
test(function tests_console_assert() {
|
||||
console.assert(true);
|
||||
|
||||
let hasThrown = false;
|
||||
try {
|
||||
console.assert(false);
|
||||
} catch {
|
||||
hasThrown = true;
|
||||
}
|
||||
assertEqual(hasThrown, true);
|
||||
});
|
||||
|
||||
test(async function tests_readFileSync() {
|
||||
const data = readFileSync("package.json");
|
||||
if (!data.byteLength) {
|
||||
throw Error(
|
||||
`Expected positive value for data.byteLength ${data.byteLength}`
|
||||
);
|
||||
}
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
const json = decoder.decode(data);
|
||||
const pkg = JSON.parse(json);
|
||||
assertEqual(pkg.name, "deno");
|
||||
});
|
||||
|
||||
test(async function tests_writeFileSync() {
|
||||
const enc = new TextEncoder();
|
||||
const data = enc.encode("Hello");
|
||||
// TODO need ability to get tmp dir.
|
||||
// const fn = "/tmp/test.txt";
|
||||
writeFileSync("/tmp/test.txt", data, 0o666);
|
||||
const dataRead = readFileSync("/tmp/test.txt");
|
||||
const dec = new TextDecoder("utf-8");
|
||||
const actual = dec.decode(dataRead);
|
||||
assertEqual("Hello", actual);
|
||||
});
|
||||
|
||||
test(function tests_console_assert() {
|
||||
console.assert(true);
|
||||
|
||||
let hasThrown = false;
|
||||
try {
|
||||
console.assert(false);
|
||||
} catch {
|
||||
hasThrown = true;
|
||||
}
|
||||
assertEqual(hasThrown, true);
|
||||
});
|
||||
|
||||
test(function tests_console_stringify_circular() {
|
||||
class Base {
|
||||
a = 1;
|
||||
m1() {}
|
||||
}
|
||||
|
||||
class Extended extends Base {
|
||||
b = 2;
|
||||
m2() {}
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
const nestedObj: any = {
|
||||
num: 1,
|
||||
bool: true,
|
||||
str: "a",
|
||||
method() {},
|
||||
un: undefined,
|
||||
nu: null,
|
||||
arrowFunc: () => {},
|
||||
extendedClass: new Extended(),
|
||||
nFunc: new Function(),
|
||||
extendedCstr: Extended
|
||||
};
|
||||
|
||||
const circularObj = {
|
||||
num: 2,
|
||||
bool: false,
|
||||
str: "b",
|
||||
method() {},
|
||||
un: undefined,
|
||||
nu: null,
|
||||
nested: nestedObj,
|
||||
emptyObj: {},
|
||||
arr: [1, "s", false, null, nestedObj],
|
||||
baseClass: new Base()
|
||||
};
|
||||
|
||||
nestedObj.o = circularObj;
|
||||
|
||||
try {
|
||||
console.log(1);
|
||||
console.log("s");
|
||||
console.log(false);
|
||||
console.log(Symbol(1));
|
||||
console.log(null);
|
||||
console.log(undefined);
|
||||
console.log(new Extended());
|
||||
console.log(function f() {});
|
||||
console.log(nestedObj);
|
||||
console.log(JSON);
|
||||
console.log(console);
|
||||
} catch {
|
||||
throw new Error("Expected no crash on circular object");
|
||||
}
|
||||
});
|
6
js/text-encoding.d.ts
vendored
Normal file
6
js/text-encoding.d.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Remove and depend on @types/text-encoding once this PR is merged
|
||||
// https://github.com/DefinitelyTyped/DefinitelyTyped/pull/26141
|
||||
declare module "text-encoding" {
|
||||
export const TextEncoder: TextEncoder;
|
||||
export const TextDecoder: TextDecoder;
|
||||
}
|
89
js/timers.ts
Normal file
89
js/timers.ts
Normal file
|
@ -0,0 +1,89 @@
|
|||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
import { deno as pb } from "./msg.pb";
|
||||
import { pubInternal, sub } from "./dispatch";
|
||||
import { assert } from "./util";
|
||||
|
||||
let nextTimerId = 1;
|
||||
|
||||
// tslint:disable-next-line:no-any
|
||||
export type TimerCallback = (...args: any[]) => void;
|
||||
|
||||
interface Timer {
|
||||
id: number;
|
||||
cb: TimerCallback;
|
||||
interval: boolean;
|
||||
// tslint:disable-next-line:no-any
|
||||
args: any[];
|
||||
delay: number; // milliseconds
|
||||
}
|
||||
|
||||
const timers = new Map<number, Timer>();
|
||||
|
||||
export function initTimers() {
|
||||
sub("timers", onMessage);
|
||||
}
|
||||
|
||||
function onMessage(payload: Uint8Array) {
|
||||
const msg = pb.Msg.decode(payload);
|
||||
assert(msg.command === pb.Msg.Command.TIMER_READY);
|
||||
const { timerReadyId, timerReadyDone } = msg;
|
||||
const timer = timers.get(timerReadyId);
|
||||
if (!timer) {
|
||||
return;
|
||||
}
|
||||
timer.cb(...timer.args);
|
||||
if (timerReadyDone) {
|
||||
timers.delete(timerReadyId);
|
||||
}
|
||||
}
|
||||
|
||||
function setTimer(
|
||||
cb: TimerCallback,
|
||||
delay: number,
|
||||
interval: boolean,
|
||||
// tslint:disable-next-line:no-any
|
||||
args: any[]
|
||||
): number {
|
||||
const timer = {
|
||||
id: nextTimerId++,
|
||||
interval,
|
||||
delay,
|
||||
args,
|
||||
cb
|
||||
};
|
||||
timers.set(timer.id, timer);
|
||||
pubInternal("timers", {
|
||||
command: pb.Msg.Command.TIMER_START,
|
||||
timerStartId: timer.id,
|
||||
timerStartInterval: timer.interval,
|
||||
timerStartDelay: timer.delay
|
||||
});
|
||||
return timer.id;
|
||||
}
|
||||
|
||||
export function setTimeout(
|
||||
cb: TimerCallback,
|
||||
delay: number,
|
||||
// tslint:disable-next-line:no-any
|
||||
...args: any[]
|
||||
): number {
|
||||
return setTimer(cb, delay, false, args);
|
||||
}
|
||||
|
||||
export function setInterval(
|
||||
cb: TimerCallback,
|
||||
delay: number,
|
||||
// tslint:disable-next-line:no-any
|
||||
...args: any[]
|
||||
): number {
|
||||
return setTimer(cb, delay, true, args);
|
||||
}
|
||||
|
||||
export function clearTimer(id: number) {
|
||||
timers.delete(id);
|
||||
pubInternal("timers", {
|
||||
command: pb.Msg.Command.TIMER_CLEAR,
|
||||
timerClearId: id
|
||||
});
|
||||
}
|
10
js/types.ts
Normal file
10
js/types.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
export type TypedArray = Uint8Array | Float32Array | Int32Array;
|
||||
|
||||
export interface ModuleInfo {
|
||||
moduleName?: string;
|
||||
filename?: string;
|
||||
sourceCode?: string;
|
||||
outputCode?: string;
|
||||
}
|
53
js/util.ts
Normal file
53
js/util.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
import { debug } from "./main";
|
||||
import { TypedArray } from "./types";
|
||||
|
||||
// Internal logging for deno. Use the "debug" variable above to control
|
||||
// output.
|
||||
// tslint:disable-next-line:no-any
|
||||
export function log(...args: any[]): void {
|
||||
if (debug) {
|
||||
console.log(...args);
|
||||
}
|
||||
}
|
||||
|
||||
export function assert(cond: boolean, msg = "") {
|
||||
if (!cond) {
|
||||
throw Error(`Assert fail. ${msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function typedArrayToArrayBuffer(ta: TypedArray): ArrayBuffer {
|
||||
const ab = ta.buffer.slice(ta.byteOffset, ta.byteOffset + ta.byteLength);
|
||||
return ab as ArrayBuffer;
|
||||
}
|
||||
|
||||
export function arrayToStr(ui8: Uint8Array): string {
|
||||
return String.fromCharCode(...ui8);
|
||||
}
|
||||
|
||||
// A `Resolvable` is a Promise with the `reject` and `resolve` functions
|
||||
// placed as methods on the promise object itself. It allows you to do:
|
||||
//
|
||||
// const p = createResolvable<number>();
|
||||
// ...
|
||||
// p.resolve(42);
|
||||
//
|
||||
// It'd be prettier to make Resolvable a class that inherits from Promise,
|
||||
// rather than an interface. This is possible in ES2016, however typescript
|
||||
// produces broken code when targeting ES5 code.
|
||||
// See https://github.com/Microsoft/TypeScript/issues/15202
|
||||
// At the time of writing, the github issue is closed but the problem remains.
|
||||
export interface Resolvable<T> extends Promise<T> {
|
||||
resolve: (value?: T | PromiseLike<T>) => void;
|
||||
// tslint:disable-next-line:no-any
|
||||
reject: (reason?: any) => void;
|
||||
}
|
||||
export function createResolvable<T>(): Resolvable<T> {
|
||||
let methods;
|
||||
const promise = new Promise<T>((resolve, reject) => {
|
||||
methods = { resolve, reject };
|
||||
});
|
||||
return Object.assign(promise, methods) as Resolvable<T>;
|
||||
}
|
273
js/v8_source_maps.ts
Normal file
273
js/v8_source_maps.ts
Normal file
|
@ -0,0 +1,273 @@
|
|||
// Copyright 2014 Evan Wallace
|
||||
// Copyright 2018 Ryan Dahl <ry@tinyclouds.org>
|
||||
// All rights reserved. MIT License.
|
||||
// Originated from source-map-support but has been heavily modified for deno.
|
||||
import { SourceMapConsumer, MappedPosition } from "source-map";
|
||||
import * as base64 from "base64-js";
|
||||
import { arrayToStr } from "./util";
|
||||
|
||||
const consumers = new Map<string, SourceMapConsumer>();
|
||||
|
||||
interface Options {
|
||||
// A callback the returns generated file contents.
|
||||
getGeneratedContents: GetGeneratedContentsCallback;
|
||||
// Usually set the following to true. Set to false for testing.
|
||||
installPrepareStackTrace: boolean;
|
||||
}
|
||||
|
||||
interface CallSite extends NodeJS.CallSite {
|
||||
getScriptNameOrSourceURL(): string;
|
||||
}
|
||||
|
||||
interface Position {
|
||||
source: string; // Filename
|
||||
column: number;
|
||||
line: number;
|
||||
}
|
||||
|
||||
type GetGeneratedContentsCallback = (fileName: string) => string;
|
||||
|
||||
let getGeneratedContents: GetGeneratedContentsCallback;
|
||||
|
||||
export function install(options: Options) {
|
||||
getGeneratedContents = options.getGeneratedContents;
|
||||
if (options.installPrepareStackTrace) {
|
||||
Error.prepareStackTrace = prepareStackTraceWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
export function prepareStackTraceWrapper(
|
||||
error: Error,
|
||||
stack: CallSite[]
|
||||
): string {
|
||||
try {
|
||||
return prepareStackTrace(error, stack);
|
||||
} catch (prepareStackError) {
|
||||
Error.prepareStackTrace = null;
|
||||
console.log("=====Error inside of prepareStackTrace====");
|
||||
console.log(prepareStackError.stack.toString());
|
||||
console.log("=====Original error=======================");
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export function prepareStackTrace(error: Error, stack: CallSite[]): string {
|
||||
const frames = stack.map(
|
||||
(frame: CallSite) => `\n at ${wrapCallSite(frame).toString()}`
|
||||
);
|
||||
return error.toString() + frames.join("");
|
||||
}
|
||||
|
||||
export function wrapCallSite(frame: CallSite): CallSite {
|
||||
if (frame.isNative()) {
|
||||
return frame;
|
||||
}
|
||||
|
||||
// Most call sites will return the source file from getFileName(), but code
|
||||
// passed to eval() ending in "//# sourceURL=..." will return the source file
|
||||
// from getScriptNameOrSourceURL() instead
|
||||
const source = frame.getFileName() || frame.getScriptNameOrSourceURL();
|
||||
|
||||
if (source) {
|
||||
const line = frame.getLineNumber();
|
||||
const column = frame.getColumnNumber() - 1;
|
||||
const position = mapSourcePosition({ source, line, column });
|
||||
frame = cloneCallSite(frame);
|
||||
frame.getFileName = () => position.source;
|
||||
frame.getLineNumber = () => position.line;
|
||||
frame.getColumnNumber = () => Number(position.column) + 1;
|
||||
frame.getScriptNameOrSourceURL = () => position.source;
|
||||
frame.toString = () => CallSiteToString(frame);
|
||||
return frame;
|
||||
}
|
||||
|
||||
// Code called using eval() needs special handling
|
||||
let origin = frame.isEval() && frame.getEvalOrigin();
|
||||
if (origin) {
|
||||
origin = mapEvalOrigin(origin);
|
||||
frame = cloneCallSite(frame);
|
||||
frame.getEvalOrigin = () => origin;
|
||||
return frame;
|
||||
}
|
||||
|
||||
// If we get here then we were unable to change the source position
|
||||
return frame;
|
||||
}
|
||||
|
||||
function cloneCallSite(frame: CallSite): CallSite {
|
||||
// tslint:disable:no-any
|
||||
const obj: any = {};
|
||||
const frame_ = frame as any;
|
||||
const props = Object.getOwnPropertyNames(Object.getPrototypeOf(frame));
|
||||
props.forEach(name => {
|
||||
obj[name] = /^(?:is|get)/.test(name)
|
||||
? () => frame_[name].call(frame)
|
||||
: frame_[name];
|
||||
});
|
||||
return (obj as any) as CallSite;
|
||||
// tslint:enable:no-any
|
||||
}
|
||||
|
||||
// Taken from source-map-support, original copied from V8's messages.js
|
||||
// MIT License. Copyright (c) 2014 Evan Wallace
|
||||
function CallSiteToString(frame: CallSite): string {
|
||||
let fileName;
|
||||
let fileLocation = "";
|
||||
if (frame.isNative()) {
|
||||
fileLocation = "native";
|
||||
} else {
|
||||
fileName = frame.getScriptNameOrSourceURL();
|
||||
if (!fileName && frame.isEval()) {
|
||||
fileLocation = frame.getEvalOrigin();
|
||||
fileLocation += ", "; // Expecting source position to follow.
|
||||
}
|
||||
|
||||
if (fileName) {
|
||||
fileLocation += fileName;
|
||||
} else {
|
||||
// Source code does not originate from a file and is not native, but we
|
||||
// can still get the source position inside the source string, e.g. in
|
||||
// an eval string.
|
||||
fileLocation += "<anonymous>";
|
||||
}
|
||||
const lineNumber = frame.getLineNumber();
|
||||
if (lineNumber != null) {
|
||||
fileLocation += ":" + String(lineNumber);
|
||||
const columnNumber = frame.getColumnNumber();
|
||||
if (columnNumber) {
|
||||
fileLocation += ":" + String(columnNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let line = "";
|
||||
const functionName = frame.getFunctionName();
|
||||
let addSuffix = true;
|
||||
const isConstructor = frame.isConstructor();
|
||||
const isMethodCall = !(frame.isToplevel() || isConstructor);
|
||||
if (isMethodCall) {
|
||||
let typeName = frame.getTypeName();
|
||||
// Fixes shim to be backward compatable with Node v0 to v4
|
||||
if (typeName === "[object Object]") {
|
||||
typeName = "null";
|
||||
}
|
||||
const methodName = frame.getMethodName();
|
||||
if (functionName) {
|
||||
if (typeName && functionName.indexOf(typeName) !== 0) {
|
||||
line += typeName + ".";
|
||||
}
|
||||
line += functionName;
|
||||
if (
|
||||
methodName &&
|
||||
functionName.indexOf("." + methodName) !==
|
||||
functionName.length - methodName.length - 1
|
||||
) {
|
||||
line += ` [as ${methodName} ]`;
|
||||
}
|
||||
} else {
|
||||
line += typeName + "." + (methodName || "<anonymous>");
|
||||
}
|
||||
} else if (isConstructor) {
|
||||
line += "new " + (functionName || "<anonymous>");
|
||||
} else if (functionName) {
|
||||
line += functionName;
|
||||
} else {
|
||||
line += fileLocation;
|
||||
addSuffix = false;
|
||||
}
|
||||
if (addSuffix) {
|
||||
line += ` (${fileLocation})`;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
// Regex for detecting source maps
|
||||
const reSourceMap = /^data:application\/json[^,]+base64,/;
|
||||
|
||||
function loadConsumer(source: string): SourceMapConsumer {
|
||||
let consumer = consumers.get(source);
|
||||
if (consumer == null) {
|
||||
const code = getGeneratedContents(source);
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let sourceMappingURL = retrieveSourceMapURL(code);
|
||||
if (!sourceMappingURL) {
|
||||
throw Error("No source map?");
|
||||
}
|
||||
|
||||
let sourceMapData: string;
|
||||
if (reSourceMap.test(sourceMappingURL)) {
|
||||
// Support source map URL as a data url
|
||||
const rawData = sourceMappingURL.slice(sourceMappingURL.indexOf(",") + 1);
|
||||
const ui8 = base64.toByteArray(rawData);
|
||||
sourceMapData = arrayToStr(ui8);
|
||||
sourceMappingURL = source;
|
||||
} else {
|
||||
// Support source map URLs relative to the source URL
|
||||
//sourceMappingURL = supportRelativeURL(source, sourceMappingURL);
|
||||
sourceMapData = getGeneratedContents(sourceMappingURL);
|
||||
}
|
||||
|
||||
//console.log("sourceMapData", sourceMapData);
|
||||
const rawSourceMap = JSON.parse(sourceMapData);
|
||||
consumer = new SourceMapConsumer(rawSourceMap);
|
||||
consumers.set(source, consumer);
|
||||
}
|
||||
return consumer;
|
||||
}
|
||||
|
||||
function retrieveSourceMapURL(fileData: string): string {
|
||||
// Get the URL of the source map
|
||||
// tslint:disable-next-line:max-line-length
|
||||
const re = /(?:\/\/[@#][ \t]+sourceMappingURL=([^\s'"]+?)[ \t]*$)|(?:\/\*[@#][ \t]+sourceMappingURL=([^\*]+?)[ \t]*(?:\*\/)[ \t]*$)/gm;
|
||||
// Keep executing the search to find the *last* sourceMappingURL to avoid
|
||||
// picking up sourceMappingURLs from comments, strings, etc.
|
||||
let lastMatch, match;
|
||||
while ((match = re.exec(fileData))) {
|
||||
lastMatch = match;
|
||||
}
|
||||
if (!lastMatch) {
|
||||
return null;
|
||||
}
|
||||
return lastMatch[1];
|
||||
}
|
||||
|
||||
function mapSourcePosition(position: Position): MappedPosition {
|
||||
const consumer = loadConsumer(position.source);
|
||||
if (consumer == null) {
|
||||
return position;
|
||||
}
|
||||
const mapped = consumer.originalPositionFor(position);
|
||||
return mapped;
|
||||
}
|
||||
|
||||
// Parses code generated by FormatEvalOrigin(), a function inside V8:
|
||||
// https://code.google.com/p/v8/source/browse/trunk/src/messages.js
|
||||
function mapEvalOrigin(origin: string): string {
|
||||
// Most eval() calls are in this format
|
||||
let match = /^eval at ([^(]+) \((.+):(\d+):(\d+)\)$/.exec(origin);
|
||||
if (match) {
|
||||
const position = mapSourcePosition({
|
||||
source: match[2],
|
||||
line: Number(match[3]),
|
||||
column: Number(match[4]) - 1
|
||||
});
|
||||
const pos = [
|
||||
position.source,
|
||||
position.line,
|
||||
Number(position.column) + 1
|
||||
].join(":");
|
||||
return `eval at ${match[1]} (${pos})`;
|
||||
}
|
||||
|
||||
// Parse nested eval() calls using recursion
|
||||
match = /^eval at ([^(]+) \((.+)\)$/.exec(origin);
|
||||
if (match) {
|
||||
return `eval at ${match[1]} (${mapEvalOrigin(match[2])})`;
|
||||
}
|
||||
|
||||
// Make sure we still return useful information if we didn't find anything
|
||||
return origin;
|
||||
}
|
|
@ -13,6 +13,6 @@
|
|||
"allowUnreachableCode": false,
|
||||
"experimentalDecorators": true
|
||||
},
|
||||
"include": ["js/**/*.ts", "js/**/*.js"],
|
||||
"exclude": ["js/mock_runtime.js", "js/node_modules"]
|
||||
"include": [ "js/main.ts" ],
|
||||
"exclude": [ "node_modules" ]
|
||||
}
|
||||
|
|
97
tslint.json
97
tslint.json
|
@ -1,77 +1,59 @@
|
|||
{
|
||||
"extends": [
|
||||
"tslint-eslint-rules", "tslint-no-circular-imports"
|
||||
],
|
||||
"rules": {
|
||||
"align": [
|
||||
true,
|
||||
// TODO "arguments",
|
||||
// TODO "elements",
|
||||
"members",
|
||||
"parameters",
|
||||
"statements"
|
||||
],
|
||||
"array-bracket-spacing": [true, "never"],
|
||||
"array-type": [true, "array-simple"],
|
||||
"arrow-return-shorthand": true,
|
||||
"ban": [true,
|
||||
{"name": "parseInt", "message": "tsstyle#type-coercion"},
|
||||
{"name": "parseFloat", "message": "tsstyle#type-coercion"},
|
||||
{"name": "Array", "message": "tsstyle#array-constructor"}
|
||||
"ban": [
|
||||
true,
|
||||
["fit"],
|
||||
["fdescribe"],
|
||||
["xit"],
|
||||
["xdescribe"],
|
||||
["fitAsync"],
|
||||
["xitAsync"],
|
||||
["fitFakeAsync"],
|
||||
["xitFakeAsync"]
|
||||
],
|
||||
"ban-types": [true,
|
||||
"ban-types": [
|
||||
true,
|
||||
["Object", "Use {} instead."],
|
||||
["String", "Use 'string' instead."],
|
||||
["Number", "Use 'number' instead."],
|
||||
["Boolean", "Use 'boolean' instead."]
|
||||
],
|
||||
"brace-style": [true, "1tbs", { "allowSingleLine": true }],
|
||||
"block-spacing": [true, "always"],
|
||||
"class-name": true,
|
||||
"comment-format": [true, "check-space"],
|
||||
"curly": [true, "ignore-same-line"],
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"ter-func-call-spacing": true,
|
||||
"indent": [true, "spaces", 2],
|
||||
"curly": true,
|
||||
"interface-name": [true, "never-prefix"],
|
||||
"jsdoc-format": true,
|
||||
"forin": false,
|
||||
"label-position": true,
|
||||
"linebreak-style": [true, "LF"],
|
||||
"max-line-length": { "options": [80] },
|
||||
"member-access": [true, "no-public"],
|
||||
"max-line-length": [true, 80],
|
||||
"new-parens": true,
|
||||
"no-angle-bracket-type-assertion": true,
|
||||
//"no-any": true,
|
||||
"no-arg": true,
|
||||
"no-conditional-assignment": true,
|
||||
"no-consecutive-blank-lines": true,
|
||||
"no-any": true,
|
||||
"no-construct": true,
|
||||
"no-consecutive-blank-lines": true,
|
||||
"no-debugger": true,
|
||||
"no-default-export": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-inferrable-types": true,
|
||||
"no-irregular-whitespace": true,
|
||||
"no-namespace": [true, "allow-declarations"],
|
||||
"no-multi-spaces": true,
|
||||
//"no-namespace": [true, "allow-declarations"],
|
||||
"no-reference": true,
|
||||
"no-require-imports": true,
|
||||
"no-string-throw": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unused-expression": true,
|
||||
"no-unused-variable": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-shorthand": true,
|
||||
"object-literal-sort-keys": [true, "match-declaration-order"],
|
||||
"one-line": [true, "check-catch", "check-finally", "check-else"],
|
||||
//"only-arrow-functions": [true, "allow-declarations", "allow-named-functions"],
|
||||
"ordered-imports": true,
|
||||
"quotemark": [true, "double"],
|
||||
"only-arrow-functions": [
|
||||
true,
|
||||
"allow-declarations",
|
||||
"allow-named-functions"
|
||||
],
|
||||
"prefer-const": true,
|
||||
"quotemark": [true, "double"],
|
||||
"radix": true,
|
||||
// https://github.com/buzinas/tslint-eslint-rules/issues/318
|
||||
// "space-before-blocks": true,
|
||||
"space-before-function-paren": false,
|
||||
"restrict-plus-operands": true,
|
||||
"semicolon": [true, "always", "ignore-bound-class-methods"],
|
||||
//"switch-default": true,
|
||||
"switch-default": true,
|
||||
"triple-equals": [true, "allow-null-check"],
|
||||
"use-isnan": true,
|
||||
"variable-name": [
|
||||
|
@ -80,29 +62,6 @@
|
|||
"ban-keywords",
|
||||
"allow-leading-underscore",
|
||||
"allow-trailing-underscore"
|
||||
],
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-module",
|
||||
"check-separator",
|
||||
"check-rest-spread",
|
||||
"check-type",
|
||||
"check-typecast",
|
||||
"check-type-operator",
|
||||
"check-preblock"
|
||||
]
|
||||
},
|
||||
"jsRules": {
|
||||
"max-line-length": { "options": [80] },
|
||||
"linebreak-style": [true, "LF"],
|
||||
"indent": [true, "spaces", 2]
|
||||
},
|
||||
"linterOptions": {
|
||||
"exclude": [
|
||||
"js/msg.pb.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue