Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix error messages when tsd fails #189

Merged
merged 2 commits into from
Mar 21, 2023
Merged
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
6 changes: 6 additions & 0 deletions source/cli.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env node
import meow from 'meow';
import {TsdError} from './lib/interfaces';
import formatter from './lib/formatter';
import tsd from './lib';

Expand Down Expand Up @@ -75,6 +76,11 @@ const exit = (message: string, {isError = true}: {isError?: boolean} = {}) => {
}
} catch (error: unknown) {
const potentialError = error as Error | undefined;

if (potentialError instanceof TsdError) {
exit(potentialError.message);
}

const errorMessage = potentialError?.stack ?? potentialError?.message ?? 'tsd unexpectedly crashed.';

exit(`Error running tsd:\n${errorMessage}`);
Expand Down
10 changes: 5 additions & 5 deletions source/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import globby from 'globby';
import {getDiagnostics as getTSDiagnostics} from './compiler';
import loadConfig from './config';
import getCustomDiagnostics from './rules';
import {Context, Config, Diagnostic, PackageJsonWithTsdConfig} from './interfaces';
import {Context, Config, Diagnostic, PackageJsonWithTsdConfig, TsdError} from './interfaces';

export interface Options {
cwd: string;
Expand All @@ -25,7 +25,7 @@ const findTypingsFile = async (pkg: PackageJsonWithTsdConfig, options: Options):
const typingsExist = await pathExists(typingsPath);

if (!typingsExist) {
throw new Error(`The type definition \`${typings}\` does not exist at \`${typingsPath}\`. Is the path correct? Create one and try again.`);
throw new TsdError(`The type definition \`${typings}\` does not exist at \`${typingsPath}\`. Is the path correct? Create one and try again.`);
}

return typings;
Expand All @@ -43,7 +43,7 @@ const findCustomTestFiles = async (testFilesPattern: readonly string[], cwd: str
const testFiles = await globby(testFilesPattern, {cwd});

if (testFiles.length === 0) {
throw new Error('Could not find any test files with the given pattern(s). Create one and try again.');
throw new TsdError('Could not find any test files with the given pattern(s). Create one and try again.');
}

return testFiles.map(file => path.join(cwd, file));
Expand All @@ -65,7 +65,7 @@ const findTestFiles = async (typingsFilePath: string, options: Options & {config
const testDirExists = await pathExists(path.join(options.cwd, testDir));

if (testFiles.length === 0 && !testDirExists) {
throw new Error(`The test file \`${testFile}\` or \`${tsxTestFile}\` does not exist in \`${options.cwd}\`. Create one and try again.`);
throw new TsdError(`The test file \`${testFile}\` or \`${tsxTestFile}\` does not exist in \`${options.cwd}\`. Create one and try again.`);
}

if (testFiles.length === 0) {
Expand All @@ -84,7 +84,7 @@ export default async (options: Options = {cwd: process.cwd()}): Promise<Diagnost
const pkgResult = await readPkgUp({cwd: options.cwd});

if (!pkgResult) {
throw new Error(`No \`package.json\` file found in \`${options.cwd}\`. Make sure you are running the command in a Node.js project.`);
throw new TsdError(`No \`package.json\` file found in \`${options.cwd}\`. Make sure you are running the command in a Node.js project.`);
}

const pkg = pkgResult.packageJson as PackageJsonWithTsdConfig;
Expand Down
7 changes: 7 additions & 0 deletions source/lib/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,10 @@ export interface Location {
start: number;
end: number;
}

export class TsdError extends Error {
constructor(message: string) {
super(message);
this.name = this.constructor.name;
}
}
9 changes: 9 additions & 0 deletions source/test/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,12 @@ test('warnings are reported with errors', async t => {
'1 error',
]);
});

test('tsd failures (not crashes) report only the message', async t => {
const cwd = path.join(__dirname, 'fixtures/no-tsd');

const {exitCode, stderr} = await t.throwsAsync<ExecaError>(execa('../../../cli.js', {cwd}));

t.is(exitCode, 1);
t.is(stderr, `The type definition \`index.d.ts\` does not exist at \`${cwd}/index.d.ts\`. Is the path correct? Create one and try again.`);
});
13 changes: 12 additions & 1 deletion source/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from 'path';
import test from 'ava';
import {verify, verifyWithFileName} from './fixtures/utils';
import tsd from '..';
import {Diagnostic} from '../lib/interfaces';
import {Diagnostic, TsdError} from '../lib/interfaces';

test('throw if no type definition was found', async t => {
const cwd = path.join(__dirname, 'fixtures/no-tsd');
Expand Down Expand Up @@ -427,3 +427,14 @@ test('parsing undefined symbol should not fail', async t => {

verify(t, diagnostics, []);
});

test('custom tsd errors are created correctly', t => {
const tsdError = t.throws<TsdError>(() => {
throw new TsdError('foo');
});

t.true(tsdError instanceof Error);
t.true(tsdError instanceof TsdError);
t.is(tsdError.name, 'TsdError');
t.is(tsdError.message, 'foo');
});