mirror of
https://github.com/denoland/deno.git
synced 2024-12-25 16:49:18 -05:00
parent
bdc97b3976
commit
6c7d337960
13 changed files with 216 additions and 21 deletions
|
@ -111,6 +111,7 @@ ts_sources = [
|
||||||
"../js/mock_builtin.js",
|
"../js/mock_builtin.js",
|
||||||
"../js/net.ts",
|
"../js/net.ts",
|
||||||
"../js/os.ts",
|
"../js/os.ts",
|
||||||
|
"../js/performance.ts",
|
||||||
"../js/permissions.ts",
|
"../js/permissions.ts",
|
||||||
"../js/plugins.d.ts",
|
"../js/plugins.d.ts",
|
||||||
"../js/process.ts",
|
"../js/process.ts",
|
||||||
|
@ -127,6 +128,7 @@ ts_sources = [
|
||||||
"../js/text_encoding.ts",
|
"../js/text_encoding.ts",
|
||||||
"../js/timers.ts",
|
"../js/timers.ts",
|
||||||
"../js/truncate.ts",
|
"../js/truncate.ts",
|
||||||
|
"../js/type_directives.ts",
|
||||||
"../js/types.ts",
|
"../js/types.ts",
|
||||||
"../js/url.ts",
|
"../js/url.ts",
|
||||||
"../js/url_search_params.ts",
|
"../js/url_search_params.ts",
|
||||||
|
@ -135,7 +137,6 @@ ts_sources = [
|
||||||
"../js/window.ts",
|
"../js/window.ts",
|
||||||
"../js/workers.ts",
|
"../js/workers.ts",
|
||||||
"../js/write_file.ts",
|
"../js/write_file.ts",
|
||||||
"../js/performance.ts",
|
|
||||||
"../js/version.ts",
|
"../js/version.ts",
|
||||||
"../js/xeval.ts",
|
"../js/xeval.ts",
|
||||||
"../tsconfig.json",
|
"../tsconfig.json",
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { cwd } from "./dir";
|
||||||
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
|
import { sendSync, msg, flatbuffers } from "./dispatch_flatbuffers";
|
||||||
import * as os from "./os";
|
import * as os from "./os";
|
||||||
import { TextDecoder, TextEncoder } from "./text_encoding";
|
import { TextDecoder, TextEncoder } from "./text_encoding";
|
||||||
|
import { getMappedModuleName, parseTypeDirectives } from "./type_directives";
|
||||||
import { assert, notImplemented } from "./util";
|
import { assert, notImplemented } from "./util";
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
import { window } from "./window";
|
import { window } from "./window";
|
||||||
|
@ -110,6 +111,7 @@ interface SourceFile {
|
||||||
filename: string | undefined;
|
filename: string | undefined;
|
||||||
mediaType: msg.MediaType;
|
mediaType: msg.MediaType;
|
||||||
sourceCode: string | undefined;
|
sourceCode: string | undefined;
|
||||||
|
typeDirectives?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EmitResult {
|
interface EmitResult {
|
||||||
|
@ -119,7 +121,7 @@ interface EmitResult {
|
||||||
|
|
||||||
/** Ops to Rust to resolve and fetch a modules meta data. */
|
/** Ops to Rust to resolve and fetch a modules meta data. */
|
||||||
function fetchSourceFile(specifier: string, referrer: string): SourceFile {
|
function fetchSourceFile(specifier: string, referrer: string): SourceFile {
|
||||||
util.log("compiler.fetchSourceFile", { specifier, referrer });
|
util.log("fetchSourceFile", { specifier, referrer });
|
||||||
// Send FetchSourceFile message
|
// Send FetchSourceFile message
|
||||||
const builder = flatbuffers.createBuilder();
|
const builder = flatbuffers.createBuilder();
|
||||||
const specifier_ = builder.createString(specifier);
|
const specifier_ = builder.createString(specifier);
|
||||||
|
@ -146,7 +148,8 @@ function fetchSourceFile(specifier: string, referrer: string): SourceFile {
|
||||||
moduleName: fetchSourceFileRes.moduleName() || undefined,
|
moduleName: fetchSourceFileRes.moduleName() || undefined,
|
||||||
filename: fetchSourceFileRes.filename() || undefined,
|
filename: fetchSourceFileRes.filename() || undefined,
|
||||||
mediaType: fetchSourceFileRes.mediaType(),
|
mediaType: fetchSourceFileRes.mediaType(),
|
||||||
sourceCode
|
sourceCode,
|
||||||
|
typeDirectives: parseTypeDirectives(sourceCode)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +171,7 @@ function humanFileSize(bytes: number): string {
|
||||||
|
|
||||||
/** Ops to rest for caching source map and compiled js */
|
/** Ops to rest for caching source map and compiled js */
|
||||||
function cache(extension: string, moduleId: string, contents: string): void {
|
function cache(extension: string, moduleId: string, contents: string): void {
|
||||||
util.log("compiler.cache", moduleId);
|
util.log("cache", extension, moduleId);
|
||||||
const builder = flatbuffers.createBuilder();
|
const builder = flatbuffers.createBuilder();
|
||||||
const extension_ = builder.createString(extension);
|
const extension_ = builder.createString(extension);
|
||||||
const moduleId_ = builder.createString(moduleId);
|
const moduleId_ = builder.createString(moduleId);
|
||||||
|
@ -189,7 +192,7 @@ const encoder = new TextEncoder();
|
||||||
function emitBundle(fileName: string, data: string): void {
|
function emitBundle(fileName: string, data: string): void {
|
||||||
// For internal purposes, when trying to emit to `$deno$` just no-op
|
// For internal purposes, when trying to emit to `$deno$` just no-op
|
||||||
if (fileName.startsWith("$deno$")) {
|
if (fileName.startsWith("$deno$")) {
|
||||||
console.warn("skipping compiler.emitBundle", fileName);
|
console.warn("skipping emitBundle", fileName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const encodedData = encoder.encode(data);
|
const encodedData = encoder.encode(data);
|
||||||
|
@ -217,7 +220,7 @@ function getExtension(
|
||||||
}
|
}
|
||||||
|
|
||||||
class Host implements ts.CompilerHost {
|
class Host implements ts.CompilerHost {
|
||||||
extensionCache: Record<string, ts.Extension> = {};
|
private _extensionCache: Record<string, ts.Extension> = {};
|
||||||
|
|
||||||
private readonly _options: ts.CompilerOptions = {
|
private readonly _options: ts.CompilerOptions = {
|
||||||
allowJs: true,
|
allowJs: true,
|
||||||
|
@ -232,23 +235,37 @@ class Host implements ts.CompilerHost {
|
||||||
target: ts.ScriptTarget.ESNext
|
target: ts.ScriptTarget.ESNext
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private _sourceFileCache: Record<string, SourceFile> = {};
|
||||||
|
|
||||||
private _resolveModule(specifier: string, referrer: string): SourceFile {
|
private _resolveModule(specifier: string, referrer: string): SourceFile {
|
||||||
|
util.log("host._resolveModule", { specifier, referrer });
|
||||||
// Handle built-in assets specially.
|
// Handle built-in assets specially.
|
||||||
if (specifier.startsWith(ASSETS)) {
|
if (specifier.startsWith(ASSETS)) {
|
||||||
const moduleName = specifier.split("/").pop()!;
|
const moduleName = specifier.split("/").pop()!;
|
||||||
|
if (moduleName in this._sourceFileCache) {
|
||||||
|
return this._sourceFileCache[moduleName];
|
||||||
|
}
|
||||||
const assetName = moduleName.includes(".")
|
const assetName = moduleName.includes(".")
|
||||||
? moduleName
|
? moduleName
|
||||||
: `${moduleName}.d.ts`;
|
: `${moduleName}.d.ts`;
|
||||||
assert(assetName in assetSourceCode, `No such asset "${assetName}"`);
|
assert(assetName in assetSourceCode, `No such asset "${assetName}"`);
|
||||||
const sourceCode = assetSourceCode[assetName];
|
const sourceCode = assetSourceCode[assetName];
|
||||||
return {
|
const sourceFile = {
|
||||||
moduleName,
|
moduleName,
|
||||||
filename: specifier,
|
filename: specifier,
|
||||||
mediaType: msg.MediaType.TypeScript,
|
mediaType: msg.MediaType.TypeScript,
|
||||||
sourceCode
|
sourceCode
|
||||||
};
|
};
|
||||||
|
this._sourceFileCache[moduleName] = sourceFile;
|
||||||
|
return sourceFile;
|
||||||
}
|
}
|
||||||
return fetchSourceFile(specifier, referrer);
|
const sourceFile = fetchSourceFile(specifier, referrer);
|
||||||
|
assert(sourceFile.moduleName != null);
|
||||||
|
const { moduleName } = sourceFile;
|
||||||
|
if (!(moduleName! in this._sourceFileCache)) {
|
||||||
|
this._sourceFileCache[moduleName!] = sourceFile;
|
||||||
|
}
|
||||||
|
return sourceFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deno specific APIs */
|
/* Deno specific APIs */
|
||||||
|
@ -277,7 +294,7 @@ class Host implements ts.CompilerHost {
|
||||||
* options which were ignored, or `undefined`.
|
* options which were ignored, or `undefined`.
|
||||||
*/
|
*/
|
||||||
configure(path: string, configurationText: string): ConfigureResponse {
|
configure(path: string, configurationText: string): ConfigureResponse {
|
||||||
util.log("compile.configure", path);
|
util.log("host.configure", path);
|
||||||
const { config, error } = ts.parseConfigFileTextToJson(
|
const { config, error } = ts.parseConfigFileTextToJson(
|
||||||
path,
|
path,
|
||||||
configurationText
|
configurationText
|
||||||
|
@ -308,7 +325,10 @@ class Host implements ts.CompilerHost {
|
||||||
|
|
||||||
/* TypeScript CompilerHost APIs */
|
/* TypeScript CompilerHost APIs */
|
||||||
|
|
||||||
fileExists(_fileName: string): boolean {
|
fileExists(fileName: string): boolean {
|
||||||
|
if (fileName.endsWith("package.json")) {
|
||||||
|
throw new TypeError("Automatic type resolution not supported");
|
||||||
|
}
|
||||||
return notImplemented();
|
return notImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,13 +362,17 @@ class Host implements ts.CompilerHost {
|
||||||
): ts.SourceFile | undefined {
|
): ts.SourceFile | undefined {
|
||||||
assert(!shouldCreateNewSourceFile);
|
assert(!shouldCreateNewSourceFile);
|
||||||
util.log("getSourceFile", fileName);
|
util.log("getSourceFile", fileName);
|
||||||
const SourceFile = this._resolveModule(fileName, ".");
|
const sourceFile =
|
||||||
if (!SourceFile || !SourceFile.sourceCode) {
|
fileName in this._sourceFileCache
|
||||||
|
? this._sourceFileCache[fileName]
|
||||||
|
: this._resolveModule(fileName, ".");
|
||||||
|
assert(sourceFile != null);
|
||||||
|
if (!sourceFile.sourceCode) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return ts.createSourceFile(
|
return ts.createSourceFile(
|
||||||
fileName,
|
fileName,
|
||||||
SourceFile.sourceCode,
|
sourceFile.sourceCode,
|
||||||
languageVersion
|
languageVersion
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -362,26 +386,37 @@ class Host implements ts.CompilerHost {
|
||||||
containingFile: string
|
containingFile: string
|
||||||
): Array<ts.ResolvedModuleFull | undefined> {
|
): Array<ts.ResolvedModuleFull | undefined> {
|
||||||
util.log("resolveModuleNames()", { moduleNames, containingFile });
|
util.log("resolveModuleNames()", { moduleNames, containingFile });
|
||||||
|
const typeDirectives: Record<string, string> | undefined =
|
||||||
|
containingFile in this._sourceFileCache
|
||||||
|
? this._sourceFileCache[containingFile].typeDirectives
|
||||||
|
: undefined;
|
||||||
return moduleNames.map(
|
return moduleNames.map(
|
||||||
(moduleName): ts.ResolvedModuleFull | undefined => {
|
(moduleName): ts.ResolvedModuleFull | undefined => {
|
||||||
const SourceFile = this._resolveModule(moduleName, containingFile);
|
const mappedModuleName = getMappedModuleName(
|
||||||
if (SourceFile.moduleName) {
|
moduleName,
|
||||||
const resolvedFileName = SourceFile.moduleName;
|
containingFile,
|
||||||
|
typeDirectives
|
||||||
|
);
|
||||||
|
const sourceFile = this._resolveModule(
|
||||||
|
mappedModuleName,
|
||||||
|
containingFile
|
||||||
|
);
|
||||||
|
if (sourceFile.moduleName) {
|
||||||
|
const resolvedFileName = sourceFile.moduleName;
|
||||||
// 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 = moduleName.startsWith(ASSETS);
|
const isExternalLibraryImport = moduleName.startsWith(ASSETS);
|
||||||
const extension = getExtension(
|
const extension = getExtension(
|
||||||
resolvedFileName,
|
resolvedFileName,
|
||||||
SourceFile.mediaType
|
sourceFile.mediaType
|
||||||
);
|
);
|
||||||
this.extensionCache[resolvedFileName] = extension;
|
this._extensionCache[resolvedFileName] = extension;
|
||||||
|
|
||||||
const r = {
|
return {
|
||||||
resolvedFileName,
|
resolvedFileName,
|
||||||
isExternalLibraryImport,
|
isExternalLibraryImport,
|
||||||
extension
|
extension
|
||||||
};
|
};
|
||||||
return r;
|
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -407,7 +442,7 @@ class Host implements ts.CompilerHost {
|
||||||
} else {
|
} else {
|
||||||
assert(sourceFiles != null && sourceFiles.length == 1);
|
assert(sourceFiles != null && sourceFiles.length == 1);
|
||||||
const sourceFileName = sourceFiles![0].fileName;
|
const sourceFileName = sourceFiles![0].fileName;
|
||||||
const maybeExtension = this.extensionCache[sourceFileName];
|
const maybeExtension = this._extensionCache[sourceFileName];
|
||||||
|
|
||||||
if (maybeExtension) {
|
if (maybeExtension) {
|
||||||
// NOTE: If it's a `.json` file we don't want to write it to disk.
|
// NOTE: If it's a `.json` file we don't want to write it to disk.
|
||||||
|
|
87
js/type_directives.ts
Normal file
87
js/type_directives.ts
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
interface DirectiveInfo {
|
||||||
|
path: string;
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remap the module name based on any supplied type directives passed. */
|
||||||
|
export function getMappedModuleName(
|
||||||
|
moduleName: string,
|
||||||
|
containingFile: string,
|
||||||
|
typeDirectives?: Record<string, string>
|
||||||
|
): string {
|
||||||
|
if (containingFile.endsWith(".d.ts") && !moduleName.endsWith(".d.ts")) {
|
||||||
|
moduleName = `${moduleName}.d.ts`;
|
||||||
|
}
|
||||||
|
if (!typeDirectives) {
|
||||||
|
return moduleName;
|
||||||
|
}
|
||||||
|
if (moduleName in typeDirectives) {
|
||||||
|
return typeDirectives[moduleName];
|
||||||
|
}
|
||||||
|
return moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Matches directives that look something like this and parses out the value
|
||||||
|
* of the directive:
|
||||||
|
*
|
||||||
|
* // @deno-types="./foo.d.ts"
|
||||||
|
*
|
||||||
|
* [See Diagram](http://bit.ly/31nZPCF)
|
||||||
|
*/
|
||||||
|
const typeDirectiveRegEx = /@deno-types\s*=\s*(["'])((?:(?=(\\?))\3.)*?)\1/gi;
|
||||||
|
|
||||||
|
/** Matches `import` or `export from` statements and parses out the value of the
|
||||||
|
* module specifier in the second capture group:
|
||||||
|
*
|
||||||
|
* import * as foo from "./foo.js"
|
||||||
|
* export { a, b, c } from "./bar.js"
|
||||||
|
*
|
||||||
|
* [See Diagram](http://bit.ly/2GSkJlF)
|
||||||
|
*/
|
||||||
|
const importExportRegEx = /(?:import|export)\s+[\s\S]*?from\s+(["'])((?:(?=(\\?))\3.)*?)\1/;
|
||||||
|
|
||||||
|
/** Parses out any Deno type directives that are part of the source code, or
|
||||||
|
* returns `undefined` if there are not any.
|
||||||
|
*/
|
||||||
|
export function parseTypeDirectives(
|
||||||
|
sourceCode: string | undefined
|
||||||
|
): Record<string, string> | undefined {
|
||||||
|
if (!sourceCode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect all the directives in the file and their start and end positions
|
||||||
|
const directives: DirectiveInfo[] = [];
|
||||||
|
let maybeMatch: RegExpExecArray | null = null;
|
||||||
|
while ((maybeMatch = typeDirectiveRegEx.exec(sourceCode))) {
|
||||||
|
const [matchString, , path] = maybeMatch;
|
||||||
|
const { index: start } = maybeMatch;
|
||||||
|
directives.push({
|
||||||
|
path,
|
||||||
|
start,
|
||||||
|
end: start + matchString.length
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!directives.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// work from the last directive backwards for the next `import`/`export`
|
||||||
|
// statement
|
||||||
|
directives.reverse();
|
||||||
|
const directiveRecords: Record<string, string> = {};
|
||||||
|
for (const { path, start, end } of directives) {
|
||||||
|
const searchString = sourceCode.substring(end);
|
||||||
|
const maybeMatch = importExportRegEx.exec(searchString);
|
||||||
|
if (maybeMatch) {
|
||||||
|
const [, , fromPath] = maybeMatch;
|
||||||
|
directiveRecords[fromPath] = path;
|
||||||
|
}
|
||||||
|
sourceCode = sourceCode.substring(0, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
return directiveRecords;
|
||||||
|
}
|
4
tests/error_type_definitions.test
Normal file
4
tests/error_type_definitions.test
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
args: run --reload tests/error_type_definitions.ts
|
||||||
|
check_stderr: true
|
||||||
|
exit_code: 1
|
||||||
|
output: tests/error_type_definitions.ts.out
|
5
tests/error_type_definitions.ts
Normal file
5
tests/error_type_definitions.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
// @deno-types="./type_definitions/bar.d.ts"
|
||||||
|
import { Bar } from "./type_definitions/bar.js";
|
||||||
|
|
||||||
|
const bar = new Bar();
|
||||||
|
console.log(bar);
|
4
tests/error_type_definitions.ts.out
Normal file
4
tests/error_type_definitions.ts.out
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[WILDCARD]error: Uncaught TypeError: Automatic type resolution not supported
|
||||||
|
[WILDCARD]js/compiler.ts:[WILDCARD]
|
||||||
|
at fileExists (js/compiler.ts:[WILDCARD])
|
||||||
|
[WILDCARD]
|
2
tests/type_definitions.test
Normal file
2
tests/type_definitions.test
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
args: run --reload tests/type_definitions.ts
|
||||||
|
output: tests/type_definitions.ts.out
|
4
tests/type_definitions.ts
Normal file
4
tests/type_definitions.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
// @deno-types="./type_definitions/foo.d.ts"
|
||||||
|
import { foo } from "./type_definitions/foo.js";
|
||||||
|
|
||||||
|
console.log(foo);
|
1
tests/type_definitions.ts.out
Normal file
1
tests/type_definitions.ts.out
Normal file
|
@ -0,0 +1 @@
|
||||||
|
[WILDCARD]foo
|
7
tests/type_definitions/bar.d.ts
vendored
Normal file
7
tests/type_definitions/bar.d.ts
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
/// <reference types="baz" />
|
||||||
|
|
||||||
|
declare namespace bar {
|
||||||
|
export class Bar {
|
||||||
|
baz: string;
|
||||||
|
}
|
||||||
|
}
|
2
tests/type_definitions/foo.d.ts
vendored
Normal file
2
tests/type_definitions/foo.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/** An exported value. */
|
||||||
|
export const foo: string;
|
1
tests/type_definitions/foo.js
Normal file
1
tests/type_definitions/foo.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const foo = "foo";
|
|
@ -580,6 +580,48 @@ import { test, assertEquals } from "./deps.ts";
|
||||||
This design circumvents a plethora of complexity spawned by package management
|
This design circumvents a plethora of complexity spawned by package management
|
||||||
software, centralized code repositories, and superfluous file formats.
|
software, centralized code repositories, and superfluous file formats.
|
||||||
|
|
||||||
|
### Using external type definitions
|
||||||
|
|
||||||
|
Deno supports both JavaScript and TypeScript as first class languages at
|
||||||
|
runtime. This means it requires fully qualified module names, including the
|
||||||
|
extension (or a server providing the correct media type). In addition, Deno has
|
||||||
|
no "magical" module resolution.
|
||||||
|
|
||||||
|
The out of the box TypeScript compiler though relies on both extension-less
|
||||||
|
modules and the Node.js module resolution logic to apply types to JavaScript
|
||||||
|
modules.
|
||||||
|
|
||||||
|
In order to bridge this gap, Deno supports compiler hints that inform Deno the
|
||||||
|
location of `.d.ts` files and the JavaScript code they relate to. A compiler
|
||||||
|
hint looks like this:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// @deno-types="./foo.d.ts"
|
||||||
|
import * as foo from "./foo.js";
|
||||||
|
```
|
||||||
|
|
||||||
|
Where the hint effects the next `import` statement (or `export ... from`
|
||||||
|
statement) where the value of the `@deno-types` will be substituted at compile
|
||||||
|
time instead of the specified module. Like in the above example, the Deno
|
||||||
|
compiler will load `./foo.d.ts` instead of `./foo.js`. Deno will still load
|
||||||
|
`./foo.js` when it runs the program.
|
||||||
|
|
||||||
|
**Not all type definitions are supported.**
|
||||||
|
|
||||||
|
Deno will use the compiler hint to load the indicated `.d.ts` files, but some
|
||||||
|
`.d.ts` files contain unsupported features. Specifically, some `.d.ts` files
|
||||||
|
expect to be able to load or reference type definitions from other packages
|
||||||
|
using the module resolution logic. For example a type reference directive to
|
||||||
|
include `node`, expecting to resolve to some path like
|
||||||
|
`./node_modules/@types/node/index.d.ts`. Since this depends on non-relative
|
||||||
|
"magical" resolution, Deno cannot resolve this.
|
||||||
|
|
||||||
|
**Why not use the triple-slash type reference?**
|
||||||
|
|
||||||
|
The TypeScript compiler supports triple-slash directives, including a type
|
||||||
|
reference directive. If Deno used this, it would interfere with the behavior of
|
||||||
|
the TypeScript compiler.
|
||||||
|
|
||||||
### Testing if current file is the main program
|
### Testing if current file is the main program
|
||||||
|
|
||||||
To test if the current script has been executed as the main input to the program
|
To test if the current script has been executed as the main input to the program
|
||||||
|
|
Loading…
Reference in a new issue