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
Expand Up @@ -2,6 +2,7 @@ import { describe, it, expect } from "vitest";
import { LanguageRegistry } from "../languages/language-registry.js";
import { StrictLanguageConfigSchema } from "../languages/types.js";
import { typescriptConfig } from "../languages/configs/typescript.js";
import { javascriptConfig } from "../languages/configs/javascript.js";
import { pythonConfig } from "../languages/configs/python.js";

describe("LanguageRegistry", () => {
Expand Down Expand Up @@ -72,6 +73,9 @@ describe("LanguageRegistry", () => {
expect(registry.getByExtension(".h")?.id).toBe("c");
expect(registry.getByExtension(".lua")?.id).toBe("lua");
expect(registry.getByExtension(".js")?.id).toBe("javascript");
expect(registry.getByExtension(".mts")?.id).toBe("typescript");
expect(registry.getByExtension(".cts")?.id).toBe("typescript");
expect(registry.getForFile("src/server.mts")?.id).toBe("typescript");
});

it("has no duplicate extension mappings across configs", () => {
Expand All @@ -93,6 +97,20 @@ describe("LanguageRegistry", () => {
});
});

describe("typescript config test patterns", () => {
it("recognizes both .test.tsx and .spec.tsx test files", () => {
expect(typescriptConfig.filePatterns.tests).toContain("*.test.tsx");
expect(typescriptConfig.filePatterns.tests).toContain("*.spec.tsx");
});
});

describe("javascript config test patterns", () => {
it("recognizes .jsx test files for parity with the .tsx patterns", () => {
expect(javascriptConfig.filePatterns.tests).toContain("*.test.jsx");
expect(javascriptConfig.filePatterns.tests).toContain("*.spec.jsx");
});
});

describe("Non-code language configs", () => {
it("detects all non-code file types via extension", () => {
const registry = LanguageRegistry.createDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const javascriptConfig = {
filePatterns: {
entryPoints: ["index.js", "src/index.js", "main.js"],
barrels: ["index.js"],
tests: ["*.test.js", "*.spec.js"],
tests: ["*.test.js", "*.spec.js", "*.test.jsx", "*.spec.jsx"],
config: ["package.json", "jsconfig.json"],
},
} satisfies LanguageConfig;
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import type { LanguageConfig } from "../types.js";
export const typescriptConfig = {
id: "typescript",
displayName: "TypeScript",
extensions: [".ts", ".tsx"],
// Declaration files (.d.ts / .d.mts / .d.cts) are intentionally NOT listed
// separately: getForFile() resolves by the final extension, so they fall
// through to .ts / .mts / .cts and are parsed as ordinary (types-only)
// TypeScript. They carry no runtime exports or call edges, so the extractor
// simply yields an empty call graph for them — no special gating is applied.
extensions: [".ts", ".tsx", ".mts", ".cts"],
treeSitter: {
wasmPackage: "tree-sitter-typescript",
wasmFile: "tree-sitter-typescript.wasm",
Expand All @@ -24,7 +29,7 @@ export const typescriptConfig = {
filePatterns: {
entryPoints: ["src/index.ts", "src/main.ts", "src/App.tsx", "index.ts"],
barrels: ["index.ts"],
tests: ["*.test.ts", "*.spec.ts", "*.test.tsx"],
tests: ["*.test.ts", "*.spec.ts", "*.test.tsx", "*.spec.tsx"],
config: ["tsconfig.json"],
},
} satisfies LanguageConfig;
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ export class TreeSitterPlugin implements AnalyzerPlugin {
private languageKeyFromPath(filePath: string): string | null {
const ext = extname(filePath).toLowerCase();

// Special case: .tsx needs its own grammar
// Special case: only .tsx needs the dedicated TSX grammar (it carries JSX).
// .mts / .cts deliberately fall through to the plain TypeScript grammar via
// _extensionToLang — they cannot contain JSX, so do NOT add them to this
// branch by analogy with the .mjs-treated-as-JS pattern.
if (ext === ".tsx") return "tsx";

return this._extensionToLang.get(ext) ?? null;
Expand Down
Loading