Skip to content

Commit d6d32e7

Browse files
Expose programming API - fixes #37
1 parent 874092b commit d6d32e7

File tree

7 files changed

+103
-34
lines changed

7 files changed

+103
-34
lines changed

package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
"node": ">=6"
1717
},
1818
"scripts": {
19-
"prepublishOnly": "npm run build && chmod +x dist/cli.js",
19+
"prepublishOnly": "npm run build",
2020
"pretest": "npm run build && cpy \"./**/**\" \"../../../dist/test/fixtures/\" --parents --cwd=source/test/fixtures",
2121
"test": "npm run lint && ava dist/test/test.js",
22-
"build": "npm run clean && tsc",
22+
"build": "npm run clean && tsc && chmod +x dist/cli.js",
2323
"clean": "del-cli dist",
2424
"lint": "tslint -p . --format stylish"
2525
},
@@ -41,6 +41,7 @@
4141
],
4242
"dependencies": {
4343
"eslint-formatter-pretty": "^1.3.0",
44+
"execa": "^2.0.4",
4445
"globby": "^9.1.0",
4546
"meow": "^5.0.0",
4647
"path-exists": "^3.0.0",

readme.md

+31
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,37 @@ Check if the function call has argument type errors.
153153
Check if a value is of the provided type `T`.
154154

155155

156+
## Programmatic API
157+
158+
You can use the programmatic API to retrieve the diagnostics and do something with them. This can be useful to run the tests with AVA, Jest or any other testing framework.
159+
160+
```ts
161+
import tsd from 'tsd';
162+
163+
(async () => {
164+
const diagnostics = await tsd();
165+
166+
console.log(diagnostics.length);
167+
//=> 2
168+
})();
169+
```
170+
171+
### tsd([options])
172+
173+
Retrieve the type definition diagnostics of the project.
174+
175+
#### options
176+
177+
Type: `object`
178+
179+
##### cwd
180+
181+
Type: `string`<br>
182+
Default: `process.cwd()`
183+
184+
Current working directory of the project to retrieve the diagnostics for.
185+
186+
156187
## License
157188

158189
MIT © [Sam Verschueren](https://github.com/SamVerschueren)

source/cli.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import tsd from './lib';
66

77
const cli = meow(`
88
Usage
9-
$ tsd [path]
9+
$ tsd [path]
1010
1111
Examples
1212
$ tsd /path/to/project

source/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1+
import tsd from './lib';
2+
13
export * from './lib/assert';
4+
export default tsd;

source/lib/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import loadConfig from './config';
77
import getCustomDiagnostics from './rules';
88
import {Context, Config} from './interfaces';
99

10-
interface Options {
10+
export interface Options {
1111
cwd: string;
1212
}
1313

source/test/cli.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as path from 'path';
2+
import test from 'ava';
3+
import * as execa from 'execa';
4+
5+
interface ExecaError extends Error {
6+
readonly exitCode: number;
7+
readonly stderr: string;
8+
}
9+
10+
test('fail if errors are found', async t => {
11+
const {exitCode, stderr} = await t.throwsAsync<ExecaError>(execa('../../../cli.js', {
12+
cwd: path.join(__dirname, 'fixtures/failure')
13+
}));
14+
15+
t.is(exitCode, 1);
16+
t.regex(stderr, /5:19[ ]{2}Argument of type number is not assignable to parameter of type string./);
17+
});
18+
19+
test('succeed if no errors are found', async t => {
20+
const {exitCode} = await execa('../../../cli.js', {
21+
cwd: path.join(__dirname, 'fixtures/success')
22+
});
23+
24+
t.is(exitCode, 0);
25+
});
26+
27+
test('provide a path', async t => {
28+
const file = path.join(__dirname, 'fixtures/failure');
29+
30+
const {exitCode, stderr} = await t.throwsAsync<ExecaError>(execa('dist/cli.js', [file]));
31+
32+
t.is(exitCode, 1);
33+
t.regex(stderr, /5:19[ ]{2}Argument of type number is not assignable to parameter of type string./);
34+
});

source/test/test.ts

+30-30
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as path from 'path';
22
import test, {ExecutionContext} from 'ava';
3-
import m from '../lib';
3+
import tsd from '..';
44
import {Diagnostic} from '../lib/interfaces';
55

66
type Expectation = [number, number, 'error' | 'warning', string, (string | RegExp)?];
@@ -32,23 +32,23 @@ const verify = (t: ExecutionContext, diagnostics: Diagnostic[], expectations: Ex
3232
};
3333

3434
test('throw if no type definition was found', async t => {
35-
await t.throwsAsync(m({cwd: path.join(__dirname, 'fixtures/no-tsd')}), 'The type definition `index.d.ts` does not exist. Create one and try again.');
35+
await t.throwsAsync(tsd({cwd: path.join(__dirname, 'fixtures/no-tsd')}), 'The type definition `index.d.ts` does not exist. Create one and try again.');
3636
});
3737

3838
test('throw if no test is found', async t => {
39-
await t.throwsAsync(m({cwd: path.join(__dirname, 'fixtures/no-test')}), 'The test file `index.test-d.ts` or `index.test-d.tsx` does not exist. Create one and try again.');
39+
await t.throwsAsync(tsd({cwd: path.join(__dirname, 'fixtures/no-test')}), 'The test file `index.test-d.ts` or `index.test-d.tsx` does not exist. Create one and try again.');
4040
});
4141

4242
test('return diagnostics', async t => {
43-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/failure')});
43+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/failure')});
4444

4545
verify(t, diagnostics, [
4646
[5, 19, 'error', 'Argument of type \'number\' is not assignable to parameter of type \'string\'.']
4747
]);
4848
});
4949

5050
test('return diagnostics from imported files as well', async t => {
51-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/failure-nested')});
51+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/failure-nested')});
5252

5353
verify(t, diagnostics, [
5454
[5, 19, 'error', 'Argument of type \'number\' is not assignable to parameter of type \'string\'.', /child.test-d.ts$/],
@@ -57,23 +57,23 @@ test('return diagnostics from imported files as well', async t => {
5757
});
5858

5959
test('fail if typings file is not part of `files` list', async t => {
60-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/no-files')});
60+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/no-files')});
6161

6262
verify(t, diagnostics, [
6363
[3, 1, 'error', 'TypeScript type definition `index.d.ts` is not part of the `files` list.', 'package.json'],
6464
]);
6565
});
6666

6767
test('fail if `typings` property is used instead of `types`', async t => {
68-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/types-property/typings')});
68+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/types-property/typings')});
6969

7070
verify(t, diagnostics, [
7171
[3, 1, 'error', 'Use property `types` instead of `typings`.', 'package.json'],
7272
]);
7373
});
7474

7575
test('fail if tests don\'t pass in strict mode', async t => {
76-
const diagnostics = await m({
76+
const diagnostics = await tsd({
7777
cwd: path.join(__dirname, 'fixtures/failure-strict-null-checks')
7878
});
7979

@@ -83,7 +83,7 @@ test('fail if tests don\'t pass in strict mode', async t => {
8383
});
8484

8585
test('overridden config defaults to `strict` if `strict` is not explicitly overridden', async t => {
86-
const diagnostics = await m({
86+
const diagnostics = await tsd({
8787
cwd: path.join(__dirname, 'fixtures/strict-null-checks-as-default-config-value')
8888
});
8989

@@ -93,7 +93,7 @@ test('overridden config defaults to `strict` if `strict` is not explicitly overr
9393
});
9494

9595
test('fail if types are used from a lib that was not explicitly specified', async t => {
96-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/lib-config/failure-missing-lib')});
96+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/lib-config/failure-missing-lib')});
9797

9898
verify(t, diagnostics, [
9999
[1, 22, 'error', 'Cannot find name \'Window\'.', /failure-missing-lib\/index.d.ts$/],
@@ -102,97 +102,97 @@ test('fail if types are used from a lib that was not explicitly specified', asyn
102102
});
103103

104104
test('allow specifying a lib as a triple-slash-reference', async t => {
105-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/lib-config/lib-as-triple-slash-reference')});
105+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/lib-config/lib-as-triple-slash-reference')});
106106

107107
verify(t, diagnostics, []);
108108
});
109109

110110
test('allow specifying a lib in package.json\'s `tsd` field', async t => {
111-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/lib-config/lib-from-package-json')});
111+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/lib-config/lib-from-package-json')});
112112

113113
verify(t, diagnostics, []);
114114
});
115115

116116
test('allow specifying a lib in tsconfig.json', async t => {
117-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/lib-config/lib-from-tsconfig-json')});
117+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/lib-config/lib-from-tsconfig-json')});
118118

119119
verify(t, diagnostics, []);
120120
});
121121

122122
test('a lib option in package.json overrdides a lib option in tsconfig.json', async t => {
123-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/lib-config/lib-from-package-json-overrides-tsconfig-json')});
123+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/lib-config/lib-from-package-json-overrides-tsconfig-json')});
124124

125125
verify(t, diagnostics, []);
126126
});
127127

128128
test('pass in loose mode when strict mode is disabled in settings', async t => {
129-
const diagnostics = await m({
129+
const diagnostics = await tsd({
130130
cwd: path.join(__dirname, 'fixtures/non-strict-check-with-config')
131131
});
132132

133133
verify(t, diagnostics, []);
134134
});
135135

136136
test('return no diagnostics', async t => {
137-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/success')});
137+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/success')});
138138

139139
verify(t, diagnostics, []);
140140
});
141141

142142
test('support non-barrel main', async t => {
143-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/test-non-barrel-main')});
143+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/test-non-barrel-main')});
144144

145145
verify(t, diagnostics, []);
146146
});
147147

148148
test('support non-barrel main using `types` property', async t => {
149-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/test-non-barrel-main-via-types')});
149+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/test-non-barrel-main-via-types')});
150150

151151
verify(t, diagnostics, []);
152152
});
153153

154154
test('support testing in sub-directories', async t => {
155-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/test-in-subdir')});
155+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/test-in-subdir')});
156156

157157
verify(t, diagnostics, []);
158158
});
159159

160160
test('support top-level await', async t => {
161-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/top-level-await')});
161+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/top-level-await')});
162162

163163
verify(t, diagnostics, []);
164164
});
165165

166166
test('support default test directory', async t => {
167-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/test-directory/default')});
167+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/test-directory/default')});
168168

169169
verify(t, diagnostics, []);
170170
});
171171

172172
test('support tsx in subdirectory', async t => {
173-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/test-directory/tsx')});
173+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/test-directory/tsx')});
174174

175175
verify(t, diagnostics, []);
176176
});
177177

178178
test('support setting a custom test directory', async t => {
179-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/test-directory/custom')});
179+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/test-directory/custom')});
180180

181181
verify(t, diagnostics, [
182182
[4, 0, 'error', 'Expected an error, but found none.']
183183
]);
184184
});
185185

186186
test('expectError for functions', async t => {
187-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/expect-error/functions')});
187+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/expect-error/functions')});
188188

189189
verify(t, diagnostics, [
190190
[5, 0, 'error', 'Expected an error, but found none.']
191191
]);
192192
});
193193

194194
test('expectError should not ignore syntactical errors', async t => {
195-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/expect-error/syntax')});
195+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/expect-error/syntax')});
196196

197197
verify(t, diagnostics, [
198198
[4, 29, 'error', '\')\' expected.'],
@@ -203,29 +203,29 @@ test('expectError should not ignore syntactical errors', async t => {
203203
});
204204

205205
test('expectError for values', async t => {
206-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/expect-error/values')});
206+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/expect-error/values')});
207207

208208
verify(t, diagnostics, [
209209
[5, 0, 'error', 'Expected an error, but found none.']
210210
]);
211211
});
212212

213213
test('missing import', async t => {
214-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/missing-import')});
214+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/missing-import')});
215215

216216
verify(t, diagnostics, [
217217
[3, 18, 'error', 'Cannot find name \'Primitive\'.']
218218
]);
219219
});
220220

221221
test('tsx', async t => {
222-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/tsx')});
222+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/tsx')});
223223

224224
verify(t, diagnostics, []);
225225
});
226226

227227
test('loose types', async t => {
228-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/strict-types/loose')});
228+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/strict-types/loose')});
229229

230230
verify(t, diagnostics, [
231231
[5, 0, 'error', 'Parameter type `string` is declared too wide for argument type `"cat"`.'],
@@ -242,7 +242,7 @@ test('loose types', async t => {
242242
});
243243

244244
test('strict types', async t => {
245-
const diagnostics = await m({cwd: path.join(__dirname, 'fixtures/strict-types/strict')});
245+
const diagnostics = await tsd({cwd: path.join(__dirname, 'fixtures/strict-types/strict')});
246246

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

0 commit comments

Comments
 (0)