From a61124c0ffe7ee15ca836e3c3b9aabfa466f3d38 Mon Sep 17 00:00:00 2001
From: Benji Visser <benji@093b.org>
Date: Wed, 8 May 2024 21:10:38 -0400
Subject: [PATCH] handling export declarations

Signed-off-by: Benji Visser <benji@093b.org>
---
 .../__snapshots__/index.test.ts.snap          | 49 ++++++++++++++++---
 .../services/language/typescript/process.ts   | 22 ++++++++-
 packages/test-project/src/utils/index.ts      |  3 ++
 3 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/packages/bumpgen-core/src/services/language/typescript/__snapshots__/index.test.ts.snap b/packages/bumpgen-core/src/services/language/typescript/__snapshots__/index.test.ts.snap
index 1ff8efa..5ab1b4b 100644
--- a/packages/bumpgen-core/src/services/language/typescript/__snapshots__/index.test.ts.snap
+++ b/packages/bumpgen-core/src/services/language/typescript/__snapshots__/index.test.ts.snap
@@ -73,6 +73,17 @@ exports[`dependencyGraphService initializes 1`] = `
     "startLine": 12,
     "typeSignature": "any",
   },
+  {
+    "block": "export * as zodUtils from "./utils";",
+    "edits": [],
+    "endLine": 7,
+    "id": "0fe7d446ed9f696d18685f95c58433a275c4475b",
+    "kind": "ExportDeclaration",
+    "name": "zodUtils",
+    "path": "/test-project/src/index.ts",
+    "startLine": 7,
+    "typeSignature": "any",
+  },
   {
     "block": "date().parse("19th September 2023");",
     "edits": [],
@@ -306,12 +317,12 @@ type UseQueryResult<TData = unknown, TError = DefaultError> = UseBaseQueryResult
   }
 }",
     "edits": [],
-    "endLine": 26,
+    "endLine": 29,
     "id": "8e0051ad7c49716420e0140ade5add29840c0b96",
     "kind": "ClassDeclaration",
     "name": "NodeRelations",
     "path": "/test-project/src/utils/index.ts",
-    "startLine": 14,
+    "startLine": 17,
     "typeSignature": "class NodeRelations  {
  constructor (hasCycle: boolean) => NodeRelations  NodeRelations.addEdge: () => string
 }",
@@ -323,12 +334,12 @@ type UseQueryResult<TData = unknown, TError = DefaultError> = UseBaseQueryResult
   return text;
 }",
     "edits": [],
-    "endLine": 38,
+    "endLine": 41,
     "id": "d377594088a1eac0cb38d0b30cce7d28f03f4011",
     "kind": "FunctionDeclaration",
     "name": "myFunction",
     "path": "/test-project/src/utils/index.ts",
-    "startLine": 34,
+    "startLine": 37,
     "typeSignature": "(text: string) => string
 ",
   },
@@ -342,12 +353,12 @@ type UseQueryResult<TData = unknown, TError = DefaultError> = UseBaseQueryResult
   });
 };",
     "edits": [],
-    "endLine": 12,
+    "endLine": 15,
     "id": "e467e428b74115c75603dd6f843a91c3adcb5ee1",
     "kind": "VariableDeclaration",
     "name": "useQueryFn",
     "path": "/test-project/src/utils/index.ts",
-    "startLine": 5,
+    "startLine": 8,
     "typeSignature": "() => void",
   },
   {
@@ -357,14 +368,36 @@ type UseQueryResult<TData = unknown, TError = DefaultError> = UseBaseQueryResult
     return isNaN(new Date(date).getTime()) ? undefined : new Date(date);
   });",
     "edits": [],
-    "endLine": 32,
+    "endLine": 35,
     "id": "87b9ecaf3b92371fe3d4b50777f320bfc95b0d82",
     "kind": "VariableDeclaration",
     "name": "date",
     "path": "/test-project/src/utils/index.ts",
-    "startLine": 28,
+    "startLine": 31,
     "typeSignature": "() => Zod.ZodEffects<Zod.ZodString, Date | undefined, string>",
   },
+  {
+    "block": "export * from "zod";",
+    "edits": [],
+    "endLine": 4,
+    "id": "fa3c9ab36ce27ac1d7e793c372758dfcca7bf676",
+    "kind": "ExportDeclaration",
+    "name": "export * from "zod";",
+    "path": "/test-project/src/utils/index.ts",
+    "startLine": 4,
+    "typeSignature": "",
+  },
+  {
+    "block": "export * from "@tanstack/react-query";",
+    "edits": [],
+    "endLine": 5,
+    "id": "0050f9ec7e413a7bff568fbc2b39d5d9268bd096",
+    "kind": "ExportDeclaration",
+    "name": "export * from "@tanstack/react-query";",
+    "path": "/test-project/src/utils/index.ts",
+    "startLine": 5,
+    "typeSignature": "",
+  },
 ]
 `;
 
diff --git a/packages/bumpgen-core/src/services/language/typescript/process.ts b/packages/bumpgen-core/src/services/language/typescript/process.ts
index cc1de6e..74b9b94 100644
--- a/packages/bumpgen-core/src/services/language/typescript/process.ts
+++ b/packages/bumpgen-core/src/services/language/typescript/process.ts
@@ -2,6 +2,7 @@ import { createHash } from "crypto";
 import type {
   ClassDeclaration,
   ExportAssignment,
+  ExportDeclaration,
   ExpressionStatement,
   FunctionDeclaration,
   Identifier,
@@ -23,6 +24,7 @@ import type {
 import { isImportNode } from "./signatures";
 
 type TopLevelTypes =
+  | ExportDeclaration
   | ModuleDeclaration
   | InterfaceDeclaration
   | ClassDeclaration
@@ -34,6 +36,7 @@ type TopLevelTypes =
 
 const isTopLevelType = (node: Node): node is TopLevelTypes => {
   return (
+    node.getKind() === SyntaxKind.ExportDeclaration ||
     node.getKind() === SyntaxKind.ModuleDeclaration ||
     node.getKind() === SyntaxKind.InterfaceDeclaration ||
     node.getKind() === SyntaxKind.ClassDeclaration ||
@@ -267,15 +270,24 @@ const getReferenceNodes = (node: TopLevelTypes) => {
 
 const createTopLevelNode = (n: TopLevelTypes) => {
   const kind = makeKind(n.getKind());
-  const idName = n
+
+  const identifierName = n
     .getFirstDescendantByKind(SyntaxKind.Identifier)
     ?.getSymbol()
     ?.getName();
   const nodeName = "getName" in n ? n.getName() : n.getSymbol()?.getName();
-  const name = nodeName ?? idName;
+  let name = nodeName ?? identifierName;
   if (!name) {
     return;
   }
+
+  // handling the case of 'export * from "x"' where the name is __export
+  // for all exports of this type, but we need to make sure ids are unique
+  // in the graph
+  if (n.getKind() === SyntaxKind.ExportDeclaration && name === "__export") {
+    name = n.getText();
+  }
+
   const path = n.getSourceFile().getFilePath();
   const surroundingBlock = getSurroundingBlock(n);
 
@@ -370,6 +382,12 @@ export const processSourceFile = (sourceFile: SourceFile) => {
     collectedEdges.push(...edges);
   });
 
+  sourceFile.getExportDeclarations().forEach((exportDeclaration) => {
+    const { nodes, edges } = processTopLevelItem(exportDeclaration);
+    collectedNodes.push(...nodes);
+    collectedEdges.push(...edges);
+  });
+
   sourceFile.getExportAssignments().forEach((exportAssignment) => {
     const { nodes, edges } = processTopLevelItem(exportAssignment);
     collectedNodes.push(...nodes);
diff --git a/packages/test-project/src/utils/index.ts b/packages/test-project/src/utils/index.ts
index f698857..108e455 100644
--- a/packages/test-project/src/utils/index.ts
+++ b/packages/test-project/src/utils/index.ts
@@ -1,6 +1,9 @@
 import { useQuery } from "@tanstack/react-query";
 import { z } from "zod";
 
+export * from "zod";
+export * from "@tanstack/react-query";
+
 // eslint-disable-next-line @typescript-eslint/no-unused-vars
 const useQueryFn = () => {
   useQuery({