Skip to content

Commit

Permalink
Ensure error messages mention source of problem
Browse files Browse the repository at this point in the history
  • Loading branch information
jakebailey committed Mar 5, 2024
1 parent 6de50d7 commit 0097e95
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 59 deletions.
6 changes: 3 additions & 3 deletions packages/dtslint/src/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ interface Tsconfig {
exclude?: string[];
}

export function checkTsconfig(dirPath: string, config: Tsconfig): string[] {
export function checkTsconfig(config: Tsconfig): string[] {
const errors = [];
const mustHave = {
noEmit: true,
Expand Down Expand Up @@ -140,13 +140,13 @@ export function checkTsconfig(dirPath: string, config: Tsconfig): string[] {
if (options.paths) {
for (const key in options.paths) {
if (options.paths[key].length !== 1) {
errors.push(`${dirPath}/tsconfig.json: "paths" must map each module specifier to only one file.`);
errors.push(`"paths" must map each module specifier to only one file.`);
}
const [target] = options.paths[key];
if (target !== "./index.d.ts") {
const m = target.match(/^(?:..\/)+([^\/]+)\/(?:v\d+\.?\d*\/)?index.d.ts$/);
if (!m || m[1] !== key) {
errors.push(`${dirPath}/tsconfig.json: "paths" must map '${key}' to ${key}'s index.d.ts.`);
errors.push(`"paths" must map '${key}' to ${key}'s index.d.ts.`);
}
}
}
Expand Down
14 changes: 11 additions & 3 deletions packages/dtslint/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,15 @@ async function runTests(
if (lows.length > 1) {
console.log("testing from", low, "to", hi, "in", versionPath);
}
const testTypesResult = await testTypesVersion(versionPath, packageJson.tsconfigs, low, hi, expectOnly, undefined, isLatest);
const testTypesResult = await testTypesVersion(
versionPath,
packageJson.tsconfigs,
low,
hi,
expectOnly,
undefined,
isLatest,
);
errors.push(...testTypesResult.errors);
}
}
Expand Down Expand Up @@ -278,9 +286,9 @@ async function testTypesVersion(

for (const tsconfig of tsconfigs) {
const tsconfigPath = joinPaths(dirPath, tsconfig);
const tsconfigErrors = checkTsconfig(dirPath, getCompilerOptions(tsconfigPath));
const tsconfigErrors = checkTsconfig(getCompilerOptions(tsconfigPath));
if (tsconfigErrors.length > 0) {
errors.push("\n\t* " + tsconfigErrors.join("\n\t* "));
errors.push("\n\t* " + tsconfigPath + ":\n\t* " + tsconfigErrors.join("\n\t* "));
}
}

Expand Down
95 changes: 42 additions & 53 deletions packages/dtslint/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,132 +20,121 @@ describe("dtslint", () => {
describe("checks", () => {
describe("checkTsconfig", () => {
it("disallows unknown compiler options", () => {
expect(checkTsconfig("test", based({ completelyInvented: true }))).toEqual([
expect(checkTsconfig(based({ completelyInvented: true }))).toEqual([
"Unexpected compiler option completelyInvented",
]);
});
it("allows exactOptionalPropertyTypes: true", () => {
expect(checkTsconfig("test", based({ exactOptionalPropertyTypes: true }))).toEqual([]);
expect(checkTsconfig(based({ exactOptionalPropertyTypes: true }))).toEqual([]);
});
it("allows module: node16", () => {
expect(checkTsconfig("test", based({ module: "node16" }))).toEqual([]);
expect(checkTsconfig(based({ module: "node16" }))).toEqual([]);
});
it("allows `paths`", () => {
expect(checkTsconfig("test", based({ paths: { boom: ["../boom/index.d.ts"] } }))).toEqual([]);
expect(checkTsconfig(based({ paths: { boom: ["../boom/index.d.ts"] } }))).toEqual([]);
});
it("disallows missing `module`", () => {
const compilerOptions = { ...base };
delete compilerOptions.module;
expect(checkTsconfig("test", { compilerOptions, files: ["index.d.ts", "base.test.ts"] })).toEqual([
expect(checkTsconfig({ compilerOptions, files: ["index.d.ts", "base.test.ts"] })).toEqual([
'Must specify "module" to `"module": "commonjs"` or `"module": "node16"`.',
]);
});
it("disallows exactOptionalPropertyTypes: false", () => {
expect(checkTsconfig("test", based({ exactOptionalPropertyTypes: false }))).toEqual([
expect(checkTsconfig(based({ exactOptionalPropertyTypes: false }))).toEqual([
'When "exactOptionalPropertyTypes" is present, it must be set to `true`.',
]);
});
it("allows paths: self-reference", () => {
expect(checkTsconfig("react-native", based({ paths: { "react-native": ["./index.d.ts"] } }))).toEqual([]);
expect(checkTsconfig(based({ paths: { "react-native": ["./index.d.ts"] } }))).toEqual([]);
});
it("allows paths: matching ../reference/index.d.ts", () => {
expect(
checkTsconfig("reactive-dep", based({ paths: { "react-native": ["../react-native/index.d.ts"] } })),
).toEqual([]);
expect(checkTsconfig(based({ paths: { "react-native": ["../react-native/index.d.ts"] } }))).toEqual([]);
expect(
checkTsconfig(
"reactive-dep",
based({ paths: { "react-native": ["../react-native/index.d.ts"], react: ["../react/v16/index.d.ts"] } }),
),
).toEqual([]);
});
it("forbids paths: mapping to multiple things", () => {
expect(
checkTsconfig(
"reactive-dep",
based({ paths: { "react-native": ["./index.d.ts", "../react-native/v0.68/index.d.ts"] } }),
),
).toEqual([`reactive-dep/tsconfig.json: "paths" must map each module specifier to only one file.`]);
checkTsconfig(based({ paths: { "react-native": ["./index.d.ts", "../react-native/v0.68/index.d.ts"] } })),
).toEqual([`"paths" must map each module specifier to only one file.`]);
});
it("allows paths: matching ../reference/version/index.d.ts", () => {
expect(checkTsconfig("reactive-dep", based({ paths: { react: ["../react/v16/index.d.ts"] } }))).toEqual([]);
expect(
checkTsconfig("reactive-dep", based({ paths: { "react-native": ["../react-native/v0.69/index.d.ts"] } })),
).toEqual([]);
expect(
checkTsconfig(
"reactive-dep/v1",
based({ paths: { "react-native": ["../../react-native/v0.69/index.d.ts"] } }),
),
).toEqual([]);
expect(checkTsconfig(based({ paths: { react: ["../react/v16/index.d.ts"] } }))).toEqual([]);
expect(checkTsconfig(based({ paths: { "react-native": ["../react-native/v0.69/index.d.ts"] } }))).toEqual([]);
expect(checkTsconfig(based({ paths: { "react-native": ["../../react-native/v0.69/index.d.ts"] } }))).toEqual(
[],
);
});
it("forbids paths: mapping to self-contained file", () => {
expect(checkTsconfig("rrrr", based({ paths: { "react-native": ["./other.d.ts"] } }))).toEqual([
`rrrr/tsconfig.json: "paths" must map 'react-native' to react-native's index.d.ts.`,
expect(checkTsconfig(based({ paths: { "react-native": ["./other.d.ts"] } }))).toEqual([
`"paths" must map 'react-native' to react-native's index.d.ts.`,
]);
});
it("forbids paths: mismatching ../NOT/index.d.ts", () => {
expect(checkTsconfig("rrrr", based({ paths: { "react-native": ["../cocoa/index.d.ts"] } }))).toEqual([
`rrrr/tsconfig.json: "paths" must map 'react-native' to react-native's index.d.ts.`,
expect(checkTsconfig(based({ paths: { "react-native": ["../cocoa/index.d.ts"] } }))).toEqual([
`"paths" must map 'react-native' to react-native's index.d.ts.`,
]);
});
it("forbids paths: mismatching ../react-native/NOT.d.ts", () => {
expect(checkTsconfig("rrrr", based({ paths: { "react-native": ["../react-native/other.d.ts"] } }))).toEqual([
`rrrr/tsconfig.json: "paths" must map 'react-native' to react-native's index.d.ts.`,
expect(checkTsconfig(based({ paths: { "react-native": ["../react-native/other.d.ts"] } }))).toEqual([
`"paths" must map 'react-native' to react-native's index.d.ts.`,
]);
});
it("forbids paths: mismatching ../react-native/NOT/index.d.ts", () => {
expect(
checkTsconfig("rrrr", based({ paths: { "react-native": ["../react-native/deep/index.d.ts"] } })),
).toEqual([`rrrr/tsconfig.json: "paths" must map 'react-native' to react-native's index.d.ts.`]);
expect(checkTsconfig(based({ paths: { "react-native": ["../react-native/deep/index.d.ts"] } }))).toEqual([
`"paths" must map 'react-native' to react-native's index.d.ts.`,
]);
});
it("forbids paths: mismatching ../react-native/version/NOT/index.d.ts", () => {
expect(
checkTsconfig("rrrr", based({ paths: { "react-native": ["../react-native/v0.68/deep/index.d.ts"] } })),
).toEqual([`rrrr/tsconfig.json: "paths" must map 'react-native' to react-native's index.d.ts.`]);
expect(checkTsconfig(based({ paths: { "react-native": ["../react-native/v0.68/deep/index.d.ts"] } }))).toEqual([
`"paths" must map 'react-native' to react-native's index.d.ts.`,
]);
});
it("forbids paths: mismatching ../react-native/version/NOT.d.ts", () => {
expect(
checkTsconfig("rrrr", based({ paths: { "react-native": ["../react-native/v0.70/other.d.ts"] } })),
).toEqual([`rrrr/tsconfig.json: "paths" must map 'react-native' to react-native's index.d.ts.`]);
expect(checkTsconfig(based({ paths: { "react-native": ["../react-native/v0.70/other.d.ts"] } }))).toEqual([
`"paths" must map 'react-native' to react-native's index.d.ts.`,
]);
});
it("Forbids exclude", () => {
expect(checkTsconfig("exclude", { compilerOptions: base, exclude: ["**/node_modules"] })).toEqual([
expect(checkTsconfig({ compilerOptions: base, exclude: ["**/node_modules"] })).toEqual([
`Use "files" instead of "exclude".`,
]);
});
it("Forbids include", () => {
expect(checkTsconfig("include", { compilerOptions: base, include: ["**/node_modules"] })).toEqual([
expect(checkTsconfig({ compilerOptions: base, include: ["**/node_modules"] })).toEqual([
`Use "files" instead of "include".`,
]);
});
it("Requires files", () => {
expect(checkTsconfig("include", { compilerOptions: base })).toEqual([`Must specify "files".`]);
expect(checkTsconfig({ compilerOptions: base })).toEqual([`Must specify "files".`]);
});
it("Requires files to contain index.d.ts", () => {
expect(
checkTsconfig("include", { compilerOptions: base, files: ["package-name.d.ts", "package-name.test.ts"] }),
).toEqual([`"files" list must include "index.d.ts".`]);
expect(checkTsconfig({ compilerOptions: base, files: ["package-name.d.ts", "package-name.test.ts"] })).toEqual([
`"files" list must include "index.d.ts".`,
]);
});
// it("Requires files to contain .[mc]ts file", () => {
// expect(checkTsconfig("include", { compilerOptions: base, files: ["index.d.ts"] })).toEqual([
// expect(checkTsconfig({ compilerOptions: base, files: ["index.d.ts"] })).toEqual([
// `"files" list must include at least one ".ts", ".tsx", ".mts" or ".cts" file for testing.`,
// ]);
// });
it("Allows files to contain index.d.ts plus a .tsx", () => {
expect(checkTsconfig("include", { compilerOptions: base, files: ["index.d.ts", "tests.tsx"] })).toEqual([]);
expect(checkTsconfig({ compilerOptions: base, files: ["index.d.ts", "tests.tsx"] })).toEqual([]);
});
it("Allows files to contain index.d.ts plus a .mts", () => {
expect(checkTsconfig("include", { compilerOptions: base, files: ["index.d.ts", "tests.mts"] })).toEqual([]);
expect(checkTsconfig({ compilerOptions: base, files: ["index.d.ts", "tests.mts"] })).toEqual([]);
});
it("Allows files to contain index.d.ts plus a .cts", () => {
expect(checkTsconfig("include", { compilerOptions: base, files: ["index.d.ts", "tests.cts"] })).toEqual([]);
expect(checkTsconfig({ compilerOptions: base, files: ["index.d.ts", "tests.cts"] })).toEqual([]);
});
it("Allows files to contain ./index.d.ts plus a ./.tsx", () => {
expect(checkTsconfig("include", { compilerOptions: base, files: ["./index.d.ts", "./tests.tsx"] })).toEqual([]);
expect(checkTsconfig({ compilerOptions: base, files: ["./index.d.ts", "./tests.tsx"] })).toEqual([]);
});
it("Issues both errors on empty files list", () => {
expect(checkTsconfig("include", { compilerOptions: base, files: [] })).toEqual([
expect(checkTsconfig({ compilerOptions: base, files: [] })).toEqual([
`"files" list must include "index.d.ts".`,
// `"files" list must include at least one ".ts", ".tsx", ".mts" or ".cts" file for testing.`,
]);
Expand Down

0 comments on commit 0097e95

Please sign in to comment.