Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: internal
packages:
- "@typespec/compiler"
---

Update init templates to use createTester API and modern ESLint configuration
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
// @ts-check
import eslint from "@eslint/js";
import { defineConfig } from "eslint/config";
import tsEslint from "typescript-eslint";

export default tsEslint.config(
export default defineConfig(
{
ignores: ["**/dist/**/*", "**/.temp/**/*"],
},
eslint.configs.recommended,
...tsEslint.configs.recommended,
{
rules: {
"@typescript-eslint/no-unused-vars": [
"warn",
{ varsIgnorePattern: "^_", argsIgnorePattern: "^_" },
],
},
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
},
"devDependencies": {
"@types/node": "latest",
"@typescript-eslint/eslint-plugin": "^8.15.0",
"@typescript-eslint/parser": "^8.15.0",
"typescript-eslint": "^8.49.0",
"eslint": "^9.15.0",
"@typespec/compiler": "latest",
"typescript": "^5.3.3",
Expand Down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot add changelog

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added changeset using pnpm change add:

  • Package: @typespec/compiler
  • Type: Internal
  • Summary: Update init templates to use createTester API and modern ESLint configuration

Changeset file: .chronus/changes/copilot-update-init-templates-testing-framework-2026-1-5-20-11-37.md (commit: 6f97eac → current)

Original file line number Diff line number Diff line change
@@ -1,43 +1,16 @@
import { Diagnostic, resolvePath } from "@typespec/compiler";
import {
createTestHost,
createTestWrapper,
expectDiagnosticEmpty,
} from "@typespec/compiler/testing";
import { EmitterTsTestLibrary } from "../src/testing/index.js";
import { expectDiagnosticEmpty } from "@typespec/compiler/testing";
import { createTester } from "@typespec/compiler/testing";

export async function createEmitterTsTestHost() {
return createTestHost({
libraries: [EmitterTsTestLibrary],
});
}

export async function createEmitterTsTestRunner() {
const host = await createEmitterTsTestHost();

return createTestWrapper(host, {
compilerOptions: {
noEmit: false,
emit: ["emitter-ts"],
},
});
}
export const Tester = createTester(resolvePath(import.meta.dirname, "../.."), {
libraries: ["emitter-ts"],
}).emit("emitter-ts");

export async function emitWithDiagnostics(
code: string
): Promise<[Record<string, string>, readonly Diagnostic[]]> {
const runner = await createEmitterTsTestRunner();
await runner.compileAndDiagnose(code, {
outputDir: "tsp-output",
});
const emitterOutputDir = "./tsp-output/emitter-ts";
const files = await runner.program.host.readDir(emitterOutputDir);

const result: Record<string, string> = {};
for (const file of files) {
result[file] = (await runner.program.host.readFile(resolvePath(emitterOutputDir, file))).text;
}
return [result, runner.program.diagnostics];
const [{ outputs }, diagnostics] = await Tester.compileAndDiagnose(code);
return [outputs, diagnostics];
}

export async function emit(code: string): Promise<Record<string, string>> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
// @ts-check
import eslint from "@eslint/js";
import { defineConfig } from "eslint/config";
import tsEslint from "typescript-eslint";

export default tsEslint.config(
export default defineConfig(
{
ignores: ["**/dist/**/*", "**/.temp/**/*"],
},
eslint.configs.recommended,
...tsEslint.configs.recommended,
{
rules: {
"@typescript-eslint/no-unused-vars": [
"warn",
{ varsIgnorePattern: "^_", argsIgnorePattern: "^_" },
],
},
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
},
"devDependencies": {
"@types/node": "latest",
"@typescript-eslint/eslint-plugin": "^8.15.0",
"@typescript-eslint/parser": "^8.15.0",
"typescript-eslint": "^8.49.0",
"@typespec/compiler": "latest",
"@typespec/library-linter": "latest",
"eslint": "^9.15.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import { strictEqual } from "node:assert";
import { describe, it, beforeEach } from "node:test";
import type { Operation } from "@typespec/compiler";
import { BasicTestRunner, expectDiagnostics, extractCursor } from "@typespec/compiler/testing";
import { describe, it } from "node:test";
import type { Operation, Program } from "@typespec/compiler";
import { expectDiagnostics } from "@typespec/compiler/testing";
import { getAlternateName } from "../src/decorators.js";
import { createLibraryTsTestRunner } from "./test-host.js";
import { Tester } from "./test-host.js";

describe("decorators", () => {
let runner: BasicTestRunner;

beforeEach(async () => {
runner = await createLibraryTsTestRunner();
})

describe("@alternateName", () => {
it("set alternate name on operation", async () => {
const { test } = (await runner.compile(
`@alternateName("bar") @test op test(): void;`
)) as { test: Operation };
strictEqual(getAlternateName(runner.program, test), "bar");
const { test, program } = (await Tester.compile(`
using LibraryTs;
@alternateName("bar") @test op test(): void;
`)) as unknown as { test: Operation; program: Program };
strictEqual(getAlternateName(program, test), "bar");
});

it("emit diagnostic if not used on an operation", async () => {
const diagnostics = await runner.diagnose(
`@alternateName("bar") model Test {}`
);
const diagnostics = await Tester.diagnose(`
using LibraryTs;
@alternateName("bar") model Test {}
`);
expectDiagnostics(diagnostics, {
severity: "error",
code: "decorator-wrong-target",
Expand All @@ -33,15 +29,14 @@ describe("decorators", () => {


it("emit diagnostic if using banned name", async () => {
const {pos, source} = extractCursor(`@alternateName(┆"banned") op test(): void;`)
const diagnostics = await runner.diagnose(
source
);
const diagnostics = await Tester.diagnose(`
using LibraryTs;
@alternateName("banned") op test(): void;
`);
expectDiagnostics(diagnostics, {
severity: "error",
code: "library-ts/banned-alternate-name",
message: `Banned alternate name "banned".`,
pos: pos + runner.autoCodeOffset
message: `Banned alternate name "banned".`
})
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
import { createTestHost, createTestWrapper } from "@typespec/compiler/testing";
import { LibraryTsTestLibrary } from "../src/testing/index.js";
import { resolvePath } from "@typespec/compiler";
import { createTester } from "@typespec/compiler/testing";

export async function createLibraryTsTestHost() {
return createTestHost({
libraries: [LibraryTsTestLibrary],
});
}

export async function createLibraryTsTestRunner() {
const host = await createLibraryTsTestHost();

return createTestWrapper(host, {
autoUsings: ["LibraryTs"]
});
}
export const Tester = createTester(resolvePath(import.meta.dirname, "../.."), {
libraries: ["library-ts"],
}).import("library-ts");

11 changes: 10 additions & 1 deletion packages/compiler/templates/emitter-ts/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
// @ts-check
import eslint from "@eslint/js";
import { defineConfig } from "eslint/config";
import tsEslint from "typescript-eslint";

export default tsEslint.config(
export default defineConfig(
{
ignores: ["**/dist/**/*", "**/.temp/**/*"],
},
eslint.configs.recommended,
...tsEslint.configs.recommended,
{
rules: {
"@typescript-eslint/no-unused-vars": [
"warn",
{ varsIgnorePattern: "^_", argsIgnorePattern: "^_" },
],
},
},
);
3 changes: 1 addition & 2 deletions packages/compiler/templates/emitter-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
},
"devDependencies": {
"@types/node": "latest",
"@typescript-eslint/eslint-plugin": "^8.15.0",
"@typescript-eslint/parser": "^8.15.0",
"typescript-eslint": "^8.49.0",
"eslint": "^9.15.0",
"@typespec/compiler": "latest",
"typescript": "^5.3.3",
Expand Down
41 changes: 7 additions & 34 deletions packages/compiler/templates/emitter-ts/test/test-host.ts.mu
Original file line number Diff line number Diff line change
@@ -1,43 +1,16 @@
import { Diagnostic, resolvePath } from "@typespec/compiler";
import {
createTestHost,
createTestWrapper,
expectDiagnosticEmpty,
} from "@typespec/compiler/testing";
import { {{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestLibrary } from "../src/testing/index.js";
import { expectDiagnosticEmpty } from "@typespec/compiler/testing";
import { createTester } from "@typespec/compiler/testing";

export async function create{{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestHost() {
return createTestHost({
libraries: [{{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestLibrary],
});
}

export async function create{{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestRunner() {
const host = await create{{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestHost();

return createTestWrapper(host, {
compilerOptions: {
noEmit: false,
emit: ["{{name}}"],
},
});
}
export const Tester = createTester(resolvePath(import.meta.dirname, "../.."), {
libraries: ["{{name}}"],
}).emit("{{name}}");

export async function emitWithDiagnostics(
code: string
): Promise<[Record<string, string>, readonly Diagnostic[]]> {
const runner = await create{{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestRunner();
await runner.compileAndDiagnose(code, {
outputDir: "tsp-output",
});
const emitterOutputDir = "./tsp-output/{{name}}";
const files = await runner.program.host.readDir(emitterOutputDir);

const result: Record<string, string> = {};
for (const file of files) {
result[file] = (await runner.program.host.readFile(resolvePath(emitterOutputDir, file))).text;
}
return [result, runner.program.diagnostics];
const [{ outputs }, diagnostics] = await Tester.compileAndDiagnose(code);
return [outputs, diagnostics];
}

export async function emit(code: string): Promise<Record<string, string>> {
Expand Down
11 changes: 10 additions & 1 deletion packages/compiler/templates/library-ts/eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
// @ts-check
import eslint from "@eslint/js";
import { defineConfig } from "eslint/config";
import tsEslint from "typescript-eslint";

export default tsEslint.config(
export default defineConfig(
{
ignores: ["**/dist/**/*", "**/.temp/**/*"],
},
eslint.configs.recommended,
...tsEslint.configs.recommended,
{
rules: {
"@typescript-eslint/no-unused-vars": [
"warn",
{ varsIgnorePattern: "^_", argsIgnorePattern: "^_" },
],
},
},
);
3 changes: 1 addition & 2 deletions packages/compiler/templates/library-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
},
"devDependencies": {
"@types/node": "latest",
"@typescript-eslint/eslint-plugin": "^8.15.0",
"@typescript-eslint/parser": "^8.15.0",
"typescript-eslint": "^8.49.0",
"@typespec/compiler": "latest",
"@typespec/library-linter": "latest",
"eslint": "^9.15.0",
Expand Down
41 changes: 18 additions & 23 deletions packages/compiler/templates/library-ts/test/decorators.test.ts.mu
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
import { strictEqual } from "node:assert";
import { describe, it, beforeEach } from "node:test";
import type { Operation } from "@typespec/compiler";
import { BasicTestRunner, expectDiagnostics, extractCursor } from "@typespec/compiler/testing";
import { describe, it } from "node:test";
import type { Operation, Program } from "@typespec/compiler";
import { expectDiagnostics } from "@typespec/compiler/testing";
import { getAlternateName } from "../src/decorators.js";
import { create{{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestRunner } from "./test-host.js";
import { Tester } from "./test-host.js";

describe("decorators", () => {
let runner: BasicTestRunner;

beforeEach(async () => {
runner = await create{{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestRunner();
})

describe("@alternateName", () => {
it("set alternate name on operation", async () => {
const { test } = (await runner.compile(
`@alternateName("bar") @test op test(): void;`
)) as { test: Operation };
strictEqual(getAlternateName(runner.program, test), "bar");
const { test, program } = (await Tester.compile(`
using {{#casing.pascalCase}}{{name}}{{/casing.pascalCase}};
@alternateName("bar") @test op test(): void;
`)) as unknown as { test: Operation; program: Program };
strictEqual(getAlternateName(program, test), "bar");
});

it("emit diagnostic if not used on an operation", async () => {
const diagnostics = await runner.diagnose(
`@alternateName("bar") model Test {}`
);
const diagnostics = await Tester.diagnose(`
using {{#casing.pascalCase}}{{name}}{{/casing.pascalCase}};
@alternateName("bar") model Test {}
`);
expectDiagnostics(diagnostics, {
severity: "error",
code: "decorator-wrong-target",
Expand All @@ -33,15 +29,14 @@ describe("decorators", () => {


it("emit diagnostic if using banned name", async () => {
const {pos, source} = extractCursor(`@alternateName(┆"banned") op test(): void;`)
const diagnostics = await runner.diagnose(
source
);
const diagnostics = await Tester.diagnose(`
using {{#casing.pascalCase}}{{name}}{{/casing.pascalCase}};
@alternateName("banned") op test(): void;
`);
expectDiagnostics(diagnostics, {
severity: "error",
code: "{{name}}/banned-alternate-name",
message: `Banned alternate name "banned".`,
pos: pos + runner.autoCodeOffset
message: `Banned alternate name "banned".`
})
});
});
Expand Down
Loading