Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add types
Browse files Browse the repository at this point in the history
ljharb committed Feb 29, 2024
1 parent aa7de58 commit 74db73b
Showing 14 changed files with 588 additions and 37 deletions.
1 change: 1 addition & 0 deletions .github/workflows/node-aught.yml
Original file line number Diff line number Diff line change
@@ -9,3 +9,4 @@ jobs:
range: '< 10'
type: minors
command: npm run tests-only
skip-ls-check: true
1 change: 1 addition & 0 deletions bin/import-or-require.js
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ const { extname: extnamePath } = require('path');
const { pathToFileURL } = require('url');
const getPackageType = require('get-package-type');

/** @type {(file: string) => undefined | Promise<unknown>} */
// eslint-disable-next-line consistent-return
module.exports = function importOrRequire(file) {
const ext = extnamePath(file);
2 changes: 2 additions & 0 deletions bin/tape
Original file line number Diff line number Diff line change
@@ -95,6 +95,7 @@ var hasImport = require('has-dynamic-import');

var tape = require('../');

/** @type {(hasSupport: boolean) => Promise<void> | void} */
function importFiles(hasSupport) {
if (!hasSupport) {
return files.forEach(function (x) { require(x); });
@@ -104,6 +105,7 @@ function importFiles(hasSupport) {

tape.wait();

/** @type {null | undefined | Promise<unknown>} */
var filesPromise = files.reduce(function (promise, file) {
return promise ? promise.then(function () {
return importOrRequire(file);
82 changes: 82 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import type { ThroughStream } from '@ljharb/through';

import type Test from './lib/test';
import type Results from './lib/results';

declare function harnessFunction(this: ThisType<Test>, name: string, opts: tape.TestOptions, cb: tape.TestCase): Test;
declare function harnessFunction(this: ThisType<Test>, name: string, opts: tape.TestOptions): Test;
declare function harnessFunction(this: ThisType<Test>, name: string, cb: tape.TestCase): Test;
declare function harnessFunction(this: ThisType<Test>, name: string): Test;
declare function harnessFunction(this: ThisType<Test>, opts: tape.TestOptions, cb: tape.TestCase): Test;
declare function harnessFunction(this: ThisType<Test>, opts: tape.TestOptions): Test;
declare function harnessFunction(this: ThisType<Test>, cb: tape.TestCase): Test;

type HarnessCallSignatures = typeof harnessFunction

declare namespace tape {
export type TestOptions = {
objectPrintDepth?: number | undefined;
skip?: boolean | undefined;
timeout?: number | undefined;
todo?: boolean | undefined;
};

export interface AssertOptions {
skip?: boolean | string | undefined;
todo?: boolean | string | undefined;
message?: string | undefined;
actual?: unknown;
expected?: unknown;
exiting?: boolean;
}

export interface TestCase {
(test: Test): void | Promise<void>;
}

export interface StreamOptions {
objectMode?: boolean | undefined;
}

function createStream(opts?: StreamOptions): ThroughStream;

export type CreateStream = typeof createStream;

export type HarnessEventHandler = (cb: Test.SyncCallback, ...rest: unknown[]) => void;

function only(name: string, cb: tape.TestCase): void;
function only(name: string, opts: tape.TestOptions, cb: tape.TestCase): void;
function only(cb: tape.TestCase): void;
function only(opts: tape.TestOptions, cb: tape.TestCase): void;

export interface Harness extends HarnessCallSignatures {
run?: () => void;
only: typeof only;
_exitCode: number;
_results: Results;
_tests: Test[];
close: () => void;
createStream: CreateStream;
onFailure: HarnessEventHandler;
onFinish: HarnessEventHandler;
}

export type HarnessConfig = {
autoclose?: boolean;
noOnly?: boolean;
stream?: NodeJS.WritableStream | ThroughStream;
exit?: boolean;
} & StreamOptions;

function createHarness(conf_?: HarnessConfig): Harness;
const Test: Test;
const test: typeof tape;
const skip: Test['skip'];
}

declare function tape(this: tape.Harness, name: string, opts: tape.TestOptions, cb: tape.TestCase): Test;
declare function tape(this: tape.Harness, name: string, cb: tape.TestCase): Test;
declare function tape(this: tape.Harness, opts?: tape.TestOptions): Test;
declare function tape(this: tape.Harness, opts: tape.TestOptions, cb: tape.TestCase): Test;

export = tape;
42 changes: 34 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
'use strict';

var defined = require('defined');
var through = require('@ljharb/through');

var createDefaultStream = require('./lib/default_stream');
var Test = require('./lib/test');
var Results = require('./lib/results');
var through = require('@ljharb/through');

var canEmitExit = typeof process !== 'undefined' && process
// @ts-expect-error i think old browserify uses `process.browser`
&& typeof process.on === 'function' && process.browser !== true;
var canExit = typeof process !== 'undefined' && process
&& typeof process.exit === 'function';

/** @typedef {import('.')} Tape */
/** @typedef {import('.').Harness} Harness */
/** @typedef {import('.').HarnessConfig} HarnessConfig */
/** @typedef {import('.').TestOptions} TestOptions */
/** @typedef {import('.').HarnessEventHandler} HarnessEventHandler */
/** @typedef {import('.').CreateStream} CreateStream */
/** @typedef {import('.').createHarness} CreateHarness */
/** @typedef {import('./lib/results').Result} Result */
/** @typedef {import('stream').Writable} WritableStream */

module.exports = (function () {
var wait = false;
/** @type {undefined | Harness} */
var harness;

/** @type {(opts?: HarnessConfig) => Harness} */
function getHarness(opts) {
// this override is here since tests fail via nyc if createHarness is moved upwards
if (!harness) {
@@ -24,6 +38,7 @@ module.exports = (function () {
return harness;
}

/** @type {(this: Harness, ...args: Parameters<Tape>) => ReturnType<Tape>} */
function lazyLoad() {
// eslint-disable-next-line no-invalid-this
return getHarness().apply(this, arguments);
@@ -43,6 +58,7 @@ module.exports = (function () {
return getHarness().only.apply(this, arguments);
};

/** @type {CreateStream} */
lazyLoad.createStream = function (opts) {
var options = opts || {};
if (!harness) {
@@ -66,21 +82,23 @@ module.exports = (function () {
return lazyLoad;
}());

/** @type {CreateHarness} */
function createHarness(conf_) {
var results = new Results({ todoIsOK: !!(process.env.TODO_IS_OK === '1') });
if (!conf_ || conf_.autoclose !== false) {
results.once('done', function () { results.close(); });
}

/** @type {Harness} */
function test(name, conf, cb) {
var t = new Test(name, conf, cb);
test._tests.push(t);

(function inspectCode(st) {
st.on('test', function sub(st_) {
st.on('test', /** @type {(st: Test) => void} */ function sub(st_) {
inspectCode(st_);
});
st.on('result', function (r) {
st.on('result', /** @type {(r: Result) => void} */ function (r) {
if (!r.todo && !r.ok && typeof r !== 'string') { test._exitCode = 1; }
});
}(t));
@@ -90,21 +108,25 @@ function createHarness(conf_) {
}
test._results = results;

test._tests = [];
/** @type {Test[]} */ test._tests = [];

/** @type {CreateStream} */
test.createStream = function (opts) {
return results.createStream(opts);
};

/** @type {HarnessEventHandler} */
test.onFinish = function (cb) {
results.on('done', cb);
};

/** @type {HarnessEventHandler} */
test.onFailure = function (cb) {
results.on('fail', cb);
};

var only = false;
/** @type {() => Test} */
test.only = function () {
if (only) { throw new Error('there can only be one only test'); }
if (conf_ && conf_.noOnly) { throw new Error('`only` tests are prohibited'); }
@@ -120,6 +142,7 @@ function createHarness(conf_) {
return test;
}

/** @type {(conf: Omit<HarnessConfig, 'autoclose'>, wait?: boolean) => Harness} */
function createExitHarness(config, wait) {
var noOnly = config.noOnly;
var objectMode = config.objectMode;
@@ -137,9 +160,11 @@ function createExitHarness(config, wait) {
if (running) { return; }
running = true;
var stream = harness.createStream({ objectMode: objectMode });
var es = stream.pipe(cStream || createDefaultStream());
// eslint-disable-next-line no-extra-parens
var es = stream.pipe(/** @type {WritableStream} */ (cStream || createDefaultStream()));
if (canEmitExit && es) { // in node v0.4, `es` is `undefined`
// TODO: use `err` arg?
// @ts-expect-error
// eslint-disable-next-line no-unused-vars
es.on('error', function (err) { harness._exitCode = 1; });
}
@@ -180,6 +205,7 @@ function createExitHarness(config, wait) {
}

module.exports.createHarness = createHarness;
module.exports.Test = Test;
module.exports.test = module.exports; // tap compat
module.exports.test.skip = Test.skip;
var moduleExports = module.exports; // this hack is needed because TS has a bug with seemingly circular exports
moduleExports.Test = Test;
moduleExports.test = module.exports; // tap compat
moduleExports.skip = Test.skip;
5 changes: 5 additions & 0 deletions lib/default_stream.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { ThroughStream } from "@ljharb/through";

declare function defaultStream(): ThroughStream;

export = defaultStream;
11 changes: 7 additions & 4 deletions lib/default_stream.js
Original file line number Diff line number Diff line change
@@ -3,11 +3,13 @@
var through = require('@ljharb/through');
var fs = require('fs');

/** @type {import('./default_stream')} */
module.exports = function () {
var line = '';
var stream = through(write, flush);
return stream;

/** @type {(buf: unknown) => void} */
function write(buf) {
if (
buf == null // eslint-disable-line eqeqeq
@@ -16,10 +18,11 @@ module.exports = function () {
flush();
return;
}
for (var i = 0; i < buf.length; i++) {
var c = typeof buf === 'string'
? buf.charAt(i)
: String.fromCharCode(buf[i]);
var b = /** @type {string | ArrayLike<number>} */ (buf); // eslint-disable-line no-extra-parens
for (var i = 0; i < b.length; i++) {
var c = typeof b === 'string'
? b.charAt(i)
: String.fromCharCode(b[i]);
if (c === '\n') {
flush();
} else {
52 changes: 52 additions & 0 deletions lib/results.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import through from '@ljharb/through';
import type { EventEmitter } from 'events';

import type { StreamOptions } from '../';
import Test = require('./test');

declare class Results extends EventEmitter {
constructor(options?: { todoIsOK?: boolean });

count: number;
fail: number;
pass: number;
tests: Test[];
todo: number;
todoIsOK: boolean;
closed?: boolean;

_isRunning: boolean;
_only: Test | null;
_stream: through.ThroughStream;

close(this: Results): void;
createStream(this: Results, opts?: StreamOptions): through.ThroughStream;
only(this: Results, t: Test): void;
push(this: Results, t: Test): void;

_watch(this: Results, t: Test): void;
}

declare namespace Results {
export type Operator = string;

export type Result = {
id: number;
ok: boolean;
skip: unknown;
todo: unknown;
name?: string;
operator: undefined | Operator;
objectPrintDepth?: number;
actual?: unknown;
expected?: unknown;
error?: unknown;
functionName?: string;
file?: string;
line?: number;
column?: number;
at?: string;
};
}

export = Results;
42 changes: 33 additions & 9 deletions lib/results.js
Original file line number Diff line number Diff line change
@@ -18,10 +18,19 @@ var nextTick = typeof setImmediate !== 'undefined'
? setImmediate
: process.nextTick;

/** @typedef {through.ThroughStream} Stream */
/** @typedef {{ ok: boolean, name: string, skip?: unknown, todo?: unknown, operator: unknown, objectPrintDepth?: number, expected: unknown, actual: unknown, at?: string, error?: Error, test: unknown, type: unknown}} Result */
/** @typedef {import('./test')} Test */
/** @typedef {import('./results')} ResultsType */
/** @typedef {import('../').StreamOptions} StreamOptions */
/** @typedef {import('stream').Writable} WritableStream */

/** @type {(str: string) => string} */
function coalesceWhiteSpaces(str) {
return $replace(String(str), /\s+/g, ' ');
}

/** @type {(results: ResultsType) => Test | undefined} */
function getNextTest(results) {
if (!results._only) {
return $shift(results.tests);
@@ -37,10 +46,12 @@ function getNextTest(results) {
return void undefined;
}

/** @type {(str: string) => boolean} */
function invalidYaml(str) {
return $exec(yamlIndicators, str) !== null;
}

/** @type {(res: Result, count: number, todoIsOK?: boolean) => string} */
function encodeResult(res, count, todoIsOK) {
var output = '';
output += (res.ok || (todoIsOK && res.todo) ? 'ok ' : 'not ok ') + count;
@@ -76,6 +87,7 @@ function encodeResult(res, count, todoIsOK) {
output += inner + 'at: ' + res.at + '\n';
}

// @ts-expect-error it's fine if `res.actual` is not an Error; the stack would just be undefined.
var actualStack = res.actual && (typeof res.actual === 'object' || typeof res.actual === 'function') ? res.actual.stack : undefined;
var errorStack = res.error && res.error.stack;
var stack = defined(actualStack, errorStack);
@@ -91,6 +103,10 @@ function encodeResult(res, count, todoIsOK) {
return output;
}

/**
* @constructor
* @param {{ todoIsOK?: boolean }} [options]
*/
function Results(options) {
if (!(this instanceof Results)) { return new Results(options); }
var opts = (arguments.length > 0 ? arguments[0] : options) || {};
@@ -107,32 +123,34 @@ function Results(options) {

inherits(Results, EventEmitter);

/** @type {(this: ResultsType, opts?: StreamOptions) => Stream} */
Results.prototype.createStream = function (opts) {
if (!opts) { opts = {}; }
var self = this;
var output;
/** @type {Stream} */ var output;
var testId = 0;
if (opts.objectMode) {
output = through();
self.on('_push', function ontest(t, extra) {
self.on('_push', /** @type {(t: Test, extra: unknown ) => void} */ function ontest(t, extra) {
var id = testId++;
t.once('prerun', function () {
/** @type {{ parent?: unknown, type: string, name: string, id: number, skip: unknown, todo: unknown }} */
var row = {
type: 'test',
name: t.name,
id: id,
skip: t._skip,
todo: t._todo
};
if (extra && hasOwn(extra, 'parent')) {
if (extra && typeof extra === 'object' && 'parent' in extra && hasOwn(extra, 'parent')) {
row.parent = extra.parent;
}
output.queue(row);
});
t.on('test', function (st) {
t.on('test', /** @type {(st: Test) => void} */ function (st) {
ontest(st, { parent: id });
});
t.on('result', function (res) {
t.on('result', /** @type {(res: Result) => void} */ function (res) {
if (res && typeof res === 'object') {
res.test = id;
res.type = 'assert';
@@ -147,7 +165,8 @@ Results.prototype.createStream = function (opts) {
} else {
output = resumer();
output.queue('TAP version 13\n');
self._stream.pipe(output);
// eslint-disable-next-line no-extra-parens
self._stream.pipe(/** @type {WritableStream} */ (/** @type {unknown} */ (output)));
}

if (!this._isRunning) {
@@ -168,19 +187,22 @@ Results.prototype.createStream = function (opts) {
return output;
};

/** @type {import('./results').prototype.push} */
Results.prototype.push = function (t) {
$push(this.tests, t);
this._watch(t);
this.emit('_push', t);
};

/** @type {import('./results').prototype.only} */
Results.prototype.only = function (t) {
this._only = t;
};

/** @type {import('./results').prototype._watch} */
Results.prototype._watch = function (t) {
var self = this;
function write(s) { self._stream.queue(s); }
/** @type {(s: string) => void} */ function write(s) { self._stream.queue(s); }

t.once('prerun', function () {
var premsg = '';
@@ -194,7 +216,7 @@ Results.prototype._watch = function (t) {
write('# ' + premsg + coalesceWhiteSpaces(t.name) + postmsg + '\n');
});

t.on('result', function (res) {
t.on('result', /** @type {(res: Result | string) => void} */ function (res) {
if (typeof res === 'string') {
write('# ' + res + '\n');
return;
@@ -210,14 +232,16 @@ Results.prototype._watch = function (t) {
}
});

t.on('test', function (st) { self._watch(st); });
t.on('test', /** @type {(st: Test) => void} */ function (st) { self._watch(st); });
};

/** @type {import('./results').prototype.close} */
Results.prototype.close = function () {
var self = this;
if (self.closed) { self._stream.emit('error', new Error('ALREADY CLOSED')); }
self.closed = true;

/** @type {(s: string) => void} */
function write(s) { self._stream.queue(s); }

write('\n1..' + self.count + '\n');
232 changes: 232 additions & 0 deletions lib/test.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import type { EventEmitter } from 'events';
import type mockProperty from 'mock-property';

import type {
AssertOptions,
TestOptions,
} from '../';
import type {
Operator,
} from './results';

declare class Test extends EventEmitter {
constructor(name: string, opts: TestOptions, cb: Test.Callback);
constructor(name: string, opts: TestOptions);
constructor(name: string, cb: Test.Callback);
constructor(name: string);
constructor(opts: TestOptions);
constructor(cb: Test.Callback);
constructor(opts: TestOptions, cb: Test.Callback);

readable: boolean;
name: string;
assertCount: number;
pendingCount: number;
calledEnd?: boolean;
ended: boolean;

// "private" properties
_cb: Test.Callback | undefined;
_objectPrintDepth: number | undefined;
_ok: boolean;
_plan: number | undefined;
_planError: boolean | undefined;
_progeny: Test[];
_skip: boolean | undefined;
_teardown: Test.Callback[];
_timeout: number | undefined;
_todo: boolean | undefined;

captureFn<X extends Test.Callback>(this: Test, original: X): Test.WrappedFn<X>;
capture<T extends Test.Callback>(this: Test, obj: object, method: PropertyKey, implementation?: T): Test.WrapResults;
end(this: Test, err?: unknown): void;
fail(this: Test, msg: string, extra?: AssertOptions): void;
intercept(this: Test, obj: object, property: PropertyKey, desc?: PropertyDescriptor): Test.InterceptResults;
pass(this: Test, msg: string, extra?: AssertOptions): void;
run(this: Test): void;
skip(this: Test, msg: string, extra?: AssertOptions): void;
timeoutAfter(this: Test, ms: number): void;
plan(this: Test, n: number): void;
comment(this: Test, msg: string): void;
teardown(this: Test, fn: Test.Callback): void;
test(this: Test, name: string, cb: Test.Callback): void;
test(this: Test, name: string, opts: TestOptions, cb: Test.Callback): void;

// assertions

ok(this: Test, value: unknown, msg: string, extra?: AssertOptions): void;
true: typeof this.ok;
assert: typeof this.ok;

notOK(this: Test, value: unknown, msg: string, extra?: AssertOptions): void;
false: typeof this.notOK;
notok: typeof this.notOK;

error(this: Test, err?: unknown, msg?: string, extra?: AssertOptions): void;
ifError: typeof this.error;
ifErr: typeof this.error;
iferror: typeof this.error;

equal(this: Test, a: unknown, b: unknown, msg: string, extra?: AssertOptions): void;
equals: typeof this.equal;
isEqual: typeof this.equal;
is: typeof this.equal;
strictEqual: typeof this.equal;
strictEquals: typeof this.equal;

notEqual(this: Test, a: unknown, b: unknown, msg: string, extra?: AssertOptions): void;
notEquals: typeof this.notEqual;
notStrictEqual: typeof this.notEqual;
notStrictEquals: typeof this.notEqual;
isNotEqual: typeof this.notEqual;
isNot: typeof this.notEqual;
not: typeof this.notEqual;
doesNotEqual: typeof this.notEqual;
isInequal: typeof this.notEqual;

looseEqual(this: Test, a: unknown, b: unknown, msg: string, extra?: AssertOptions): void;
looseEquals: typeof this.looseEqual;

notLooseEqual(this: Test, a: unknown, b: unknown, msg: string, extra?: AssertOptions): void;
notLooseEquals: typeof this.notLooseEqual;

deepEqual(this: Test, a: unknown, b: unknown, msg: string, extra?: AssertOptions): void;
deepEquals: typeof this.deepEqual;
isEquivalent: typeof this.deepEqual;
same: typeof this.deepEqual;

notDeepEqual(this: Test, a: unknown, b: unknown, msg: string, extra?: AssertOptions): void;
notDeepEquals: typeof this.notDeepEqual;
notEquivalent: typeof this.notDeepEqual;
notDeeply: typeof this.notDeepEqual;
notSame: typeof this.notDeepEqual;
isNotDeepEqual: typeof this.notDeepEqual;
isNotDeeply: typeof this.notDeepEqual;
isNotEquivalent: typeof this.notDeepEqual;
isInequivalent: typeof this.notDeepEqual;

deepLooseEqual(this: Test, a: unknown, b: unknown, msg: string, extra?: AssertOptions): void;

notDeepLooseEqual(this: Test, a: unknown, b: unknown, msg: string, extra?: AssertOptions): void;

throws(
this: Test,
fn: () => void,
exceptionExpected: RegExp | Function | Error | string | undefined,
msg: string,
extra?: AssertOptions,
): void;
throws(
this: Test,
fn: () => void,
msg: string,
extra?: AssertOptions,
): void;

doesNotThrow(
this: Test,
fn: () => void,
exceptionExpected: RegExp | Function | undefined,
msg: string,
extra?: AssertOptions,
): void;
doesNotThrow(
this: Test,
fn: () => void,
msg: string,
extra?: AssertOptions,
): void;

match(
this: Test,
actual: string,
expected: RegExp,
msg: string,
extra?: AssertOptions,
): void;

doesNotMatch(
this: Test,
actual: string,
expected: RegExp,
msg: string,
extra?: AssertOptions,
): void;

static skip(
name: string,
opts: TestOptions,
cb: Test.Callback,
): Test;

// "private" methods

_assert(
this: Test,
maybeOK: boolean | unknown,
opts: TestOptions & {
message?: string;
operator?: Operator;
error?: unknown;
actual?: unknown;
expected?: unknown;
extra?: AssertOptions & {
operator?: Operator;
error?: unknown;
};
},
): void;
_end(this: Test, err?: unknown): void;
_exit(this: Test): void;
_pendingAsserts(this: Test): number;
}

declare namespace Test {
export type SyncCallback = (...args: unknown[]) => unknown;
export type Callback = (...args: unknown[]) => unknown | Promise<unknown>;

export type ReturnCall = {
args: unknown[];
receiver: {};
returned: unknown;
};

export type ThrowCall = {
args: unknown[];
receiver: {};
threw: true;
};

export type Call = {
type: 'get' | 'set';
success: boolean;
value: unknown;
args: unknown[];
receiver: unknown;
}

export type RestoreFunction = Exclude<ReturnType<typeof mockProperty>, undefined>;

export type WrapResults = {
(): WrappedCall[];
restore?: RestoreFunction;
};

export type WrappedFn<T extends Callback> = { (): T; calls?: WrappedCall[] };

export type WrapObject<T extends Callback> = {
__proto__: null;
wrapped: WrappedFn<T>;
calls: WrappedCall[];
results: Test.WrapResults;
};

export type WrappedCall = ReturnCall | ThrowCall;

export type InterceptResults = {
(): Call[];
restore: RestoreFunction;
}
}

export = Test;
107 changes: 92 additions & 15 deletions lib/test.js

Large diffs are not rendered by default.

29 changes: 28 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -44,7 +44,32 @@
"string.prototype.trim": "^1.2.8"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.15.1",
"@ljharb/eslint-config": "^21.1.0",
"@ljharb/tsconfig": "^0.2.0",
"@types/array.prototype.every": "^1.1.1",
"@types/array.prototype.find": "^2.2.0",
"@types/array.prototype.flatmap": "^1.2.6",
"@types/call-bind": "^1.0.5",
"@types/concat-stream": "^2.0.3",
"@types/deep-equal": "^1.0.4",
"@types/defined": "^1.0.2",
"@types/eslint": "~8.4",
"@types/falafel": "^2.2.2",
"@types/for-each": "^0.3.3",
"@types/get-package-type": "^0.1.0",
"@types/glob": "^8.1.0",
"@types/inherits": "^0.0.33",
"@types/is-regex": "^1.0.2",
"@types/js-yaml": "^4.0.9",
"@types/minimist": "^1.2.5",
"@types/mock-property": "^1.0.2",
"@types/object-inspect": "^1.8.4",
"@types/object-is": "^1.1.0",
"@types/object-keys": "^1.0.3",
"@types/resolve": "^1.20.6",
"@types/string.prototype.trim": "^1.2.0",
"@types/tape": "^5.6.4",
"array.prototype.flatmap": "^1.3.2",
"aud": "^2.0.4",
"auto-changelog": "^2.4.0",
@@ -61,7 +86,8 @@
"nyc": "^10.3.2",
"safe-publish-latest": "^2.0.0",
"tap": "^8.0.1",
"tap-parser": "^5.4.0"
"tap-parser": "^5.4.0",
"typescript": "next"
},
"scripts": {
"prepack": "npmignore --auto --commentLines=autogenerated",
@@ -74,6 +100,7 @@
"eclint:windows": "eclint check *.js",
"prelint": "npm-run-posix-or-windows eclint",
"lint": "eslint --ext .js,.cjs,.mjs . bin/*",
"postlint": "tsc -P . && attw -P",
"pretest": "npm run lint",
"test": "npm-run-posix-or-windows tests-only",
"posttest": "aud --production",
7 changes: 7 additions & 0 deletions test/common.js
Original file line number Diff line number Diff line change
@@ -5,6 +5,10 @@ var spawn = require('child_process').spawn;
var concat = require('concat-stream');
var yaml = require('js-yaml');

/** @typedef {import('../lib/result').Result} Result */
/** @typedef {import('../lib/test').SyncCallback} SyncCallback */

/** @type {(body: string, includeStack: boolean) => Result} */
module.exports.getDiag = function (body, includeStack) {
var yamlStart = body.indexOf(' ---');
var yamlEnd = body.indexOf(' ...\n');
@@ -38,6 +42,7 @@ module.exports.getDiag = function (body, includeStack) {
// strip out all stack frames that aren't directly under our test directory,
// and replace them with placeholders.

/** @type {(line: string) => null | string} */
var stripChangingData = function (line) {
var withoutTestDir = line.replace(__dirname, '$TEST');
var withoutPackageDir = withoutTestDir.replace(path.dirname(__dirname), '$TAPE');
@@ -62,6 +67,7 @@ var stripChangingData = function (line) {
};
module.exports.stripChangingData = stripChangingData;

/** @type {(output: string) => string} */
module.exports.stripFullStack = function (output) {
var stripped = ' [... stack stripped ...]';
var withDuplicates = output.split(/\r?\n/g).map(stripChangingData).map(function (line) {
@@ -97,6 +103,7 @@ module.exports.stripFullStack = function (output) {
).split(/\r?\n/g);
};

/** @type {(folderName: string, fileName: string, cb: SyncCallback) => void} */
module.exports.runProgram = function (folderName, fileName, cb) {
var result = {
stdout: null,
12 changes: 12 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extends": "@ljharb/tsconfig",
"compilerOptions": {
"target": "ES2021",
"strictBindCallApply": false, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
},
"exclude": [
"coverage/**",
"example/**",
"test/**/*",
],
}

0 comments on commit 74db73b

Please sign in to comment.