tstyche 1.0.0-beta.4 → 1.0.0-beta.6
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 +30 -3
- package/README.md +4 -3
- package/build/index.d.cts +4 -0
- package/build/index.d.ts +4 -0
- package/build/tstyche.js +153 -56
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.0-beta.6] - 2023-12-03
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **New!** Add `.toHaveProperty()` matcher ([#36](https://github.com/tstyche/tstyche/pull/36))
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Accept template literals as arguments of the `.toRaiseError()` matcher ([#38](https://github.com/tstyche/tstyche/pull/38))
|
|
12
|
+
|
|
13
|
+
## [1.0.0-beta.5] - 2023-11-27
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **Breaking!** Move retry logic to the `Lock` class ([#31](https://github.com/tstyche/tstyche/pull/31))
|
|
18
|
+
- Bring back support for Node.js 16 ([#28](https://github.com/tstyche/tstyche/pull/28), [#27](https://github.com/tstyche/tstyche/pull/27))
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **New!** Add support for the `current` target tag ([#33](https://github.com/tstyche/tstyche/pull/33))
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Allow `.raiseError()` to take template literals as arguments ([#35](https://github.com/tstyche/tstyche/pull/35))
|
|
27
|
+
|
|
3
28
|
## [1.0.0-beta.4] - 2023-11-24
|
|
4
29
|
|
|
5
30
|
### Added
|
|
@@ -8,9 +33,9 @@
|
|
|
8
33
|
|
|
9
34
|
### Removed
|
|
10
35
|
|
|
11
|
-
- **Breaking
|
|
12
|
-
- **Breaking
|
|
13
|
-
- **Breaking
|
|
36
|
+
- **Breaking!** Remove the `context()` helper ([#24](https://github.com/tstyche/tstyche/pull/24))
|
|
37
|
+
- **Breaking!** Drop support for Node.js 16 ([#22](https://github.com/tstyche/tstyche/pull/22))
|
|
38
|
+
- **Breaking!** Rename methods of the `StoreService` class ([`5d74201`](https://github.com/tstyche/tstyche/commit/5d74201))
|
|
14
39
|
|
|
15
40
|
### Fixed
|
|
16
41
|
|
|
@@ -40,6 +65,8 @@
|
|
|
40
65
|
|
|
41
66
|
_First pre-release._
|
|
42
67
|
|
|
68
|
+
[1.0.0-beta.6]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.6
|
|
69
|
+
[1.0.0-beta.5]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.5
|
|
43
70
|
[1.0.0-beta.4]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.4
|
|
44
71
|
[1.0.0-beta.3]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.3
|
|
45
72
|
[1.0.0-beta.2]: https://github.com/tstyche/tstyche/releases/tag/v1.0.0-beta.2
|
package/README.md
CHANGED
|
@@ -56,9 +56,10 @@ test("handles numbers", () => {
|
|
|
56
56
|
|
|
57
57
|
Here is the list of all matchers:
|
|
58
58
|
|
|
59
|
-
- `.toBeAssignable()`, `.toEqual()`, `.toMatch()` compares types or types of expression
|
|
60
|
-
- `.
|
|
61
|
-
- `.
|
|
59
|
+
- `.toBeAssignable()`, `.toEqual()`, `.toMatch()` compares types or types of expression,
|
|
60
|
+
- `.toHaveProperty()` looks up keys on an object type,
|
|
61
|
+
- `.toRaiseError()` captures the type error message or code,
|
|
62
|
+
- `.toBeString()`, `.toBeNumber()`, `.toBeVoid()` and 9 more shorthand checks for primitive types.
|
|
62
63
|
|
|
63
64
|
## Runner
|
|
64
65
|
|
package/build/index.d.cts
CHANGED
|
@@ -133,6 +133,10 @@ interface Matchers {
|
|
|
133
133
|
*/
|
|
134
134
|
(target: unknown): void;
|
|
135
135
|
};
|
|
136
|
+
/**
|
|
137
|
+
* Checks if a property key exists on the source type.
|
|
138
|
+
*/
|
|
139
|
+
toHaveProperty: (key: string | number | symbol) => void;
|
|
136
140
|
/**
|
|
137
141
|
* Checks if the target type is a subtype the source type.
|
|
138
142
|
*/
|
package/build/index.d.ts
CHANGED
|
@@ -133,6 +133,10 @@ interface Matchers {
|
|
|
133
133
|
*/
|
|
134
134
|
(target: unknown): void;
|
|
135
135
|
};
|
|
136
|
+
/**
|
|
137
|
+
* Checks if a property key exists on the source type.
|
|
138
|
+
*/
|
|
139
|
+
toHaveProperty: (key: string | number | symbol) => void;
|
|
136
140
|
/**
|
|
137
141
|
* Checks if the target type is a subtype the source type.
|
|
138
142
|
*/
|
package/build/tstyche.js
CHANGED
|
@@ -5,7 +5,7 @@ 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
|
|
8
|
+
import https from 'node:https';
|
|
9
9
|
|
|
10
10
|
class EventEmitter {
|
|
11
11
|
static #handlers = new Set();
|
|
@@ -1396,7 +1396,10 @@ class IdentifierLookup {
|
|
|
1396
1396
|
};
|
|
1397
1397
|
}
|
|
1398
1398
|
clone() {
|
|
1399
|
-
return
|
|
1399
|
+
return {
|
|
1400
|
+
namedImports: { ...this.#identifiers.namedImports },
|
|
1401
|
+
namespace: this.#identifiers.namespace,
|
|
1402
|
+
};
|
|
1400
1403
|
}
|
|
1401
1404
|
handleImportDeclaration(node) {
|
|
1402
1405
|
if (this.#moduleSpecifiers.includes(node.moduleSpecifier.getText()) &&
|
|
@@ -1508,6 +1511,7 @@ class CollectService {
|
|
|
1508
1511
|
"toBeUnknown",
|
|
1509
1512
|
"toBeVoid",
|
|
1510
1513
|
"toEqual",
|
|
1514
|
+
"toHaveProperty",
|
|
1511
1515
|
"toMatch",
|
|
1512
1516
|
"toRaiseError",
|
|
1513
1517
|
];
|
|
@@ -1679,8 +1683,12 @@ class Checker {
|
|
|
1679
1683
|
#assertNonNullishTypeChecker(assertion) {
|
|
1680
1684
|
this.#assertNonNullish(assertion.typeChecker, "The 'typeChecker' was not provided.");
|
|
1681
1685
|
}
|
|
1686
|
+
#assertStringsOrNumber(expression) {
|
|
1687
|
+
return (expression != null &&
|
|
1688
|
+
(this.compiler.isStringLiteralLike(expression) || this.compiler.isNumericLiteral(expression)));
|
|
1689
|
+
}
|
|
1682
1690
|
#assertStringsOrNumbers(nodes) {
|
|
1683
|
-
return nodes.every((expression) => this
|
|
1691
|
+
return nodes.every((expression) => this.#assertStringsOrNumber(expression));
|
|
1684
1692
|
}
|
|
1685
1693
|
explain(assertion) {
|
|
1686
1694
|
this.#assertNonNullishTypeChecker(assertion);
|
|
@@ -1738,6 +1746,26 @@ class Checker {
|
|
|
1738
1746
|
: `Type '${targetTypeText}' is not identical to type '${sourceTypeText}'.`, origin),
|
|
1739
1747
|
];
|
|
1740
1748
|
}
|
|
1749
|
+
case "toHaveProperty": {
|
|
1750
|
+
this.#assertNonNullishSourceType(assertion);
|
|
1751
|
+
this.#assertNonNullishTargetType(assertion);
|
|
1752
|
+
const sourceText = assertion.typeChecker.typeToString(assertion.sourceType.type);
|
|
1753
|
+
let targetArgumentText;
|
|
1754
|
+
if (assertion.targetType.type.flags & this.compiler.TypeFlags.StringOrNumberLiteral) {
|
|
1755
|
+
targetArgumentText = String(assertion.targetType.type.value);
|
|
1756
|
+
}
|
|
1757
|
+
else if (assertion.targetType.type.flags & this.compiler.TypeFlags.UniqueESSymbol) {
|
|
1758
|
+
targetArgumentText = `[${this.compiler.unescapeLeadingUnderscores(assertion.targetType.type.symbol.escapedName)}]`;
|
|
1759
|
+
}
|
|
1760
|
+
else {
|
|
1761
|
+
throw new Error("An argument for 'key' must be of type 'string | number | symbol'.");
|
|
1762
|
+
}
|
|
1763
|
+
return [
|
|
1764
|
+
Diagnostic.error(assertion.isNot
|
|
1765
|
+
? `Property '${targetArgumentText}' exists on type '${sourceText}'.`
|
|
1766
|
+
: `Property '${targetArgumentText}' does not exist on type '${sourceText}'.`, origin),
|
|
1767
|
+
];
|
|
1768
|
+
}
|
|
1741
1769
|
case "toMatch": {
|
|
1742
1770
|
this.#assertNonNullishSourceType(assertion);
|
|
1743
1771
|
this.#assertNonNullishTargetType(assertion);
|
|
@@ -1791,7 +1819,7 @@ class Checker {
|
|
|
1791
1819
|
}
|
|
1792
1820
|
const isMatch = this.#matchExpectedError(diagnostic, argument);
|
|
1793
1821
|
if (!assertion.isNot && !isMatch) {
|
|
1794
|
-
const expectedText = this.compiler.
|
|
1822
|
+
const expectedText = this.compiler.isStringLiteralLike(argument)
|
|
1795
1823
|
? `matching substring '${argument.text}'`
|
|
1796
1824
|
: `with code ${argument.text}`;
|
|
1797
1825
|
const related = [
|
|
@@ -1801,7 +1829,7 @@ class Checker {
|
|
|
1801
1829
|
diagnostics.push(Diagnostic.error(`${sourceText} did not raise a type error ${expectedText}.`, origin).add({ related }));
|
|
1802
1830
|
}
|
|
1803
1831
|
if (assertion.isNot && isMatch) {
|
|
1804
|
-
const expectedText = this.compiler.
|
|
1832
|
+
const expectedText = this.compiler.isStringLiteralLike(argument)
|
|
1805
1833
|
? `matching substring '${argument.text}'`
|
|
1806
1834
|
: `with code ${argument.text}`;
|
|
1807
1835
|
const related = [
|
|
@@ -1887,6 +1915,27 @@ class Checker {
|
|
|
1887
1915
|
this.#assertNonNullish(assertion.typeChecker?.isTypeIdenticalTo, "The 'isTypeIdenticalTo' method is missing in the provided type checker.");
|
|
1888
1916
|
return assertion.typeChecker.isTypeIdenticalTo(assertion.sourceType.type, assertion.targetType.type);
|
|
1889
1917
|
}
|
|
1918
|
+
case "toHaveProperty": {
|
|
1919
|
+
this.#assertNonNullishSourceType(assertion);
|
|
1920
|
+
this.#assertNonNullishTargetType(assertion);
|
|
1921
|
+
if (!(assertion.sourceType.type.flags & this.compiler.TypeFlags.StructuredType)) {
|
|
1922
|
+
const receivedText = assertion.typeChecker?.typeToString(assertion.sourceType.type);
|
|
1923
|
+
throw new Error(`An argument for 'source' must be of object type, received: '${receivedText}'.`);
|
|
1924
|
+
}
|
|
1925
|
+
let targetArgumentText;
|
|
1926
|
+
if (assertion.targetType.type.flags & this.compiler.TypeFlags.StringOrNumberLiteral) {
|
|
1927
|
+
targetArgumentText = String(assertion.targetType.type.value);
|
|
1928
|
+
}
|
|
1929
|
+
else if (assertion.targetType.type.flags & this.compiler.TypeFlags.UniqueESSymbol) {
|
|
1930
|
+
targetArgumentText = this.compiler.unescapeLeadingUnderscores(assertion.targetType.type.escapedName);
|
|
1931
|
+
}
|
|
1932
|
+
else {
|
|
1933
|
+
throw new Error("An argument for 'key' must be of type 'string | number | symbol'.");
|
|
1934
|
+
}
|
|
1935
|
+
return assertion.sourceType.type.getProperties().some((property) => {
|
|
1936
|
+
return this.compiler.unescapeLeadingUnderscores(property.escapedName) === targetArgumentText;
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1890
1939
|
case "toMatch": {
|
|
1891
1940
|
this.#assertNonNullishSourceType(assertion);
|
|
1892
1941
|
this.#assertNonNullishTargetType(assertion);
|
|
@@ -1904,7 +1953,7 @@ class Checker {
|
|
|
1904
1953
|
return false;
|
|
1905
1954
|
}
|
|
1906
1955
|
return assertion.targetArguments.every((expectedArgument, index) => {
|
|
1907
|
-
if (this.compiler.
|
|
1956
|
+
if (this.compiler.isStringLiteralLike(expectedArgument)) {
|
|
1908
1957
|
return this.compiler
|
|
1909
1958
|
.flattenDiagnosticMessageText(assertion.diagnostics[index]?.messageText, " ", 0)
|
|
1910
1959
|
.includes(expectedArgument.text);
|
|
@@ -1920,7 +1969,7 @@ class Checker {
|
|
|
1920
1969
|
}
|
|
1921
1970
|
}
|
|
1922
1971
|
#matchExpectedError(diagnostic, argument) {
|
|
1923
|
-
if (this.compiler.
|
|
1972
|
+
if (this.compiler.isStringLiteralLike(argument)) {
|
|
1924
1973
|
return this.compiler.flattenDiagnosticMessageText(diagnostic.messageText, " ", 0).includes(argument.text);
|
|
1925
1974
|
}
|
|
1926
1975
|
if (this.compiler.isNumericLiteral(argument)) {
|
|
@@ -2330,7 +2379,7 @@ class OptionDefinitionsMap {
|
|
|
2330
2379
|
items: {
|
|
2331
2380
|
brand: "string",
|
|
2332
2381
|
name: "target",
|
|
2333
|
-
pattern: "^([45]\\.[0-9](\\.[0-9])?)|beta|latest|next|rc$",
|
|
2382
|
+
pattern: "^([45]\\.[0-9](\\.[0-9])?)|beta|current|latest|next|rc$",
|
|
2334
2383
|
},
|
|
2335
2384
|
name: "target",
|
|
2336
2385
|
},
|
|
@@ -2426,7 +2475,7 @@ class OptionUsageText {
|
|
|
2426
2475
|
const supportedTagsText = `Supported tags: ${["'", supportedTags.join("', '"), "'"].join("")}.`;
|
|
2427
2476
|
switch (this.#optionGroup) {
|
|
2428
2477
|
case 2:
|
|
2429
|
-
usageText.push("Argument for the '--target' option must be a single tag or a comma separated list
|
|
2478
|
+
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);
|
|
2430
2479
|
break;
|
|
2431
2480
|
case 4:
|
|
2432
2481
|
usageText.push("Item of the 'target' list must be a supported version tag.", supportedTagsText);
|
|
@@ -2916,58 +2965,85 @@ class Lock {
|
|
|
2916
2965
|
#lockFilePath;
|
|
2917
2966
|
static #lockSuffix = "__lock__";
|
|
2918
2967
|
constructor(targetPath) {
|
|
2919
|
-
this.#lockFilePath = Lock
|
|
2968
|
+
this.#lockFilePath = Lock.#getLockFilePath(targetPath);
|
|
2920
2969
|
writeFileSync(this.#lockFilePath, "");
|
|
2921
2970
|
process.on("exit", () => {
|
|
2922
2971
|
this.release();
|
|
2923
2972
|
});
|
|
2924
2973
|
}
|
|
2925
|
-
static getLockFilePath(targetPath) {
|
|
2974
|
+
static #getLockFilePath(targetPath) {
|
|
2926
2975
|
return `${targetPath}${Lock.#lockSuffix}`;
|
|
2927
2976
|
}
|
|
2928
|
-
static isLocked(targetPath) {
|
|
2929
|
-
|
|
2977
|
+
static async isLocked(targetPath, options) {
|
|
2978
|
+
let isLocked = existsSync(Lock.#getLockFilePath(targetPath));
|
|
2979
|
+
if (!isLocked) {
|
|
2980
|
+
return isLocked;
|
|
2981
|
+
}
|
|
2982
|
+
if (options?.timeout == null) {
|
|
2983
|
+
return isLocked;
|
|
2984
|
+
}
|
|
2985
|
+
const waitStartTime = Date.now();
|
|
2986
|
+
while (isLocked) {
|
|
2987
|
+
if (options.signal?.aborted === true) {
|
|
2988
|
+
break;
|
|
2989
|
+
}
|
|
2990
|
+
if (Date.now() - waitStartTime > options.timeout) {
|
|
2991
|
+
options.onDiagnostic?.(`Lock wait timeout of ${options.timeout / 1000}s was exceeded.`);
|
|
2992
|
+
break;
|
|
2993
|
+
}
|
|
2994
|
+
await Lock.#sleep(1000);
|
|
2995
|
+
isLocked = existsSync(Lock.#getLockFilePath(targetPath));
|
|
2996
|
+
}
|
|
2997
|
+
return isLocked;
|
|
2930
2998
|
}
|
|
2931
2999
|
release() {
|
|
2932
3000
|
rmSync(this.#lockFilePath, { force: true });
|
|
2933
3001
|
}
|
|
3002
|
+
static async #sleep(time) {
|
|
3003
|
+
return new Promise((resolve) => setTimeout(resolve, time));
|
|
3004
|
+
}
|
|
2934
3005
|
}
|
|
2935
3006
|
|
|
2936
3007
|
class CompilerModuleWorker {
|
|
2937
3008
|
#cachePath;
|
|
3009
|
+
#onDiagnostic;
|
|
2938
3010
|
#readyFileName = "__ready__";
|
|
2939
3011
|
#timeout = Environment.timeout * 1000;
|
|
2940
|
-
constructor(cachePath) {
|
|
3012
|
+
constructor(cachePath, onDiagnostic) {
|
|
2941
3013
|
this.#cachePath = cachePath;
|
|
3014
|
+
this.#onDiagnostic = onDiagnostic;
|
|
2942
3015
|
}
|
|
2943
3016
|
async ensure(compilerVersion, signal) {
|
|
2944
3017
|
const installationPath = path.join(this.#cachePath, compilerVersion);
|
|
2945
3018
|
const readyFilePath = path.join(installationPath, this.#readyFileName);
|
|
2946
3019
|
const tsserverFilePath = path.join(installationPath, "node_modules", "typescript", "lib", "tsserverlibrary.js");
|
|
2947
3020
|
const typescriptFilePath = path.join(installationPath, "node_modules", "typescript", "lib", "typescript.js");
|
|
2948
|
-
if (Lock.isLocked(installationPath
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
}
|
|
2957
|
-
}
|
|
3021
|
+
if (await Lock.isLocked(installationPath, {
|
|
3022
|
+
onDiagnostic: (text) => {
|
|
3023
|
+
this.#onDiagnostic(Diagnostic.error([`Failed to install 'typescript@${compilerVersion}'.`, text]));
|
|
3024
|
+
},
|
|
3025
|
+
signal,
|
|
3026
|
+
timeout: this.#timeout,
|
|
3027
|
+
})) {
|
|
3028
|
+
return;
|
|
2958
3029
|
}
|
|
2959
3030
|
if (existsSync(readyFilePath)) {
|
|
2960
3031
|
return tsserverFilePath;
|
|
2961
3032
|
}
|
|
2962
3033
|
EventEmitter.dispatch(["store:info", { compilerVersion, installationPath: this.#normalizePath(installationPath) }]);
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
3034
|
+
try {
|
|
3035
|
+
await fs.mkdir(installationPath, { recursive: true });
|
|
3036
|
+
const lock = new Lock(installationPath);
|
|
3037
|
+
await fs.writeFile(path.join(installationPath, "package.json"), this.#getPackageJson(compilerVersion));
|
|
3038
|
+
await this.#installPackage(installationPath, signal);
|
|
3039
|
+
await fs.writeFile(tsserverFilePath, await this.#getPatched(compilerVersion, tsserverFilePath));
|
|
3040
|
+
await fs.writeFile(typescriptFilePath, await this.#getPatched(compilerVersion, typescriptFilePath));
|
|
3041
|
+
await fs.writeFile(readyFilePath, "");
|
|
3042
|
+
lock.release();
|
|
3043
|
+
}
|
|
3044
|
+
catch (error) {
|
|
3045
|
+
this.#onDiagnostic(Diagnostic.fromError(`Failed to install 'typescript@${compilerVersion}'.`, error));
|
|
3046
|
+
}
|
|
2971
3047
|
return tsserverFilePath;
|
|
2972
3048
|
}
|
|
2973
3049
|
#getPackageJson(version) {
|
|
@@ -3043,14 +3119,34 @@ class ManifestWorker {
|
|
|
3043
3119
|
this.#prune = prune;
|
|
3044
3120
|
}
|
|
3045
3121
|
async #fetch(signal) {
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3122
|
+
return new Promise((resolve, reject) => {
|
|
3123
|
+
const request = https.get(new URL("typescript", this.#registryUrl), {
|
|
3124
|
+
headers: { accept: "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*" },
|
|
3125
|
+
signal,
|
|
3126
|
+
}, (result) => {
|
|
3127
|
+
if (result.statusCode !== 200) {
|
|
3128
|
+
reject(new Error(`Request failed with status code ${String(result.statusCode)}.`));
|
|
3129
|
+
return;
|
|
3130
|
+
}
|
|
3131
|
+
result.setEncoding("utf8");
|
|
3132
|
+
let rawData = "";
|
|
3133
|
+
result.on("data", (chunk) => {
|
|
3134
|
+
rawData += chunk;
|
|
3135
|
+
});
|
|
3136
|
+
result.on("end", () => {
|
|
3137
|
+
try {
|
|
3138
|
+
const packageMetadata = JSON.parse(rawData);
|
|
3139
|
+
resolve(packageMetadata);
|
|
3140
|
+
}
|
|
3141
|
+
catch (error) {
|
|
3142
|
+
reject(error);
|
|
3143
|
+
}
|
|
3144
|
+
});
|
|
3145
|
+
});
|
|
3146
|
+
request.on("error", (error) => {
|
|
3147
|
+
reject(error);
|
|
3148
|
+
});
|
|
3049
3149
|
});
|
|
3050
|
-
if (!result.ok) {
|
|
3051
|
-
throw new Error(`Request failed with status code ${String(result.status)}.`);
|
|
3052
|
-
}
|
|
3053
|
-
return result.json();
|
|
3054
3150
|
}
|
|
3055
3151
|
isOutdated(manifest, ageTolerance = 0) {
|
|
3056
3152
|
if (Date.now() - manifest.lastUpdated > 2 * 60 * 60 * 1000 + ageTolerance * 1000) {
|
|
@@ -3093,15 +3189,15 @@ class ManifestWorker {
|
|
|
3093
3189
|
.sort();
|
|
3094
3190
|
const minorVersions = [...new Set(manifest.versions.map((version) => version.slice(0, -2)))];
|
|
3095
3191
|
for (const tag of minorVersions) {
|
|
3096
|
-
const resolvedVersion = manifest.versions.
|
|
3192
|
+
const resolvedVersion = manifest.versions.filter((version) => version.startsWith(tag)).pop();
|
|
3097
3193
|
if (resolvedVersion != null) {
|
|
3098
3194
|
manifest.resolutions[tag] = resolvedVersion;
|
|
3099
3195
|
}
|
|
3100
3196
|
}
|
|
3101
|
-
for (const
|
|
3102
|
-
const distributionTagValue = packageMetadata["dist-tags"][
|
|
3197
|
+
for (const tagKey of ["beta", "latest", "next", "rc"]) {
|
|
3198
|
+
const distributionTagValue = packageMetadata["dist-tags"][tagKey];
|
|
3103
3199
|
if (distributionTagValue != null) {
|
|
3104
|
-
manifest.resolutions[
|
|
3200
|
+
manifest.resolutions[tagKey] = distributionTagValue;
|
|
3105
3201
|
}
|
|
3106
3202
|
}
|
|
3107
3203
|
return manifest;
|
|
@@ -3171,7 +3267,7 @@ class StoreService {
|
|
|
3171
3267
|
#nodeRequire = createRequire(import.meta.url);
|
|
3172
3268
|
constructor() {
|
|
3173
3269
|
this.#cachePath = Environment.storePath;
|
|
3174
|
-
this.#compilerModuleWorker = new CompilerModuleWorker(this.#cachePath);
|
|
3270
|
+
this.#compilerModuleWorker = new CompilerModuleWorker(this.#cachePath, this.#onDiagnostic);
|
|
3175
3271
|
this.#manifestWorker = new ManifestWorker(this.#cachePath, async () => this.prune());
|
|
3176
3272
|
}
|
|
3177
3273
|
get supportedTags() {
|
|
@@ -3179,7 +3275,7 @@ class StoreService {
|
|
|
3179
3275
|
this.#onDiagnostic(Diagnostic.error("Store manifest is not open. Call 'StoreService.open()' first."));
|
|
3180
3276
|
return [];
|
|
3181
3277
|
}
|
|
3182
|
-
return [...Object.keys(this.#manifest.resolutions), ...this.#manifest.versions].sort();
|
|
3278
|
+
return [...Object.keys(this.#manifest.resolutions), ...this.#manifest.versions, "current"].sort();
|
|
3183
3279
|
}
|
|
3184
3280
|
async install(tag, signal) {
|
|
3185
3281
|
if (!this.#manifest) {
|
|
@@ -3191,14 +3287,7 @@ class StoreService {
|
|
|
3191
3287
|
this.#onDiagnostic(Diagnostic.error(`Cannot add the 'typescript' package for the '${tag}' tag.`));
|
|
3192
3288
|
return;
|
|
3193
3289
|
}
|
|
3194
|
-
|
|
3195
|
-
try {
|
|
3196
|
-
modulePath = await this.#compilerModuleWorker.ensure(version, signal);
|
|
3197
|
-
}
|
|
3198
|
-
catch (error) {
|
|
3199
|
-
this.#onDiagnostic(Diagnostic.fromError(`Failed to install 'typescript@${version}'.`, error));
|
|
3200
|
-
}
|
|
3201
|
-
return modulePath;
|
|
3290
|
+
return this.#compilerModuleWorker.ensure(version, signal);
|
|
3202
3291
|
}
|
|
3203
3292
|
async load(tag, signal) {
|
|
3204
3293
|
let modulePath;
|
|
@@ -3218,9 +3307,9 @@ class StoreService {
|
|
|
3218
3307
|
}
|
|
3219
3308
|
return;
|
|
3220
3309
|
}
|
|
3221
|
-
#onDiagnostic(diagnostic) {
|
|
3310
|
+
#onDiagnostic = (diagnostic) => {
|
|
3222
3311
|
EventEmitter.dispatch(["store:error", { diagnostics: [diagnostic] }]);
|
|
3223
|
-
}
|
|
3312
|
+
};
|
|
3224
3313
|
async open(signal) {
|
|
3225
3314
|
if (this.#manifest) {
|
|
3226
3315
|
return;
|
|
@@ -3235,6 +3324,14 @@ class StoreService {
|
|
|
3235
3324
|
this.#onDiagnostic(Diagnostic.error("Store manifest is not open. Call 'StoreService.open()' first."));
|
|
3236
3325
|
return;
|
|
3237
3326
|
}
|
|
3327
|
+
if (tag === "current") {
|
|
3328
|
+
try {
|
|
3329
|
+
tag = this.#nodeRequire("typescript").version;
|
|
3330
|
+
}
|
|
3331
|
+
catch (error) {
|
|
3332
|
+
this.#onDiagnostic(Diagnostic.fromError("Failed to resolve tag 'current'. The 'typescript' package might be not installed.", error));
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3238
3335
|
if (this.#manifest.versions.includes(tag)) {
|
|
3239
3336
|
return tag;
|
|
3240
3337
|
}
|
|
@@ -3260,7 +3357,7 @@ class StoreService {
|
|
|
3260
3357
|
this.#onDiagnostic(Diagnostic.error("Store manifest is not open. Call 'StoreService.open()' first."));
|
|
3261
3358
|
return false;
|
|
3262
3359
|
}
|
|
3263
|
-
if (this.#manifest.versions.includes(tag) || tag in this.#manifest.resolutions) {
|
|
3360
|
+
if (this.#manifest.versions.includes(tag) || tag in this.#manifest.resolutions || tag === "current") {
|
|
3264
3361
|
return true;
|
|
3265
3362
|
}
|
|
3266
3363
|
if (this.#manifest.resolutions["latest"] != null &&
|
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.6",
|
|
4
4
|
"description": "The Essential Type Testing Tool.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -57,14 +57,14 @@
|
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@jest/globals": "29.7.0",
|
|
59
59
|
"@rollup/plugin-typescript": "11.1.5",
|
|
60
|
-
"@types/node": "20.
|
|
61
|
-
"@typescript-eslint/eslint-plugin": "6.
|
|
62
|
-
"@typescript-eslint/parser": "6.
|
|
60
|
+
"@types/node": "20.10.2",
|
|
61
|
+
"@typescript-eslint/eslint-plugin": "6.13.1",
|
|
62
|
+
"@typescript-eslint/parser": "6.13.1",
|
|
63
63
|
"ajv": "8.12.0",
|
|
64
64
|
"c8": "8.0.1",
|
|
65
|
-
"cspell": "8.
|
|
66
|
-
"eslint": "8.
|
|
67
|
-
"eslint-config-prettier": "9.
|
|
65
|
+
"cspell": "8.1.0",
|
|
66
|
+
"eslint": "8.55.0",
|
|
67
|
+
"eslint-config-prettier": "9.1.0",
|
|
68
68
|
"eslint-import-resolver-typescript": "3.6.1",
|
|
69
69
|
"eslint-plugin-import": "2.29.0",
|
|
70
70
|
"eslint-plugin-jest": "27.6.0",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"jest-serializer-ansi-escapes": "2.0.1",
|
|
77
77
|
"magic-string": "0.30.5",
|
|
78
78
|
"prettier": "3.1.0",
|
|
79
|
-
"rollup": "4.
|
|
79
|
+
"rollup": "4.6.1",
|
|
80
80
|
"rollup-plugin-dts": "6.1.0",
|
|
81
81
|
"rollup-plugin-tsconfig-paths": "1.5.2",
|
|
82
82
|
"ts-node": "10.9.1",
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"optional": true
|
|
92
92
|
}
|
|
93
93
|
},
|
|
94
|
-
"packageManager": "yarn@
|
|
94
|
+
"packageManager": "yarn@3.7.0",
|
|
95
95
|
"engines": {
|
|
96
|
-
"node": "^18.
|
|
96
|
+
"node": "^16.14 || 18.x || >=20.x"
|
|
97
97
|
}
|
|
98
98
|
}
|