diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts
index d4cccf374ec7d..952266d5ebcce 100644
--- a/src/services/findAllReferences.ts
+++ b/src/services/findAllReferences.ts
@@ -890,6 +890,10 @@ namespace ts.FindAllReferences {
node.kind === SyntaxKind.ReadonlyKeyword ? isReadonlyTypeOperator : undefined);
}
+ if (isImportMeta(node.parent) && node.parent.name === node) {
+ return getAllReferencesForImportMeta(sourceFiles, cancellationToken);
+ }
+
if (isStaticModifier(node) && isClassStaticBlockDeclaration(node.parent)) {
return [{ definition: { type: DefinitionKind.Keyword, node }, references: [nodeEntry(node)] }];
}
@@ -1435,6 +1439,19 @@ namespace ts.FindAllReferences {
}
}
+ function getAllReferencesForImportMeta(sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined {
+ const references = flatMap(sourceFiles, sourceFile => {
+ cancellationToken.throwIfCancellationRequested();
+ return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, "meta", sourceFile), node => {
+ const parent = node.parent;
+ if (isImportMeta(parent)) {
+ return nodeEntry(parent);
+ }
+ });
+ });
+ return references.length ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined;
+ }
+
function getAllReferencesForKeyword(sourceFiles: readonly SourceFile[], keywordKind: SyntaxKind, cancellationToken: CancellationToken, filter?: (node: Node) => boolean): SymbolAndEntries[] | undefined {
const references = flatMap(sourceFiles, sourceFile => {
cancellationToken.throwIfCancellationRequested();
diff --git a/src/services/goToDefinition.ts b/src/services/goToDefinition.ts
index 2464b6d967232..3b49ec4b64610 100644
--- a/src/services/goToDefinition.ts
+++ b/src/services/goToDefinition.ts
@@ -198,6 +198,10 @@ namespace ts.GoToDefinition {
return undefined;
}
+ if (isImportMeta(node.parent) && node.parent.name === node) {
+ return definitionFromType(typeChecker.getTypeAtLocation(node.parent), typeChecker, node.parent);
+ }
+
const symbol = getSymbol(node, typeChecker);
if (!symbol) return undefined;
diff --git a/src/services/services.ts b/src/services/services.ts
index fa56017da5e16..6d144565dcc57 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -1724,6 +1724,9 @@ namespace ts {
if (isNamedTupleMember(node.parent) && node.pos === node.parent.pos) {
return node.parent;
}
+ if (isImportMeta(node.parent) && node.parent.name === node) {
+ return node.parent;
+ }
return node;
}
@@ -1740,6 +1743,8 @@ namespace ts {
case SyntaxKind.SuperKeyword:
case SyntaxKind.NamedTupleMember:
return true;
+ case SyntaxKind.MetaProperty:
+ return isImportMeta(node);
default:
return false;
}
diff --git a/tests/baselines/reference/findAllRefsImportMeta.baseline.jsonc b/tests/baselines/reference/findAllRefsImportMeta.baseline.jsonc
new file mode 100644
index 0000000000000..3d52240d3a867
--- /dev/null
+++ b/tests/baselines/reference/findAllRefsImportMeta.baseline.jsonc
@@ -0,0 +1,61 @@
+// === /tests/cases/fourslash/foo.ts ===
+// ///
+// ///
+// import./*FIND ALL REFS*/[|meta|];
+// import.[|meta|];
+
+// === /tests/cases/fourslash/baz.ts ===
+// ///
+// ///
+// let x = import
+// . // hai :)
+// [|meta|];
+
+[
+ {
+ "definition": {
+ "containerKind": "",
+ "containerName": "",
+ "fileName": "/tests/cases/fourslash/foo.ts",
+ "kind": "keyword",
+ "textSpan": {
+ "start": 82,
+ "length": 4
+ },
+ "displayParts": [
+ {
+ "kind": "keyword"
+ }
+ ]
+ },
+ "references": [
+ {
+ "textSpan": {
+ "start": 82,
+ "length": 4
+ },
+ "fileName": "/tests/cases/fourslash/foo.ts",
+ "isWriteAccess": false,
+ "isDefinition": false
+ },
+ {
+ "textSpan": {
+ "start": 95,
+ "length": 4
+ },
+ "fileName": "/tests/cases/fourslash/foo.ts",
+ "isWriteAccess": false,
+ "isDefinition": false
+ },
+ {
+ "textSpan": {
+ "start": 109,
+ "length": 4
+ },
+ "fileName": "/tests/cases/fourslash/baz.ts",
+ "isWriteAccess": false,
+ "isDefinition": false
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/tests/baselines/reference/quickInfoImportMeta.baseline b/tests/baselines/reference/quickInfoImportMeta.baseline
new file mode 100644
index 0000000000000..e576927262fb2
--- /dev/null
+++ b/tests/baselines/reference/quickInfoImportMeta.baseline
@@ -0,0 +1,41 @@
+[
+ {
+ "marker": {
+ "fileName": "/tests/cases/fourslash/foo.ts",
+ "position": 77,
+ "name": "1"
+ },
+ "quickInfo": {
+ "kind": "",
+ "kindModifiers": "",
+ "textSpan": {
+ "start": 75,
+ "length": 6
+ },
+ "displayParts": [],
+ "documentation": []
+ }
+ },
+ {
+ "marker": {
+ "fileName": "/tests/cases/fourslash/foo.ts",
+ "position": 84,
+ "name": "2"
+ },
+ "quickInfo": {
+ "kind": "interface",
+ "kindModifiers": "declare",
+ "textSpan": {
+ "start": 75,
+ "length": 11
+ },
+ "displayParts": [],
+ "documentation": [
+ {
+ "text": "The type of `import.meta`.\n\nIf you need to declare that a given property exists on `import.meta`,\nthis type may be augmented via interface merging.",
+ "kind": "text"
+ }
+ ]
+ }
+ }
+]
\ No newline at end of file
diff --git a/tests/cases/fourslash/findAllRefsImportMeta.ts b/tests/cases/fourslash/findAllRefsImportMeta.ts
new file mode 100644
index 0000000000000..1040f9542e4a9
--- /dev/null
+++ b/tests/cases/fourslash/findAllRefsImportMeta.ts
@@ -0,0 +1,26 @@
+// @noLib: true
+
+///
+
+// @module: esnext
+// @Filename: foo.ts
+///////
+///////
+////import./**/meta;
+////import.[|meta|];
+
+//@Filename: bar.d.ts
+////interface ImportMeta {
+////}
+
+// @Filename: baz.ts
+///////
+///////
+////let x = import
+//// . // hai :)
+//// meta;
+
+verify.baselineFindAllReferences("");
+
+goTo.rangeStart(test.ranges()[0]);
+verify.renameInfoFailed();
diff --git a/tests/cases/fourslash/goToDefinitionImportMeta.ts b/tests/cases/fourslash/goToDefinitionImportMeta.ts
new file mode 100644
index 0000000000000..4594fef1b6766
--- /dev/null
+++ b/tests/cases/fourslash/goToDefinitionImportMeta.ts
@@ -0,0 +1,13 @@
+///
+
+// @module: esnext
+// @Filename: foo.ts
+///////
+///////
+////import.me/*reference*/ta;
+
+//@Filename: bar.d.ts
+////interface ImportMeta {
+////}
+
+verify.goToDefinition("reference", []);
diff --git a/tests/cases/fourslash/goToTypeDefinitionImportMeta.ts b/tests/cases/fourslash/goToTypeDefinitionImportMeta.ts
new file mode 100644
index 0000000000000..a7d1d72495e34
--- /dev/null
+++ b/tests/cases/fourslash/goToTypeDefinitionImportMeta.ts
@@ -0,0 +1,13 @@
+///
+
+// @module: esnext
+// @Filename: foo.ts
+///////
+///////
+////import.me/*reference*/ta;
+
+//@Filename: bar.d.ts
+////interface /*definition*/ImportMeta {
+////}
+
+verify.goToType("reference", "definition");
diff --git a/tests/cases/fourslash/quickInfoImportMeta.ts b/tests/cases/fourslash/quickInfoImportMeta.ts
new file mode 100644
index 0000000000000..928266b860f34
--- /dev/null
+++ b/tests/cases/fourslash/quickInfoImportMeta.ts
@@ -0,0 +1,19 @@
+///
+
+// @module: esnext
+// @Filename: foo.ts
+///////
+///////
+////im/*1*/port.me/*2*/ta;
+
+//@Filename: bar.d.ts
+/////**
+//// * 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 {
+////}
+
+verify.baselineQuickInfo()