Repository: fabien0102/ts-to-zod (ts)

Issue:
Aliased name imports get wrongly converted
## Bug description

For further documentation i have to use export types in a certain way.
Due to this duplicate naming may occure and i have to rename types and interfaces when importing.
This results in imported zod schema not being aliased correctly, to import  and alias the resulting schemas.

### Input

```ts
// a.ts
export interface Obj {
    bug: "with aliased imports"
}
```

```ts
// b.ts
import { Obj as Renamed } from "./a.ts"

export interface Obj extends Renamed {
    should: "rename"
}
```

### Expected output

```ts
// a.ts
export const ObjSchema = z.object({
  bug: z.literal("with aliased imports")
})
```

```ts
import { ObjSchema as RenamedSchema } from "./a.ts"
// a.ts
export const ObjSchema= RenamedSchema.extend({
    should: z.literal("rename")
})
```

### Actual output

```ts
// a.ts
export const ObjSchema = z.object({
  bug: z.literal("with aliased imports")
})
```

```ts
import { RenamedSchema } from "./a.ts"
// a.ts
export const ObjSchema = RenamedSchema.extend({
    should: z.literal("rename")
})
```

**Versions**

- Typescript: `v5.6.3`
- Zod: `v3.23.8`


Pull request:
fix(Imports): support for named imports in generated files
# Why

Fixes #285

Patch:
diff --git a/example/heros.zod.ts b/example/heros.zod.ts
index 33d65f3..0de82d8 100644
--- a/example/heros.zod.ts
+++ b/example/heros.zod.ts
@@ -1,6 +1,11 @@
 // Generated by ts-to-zod
 import { z } from "zod";
-import { EnemyPower, Villain, EvilPlan, EvilPlanDetails } from "./heros";
+import {
+  type Villain,
+  type EvilPlan,
+  type EvilPlanDetails,
+  EnemyPower,
+} from "./heros";
 
 import { personSchema } from "./person.zod";
 
diff --git a/src/core/generate.ts b/src/core/generate.ts
index 24838b1..c65cca1 100644
--- a/src/core/generate.ts
+++ b/src/core/generate.ts
@@ -19,6 +19,8 @@ import {
 import {
   getImportIdentifiers,
   createImportNode,
+  ImportIdentifier,
+  getSingleImportIdentierForNode,
 } from "../utils/importHandling";
 
 import { generateIntegrationTests } from "./generateIntegrationTests";
@@ -129,7 +131,7 @@ export function generate({
 
     if (ts.isImportDeclaration(node) && node.importClause) {
       const identifiers = getImportIdentifiers(node);
-      identifiers.forEach((i) => typeNameMapping.set(i, node));
+      identifiers.forEach(({ name }) => typeNameMapping.set(name, node));
 
       // Check if we're importing from a mapped file
       const eligibleMapping = inputOutputMappings.find(
@@ -144,20 +146,26 @@ export function generate({
         const schemaMethod =
           eligibleMapping.getSchemaName || DEFAULT_GET_SCHEMA;
 
-        const identifiers = getImportIdentifiers(node);
-        identifiers.forEach((i) =>
-          importedZodNamesAvailable.set(i, schemaMethod(i))
+        identifiers.forEach(({ name }) =>
+          importedZodNamesAvailable.set(name, schemaMethod(name))
         );
 
         const zodImportNode = createImportNode(
-          identifiers.map(schemaMethod),
+          identifiers.map(({ name, original }) => {
+            return {
+              name: schemaMethod(name),
+              original: original ? schemaMethod(original) : undefined,
+            };
+          }),
           eligibleMapping.output
         );
         zodImportNodes.push(zodImportNode);
       }
       // Not a Zod import, handling it as 3rd party import later on
       else {
-        identifiers.forEach((i) => externalImportNamesAvailable.add(i));
+        identifiers.forEach(({ name }) =>
+          externalImportNamesAvailable.add(name)
+        );
       }
     }
   };
@@ -189,7 +197,7 @@ export function generate({
   const importedZodSchemas = new Set<string>();
 
   // All original import to keep in the target
-  const importsToKeep = new Map<ts.ImportDeclaration, string[]>();
+  const importsToKeep = new Map<ts.ImportDeclaration, ImportIdentifier[]>();
 
   /**
    * We browse all the extracted type references from the source file
@@ -208,10 +216,15 @@ export function generate({
       // If the reference is part of a qualified name, we need to import it from the same file
       if (typeRef.partOfQualifiedName) {
         const identifiers = importsToKeep.get(node);
+        const importIdentifier = getSingleImportIdentierForNode(
+          node,
+          typeRef.name
+        );
+        if (!importIdentifier) return;
         if (identifiers) {
-          identifiers.push(typeRef.name);
+          identifiers.push(importIdentifier);
         } else {
-          importsToKeep.set(node, [typeRef.name]);
+          importsToKeep.set(node, [importIdentifier]);
         }
         return;
       }
@@ -379,7 +392,7 @@ ${Array.from(zodSchemasWithMissingDependencies).join("\n")}`
 
   const zodImportToOutput = zodImportNodes.filter((node) => {
     const nodeIdentifiers = getImportIdentifiers(node);
-    return nodeIdentifiers.some((i) => importedZodSchemas.has(i));
+    return nodeIdentifiers.some(({ name }) => importedZodSchemas.has(name));
   });
 
   const originalImportsToOutput = Array.from(importsToKeep.keys()).map((node) =>
diff --git a/src/core/generateZodSchema.ts b/src/core/generateZodSchema.ts
index b356d54..4a3a6d1 100644
--- a/src/core/generateZodSchema.ts
+++ b/src/core/generateZodSchema.ts
@@ -311,23 +311,27 @@ function buildZodPrimitive({
   | ts.Identifier
   | ts.PropertyAccessExpression {
   const schema = jsDocTags.schema;
+
+  // Schema override when it doesn't start with a dot, return the schema directly
+  if (schema && !schema.startsWith(".")) {
+    return f.createPropertyAccessExpression(
+      f.createIdentifier(z),
+      f.createIdentifier(schema)
+    );
+  }
+
   delete jsDocTags.schema;
   const generatedSchema = buildZodPrimitiveInternal({ jsDocTags, z, ...rest });
-  // schema not specified? return generated one
+
+  // No schema override? Return generated one
   if (!schema) {
     return generatedSchema;
   }
-  // schema starts with dot? append it
-  if (schema.startsWith(".")) {
-    return f.createPropertyAccessExpression(
-      generatedSchema,
-      f.createIdentifier(schema.slice(1))
-    );
-  }
-  // otherwise use provided schema verbatim
+
+  // Schema override starts with dot? Append it
   return f.createPropertyAccessExpression(
-    f.createIdentifier(z),
-    f.createIdentifier(schema)
+    generatedSchema,
+    f.createIdentifier(schema.slice(1))
   );
 }
 
diff --git a/src/core/jsDocTags.ts b/src/core/jsDocTags.ts
index 029b02b..122aa3f 100644
--- a/src/core/jsDocTags.ts
+++ b/src/core/jsDocTags.ts
@@ -22,6 +22,11 @@ const builtInJSDocFormatsTypes = [
 
 type BuiltInJSDocFormatsType = (typeof builtInJSDocFormatsTypes)[number];
 
+type JsonPrimitive = string | number | boolean | null;
+type JsonArray = JsonValue[];
+type JsonObject = { [key: string]: JsonValue };
+type JsonValue = JsonPrimitive | JsonArray | JsonObject;
+
 /**
  * Type guard to filter supported JSDoc format tag values (built-in).
  *
@@ -58,7 +63,7 @@ export interface JSDocTagsBase {
   description?: string;
   minimum?: TagWithError<number>;
   maximum?: TagWithError<number>;
-  default?: number | string | boolean | null;
+  default?: JsonValue;
   minLength?: TagWithError<number>;
   maxLength?: TagWithError<number>;
   format?: TagWithError<BuiltInJSDocFormatsType | CustomJSDocFormatType>;
@@ -191,28 +196,15 @@ export function getJSDocTags(nodeType: ts.Node, sourceFile: ts.SourceFile) {
             jsDocTags[tagName] = { value, errorMessage };
             break;
           case "default":
-            if (tag.comment === "null") {
-              jsDocTags[tagName] = null;
-            } else if (
-              tag.comment &&
-              !tag.comment.includes('"') &&
-              !Number.isNaN(parseInt(tag.comment))
-            ) {
-              // number
-              jsDocTags[tagName] = parseInt(tag.comment);
-            } else if (tag.comment && ["false", "true"].includes(tag.comment)) {
-              // boolean
-              jsDocTags[tagName] = tag.comment === "true";
-            } else if (
-              tag.comment &&
-              tag.comment.startsWith('"') &&
-              tag.comment.endsWith('"')
-            ) {
-              // string with double quotes
-              jsDocTags[tagName] = tag.comment.slice(1, -1);
-            } else if (tag.comment) {
-              // string without quotes
-              jsDocTags[tagName] = tag.comment;
+            if (tag.comment) {
+              try {
+                // Attempt to parse as JSON
+                const parsedValue = JSON.parse(tag.comment);
+                jsDocTags[tagName] = parsedValue;
+              } catch (e) {
+                // If JSON parsing fails, handle as before
+                jsDocTags[tagName] = tag.comment;
+              }
             }
             break;
           case "strict":
@@ -363,7 +355,11 @@ export function jsDocTagToZodProperties(
             : [f.createNumericLiteral(jsDocTags.default)]
           : jsDocTags.default === null
           ? [f.createNull()]
-          : [f.createStringLiteral(jsDocTags.default)],
+          : Array.isArray(jsDocTags.default)
+          ? [createArrayLiteralExpression(jsDocTags.default)]
+          : typeof jsDocTags.default === "object"
+          ? [createObjectLiteralExpression(jsDocTags.default)]
+          : [f.createStringLiteral(String(jsDocTags.default))],
     });
   }
 
@@ -494,3 +490,61 @@ function withErrorMessage(expression: ts.Expression, errorMessage?: string) {
   }
   return [expression];
 }
+
+// Helper function to create an array literal expression
+function createArrayLiteralExpression(
+  arr: JsonValue[]
+): ts.ArrayLiteralExpression {
+  const elements = arr.map((item) => {
+    if (typeof item === "string") return f.createStringLiteral(item);
+    if (typeof item === "number") return f.createNumericLiteral(item);
+    if (typeof item === "boolean")
+      return item ? f.createTrue() : f.createFalse();
+    if (item === null) return f.createNull();
+    if (Array.isArray(item)) return createArrayLiteralExpression(item);
+    if (typeof item === "object") return createObjectLiteralExpression(item);
+    return f.createStringLiteral(String(item));
+  });
+  return f.createArrayLiteralExpression(elements);
+}
+
+// Helper function to create an object literal expression
+function createObjectLiteralExpression(
+  obj: Record<string, JsonValue>
+): ts.ObjectLiteralExpression {
+  const properties = Object.entries(obj).map(([key, value]) => {
+    const propertyName = f.createStringLiteral(key);
+    if (typeof value === "string")
+      return f.createPropertyAssignment(
+        propertyName,
+        f.createStringLiteral(value)
+      );
+    if (typeof value === "number")
+      return f.createPropertyAssignment(
+        propertyName,
+        f.createNumericLiteral(value)
+      );
+    if (typeof value === "boolean")
+      return f.createPropertyAssignment(
+        propertyName,
+        value ? f.createTrue() : f.createFalse()
+      );
+    if (value === null)
+      return f.createPropertyAssignment(propertyName, f.createNull());
+    if (Array.isArray(value))
+      return f.createPropertyAssignment(
+        propertyName,
+        createArrayLiteralExpression(value)
+      );
+    if (typeof value === "object")
+      return f.createPropertyAssignment(
+        propertyName,
+        createObjectLiteralExpression(value)
+      );
+    return f.createPropertyAssignment(
+      propertyName,
+      f.createStringLiteral(String(value))
+    );
+  });
+  return f.createObjectLiteralExpression(properties);
+}
diff --git a/src/core/validateGeneratedTypes.ts b/src/core/validateGeneratedTypes.ts
index 961ad78..6e999f0 100644
--- a/src/core/validateGeneratedTypes.ts
+++ b/src/core/validateGeneratedTypes.ts
@@ -65,7 +65,7 @@ export function validateGeneratedTypes({
     ) {
       if (node.importClause) {
         const identifiers = getImportIdentifiers(node);
-        identifiers.forEach((i) => importsToHandleAsAny.add(i));
+        identifiers.forEach(({ name }) => importsToHandleAsAny.add(name));
       }
     }
   };
diff --git a/src/utils/importHandling.ts b/src/utils/importHandling.ts
index 6a25484..5268578 100644
--- a/src/utils/importHandling.ts
+++ b/src/utils/importHandling.ts
@@ -1,19 +1,27 @@
 import ts from "typescript";
 const { factory: f } = ts;
 
+export type ImportIdentifier = {
+  name: string;
+  original?: string;
+};
+
 /**
  * Extracts the list of import identifiers from an import clause
  * @param node an ImportDeclaration node
  * @returns an array of all identifiers found in statement
  */
-export function getImportIdentifiers(node: ts.ImportDeclaration): string[] {
+export function getImportIdentifiers(
+  node: ts.ImportDeclaration
+): ImportIdentifier[] {
   if (!node.importClause) return [];
 
   const { importClause } = node;
-  const importIdentifiers: string[] = [];
+  const importIdentifiers: ImportIdentifier[] = [];
 
   // Case `import MyGlobal from "module";`
-  if (importClause.name) importIdentifiers.push(importClause.name.text);
+  if (importClause.name)
+    importIdentifiers.push({ name: importClause.name.text });
 
   if (importClause.namedBindings) {
     // Cases `import { A, B } from "module"`
@@ -21,28 +29,46 @@ export function getImportIdentifiers(node: ts.ImportDeclaration): string[] {
     if (ts.isNamedImports(importClause.namedBindings)) {
       for (const element of importClause.namedBindings.elements) {
         if (ts.isImportSpecifier(element)) {
-          importIdentifiers.push(element.name.text);
+          importIdentifiers.push({
+            name: element.name.text,
+            original: element.propertyName?.text,
+          });
         }
       }
     }
     // Case `import * as A from "module"`
     else if (ts.isNamespaceImport(importClause.namedBindings)) {
-      importIdentifiers.push(importClause.namedBindings.name.text);
+      importIdentifiers.push({ name: importClause.namedBindings.name.text });
     }
   }
 
   return importIdentifiers;
 }
 
+export function getSingleImportIdentierForNode(
+  node: ts.ImportDeclaration,
+  identifier: string
+): ImportIdentifier | undefined {
+  const allIdentifiers = getImportIdentifiers(node);
+  return allIdentifiers.find(({ name }) => name === identifier);
+}
+
 /**
  * Creates an import statement from the given arguments
  * @param identifiers array of types to import
  * @param path module path
  * @returns an ImportDeclaration node that corresponds to `import { ...identifiers } from "path"`
  */
-export function createImportNode(identifiers: string[], path: string) {
-  const specifiers = identifiers.map((i) =>
-    f.createImportSpecifier(false, undefined, f.createIdentifier(i))
+export function createImportNode(
+  identifiers: ImportIdentifier[],
+  path: string
+) {
+  const specifiers = identifiers.map(({ name, original }) =>
+    f.createImportSpecifier(
+      false,
+      original ? f.createIdentifier(original) : undefined,
+      f.createIdentifier(name)
+    )
   );
 
   return f.createImportDeclaration(


Test patch:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index cb7844d..9a461c3 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -30,5 +30,4 @@ jobs:
       - run: chmod +x ./bin/run
       - run: yarn build
       - run: yarn test:ci
-      - run: yarn codecov
       - run: yarn lint
diff --git a/src/core/generate.test.ts b/src/core/generate.test.ts
index ca9dd56..fee40f8 100644
--- a/src/core/generate.test.ts
+++ b/src/core/generate.test.ts
@@ -738,6 +738,62 @@ describe("generate", () => {
       });
     });
 
+    describe("named import", () => {
+      const sourceText = `
+      import { Villain as Nemesis } from "@project/villain-module";
+  
+      export interface Superman {
+        nemesis: Nemesis;
+        id: number
+      }
+      `;
+
+      const { getZodSchemasFile, getIntegrationTestFile, errors } = generate({
+        sourceText,
+      });
+
+      it("should generate the zod schemas", () => {
+        expect(getZodSchemasFile("./source")).toMatchInlineSnapshot(`
+      "// Generated by ts-to-zod
+      import { z } from "zod";
+
+      const nemesisSchema = z.any();
+
+      export const supermanSchema = z.object({
+          nemesis: nemesisSchema,
+          id: z.number()
+      });
+      "
+      `);
+      });
+
+      it("should generate the integration tests", () => {
+        expect(getIntegrationTestFile("./hero", "hero.zod"))
+          .toMatchInlineSnapshot(`
+      "// Generated by ts-to-zod
+      import { z } from "zod";
+
+      import * as spec from "./hero";
+      import * as generated from "hero.zod";
+
+      // eslint-disable-next-line @typescript-eslint/no-unused-vars
+      function expectType<T>(_: T) {
+        /* noop */
+      }
+
+      export type supermanSchemaInferredType = z.infer<typeof generated.supermanSchema>;
+
+      expectType<spec.Superman>({} as supermanSchemaInferredType)
+      expectType<supermanSchemaInferredType>({} as spec.Superman)
+      "
+      `);
+      });
+
+      it("should not have any errors", () => {
+        expect(errors.length).toBe(0);
+      });
+    });
+
     describe("multiple imports", () => {
       const sourceText = `
       import { Name } from "nameModule";
@@ -1115,6 +1171,78 @@ describe("generate", () => {
       });
     });
 
+    describe("one named import in one statement", () => {
+      const input = "./hero";
+      const output = "./hero.zod";
+      const inputOutputMappings = [{ input, output }];
+
+      const sourceText = `
+      import { Hero as Superman } from "${input}"
+    
+      export interface Person {
+        id: number
+        hero: Superman
+      }
+      `;
+
+      const { getZodSchemasFile } = generate({
+        sourceText,
+        inputOutputMappings,
+      });
+
+      it("should generate the zod schemas with right import", () => {
+        expect(getZodSchemasFile(input)).toMatchInlineSnapshot(`
+        "// Generated by ts-to-zod
+        import { z } from "zod";
+
+        import { heroSchema as supermanSchema } from "${output}";
+
+        export const personSchema = z.object({
+            id: z.number(),
+            hero: supermanSchema
+        });
+        "
+      `);
+      });
+    });
+
+    describe("mixed named imports in one statement", () => {
+      const input = "./hero";
+      const output = "./hero.zod";
+      const inputOutputMappings = [{ input, output }];
+
+      const sourceText = `
+      import { Hero as Superman, Villain } from "${input}"
+    
+      export interface Person {
+        id: number
+        hero: Superman
+        nemesis: Villain
+      }
+      `;
+
+      const { getZodSchemasFile } = generate({
+        sourceText,
+        inputOutputMappings,
+      });
+
+      it("should generate the zod schemas with right import", () => {
+        expect(getZodSchemasFile(input)).toMatchInlineSnapshot(`
+        "// Generated by ts-to-zod
+        import { z } from "zod";
+
+        import { heroSchema as supermanSchema, villainSchema } from "${output}";
+
+        export const personSchema = z.object({
+            id: z.number(),
+            hero: supermanSchema,
+            nemesis: villainSchema
+        });
+        "
+      `);
+      });
+    });
+
     describe("one import in one statement, alternate getSchemaName for mapping", () => {
       const input = "./hero";
       const output = "./hero.zod";
diff --git a/src/core/generateZodSchema.test.ts b/src/core/generateZodSchema.test.ts
index 5ca0a5f..76067a5 100644
--- a/src/core/generateZodSchema.test.ts
+++ b/src/core/generateZodSchema.test.ts
@@ -1582,6 +1582,67 @@ describe("generateZodSchema", () => {
     `);
   });
 
+  it("should deal with @default with array value", () => {
+    const source = `export interface WithArrayDefault {
+      /**
+       * @default ["superman", "batman", "wonder woman"]
+       */
+      justiceLeague: string[];
+    }`;
+    expect(generate(source)).toMatchInlineSnapshot(`
+      "export const withArrayDefaultSchema = z.object({
+          /**
+           * @default ["superman", "batman", "wonder woman"]
+           */
+          justiceLeague: z.array(z.string()).default(["superman", "batman", "wonder woman"])
+      });"
+    `);
+  });
+
+  it("should deal with @default with object value", () => {
+    const source = `export interface WithObjectDefault {
+      /**
+       * @default { "name": "Clark Kent", "age": 30, "isHero": true }
+       */
+      superman: { name: string; age: number; isHero: boolean };
+    }`;
+    expect(generate(source)).toMatchInlineSnapshot(`
+      "export const withObjectDefaultSchema = z.object({
+          /**
+           * @default { "name": "Clark Kent", "age": 30, "isHero": true }
+           */
+          superman: z.object({
+              name: z.string(),
+              age: z.number(),
+              isHero: z.boolean()
+          }).default({ "name": "Clark Kent", "age": 30, "isHero": true })
+      });"
+    `);
+  });
+
+  it("should deal with @default with nested array and object values", () => {
+    const source = `export interface WithNestedDefault {
+      /**
+       * @default { "heroes": ["superman", "batman"], "villains": [{ "name": "Lex Luthor", "age": 40 }] }
+       */
+      dcUniverse: { heroes: string[]; villains: { name: string; age: number }[] };
+    }`;
+    expect(generate(source)).toMatchInlineSnapshot(`
+      "export const withNestedDefaultSchema = z.object({
+          /**
+           * @default { "heroes": ["superman", "batman"], "villains": [{ "name": "Lex Luthor", "age": 40 }] }
+           */
+          dcUniverse: z.object({
+              heroes: z.array(z.string()),
+              villains: z.array(z.object({
+                  name: z.string(),
+                  age: z.number()
+              }))
+          }).default({ "heroes": ["superman", "batman"], "villains": [{ "name": "Lex Luthor", "age": 40 }] })
+      });"
+    `);
+  });
+
   it("should ignore unknown/broken jsdoc format", () => {
     const source = `export interface Hero {
      /**
diff --git a/src/utils/importHandling.test.ts b/src/utils/importHandling.test.ts
index 994b9f6..899b671 100644
--- a/src/utils/importHandling.test.ts
+++ b/src/utils/importHandling.test.ts
@@ -17,7 +17,7 @@ describe("getImportIdentifiers", () => {
     `;
 
     expect(getImportIdentifiers(getImportNode(sourceText))).toEqual([
-      "MyGlobal",
+      { name: "MyGlobal" },
     ]);
   });
 
@@ -27,7 +27,7 @@ describe("getImportIdentifiers", () => {
     `;
 
     expect(getImportIdentifiers(getImportNode(sourceText))).toEqual([
-      "MyGlobal",
+      { name: "MyGlobal" },
     ]);
   });
 
@@ -37,7 +37,7 @@ describe("getImportIdentifiers", () => {
     `;
 
     expect(getImportIdentifiers(getImportNode(sourceText))).toEqual([
-      "MyGlobal",
+      { name: "MyGlobal" },
     ]);
   });
 
@@ -47,7 +47,7 @@ describe("getImportIdentifiers", () => {
     `;
 
     expect(getImportIdentifiers(getImportNode(sourceText))).toEqual([
-      "MyGlobal",
+      { name: "MyGlobal", original: "AA" },
     ]);
   });
 
@@ -57,8 +57,8 @@ describe("getImportIdentifiers", () => {
     `;
 
     expect(getImportIdentifiers(getImportNode(sourceText))).toEqual([
-      "MyGlobal",
-      "MyGlobal2",
+      { name: "MyGlobal" },
+      { name: "MyGlobal2" },
     ]);
   });
 
@@ -68,8 +68,8 @@ describe("getImportIdentifiers", () => {
     `;
 
     expect(getImportIdentifiers(getImportNode(sourceText))).toEqual([
-      "MyGlobal",
-      "MyGlobal2",
+      { name: "MyGlobal" },
+      { name: "MyGlobal2" },
     ]);
   });
 });
@@ -85,7 +85,7 @@ describe("createImportNode", () => {
   }
 
   it("should create an ImportDeclaration node correctly", () => {
-    const identifiers = ["Test1", "Test2"];
+    const identifiers = [{ name: "Test1" }, { name: "Test2" }];
     const path = "./testPath";
 
     const expected = 'import { Test1, Test2 } from "./testPath";';
@@ -96,11 +96,25 @@ describe("createImportNode", () => {
   });
 
   it("should handle empty identifiers array", () => {
-    const identifiers: string[] = [];
     const path = "./testPath";
 
     // Yes, this is valid
     const expected = 'import {} from "./testPath";';
+    const result = createImportNode([], path);
+
+    expect(printNode(result)).toEqual(expected);
+  });
+
+  it("should create an ImportDeclaration with alias", () => {
+    const identifiers = [
+      { name: "Test1", original: "T1" },
+      { name: "Test2" },
+      { name: "Test3", original: "T3" },
+    ];
+    const path = "./testPath";
+
+    const expected =
+      'import { T1 as Test1, Test2, T3 as Test3 } from "./testPath";';
 
     const result = createImportNode(identifiers, path);