From 8923eec80a49994a653cd791a578126451a336c4 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 9 Apr 2018 15:14:32 -0700 Subject: [PATCH 01/15] Added tests for 'import.meta'. --- .../es2019/importMeta/importMeta.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/cases/conformance/es2019/importMeta/importMeta.ts diff --git a/tests/cases/conformance/es2019/importMeta/importMeta.ts b/tests/cases/conformance/es2019/importMeta/importMeta.ts new file mode 100644 index 0000000000000..f23410fc53611 --- /dev/null +++ b/tests/cases/conformance/es2019/importMeta/importMeta.ts @@ -0,0 +1,28 @@ + +// @target: esnext +// @lib: es5,dom + +// @Filename: example.ts +// Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example +(async () => { + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); + const blob = await response.blob(); + + const size = import.meta.scriptElement.dataset.size || 300; + + const image = new Image(); + image.src = URL.createObjectURL(blob); + image.width = image.height = size; + + document.body.appendChild(image); +})(); + +// @Filename: moduleLookingFile01.ts +export let x = import.meta; +export let y = import.metal; +export let z = import.import.import.malkovich; + +// @Filename: scriptLookingFile01.ts +let globalA = import.meta; +let globalB = import.metal; +let globalC = import.import.import.malkovich; From 9b8670cf9208c2681548b2859957297d268535cc Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 9 Apr 2018 15:28:37 -0700 Subject: [PATCH 02/15] Accepted baselines. --- .../baselines/reference/importMeta.errors.txt | 125 ++++++++++++++++++ tests/baselines/reference/importMeta.js | 48 +++++++ tests/baselines/reference/importMeta.symbols | 82 ++++++++++++ tests/baselines/reference/importMeta.types | 111 ++++++++++++++++ 4 files changed, 366 insertions(+) create mode 100644 tests/baselines/reference/importMeta.errors.txt create mode 100644 tests/baselines/reference/importMeta.js create mode 100644 tests/baselines/reference/importMeta.symbols create mode 100644 tests/baselines/reference/importMeta.types diff --git a/tests/baselines/reference/importMeta.errors.txt b/tests/baselines/reference/importMeta.errors.txt new file mode 100644 index 0000000000000..498da8efdc13b --- /dev/null +++ b/tests/baselines/reference/importMeta.errors.txt @@ -0,0 +1,125 @@ +error TS2468: Cannot find global value 'Promise'. +tests/cases/conformance/es2019/importMeta/example.ts(2,2): error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. +tests/cases/conformance/es2019/importMeta/example.ts(3,59): error TS1135: Argument expression expected. +tests/cases/conformance/es2019/importMeta/example.ts(3,65): error TS1135: Argument expression expected. +tests/cases/conformance/es2019/importMeta/example.ts(3,66): error TS2448: Block-scoped variable 'meta' used before its declaration. +tests/cases/conformance/es2019/importMeta/example.ts(6,9): error TS2451: Cannot redeclare block-scoped variable 'size'. +tests/cases/conformance/es2019/importMeta/example.ts(6,16): error TS1109: Expression expected. +tests/cases/conformance/es2019/importMeta/example.ts(6,22): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/example.ts(6,27): error TS1005: ',' expected. +tests/cases/conformance/es2019/importMeta/example.ts(6,41): error TS1005: ',' expected. +tests/cases/conformance/es2019/importMeta/example.ts(6,49): error TS1005: ',' expected. +tests/cases/conformance/es2019/importMeta/example.ts(6,50): error TS2451: Cannot redeclare block-scoped variable 'size'. +tests/cases/conformance/es2019/importMeta/example.ts(6,55): error TS1005: ',' expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(1,16): error TS1109: Expression expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(1,22): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,16): error TS1109: Expression expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,22): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,16): error TS1109: Expression expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,22): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,23): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,29): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,30): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,36): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(1,15): error TS1109: Expression expected. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(1,21): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(2,15): error TS1109: Expression expected. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(2,21): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,15): error TS1109: Expression expected. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,21): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,22): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,28): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,29): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,35): error TS1134: Variable declaration expected. + + +!!! error TS2468: Cannot find global value 'Promise'. +==== tests/cases/conformance/es2019/importMeta/example.ts (12 errors) ==== + // Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example + (async () => { + ~~~~~~~~~~~~~ +!!! error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); + ~~~~~~ +!!! error TS1135: Argument expression expected. + ~ +!!! error TS1135: Argument expression expected. + ~~~~ +!!! error TS2448: Block-scoped variable 'meta' used before its declaration. + const blob = await response.blob(); + + const size = import.meta.scriptElement.dataset.size || 300; + ~~~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'size'. + ~~~~~~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1005: ',' expected. + ~ +!!! error TS1005: ',' expected. + ~ +!!! error TS1005: ',' expected. + ~~~~ +!!! error TS2451: Cannot redeclare block-scoped variable 'size'. + ~~ +!!! error TS1005: ',' expected. + + const image = new Image(); + image.src = URL.createObjectURL(blob); + image.width = image.height = size; + + document.body.appendChild(image); + })(); + +==== tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts (10 errors) ==== + export let x = import.meta; + ~~~~~~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1134: Variable declaration expected. + export let y = import.metal; + ~~~~~~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1134: Variable declaration expected. + export let z = import.import.import.malkovich; + ~~~~~~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1134: Variable declaration expected. + ~~~~~~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. + ~~~~~~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. + +==== tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts (10 errors) ==== + let globalA = import.meta; + ~~~~~~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1134: Variable declaration expected. + let globalB = import.metal; + ~~~~~~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1134: Variable declaration expected. + let globalC = import.import.import.malkovich; + ~~~~~~ +!!! error TS1109: Expression expected. + ~ +!!! error TS1134: Variable declaration expected. + ~~~~~~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. + ~~~~~~ +!!! error TS1134: Variable declaration expected. + ~ +!!! error TS1134: Variable declaration expected. + \ No newline at end of file diff --git a/tests/baselines/reference/importMeta.js b/tests/baselines/reference/importMeta.js new file mode 100644 index 0000000000000..9391dbc4899b2 --- /dev/null +++ b/tests/baselines/reference/importMeta.js @@ -0,0 +1,48 @@ +//// [tests/cases/conformance/es2019/importMeta/importMeta.ts] //// + +//// [example.ts] +// Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example +(async () => { + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); + const blob = await response.blob(); + + const size = import.meta.scriptElement.dataset.size || 300; + + const image = new Image(); + image.src = URL.createObjectURL(blob); + image.width = image.height = size; + + document.body.appendChild(image); +})(); + +//// [moduleLookingFile01.ts] +export let x = import.meta; +export let y = import.metal; +export let z = import.import.import.malkovich; + +//// [scriptLookingFile01.ts] +let globalA = import.meta; +let globalB = import.metal; +let globalC = import.import.import.malkovich; + + +//// [example.js] +// Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example +(async () => { + const response = await fetch(new URL("../hamsters.jpg", meta.url).toString()); + const blob = await response.blob(); + const size = , meta, scriptElement, dataset, size; + || 300; + const image = new Image(); + image.src = URL.createObjectURL(blob); + image.width = image.height = size; + document.body.appendChild(image); +})(); +//// [moduleLookingFile01.js] +export let x = , meta; +export let y = , metal; +export let z = , malkovich; +//// [scriptLookingFile01.js] +let globalA = , meta; +let globalB = , metal; +let globalC = , malkovich; diff --git a/tests/baselines/reference/importMeta.symbols b/tests/baselines/reference/importMeta.symbols new file mode 100644 index 0000000000000..cff36047d37f0 --- /dev/null +++ b/tests/baselines/reference/importMeta.symbols @@ -0,0 +1,82 @@ +=== tests/cases/conformance/es2019/importMeta/example.ts === +// Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example +(async () => { + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); +>response : Symbol(response, Decl(example.ts, 2, 7)) +>fetch : Symbol(fetch, Decl(lib.dom.d.ts, --, --)) +>new URL("../hamsters.jpg", import.meta.url).toString : Symbol(URL.toString, Decl(lib.dom.d.ts, --, --)) +>URL : Symbol(URL, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>meta : Symbol(meta, Decl(example.ts, 5, 22)) +>toString : Symbol(URL.toString, Decl(lib.dom.d.ts, --, --)) + + const blob = await response.blob(); +>blob : Symbol(blob, Decl(example.ts, 3, 7)) +>response.blob : Symbol(Body.blob, Decl(lib.dom.d.ts, --, --)) +>response : Symbol(response, Decl(example.ts, 2, 7)) +>blob : Symbol(Body.blob, Decl(lib.dom.d.ts, --, --)) + + const size = import.meta.scriptElement.dataset.size || 300; +>size : Symbol(size, Decl(example.ts, 5, 7)) +>meta : Symbol(meta, Decl(example.ts, 5, 22)) +>scriptElement : Symbol(scriptElement, Decl(example.ts, 5, 27)) +>dataset : Symbol(dataset, Decl(example.ts, 5, 41)) +>size : Symbol(size, Decl(example.ts, 5, 49)) + + const image = new Image(); +>image : Symbol(image, Decl(example.ts, 7, 7)) +>Image : Symbol(Image, Decl(lib.dom.d.ts, --, --)) + + image.src = URL.createObjectURL(blob); +>image.src : Symbol(HTMLImageElement.src, Decl(lib.dom.d.ts, --, --)) +>image : Symbol(image, Decl(example.ts, 7, 7)) +>src : Symbol(HTMLImageElement.src, Decl(lib.dom.d.ts, --, --)) +>URL.createObjectURL : Symbol(createObjectURL, Decl(lib.dom.d.ts, --, --)) +>URL : Symbol(URL, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>createObjectURL : Symbol(createObjectURL, Decl(lib.dom.d.ts, --, --)) +>blob : Symbol(blob, Decl(example.ts, 3, 7)) + + image.width = image.height = size; +>image.width : Symbol(HTMLImageElement.width, Decl(lib.dom.d.ts, --, --)) +>image : Symbol(image, Decl(example.ts, 7, 7)) +>width : Symbol(HTMLImageElement.width, Decl(lib.dom.d.ts, --, --)) +>image.height : Symbol(HTMLImageElement.height, Decl(lib.dom.d.ts, --, --)) +>image : Symbol(image, Decl(example.ts, 7, 7)) +>height : Symbol(HTMLImageElement.height, Decl(lib.dom.d.ts, --, --)) +>size : Symbol(size, Decl(example.ts, 5, 7)) + + document.body.appendChild(image); +>document.body.appendChild : Symbol(Node.appendChild, Decl(lib.dom.d.ts, --, --)) +>document.body : Symbol(Document.body, Decl(lib.dom.d.ts, --, --)) +>document : Symbol(document, Decl(lib.dom.d.ts, --, --)) +>body : Symbol(Document.body, Decl(lib.dom.d.ts, --, --)) +>appendChild : Symbol(Node.appendChild, Decl(lib.dom.d.ts, --, --)) +>image : Symbol(image, Decl(example.ts, 7, 7)) + +})(); + +=== tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts === +export let x = import.meta; +>x : Symbol(x, Decl(moduleLookingFile01.ts, 0, 10)) +>meta : Symbol(meta, Decl(moduleLookingFile01.ts, 0, 22)) + +export let y = import.metal; +>y : Symbol(y, Decl(moduleLookingFile01.ts, 1, 10)) +>metal : Symbol(metal, Decl(moduleLookingFile01.ts, 1, 22)) + +export let z = import.import.import.malkovich; +>z : Symbol(z, Decl(moduleLookingFile01.ts, 2, 10)) +>malkovich : Symbol(malkovich, Decl(moduleLookingFile01.ts, 2, 36)) + +=== tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts === +let globalA = import.meta; +>globalA : Symbol(globalA, Decl(scriptLookingFile01.ts, 0, 3)) +>meta : Symbol(meta, Decl(scriptLookingFile01.ts, 0, 21)) + +let globalB = import.metal; +>globalB : Symbol(globalB, Decl(scriptLookingFile01.ts, 1, 3)) +>metal : Symbol(metal, Decl(scriptLookingFile01.ts, 1, 21)) + +let globalC = import.import.import.malkovich; +>globalC : Symbol(globalC, Decl(scriptLookingFile01.ts, 2, 3)) +>malkovich : Symbol(malkovich, Decl(scriptLookingFile01.ts, 2, 35)) + diff --git a/tests/baselines/reference/importMeta.types b/tests/baselines/reference/importMeta.types new file mode 100644 index 0000000000000..5004627cb4c15 --- /dev/null +++ b/tests/baselines/reference/importMeta.types @@ -0,0 +1,111 @@ +=== tests/cases/conformance/es2019/importMeta/example.ts === +// Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example +(async () => { +>(async () => { const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); const blob = await response.blob(); const size = import.meta.scriptElement.dataset.size || 300; const image = new Image(); image.src = URL.createObjectURL(blob); image.width = image.height = size; document.body.appendChild(image);})() : Promise +>(async () => { const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); const blob = await response.blob(); const size = import.meta.scriptElement.dataset.size || 300; const image = new Image(); image.src = URL.createObjectURL(blob); image.width = image.height = size; document.body.appendChild(image);}) : () => Promise +>async () => { const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); const blob = await response.blob(); const size = import.meta.scriptElement.dataset.size || 300; const image = new Image(); image.src = URL.createObjectURL(blob); image.width = image.height = size; document.body.appendChild(image);} : () => Promise + + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); +>response : Response +>await fetch(new URL("../hamsters.jpg", import.meta.url).toString()) : Response +>fetch(new URL("../hamsters.jpg", import.meta.url).toString()) : Promise +>fetch : (input?: string | Request, init?: RequestInit) => Promise +>new URL("../hamsters.jpg", import.meta.url).toString() : string +>new URL("../hamsters.jpg", import.meta.url).toString : () => string +>new URL("../hamsters.jpg", import.meta.url) : URL +>URL : { new (url: string, base?: string | URL): URL; prototype: URL; createObjectURL(object: any, options?: ObjectURLOptions): string; revokeObjectURL(url: string): void; } +>"../hamsters.jpg" : "../hamsters.jpg" +>meta.url : any +>meta : any +>url : any +>toString : () => string + + const blob = await response.blob(); +>blob : Blob +>await response.blob() : Blob +>response.blob() : Promise +>response.blob : () => Promise +>response : Response +>blob : () => Promise + + const size = import.meta.scriptElement.dataset.size || 300; +>size : any +> : any +>meta : any +>scriptElement : any +>dataset : any +>size : any +>|| 300 : any +> : any +>300 : 300 + + const image = new Image(); +>image : HTMLImageElement +>new Image() : HTMLImageElement +>Image : new (width?: number, height?: number) => HTMLImageElement + + image.src = URL.createObjectURL(blob); +>image.src = URL.createObjectURL(blob) : string +>image.src : string +>image : HTMLImageElement +>src : string +>URL.createObjectURL(blob) : string +>URL.createObjectURL : (object: any, options?: ObjectURLOptions) => string +>URL : { new (url: string, base?: string | URL): URL; prototype: URL; createObjectURL(object: any, options?: ObjectURLOptions): string; revokeObjectURL(url: string): void; } +>createObjectURL : (object: any, options?: ObjectURLOptions) => string +>blob : Blob + + image.width = image.height = size; +>image.width = image.height = size : any +>image.width : number +>image : HTMLImageElement +>width : number +>image.height = size : any +>image.height : number +>image : HTMLImageElement +>height : number +>size : any + + document.body.appendChild(image); +>document.body.appendChild(image) : HTMLImageElement +>document.body.appendChild : (newChild: T) => T +>document.body : HTMLElement +>document : Document +>body : HTMLElement +>appendChild : (newChild: T) => T +>image : HTMLImageElement + +})(); + +=== tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts === +export let x = import.meta; +>x : any +> : any +>meta : any + +export let y = import.metal; +>y : any +> : any +>metal : any + +export let z = import.import.import.malkovich; +>z : any +> : any +>malkovich : any + +=== tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts === +let globalA = import.meta; +>globalA : any +> : any +>meta : any + +let globalB = import.metal; +>globalB : any +> : any +>metal : any + +let globalC = import.import.import.malkovich; +>globalC : any +> : any +>malkovich : any + From 9e2bbb6f8a9dca00a899ef7eabccbc31bf8aa935 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 9 Apr 2018 17:03:05 -0700 Subject: [PATCH 03/15] Basic parsing/emitting support for 'import.meta'. --- src/compiler/parser.ts | 86 +++++++++++++++++++++++++++++++---------- src/compiler/program.ts | 2 +- src/compiler/types.ts | 29 ++++++++------ 3 files changed, 85 insertions(+), 32 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 0b89c3c313cf5..e9a685d9d267a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -542,7 +542,7 @@ namespace ts { const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks); // Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import. // We will manually port the flag to the new source file. - newSourceFile.flags |= (sourceFile.flags & NodeFlags.PossiblyContainsDynamicImport); + newSourceFile.flags |= (sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags); return newSourceFile; } @@ -2627,6 +2627,20 @@ namespace ts { return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken; } + function nextTokenIsDot() { + return nextToken() === SyntaxKind.DotToken; + } + + function nextTokenIsOpenParenOrLessThanOrDot() { + switch (nextToken()) { + case SyntaxKind.OpenParenToken: + case SyntaxKind.LessThanToken: + case SyntaxKind.DotToken: + return true; + } + return false; + } + function parseTypeLiteral(): TypeLiteralNode { const node = createNode(SyntaxKind.TypeLiteral); node.members = parseObjectTypeMembers(); @@ -3095,7 +3109,7 @@ namespace ts { case SyntaxKind.Identifier: return true; case SyntaxKind.ImportKeyword: - return lookAhead(nextTokenIsOpenParenOrLessThan); + return lookAhead(nextTokenIsOpenParenOrLessThanOrDot); default: return isIdentifier(); } @@ -3957,14 +3971,31 @@ namespace ts { // 3)we have a MemberExpression which either completes the LeftHandSideExpression, // or starts the beginning of the first four CallExpression productions. let expression: MemberExpression; - if (token() === SyntaxKind.ImportKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) { - // We don't want to eagerly consume all import keyword as import call expression so we look a head to find "(" - // For example: - // var foo3 = require("subfolder - // import * as foo1 from "module-from-node - // We want this import to be a statement rather than import call expression - sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport; - expression = parseTokenNode(); + if (token() === SyntaxKind.ImportKeyword) { + if (lookAhead(nextTokenIsOpenParenOrLessThan)) { + // We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "(" + // For example: + // var foo3 = require("subfolder + // import * as foo1 from "module-from-node + // We want this import to be a statement rather than import call expression + sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport; + expression = parseTokenNode(); + } + else if (lookAhead(nextTokenIsDot)) { + // This is an 'import.*' metaproperty (i.e. 'import.meta') + const fullStart = scanner.getStartPos(); + nextToken(); // advance past the 'import' + nextToken(); // advance past the dot + const node = createNode(SyntaxKind.MetaProperty, fullStart) as MetaProperty; + node.keywordToken = SyntaxKind.ImportKeyword; + node.name = parseIdentifierName(); + expression = finishNode(node); + + sourceFile.flags |= NodeFlags.PossiblyContainsImportMeta; + } + else { + expression = parseMemberExpressionOrHigher(); + } } else { expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher(); @@ -4508,7 +4539,7 @@ namespace ts { case SyntaxKind.FunctionKeyword: return parseFunctionExpression(); case SyntaxKind.NewKeyword: - return parseNewExpression(); + return parseNewExpressionOrNewDotTarget(); case SyntaxKind.SlashToken: case SyntaxKind.SlashEqualsToken: if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) { @@ -4659,7 +4690,7 @@ namespace ts { return isIdentifier() ? parseIdentifier() : undefined; } - function parseNewExpression(): NewExpression | MetaProperty { + function parseNewExpressionOrNewDotTarget(): NewExpression | MetaProperty { const fullStart = scanner.getStartPos(); parseExpected(SyntaxKind.NewKeyword); if (parseOptional(SyntaxKind.DotToken)) { @@ -5093,7 +5124,7 @@ namespace ts { return true; case SyntaxKind.ImportKeyword: - return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThan); + return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThanOrDot); case SyntaxKind.ConstKeyword: case SyntaxKind.ExportKeyword: @@ -6079,14 +6110,29 @@ namespace ts { } function setExternalModuleIndicator(sourceFile: SourceFile) { - sourceFile.externalModuleIndicator = forEach(sourceFile.statements, node => - hasModifier(node, ModifierFlags.Export) - || node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference - || node.kind === SyntaxKind.ImportDeclaration - || node.kind === SyntaxKind.ExportAssignment - || node.kind === SyntaxKind.ExportDeclaration + // Usually we'd like to avoid a full tree walk, but it's possible + // that we have a deeper external module indicator (e.g. `import.meta`, + // and possibly nested import statements in the future). + // Ideally the first few statements will be an import/export anyway. + sourceFile.externalModuleIndicator = + !(sourceFile.flags & NodeFlags.PossiblyContainsImportMeta) ? + forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) : + walkTreeForExternalModuleIndicators(sourceFile); + } + + function isAnExternalModuleIndicatorNode(node: Node) { + return hasModifier(node, ModifierFlags.Export) + || node.kind === SyntaxKind.ImportEqualsDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference + || node.kind === SyntaxKind.ImportDeclaration + || node.kind === SyntaxKind.ExportAssignment + || node.kind === SyntaxKind.ExportDeclaration + || isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta" ? node - : undefined); + : undefined + } + + function walkTreeForExternalModuleIndicators(node: Node): Node { + return isAnExternalModuleIndicatorNode(node) ? node : forEachChild(node, walkTreeForExternalModuleIndicators); } const enum ParsingContext { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 31220c68d3cb9..57c69b77bb9d2 100755 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -989,7 +989,7 @@ namespace ts { // moduleAugmentations has changed oldProgram.structureIsReused = StructureIsReused.SafeModules; } - if ((oldSourceFile.flags & NodeFlags.PossiblyContainsDynamicImport) !== (newSourceFile.flags & NodeFlags.PossiblyContainsDynamicImport)) { + if ((oldSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) !== (newSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags)) { // dynamicImport has changed oldProgram.structureIsReused = StructureIsReused.SafeModules; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ac32d91c61ad7..42cf1325551e8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -490,19 +490,21 @@ namespace ts { ThisNodeOrAnySubNodesHasError = 1 << 17, // If this node or any of its children had an error HasAggregatedChildData = 1 << 18, // If we've computed data from children and cached it in this node - // This flag will be set when the parser encounters a dynamic import expression so that module resolution - // will not have to walk the tree if the flag is not set. However, this flag is just a approximation because - // once it is set, the flag never gets cleared (hence why it's named "PossiblyContainsDynamicImport"). - // During editing, if dynamic import is removed, incremental parsing will *NOT* update this flag. This means that the tree will always be traversed - // during module resolution. However, the removal operation should not occur often and in the case of the + // These flags will be set when the parser encounters a dynamic import expression or 'import.meta' to avoid + // walking the tree if the flags are not set. However, these flags are just a approximation + // (hence why it's named "PossiblyContainsDynamicImport") because once set, the flags never get cleared. + // During editing, if a dynamic import is removed, incremental parsing will *NOT* clear this flag. + // This means that the tree will always be traversed during module resolution, or when looking for external module indicators. + // However, the removal operation should not occur often and in the case of the // removal, it is likely that users will add the import anyway. // The advantage of this approach is its simplicity. For the case of batch compilation, // we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used. - /* @internal */ - PossiblyContainsDynamicImport = 1 << 19, - JSDoc = 1 << 20, // If node was parsed inside jsdoc - /* @internal */ Ambient = 1 << 21, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier. - /* @internal */ InWithStatement = 1 << 22, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`) + /* @internal */ PossiblyContainsDynamicImport = 1 << 19, + /* @internal */ PossiblyContainsImportMeta = 1 << 20, + + JSDoc = 1 << 21, // If node was parsed inside jsdoc + /* @internal */ Ambient = 1 << 22, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier. + /* @internal */ InWithStatement = 1 << 23, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`) BlockScoped = Let | Const, @@ -514,6 +516,11 @@ namespace ts { // Exclude these flags when parsing a Type TypeExcludesFlags = YieldContext | AwaitContext, + + // Represents all flags that are potentially set once and + // never cleared on SourceFiles which get re-used in between incremental parses. + // See the comment above on `PossiblyContainsDynamicImport` and `PossiblyContainsImportMeta`. + /* @internal */ PermanentlySetIncrementalFlags = PossiblyContainsDynamicImport | PossiblyContainsImportMeta, } export const enum ModifierFlags { @@ -1754,7 +1761,7 @@ namespace ts { // for the same reasons we treat NewExpression as a PrimaryExpression. export interface MetaProperty extends PrimaryExpression { kind: SyntaxKind.MetaProperty; - keywordToken: SyntaxKind.NewKeyword; + keywordToken: SyntaxKind.NewKeyword | SyntaxKind.ImportKeyword; name: Identifier; } From f0081f0a049e2b4b3116eb9bdea84db1b19ccfc5 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 10 Apr 2018 12:59:03 -0700 Subject: [PATCH 04/15] Basic checking for 'import.meta'. --- src/compiler/checker.ts | 35 +++++++++++++++++++++++++++++++---- src/lib/es5.d.ts | 4 ++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5634e06d5fd2b..444a23881c92e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -434,6 +434,7 @@ namespace ts { let deferredGlobalAsyncIteratorType: GenericType; let deferredGlobalAsyncIterableIteratorType: GenericType; let deferredGlobalTemplateStringsArrayType: ObjectType; + let deferredGlobalImportMetaType: ObjectType; let deferredNodes: Node[]; const allPotentiallyUnusedIdentifiers = createMap>(); // key is file name @@ -7708,6 +7709,10 @@ namespace ts { return deferredGlobalTemplateStringsArrayType || (deferredGlobalTemplateStringsArrayType = getGlobalType("TemplateStringsArray" as __String, /*arity*/ 0, /*reportErrors*/ true)) || emptyObjectType; } + function getGlobalImportMetaType() { + return deferredGlobalImportMetaType || (deferredGlobalImportMetaType = getGlobalType("ImportMeta" as __String, /*arity*/ 0, /*reportErrors*/ true)) || emptyObjectType; + } + function getGlobalESSymbolConstructorSymbol(reportErrors: boolean) { return deferredGlobalESSymbolConstructorSymbol || (deferredGlobalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol" as __String, reportErrors)); } @@ -18691,6 +18696,20 @@ namespace ts { function checkMetaProperty(node: MetaProperty) { checkGrammarMetaProperty(node); + + if (node.keywordToken === SyntaxKind.NewKeyword) { + return checkNewTargetMetaProperty(node); + } + + if (node.keywordToken === SyntaxKind.ImportKeyword) { + const file = getSourceFileOfNode(node); + Debug.assert(!!(file.flags & NodeFlags.PossiblyContainsImportMeta), "Containing file is missing import meta node flag."); + Debug.assert(!!file.externalModuleIndicator, "Containing file should be a module."); + return node.name.escapedText === "meta" ? getGlobalImportMetaType() : unknownType; + } + } + + function checkNewTargetMetaProperty(node: MetaProperty) { const container = getNewTargetContainer(node); if (!container) { error(node, Diagnostics.Meta_property_0_is_only_allowed_in_the_body_of_a_function_declaration_function_expression_or_constructor, "new.target"); @@ -27554,10 +27573,18 @@ namespace ts { } function checkGrammarMetaProperty(node: MetaProperty) { - if (node.keywordToken === SyntaxKind.NewKeyword) { - if (node.name.escapedText !== "target") { - return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, node.name.escapedText, tokenToString(node.keywordToken), "target"); - } + const escapedText = node.name.escapedText; + switch (node.keywordToken) { + case SyntaxKind.NewKeyword: + if (escapedText !== "target") { + return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, node.name.escapedText, tokenToString(node.keywordToken), "target"); + } + break; + case SyntaxKind.ImportKeyword: + if (escapedText !== "meta") { + return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, node.name.escapedText, tokenToString(node.keywordToken), "meta"); + } + break; } } diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index ea59c10c83e52..cd4be60e8e42a 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -505,6 +505,10 @@ interface TemplateStringsArray extends ReadonlyArray { readonly raw: ReadonlyArray; } +interface ImportMeta { + [propertyName: string]: any; +} + interface Math { /** The mathematical constant e. This is Euler's number, the base of natural logarithms. */ readonly E: number; From 910c5d338be381b34331d12120a11bea92ba7e65 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 10 Apr 2018 12:59:38 -0700 Subject: [PATCH 05/15] Accepted baselines. --- .../reference/api/tsserverlibrary.d.ts | 6 +- tests/baselines/reference/api/typescript.d.ts | 6 +- .../baselines/reference/importMeta.errors.txt | 107 +++--------------- tests/baselines/reference/importMeta.js | 17 ++- tests/baselines/reference/importMeta.symbols | 11 -- tests/baselines/reference/importMeta.types | 35 ++++-- 6 files changed, 50 insertions(+), 132 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index a990c0af27415..12231a0fa76cb 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -414,11 +414,11 @@ declare namespace ts { JavaScriptFile = 65536, ThisNodeOrAnySubNodesHasError = 131072, HasAggregatedChildData = 262144, - JSDoc = 1048576, + JSDoc = 2097152, BlockScoped = 3, ReachabilityCheckFlags = 384, ReachabilityAndEmitFlags = 1408, - ContextFlags = 6387712, + ContextFlags = 12679168, TypeExcludesFlags = 20480 } enum ModifierFlags { @@ -1070,7 +1070,7 @@ declare namespace ts { } interface MetaProperty extends PrimaryExpression { kind: SyntaxKind.MetaProperty; - keywordToken: SyntaxKind.NewKeyword; + keywordToken: SyntaxKind.NewKeyword | SyntaxKind.ImportKeyword; name: Identifier; } interface JsxElement extends PrimaryExpression { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 5b6ef18b680eb..3e20ece19b617 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -414,11 +414,11 @@ declare namespace ts { JavaScriptFile = 65536, ThisNodeOrAnySubNodesHasError = 131072, HasAggregatedChildData = 262144, - JSDoc = 1048576, + JSDoc = 2097152, BlockScoped = 3, ReachabilityCheckFlags = 384, ReachabilityAndEmitFlags = 1408, - ContextFlags = 6387712, + ContextFlags = 12679168, TypeExcludesFlags = 20480 } enum ModifierFlags { @@ -1070,7 +1070,7 @@ declare namespace ts { } interface MetaProperty extends PrimaryExpression { kind: SyntaxKind.MetaProperty; - keywordToken: SyntaxKind.NewKeyword; + keywordToken: SyntaxKind.NewKeyword | SyntaxKind.ImportKeyword; name: Identifier; } interface JsxElement extends PrimaryExpression { diff --git a/tests/baselines/reference/importMeta.errors.txt b/tests/baselines/reference/importMeta.errors.txt index 498da8efdc13b..146b7afc21163 100644 --- a/tests/baselines/reference/importMeta.errors.txt +++ b/tests/baselines/reference/importMeta.errors.txt @@ -1,70 +1,21 @@ error TS2468: Cannot find global value 'Promise'. tests/cases/conformance/es2019/importMeta/example.ts(2,2): error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. -tests/cases/conformance/es2019/importMeta/example.ts(3,59): error TS1135: Argument expression expected. -tests/cases/conformance/es2019/importMeta/example.ts(3,65): error TS1135: Argument expression expected. -tests/cases/conformance/es2019/importMeta/example.ts(3,66): error TS2448: Block-scoped variable 'meta' used before its declaration. -tests/cases/conformance/es2019/importMeta/example.ts(6,9): error TS2451: Cannot redeclare block-scoped variable 'size'. -tests/cases/conformance/es2019/importMeta/example.ts(6,16): error TS1109: Expression expected. -tests/cases/conformance/es2019/importMeta/example.ts(6,22): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/example.ts(6,27): error TS1005: ',' expected. -tests/cases/conformance/es2019/importMeta/example.ts(6,41): error TS1005: ',' expected. -tests/cases/conformance/es2019/importMeta/example.ts(6,49): error TS1005: ',' expected. -tests/cases/conformance/es2019/importMeta/example.ts(6,50): error TS2451: Cannot redeclare block-scoped variable 'size'. -tests/cases/conformance/es2019/importMeta/example.ts(6,55): error TS1005: ',' expected. -tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(1,16): error TS1109: Expression expected. -tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(1,22): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,16): error TS1109: Expression expected. -tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,22): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,16): error TS1109: Expression expected. -tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,22): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,23): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,29): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,30): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,36): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(1,15): error TS1109: Expression expected. -tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(1,21): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(2,15): error TS1109: Expression expected. -tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(2,21): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,15): error TS1109: Expression expected. -tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,21): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,22): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,28): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,29): error TS1134: Variable declaration expected. -tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,35): error TS1134: Variable declaration expected. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,23): error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,23): error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(2,22): error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,22): error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? !!! error TS2468: Cannot find global value 'Promise'. -==== tests/cases/conformance/es2019/importMeta/example.ts (12 errors) ==== +==== tests/cases/conformance/es2019/importMeta/example.ts (1 errors) ==== // Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example (async () => { ~~~~~~~~~~~~~ !!! error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); - ~~~~~~ -!!! error TS1135: Argument expression expected. - ~ -!!! error TS1135: Argument expression expected. - ~~~~ -!!! error TS2448: Block-scoped variable 'meta' used before its declaration. const blob = await response.blob(); const size = import.meta.scriptElement.dataset.size || 300; - ~~~~ -!!! error TS2451: Cannot redeclare block-scoped variable 'size'. - ~~~~~~ -!!! error TS1109: Expression expected. - ~ -!!! error TS1134: Variable declaration expected. - ~ -!!! error TS1005: ',' expected. - ~ -!!! error TS1005: ',' expected. - ~ -!!! error TS1005: ',' expected. - ~~~~ -!!! error TS2451: Cannot redeclare block-scoped variable 'size'. - ~~ -!!! error TS1005: ',' expected. const image = new Image(); image.src = URL.createObjectURL(blob); @@ -73,53 +24,21 @@ tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,35): error TS document.body.appendChild(image); })(); -==== tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts (10 errors) ==== +==== tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts (2 errors) ==== export let x = import.meta; - ~~~~~~ -!!! error TS1109: Expression expected. - ~ -!!! error TS1134: Variable declaration expected. export let y = import.metal; - ~~~~~~ -!!! error TS1109: Expression expected. - ~ -!!! error TS1134: Variable declaration expected. + ~~~~~ +!!! error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? export let z = import.import.import.malkovich; - ~~~~~~ -!!! error TS1109: Expression expected. - ~ -!!! error TS1134: Variable declaration expected. ~~~~~~ -!!! error TS1134: Variable declaration expected. - ~ -!!! error TS1134: Variable declaration expected. - ~~~~~~ -!!! error TS1134: Variable declaration expected. - ~ -!!! error TS1134: Variable declaration expected. +!!! error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? -==== tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts (10 errors) ==== +==== tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts (2 errors) ==== let globalA = import.meta; - ~~~~~~ -!!! error TS1109: Expression expected. - ~ -!!! error TS1134: Variable declaration expected. let globalB = import.metal; - ~~~~~~ -!!! error TS1109: Expression expected. - ~ -!!! error TS1134: Variable declaration expected. + ~~~~~ +!!! error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? let globalC = import.import.import.malkovich; - ~~~~~~ -!!! error TS1109: Expression expected. - ~ -!!! error TS1134: Variable declaration expected. ~~~~~~ -!!! error TS1134: Variable declaration expected. - ~ -!!! error TS1134: Variable declaration expected. - ~~~~~~ -!!! error TS1134: Variable declaration expected. - ~ -!!! error TS1134: Variable declaration expected. +!!! error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? \ No newline at end of file diff --git a/tests/baselines/reference/importMeta.js b/tests/baselines/reference/importMeta.js index 9391dbc4899b2..34148382d701c 100644 --- a/tests/baselines/reference/importMeta.js +++ b/tests/baselines/reference/importMeta.js @@ -29,20 +29,19 @@ let globalC = import.import.import.malkovich; //// [example.js] // Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example (async () => { - const response = await fetch(new URL("../hamsters.jpg", meta.url).toString()); + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); const blob = await response.blob(); - const size = , meta, scriptElement, dataset, size; - || 300; + const size = import.meta.scriptElement.dataset.size || 300; const image = new Image(); image.src = URL.createObjectURL(blob); image.width = image.height = size; document.body.appendChild(image); })(); //// [moduleLookingFile01.js] -export let x = , meta; -export let y = , metal; -export let z = , malkovich; +export let x = import.meta; +export let y = import.metal; +export let z = import.import.import.malkovich; //// [scriptLookingFile01.js] -let globalA = , meta; -let globalB = , metal; -let globalC = , malkovich; +let globalA = import.meta; +let globalB = import.metal; +let globalC = import.import.import.malkovich; diff --git a/tests/baselines/reference/importMeta.symbols b/tests/baselines/reference/importMeta.symbols index cff36047d37f0..fa95f49855436 100644 --- a/tests/baselines/reference/importMeta.symbols +++ b/tests/baselines/reference/importMeta.symbols @@ -6,7 +6,6 @@ >fetch : Symbol(fetch, Decl(lib.dom.d.ts, --, --)) >new URL("../hamsters.jpg", import.meta.url).toString : Symbol(URL.toString, Decl(lib.dom.d.ts, --, --)) >URL : Symbol(URL, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) ->meta : Symbol(meta, Decl(example.ts, 5, 22)) >toString : Symbol(URL.toString, Decl(lib.dom.d.ts, --, --)) const blob = await response.blob(); @@ -17,10 +16,6 @@ const size = import.meta.scriptElement.dataset.size || 300; >size : Symbol(size, Decl(example.ts, 5, 7)) ->meta : Symbol(meta, Decl(example.ts, 5, 22)) ->scriptElement : Symbol(scriptElement, Decl(example.ts, 5, 27)) ->dataset : Symbol(dataset, Decl(example.ts, 5, 41)) ->size : Symbol(size, Decl(example.ts, 5, 49)) const image = new Image(); >image : Symbol(image, Decl(example.ts, 7, 7)) @@ -57,26 +52,20 @@ === tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts === export let x = import.meta; >x : Symbol(x, Decl(moduleLookingFile01.ts, 0, 10)) ->meta : Symbol(meta, Decl(moduleLookingFile01.ts, 0, 22)) export let y = import.metal; >y : Symbol(y, Decl(moduleLookingFile01.ts, 1, 10)) ->metal : Symbol(metal, Decl(moduleLookingFile01.ts, 1, 22)) export let z = import.import.import.malkovich; >z : Symbol(z, Decl(moduleLookingFile01.ts, 2, 10)) ->malkovich : Symbol(malkovich, Decl(moduleLookingFile01.ts, 2, 36)) === tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts === let globalA = import.meta; >globalA : Symbol(globalA, Decl(scriptLookingFile01.ts, 0, 3)) ->meta : Symbol(meta, Decl(scriptLookingFile01.ts, 0, 21)) let globalB = import.metal; >globalB : Symbol(globalB, Decl(scriptLookingFile01.ts, 1, 3)) ->metal : Symbol(metal, Decl(scriptLookingFile01.ts, 1, 21)) let globalC = import.import.import.malkovich; >globalC : Symbol(globalC, Decl(scriptLookingFile01.ts, 2, 3)) ->malkovich : Symbol(malkovich, Decl(scriptLookingFile01.ts, 2, 35)) diff --git a/tests/baselines/reference/importMeta.types b/tests/baselines/reference/importMeta.types index 5004627cb4c15..04384789f0638 100644 --- a/tests/baselines/reference/importMeta.types +++ b/tests/baselines/reference/importMeta.types @@ -15,7 +15,8 @@ >new URL("../hamsters.jpg", import.meta.url) : URL >URL : { new (url: string, base?: string | URL): URL; prototype: URL; createObjectURL(object: any, options?: ObjectURLOptions): string; revokeObjectURL(url: string): void; } >"../hamsters.jpg" : "../hamsters.jpg" ->meta.url : any +>import.meta.url : any +>import.meta : ImportMeta >meta : any >url : any >toString : () => string @@ -30,13 +31,15 @@ const size = import.meta.scriptElement.dataset.size || 300; >size : any -> : any +>import.meta.scriptElement.dataset.size || 300 : any +>import.meta.scriptElement.dataset.size : any +>import.meta.scriptElement.dataset : any +>import.meta.scriptElement : any +>import.meta : ImportMeta >meta : any >scriptElement : any >dataset : any >size : any ->|| 300 : any -> : any >300 : 300 const image = new Image(); @@ -79,33 +82,41 @@ === tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts === export let x = import.meta; ->x : any -> : any +>x : ImportMeta +>import.meta : ImportMeta >meta : any export let y = import.metal; >y : any -> : any +>import.metal : any >metal : any export let z = import.import.import.malkovich; >z : any -> : any +>import.import.import.malkovich : any +>import.import.import : any +>import.import : any +>import : any +>import : any >malkovich : any === tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts === let globalA = import.meta; ->globalA : any -> : any +>globalA : ImportMeta +>import.meta : ImportMeta >meta : any let globalB = import.metal; >globalB : any -> : any +>import.metal : any >metal : any let globalC = import.import.import.malkovich; >globalC : any -> : any +>import.import.import.malkovich : any +>import.import.import : any +>import.import : any +>import : any +>import : any >malkovich : any From 7c0f249619877ea3f1619c686adf0348e4328654 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 10 Apr 2018 16:10:04 -0700 Subject: [PATCH 06/15] Added semicolon. --- src/compiler/parser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e9a685d9d267a..d61a57ce5aeac 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6128,7 +6128,7 @@ namespace ts { || node.kind === SyntaxKind.ExportDeclaration || isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta" ? node - : undefined + : undefined; } function walkTreeForExternalModuleIndicators(node: Node): Node { From 56f4b2eea43537c8cde20db63b4b2b3592dac8af Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 10 Apr 2018 16:12:00 -0700 Subject: [PATCH 07/15] Provide an error when using 'import.meta' without setting 'esnext'. --- src/compiler/checker.ts | 15 +++++++++++---- src/compiler/diagnosticMessages.json | 4 ++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 444a23881c92e..b2e4e3b937724 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18702,10 +18702,7 @@ namespace ts { } if (node.keywordToken === SyntaxKind.ImportKeyword) { - const file = getSourceFileOfNode(node); - Debug.assert(!!(file.flags & NodeFlags.PossiblyContainsImportMeta), "Containing file is missing import meta node flag."); - Debug.assert(!!file.externalModuleIndicator, "Containing file should be a module."); - return node.name.escapedText === "meta" ? getGlobalImportMetaType() : unknownType; + return checkImportMetaProperty(node); } } @@ -18725,6 +18722,16 @@ namespace ts { } } + function checkImportMetaProperty(node: MetaProperty) { + if (languageVersion < ScriptTarget.ESNext && modulekind < ModuleKind.ESNext) { + error(node, Diagnostics.The_import_meta_meta_property_is_only_allowed_using_ESNext_for_the_target_and_module_compiler_options); + } + const file = getSourceFileOfNode(node); + Debug.assert(!!(file.flags & NodeFlags.PossiblyContainsImportMeta), "Containing file is missing import meta node flag."); + Debug.assert(!!file.externalModuleIndicator, "Containing file should be a module."); + return node.name.escapedText === "meta" ? getGlobalImportMetaType() : unknownType; + } + function getTypeOfParameter(symbol: Symbol) { const type = getTypeOfSymbol(symbol); if (strictNullChecks) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 69a90fbabf5b4..b91165ea17b59 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -967,6 +967,10 @@ "category": "Error", "code": 1342 }, + "The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options.": { + "category": "Error", + "code": 1343 + }, "Duplicate identifier '{0}'.": { "category": "Error", From 4f497e6c0c250d68af4ae9045922eace82d3750f Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 10 Apr 2018 16:28:50 -0700 Subject: [PATCH 08/15] Added tests around ES5, assigning to 'import.meta' and properties, global augmentations. --- .../es2019/importMeta/importMeta.ts | 13 ++++++ .../es2019/importMeta/importMetaES5.ts | 42 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 tests/cases/conformance/es2019/importMeta/importMetaES5.ts diff --git a/tests/cases/conformance/es2019/importMeta/importMeta.ts b/tests/cases/conformance/es2019/importMeta/importMeta.ts index f23410fc53611..c5022cf4abe26 100644 --- a/tests/cases/conformance/es2019/importMeta/importMeta.ts +++ b/tests/cases/conformance/es2019/importMeta/importMeta.ts @@ -26,3 +26,16 @@ export let z = import.import.import.malkovich; let globalA = import.meta; let globalB = import.metal; let globalC = import.import.import.malkovich; + +// @Filename: assignmentTargets.ts +export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; +import.meta = foo; + +// @Filename augmentations.ts +declare global { + interface ImportMeta { + wellKnownProperty: { a: number, b: string, c: boolean }; + } +} + +const { a, b, c } = import.meta.wellKnownProperty; \ No newline at end of file diff --git a/tests/cases/conformance/es2019/importMeta/importMetaES5.ts b/tests/cases/conformance/es2019/importMeta/importMetaES5.ts new file mode 100644 index 0000000000000..b11a32ecc9b22 --- /dev/null +++ b/tests/cases/conformance/es2019/importMeta/importMetaES5.ts @@ -0,0 +1,42 @@ + +// @target: es5 +// @module: commonjs +// @lib: es5,dom + +// @Filename: example.ts +// Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example +(async () => { + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); + const blob = await response.blob(); + + const size = import.meta.scriptElement.dataset.size || 300; + + const image = new Image(); + image.src = URL.createObjectURL(blob); + image.width = image.height = size; + + document.body.appendChild(image); +})(); + +// @Filename: moduleLookingFile01.ts +export let x = import.meta; +export let y = import.metal; +export let z = import.import.import.malkovich; + +// @Filename: scriptLookingFile01.ts +let globalA = import.meta; +let globalB = import.metal; +let globalC = import.import.import.malkovich; + +// @Filename: assignmentTargets.ts +export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; +import.meta = foo; + +// @Filename augmentations.ts +declare global { + interface ImportMeta { + wellKnownProperty: { a: number, b: string, c: boolean }; + } +} + +const { a, b, c } = import.meta.wellKnownProperty; \ No newline at end of file From 1ea269af87787a2dbdde4e542936dc56905675bc Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 10 Apr 2018 16:29:05 -0700 Subject: [PATCH 09/15] Accepted baselines. --- .../baselines/reference/importMeta.errors.txt | 17 +- tests/baselines/reference/importMeta.js | 16 ++ tests/baselines/reference/importMeta.symbols | 30 ++++ tests/baselines/reference/importMeta.types | 47 +++++ .../reference/importMetaES5.errors.txt | 98 ++++++++++ tests/baselines/reference/importMetaES5.js | 117 ++++++++++++ .../baselines/reference/importMetaES5.symbols | 101 +++++++++++ tests/baselines/reference/importMetaES5.types | 169 ++++++++++++++++++ 8 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/importMetaES5.errors.txt create mode 100644 tests/baselines/reference/importMetaES5.js create mode 100644 tests/baselines/reference/importMetaES5.symbols create mode 100644 tests/baselines/reference/importMetaES5.types diff --git a/tests/baselines/reference/importMeta.errors.txt b/tests/baselines/reference/importMeta.errors.txt index 146b7afc21163..2c44876fe23f1 100644 --- a/tests/baselines/reference/importMeta.errors.txt +++ b/tests/baselines/reference/importMeta.errors.txt @@ -1,4 +1,5 @@ error TS2468: Cannot find global value 'Promise'. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(2,1): error TS2364: The left-hand side of an assignment expression must be a variable or a property access. tests/cases/conformance/es2019/importMeta/example.ts(2,2): error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,23): error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,23): error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? @@ -41,4 +42,18 @@ tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,22): error TS let globalC = import.import.import.malkovich; ~~~~~~ !!! error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? - \ No newline at end of file + +==== tests/cases/conformance/es2019/importMeta/assignmentTargets.ts (1 errors) ==== + export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; + import.meta = foo; + ~~~~~~~~~~~ +!!! error TS2364: The left-hand side of an assignment expression must be a variable or a property access. + + // @Filename augmentations.ts + declare global { + interface ImportMeta { + wellKnownProperty: { a: number, b: string, c: boolean }; + } + } + + const { a, b, c } = import.meta.wellKnownProperty; \ No newline at end of file diff --git a/tests/baselines/reference/importMeta.js b/tests/baselines/reference/importMeta.js index 34148382d701c..4b6fa5436f567 100644 --- a/tests/baselines/reference/importMeta.js +++ b/tests/baselines/reference/importMeta.js @@ -25,6 +25,18 @@ let globalA = import.meta; let globalB = import.metal; let globalC = import.import.import.malkovich; +//// [assignmentTargets.ts] +export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; +import.meta = foo; + +// @Filename augmentations.ts +declare global { + interface ImportMeta { + wellKnownProperty: { a: number, b: string, c: boolean }; + } +} + +const { a, b, c } = import.meta.wellKnownProperty; //// [example.js] // Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example @@ -45,3 +57,7 @@ export let z = import.import.import.malkovich; let globalA = import.meta; let globalB = import.metal; let globalC = import.import.import.malkovich; +//// [assignmentTargets.js] +export const foo = import.meta.blah = import.meta.blue = import.meta; +import.meta = foo; +const { a, b, c } = import.meta.wellKnownProperty; diff --git a/tests/baselines/reference/importMeta.symbols b/tests/baselines/reference/importMeta.symbols index fa95f49855436..58d8f9807d4c1 100644 --- a/tests/baselines/reference/importMeta.symbols +++ b/tests/baselines/reference/importMeta.symbols @@ -69,3 +69,33 @@ let globalB = import.metal; let globalC = import.import.import.malkovich; >globalC : Symbol(globalC, Decl(scriptLookingFile01.ts, 2, 3)) +=== tests/cases/conformance/es2019/importMeta/assignmentTargets.ts === +export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; +>foo : Symbol(foo, Decl(assignmentTargets.ts, 0, 12)) +>ImportMeta : Symbol(ImportMeta, Decl(lib.es5.d.ts, --, --), Decl(assignmentTargets.ts, 4, 16)) + +import.meta = foo; +>foo : Symbol(foo, Decl(assignmentTargets.ts, 0, 12)) + +// @Filename augmentations.ts +declare global { +>global : Symbol(global, Decl(assignmentTargets.ts, 1, 18)) + + interface ImportMeta { +>ImportMeta : Symbol(ImportMeta, Decl(lib.es5.d.ts, --, --), Decl(assignmentTargets.ts, 4, 16)) + + wellKnownProperty: { a: number, b: string, c: boolean }; +>wellKnownProperty : Symbol(ImportMeta.wellKnownProperty, Decl(assignmentTargets.ts, 5, 24)) +>a : Symbol(a, Decl(assignmentTargets.ts, 6, 24)) +>b : Symbol(b, Decl(assignmentTargets.ts, 6, 35)) +>c : Symbol(c, Decl(assignmentTargets.ts, 6, 46)) + } +} + +const { a, b, c } = import.meta.wellKnownProperty; +>a : Symbol(a, Decl(assignmentTargets.ts, 10, 7)) +>b : Symbol(b, Decl(assignmentTargets.ts, 10, 10)) +>c : Symbol(c, Decl(assignmentTargets.ts, 10, 13)) +>import.meta.wellKnownProperty : Symbol(ImportMeta.wellKnownProperty, Decl(assignmentTargets.ts, 5, 24)) +>wellKnownProperty : Symbol(ImportMeta.wellKnownProperty, Decl(assignmentTargets.ts, 5, 24)) + diff --git a/tests/baselines/reference/importMeta.types b/tests/baselines/reference/importMeta.types index 04384789f0638..c6140c8d05d03 100644 --- a/tests/baselines/reference/importMeta.types +++ b/tests/baselines/reference/importMeta.types @@ -120,3 +120,50 @@ let globalC = import.import.import.malkovich; >import : any >malkovich : any +=== tests/cases/conformance/es2019/importMeta/assignmentTargets.ts === +export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; +>foo : ImportMeta +>ImportMeta : ImportMeta +>import.meta.blah = import.meta.blue = import.meta : ImportMeta +>import.meta.blah : any +>import.meta : ImportMeta +>meta : any +>blah : any +>import.meta.blue = import.meta : ImportMeta +>import.meta.blue : any +>import.meta : ImportMeta +>meta : any +>blue : any +>import.meta : ImportMeta +>meta : any + +import.meta = foo; +>import.meta = foo : ImportMeta +>import.meta : ImportMeta +>meta : any +>foo : ImportMeta + +// @Filename augmentations.ts +declare global { +>global : any + + interface ImportMeta { +>ImportMeta : ImportMeta + + wellKnownProperty: { a: number, b: string, c: boolean }; +>wellKnownProperty : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + } +} + +const { a, b, c } = import.meta.wellKnownProperty; +>a : number +>b : string +>c : boolean +>import.meta.wellKnownProperty : { a: number; b: string; c: boolean; } +>import.meta : ImportMeta +>meta : any +>wellKnownProperty : { a: number; b: string; c: boolean; } + diff --git a/tests/baselines/reference/importMetaES5.errors.txt b/tests/baselines/reference/importMetaES5.errors.txt new file mode 100644 index 0000000000000..46cc1107f6927 --- /dev/null +++ b/tests/baselines/reference/importMetaES5.errors.txt @@ -0,0 +1,98 @@ +error TS2468: Cannot find global value 'Promise'. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(1,32): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(1,51): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(1,70): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(2,1): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(2,1): error TS2364: The left-hand side of an assignment expression must be a variable or a property access. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(11,21): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/example.ts(2,2): error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. +tests/cases/conformance/es2019/importMeta/example.ts(3,59): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/example.ts(6,16): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(1,16): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,16): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,23): error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,16): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,23): error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(1,15): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(2,15): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(2,22): error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,15): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,22): error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? + + +!!! error TS2468: Cannot find global value 'Promise'. +==== tests/cases/conformance/es2019/importMeta/example.ts (3 errors) ==== + // Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example + (async () => { + ~~~~~~~~~~~~~ +!!! error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); + ~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + const blob = await response.blob(); + + const size = import.meta.scriptElement.dataset.size || 300; + ~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + + const image = new Image(); + image.src = URL.createObjectURL(blob); + image.width = image.height = size; + + document.body.appendChild(image); + })(); + +==== tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts (5 errors) ==== + export let x = import.meta; + ~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + export let y = import.metal; + ~~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~~~ +!!! error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? + export let z = import.import.import.malkovich; + ~~~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~~~~ +!!! error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? + +==== tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts (5 errors) ==== + let globalA = import.meta; + ~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + let globalB = import.metal; + ~~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~~~ +!!! error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? + let globalC = import.import.import.malkovich; + ~~~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~~~~ +!!! error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? + +==== tests/cases/conformance/es2019/importMeta/assignmentTargets.ts (6 errors) ==== + export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; + ~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + import.meta = foo; + ~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~~~~~~~~~ +!!! error TS2364: The left-hand side of an assignment expression must be a variable or a property access. + + // @Filename augmentations.ts + declare global { + interface ImportMeta { + wellKnownProperty: { a: number, b: string, c: boolean }; + } + } + + const { a, b, c } = import.meta.wellKnownProperty; + ~~~~~~~~~~~ +!!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. \ No newline at end of file diff --git a/tests/baselines/reference/importMetaES5.js b/tests/baselines/reference/importMetaES5.js new file mode 100644 index 0000000000000..8ac695412ff7e --- /dev/null +++ b/tests/baselines/reference/importMetaES5.js @@ -0,0 +1,117 @@ +//// [tests/cases/conformance/es2019/importMeta/importMetaES5.ts] //// + +//// [example.ts] +// Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example +(async () => { + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); + const blob = await response.blob(); + + const size = import.meta.scriptElement.dataset.size || 300; + + const image = new Image(); + image.src = URL.createObjectURL(blob); + image.width = image.height = size; + + document.body.appendChild(image); +})(); + +//// [moduleLookingFile01.ts] +export let x = import.meta; +export let y = import.metal; +export let z = import.import.import.malkovich; + +//// [scriptLookingFile01.ts] +let globalA = import.meta; +let globalB = import.metal; +let globalC = import.import.import.malkovich; + +//// [assignmentTargets.ts] +export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; +import.meta = foo; + +// @Filename augmentations.ts +declare global { + interface ImportMeta { + wellKnownProperty: { a: number, b: string, c: boolean }; + } +} + +const { a, b, c } = import.meta.wellKnownProperty; + +//// [example.js] +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [0, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var _this = this; +Object.defineProperty(exports, "__esModule", { value: true }); +// Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example +(function () { return __awaiter(_this, void 0, void 0, function () { + var response, blob, size, image; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, fetch(new URL("../hamsters.jpg", import.meta.url).toString())]; + case 1: + response = _a.sent(); + return [4 /*yield*/, response.blob()]; + case 2: + blob = _a.sent(); + size = import.meta.scriptElement.dataset.size || 300; + image = new Image(); + image.src = URL.createObjectURL(blob); + image.width = image.height = size; + document.body.appendChild(image); + return [2 /*return*/]; + } + }); +}); })(); +//// [moduleLookingFile01.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.x = (import.meta); +exports.y = (import.metal); +exports.z = import.import.import.malkovich; +//// [scriptLookingFile01.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var globalA = import.meta; +var globalB = import.metal; +var globalC = import.import.import.malkovich; +//// [assignmentTargets.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.foo = import.meta.blah = import.meta.blue = import.meta; +import.meta = exports.foo; +var _a = import.meta.wellKnownProperty, a = _a.a, b = _a.b, c = _a.c; diff --git a/tests/baselines/reference/importMetaES5.symbols b/tests/baselines/reference/importMetaES5.symbols new file mode 100644 index 0000000000000..58d8f9807d4c1 --- /dev/null +++ b/tests/baselines/reference/importMetaES5.symbols @@ -0,0 +1,101 @@ +=== tests/cases/conformance/es2019/importMeta/example.ts === +// Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example +(async () => { + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); +>response : Symbol(response, Decl(example.ts, 2, 7)) +>fetch : Symbol(fetch, Decl(lib.dom.d.ts, --, --)) +>new URL("../hamsters.jpg", import.meta.url).toString : Symbol(URL.toString, Decl(lib.dom.d.ts, --, --)) +>URL : Symbol(URL, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>toString : Symbol(URL.toString, Decl(lib.dom.d.ts, --, --)) + + const blob = await response.blob(); +>blob : Symbol(blob, Decl(example.ts, 3, 7)) +>response.blob : Symbol(Body.blob, Decl(lib.dom.d.ts, --, --)) +>response : Symbol(response, Decl(example.ts, 2, 7)) +>blob : Symbol(Body.blob, Decl(lib.dom.d.ts, --, --)) + + const size = import.meta.scriptElement.dataset.size || 300; +>size : Symbol(size, Decl(example.ts, 5, 7)) + + const image = new Image(); +>image : Symbol(image, Decl(example.ts, 7, 7)) +>Image : Symbol(Image, Decl(lib.dom.d.ts, --, --)) + + image.src = URL.createObjectURL(blob); +>image.src : Symbol(HTMLImageElement.src, Decl(lib.dom.d.ts, --, --)) +>image : Symbol(image, Decl(example.ts, 7, 7)) +>src : Symbol(HTMLImageElement.src, Decl(lib.dom.d.ts, --, --)) +>URL.createObjectURL : Symbol(createObjectURL, Decl(lib.dom.d.ts, --, --)) +>URL : Symbol(URL, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>createObjectURL : Symbol(createObjectURL, Decl(lib.dom.d.ts, --, --)) +>blob : Symbol(blob, Decl(example.ts, 3, 7)) + + image.width = image.height = size; +>image.width : Symbol(HTMLImageElement.width, Decl(lib.dom.d.ts, --, --)) +>image : Symbol(image, Decl(example.ts, 7, 7)) +>width : Symbol(HTMLImageElement.width, Decl(lib.dom.d.ts, --, --)) +>image.height : Symbol(HTMLImageElement.height, Decl(lib.dom.d.ts, --, --)) +>image : Symbol(image, Decl(example.ts, 7, 7)) +>height : Symbol(HTMLImageElement.height, Decl(lib.dom.d.ts, --, --)) +>size : Symbol(size, Decl(example.ts, 5, 7)) + + document.body.appendChild(image); +>document.body.appendChild : Symbol(Node.appendChild, Decl(lib.dom.d.ts, --, --)) +>document.body : Symbol(Document.body, Decl(lib.dom.d.ts, --, --)) +>document : Symbol(document, Decl(lib.dom.d.ts, --, --)) +>body : Symbol(Document.body, Decl(lib.dom.d.ts, --, --)) +>appendChild : Symbol(Node.appendChild, Decl(lib.dom.d.ts, --, --)) +>image : Symbol(image, Decl(example.ts, 7, 7)) + +})(); + +=== tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts === +export let x = import.meta; +>x : Symbol(x, Decl(moduleLookingFile01.ts, 0, 10)) + +export let y = import.metal; +>y : Symbol(y, Decl(moduleLookingFile01.ts, 1, 10)) + +export let z = import.import.import.malkovich; +>z : Symbol(z, Decl(moduleLookingFile01.ts, 2, 10)) + +=== tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts === +let globalA = import.meta; +>globalA : Symbol(globalA, Decl(scriptLookingFile01.ts, 0, 3)) + +let globalB = import.metal; +>globalB : Symbol(globalB, Decl(scriptLookingFile01.ts, 1, 3)) + +let globalC = import.import.import.malkovich; +>globalC : Symbol(globalC, Decl(scriptLookingFile01.ts, 2, 3)) + +=== tests/cases/conformance/es2019/importMeta/assignmentTargets.ts === +export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; +>foo : Symbol(foo, Decl(assignmentTargets.ts, 0, 12)) +>ImportMeta : Symbol(ImportMeta, Decl(lib.es5.d.ts, --, --), Decl(assignmentTargets.ts, 4, 16)) + +import.meta = foo; +>foo : Symbol(foo, Decl(assignmentTargets.ts, 0, 12)) + +// @Filename augmentations.ts +declare global { +>global : Symbol(global, Decl(assignmentTargets.ts, 1, 18)) + + interface ImportMeta { +>ImportMeta : Symbol(ImportMeta, Decl(lib.es5.d.ts, --, --), Decl(assignmentTargets.ts, 4, 16)) + + wellKnownProperty: { a: number, b: string, c: boolean }; +>wellKnownProperty : Symbol(ImportMeta.wellKnownProperty, Decl(assignmentTargets.ts, 5, 24)) +>a : Symbol(a, Decl(assignmentTargets.ts, 6, 24)) +>b : Symbol(b, Decl(assignmentTargets.ts, 6, 35)) +>c : Symbol(c, Decl(assignmentTargets.ts, 6, 46)) + } +} + +const { a, b, c } = import.meta.wellKnownProperty; +>a : Symbol(a, Decl(assignmentTargets.ts, 10, 7)) +>b : Symbol(b, Decl(assignmentTargets.ts, 10, 10)) +>c : Symbol(c, Decl(assignmentTargets.ts, 10, 13)) +>import.meta.wellKnownProperty : Symbol(ImportMeta.wellKnownProperty, Decl(assignmentTargets.ts, 5, 24)) +>wellKnownProperty : Symbol(ImportMeta.wellKnownProperty, Decl(assignmentTargets.ts, 5, 24)) + diff --git a/tests/baselines/reference/importMetaES5.types b/tests/baselines/reference/importMetaES5.types new file mode 100644 index 0000000000000..c6140c8d05d03 --- /dev/null +++ b/tests/baselines/reference/importMetaES5.types @@ -0,0 +1,169 @@ +=== tests/cases/conformance/es2019/importMeta/example.ts === +// Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example +(async () => { +>(async () => { const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); const blob = await response.blob(); const size = import.meta.scriptElement.dataset.size || 300; const image = new Image(); image.src = URL.createObjectURL(blob); image.width = image.height = size; document.body.appendChild(image);})() : Promise +>(async () => { const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); const blob = await response.blob(); const size = import.meta.scriptElement.dataset.size || 300; const image = new Image(); image.src = URL.createObjectURL(blob); image.width = image.height = size; document.body.appendChild(image);}) : () => Promise +>async () => { const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); const blob = await response.blob(); const size = import.meta.scriptElement.dataset.size || 300; const image = new Image(); image.src = URL.createObjectURL(blob); image.width = image.height = size; document.body.appendChild(image);} : () => Promise + + const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); +>response : Response +>await fetch(new URL("../hamsters.jpg", import.meta.url).toString()) : Response +>fetch(new URL("../hamsters.jpg", import.meta.url).toString()) : Promise +>fetch : (input?: string | Request, init?: RequestInit) => Promise +>new URL("../hamsters.jpg", import.meta.url).toString() : string +>new URL("../hamsters.jpg", import.meta.url).toString : () => string +>new URL("../hamsters.jpg", import.meta.url) : URL +>URL : { new (url: string, base?: string | URL): URL; prototype: URL; createObjectURL(object: any, options?: ObjectURLOptions): string; revokeObjectURL(url: string): void; } +>"../hamsters.jpg" : "../hamsters.jpg" +>import.meta.url : any +>import.meta : ImportMeta +>meta : any +>url : any +>toString : () => string + + const blob = await response.blob(); +>blob : Blob +>await response.blob() : Blob +>response.blob() : Promise +>response.blob : () => Promise +>response : Response +>blob : () => Promise + + const size = import.meta.scriptElement.dataset.size || 300; +>size : any +>import.meta.scriptElement.dataset.size || 300 : any +>import.meta.scriptElement.dataset.size : any +>import.meta.scriptElement.dataset : any +>import.meta.scriptElement : any +>import.meta : ImportMeta +>meta : any +>scriptElement : any +>dataset : any +>size : any +>300 : 300 + + const image = new Image(); +>image : HTMLImageElement +>new Image() : HTMLImageElement +>Image : new (width?: number, height?: number) => HTMLImageElement + + image.src = URL.createObjectURL(blob); +>image.src = URL.createObjectURL(blob) : string +>image.src : string +>image : HTMLImageElement +>src : string +>URL.createObjectURL(blob) : string +>URL.createObjectURL : (object: any, options?: ObjectURLOptions) => string +>URL : { new (url: string, base?: string | URL): URL; prototype: URL; createObjectURL(object: any, options?: ObjectURLOptions): string; revokeObjectURL(url: string): void; } +>createObjectURL : (object: any, options?: ObjectURLOptions) => string +>blob : Blob + + image.width = image.height = size; +>image.width = image.height = size : any +>image.width : number +>image : HTMLImageElement +>width : number +>image.height = size : any +>image.height : number +>image : HTMLImageElement +>height : number +>size : any + + document.body.appendChild(image); +>document.body.appendChild(image) : HTMLImageElement +>document.body.appendChild : (newChild: T) => T +>document.body : HTMLElement +>document : Document +>body : HTMLElement +>appendChild : (newChild: T) => T +>image : HTMLImageElement + +})(); + +=== tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts === +export let x = import.meta; +>x : ImportMeta +>import.meta : ImportMeta +>meta : any + +export let y = import.metal; +>y : any +>import.metal : any +>metal : any + +export let z = import.import.import.malkovich; +>z : any +>import.import.import.malkovich : any +>import.import.import : any +>import.import : any +>import : any +>import : any +>malkovich : any + +=== tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts === +let globalA = import.meta; +>globalA : ImportMeta +>import.meta : ImportMeta +>meta : any + +let globalB = import.metal; +>globalB : any +>import.metal : any +>metal : any + +let globalC = import.import.import.malkovich; +>globalC : any +>import.import.import.malkovich : any +>import.import.import : any +>import.import : any +>import : any +>import : any +>malkovich : any + +=== tests/cases/conformance/es2019/importMeta/assignmentTargets.ts === +export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; +>foo : ImportMeta +>ImportMeta : ImportMeta +>import.meta.blah = import.meta.blue = import.meta : ImportMeta +>import.meta.blah : any +>import.meta : ImportMeta +>meta : any +>blah : any +>import.meta.blue = import.meta : ImportMeta +>import.meta.blue : any +>import.meta : ImportMeta +>meta : any +>blue : any +>import.meta : ImportMeta +>meta : any + +import.meta = foo; +>import.meta = foo : ImportMeta +>import.meta : ImportMeta +>meta : any +>foo : ImportMeta + +// @Filename augmentations.ts +declare global { +>global : any + + interface ImportMeta { +>ImportMeta : ImportMeta + + wellKnownProperty: { a: number, b: string, c: boolean }; +>wellKnownProperty : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + } +} + +const { a, b, c } = import.meta.wellKnownProperty; +>a : number +>b : string +>c : boolean +>import.meta.wellKnownProperty : { a: number; b: string; c: boolean; } +>import.meta : ImportMeta +>meta : any +>wellKnownProperty : { a: number; b: string; c: boolean; } + From 0feefab765214f080e5d8db37bde42830a1c8884 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 10 Apr 2018 16:30:02 -0700 Subject: [PATCH 10/15] 'modulekind' -> 'moduleKind' --- src/compiler/checker.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b2e4e3b937724..aa9bbccffd9ec 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -64,7 +64,7 @@ namespace ts { const compilerOptions = host.getCompilerOptions(); const languageVersion = getEmitScriptTarget(compilerOptions); - const modulekind = getEmitModuleKind(compilerOptions); + const moduleKind = getEmitModuleKind(compilerOptions); const allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions); const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks"); const strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes"); @@ -1085,7 +1085,7 @@ namespace ts { const declarationFile = getSourceFileOfNode(declaration); const useFile = getSourceFileOfNode(usage); if (declarationFile !== useFile) { - if ((modulekind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) || + if ((moduleKind && (declarationFile.externalModuleIndicator || useFile.externalModuleIndicator)) || (!compilerOptions.outFile && !compilerOptions.out) || isInTypeQuery(usage) || declaration.flags & NodeFlags.Ambient) { @@ -18723,7 +18723,7 @@ namespace ts { } function checkImportMetaProperty(node: MetaProperty) { - if (languageVersion < ScriptTarget.ESNext && modulekind < ModuleKind.ESNext) { + if (languageVersion < ScriptTarget.ESNext && moduleKind < ModuleKind.ESNext) { error(node, Diagnostics.The_import_meta_meta_property_is_only_allowed_using_ESNext_for_the_target_and_module_compiler_options); } const file = getSourceFileOfNode(node); @@ -22329,7 +22329,7 @@ namespace ts { function checkCollisionWithRequireExportsInGeneratedCode(node: Node, name: Identifier) { // No need to check for require or exports for ES6 modules and later - if (modulekind >= ModuleKind.ES2015 || compilerOptions.noEmit) { + if (moduleKind >= ModuleKind.ES2015 || compilerOptions.noEmit) { return; } @@ -24518,7 +24518,7 @@ namespace ts { } } else { - if (modulekind >= ModuleKind.ES2015 && !(node.flags & NodeFlags.Ambient)) { + if (moduleKind >= ModuleKind.ES2015 && !(node.flags & NodeFlags.Ambient)) { // Import equals declaration is deprecated in es6 or above grammarErrorOnNode(node, Diagnostics.Import_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead); } @@ -24556,7 +24556,7 @@ namespace ts { error(node.moduleSpecifier, Diagnostics.Module_0_uses_export_and_cannot_be_used_with_export_Asterisk, symbolToString(moduleSymbol)); } - if (modulekind !== ModuleKind.System && modulekind !== ModuleKind.ES2015 && modulekind !== ModuleKind.ESNext) { + if (moduleKind !== ModuleKind.System && moduleKind !== ModuleKind.ES2015 && moduleKind !== ModuleKind.ESNext) { checkExternalEmitHelpers(node, ExternalEmitHelpers.ExportStar); } } @@ -24629,11 +24629,11 @@ namespace ts { } if (node.isExportEquals && !(node.flags & NodeFlags.Ambient)) { - if (modulekind >= ModuleKind.ES2015) { + if (moduleKind >= ModuleKind.ES2015) { // export assignment is not supported in es6 modules grammarErrorOnNode(node, Diagnostics.Export_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_export_default_or_another_module_format_instead); } - else if (modulekind === ModuleKind.System) { + else if (moduleKind === ModuleKind.System) { // system modules does not support export assignment grammarErrorOnNode(node, Diagnostics.Export_assignment_is_not_supported_when_module_flag_is_system); } @@ -27790,7 +27790,7 @@ namespace ts { } function checkGrammarImportCallExpression(node: ImportCall): boolean { - if (modulekind === ModuleKind.ES2015) { + if (moduleKind === ModuleKind.ES2015) { return grammarErrorOnNode(node, Diagnostics.Dynamic_import_cannot_be_used_when_targeting_ECMAScript_2015_modules); } From a55febda779bd9c24b1d3b454860a40b351c158e Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 24 Apr 2018 12:21:36 -0700 Subject: [PATCH 11/15] Make 'ImportMeta' more minimal. --- src/lib/es5.d.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index cd4be60e8e42a..55c184f672f75 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -505,8 +505,13 @@ interface TemplateStringsArray extends ReadonlyArray { readonly raw: ReadonlyArray; } +/** + * The type of `import.meta`. + * + * If you need to declare that a given property exists on `import.meta`, + * this type may be augmented via interface merging. + */ interface ImportMeta { - [propertyName: string]: any; } interface Math { From 28f8d7532fac10e68da376bb355bf87212901f8b Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 24 Apr 2018 12:39:41 -0700 Subject: [PATCH 12/15] Accepted baselines. --- tests/baselines/reference/importMeta.errors.txt | 16 ++++++++++++++-- .../baselines/reference/importMetaES5.errors.txt | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/importMeta.errors.txt b/tests/baselines/reference/importMeta.errors.txt index 2c44876fe23f1..999c883f26618 100644 --- a/tests/baselines/reference/importMeta.errors.txt +++ b/tests/baselines/reference/importMeta.errors.txt @@ -1,6 +1,10 @@ error TS2468: Cannot find global value 'Promise'. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(1,44): error TS2339: Property 'blah' does not exist on type 'ImportMeta'. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(1,63): error TS2339: Property 'blue' does not exist on type 'ImportMeta'. tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(2,1): error TS2364: The left-hand side of an assignment expression must be a variable or a property access. tests/cases/conformance/es2019/importMeta/example.ts(2,2): error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. +tests/cases/conformance/es2019/importMeta/example.ts(3,71): error TS2339: Property 'url' does not exist on type 'ImportMeta'. +tests/cases/conformance/es2019/importMeta/example.ts(6,28): error TS2339: Property 'scriptElement' does not exist on type 'ImportMeta'. tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,23): error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(3,23): error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(2,22): error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? @@ -8,15 +12,19 @@ tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,22): error TS !!! error TS2468: Cannot find global value 'Promise'. -==== tests/cases/conformance/es2019/importMeta/example.ts (1 errors) ==== +==== tests/cases/conformance/es2019/importMeta/example.ts (3 errors) ==== // Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example (async () => { ~~~~~~~~~~~~~ !!! error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); + ~~~ +!!! error TS2339: Property 'url' does not exist on type 'ImportMeta'. const blob = await response.blob(); const size = import.meta.scriptElement.dataset.size || 300; + ~~~~~~~~~~~~~ +!!! error TS2339: Property 'scriptElement' does not exist on type 'ImportMeta'. const image = new Image(); image.src = URL.createObjectURL(blob); @@ -43,8 +51,12 @@ tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,22): error TS ~~~~~~ !!! error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? -==== tests/cases/conformance/es2019/importMeta/assignmentTargets.ts (1 errors) ==== +==== tests/cases/conformance/es2019/importMeta/assignmentTargets.ts (3 errors) ==== export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; + ~~~~ +!!! error TS2339: Property 'blah' does not exist on type 'ImportMeta'. + ~~~~ +!!! error TS2339: Property 'blue' does not exist on type 'ImportMeta'. import.meta = foo; ~~~~~~~~~~~ !!! error TS2364: The left-hand side of an assignment expression must be a variable or a property access. diff --git a/tests/baselines/reference/importMetaES5.errors.txt b/tests/baselines/reference/importMetaES5.errors.txt index 46cc1107f6927..71b67efae0143 100644 --- a/tests/baselines/reference/importMetaES5.errors.txt +++ b/tests/baselines/reference/importMetaES5.errors.txt @@ -1,13 +1,17 @@ error TS2468: Cannot find global value 'Promise'. tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(1,32): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(1,44): error TS2339: Property 'blah' does not exist on type 'ImportMeta'. tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(1,51): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(1,63): error TS2339: Property 'blue' does not exist on type 'ImportMeta'. tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(1,70): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(2,1): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(2,1): error TS2364: The left-hand side of an assignment expression must be a variable or a property access. tests/cases/conformance/es2019/importMeta/assignmentTargets.ts(11,21): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. tests/cases/conformance/es2019/importMeta/example.ts(2,2): error TS2705: An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option. tests/cases/conformance/es2019/importMeta/example.ts(3,59): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/example.ts(3,71): error TS2339: Property 'url' does not exist on type 'ImportMeta'. tests/cases/conformance/es2019/importMeta/example.ts(6,16): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. +tests/cases/conformance/es2019/importMeta/example.ts(6,28): error TS2339: Property 'scriptElement' does not exist on type 'ImportMeta'. tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(1,16): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,16): error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. tests/cases/conformance/es2019/importMeta/moduleLookingFile01.ts(2,23): error TS17012: 'metal' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? @@ -21,7 +25,7 @@ tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,22): error TS !!! error TS2468: Cannot find global value 'Promise'. -==== tests/cases/conformance/es2019/importMeta/example.ts (3 errors) ==== +==== tests/cases/conformance/es2019/importMeta/example.ts (5 errors) ==== // Adapted from https://github.com/tc39/proposal-import-meta/tree/c3902a9ffe2e69a7ac42c19d7ea74cbdcea9b7fb#example (async () => { ~~~~~~~~~~~~~ @@ -29,11 +33,15 @@ tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,22): error TS const response = await fetch(new URL("../hamsters.jpg", import.meta.url).toString()); ~~~~~~~~~~~ !!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~ +!!! error TS2339: Property 'url' does not exist on type 'ImportMeta'. const blob = await response.blob(); const size = import.meta.scriptElement.dataset.size || 300; ~~~~~~~~~~~ !!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~~~~~~~~~~~ +!!! error TS2339: Property 'scriptElement' does not exist on type 'ImportMeta'. const image = new Image(); image.src = URL.createObjectURL(blob); @@ -72,12 +80,16 @@ tests/cases/conformance/es2019/importMeta/scriptLookingFile01.ts(3,22): error TS ~~~~~~ !!! error TS17012: 'import' is not a valid meta-property for keyword 'import'. Did you mean 'meta'? -==== tests/cases/conformance/es2019/importMeta/assignmentTargets.ts (6 errors) ==== +==== tests/cases/conformance/es2019/importMeta/assignmentTargets.ts (8 errors) ==== export const foo: ImportMeta = import.meta.blah = import.meta.blue = import.meta; ~~~~~~~~~~~ !!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~~ +!!! error TS2339: Property 'blah' does not exist on type 'ImportMeta'. ~~~~~~~~~~~ !!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. + ~~~~ +!!! error TS2339: Property 'blue' does not exist on type 'ImportMeta'. ~~~~~~~~~~~ !!! error TS1343: The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options. import.meta = foo; From bc0d3e129700b6dda0fb504c5c55bf95f7a4f7d7 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 27 Apr 2018 17:19:57 -0700 Subject: [PATCH 13/15] Look for top-level imports/exports before diving into the tree. --- src/compiler/parser.ts | 24 +++++++++++++++--------- src/compiler/types.ts | 6 +++++- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 12e498787c82e..32e7ca19dd313 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6139,14 +6139,11 @@ namespace ts { } function setExternalModuleIndicator(sourceFile: SourceFile) { - // Usually we'd like to avoid a full tree walk, but it's possible - // that we have a deeper external module indicator (e.g. `import.meta`, - // and possibly nested import statements in the future). - // Ideally the first few statements will be an import/export anyway. + // Try to use the first top-level import/export when available, then + // fall back to looking for an 'import.meta' somewhere in the tree if necessary. sourceFile.externalModuleIndicator = - !(sourceFile.flags & NodeFlags.PossiblyContainsImportMeta) ? - forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) : - walkTreeForExternalModuleIndicators(sourceFile); + forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) || + getImportMetaIfNecessary(sourceFile); } function isAnExternalModuleIndicatorNode(node: Node) { @@ -6155,13 +6152,22 @@ namespace ts { || node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ExportAssignment || node.kind === SyntaxKind.ExportDeclaration - || isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta" ? node : undefined; } + function getImportMetaIfNecessary(sourceFile: SourceFile) { + return sourceFile.flags & NodeFlags.PossiblyContainsImportMeta ? + walkTreeForExternalModuleIndicators(sourceFile) : + undefined; + } + function walkTreeForExternalModuleIndicators(node: Node): Node { - return isAnExternalModuleIndicatorNode(node) ? node : forEachChild(node, walkTreeForExternalModuleIndicators); + return isImportMeta(node) ? node : forEachChild(node, walkTreeForExternalModuleIndicators); + } + + function isImportMeta(node: Node): boolean { + return isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta"; } const enum ParsingContext { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c678c4dab93e1..2622fe3f5e44a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2564,7 +2564,11 @@ namespace ts { languageVersion: ScriptTarget; /* @internal */ scriptKind: ScriptKind; - // The first node that causes this file to be an external module + /** + * The first "most obvious" node that makes a file an external module. + * This is intended to be the first top-level import/export, + * but could be arbitrarily nested (e.g. `import.meta`). + */ /* @internal */ externalModuleIndicator: Node; // The first node that causes this file to be a CommonJS module /* @internal */ commonJsModuleIndicator: Node; From 161535bc848d750de4d266d3c2f829ac1662bbcc Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 27 Apr 2018 17:51:18 -0700 Subject: [PATCH 14/15] Check for both 'module' and 'target'. --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 499beb6e87dc1..e43766d54569c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18812,7 +18812,7 @@ namespace ts { } function checkImportMetaProperty(node: MetaProperty) { - if (languageVersion < ScriptTarget.ESNext && moduleKind < ModuleKind.ESNext) { + if (languageVersion < ScriptTarget.ESNext || moduleKind < ModuleKind.ESNext) { error(node, Diagnostics.The_import_meta_meta_property_is_only_allowed_using_ESNext_for_the_target_and_module_compiler_options); } const file = getSourceFileOfNode(node); From 12a3e39dcacc4180ab9beb17b35431ca1d598d83 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 27 Apr 2018 18:17:44 -0700 Subject: [PATCH 15/15] Specify ESNext module in test. --- tests/cases/conformance/es2019/importMeta/importMeta.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cases/conformance/es2019/importMeta/importMeta.ts b/tests/cases/conformance/es2019/importMeta/importMeta.ts index c5022cf4abe26..71d635a6534cc 100644 --- a/tests/cases/conformance/es2019/importMeta/importMeta.ts +++ b/tests/cases/conformance/es2019/importMeta/importMeta.ts @@ -1,5 +1,6 @@ // @target: esnext +// @module: esnext // @lib: es5,dom // @Filename: example.ts