tstyche 1.0.0-beta.3 → 1.0.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/README.md +6 -6
- package/build/index.cjs +0 -1
- package/build/index.d.cts +13 -17
- package/build/index.d.ts +13 -17
- package/build/index.js +1 -1
- package/build/tstyche.d.ts +3 -3
- package/build/tstyche.js +105 -79
- package/package.json +14 -43
- package/lib/schema.json +0 -47
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [1.0.0-beta.5] - 2023-11-27
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Breaking:** Move retry logic to the `Lock` class ([#31](https://github.com/tstyche/tstyche/pull/31))
|
|
8
|
+
- Bring back support for Node.js 16 ([#28](https://github.com/tstyche/tstyche/pull/28), [#27](https://github.com/tstyche/tstyche/pull/27))
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Add support for the `current` target tag ([#33](https://github.com/tstyche/tstyche/pull/33))
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Allow `.raiseError()` to take template literals as arguments. ([#35](https://github.com/tstyche/tstyche/pull/35))
|
|
17
|
+
|
|
18
|
+
## [1.0.0-beta.4] - 2023-11-24
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Use Node.js Fetch API ([#23](https://github.com/tstyche/tstyche/pull/23))
|
|
23
|
+
|
|
24
|
+
### Removed
|
|
25
|
+
|
|
26
|
+
- **Breaking:** Remove the `context()` helper ([#24](https://github.com/tstyche/tstyche/pull/24))
|
|
27
|
+
- **Breaking:** Drop support for Node.js 16 ([#22](https://github.com/tstyche/tstyche/pull/22))
|
|
28
|
+
- **Breaking:** Rename methods of the `StoreService` class ([`5d74201`](https://github.com/tstyche/tstyche/commit/5d74201))
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Tune up behavior of `.skip` and `.only` run mode flags ([#25](https://github.com/tstyche/tstyche/pull/25))
|
|
33
|
+
- Clean up error messages of primitive type matchers ([#21](https://github.com/tstyche/tstyche/pull/21))
|
|
34
|
+
- Normalize `installationPath` path output ([#19](https://github.com/tstyche/tstyche/pull/19))
|
|
35
|
+
|
|
36
|
+
## [1.0.0-beta.3] - 2023-11-13
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- Support TypeScript's 'node10' and 'node16' resolutions ([`7dd805a`](https://github.com/tstyche/tstyche/commit/7dd805a), [`9c83e79`](https://github.com/tstyche/tstyche/commit/9c83e79))
|
|
41
|
+
|
|
42
|
+
## [1.0.0-beta.2] - 2023-11-12
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- Support TypeScript's 'node10' resolution ([#7](https://github.com/tstyche/tstyche/pull/7))
|
|
47
|
+
|
|
48
|
+
## [1.0.0-beta.1] - 2023-11-09
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- Include 'cjs' files in the published package ([`90b6473`](https://github.com/tstyche/tstyche/commit/90b6473))
|
|
53
|
+
|
|
54
|
+
## [1.0.0-beta.0] - 2023-11-09
|
|
55
|
+
|
|
56
|
+
_First pre-release._
|
|
57
|
+
|
|
58
|
+
[1.0.0-beta.5]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.5
|
|
59
|
+
[1.0.0-beta.4]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.4
|
|
60
|
+
[1.0.0-beta.3]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.3
|
|
61
|
+
[1.0.0-beta.2]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.2
|
|
62
|
+
[1.0.0-beta.1]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.1
|
|
63
|
+
[1.0.0-beta.0]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.0
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ test("firstItem", () => {
|
|
|
31
31
|
|
|
32
32
|
To organize, debug and plan tests TSTyche has:
|
|
33
33
|
|
|
34
|
-
- `test()`, `it()
|
|
34
|
+
- `test()`, `it()` and `describe()` helpers,
|
|
35
35
|
- with `.only`, `.skip` and `.todo` run mode flags.
|
|
36
36
|
|
|
37
37
|
## Assertions
|
|
@@ -39,18 +39,18 @@ To organize, debug and plan tests TSTyche has:
|
|
|
39
39
|
The assertions can be used to write type tests (like in the above example) or mixed in your functional tests:
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
|
+
import assert from "node:assert/strict";
|
|
43
|
+
import { test } from "node:test";
|
|
42
44
|
import * as tstyche from "tstyche";
|
|
43
45
|
|
|
44
46
|
function secondItem<T>(target: Array<T>): T | undefined {
|
|
45
47
|
return target[1];
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
expect(secondItem([1, 2, 3])).toBe(1);
|
|
50
|
+
test("handles numbers", () => {
|
|
51
|
+
assert.strictEqual(secondItem([1, 2, 3]), 2);
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
});
|
|
53
|
+
tstyche.expect(secondItem([1, 2, 3])).type.toEqual<number | undefined>();
|
|
54
54
|
});
|
|
55
55
|
```
|
|
56
56
|
|
package/build/index.cjs
CHANGED
package/build/index.d.cts
CHANGED
|
@@ -60,7 +60,7 @@ interface Test {
|
|
|
60
60
|
}
|
|
61
61
|
interface Matchers {
|
|
62
62
|
/**
|
|
63
|
-
* Checks if the
|
|
63
|
+
* Checks if the `any` type is identical to the source type.
|
|
64
64
|
*/
|
|
65
65
|
toBeAny: () => void;
|
|
66
66
|
/**
|
|
@@ -77,47 +77,47 @@ interface Matchers {
|
|
|
77
77
|
(target: unknown): void;
|
|
78
78
|
};
|
|
79
79
|
/**
|
|
80
|
-
* Checks if the
|
|
80
|
+
* Checks if the `bigint` type is identical to the source type.
|
|
81
81
|
*/
|
|
82
82
|
toBeBigInt: () => void;
|
|
83
83
|
/**
|
|
84
|
-
* Checks if the
|
|
84
|
+
* Checks if the `boolean` type is identical to the source type.
|
|
85
85
|
*/
|
|
86
86
|
toBeBoolean: () => void;
|
|
87
87
|
/**
|
|
88
|
-
* Checks if the
|
|
88
|
+
* Checks if the `never` type is identical to the source type.
|
|
89
89
|
*/
|
|
90
90
|
toBeNever: () => void;
|
|
91
91
|
/**
|
|
92
|
-
* Checks if the
|
|
92
|
+
* Checks if the `null` type is identical to the source type.
|
|
93
93
|
*/
|
|
94
94
|
toBeNull: () => void;
|
|
95
95
|
/**
|
|
96
|
-
* Checks if the
|
|
96
|
+
* Checks if the `number` type is identical to the source type.
|
|
97
97
|
*/
|
|
98
98
|
toBeNumber: () => void;
|
|
99
99
|
/**
|
|
100
|
-
* Checks if the
|
|
100
|
+
* Checks if the `string` type is identical to the source type.
|
|
101
101
|
*/
|
|
102
102
|
toBeString: () => void;
|
|
103
103
|
/**
|
|
104
|
-
* Checks if the
|
|
104
|
+
* Checks if the `symbol` type is identical to the source type.
|
|
105
105
|
*/
|
|
106
106
|
toBeSymbol: () => void;
|
|
107
107
|
/**
|
|
108
|
-
* Checks if the
|
|
108
|
+
* Checks if the `undefined` type is identical to the source type.
|
|
109
109
|
*/
|
|
110
110
|
toBeUndefined: () => void;
|
|
111
111
|
/**
|
|
112
|
-
* Checks if the
|
|
112
|
+
* Checks if the `unique symbol` type is identical to the source type.
|
|
113
113
|
*/
|
|
114
114
|
toBeUniqueSymbol: () => void;
|
|
115
115
|
/**
|
|
116
|
-
* Checks if the
|
|
116
|
+
* Checks if the `unknown` type is identical to the source type.
|
|
117
117
|
*/
|
|
118
118
|
toBeUnknown: () => void;
|
|
119
119
|
/**
|
|
120
|
-
* Checks if the
|
|
120
|
+
* Checks if the `void` type is identical to the source type.
|
|
121
121
|
*/
|
|
122
122
|
toBeVoid: () => void;
|
|
123
123
|
/**
|
|
@@ -256,10 +256,6 @@ interface Expect {
|
|
|
256
256
|
* Defines a test group.
|
|
257
257
|
*/
|
|
258
258
|
declare const describe: Describe;
|
|
259
|
-
/**
|
|
260
|
-
* Defines a test group.
|
|
261
|
-
*/
|
|
262
|
-
declare const context: Describe;
|
|
263
259
|
/**
|
|
264
260
|
* Defines a single test.
|
|
265
261
|
*/
|
|
@@ -273,4 +269,4 @@ declare const it: Test;
|
|
|
273
269
|
*/
|
|
274
270
|
declare const expect: Expect;
|
|
275
271
|
|
|
276
|
-
export {
|
|
272
|
+
export { describe, expect, it, test };
|
package/build/index.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ interface Test {
|
|
|
60
60
|
}
|
|
61
61
|
interface Matchers {
|
|
62
62
|
/**
|
|
63
|
-
* Checks if the
|
|
63
|
+
* Checks if the `any` type is identical to the source type.
|
|
64
64
|
*/
|
|
65
65
|
toBeAny: () => void;
|
|
66
66
|
/**
|
|
@@ -77,47 +77,47 @@ interface Matchers {
|
|
|
77
77
|
(target: unknown): void;
|
|
78
78
|
};
|
|
79
79
|
/**
|
|
80
|
-
* Checks if the
|
|
80
|
+
* Checks if the `bigint` type is identical to the source type.
|
|
81
81
|
*/
|
|
82
82
|
toBeBigInt: () => void;
|
|
83
83
|
/**
|
|
84
|
-
* Checks if the
|
|
84
|
+
* Checks if the `boolean` type is identical to the source type.
|
|
85
85
|
*/
|
|
86
86
|
toBeBoolean: () => void;
|
|
87
87
|
/**
|
|
88
|
-
* Checks if the
|
|
88
|
+
* Checks if the `never` type is identical to the source type.
|
|
89
89
|
*/
|
|
90
90
|
toBeNever: () => void;
|
|
91
91
|
/**
|
|
92
|
-
* Checks if the
|
|
92
|
+
* Checks if the `null` type is identical to the source type.
|
|
93
93
|
*/
|
|
94
94
|
toBeNull: () => void;
|
|
95
95
|
/**
|
|
96
|
-
* Checks if the
|
|
96
|
+
* Checks if the `number` type is identical to the source type.
|
|
97
97
|
*/
|
|
98
98
|
toBeNumber: () => void;
|
|
99
99
|
/**
|
|
100
|
-
* Checks if the
|
|
100
|
+
* Checks if the `string` type is identical to the source type.
|
|
101
101
|
*/
|
|
102
102
|
toBeString: () => void;
|
|
103
103
|
/**
|
|
104
|
-
* Checks if the
|
|
104
|
+
* Checks if the `symbol` type is identical to the source type.
|
|
105
105
|
*/
|
|
106
106
|
toBeSymbol: () => void;
|
|
107
107
|
/**
|
|
108
|
-
* Checks if the
|
|
108
|
+
* Checks if the `undefined` type is identical to the source type.
|
|
109
109
|
*/
|
|
110
110
|
toBeUndefined: () => void;
|
|
111
111
|
/**
|
|
112
|
-
* Checks if the
|
|
112
|
+
* Checks if the `unique symbol` type is identical to the source type.
|
|
113
113
|
*/
|
|
114
114
|
toBeUniqueSymbol: () => void;
|
|
115
115
|
/**
|
|
116
|
-
* Checks if the
|
|
116
|
+
* Checks if the `unknown` type is identical to the source type.
|
|
117
117
|
*/
|
|
118
118
|
toBeUnknown: () => void;
|
|
119
119
|
/**
|
|
120
|
-
* Checks if the
|
|
120
|
+
* Checks if the `void` type is identical to the source type.
|
|
121
121
|
*/
|
|
122
122
|
toBeVoid: () => void;
|
|
123
123
|
/**
|
|
@@ -256,10 +256,6 @@ interface Expect {
|
|
|
256
256
|
* Defines a test group.
|
|
257
257
|
*/
|
|
258
258
|
declare const describe: Describe;
|
|
259
|
-
/**
|
|
260
|
-
* Defines a test group.
|
|
261
|
-
*/
|
|
262
|
-
declare const context: Describe;
|
|
263
259
|
/**
|
|
264
260
|
* Defines a single test.
|
|
265
261
|
*/
|
|
@@ -273,4 +269,4 @@ declare const it: Test;
|
|
|
273
269
|
*/
|
|
274
270
|
declare const expect: Expect;
|
|
275
271
|
|
|
276
|
-
export {
|
|
272
|
+
export { describe, expect, it, test };
|
package/build/index.js
CHANGED
package/build/tstyche.d.ts
CHANGED
|
@@ -35,10 +35,10 @@ declare class Diagnostic {
|
|
|
35
35
|
declare class StoreService {
|
|
36
36
|
#private;
|
|
37
37
|
constructor();
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
get supportedTags(): Array<string>;
|
|
39
|
+
install(tag: string, signal?: AbortSignal): Promise<string | undefined>;
|
|
40
|
+
load(tag: string, signal?: AbortSignal): Promise<typeof ts | undefined>;
|
|
40
41
|
open(signal?: AbortSignal): Promise<void>;
|
|
41
|
-
prepareCompilerModule(tag: string, signal?: AbortSignal): Promise<string | undefined>;
|
|
42
42
|
prune(): Promise<void>;
|
|
43
43
|
resolveTag(tag: string): string | undefined;
|
|
44
44
|
update(signal?: AbortSignal): Promise<void>;
|
package/build/tstyche.js
CHANGED
|
@@ -5,7 +5,6 @@ import path from 'node:path';
|
|
|
5
5
|
import fs from 'node:fs/promises';
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
7
|
import { spawn } from 'node:child_process';
|
|
8
|
-
import { setInterval } from 'node:timers/promises';
|
|
9
8
|
import https from 'node:https';
|
|
10
9
|
|
|
11
10
|
class EventEmitter {
|
|
@@ -1387,7 +1386,6 @@ class IdentifierLookup {
|
|
|
1387
1386
|
this.compiler = compiler;
|
|
1388
1387
|
this.#identifiers = identifiers ?? {
|
|
1389
1388
|
namedImports: {
|
|
1390
|
-
context: undefined,
|
|
1391
1389
|
describe: undefined,
|
|
1392
1390
|
expect: undefined,
|
|
1393
1391
|
it: undefined,
|
|
@@ -1464,7 +1462,6 @@ class IdentifierLookup {
|
|
|
1464
1462
|
return;
|
|
1465
1463
|
}
|
|
1466
1464
|
switch (identifierName) {
|
|
1467
|
-
case "context":
|
|
1468
1465
|
case "describe":
|
|
1469
1466
|
return { brand: "describe", flags };
|
|
1470
1467
|
case "it":
|
|
@@ -1621,7 +1618,7 @@ class ProjectService {
|
|
|
1621
1618
|
startGroup: doNothing,
|
|
1622
1619
|
};
|
|
1623
1620
|
const host = {
|
|
1624
|
-
...compiler.sys,
|
|
1621
|
+
...this.compiler.sys,
|
|
1625
1622
|
clearImmediate,
|
|
1626
1623
|
clearTimeout,
|
|
1627
1624
|
setImmediate,
|
|
@@ -1686,7 +1683,9 @@ class Checker {
|
|
|
1686
1683
|
this.#assertNonNullish(assertion.typeChecker, "The 'typeChecker' was not provided.");
|
|
1687
1684
|
}
|
|
1688
1685
|
#assertStringsOrNumbers(nodes) {
|
|
1689
|
-
return nodes.every((expression) => this.compiler.isStringLiteral(expression) ||
|
|
1686
|
+
return nodes.every((expression) => this.compiler.isStringLiteral(expression) ||
|
|
1687
|
+
this.compiler.isNumericLiteral(expression) ||
|
|
1688
|
+
this.compiler.isNoSubstitutionTemplateLiteral(expression));
|
|
1690
1689
|
}
|
|
1691
1690
|
explain(assertion) {
|
|
1692
1691
|
this.#assertNonNullishTypeChecker(assertion);
|
|
@@ -1838,7 +1837,9 @@ class Checker {
|
|
|
1838
1837
|
};
|
|
1839
1838
|
const sourceText = assertion.typeChecker.typeToString(assertion.sourceType.type);
|
|
1840
1839
|
return [
|
|
1841
|
-
Diagnostic.error(assertion.isNot
|
|
1840
|
+
Diagnostic.error(assertion.isNot
|
|
1841
|
+
? `Type '${targetText}' is identical to type '${sourceText}'.`
|
|
1842
|
+
: `Type '${targetText}' is not identical to type '${sourceText}'.`, origin),
|
|
1842
1843
|
];
|
|
1843
1844
|
}
|
|
1844
1845
|
match(assertion) {
|
|
@@ -2057,7 +2058,8 @@ class TestTreeWorker {
|
|
|
2057
2058
|
const describeResult = new DescribeResult(describe, parentResult);
|
|
2058
2059
|
EventEmitter.dispatch(["describe:start", { result: describeResult }]);
|
|
2059
2060
|
runMode = this.#resolveRunMode(runMode, describe);
|
|
2060
|
-
if (!(runMode & 4 || runMode &
|
|
2061
|
+
if (!(runMode & 4 || (this.#hasOnly && !(runMode & 2)) || runMode & 8) &&
|
|
2062
|
+
describe.diagnostics.length > 0) {
|
|
2061
2063
|
EventEmitter.dispatch([
|
|
2062
2064
|
"file:error",
|
|
2063
2065
|
{
|
|
@@ -2079,11 +2081,7 @@ class TestTreeWorker {
|
|
|
2079
2081
|
EventEmitter.dispatch(["test:todo", { result: testResult }]);
|
|
2080
2082
|
return;
|
|
2081
2083
|
}
|
|
2082
|
-
if (runMode & 4) {
|
|
2083
|
-
EventEmitter.dispatch(["test:skip", { result: testResult }]);
|
|
2084
|
-
return;
|
|
2085
|
-
}
|
|
2086
|
-
if (test.diagnostics.length > 0) {
|
|
2084
|
+
if (!(runMode & 4 || (this.#hasOnly && !(runMode & 2))) && test.diagnostics.length > 0) {
|
|
2087
2085
|
EventEmitter.dispatch([
|
|
2088
2086
|
"test:error",
|
|
2089
2087
|
{
|
|
@@ -2094,7 +2092,7 @@ class TestTreeWorker {
|
|
|
2094
2092
|
return;
|
|
2095
2093
|
}
|
|
2096
2094
|
this.visit(test.members, runMode, testResult);
|
|
2097
|
-
if (
|
|
2095
|
+
if (runMode & 4 || (this.#hasOnly && !(runMode & 2))) {
|
|
2098
2096
|
EventEmitter.dispatch(["test:skip", { result: testResult }]);
|
|
2099
2097
|
return;
|
|
2100
2098
|
}
|
|
@@ -2196,7 +2194,7 @@ class TaskRunner {
|
|
|
2196
2194
|
for (const versionTag of target) {
|
|
2197
2195
|
const targetResult = new TargetResult(versionTag, testFiles);
|
|
2198
2196
|
EventEmitter.dispatch(["target:start", { result: targetResult }]);
|
|
2199
|
-
const compiler = await this.#storeService.
|
|
2197
|
+
const compiler = await this.#storeService.load(versionTag, signal);
|
|
2200
2198
|
if (compiler) {
|
|
2201
2199
|
const testFileRunner = new TestFileRunner(this.resolvedConfig, compiler);
|
|
2202
2200
|
for (const testFile of testFiles) {
|
|
@@ -2337,7 +2335,7 @@ class OptionDefinitionsMap {
|
|
|
2337
2335
|
items: {
|
|
2338
2336
|
brand: "string",
|
|
2339
2337
|
name: "target",
|
|
2340
|
-
pattern: "^([45]\\.[0-9](\\.[0-9])?)|beta|latest|next|rc$",
|
|
2338
|
+
pattern: "^([45]\\.[0-9](\\.[0-9])?)|beta|current|latest|next|rc$",
|
|
2341
2339
|
},
|
|
2342
2340
|
name: "target",
|
|
2343
2341
|
},
|
|
@@ -2429,11 +2427,11 @@ class OptionUsageText {
|
|
|
2429
2427
|
const usageText = [];
|
|
2430
2428
|
switch (optionName) {
|
|
2431
2429
|
case "target": {
|
|
2432
|
-
const supportedTags = this.#storeService
|
|
2430
|
+
const { supportedTags } = this.#storeService;
|
|
2433
2431
|
const supportedTagsText = `Supported tags: ${["'", supportedTags.join("', '"), "'"].join("")}.`;
|
|
2434
2432
|
switch (this.#optionGroup) {
|
|
2435
2433
|
case 2:
|
|
2436
|
-
usageText.push("Argument for the '--target' option must be a single tag or a comma separated list
|
|
2434
|
+
usageText.push("Argument for the '--target' option must be a single tag or a comma separated list.", "Usage examples: '--target 4.9', '--target 5.0.4', '--target 4.7,4.8,latest'.", supportedTagsText);
|
|
2437
2435
|
break;
|
|
2438
2436
|
case 4:
|
|
2439
2437
|
usageText.push("Item of the 'target' list must be a supported version tag.", supportedTagsText);
|
|
@@ -2923,58 +2921,85 @@ class Lock {
|
|
|
2923
2921
|
#lockFilePath;
|
|
2924
2922
|
static #lockSuffix = "__lock__";
|
|
2925
2923
|
constructor(targetPath) {
|
|
2926
|
-
this.#lockFilePath = Lock
|
|
2924
|
+
this.#lockFilePath = Lock.#getLockFilePath(targetPath);
|
|
2927
2925
|
writeFileSync(this.#lockFilePath, "");
|
|
2928
2926
|
process.on("exit", () => {
|
|
2929
2927
|
this.release();
|
|
2930
2928
|
});
|
|
2931
2929
|
}
|
|
2932
|
-
static getLockFilePath(targetPath) {
|
|
2930
|
+
static #getLockFilePath(targetPath) {
|
|
2933
2931
|
return `${targetPath}${Lock.#lockSuffix}`;
|
|
2934
2932
|
}
|
|
2935
|
-
static isLocked(targetPath) {
|
|
2936
|
-
|
|
2933
|
+
static async isLocked(targetPath, options) {
|
|
2934
|
+
let isLocked = existsSync(Lock.#getLockFilePath(targetPath));
|
|
2935
|
+
if (!isLocked) {
|
|
2936
|
+
return isLocked;
|
|
2937
|
+
}
|
|
2938
|
+
if (options?.timeout == null) {
|
|
2939
|
+
return isLocked;
|
|
2940
|
+
}
|
|
2941
|
+
const waitStartTime = Date.now();
|
|
2942
|
+
while (isLocked) {
|
|
2943
|
+
if (options.signal?.aborted === true) {
|
|
2944
|
+
break;
|
|
2945
|
+
}
|
|
2946
|
+
if (Date.now() - waitStartTime > options.timeout) {
|
|
2947
|
+
options.onDiagnostic?.(`Lock wait timeout of ${options.timeout / 1000}s was exceeded.`);
|
|
2948
|
+
break;
|
|
2949
|
+
}
|
|
2950
|
+
await Lock.#sleep(1000);
|
|
2951
|
+
isLocked = existsSync(Lock.#getLockFilePath(targetPath));
|
|
2952
|
+
}
|
|
2953
|
+
return isLocked;
|
|
2937
2954
|
}
|
|
2938
2955
|
release() {
|
|
2939
2956
|
rmSync(this.#lockFilePath, { force: true });
|
|
2940
2957
|
}
|
|
2958
|
+
static async #sleep(time) {
|
|
2959
|
+
return new Promise((resolve) => setTimeout(resolve, time));
|
|
2960
|
+
}
|
|
2941
2961
|
}
|
|
2942
2962
|
|
|
2943
2963
|
class CompilerModuleWorker {
|
|
2944
2964
|
#cachePath;
|
|
2965
|
+
#onDiagnostic;
|
|
2945
2966
|
#readyFileName = "__ready__";
|
|
2946
2967
|
#timeout = Environment.timeout * 1000;
|
|
2947
|
-
constructor(cachePath) {
|
|
2968
|
+
constructor(cachePath, onDiagnostic) {
|
|
2948
2969
|
this.#cachePath = cachePath;
|
|
2970
|
+
this.#onDiagnostic = onDiagnostic;
|
|
2949
2971
|
}
|
|
2950
2972
|
async ensure(compilerVersion, signal) {
|
|
2951
2973
|
const installationPath = path.join(this.#cachePath, compilerVersion);
|
|
2952
2974
|
const readyFilePath = path.join(installationPath, this.#readyFileName);
|
|
2953
2975
|
const tsserverFilePath = path.join(installationPath, "node_modules", "typescript", "lib", "tsserverlibrary.js");
|
|
2954
2976
|
const typescriptFilePath = path.join(installationPath, "node_modules", "typescript", "lib", "typescript.js");
|
|
2955
|
-
if (Lock.isLocked(installationPath
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
}
|
|
2964
|
-
}
|
|
2977
|
+
if (await Lock.isLocked(installationPath, {
|
|
2978
|
+
onDiagnostic: (text) => {
|
|
2979
|
+
this.#onDiagnostic(Diagnostic.error([`Failed to install 'typescript@${compilerVersion}'.`, text]));
|
|
2980
|
+
},
|
|
2981
|
+
signal,
|
|
2982
|
+
timeout: this.#timeout,
|
|
2983
|
+
})) {
|
|
2984
|
+
return;
|
|
2965
2985
|
}
|
|
2966
2986
|
if (existsSync(readyFilePath)) {
|
|
2967
2987
|
return tsserverFilePath;
|
|
2968
2988
|
}
|
|
2969
|
-
EventEmitter.dispatch(["store:info", { compilerVersion, installationPath }]);
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2989
|
+
EventEmitter.dispatch(["store:info", { compilerVersion, installationPath: this.#normalizePath(installationPath) }]);
|
|
2990
|
+
try {
|
|
2991
|
+
await fs.mkdir(installationPath, { recursive: true });
|
|
2992
|
+
const lock = new Lock(installationPath);
|
|
2993
|
+
await fs.writeFile(path.join(installationPath, "package.json"), this.#getPackageJson(compilerVersion));
|
|
2994
|
+
await this.#installPackage(installationPath, signal);
|
|
2995
|
+
await fs.writeFile(tsserverFilePath, await this.#getPatched(compilerVersion, tsserverFilePath));
|
|
2996
|
+
await fs.writeFile(typescriptFilePath, await this.#getPatched(compilerVersion, typescriptFilePath));
|
|
2997
|
+
await fs.writeFile(readyFilePath, "");
|
|
2998
|
+
lock.release();
|
|
2999
|
+
}
|
|
3000
|
+
catch (error) {
|
|
3001
|
+
this.#onDiagnostic(Diagnostic.fromError(`Failed to install 'typescript@${compilerVersion}'.`, error));
|
|
3002
|
+
}
|
|
2978
3003
|
return tsserverFilePath;
|
|
2979
3004
|
}
|
|
2980
3005
|
#getPackageJson(version) {
|
|
@@ -3029,6 +3054,12 @@ class CompilerModuleWorker {
|
|
|
3029
3054
|
});
|
|
3030
3055
|
});
|
|
3031
3056
|
}
|
|
3057
|
+
#normalizePath(filePath) {
|
|
3058
|
+
if (path.sep === "/") {
|
|
3059
|
+
return filePath;
|
|
3060
|
+
}
|
|
3061
|
+
return filePath.replace(/\\/g, "/");
|
|
3062
|
+
}
|
|
3032
3063
|
}
|
|
3033
3064
|
|
|
3034
3065
|
class ManifestWorker {
|
|
@@ -3119,10 +3150,10 @@ class ManifestWorker {
|
|
|
3119
3150
|
manifest.resolutions[tag] = resolvedVersion;
|
|
3120
3151
|
}
|
|
3121
3152
|
}
|
|
3122
|
-
for (const
|
|
3123
|
-
const distributionTagValue = packageMetadata["dist-tags"][
|
|
3153
|
+
for (const tagKey of ["beta", "latest", "next", "rc"]) {
|
|
3154
|
+
const distributionTagValue = packageMetadata["dist-tags"][tagKey];
|
|
3124
3155
|
if (distributionTagValue != null) {
|
|
3125
|
-
manifest.resolutions[
|
|
3156
|
+
manifest.resolutions[tagKey] = distributionTagValue;
|
|
3126
3157
|
}
|
|
3127
3158
|
}
|
|
3128
3159
|
return manifest;
|
|
@@ -3192,17 +3223,29 @@ class StoreService {
|
|
|
3192
3223
|
#nodeRequire = createRequire(import.meta.url);
|
|
3193
3224
|
constructor() {
|
|
3194
3225
|
this.#cachePath = Environment.storePath;
|
|
3195
|
-
this.#compilerModuleWorker = new CompilerModuleWorker(this.#cachePath);
|
|
3226
|
+
this.#compilerModuleWorker = new CompilerModuleWorker(this.#cachePath, this.#onDiagnostic);
|
|
3196
3227
|
this.#manifestWorker = new ManifestWorker(this.#cachePath, async () => this.prune());
|
|
3197
3228
|
}
|
|
3198
|
-
|
|
3229
|
+
get supportedTags() {
|
|
3199
3230
|
if (!this.#manifest) {
|
|
3200
3231
|
this.#onDiagnostic(Diagnostic.error("Store manifest is not open. Call 'StoreService.open()' first."));
|
|
3201
3232
|
return [];
|
|
3202
3233
|
}
|
|
3203
|
-
return [...Object.keys(this.#manifest.resolutions), ...this.#manifest.versions].sort();
|
|
3234
|
+
return [...Object.keys(this.#manifest.resolutions), ...this.#manifest.versions, "current"].sort();
|
|
3204
3235
|
}
|
|
3205
|
-
async
|
|
3236
|
+
async install(tag, signal) {
|
|
3237
|
+
if (!this.#manifest) {
|
|
3238
|
+
this.#onDiagnostic(Diagnostic.error("Store manifest is not open. Call 'StoreService.open()' first."));
|
|
3239
|
+
return;
|
|
3240
|
+
}
|
|
3241
|
+
const version = this.resolveTag(tag);
|
|
3242
|
+
if (version == null) {
|
|
3243
|
+
this.#onDiagnostic(Diagnostic.error(`Cannot add the 'typescript' package for the '${tag}' tag.`));
|
|
3244
|
+
return;
|
|
3245
|
+
}
|
|
3246
|
+
return this.#compilerModuleWorker.ensure(version, signal);
|
|
3247
|
+
}
|
|
3248
|
+
async load(tag, signal) {
|
|
3206
3249
|
let modulePath;
|
|
3207
3250
|
if (tag === "local") {
|
|
3208
3251
|
try {
|
|
@@ -3213,47 +3256,22 @@ class StoreService {
|
|
|
3213
3256
|
}
|
|
3214
3257
|
}
|
|
3215
3258
|
if (modulePath == null) {
|
|
3216
|
-
modulePath = await this.
|
|
3259
|
+
modulePath = await this.install(tag, signal);
|
|
3217
3260
|
}
|
|
3218
3261
|
if (modulePath != null) {
|
|
3219
3262
|
return this.#nodeRequire(modulePath);
|
|
3220
3263
|
}
|
|
3221
3264
|
return;
|
|
3222
3265
|
}
|
|
3223
|
-
#onDiagnostic(diagnostic) {
|
|
3266
|
+
#onDiagnostic = (diagnostic) => {
|
|
3224
3267
|
EventEmitter.dispatch(["store:error", { diagnostics: [diagnostic] }]);
|
|
3225
|
-
}
|
|
3268
|
+
};
|
|
3226
3269
|
async open(signal) {
|
|
3227
3270
|
if (this.#manifest) {
|
|
3228
3271
|
return;
|
|
3229
3272
|
}
|
|
3230
3273
|
this.#manifest = await this.#manifestWorker.open(signal);
|
|
3231
3274
|
}
|
|
3232
|
-
async prepareCompilerModule(tag, signal) {
|
|
3233
|
-
if (!this.#manifest) {
|
|
3234
|
-
this.#onDiagnostic(Diagnostic.error("Store manifest is not open. Call 'StoreService.open()' first."));
|
|
3235
|
-
return;
|
|
3236
|
-
}
|
|
3237
|
-
const version = this.resolveTag(tag);
|
|
3238
|
-
if (version == null) {
|
|
3239
|
-
this.#onDiagnostic(Diagnostic.error(`Cannot add the 'typescript' package for the '${tag}' tag.`));
|
|
3240
|
-
return;
|
|
3241
|
-
}
|
|
3242
|
-
let modulePath;
|
|
3243
|
-
try {
|
|
3244
|
-
modulePath = await this.#compilerModuleWorker.ensure(version, signal);
|
|
3245
|
-
}
|
|
3246
|
-
catch (error) {
|
|
3247
|
-
this.#onDiagnostic(Diagnostic.fromError(`Failed to install 'typescript@${version}'.`, error));
|
|
3248
|
-
}
|
|
3249
|
-
if (modulePath != null) {
|
|
3250
|
-
if (!("lastUsed" in this.#manifest)) {
|
|
3251
|
-
this.#manifest.lastUsed = {};
|
|
3252
|
-
}
|
|
3253
|
-
this.#manifest.lastUsed[version] = Date.now();
|
|
3254
|
-
}
|
|
3255
|
-
return modulePath;
|
|
3256
|
-
}
|
|
3257
3275
|
async prune() {
|
|
3258
3276
|
await fs.rm(this.#cachePath, { force: true, recursive: true });
|
|
3259
3277
|
}
|
|
@@ -3262,6 +3280,14 @@ class StoreService {
|
|
|
3262
3280
|
this.#onDiagnostic(Diagnostic.error("Store manifest is not open. Call 'StoreService.open()' first."));
|
|
3263
3281
|
return;
|
|
3264
3282
|
}
|
|
3283
|
+
if (tag === "current") {
|
|
3284
|
+
try {
|
|
3285
|
+
tag = this.#nodeRequire("typescript").version;
|
|
3286
|
+
}
|
|
3287
|
+
catch (error) {
|
|
3288
|
+
this.#onDiagnostic(Diagnostic.fromError("Failed to resolve tag 'current'. The 'typescript' package might be not installed.", error));
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3265
3291
|
if (this.#manifest.versions.includes(tag)) {
|
|
3266
3292
|
return tag;
|
|
3267
3293
|
}
|
|
@@ -3287,7 +3313,7 @@ class StoreService {
|
|
|
3287
3313
|
this.#onDiagnostic(Diagnostic.error("Store manifest is not open. Call 'StoreService.open()' first."));
|
|
3288
3314
|
return false;
|
|
3289
3315
|
}
|
|
3290
|
-
if (this.#manifest.versions.includes(tag) || tag in this.#manifest.resolutions) {
|
|
3316
|
+
if (this.#manifest.versions.includes(tag) || tag in this.#manifest.resolutions || tag === "current") {
|
|
3291
3317
|
return true;
|
|
3292
3318
|
}
|
|
3293
3319
|
if (this.#manifest.resolutions["latest"] != null &&
|
|
@@ -3487,7 +3513,7 @@ class Cli {
|
|
|
3487
3513
|
if (this.#process.exitCode === 1) {
|
|
3488
3514
|
return;
|
|
3489
3515
|
}
|
|
3490
|
-
const compiler = await this.#storeService.
|
|
3516
|
+
const compiler = await this.#storeService.load("local", this.#abortController.signal);
|
|
3491
3517
|
if (!compiler) {
|
|
3492
3518
|
return;
|
|
3493
3519
|
}
|
|
@@ -3529,7 +3555,7 @@ class Cli {
|
|
|
3529
3555
|
}
|
|
3530
3556
|
if (configService.commandLineOptions.install === true) {
|
|
3531
3557
|
for (const tag of resolvedConfig.target) {
|
|
3532
|
-
await this.#storeService.
|
|
3558
|
+
await this.#storeService.install(tag, this.#abortController.signal);
|
|
3533
3559
|
}
|
|
3534
3560
|
return;
|
|
3535
3561
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tstyche",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.5",
|
|
4
4
|
"description": "The Essential Type Testing Tool.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -28,16 +28,17 @@
|
|
|
28
28
|
},
|
|
29
29
|
"main": "./build/index.js",
|
|
30
30
|
"types": "./build/index.d.ts",
|
|
31
|
-
"bin": "build/bin.js",
|
|
31
|
+
"bin": "./build/bin.js",
|
|
32
32
|
"files": [
|
|
33
|
-
"build/*"
|
|
34
|
-
"lib/*.json"
|
|
33
|
+
"build/*"
|
|
35
34
|
],
|
|
36
35
|
"scripts": {
|
|
37
36
|
"build": "rollup --config rollup.config.js",
|
|
38
37
|
"build:watch": "yarn build --sourcemap --watch",
|
|
39
38
|
"clean": "rm -rf build",
|
|
40
|
-
"generate": "
|
|
39
|
+
"generate": "yarn generate:schema && yarn generate:types",
|
|
40
|
+
"generate:schema": "node scripts/generate-schema.js",
|
|
41
|
+
"generate:types": "node scripts/generate-types.js",
|
|
41
42
|
"lint": "yarn lint:cspell && yarn lint:eslint && yarn lint:prettier",
|
|
42
43
|
"lint:cspell": "cspell --cache --config cspell.config.json --quiet",
|
|
43
44
|
"lint:eslint": "yarn lint:eslint:md && yarn lint:eslint:ts",
|
|
@@ -56,13 +57,13 @@
|
|
|
56
57
|
"devDependencies": {
|
|
57
58
|
"@jest/globals": "29.7.0",
|
|
58
59
|
"@rollup/plugin-typescript": "11.1.5",
|
|
59
|
-
"@types/node": "20.
|
|
60
|
-
"@typescript-eslint/eslint-plugin": "6.
|
|
61
|
-
"@typescript-eslint/parser": "6.
|
|
60
|
+
"@types/node": "20.10.0",
|
|
61
|
+
"@typescript-eslint/eslint-plugin": "6.12.0",
|
|
62
|
+
"@typescript-eslint/parser": "6.12.0",
|
|
62
63
|
"ajv": "8.12.0",
|
|
63
64
|
"c8": "8.0.1",
|
|
64
65
|
"cspell": "8.0.0",
|
|
65
|
-
"eslint": "8.
|
|
66
|
+
"eslint": "8.54.0",
|
|
66
67
|
"eslint-config-prettier": "9.0.0",
|
|
67
68
|
"eslint-import-resolver-typescript": "3.6.1",
|
|
68
69
|
"eslint-plugin-import": "2.29.0",
|
|
@@ -75,13 +76,12 @@
|
|
|
75
76
|
"jest-serializer-ansi-escapes": "2.0.1",
|
|
76
77
|
"magic-string": "0.30.5",
|
|
77
78
|
"prettier": "3.1.0",
|
|
78
|
-
"rollup": "4.
|
|
79
|
+
"rollup": "4.6.0",
|
|
79
80
|
"rollup-plugin-dts": "6.1.0",
|
|
80
81
|
"rollup-plugin-tsconfig-paths": "1.5.2",
|
|
81
82
|
"ts-node": "10.9.1",
|
|
82
83
|
"tslib": "2.6.2",
|
|
83
|
-
"typescript": "5.2.2"
|
|
84
|
-
"wireit": "0.14.1"
|
|
84
|
+
"typescript": "5.2.2"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"typescript": "4.x || 5.x"
|
|
@@ -91,37 +91,8 @@
|
|
|
91
91
|
"optional": true
|
|
92
92
|
}
|
|
93
93
|
},
|
|
94
|
-
"packageManager": "yarn@
|
|
94
|
+
"packageManager": "yarn@3.7.0",
|
|
95
95
|
"engines": {
|
|
96
96
|
"node": "^16.14 || 18.x || >=20.x"
|
|
97
|
-
},
|
|
98
|
-
"wireit": {
|
|
99
|
-
"generate": {
|
|
100
|
-
"dependencies": [
|
|
101
|
-
"generate:schema",
|
|
102
|
-
"generate:types"
|
|
103
|
-
]
|
|
104
|
-
},
|
|
105
|
-
"generate:schema": {
|
|
106
|
-
"command": "node scripts/generate-schema.js",
|
|
107
|
-
"files": [
|
|
108
|
-
"./build",
|
|
109
|
-
"./scripts/generate-schema.js"
|
|
110
|
-
],
|
|
111
|
-
"output": [
|
|
112
|
-
"./lib/schema.json"
|
|
113
|
-
]
|
|
114
|
-
},
|
|
115
|
-
"generate:types": {
|
|
116
|
-
"command": "node scripts/generate-types.js",
|
|
117
|
-
"files": [
|
|
118
|
-
"./build",
|
|
119
|
-
"./scripts/generate-types.js"
|
|
120
|
-
],
|
|
121
|
-
"output": [
|
|
122
|
-
"./lib/CommandLineOptions.ts",
|
|
123
|
-
"./lib/ConfigFileOptions.ts"
|
|
124
|
-
]
|
|
125
|
-
}
|
|
126
97
|
}
|
|
127
|
-
}
|
|
98
|
+
}
|
package/lib/schema.json
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"definitions": {},
|
|
4
|
-
"properties": {
|
|
5
|
-
"allowNoTestFiles": {
|
|
6
|
-
"default": false,
|
|
7
|
-
"description": "Do not raise an error, if no test files are selected.",
|
|
8
|
-
"type": "boolean"
|
|
9
|
-
},
|
|
10
|
-
"failFast": {
|
|
11
|
-
"default": false,
|
|
12
|
-
"description": "Stop running tests after the first failed assertion.",
|
|
13
|
-
"type": "boolean"
|
|
14
|
-
},
|
|
15
|
-
"rootPath": {
|
|
16
|
-
"default": "./",
|
|
17
|
-
"description": "The path to a directory containing files of a test project.",
|
|
18
|
-
"type": "string"
|
|
19
|
-
},
|
|
20
|
-
"target": {
|
|
21
|
-
"default": [
|
|
22
|
-
"latest"
|
|
23
|
-
],
|
|
24
|
-
"description": "The list of TypeScript versions to be tested on.",
|
|
25
|
-
"items": {
|
|
26
|
-
"pattern": "^([45]\\.[0-9](\\.[0-9])?)|beta|latest|next|rc$",
|
|
27
|
-
"type": "string"
|
|
28
|
-
},
|
|
29
|
-
"type": "array",
|
|
30
|
-
"uniqueItems": true
|
|
31
|
-
},
|
|
32
|
-
"testFileMatch": {
|
|
33
|
-
"default": [
|
|
34
|
-
"**/*.tst.*",
|
|
35
|
-
"**/__typetests__/*.test.*",
|
|
36
|
-
"**/typetests/*.test.*"
|
|
37
|
-
],
|
|
38
|
-
"description": "The list of glob patterns matching the test files.",
|
|
39
|
-
"items": {
|
|
40
|
-
"type": "string"
|
|
41
|
-
},
|
|
42
|
-
"type": "array",
|
|
43
|
-
"uniqueItems": true
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
"type": "object"
|
|
47
|
-
}
|