From f67c71f11a0de56294fad6f27a579bed09589f64 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 19:54:38 +0000 Subject: [PATCH 1/8] Initial plan From 7fa849105df234a3e40ca203c1390c0d9cacf340 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 20:07:32 +0000 Subject: [PATCH 2/8] feat(compiler): support importing ts decorator modules Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com> --- packages/compiler/src/core/source-file.ts | 2 +- .../compiler/test/checker/imports.test.ts | 23 +++++++++++++++++++ .../docs/docs/language-basics/imports.md | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/core/source-file.ts b/packages/compiler/src/core/source-file.ts index 756964c278d..6c7b55195f4 100644 --- a/packages/compiler/src/core/source-file.ts +++ b/packages/compiler/src/core/source-file.ts @@ -40,7 +40,7 @@ export function createSourceFile(text: string, path: string): SourceFile { export function getSourceFileKindFromExt(path: string): SourceFileKind | undefined { const ext = getAnyExtensionFromPath(path); - if (ext === ".js" || ext === ".mjs") { + if (ext === ".js" || ext === ".mjs" || ext === ".ts") { return "js"; } else if (ext === ".tsp") { return "typespec"; diff --git a/packages/compiler/test/checker/imports.test.ts b/packages/compiler/test/checker/imports.test.ts index e01a47705de..d86a0d1f6b3 100644 --- a/packages/compiler/test/checker/imports.test.ts +++ b/packages/compiler/test/checker/imports.test.ts @@ -68,6 +68,29 @@ describe("compiler: imports", () => { expectFileLoaded(program, { typespec: ["proj/main.tsp"], js: ["blue.js"] }); }); + it("import relative TS file", async () => { + const { program } = await Tester.files({ + "blue.ts": mockFile.js({ $blue() {} }), + }).compile(` + import "./blue.ts"; + @blue + model A {} + `); + expectFileLoaded(program, { typespec: ["main.tsp"], js: ["blue.ts"] }); + }); + + it("import relative TS file in parent folder", async () => { + const { program } = await Tester.files({ + "blue.ts": mockFile.js({ $blue() {} }), + "proj/main.tsp": ` + import "../blue.ts"; + @blue + model A {} + `, + }).compile(`import "./proj/main.tsp";`); + expectFileLoaded(program, { typespec: ["proj/main.tsp"], js: ["blue.ts"] }); + }); + it("import directory with main.tsp", async () => { const { program } = await Tester.files({ "test/main.tsp": `model C { }`, diff --git a/website/src/content/docs/docs/language-basics/imports.md b/website/src/content/docs/docs/language-basics/imports.md index 163b0b0633e..9819bf404da 100644 --- a/website/src/content/docs/docs/language-basics/imports.md +++ b/website/src/content/docs/docs/language-basics/imports.md @@ -7,7 +7,7 @@ llmstxt: true Imports are used to include files or libraries into your TypeSpec program. When compiling a TypeSpec file, you specify the path to your root TypeSpec file, typically named "main.tsp". From this root file, any imported files are added to your program. If a directory is imported, TypeSpec will search for a `main.tsp` file within that directory. -The path specified in the import must either start with `"./"` or `"../"`, or be an absolute path. The path should either point to a directory, or have an extension of either ".tsp" or ".js". The examples below illustrate how to use imports to assemble a TypeSpec program from multiple files: +The path specified in the import must either start with `"./"` or `"../"`, or be an absolute path. The path should either point to a directory, or have an extension of either ".tsp", ".js", or ".ts". The examples below illustrate how to use imports to assemble a TypeSpec program from multiple files: ## Importing a TypeSpec file From 4282ea43681f3e2bf9b3a3a89d113f08fa4e1c97 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 20:11:44 +0000 Subject: [PATCH 3/8] test(compiler): normalize new ts import test formatting Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com> --- packages/compiler/test/checker/imports.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/compiler/test/checker/imports.test.ts b/packages/compiler/test/checker/imports.test.ts index d86a0d1f6b3..48fa9e33703 100644 --- a/packages/compiler/test/checker/imports.test.ts +++ b/packages/compiler/test/checker/imports.test.ts @@ -74,7 +74,7 @@ describe("compiler: imports", () => { }).compile(` import "./blue.ts"; @blue - model A {} + model A {} `); expectFileLoaded(program, { typespec: ["main.tsp"], js: ["blue.ts"] }); }); @@ -85,7 +85,7 @@ describe("compiler: imports", () => { "proj/main.tsp": ` import "../blue.ts"; @blue - model A {} + model A {} `, }).compile(`import "./proj/main.tsp";`); expectFileLoaded(program, { typespec: ["proj/main.tsp"], js: ["blue.ts"] }); From b35f639e470096e5da86830efbb45a5f72c1b4fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 20:44:31 +0000 Subject: [PATCH 4/8] test(compiler): add e2e coverage for relative .ts imports Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com> --- .../test/e2e/scenarios/import-relative-ts/decorators.ts | 1 + .../compiler/test/e2e/scenarios/import-relative-ts/main.tsp | 4 ++++ packages/compiler/test/e2e/scenarios/scenarios.e2e.ts | 5 +++++ 3 files changed, 10 insertions(+) create mode 100644 packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts create mode 100644 packages/compiler/test/e2e/scenarios/import-relative-ts/main.tsp diff --git a/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts b/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts new file mode 100644 index 00000000000..251decf7683 --- /dev/null +++ b/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts @@ -0,0 +1 @@ +export function $blue() {} diff --git a/packages/compiler/test/e2e/scenarios/import-relative-ts/main.tsp b/packages/compiler/test/e2e/scenarios/import-relative-ts/main.tsp new file mode 100644 index 00000000000..507a5b7c601 --- /dev/null +++ b/packages/compiler/test/e2e/scenarios/import-relative-ts/main.tsp @@ -0,0 +1,4 @@ +import "./decorators.ts"; + +@blue +model A {} diff --git a/packages/compiler/test/e2e/scenarios/scenarios.e2e.ts b/packages/compiler/test/e2e/scenarios/scenarios.e2e.ts index ff0c2cd32c7..1a1b2783147 100644 --- a/packages/compiler/test/e2e/scenarios/scenarios.e2e.ts +++ b/packages/compiler/test/e2e/scenarios/scenarios.e2e.ts @@ -130,6 +130,11 @@ describe("compiler: entrypoints", () => { expectDiagnosticEmpty(program.diagnostics); }); + it("succeed with relative .ts module import", async () => { + const program = await compileScenario("import-relative-ts"); + expectDiagnosticEmpty(program.diagnostics); + }); + it("succeed if loading different install of the same library at the same version", async () => { const program = await compileScenario("same-library-same-version", { emit: ["@typespec/lib2"], From 5efe37330cd72710d6e5953f830af008ec74c634 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 21:43:20 +0000 Subject: [PATCH 5/8] test(compiler): add TypeScript syntax to ts import e2e fixture Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com> --- .../test/e2e/scenarios/import-relative-ts/decorators.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts b/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts index 251decf7683..4d168a5b8f6 100644 --- a/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts +++ b/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts @@ -1 +1,5 @@ -export function $blue() {} +type DecoratorContext = { + program: unknown; +}; + +export function $blue(_context: DecoratorContext, _target: unknown): void {} From 7c166e89ffc9d9cadbe807e4355a7c8fd74cec0a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 21:45:49 +0000 Subject: [PATCH 6/8] test(compiler): strengthen ts import fixture with typed signature Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com> --- .../e2e/scenarios/import-relative-ts/decorators.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts b/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts index 4d168a5b8f6..8bf24ab6e7a 100644 --- a/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts +++ b/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts @@ -1,5 +1,12 @@ type DecoratorContext = { - program: unknown; + program: object; }; -export function $blue(_context: DecoratorContext, _target: unknown): void {} +type DecoratorTarget = { + name: string; +}; + +export function $blue(context: DecoratorContext, target: DecoratorTarget): void { + void context; + void target; +} From 05ab0f756add14c5bb6e9968d67fa2f21a3847b1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 21:49:30 +0000 Subject: [PATCH 7/8] test(compiler): refine typed ts fixture context and usage Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com> --- .../test/e2e/scenarios/import-relative-ts/decorators.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts b/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts index 8bf24ab6e7a..afd5bf00ac0 100644 --- a/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts +++ b/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts @@ -1,5 +1,7 @@ type DecoratorContext = { - program: object; + program: { + compilerVersion?: string; + }; }; type DecoratorTarget = { @@ -7,6 +9,7 @@ type DecoratorTarget = { }; export function $blue(context: DecoratorContext, target: DecoratorTarget): void { - void context; - void target; + if (context.program.compilerVersion === "__never__" && target.name === "__never__") { + throw new Error("Unreachable branch for e2e fixture."); + } } From 80f4f9fb2d951861bb46d045fedfc334e52217ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 10 Jun 2026 22:02:57 +0000 Subject: [PATCH 8/8] test(compiler): simplify ts e2e decorator fixture types Co-authored-by: timotheeguerin <1031227+timotheeguerin@users.noreply.github.com> --- .../scenarios/import-relative-ts/decorators.ts | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts b/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts index afd5bf00ac0..b5d5208dc20 100644 --- a/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts +++ b/packages/compiler/test/e2e/scenarios/import-relative-ts/decorators.ts @@ -1,15 +1,4 @@ -type DecoratorContext = { - program: { - compilerVersion?: string; - }; -}; - -type DecoratorTarget = { - name: string; -}; - -export function $blue(context: DecoratorContext, target: DecoratorTarget): void { - if (context.program.compilerVersion === "__never__" && target.name === "__never__") { - throw new Error("Unreachable branch for e2e fixture."); - } +export function $blue(context: unknown, target: unknown): void { + void context; + void target; }