1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-25 16:49:18 -05:00

Ensure global type instances are available.

This commit is contained in:
Kitson Kelly 2018-11-09 11:09:18 +11:00 committed by Ryan Dahl
parent 172f5a5133
commit 34b6b86c76
12 changed files with 113 additions and 38 deletions

View file

@ -6,11 +6,12 @@ import { assetSourceCode } from "./assets";
import * as deno from "./deno"; import * as deno from "./deno";
import { globalEval } from "./global_eval"; import { globalEval } from "./global_eval";
import { libdeno } from "./libdeno"; import { libdeno } from "./libdeno";
import { window } from "./globals";
import * as os from "./os"; import * as os from "./os";
import { RawSourceMap } from "./types"; import { RawSourceMap } from "./types";
import { assert, log, notImplemented } from "./util"; import { assert, log, notImplemented } from "./util";
const window = globalEval("this");
const EOL = "\n"; const EOL = "\n";
const ASSETS = "$asset$"; const ASSETS = "$asset$";
const LIB_RUNTIME = "lib.deno_runtime.d.ts"; const LIB_RUNTIME = "lib.deno_runtime.d.ts";

View file

@ -1,23 +1,33 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license. // Copyright 2018 the Deno authors. All rights reserved. MIT license.
// This is a "special" module, in that it define the global runtime scope of
// Deno, and therefore it defines a lot of the runtime environemnt that code
// is evaluated in. We use this file to automatically build the runtime type
// library.
// Modules which will make up part of the global public API surface should be
// imported as namespaces, so when the runtime tpye library is generated they
// can be expressed as a namespace in the type library.
import * as blob from "./blob"; import * as blob from "./blob";
import * as consoleTypes from "./console";
import * as domTypes from "./dom_types";
import * as file from "./file"; import * as file from "./file";
import * as formdata from "./form_data"; import * as formData from "./form_data";
import * as console_ from "./console"; import * as fetchTypes from "./fetch";
import * as fetch_ from "./fetch"; import * as headers from "./headers";
import { Headers } from "./headers";
import { globalEval } from "./global_eval";
import { libdeno } from "./libdeno";
import * as textEncoding from "./text_encoding"; import * as textEncoding from "./text_encoding";
import * as timers from "./timers"; import * as timers from "./timers";
import * as urlSearchParams from "./url_search_params"; import * as urlSearchParams from "./url_search_params";
import * as domTypes from "./dom_types";
// These imports are not exposed and therefore are fine to just import the
// symbols required.
import { globalEval } from "./global_eval";
import { libdeno } from "./libdeno";
// During the build process, augmentations to the variable `window` in this // During the build process, augmentations to the variable `window` in this
// file are tracked and created as part of default library that is built into // file are tracked and created as part of default library that is built into
// deno, we only need to declare the enough to compile deno. // Deno, we only need to declare the enough to compile Deno.
declare global { declare global {
const console: console_.Console; const console: consoleTypes.Console;
const setTimeout: typeof timers.setTimeout; const setTimeout: typeof timers.setTimeout;
// tslint:disable-next-line:variable-name // tslint:disable-next-line:variable-name
const TextEncoder: typeof textEncoding.TextEncoder; const TextEncoder: typeof textEncoding.TextEncoder;
@ -25,26 +35,41 @@ declare global {
// A reference to the global object. // A reference to the global object.
export const window = globalEval("this"); export const window = globalEval("this");
// A self reference to the global object.
window.window = window; window.window = window;
window.setTimeout = timers.setTimeout; // Globally available functions and object instances.
window.setInterval = timers.setInterval;
window.clearTimeout = timers.clearTimer;
window.clearInterval = timers.clearTimer;
window.console = new console_.Console(libdeno.print);
window.TextEncoder = textEncoding.TextEncoder;
window.TextDecoder = textEncoding.TextDecoder;
window.atob = textEncoding.atob; window.atob = textEncoding.atob;
window.btoa = textEncoding.btoa; window.btoa = textEncoding.btoa;
window.fetch = fetchTypes.fetch;
window.clearTimeout = timers.clearTimer;
window.clearInterval = timers.clearTimer;
window.console = new consoleTypes.Console(libdeno.print);
window.setTimeout = timers.setTimeout;
window.setInterval = timers.setInterval;
window.URLSearchParams = urlSearchParams.URLSearchParams; // When creating the runtime type library, we use modifications to `window` to
// determine what is in the global namespace. When we put a class in the
window.fetch = fetch_.fetch; // namespace, we also need its global instance type as well, otherwise users
// won't be able to refer to instances.
// using the `as` keyword to mask the internal types when generating the // We have to export the type aliases, so that TypeScript _knows_ they are
// runtime library // being used, which it cannot statically determine within this module.
window.Headers = Headers as domTypes.HeadersConstructor;
window.Blob = blob.DenoBlob; window.Blob = blob.DenoBlob;
export type Blob = blob.DenoBlob;
window.File = file.DenoFile; window.File = file.DenoFile;
window.FormData = formdata.FormData as domTypes.FormDataConstructor; export type File = file.DenoFile;
window.URLSearchParams = urlSearchParams.URLSearchParams;
export type URLSearchParams = urlSearchParams.URLSearchParams;
// Using the `as` keyword to use standard compliant interfaces as the Deno
// implementations contain some implementation details we wouldn't want to
// expose in the runtime type library.
window.Headers = headers.Headers as domTypes.HeadersConstructor;
export type Headers = domTypes.Headers;
window.FormData = formData.FormData as domTypes.FormDataConstructor;
export type FormData = domTypes.FormData;
// While these are classes, they have their global instance types created in
// other type definitions, therefore we do not have to include them here.
window.TextEncoder = textEncoding.TextEncoder;
window.TextDecoder = textEncoding.TextDecoder;

View file

@ -169,3 +169,11 @@ test(function headerSymbolIteratorSuccess() {
assertEqual(value, headers.get(key)); assertEqual(value, headers.get(key));
} }
}); });
test(function headerTypesAvailable() {
function newHeaders(): Headers {
return new Headers();
}
const headers = newHeaders();
assert(headers instanceof Headers);
});

View file

@ -1,4 +1,7 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license. // Copyright 2018 the Deno authors. All rights reserved. MIT license.
// We need to make sure this module loads, for its side effects.
import "./globals";
import * as flatbuffers from "./flatbuffers"; import * as flatbuffers from "./flatbuffers";
import * as msg from "gen/msg_generated"; import * as msg from "gen/msg_generated";
import { assert, log, setLogDebug } from "./util"; import { assert, log, setLogDebug } from "./util";

View file

@ -6,7 +6,9 @@ import * as deno from "./deno";
import { close } from "./files"; import { close } from "./files";
import * as dispatch from "./dispatch"; import * as dispatch from "./dispatch";
import { exit } from "./os"; import { exit } from "./os";
import { window } from "./globals"; import { globalEval } from "./global_eval";
const window = globalEval("this");
function startRepl(historyFile: string): number { function startRepl(historyFile: string): number {
const builder = flatbuffers.createBuilder(); const builder = flatbuffers.createBuilder();

View file

@ -4,7 +4,7 @@
[WILDCARD]~~~~~~ [WILDCARD]~~~~~~
$asset$/lib.deno_runtime.d.tsILDCARD] $asset$/lib.deno_runtime.d.tsILDCARD]
[WILDCARD]declare const console: console_.Console; [WILDCARD]declare const console: consoleTypes.Console;
[WILDCARD]~~~~~~~ [WILDCARD]~~~~~~~
[WILDCARD]'console' is declared here. [WILDCARD]'console' is declared here.

View file

@ -4,7 +4,7 @@
[WILDCARD]~~~~~~ [WILDCARD]~~~~~~
$asset$/lib.deno_runtime.d.tsILDCARD] $asset$/lib.deno_runtime.d.tsILDCARD]
[WILDCARD]declare const console: console_.Console; [WILDCARD]declare const console: consoleTypes.Console;
[WILDCARD]~~~~~~~ [WILDCARD]~~~~~~~
[WILDCARD]'console' is declared here. [WILDCARD]'console' is declared here.

View file

@ -72,17 +72,16 @@ like this:
- This process assumes that all the modules that feed `js/deno.ts` will have a - This process assumes that all the modules that feed `js/deno.ts` will have a
public type API that does not have name conflicts. public type API that does not have name conflicts.
- We process the `js/globals.ts` file to generate the global namespace. - We process the `js/globals.ts` file to generate the global namespace.
- Currently we create a `"globals"` module which will contain the type
definitions.
- We create a `Window` interface and a `global` scope augmentation namespace. - We create a `Window` interface and a `global` scope augmentation namespace.
- We iterate over augmentations to the `window` variable declared in the file, - We iterate over augmentations to the `window` variable declared in the file,
extract the type information and apply it to both a global variable extract the type information and apply it to both a global variable
declaration and a property on the `Window` interface. declaration and a property on the `Window` interface.
- We identify any type aliases in the module and declare them globally.
- We take each namespace import to `js/globals.ts`, we resolve the emitted - We take each namespace import to `js/globals.ts`, we resolve the emitted
declaration `.d.ts` file and create it as its own namespace withing the declaration `.d.ts` file and create it as its own namespace within the global
`"globals"` module. It is unsafe to just flatten these, because there is a scope. It is unsafe to just flatten these, because there is a high risk of
high risk of collisions, but also, it makes authoring the types easier within collisions, but also, it makes authoring the types easier within the generated
the generated interface and variable declarations. interface and variable declarations.
- We then validate the resulting definition file and write it out to the - We then validate the resulting definition file and write it out to the
appropriate build path. appropriate build path.

View file

@ -42,6 +42,22 @@ export function addSourceComment(
); );
} }
/** Add a declaration of a type alias to a node */
export function addTypeAlias(
node: StatementedNode,
name: string,
type: string,
hasDeclareKeyword = false,
jsdocs?: JSDoc[]
) {
return node.addTypeAlias({
name,
type,
docs: jsdocs && jsdocs.map(jsdoc => jsdoc.getText()),
hasDeclareKeyword
});
}
/** Add a declaration of a variable to a node */ /** Add a declaration of a variable to a node */
export function addVariableDeclaration( export function addVariableDeclaration(
node: StatementedNode, node: StatementedNode,

View file

@ -21,7 +21,8 @@ import {
loadFiles, loadFiles,
logDiagnostics, logDiagnostics,
namespaceSourceFile, namespaceSourceFile,
normalizeSlashes normalizeSlashes,
addTypeAlias
} from "./ast_util"; } from "./ast_util";
export interface BuildLibraryOptions { export interface BuildLibraryOptions {
@ -216,6 +217,16 @@ export function mergeGlobal({
addInterfaceProperty(interfaceDeclaration, property, type); addInterfaceProperty(interfaceDeclaration, property, type);
} }
// We need to copy over any type aliases
for (const typeAlias of sourceFile.getTypeAliases()) {
addTypeAlias(
targetSourceFile,
typeAlias.getName(),
typeAlias.getType().getText(sourceFile),
true
);
}
// We need to ensure that we only namespace each source file once, so we // We need to ensure that we only namespace each source file once, so we
// will use this map for tracking that. // will use this map for tracking that.
const sourceFileMap = new Map<SourceFile, string>(); const sourceFileMap = new Map<SourceFile, string>();

View file

@ -149,7 +149,15 @@ test(function buildLibraryMerge() {
variableDeclarations[4].getType().getText(), variableDeclarations[4].getType().getText(),
`typeof moduleD.reprocess` `typeof moduleD.reprocess`
); );
assertEqual(variableDeclarations.length, 5); assertEqual(
variableDeclarations[5].getType().getText(),
`typeof moduleC.Bar`
);
assertEqual(variableDeclarations.length, 6);
const typeAliases = targetSourceFile.getTypeAliases();
assertEqual(typeAliases[0].getName(), "Bar");
assertEqual(typeAliases[0].getType().getText(), "moduleC.Bar");
assertEqual(typeAliases.length, 1);
}); });
// TODO author unit tests for `ast_util.ts` // TODO author unit tests for `ast_util.ts`

View file

@ -8,3 +8,5 @@ foobarbaz.bar = new moduleC.Bar();
foobarbaz.qat = moduleC.qat; foobarbaz.qat = moduleC.qat;
foobarbaz.process = moduleE.process; foobarbaz.process = moduleE.process;
foobarbaz.reprocess = moduleD.reprocess; foobarbaz.reprocess = moduleD.reprocess;
foobarbaz.Bar = moduleC.Bar;
export type Bar = moduleC.Bar;