From 64f0dfd50e3eb6db1a0e66aec6b1c01a4ef76cea Mon Sep 17 00:00:00 2001 From: Kitson Kelly Date: Mon, 22 Oct 2018 16:08:14 +1100 Subject: [PATCH] Improve globals for runtime type library --- js/globals.ts | 10 ++-- tests/error_003_typescript.ts.out | 2 +- tools/ts_library_builder/ast_util.ts | 18 +++++-- tools/ts_library_builder/build_library.ts | 65 ++++++++--------------- tools/ts_library_builder/test.ts | 30 ++++------- 5 files changed, 53 insertions(+), 72 deletions(-) diff --git a/js/globals.ts b/js/globals.ts index e65fee9287..401819ac61 100644 --- a/js/globals.ts +++ b/js/globals.ts @@ -1,19 +1,19 @@ // Copyright 2018 the Deno authors. All rights reserved. MIT license. import * as blob from "./blob"; -import * as console from "./console"; +import * as console_ from "./console"; import * as fetch_ from "./fetch"; import { globalEval } from "./global_eval"; import { libdeno } from "./libdeno"; import * as textEncoding from "./text_encoding"; import * as timers from "./timers"; -import * as urlsearchparams from "./url_search_params"; +import * as urlSearchParams from "./url_search_params"; // 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 // deno, we only need to declare the enough to compile deno. declare global { - const console: console.Console; + const console: console_.Console; const setTimeout: typeof timers.setTimeout; // tslint:disable-next-line:variable-name const TextEncoder: typeof textEncoding.TextEncoder; @@ -28,13 +28,13 @@ window.setInterval = timers.setInterval; window.clearTimeout = timers.clearTimer; window.clearInterval = timers.clearTimer; -window.console = new console.Console(libdeno.print); +window.console = new console_.Console(libdeno.print); window.TextEncoder = textEncoding.TextEncoder; window.TextDecoder = textEncoding.TextDecoder; window.atob = textEncoding.atob; window.btoa = textEncoding.btoa; -window.URLSearchParams = urlsearchparams.URLSearchParams; +window.URLSearchParams = urlSearchParams.URLSearchParams; window.fetch = fetch_.fetch; diff --git a/tests/error_003_typescript.ts.out b/tests/error_003_typescript.ts.out index c0e14c3512..e2b5cae05f 100644 --- a/tests/error_003_typescript.ts.out +++ b/tests/error_003_typescript.ts.out @@ -4,7 +4,7 @@ [WILDCARD]~~~~~~ $asset$/lib.deno_runtime.d.tsILDCARD] -[WILDCARD]const console: console.Console; +[WILDCARD]declare const console: console_.Console; [WILDCARD]~~~~~~~ [WILDCARD]'console' is declared here. diff --git a/tools/ts_library_builder/ast_util.ts b/tools/ts_library_builder/ast_util.ts index c13195b08b..4590dcea58 100644 --- a/tools/ts_library_builder/ast_util.ts +++ b/tools/ts_library_builder/ast_util.ts @@ -47,12 +47,14 @@ export function addVariableDeclaration( node: StatementedNode, name: string, type: string, + hasDeclareKeyword?: boolean, jsdocs?: JSDoc[] ): VariableStatement { return node.addVariableStatement({ declarationKind: VariableDeclarationKind.Const, declarations: [{ name, type }], - docs: jsdocs && jsdocs.map(jsdoc => jsdoc.getText()) + docs: jsdocs && jsdocs.map(jsdoc => jsdoc.getText()), + hasDeclareKeyword }); } @@ -281,8 +283,17 @@ export function namespaceSourceFile( } }); + // TODO need to properly unwrap this const globalNamespace = sourceFile.getNamespace("global"); - const globalNamespaceText = globalNamespace && globalNamespace.print(); + let globalNamespaceText = ""; + if (globalNamespace) { + const structure = globalNamespace.getStructure(); + if (structure.bodyText && typeof structure.bodyText === "string") { + globalNamespaceText = structure.bodyText; + } else { + throw new TypeError("Unexpected global declaration structure."); + } + } if (globalNamespace) { globalNamespace.remove(); } @@ -319,7 +330,8 @@ export function namespaceSourceFile( return `${output} ${globalNamespaceText || ""} - namespace ${namespace} { + + declare namespace ${namespace} { ${debug ? getSourceComment(sourceFile, rootPath) : ""} ${sourceFile.getText()} }`; diff --git a/tools/ts_library_builder/build_library.ts b/tools/ts_library_builder/build_library.ts index 9bd4d4ee5b..e4111fe213 100644 --- a/tools/ts_library_builder/build_library.ts +++ b/tools/ts_library_builder/build_library.ts @@ -123,54 +123,36 @@ export function flatten({ namespace.addStatements(statements); } -interface MergeOptions { +interface MergeGlobalOptions { basePath: string; - declarationProject: Project; debug?: boolean; - globalVarName: string; + declarationProject: Project; filePath: string; + globalVarName: string; inputProject: Project; interfaceName: string; - namespaceName: string; targetSourceFile: SourceFile; } -/** Take a module and merge into into a single namespace */ -export function merge({ +/** Take a module and merge it into the global scope */ +export function mergeGlobal({ basePath, - declarationProject, debug, - globalVarName, + declarationProject, filePath, + globalVarName, inputProject, interfaceName, - namespaceName, targetSourceFile -}: MergeOptions) { - // We have to build the module/namespace in small pieces which will reflect - // how the global runtime environment will be for Deno - - // We need to add a module named `"globals"` which will contain all the global - // runtime context - const mergedModule = targetSourceFile.addNamespace({ - name: namespaceName, - hasDeclareKeyword: true, - declarationKind: NamespaceDeclarationKind.Module - }); - - // Add the global Window interface - const interfaceDeclaration = mergedModule.addInterface({ - name: interfaceName - }); - - // Add the global scope augmentation module of the "globals" module - const mergedGlobalNamespace = mergedModule.addNamespace({ - name: "global", - declarationKind: NamespaceDeclarationKind.Global +}: MergeGlobalOptions): void { + // Add the global object interface + const interfaceDeclaration = targetSourceFile.addInterface({ + name: interfaceName, + hasDeclareKeyword: true }); // Declare the global variable - addVariableDeclaration(mergedGlobalNamespace, globalVarName, interfaceName); + addVariableDeclaration(targetSourceFile, globalVarName, interfaceName, true); // Add self reference to the global variable addInterfaceProperty(interfaceDeclaration, globalVarName, interfaceName); @@ -201,9 +183,9 @@ export function merge({ TypeGuards.isPropertyAccessExpression(leftExpression) && leftExpression.getExpression().getText() === globalVarName ) { - const windowProperty = leftExpression.getName(); - if (windowProperty !== globalVarName) { - globalVariables.set(windowProperty, { + const globalVarProperty = leftExpression.getName(); + if (globalVarProperty !== globalVarName) { + globalVariables.set(globalVarProperty, { type: firstChild.getType(), node }); @@ -228,7 +210,7 @@ export function merge({ dependentSourceFiles.add(valueDeclaration.getSourceFile()); } } - addVariableDeclaration(mergedGlobalNamespace, property, type); + addVariableDeclaration(targetSourceFile, property, type, true); addInterfaceProperty(interfaceDeclaration, property, type); } @@ -255,7 +237,7 @@ export function merge({ const dtsSourceFile = declarationProject.getSourceFileOrThrow( dtsFilePath ); - mergedModule.addStatements( + targetSourceFile.addStatements( namespaceSourceFile(dtsSourceFile, { debug, namespace: declaration.getNamespaceImportOrThrow().getText(), @@ -267,7 +249,7 @@ export function merge({ } if (debug) { - addSourceComment(mergedModule, sourceFile, basePath); + addSourceComment(targetSourceFile, sourceFile, basePath); } } @@ -413,20 +395,19 @@ export function main({ console.log(`Created module "deno".`); } - merge({ + mergeGlobal({ basePath, - declarationProject, debug, - globalVarName: "window", + declarationProject, filePath: `${basePath}/js/globals.ts`, + globalVarName: "window", inputProject, interfaceName: "Window", - namespaceName: `"globals"`, targetSourceFile: libDTs }); if (!silent) { - console.log(`Created module "globals".`); + console.log(`Merged "globals" into global scope.`); } // Add the preamble diff --git a/tools/ts_library_builder/test.ts b/tools/ts_library_builder/test.ts index b123cb1c5f..70b6145ebd 100644 --- a/tools/ts_library_builder/test.ts +++ b/tools/ts_library_builder/test.ts @@ -4,7 +4,7 @@ import { Project, ts } from "ts-simple-ast"; import { assert, assertEqual, test } from "../../js/testing/testing"; -import { flatten, merge } from "./build_library"; +import { flatten, mergeGlobal } from "./build_library"; import { loadDtsFiles } from "./ast_util"; const { ModuleKind, ModuleResolutionKind, ScriptTarget } = ts; @@ -116,7 +116,7 @@ test(function buildLibraryMerge() { outputSourceFile: targetSourceFile } = setupFixtures(); - merge({ + mergeGlobal({ basePath, declarationProject, debug, @@ -124,31 +124,19 @@ test(function buildLibraryMerge() { filePath: `${buildPath}/globals.ts`, inputProject, interfaceName: "FooBar", - namespaceName: `"bazqat"`, targetSourceFile }); - assert(targetSourceFile.getNamespace(`"bazqat"`) != null); + assert(targetSourceFile.getNamespace("moduleC") != null); assertEqual(targetSourceFile.getNamespaces().length, 1); - const namespaceBazqat = targetSourceFile.getNamespaceOrThrow(`"bazqat"`); - assert(namespaceBazqat.getNamespace("global") != null); - assert(namespaceBazqat.getNamespace("moduleC") != null); - assertEqual(namespaceBazqat.getNamespaces().length, 2); - assert(namespaceBazqat.getInterface("FooBar") != null); - assertEqual(namespaceBazqat.getInterfaces().length, 1); - const globalNamespace = namespaceBazqat.getNamespaceOrThrow("global"); - const variableDeclarations = globalNamespace.getVariableDeclarations(); - assertEqual( - variableDeclarations[0].getType().getText(), - `import("bazqat").FooBar` - ); - assertEqual( - variableDeclarations[1].getType().getText(), - `import("bazqat").moduleC.Bar` - ); + assert(targetSourceFile.getInterface("FooBar") != null); + assertEqual(targetSourceFile.getInterfaces().length, 1); + const variableDeclarations = targetSourceFile.getVariableDeclarations(); + assertEqual(variableDeclarations[0].getType().getText(), `FooBar`); + assertEqual(variableDeclarations[1].getType().getText(), `moduleC.Bar`); assertEqual( variableDeclarations[2].getType().getText(), - `typeof import("bazqat").moduleC.qat` + `typeof moduleC.qat` ); assertEqual(variableDeclarations.length, 3); });