tstyche 2.1.0 → 3.0.0-beta.0
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/README.md +1 -7
- package/build/tstyche.d.ts +27 -28
- package/build/tstyche.js +443 -429
- package/package.json +14 -16
package/build/tstyche.js
CHANGED
|
@@ -6,7 +6,7 @@ import os from 'node:os';
|
|
|
6
6
|
import { watch, existsSync, writeFileSync, rmSync } from 'node:fs';
|
|
7
7
|
import fs from 'node:fs/promises';
|
|
8
8
|
import vm from 'node:vm';
|
|
9
|
-
import
|
|
9
|
+
import streamConsumers from 'node:stream/consumers';
|
|
10
10
|
|
|
11
11
|
class EventEmitter {
|
|
12
12
|
static #handlers = new Set();
|
|
@@ -446,6 +446,7 @@ class Environment {
|
|
|
446
446
|
static #isCi = Environment.#resolveIsCi();
|
|
447
447
|
static #noColor = Environment.#resolveNoColor();
|
|
448
448
|
static #noInteractive = Environment.#resolveNoInteractive();
|
|
449
|
+
static #npmRegistry = Environment.#resolveNpmRegistry();
|
|
449
450
|
static #storePath = Environment.#resolveStorePath();
|
|
450
451
|
static #timeout = Environment.#resolveTimeout();
|
|
451
452
|
static #typescriptPath = Environment.#resolveTypeScriptPath();
|
|
@@ -458,6 +459,9 @@ class Environment {
|
|
|
458
459
|
static get noInteractive() {
|
|
459
460
|
return Environment.#noInteractive;
|
|
460
461
|
}
|
|
462
|
+
static get npmRegistry() {
|
|
463
|
+
return Environment.#npmRegistry;
|
|
464
|
+
}
|
|
461
465
|
static get storePath() {
|
|
462
466
|
return Environment.#storePath;
|
|
463
467
|
}
|
|
@@ -488,6 +492,12 @@ class Environment {
|
|
|
488
492
|
}
|
|
489
493
|
return !process.stdout.isTTY;
|
|
490
494
|
}
|
|
495
|
+
static #resolveNpmRegistry() {
|
|
496
|
+
if (process.env["TSTYCHE_NPM_REGISTRY"] != null) {
|
|
497
|
+
return process.env["TSTYCHE_NPM_REGISTRY"];
|
|
498
|
+
}
|
|
499
|
+
return "https://registry.npmjs.org";
|
|
500
|
+
}
|
|
491
501
|
static #resolveStorePath() {
|
|
492
502
|
if (process.env["TSTYCHE_STORE_PATH"] != null) {
|
|
493
503
|
return Path.resolve(process.env["TSTYCHE_STORE_PATH"]);
|
|
@@ -505,7 +515,7 @@ class Environment {
|
|
|
505
515
|
}
|
|
506
516
|
static #resolveTimeout() {
|
|
507
517
|
if (process.env["TSTYCHE_TIMEOUT"] != null) {
|
|
508
|
-
return Number(process.env["TSTYCHE_TIMEOUT"]);
|
|
518
|
+
return Number.parseFloat(process.env["TSTYCHE_TIMEOUT"]);
|
|
509
519
|
}
|
|
510
520
|
return 30;
|
|
511
521
|
}
|
|
@@ -589,7 +599,7 @@ class Scribbler {
|
|
|
589
599
|
#visitChildren(children) {
|
|
590
600
|
const text = [];
|
|
591
601
|
for (const child of children) {
|
|
592
|
-
if (typeof child === "string") {
|
|
602
|
+
if (typeof child === "string" || typeof child === "number") {
|
|
593
603
|
text.push(child);
|
|
594
604
|
continue;
|
|
595
605
|
}
|
|
@@ -605,8 +615,8 @@ class Scribbler {
|
|
|
605
615
|
}
|
|
606
616
|
}
|
|
607
617
|
|
|
608
|
-
function addsPackageStepText(
|
|
609
|
-
return (jsx(Line, { children: [jsx(Text, { color: "90", children: "adds" }), " TypeScript ",
|
|
618
|
+
function addsPackageStepText(packageVersion, packagePath) {
|
|
619
|
+
return (jsx(Line, { children: [jsx(Text, { color: "90", children: "adds" }), " TypeScript ", packageVersion, jsx(Text, { color: "90", children: [" to ", packagePath] })] }));
|
|
610
620
|
}
|
|
611
621
|
|
|
612
622
|
function describeNameText(name, indent = 0) {
|
|
@@ -616,61 +626,72 @@ function describeNameText(name, indent = 0) {
|
|
|
616
626
|
function BreadcrumbsText({ ancestor }) {
|
|
617
627
|
const text = [];
|
|
618
628
|
while ("name" in ancestor) {
|
|
619
|
-
text.
|
|
629
|
+
text.push(ancestor.name);
|
|
620
630
|
ancestor = ancestor.parent;
|
|
621
631
|
}
|
|
622
|
-
|
|
632
|
+
text.push("");
|
|
633
|
+
return jsx(Text, { color: "90", children: text.reverse().join(" ❭ ") });
|
|
623
634
|
}
|
|
624
|
-
function CodeLineText({
|
|
625
|
-
return (jsx(Line, { children: [jsx(Text, { color: lineNumberColor, children:
|
|
635
|
+
function CodeLineText({ gutterWidth, lineNumber, lineNumberColor = "90", lineText }) {
|
|
636
|
+
return (jsx(Line, { children: [jsx(Text, { color: lineNumberColor, children: lineNumber.toString().padStart(gutterWidth) }), jsx(Text, { color: "90", children: " | " }), lineText] }));
|
|
626
637
|
}
|
|
627
|
-
function SquiggleLineText({ gutterWidth, indentWidth = 0, squiggleWidth }) {
|
|
628
|
-
return (jsx(Line, { children: [" ".repeat(gutterWidth), jsx(Text, { color: "90", children: " | " }), " ".repeat(indentWidth), jsx(Text, { color:
|
|
638
|
+
function SquiggleLineText({ gutterWidth, indentWidth = 0, squiggleColor, squiggleWidth }) {
|
|
639
|
+
return (jsx(Line, { children: [" ".repeat(gutterWidth), jsx(Text, { color: "90", children: " | " }), " ".repeat(indentWidth), jsx(Text, { color: squiggleColor, children: "~".repeat(squiggleWidth === 0 ? 1 : squiggleWidth) })] }));
|
|
629
640
|
}
|
|
630
|
-
function CodeSpanText({ diagnosticOrigin }) {
|
|
641
|
+
function CodeSpanText({ diagnosticCategory, diagnosticOrigin }) {
|
|
631
642
|
const lastLineInFile = diagnosticOrigin.sourceFile.getLineAndCharacterOfPosition(diagnosticOrigin.sourceFile.text.length).line;
|
|
632
643
|
const { character: firstMarkedLineCharacter, line: firstMarkedLine } = diagnosticOrigin.sourceFile.getLineAndCharacterOfPosition(diagnosticOrigin.start);
|
|
633
644
|
const { character: lastMarkedLineCharacter, line: lastMarkedLine } = diagnosticOrigin.sourceFile.getLineAndCharacterOfPosition(diagnosticOrigin.end);
|
|
634
645
|
const firstLine = Math.max(firstMarkedLine - 2, 0);
|
|
635
646
|
const lastLine = Math.min(firstLine + 5, lastLineInFile);
|
|
636
|
-
const gutterWidth =
|
|
647
|
+
const gutterWidth = (lastLine + 1).toString().length + 2;
|
|
648
|
+
let highlightColor;
|
|
649
|
+
switch (diagnosticCategory) {
|
|
650
|
+
case "error": {
|
|
651
|
+
highlightColor = "31";
|
|
652
|
+
break;
|
|
653
|
+
}
|
|
654
|
+
case "warning": {
|
|
655
|
+
highlightColor = "33";
|
|
656
|
+
break;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
637
659
|
const codeSpan = [];
|
|
638
660
|
for (let index = firstLine; index <= lastLine; index++) {
|
|
639
661
|
const lineStart = diagnosticOrigin.sourceFile.getPositionOfLineAndCharacter(index, 0);
|
|
640
662
|
const lineEnd = index === lastLineInFile
|
|
641
663
|
? diagnosticOrigin.sourceFile.text.length
|
|
642
664
|
: diagnosticOrigin.sourceFile.getPositionOfLineAndCharacter(index + 1, 0);
|
|
643
|
-
const lineNumberText = String(index + 1);
|
|
644
665
|
const lineText = diagnosticOrigin.sourceFile.text.slice(lineStart, lineEnd).trimEnd().replace(/\t/g, " ");
|
|
645
666
|
if (index >= firstMarkedLine && index <= lastMarkedLine) {
|
|
646
|
-
codeSpan.push(jsx(CodeLineText, { gutterWidth: gutterWidth,
|
|
667
|
+
codeSpan.push(jsx(CodeLineText, { gutterWidth: gutterWidth, lineNumber: index + 1, lineNumberColor: highlightColor, lineText: lineText }));
|
|
647
668
|
if (index === firstMarkedLine) {
|
|
648
669
|
const squiggleLength = index === lastMarkedLine
|
|
649
670
|
? lastMarkedLineCharacter - firstMarkedLineCharacter
|
|
650
671
|
: lineText.length - firstMarkedLineCharacter;
|
|
651
|
-
codeSpan.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, indentWidth: firstMarkedLineCharacter, squiggleWidth: squiggleLength }));
|
|
672
|
+
codeSpan.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, indentWidth: firstMarkedLineCharacter, squiggleColor: highlightColor, squiggleWidth: squiggleLength }));
|
|
652
673
|
}
|
|
653
674
|
else if (index === lastMarkedLine) {
|
|
654
|
-
codeSpan.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleWidth: lastMarkedLineCharacter }));
|
|
675
|
+
codeSpan.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth: lastMarkedLineCharacter }));
|
|
655
676
|
}
|
|
656
677
|
else {
|
|
657
|
-
codeSpan.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleWidth: lineText.length }));
|
|
678
|
+
codeSpan.push(jsx(SquiggleLineText, { gutterWidth: gutterWidth, squiggleColor: highlightColor, squiggleWidth: lineText.length }));
|
|
658
679
|
}
|
|
659
680
|
}
|
|
660
681
|
else {
|
|
661
|
-
codeSpan.push(jsx(CodeLineText, { gutterWidth: gutterWidth,
|
|
682
|
+
codeSpan.push(jsx(CodeLineText, { gutterWidth: gutterWidth, lineNumber: index + 1, lineText: lineText }));
|
|
662
683
|
}
|
|
663
684
|
}
|
|
664
|
-
const location = (jsx(Line, { children: [" ".repeat(gutterWidth + 2), jsx(Text, { color: "90", children: " at " }), jsx(Text, { color: "36", children: Path.relative("", diagnosticOrigin.sourceFile.fileName) }), jsx(Text, { color: "90", children:
|
|
685
|
+
const location = (jsx(Line, { children: [" ".repeat(gutterWidth + 2), jsx(Text, { color: "90", children: " at " }), jsx(Text, { color: "36", children: Path.relative("", diagnosticOrigin.sourceFile.fileName) }), jsx(Text, { color: "90", children: `:${firstMarkedLine + 1}:${firstMarkedLineCharacter + 1}` }), diagnosticOrigin.assertion && jsx(BreadcrumbsText, { ancestor: diagnosticOrigin.assertion.parent })] }));
|
|
665
686
|
return (jsx(Text, { children: [codeSpan, jsx(Line, {}), location] }));
|
|
666
687
|
}
|
|
667
688
|
|
|
668
689
|
function DiagnosticText({ diagnostic }) {
|
|
669
|
-
const code =
|
|
690
|
+
const code = diagnostic.code ? jsx(Text, { color: "90", children: [" ", diagnostic.code] }) : undefined;
|
|
670
691
|
const text = Array.isArray(diagnostic.text) ? diagnostic.text : [diagnostic.text];
|
|
671
692
|
const message = text.map((text, index) => (jsx(Text, { children: [index === 1 ? jsx(Line, {}) : undefined, jsx(Line, { children: [text, code] })] })));
|
|
672
693
|
const related = diagnostic.related?.map((relatedDiagnostic) => jsx(DiagnosticText, { diagnostic: relatedDiagnostic }));
|
|
673
|
-
const codeSpan = diagnostic.origin ? (jsx(Text, { children: [jsx(Line, {}), jsx(CodeSpanText, { diagnosticOrigin: diagnostic.origin })] })) : undefined;
|
|
694
|
+
const codeSpan = diagnostic.origin ? (jsx(Text, { children: [jsx(Line, {}), jsx(CodeSpanText, { diagnosticCategory: diagnostic.category, diagnosticOrigin: diagnostic.origin })] })) : undefined;
|
|
674
695
|
return (jsx(Text, { children: [message, codeSpan, jsx(Line, {}), jsx(Text, { indent: 2, children: related })] }));
|
|
675
696
|
}
|
|
676
697
|
function diagnosticText(diagnostic) {
|
|
@@ -747,11 +768,7 @@ function HelpHeaderText({ tstycheVersion }) {
|
|
|
747
768
|
return (jsx(Line, { children: ["The TSTyche Type Test Runner", jsx(HintText, { children: tstycheVersion })] }));
|
|
748
769
|
}
|
|
749
770
|
function CommandText({ hint, text }) {
|
|
750
|
-
|
|
751
|
-
if (hint != null) {
|
|
752
|
-
hintText = jsx(HintText, { children: hint });
|
|
753
|
-
}
|
|
754
|
-
return (jsx(Line, { indent: 1, children: [jsx(Text, { color: "34", children: text }), hintText] }));
|
|
771
|
+
return (jsx(Line, { indent: 1, children: [jsx(Text, { color: "34", children: text }), hint && jsx(HintText, { children: hint })] }));
|
|
755
772
|
}
|
|
756
773
|
function OptionDescriptionText({ text }) {
|
|
757
774
|
return jsx(Line, { indent: 1, children: text });
|
|
@@ -766,11 +783,11 @@ function CommandLineUsageText() {
|
|
|
766
783
|
return jsx(Text, { children: usageText });
|
|
767
784
|
}
|
|
768
785
|
function CommandLineOptionNameText({ text }) {
|
|
769
|
-
return jsx(Text, { children:
|
|
786
|
+
return jsx(Text, { children: `--${text}` });
|
|
770
787
|
}
|
|
771
788
|
function CommandLineOptionHintText({ definition }) {
|
|
772
789
|
if (definition.brand === "list") {
|
|
773
|
-
return
|
|
790
|
+
return jsx(Text, { children: `${definition.brand} of ${definition.items.brand}s` });
|
|
774
791
|
}
|
|
775
792
|
return jsx(Text, { children: definition.brand });
|
|
776
793
|
}
|
|
@@ -835,16 +852,16 @@ function RowText({ label, text }) {
|
|
|
835
852
|
return (jsx(Line, { children: [`${label}:`.padEnd(12), text] }));
|
|
836
853
|
}
|
|
837
854
|
function CountText({ failed, passed, skipped, todo, total }) {
|
|
838
|
-
return (jsx(Text, { children: [failed > 0 ? (jsx(Text, { children: [jsx(Text, { color: "31", children: [
|
|
855
|
+
return (jsx(Text, { children: [failed > 0 ? (jsx(Text, { children: [jsx(Text, { color: "31", children: [failed, " failed"] }), jsx(Text, { children: ", " })] })) : undefined, skipped > 0 ? (jsx(Text, { children: [jsx(Text, { color: "33", children: [skipped, " skipped"] }), jsx(Text, { children: ", " })] })) : undefined, todo > 0 ? (jsx(Text, { children: [jsx(Text, { color: "35", children: [todo, " todo"] }), jsx(Text, { children: ", " })] })) : undefined, passed > 0 ? (jsx(Text, { children: [jsx(Text, { color: "32", children: [passed, " passed"] }), jsx(Text, { children: ", " })] })) : undefined, jsx(Text, { children: [total, " total"] })] }));
|
|
839
856
|
}
|
|
840
857
|
function DurationText({ seconds }) {
|
|
841
|
-
return jsx(Text, { children: `${
|
|
858
|
+
return jsx(Text, { children: `${Math.round(seconds * 10) / 10}s` });
|
|
842
859
|
}
|
|
843
860
|
function MatchText({ text }) {
|
|
844
861
|
if (typeof text === "string") {
|
|
845
862
|
return jsx(Text, { children: ["'", text, "'"] });
|
|
846
863
|
}
|
|
847
|
-
if (text.length
|
|
864
|
+
if (text.length === 1) {
|
|
848
865
|
return jsx(Text, { children: ["'", ...text, "'"] });
|
|
849
866
|
}
|
|
850
867
|
const lastItem = text.pop();
|
|
@@ -856,7 +873,7 @@ function RanFilesText({ onlyMatch, pathMatch, skipMatch }) {
|
|
|
856
873
|
testNameMatchText.push(jsx(Text, { children: [jsx(Text, { color: "90", children: "matching " }), jsx(MatchText, { text: onlyMatch })] }));
|
|
857
874
|
}
|
|
858
875
|
if (skipMatch != null) {
|
|
859
|
-
testNameMatchText.push(jsx(Text, { children: [onlyMatch
|
|
876
|
+
testNameMatchText.push(jsx(Text, { children: [onlyMatch && jsx(Text, { color: "90", children: " and " }), jsx(Text, { color: "90", children: "not matching " }), jsx(MatchText, { text: skipMatch })] }));
|
|
860
877
|
}
|
|
861
878
|
let pathMatchText;
|
|
862
879
|
if (pathMatch.length > 0) {
|
|
@@ -987,7 +1004,7 @@ class RunReporter extends Reporter {
|
|
|
987
1004
|
break;
|
|
988
1005
|
}
|
|
989
1006
|
case "store:info": {
|
|
990
|
-
this.outputService.writeMessage(addsPackageStepText(payload.
|
|
1007
|
+
this.outputService.writeMessage(addsPackageStepText(payload.packageVersion, payload.packagePath));
|
|
991
1008
|
this.#hasReportedAdds = true;
|
|
992
1009
|
break;
|
|
993
1010
|
}
|
|
@@ -1111,7 +1128,7 @@ class RunReporter extends Reporter {
|
|
|
1111
1128
|
class SetupReporter extends Reporter {
|
|
1112
1129
|
handleEvent([eventName, payload]) {
|
|
1113
1130
|
if (eventName === "store:info") {
|
|
1114
|
-
this.outputService.writeMessage(addsPackageStepText(payload.
|
|
1131
|
+
this.outputService.writeMessage(addsPackageStepText(payload.packageVersion, payload.packagePath));
|
|
1115
1132
|
return;
|
|
1116
1133
|
}
|
|
1117
1134
|
if ("diagnostics" in payload) {
|
|
@@ -1297,7 +1314,7 @@ class Diagnostic {
|
|
|
1297
1314
|
}
|
|
1298
1315
|
static fromDiagnostics(diagnostics, compiler) {
|
|
1299
1316
|
return diagnostics.map((diagnostic) => {
|
|
1300
|
-
const code = `ts(${
|
|
1317
|
+
const code = `ts(${diagnostic.code})`;
|
|
1301
1318
|
let origin;
|
|
1302
1319
|
if (Diagnostic.#isTsDiagnosticWithLocation(diagnostic)) {
|
|
1303
1320
|
origin = new DiagnosticOrigin(diagnostic.start, diagnostic.start + diagnostic.length, diagnostic.file);
|
|
@@ -1310,17 +1327,6 @@ class Diagnostic {
|
|
|
1310
1327
|
return new Diagnostic(text, "error", origin).add({ code, related });
|
|
1311
1328
|
});
|
|
1312
1329
|
}
|
|
1313
|
-
static fromError(text, error) {
|
|
1314
|
-
const messageText = Array.isArray(text) ? text : [text];
|
|
1315
|
-
if (error instanceof Error && error.stack != null) {
|
|
1316
|
-
if (messageText.length > 1) {
|
|
1317
|
-
messageText.push("");
|
|
1318
|
-
}
|
|
1319
|
-
const stackLines = error.stack.split("\n").map((line) => line.trimStart());
|
|
1320
|
-
messageText.push(...stackLines);
|
|
1321
|
-
}
|
|
1322
|
-
return Diagnostic.error(messageText);
|
|
1323
|
-
}
|
|
1324
1330
|
static #isTsDiagnosticWithLocation(diagnostic) {
|
|
1325
1331
|
return diagnostic.file != null && diagnostic.start != null && diagnostic.length != null;
|
|
1326
1332
|
}
|
|
@@ -1446,10 +1452,21 @@ class SelectService {
|
|
|
1446
1452
|
#onDiagnostics(diagnostic) {
|
|
1447
1453
|
EventEmitter.dispatch(["select:error", { diagnostics: [diagnostic] }]);
|
|
1448
1454
|
}
|
|
1455
|
+
async #resolveEntryMeta(entry, targetPath) {
|
|
1456
|
+
if (!entry.isSymbolicLink()) {
|
|
1457
|
+
return entry;
|
|
1458
|
+
}
|
|
1459
|
+
let entryMeta;
|
|
1460
|
+
try {
|
|
1461
|
+
entryMeta = await fs.stat([targetPath, entry.name].join("/"));
|
|
1462
|
+
}
|
|
1463
|
+
catch {
|
|
1464
|
+
}
|
|
1465
|
+
return entryMeta;
|
|
1466
|
+
}
|
|
1449
1467
|
async selectFiles() {
|
|
1450
|
-
const currentPath = ".";
|
|
1451
1468
|
const testFilePaths = [];
|
|
1452
|
-
await this.#visitDirectory(
|
|
1469
|
+
await this.#visitDirectory(".", testFilePaths);
|
|
1453
1470
|
if (testFilePaths.length === 0) {
|
|
1454
1471
|
this.#onDiagnostics(Diagnostic.error(SelectDiagnosticText.noTestFilesWereSelected(this.#resolvedConfig)));
|
|
1455
1472
|
}
|
|
@@ -1457,38 +1474,20 @@ class SelectService {
|
|
|
1457
1474
|
}
|
|
1458
1475
|
async #visitDirectory(currentPath, testFilePaths) {
|
|
1459
1476
|
const targetPath = Path.join(this.#resolvedConfig.rootPath, currentPath);
|
|
1460
|
-
let entries;
|
|
1461
1477
|
try {
|
|
1462
|
-
entries = await fs.readdir(targetPath, { withFileTypes: true });
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
}
|
|
1469
|
-
for (const entry of entries) {
|
|
1470
|
-
let entryMeta;
|
|
1471
|
-
if (entry.isSymbolicLink()) {
|
|
1472
|
-
try {
|
|
1473
|
-
entryMeta = await fs.stat([targetPath, entry.name].join("/"));
|
|
1478
|
+
const entries = await fs.readdir(targetPath, { withFileTypes: true });
|
|
1479
|
+
for (const entry of entries) {
|
|
1480
|
+
const entryMeta = await this.#resolveEntryMeta(entry, targetPath);
|
|
1481
|
+
const entryPath = [currentPath, entry.name].join("/");
|
|
1482
|
+
if (entryMeta?.isDirectory() && this.#isDirectoryIncluded(entryPath)) {
|
|
1483
|
+
await this.#visitDirectory(entryPath, testFilePaths);
|
|
1474
1484
|
}
|
|
1475
|
-
|
|
1485
|
+
else if (entryMeta?.isFile() && this.#isFileIncluded(entryPath)) {
|
|
1486
|
+
testFilePaths.push([targetPath, entry.name].join("/"));
|
|
1476
1487
|
}
|
|
1477
1488
|
}
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
}
|
|
1481
|
-
if (!entryMeta) {
|
|
1482
|
-
continue;
|
|
1483
|
-
}
|
|
1484
|
-
const entryPath = [currentPath, entry.name].join("/");
|
|
1485
|
-
if (entryMeta.isDirectory() && this.#isDirectoryIncluded(entryPath)) {
|
|
1486
|
-
await this.#visitDirectory(entryPath, testFilePaths);
|
|
1487
|
-
continue;
|
|
1488
|
-
}
|
|
1489
|
-
if (entryMeta.isFile() && this.#isFileIncluded(entryPath)) {
|
|
1490
|
-
testFilePaths.push([targetPath, entry.name].join("/"));
|
|
1491
|
-
}
|
|
1489
|
+
}
|
|
1490
|
+
catch {
|
|
1492
1491
|
}
|
|
1493
1492
|
}
|
|
1494
1493
|
}
|
|
@@ -1888,6 +1887,132 @@ var TestMemberFlags;
|
|
|
1888
1887
|
TestMemberFlags[TestMemberFlags["Todo"] = 8] = "Todo";
|
|
1889
1888
|
})(TestMemberFlags || (TestMemberFlags = {}));
|
|
1890
1889
|
|
|
1890
|
+
class Version {
|
|
1891
|
+
static isGreaterThan(source, target) {
|
|
1892
|
+
return !(source === target) && Version.#satisfies(source, target);
|
|
1893
|
+
}
|
|
1894
|
+
static isSatisfiedWith(source, target) {
|
|
1895
|
+
return source === target || Version.#satisfies(source, target);
|
|
1896
|
+
}
|
|
1897
|
+
static isVersionTag(target) {
|
|
1898
|
+
return /^\d+/.test(target);
|
|
1899
|
+
}
|
|
1900
|
+
static #satisfies(source, target) {
|
|
1901
|
+
const sourceElements = source.split(/\.|-/);
|
|
1902
|
+
const targetElements = target.split(/\.|-/);
|
|
1903
|
+
function compare(index = 0) {
|
|
1904
|
+
const sourceElement = sourceElements[index];
|
|
1905
|
+
const targetElement = targetElements[index];
|
|
1906
|
+
if (sourceElement > targetElement) {
|
|
1907
|
+
return true;
|
|
1908
|
+
}
|
|
1909
|
+
if (sourceElement < targetElement) {
|
|
1910
|
+
return false;
|
|
1911
|
+
}
|
|
1912
|
+
if (index === sourceElements.length - 1 || index === targetElements.length - 1) {
|
|
1913
|
+
return true;
|
|
1914
|
+
}
|
|
1915
|
+
return compare(index + 1);
|
|
1916
|
+
}
|
|
1917
|
+
return compare();
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
class ProjectService {
|
|
1922
|
+
#compiler;
|
|
1923
|
+
#service;
|
|
1924
|
+
constructor(compiler) {
|
|
1925
|
+
this.#compiler = compiler;
|
|
1926
|
+
function doNothing() {
|
|
1927
|
+
}
|
|
1928
|
+
function returnFalse() {
|
|
1929
|
+
return false;
|
|
1930
|
+
}
|
|
1931
|
+
function returnUndefined() {
|
|
1932
|
+
return undefined;
|
|
1933
|
+
}
|
|
1934
|
+
const noopWatcher = { close: doNothing };
|
|
1935
|
+
const noopLogger = {
|
|
1936
|
+
close: doNothing,
|
|
1937
|
+
endGroup: doNothing,
|
|
1938
|
+
getLogFileName: returnUndefined,
|
|
1939
|
+
hasLevel: returnFalse,
|
|
1940
|
+
info: doNothing,
|
|
1941
|
+
loggingEnabled: returnFalse,
|
|
1942
|
+
msg: doNothing,
|
|
1943
|
+
perftrc: doNothing,
|
|
1944
|
+
startGroup: doNothing,
|
|
1945
|
+
};
|
|
1946
|
+
const host = {
|
|
1947
|
+
...this.#compiler.sys,
|
|
1948
|
+
clearImmediate,
|
|
1949
|
+
clearTimeout,
|
|
1950
|
+
setImmediate,
|
|
1951
|
+
setTimeout,
|
|
1952
|
+
watchDirectory: () => noopWatcher,
|
|
1953
|
+
watchFile: () => noopWatcher,
|
|
1954
|
+
};
|
|
1955
|
+
this.#service = new this.#compiler.server.ProjectService({
|
|
1956
|
+
allowLocalPluginLoads: true,
|
|
1957
|
+
cancellationToken: this.#compiler.server.nullCancellationToken,
|
|
1958
|
+
host,
|
|
1959
|
+
logger: noopLogger,
|
|
1960
|
+
session: undefined,
|
|
1961
|
+
useInferredProjectPerProjectRoot: true,
|
|
1962
|
+
useSingleInferredProject: false,
|
|
1963
|
+
});
|
|
1964
|
+
this.#service.setCompilerOptionsForInferredProjects(this.#getDefaultCompilerOptions());
|
|
1965
|
+
}
|
|
1966
|
+
closeFile(filePath) {
|
|
1967
|
+
this.#service.closeClientFile(filePath);
|
|
1968
|
+
}
|
|
1969
|
+
#getDefaultCompilerOptions() {
|
|
1970
|
+
const defaultCompilerOptions = {
|
|
1971
|
+
allowJs: true,
|
|
1972
|
+
checkJs: true,
|
|
1973
|
+
esModuleInterop: true,
|
|
1974
|
+
jsx: "preserve",
|
|
1975
|
+
module: "esnext",
|
|
1976
|
+
moduleResolution: "node",
|
|
1977
|
+
resolveJsonModule: true,
|
|
1978
|
+
strictFunctionTypes: true,
|
|
1979
|
+
strictNullChecks: true,
|
|
1980
|
+
target: "esnext",
|
|
1981
|
+
};
|
|
1982
|
+
if (Version.isSatisfiedWith(this.#compiler.version, "5.4")) {
|
|
1983
|
+
defaultCompilerOptions.module = "preserve";
|
|
1984
|
+
}
|
|
1985
|
+
if (Version.isSatisfiedWith(this.#compiler.version, "5.0")) {
|
|
1986
|
+
defaultCompilerOptions.allowImportingTsExtensions = true;
|
|
1987
|
+
defaultCompilerOptions.moduleResolution = "bundler";
|
|
1988
|
+
}
|
|
1989
|
+
return defaultCompilerOptions;
|
|
1990
|
+
}
|
|
1991
|
+
getDefaultProject(filePath) {
|
|
1992
|
+
return this.#service.getDefaultProjectForFile(this.#compiler.server.toNormalizedPath(filePath), true);
|
|
1993
|
+
}
|
|
1994
|
+
getLanguageService(filePath) {
|
|
1995
|
+
const project = this.getDefaultProject(filePath);
|
|
1996
|
+
if (!project) {
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
return project.getLanguageService(true);
|
|
2000
|
+
}
|
|
2001
|
+
openFile(filePath, sourceText, projectRootPath) {
|
|
2002
|
+
const { configFileErrors, configFileName } = this.#service.openClientFile(filePath, sourceText, undefined, projectRootPath);
|
|
2003
|
+
EventEmitter.dispatch([
|
|
2004
|
+
"project:info",
|
|
2005
|
+
{ compilerVersion: this.#compiler.version, projectConfigFilePath: configFileName },
|
|
2006
|
+
]);
|
|
2007
|
+
if (configFileErrors && configFileErrors.length > 0) {
|
|
2008
|
+
EventEmitter.dispatch([
|
|
2009
|
+
"project:error",
|
|
2010
|
+
{ diagnostics: Diagnostic.fromDiagnostics(configFileErrors, this.#compiler) },
|
|
2011
|
+
]);
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
|
|
1891
2016
|
class ExpectDiagnosticText {
|
|
1892
2017
|
static argumentOrTypeArgumentMustBeProvided(argumentNameText, typeArgumentNameText) {
|
|
1893
2018
|
return `An argument for '${argumentNameText}' or type argument for '${typeArgumentNameText}' must be provided.`;
|
|
@@ -1904,17 +2029,11 @@ class ExpectDiagnosticText {
|
|
|
1904
2029
|
static componentDoesNotAcceptProps(isTypeNode) {
|
|
1905
2030
|
return `${isTypeNode ? "Component type" : "Component"} does not accept props of the given type.`;
|
|
1906
2031
|
}
|
|
1907
|
-
static matcherIsDeprecated(matcherNameText) {
|
|
1908
|
-
return [
|
|
1909
|
-
`The '.${matcherNameText}()' matcher is deprecated and will be removed in TSTyche 3.`,
|
|
1910
|
-
"To learn more, visit https://tstyche.org/releases/tstyche-2",
|
|
1911
|
-
];
|
|
1912
|
-
}
|
|
1913
2032
|
static matcherIsNotSupported(matcherNameText) {
|
|
1914
2033
|
return `The '.${matcherNameText}()' matcher is not supported.`;
|
|
1915
2034
|
}
|
|
1916
|
-
static overloadGaveTheFollowingError(
|
|
1917
|
-
return `Overload ${
|
|
2035
|
+
static overloadGaveTheFollowingError(index, count, signatureText) {
|
|
2036
|
+
return `Overload ${index} of ${count}, '${signatureText}', gave the following error.`;
|
|
1918
2037
|
}
|
|
1919
2038
|
static raisedTypeError(count = 1) {
|
|
1920
2039
|
return `The raised type error${count === 1 ? "" : "s"}:`;
|
|
@@ -1967,7 +2086,7 @@ class ExpectDiagnosticText {
|
|
|
1967
2086
|
static typeRaisedError(isTypeNode, count, targetCount) {
|
|
1968
2087
|
let countText = "a";
|
|
1969
2088
|
if (count > 1 || targetCount > 1) {
|
|
1970
|
-
countText = count > targetCount ?
|
|
2089
|
+
countText = count > targetCount ? `${count}` : `only ${count}`;
|
|
1971
2090
|
}
|
|
1972
2091
|
return `${isTypeNode ? "Type" : "Expression type"} raised ${countText} type error${count === 1 ? "" : "s"}.`;
|
|
1973
2092
|
}
|
|
@@ -2058,19 +2177,19 @@ class MatchWorker {
|
|
|
2058
2177
|
return type;
|
|
2059
2178
|
}
|
|
2060
2179
|
isAnyOrNeverType(type) {
|
|
2061
|
-
return
|
|
2180
|
+
return !!(type.flags & (this.#compiler.TypeFlags.Any | this.#compiler.TypeFlags.Never));
|
|
2062
2181
|
}
|
|
2063
2182
|
isStringOrNumberLiteralType(type) {
|
|
2064
|
-
return
|
|
2183
|
+
return !!(type.flags & this.#compiler.TypeFlags.StringOrNumberLiteral);
|
|
2065
2184
|
}
|
|
2066
2185
|
isObjectType(type) {
|
|
2067
|
-
return
|
|
2186
|
+
return !!(type.flags & this.#compiler.TypeFlags.Object);
|
|
2068
2187
|
}
|
|
2069
2188
|
isUnionType(type) {
|
|
2070
|
-
return
|
|
2189
|
+
return !!(type.flags & this.#compiler.TypeFlags.Union);
|
|
2071
2190
|
}
|
|
2072
2191
|
isUniqueSymbolType(type) {
|
|
2073
|
-
return
|
|
2192
|
+
return !!(type.flags & this.#compiler.TypeFlags.UniqueESSymbol);
|
|
2074
2193
|
}
|
|
2075
2194
|
resolveDiagnosticOrigin(symbol, enclosingNode) {
|
|
2076
2195
|
if (symbol.valueDeclaration != null &&
|
|
@@ -2097,7 +2216,7 @@ class PrimitiveTypeMatcher {
|
|
|
2097
2216
|
}
|
|
2098
2217
|
match(matchWorker, sourceNode) {
|
|
2099
2218
|
const sourceType = matchWorker.getType(sourceNode);
|
|
2100
|
-
const isMatch =
|
|
2219
|
+
const isMatch = !!(sourceType.flags & this.#targetTypeFlag);
|
|
2101
2220
|
return {
|
|
2102
2221
|
explain: () => this.#explain(matchWorker, sourceNode),
|
|
2103
2222
|
isMatch,
|
|
@@ -2122,7 +2241,7 @@ class ToAcceptProps {
|
|
|
2122
2241
|
const origin = DiagnosticOrigin.fromNode(targetNode, matchWorker.assertion);
|
|
2123
2242
|
if (signatures.length > 1) {
|
|
2124
2243
|
const signatureText = this.#typeChecker.signatureToString(signature, sourceNode);
|
|
2125
|
-
const overloadText = ExpectDiagnosticText.overloadGaveTheFollowingError(
|
|
2244
|
+
const overloadText = ExpectDiagnosticText.overloadGaveTheFollowingError(index + 1, signatures.length, signatureText);
|
|
2126
2245
|
diagnostic = Diagnostic.error([introText, overloadText], origin);
|
|
2127
2246
|
}
|
|
2128
2247
|
else {
|
|
@@ -2343,7 +2462,7 @@ class ToHaveProperty {
|
|
|
2343
2462
|
const targetType = matchWorker.getType(targetNode);
|
|
2344
2463
|
let propertyNameText;
|
|
2345
2464
|
if (matchWorker.isStringOrNumberLiteralType(targetType)) {
|
|
2346
|
-
propertyNameText =
|
|
2465
|
+
propertyNameText = targetType.value.toString();
|
|
2347
2466
|
}
|
|
2348
2467
|
else {
|
|
2349
2468
|
propertyNameText = `[${this.#compiler.unescapeLeadingUnderscores(targetType.symbol.escapedName)}]`;
|
|
@@ -2367,7 +2486,7 @@ class ToHaveProperty {
|
|
|
2367
2486
|
const targetType = matchWorker.getType(targetNode);
|
|
2368
2487
|
let propertyNameText;
|
|
2369
2488
|
if (matchWorker.isStringOrNumberLiteralType(targetType)) {
|
|
2370
|
-
propertyNameText =
|
|
2489
|
+
propertyNameText = targetType.value.toString();
|
|
2371
2490
|
}
|
|
2372
2491
|
else if (matchWorker.isUniqueSymbolType(targetType)) {
|
|
2373
2492
|
propertyNameText = this.#compiler.unescapeLeadingUnderscores(targetType.escapedName);
|
|
@@ -2473,7 +2592,7 @@ class ToRaiseError {
|
|
|
2473
2592
|
if (this.#compiler.isStringLiteralLike(targetNode)) {
|
|
2474
2593
|
return this.#compiler.flattenDiagnosticMessageText(diagnostic.messageText, " ", 0).includes(targetNode.text);
|
|
2475
2594
|
}
|
|
2476
|
-
return Number(targetNode.text) === diagnostic.code;
|
|
2595
|
+
return Number.parseInt(targetNode.text) === diagnostic.code;
|
|
2477
2596
|
}
|
|
2478
2597
|
}
|
|
2479
2598
|
|
|
@@ -2483,7 +2602,6 @@ class ExpectService {
|
|
|
2483
2602
|
toAcceptProps;
|
|
2484
2603
|
toBe;
|
|
2485
2604
|
toBeAny;
|
|
2486
|
-
toBeAssignable;
|
|
2487
2605
|
toBeAssignableTo;
|
|
2488
2606
|
toBeAssignableWith;
|
|
2489
2607
|
toBeBigInt;
|
|
@@ -2497,7 +2615,6 @@ class ExpectService {
|
|
|
2497
2615
|
toBeUniqueSymbol;
|
|
2498
2616
|
toBeUnknown;
|
|
2499
2617
|
toBeVoid;
|
|
2500
|
-
toEqual;
|
|
2501
2618
|
toHaveProperty;
|
|
2502
2619
|
toMatch;
|
|
2503
2620
|
toRaiseError;
|
|
@@ -2507,7 +2624,6 @@ class ExpectService {
|
|
|
2507
2624
|
this.toAcceptProps = new ToAcceptProps(compiler, typeChecker);
|
|
2508
2625
|
this.toBe = new ToBe();
|
|
2509
2626
|
this.toBeAny = new PrimitiveTypeMatcher(compiler.TypeFlags.Any);
|
|
2510
|
-
this.toBeAssignable = new ToBeAssignableWith();
|
|
2511
2627
|
this.toBeAssignableTo = new ToBeAssignableTo();
|
|
2512
2628
|
this.toBeAssignableWith = new ToBeAssignableWith();
|
|
2513
2629
|
this.toBeBigInt = new PrimitiveTypeMatcher(compiler.TypeFlags.BigInt);
|
|
@@ -2521,28 +2637,12 @@ class ExpectService {
|
|
|
2521
2637
|
this.toBeUniqueSymbol = new PrimitiveTypeMatcher(compiler.TypeFlags.UniqueESSymbol);
|
|
2522
2638
|
this.toBeUnknown = new PrimitiveTypeMatcher(compiler.TypeFlags.Unknown);
|
|
2523
2639
|
this.toBeVoid = new PrimitiveTypeMatcher(compiler.TypeFlags.Void);
|
|
2524
|
-
this.toEqual = new ToBe();
|
|
2525
2640
|
this.toHaveProperty = new ToHaveProperty(compiler);
|
|
2526
2641
|
this.toMatch = new ToMatch();
|
|
2527
2642
|
this.toRaiseError = new ToRaiseError(compiler);
|
|
2528
2643
|
}
|
|
2529
|
-
static assertTypeChecker(typeChecker) {
|
|
2530
|
-
return "isTypeRelatedTo" in typeChecker && "relation" in typeChecker;
|
|
2531
|
-
}
|
|
2532
|
-
#handleDeprecated(matcherNameText, assertion) {
|
|
2533
|
-
switch (matcherNameText) {
|
|
2534
|
-
case "toBeAssignable":
|
|
2535
|
-
case "toEqual": {
|
|
2536
|
-
const text = ExpectDiagnosticText.matcherIsDeprecated(matcherNameText);
|
|
2537
|
-
const origin = DiagnosticOrigin.fromNode(assertion.matcherName);
|
|
2538
|
-
EventEmitter.dispatch(["deprecation:info", { diagnostics: [Diagnostic.warning(text, origin)] }]);
|
|
2539
|
-
break;
|
|
2540
|
-
}
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
2644
|
match(assertion, onDiagnostics) {
|
|
2544
2645
|
const matcherNameText = assertion.matcherName.getText();
|
|
2545
|
-
this.#handleDeprecated(matcherNameText, assertion);
|
|
2546
2646
|
if (!assertion.source[0]) {
|
|
2547
2647
|
this.#onSourceArgumentOrTypeArgumentMustBeProvided(assertion, onDiagnostics);
|
|
2548
2648
|
return;
|
|
@@ -2551,10 +2651,8 @@ class ExpectService {
|
|
|
2551
2651
|
switch (matcherNameText) {
|
|
2552
2652
|
case "toAcceptProps":
|
|
2553
2653
|
case "toBe":
|
|
2554
|
-
case "toBeAssignable":
|
|
2555
2654
|
case "toBeAssignableTo":
|
|
2556
2655
|
case "toBeAssignableWith":
|
|
2557
|
-
case "toEqual":
|
|
2558
2656
|
case "toMatch": {
|
|
2559
2657
|
if (!assertion.target[0]) {
|
|
2560
2658
|
this.#onTargetArgumentOrTypeArgumentMustBeProvided(assertion, onDiagnostics);
|
|
@@ -2611,132 +2709,6 @@ class ExpectService {
|
|
|
2611
2709
|
}
|
|
2612
2710
|
}
|
|
2613
2711
|
|
|
2614
|
-
class Version {
|
|
2615
|
-
static isGreaterThan(source, target) {
|
|
2616
|
-
return !(source === target) && Version.#satisfies(source, target);
|
|
2617
|
-
}
|
|
2618
|
-
static isSatisfiedWith(source, target) {
|
|
2619
|
-
return source === target || Version.#satisfies(source, target);
|
|
2620
|
-
}
|
|
2621
|
-
static isVersionTag(target) {
|
|
2622
|
-
return /^\d+/.test(target);
|
|
2623
|
-
}
|
|
2624
|
-
static #satisfies(source, target) {
|
|
2625
|
-
const sourceElements = source.split(/\.|-/);
|
|
2626
|
-
const targetElements = target.split(/\.|-/);
|
|
2627
|
-
function compare(index = 0) {
|
|
2628
|
-
const sourceElement = sourceElements[index];
|
|
2629
|
-
const targetElement = targetElements[index];
|
|
2630
|
-
if (sourceElement > targetElement) {
|
|
2631
|
-
return true;
|
|
2632
|
-
}
|
|
2633
|
-
if (sourceElement < targetElement) {
|
|
2634
|
-
return false;
|
|
2635
|
-
}
|
|
2636
|
-
if (index === sourceElements.length - 1 || index === targetElements.length - 1) {
|
|
2637
|
-
return true;
|
|
2638
|
-
}
|
|
2639
|
-
return compare(index + 1);
|
|
2640
|
-
}
|
|
2641
|
-
return compare();
|
|
2642
|
-
}
|
|
2643
|
-
}
|
|
2644
|
-
|
|
2645
|
-
class ProjectService {
|
|
2646
|
-
#compiler;
|
|
2647
|
-
#service;
|
|
2648
|
-
constructor(compiler) {
|
|
2649
|
-
this.#compiler = compiler;
|
|
2650
|
-
function doNothing() {
|
|
2651
|
-
}
|
|
2652
|
-
function returnFalse() {
|
|
2653
|
-
return false;
|
|
2654
|
-
}
|
|
2655
|
-
function returnUndefined() {
|
|
2656
|
-
return undefined;
|
|
2657
|
-
}
|
|
2658
|
-
const noopWatcher = { close: doNothing };
|
|
2659
|
-
const noopLogger = {
|
|
2660
|
-
close: doNothing,
|
|
2661
|
-
endGroup: doNothing,
|
|
2662
|
-
getLogFileName: returnUndefined,
|
|
2663
|
-
hasLevel: returnFalse,
|
|
2664
|
-
info: doNothing,
|
|
2665
|
-
loggingEnabled: returnFalse,
|
|
2666
|
-
msg: doNothing,
|
|
2667
|
-
perftrc: doNothing,
|
|
2668
|
-
startGroup: doNothing,
|
|
2669
|
-
};
|
|
2670
|
-
const host = {
|
|
2671
|
-
...this.#compiler.sys,
|
|
2672
|
-
clearImmediate,
|
|
2673
|
-
clearTimeout,
|
|
2674
|
-
setImmediate,
|
|
2675
|
-
setTimeout,
|
|
2676
|
-
watchDirectory: () => noopWatcher,
|
|
2677
|
-
watchFile: () => noopWatcher,
|
|
2678
|
-
};
|
|
2679
|
-
this.#service = new this.#compiler.server.ProjectService({
|
|
2680
|
-
allowLocalPluginLoads: true,
|
|
2681
|
-
cancellationToken: this.#compiler.server.nullCancellationToken,
|
|
2682
|
-
host,
|
|
2683
|
-
logger: noopLogger,
|
|
2684
|
-
session: undefined,
|
|
2685
|
-
useInferredProjectPerProjectRoot: true,
|
|
2686
|
-
useSingleInferredProject: false,
|
|
2687
|
-
});
|
|
2688
|
-
this.#service.setCompilerOptionsForInferredProjects(this.#getDefaultCompilerOptions());
|
|
2689
|
-
}
|
|
2690
|
-
closeFile(filePath) {
|
|
2691
|
-
this.#service.closeClientFile(filePath);
|
|
2692
|
-
}
|
|
2693
|
-
#getDefaultCompilerOptions() {
|
|
2694
|
-
const defaultCompilerOptions = {
|
|
2695
|
-
allowJs: true,
|
|
2696
|
-
checkJs: true,
|
|
2697
|
-
esModuleInterop: true,
|
|
2698
|
-
jsx: "preserve",
|
|
2699
|
-
module: "esnext",
|
|
2700
|
-
moduleResolution: "node",
|
|
2701
|
-
resolveJsonModule: true,
|
|
2702
|
-
strictFunctionTypes: true,
|
|
2703
|
-
strictNullChecks: true,
|
|
2704
|
-
target: "esnext",
|
|
2705
|
-
};
|
|
2706
|
-
if (Version.isSatisfiedWith(this.#compiler.version, "5.4")) {
|
|
2707
|
-
defaultCompilerOptions.module = "preserve";
|
|
2708
|
-
}
|
|
2709
|
-
if (Version.isSatisfiedWith(this.#compiler.version, "5.0")) {
|
|
2710
|
-
defaultCompilerOptions.allowImportingTsExtensions = true;
|
|
2711
|
-
defaultCompilerOptions.moduleResolution = "bundler";
|
|
2712
|
-
}
|
|
2713
|
-
return defaultCompilerOptions;
|
|
2714
|
-
}
|
|
2715
|
-
getDefaultProject(filePath) {
|
|
2716
|
-
return this.#service.getDefaultProjectForFile(this.#compiler.server.toNormalizedPath(filePath), true);
|
|
2717
|
-
}
|
|
2718
|
-
getLanguageService(filePath) {
|
|
2719
|
-
const project = this.getDefaultProject(filePath);
|
|
2720
|
-
if (!project) {
|
|
2721
|
-
return;
|
|
2722
|
-
}
|
|
2723
|
-
return project.getLanguageService(true);
|
|
2724
|
-
}
|
|
2725
|
-
openFile(filePath, sourceText, projectRootPath) {
|
|
2726
|
-
const { configFileErrors, configFileName } = this.#service.openClientFile(filePath, sourceText, undefined, projectRootPath);
|
|
2727
|
-
EventEmitter.dispatch([
|
|
2728
|
-
"project:info",
|
|
2729
|
-
{ compilerVersion: this.#compiler.version, projectConfigFilePath: configFileName },
|
|
2730
|
-
]);
|
|
2731
|
-
if (configFileErrors && configFileErrors.length > 0) {
|
|
2732
|
-
EventEmitter.dispatch([
|
|
2733
|
-
"project:error",
|
|
2734
|
-
{ diagnostics: Diagnostic.fromDiagnostics(configFileErrors, this.#compiler) },
|
|
2735
|
-
]);
|
|
2736
|
-
}
|
|
2737
|
-
}
|
|
2738
|
-
}
|
|
2739
|
-
|
|
2740
2712
|
class TestTreeWorker {
|
|
2741
2713
|
#compiler;
|
|
2742
2714
|
#cancellationToken;
|
|
@@ -2951,11 +2923,6 @@ class TestFileRunner {
|
|
|
2951
2923
|
return;
|
|
2952
2924
|
}
|
|
2953
2925
|
const typeChecker = program.getTypeChecker();
|
|
2954
|
-
if (!ExpectService.assertTypeChecker(typeChecker)) {
|
|
2955
|
-
const text = "The required 'isTypeRelatedTo()' method is missing in the provided type checker.";
|
|
2956
|
-
EventEmitter.dispatch(["file:error", { diagnostics: [Diagnostic.error(text)], result: fileResult }]);
|
|
2957
|
-
return;
|
|
2958
|
-
}
|
|
2959
2926
|
const testTreeWorker = new TestTreeWorker(this.#resolvedConfig, this.#compiler, typeChecker, {
|
|
2960
2927
|
cancellationToken,
|
|
2961
2928
|
fileResult,
|
|
@@ -3003,7 +2970,7 @@ class TaskRunner {
|
|
|
3003
2970
|
for (const versionTag of this.#resolvedConfig.target) {
|
|
3004
2971
|
const targetResult = new TargetResult(versionTag, testFiles);
|
|
3005
2972
|
EventEmitter.dispatch(["target:start", { result: targetResult }]);
|
|
3006
|
-
const compiler = await this.#storeService.load(versionTag
|
|
2973
|
+
const compiler = await this.#storeService.load(versionTag);
|
|
3007
2974
|
if (compiler) {
|
|
3008
2975
|
const testFileRunner = new TestFileRunner(this.#resolvedConfig, compiler);
|
|
3009
2976
|
for (const testFile of testFiles) {
|
|
@@ -3032,7 +2999,7 @@ class TSTyche {
|
|
|
3032
2999
|
#selectService;
|
|
3033
3000
|
#storeService;
|
|
3034
3001
|
#taskRunner;
|
|
3035
|
-
static version = "
|
|
3002
|
+
static version = "3.0.0-beta.0";
|
|
3036
3003
|
constructor(resolvedConfig, outputService, selectService, storeService) {
|
|
3037
3004
|
this.#resolvedConfig = resolvedConfig;
|
|
3038
3005
|
this.#outputService = outputService;
|
|
@@ -3612,32 +3579,124 @@ var OptionGroup;
|
|
|
3612
3579
|
})(OptionGroup || (OptionGroup = {}));
|
|
3613
3580
|
|
|
3614
3581
|
class StoreDiagnosticText {
|
|
3615
|
-
static
|
|
3616
|
-
return `
|
|
3582
|
+
static cannotAddTypeScriptPackage(tag) {
|
|
3583
|
+
return `Cannot add the 'typescript' package for the '${tag}' tag.`;
|
|
3584
|
+
}
|
|
3585
|
+
static failedToFetchMetadata(registry) {
|
|
3586
|
+
return `Failed to fetch metadata of the 'typescript' package from '${registry}'.`;
|
|
3617
3587
|
}
|
|
3618
|
-
static
|
|
3619
|
-
return `
|
|
3588
|
+
static failedToInstalTypeScript(version) {
|
|
3589
|
+
return `Failed to install 'typescript@${version}'.`;
|
|
3590
|
+
}
|
|
3591
|
+
static failedToUpdateMetadata(registry) {
|
|
3592
|
+
return `Failed to update metadata of the 'typescript' package from '${registry}'.`;
|
|
3620
3593
|
}
|
|
3621
3594
|
static maybeNetworkConnectionIssue() {
|
|
3622
3595
|
return "Might be there is an issue with the registry or the network connection.";
|
|
3623
3596
|
}
|
|
3624
|
-
static
|
|
3625
|
-
return `
|
|
3597
|
+
static maybeOutdatedResolution(tag) {
|
|
3598
|
+
return `The resolution of the '${tag}' tag may be outdated.`;
|
|
3599
|
+
}
|
|
3600
|
+
static requestFailedWithStatusCode(code) {
|
|
3601
|
+
return `The request failed with status code ${code}.`;
|
|
3602
|
+
}
|
|
3603
|
+
static requestTimeoutWasExceeded(timeout) {
|
|
3604
|
+
return `The request timeout of ${timeout / 1000}s was exceeded.`;
|
|
3605
|
+
}
|
|
3606
|
+
static lockWaitTimeoutWasExceeded(timeout) {
|
|
3607
|
+
return `Lock wait timeout of ${timeout / 1000}s was exceeded.`;
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
|
|
3611
|
+
class Fetcher {
|
|
3612
|
+
#onDiagnostics;
|
|
3613
|
+
constructor(onDiagnostics) {
|
|
3614
|
+
this.#onDiagnostics = onDiagnostics;
|
|
3615
|
+
}
|
|
3616
|
+
async get(request, timeout, diagnostic, options) {
|
|
3617
|
+
try {
|
|
3618
|
+
const response = await fetch(request, { signal: AbortSignal.timeout(timeout) });
|
|
3619
|
+
if (!response.ok) {
|
|
3620
|
+
!options?.suppressErrors &&
|
|
3621
|
+
this.#onDiagnostics(diagnostic.extendWith(StoreDiagnosticText.requestFailedWithStatusCode(response.status)));
|
|
3622
|
+
return;
|
|
3623
|
+
}
|
|
3624
|
+
return response;
|
|
3625
|
+
}
|
|
3626
|
+
catch (error) {
|
|
3627
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
3628
|
+
!options?.suppressErrors &&
|
|
3629
|
+
this.#onDiagnostics(diagnostic.extendWith(StoreDiagnosticText.requestTimeoutWasExceeded(timeout)));
|
|
3630
|
+
}
|
|
3631
|
+
else {
|
|
3632
|
+
!options?.suppressErrors &&
|
|
3633
|
+
this.#onDiagnostics(diagnostic.extendWith(StoreDiagnosticText.maybeNetworkConnectionIssue()));
|
|
3634
|
+
}
|
|
3635
|
+
}
|
|
3636
|
+
return;
|
|
3637
|
+
}
|
|
3638
|
+
}
|
|
3639
|
+
|
|
3640
|
+
class Lock {
|
|
3641
|
+
#lockFilePath;
|
|
3642
|
+
constructor(lockFilePath) {
|
|
3643
|
+
this.#lockFilePath = lockFilePath;
|
|
3644
|
+
writeFileSync(this.#lockFilePath, "");
|
|
3645
|
+
process.on("exit", () => {
|
|
3646
|
+
this.release();
|
|
3647
|
+
});
|
|
3648
|
+
}
|
|
3649
|
+
release() {
|
|
3650
|
+
rmSync(this.#lockFilePath, { force: true });
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
class LockService {
|
|
3655
|
+
#onDiagnostics;
|
|
3656
|
+
constructor(onDiagnostics) {
|
|
3657
|
+
this.#onDiagnostics = onDiagnostics;
|
|
3658
|
+
}
|
|
3659
|
+
#getLockFilePath(targetPath) {
|
|
3660
|
+
return `${targetPath}__lock__`;
|
|
3661
|
+
}
|
|
3662
|
+
getLock(targetPath) {
|
|
3663
|
+
const lockFilePath = this.#getLockFilePath(targetPath);
|
|
3664
|
+
return new Lock(lockFilePath);
|
|
3665
|
+
}
|
|
3666
|
+
async isLocked(targetPath, timeout, diagnostic) {
|
|
3667
|
+
const lockFilePath = this.#getLockFilePath(targetPath);
|
|
3668
|
+
let isLocked = existsSync(lockFilePath);
|
|
3669
|
+
if (!isLocked) {
|
|
3670
|
+
return isLocked;
|
|
3671
|
+
}
|
|
3672
|
+
const waitStartTime = Date.now();
|
|
3673
|
+
while (isLocked) {
|
|
3674
|
+
if (Date.now() - waitStartTime > timeout) {
|
|
3675
|
+
this.#onDiagnostics(diagnostic.extendWith(StoreDiagnosticText.lockWaitTimeoutWasExceeded(timeout)));
|
|
3676
|
+
break;
|
|
3677
|
+
}
|
|
3678
|
+
await this.#sleep(1000);
|
|
3679
|
+
isLocked = existsSync(lockFilePath);
|
|
3680
|
+
}
|
|
3681
|
+
return isLocked;
|
|
3682
|
+
}
|
|
3683
|
+
async #sleep(delay) {
|
|
3684
|
+
return new Promise((resolve) => setTimeout(resolve, delay));
|
|
3626
3685
|
}
|
|
3627
3686
|
}
|
|
3628
3687
|
|
|
3629
3688
|
class ManifestWorker {
|
|
3630
|
-
#
|
|
3689
|
+
#fetcher;
|
|
3631
3690
|
#manifestFilePath;
|
|
3632
|
-
#
|
|
3633
|
-
#registryUrl = new URL("https://registry.npmjs.org");
|
|
3691
|
+
#npmRegistry;
|
|
3634
3692
|
#storePath;
|
|
3635
3693
|
#timeout = Environment.timeout * 1000;
|
|
3636
|
-
#version = "
|
|
3637
|
-
constructor(storePath,
|
|
3694
|
+
#version = "2";
|
|
3695
|
+
constructor(storePath, npmRegistry, fetcher) {
|
|
3638
3696
|
this.#storePath = storePath;
|
|
3639
|
-
this.#
|
|
3640
|
-
this.#
|
|
3697
|
+
this.#npmRegistry = npmRegistry;
|
|
3698
|
+
this.#fetcher = fetcher;
|
|
3699
|
+
this.#manifestFilePath = Path.join(storePath, "store-manifest.json");
|
|
3641
3700
|
}
|
|
3642
3701
|
async #create() {
|
|
3643
3702
|
const manifest = await this.#load();
|
|
@@ -3653,59 +3712,48 @@ class ManifestWorker {
|
|
|
3653
3712
|
return false;
|
|
3654
3713
|
}
|
|
3655
3714
|
async #load(options) {
|
|
3715
|
+
const diagnostic = Diagnostic.error(StoreDiagnosticText.failedToFetchMetadata(this.#npmRegistry));
|
|
3716
|
+
const request = new Request(new URL("typescript", this.#npmRegistry), {
|
|
3717
|
+
headers: {
|
|
3718
|
+
["Accept"]: "application/vnd.npm.install-v1+json;q=1.0, application/json;q=0.8, */*",
|
|
3719
|
+
},
|
|
3720
|
+
});
|
|
3721
|
+
const response = await this.#fetcher.get(request, this.#timeout, diagnostic, {
|
|
3722
|
+
suppressErrors: options?.suppressErrors,
|
|
3723
|
+
});
|
|
3724
|
+
if (!response) {
|
|
3725
|
+
return;
|
|
3726
|
+
}
|
|
3656
3727
|
const manifest = {
|
|
3657
3728
|
$version: this.#version,
|
|
3658
3729
|
lastUpdated: Date.now(),
|
|
3730
|
+
npmRegistry: this.#npmRegistry,
|
|
3659
3731
|
resolutions: {},
|
|
3732
|
+
packages: {},
|
|
3660
3733
|
versions: [],
|
|
3661
3734
|
};
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
});
|
|
3668
|
-
if (!response.ok) {
|
|
3669
|
-
this.#onDiagnostics(Diagnostic.error([
|
|
3670
|
-
StoreDiagnosticText.failedToFetchMetadata(this.#registryUrl),
|
|
3671
|
-
StoreDiagnosticText.failedWithStatusCode(response.status),
|
|
3672
|
-
]));
|
|
3673
|
-
return;
|
|
3735
|
+
const packageMetadata = (await response.json());
|
|
3736
|
+
for (const [tag, meta] of Object.entries(packageMetadata.versions)) {
|
|
3737
|
+
if (/^(4|5)\.\d\.\d$/.test(tag)) {
|
|
3738
|
+
manifest.versions.push(tag);
|
|
3739
|
+
manifest.packages[tag] = { integrity: meta.dist.integrity, tarball: meta.dist.tarball };
|
|
3674
3740
|
}
|
|
3675
|
-
packageMetadata = (await response.json());
|
|
3676
3741
|
}
|
|
3677
|
-
catch (error) {
|
|
3678
|
-
if (options?.quite === true) {
|
|
3679
|
-
return;
|
|
3680
|
-
}
|
|
3681
|
-
if (error instanceof Error && error.name === "TimeoutError") {
|
|
3682
|
-
this.#onDiagnostics(Diagnostic.error([
|
|
3683
|
-
StoreDiagnosticText.failedToFetchMetadata(this.#registryUrl),
|
|
3684
|
-
StoreDiagnosticText.setupTimeoutExceeded(this.#timeout),
|
|
3685
|
-
]));
|
|
3686
|
-
}
|
|
3687
|
-
else {
|
|
3688
|
-
this.#onDiagnostics(Diagnostic.error([
|
|
3689
|
-
StoreDiagnosticText.failedToFetchMetadata(this.#registryUrl),
|
|
3690
|
-
StoreDiagnosticText.maybeNetworkConnectionIssue(),
|
|
3691
|
-
]));
|
|
3692
|
-
}
|
|
3693
|
-
return;
|
|
3694
|
-
}
|
|
3695
|
-
manifest.versions = Object.keys(packageMetadata.versions)
|
|
3696
|
-
.filter((version) => /^(4|5)\.\d\.\d$/.test(version))
|
|
3697
|
-
.sort();
|
|
3698
3742
|
const minorVersions = [...new Set(manifest.versions.map((version) => version.slice(0, -2)))];
|
|
3699
3743
|
for (const tag of minorVersions) {
|
|
3700
|
-
const resolvedVersion = manifest.versions.
|
|
3744
|
+
const resolvedVersion = manifest.versions.findLast((version) => version.startsWith(tag));
|
|
3701
3745
|
if (resolvedVersion != null) {
|
|
3702
3746
|
manifest.resolutions[tag] = resolvedVersion;
|
|
3703
3747
|
}
|
|
3704
3748
|
}
|
|
3705
|
-
for (const
|
|
3706
|
-
const
|
|
3707
|
-
if (
|
|
3708
|
-
manifest.resolutions[
|
|
3749
|
+
for (const tag of ["beta", "latest", "next", "rc"]) {
|
|
3750
|
+
const version = packageMetadata["dist-tags"][tag];
|
|
3751
|
+
if (version != null) {
|
|
3752
|
+
manifest.resolutions[tag] = version;
|
|
3753
|
+
const meta = packageMetadata.versions[version];
|
|
3754
|
+
if (meta != null) {
|
|
3755
|
+
manifest.packages[version] = { integrity: meta.dist.integrity, tarball: meta.dist.tarball };
|
|
3756
|
+
}
|
|
3709
3757
|
}
|
|
3710
3758
|
}
|
|
3711
3759
|
return manifest;
|
|
@@ -3715,28 +3763,18 @@ class ManifestWorker {
|
|
|
3715
3763
|
if (!existsSync(this.#manifestFilePath)) {
|
|
3716
3764
|
return this.#create();
|
|
3717
3765
|
}
|
|
3718
|
-
|
|
3719
|
-
try {
|
|
3720
|
-
manifestText = await fs.readFile(this.#manifestFilePath, { encoding: "utf8" });
|
|
3721
|
-
}
|
|
3722
|
-
catch (error) {
|
|
3723
|
-
this.#onDiagnostics(Diagnostic.fromError("Failed to open store manifest.", error));
|
|
3724
|
-
}
|
|
3725
|
-
if (!manifestText) {
|
|
3726
|
-
return;
|
|
3727
|
-
}
|
|
3766
|
+
const manifestText = await fs.readFile(this.#manifestFilePath, { encoding: "utf8" });
|
|
3728
3767
|
try {
|
|
3729
3768
|
manifest = JSON.parse(manifestText);
|
|
3730
3769
|
}
|
|
3731
3770
|
catch {
|
|
3732
3771
|
}
|
|
3733
|
-
if (!manifest || manifest.$version !== this.#version) {
|
|
3772
|
+
if (!manifest || manifest.$version !== this.#version || manifest.npmRegistry !== this.#npmRegistry) {
|
|
3734
3773
|
await fs.rm(this.#storePath, { force: true, recursive: true });
|
|
3735
3774
|
return this.#create();
|
|
3736
3775
|
}
|
|
3737
3776
|
if (this.isOutdated(manifest) || options?.refresh === true) {
|
|
3738
|
-
const
|
|
3739
|
-
const freshManifest = await this.#load({ quite });
|
|
3777
|
+
const freshManifest = await this.#load({ suppressErrors: !options?.refresh });
|
|
3740
3778
|
if (freshManifest != null) {
|
|
3741
3779
|
await this.persist(freshManifest);
|
|
3742
3780
|
return freshManifest;
|
|
@@ -3752,136 +3790,106 @@ class ManifestWorker {
|
|
|
3752
3790
|
}
|
|
3753
3791
|
}
|
|
3754
3792
|
|
|
3755
|
-
class
|
|
3756
|
-
#
|
|
3757
|
-
static
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
});
|
|
3764
|
-
}
|
|
3765
|
-
static #getLockFilePath(targetPath) {
|
|
3766
|
-
return `${targetPath}${Lock.#lockSuffix}`;
|
|
3767
|
-
}
|
|
3768
|
-
static async isLocked(targetPath, options) {
|
|
3769
|
-
let isLocked = existsSync(Lock.#getLockFilePath(targetPath));
|
|
3770
|
-
if (!isLocked) {
|
|
3771
|
-
return isLocked;
|
|
3772
|
-
}
|
|
3773
|
-
if (!options?.timeout) {
|
|
3774
|
-
return isLocked;
|
|
3775
|
-
}
|
|
3776
|
-
const waitStartTime = Date.now();
|
|
3777
|
-
while (isLocked) {
|
|
3778
|
-
if (options.cancellationToken?.isCancellationRequested === true) {
|
|
3793
|
+
class TarReader {
|
|
3794
|
+
static #textDecoder = new TextDecoder();
|
|
3795
|
+
static async *extract(stream) {
|
|
3796
|
+
const buffer = await streamConsumers.arrayBuffer(stream);
|
|
3797
|
+
let offset = 0;
|
|
3798
|
+
while (offset < buffer.byteLength - 512) {
|
|
3799
|
+
const name = TarReader.#read(buffer, offset, 100);
|
|
3800
|
+
if (name.length === 0) {
|
|
3779
3801
|
break;
|
|
3780
3802
|
}
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3803
|
+
const size = Number.parseInt(TarReader.#read(buffer, offset + 124, 12), 8);
|
|
3804
|
+
const contents = new Uint8Array(buffer, offset + 512, size);
|
|
3805
|
+
yield { name, contents };
|
|
3806
|
+
offset += 512 + 512 * Math.trunc(size / 512);
|
|
3807
|
+
if (size % 512) {
|
|
3808
|
+
offset += 512;
|
|
3784
3809
|
}
|
|
3785
|
-
await Lock.#sleep(1000);
|
|
3786
|
-
isLocked = existsSync(Lock.#getLockFilePath(targetPath));
|
|
3787
3810
|
}
|
|
3788
|
-
return isLocked;
|
|
3789
3811
|
}
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3812
|
+
static #read(buffer, byteOffset, length) {
|
|
3813
|
+
let view = new Uint8Array(buffer, byteOffset, length);
|
|
3814
|
+
const zeroIndex = view.indexOf(0);
|
|
3815
|
+
if (zeroIndex !== -1) {
|
|
3816
|
+
view = view.subarray(0, zeroIndex);
|
|
3817
|
+
}
|
|
3818
|
+
return TarReader.#textDecoder.decode(view);
|
|
3795
3819
|
}
|
|
3796
3820
|
}
|
|
3797
3821
|
|
|
3798
|
-
class
|
|
3799
|
-
#
|
|
3800
|
-
#
|
|
3822
|
+
class PackageService {
|
|
3823
|
+
#fetcher;
|
|
3824
|
+
#lockService;
|
|
3801
3825
|
#storePath;
|
|
3802
3826
|
#timeout = Environment.timeout * 1000;
|
|
3803
|
-
constructor(storePath,
|
|
3827
|
+
constructor(storePath, fetcher, lockService) {
|
|
3804
3828
|
this.#storePath = storePath;
|
|
3805
|
-
this.#
|
|
3829
|
+
this.#fetcher = fetcher;
|
|
3830
|
+
this.#lockService = lockService;
|
|
3806
3831
|
}
|
|
3807
|
-
async ensure(
|
|
3808
|
-
const
|
|
3809
|
-
const readyFilePath = Path.join(
|
|
3810
|
-
const modulePath = Path.join(
|
|
3832
|
+
async ensure(packageVersion, manifest) {
|
|
3833
|
+
const packagePath = Path.join(this.#storePath, `typescript@${packageVersion}`);
|
|
3834
|
+
const readyFilePath = Path.join(packagePath, "__ready__");
|
|
3835
|
+
const modulePath = Path.join(packagePath, "lib", "typescript.js");
|
|
3811
3836
|
if (existsSync(readyFilePath)) {
|
|
3812
3837
|
return modulePath;
|
|
3813
3838
|
}
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
onDiagnostics: (text) => {
|
|
3817
|
-
this.#onDiagnostics(Diagnostic.error([`Failed to install 'typescript@${compilerVersion}'.`, text]));
|
|
3818
|
-
},
|
|
3819
|
-
timeout: this.#timeout,
|
|
3820
|
-
})) {
|
|
3839
|
+
const diagnostic = Diagnostic.error(StoreDiagnosticText.failedToInstalTypeScript(packageVersion));
|
|
3840
|
+
if (await this.#lockService.isLocked(packagePath, this.#timeout, diagnostic)) {
|
|
3821
3841
|
return;
|
|
3822
3842
|
}
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
typescript: compilerVersion,
|
|
3835
|
-
},
|
|
3836
|
-
};
|
|
3837
|
-
await fs.writeFile(Path.join(installationPath, "package.json"), JSON.stringify(packageJson, null, 2));
|
|
3838
|
-
await this.#install(installationPath);
|
|
3839
|
-
await fs.writeFile(readyFilePath, "");
|
|
3843
|
+
EventEmitter.dispatch(["store:info", { packagePath, packageVersion }]);
|
|
3844
|
+
const resource = manifest.packages[packageVersion];
|
|
3845
|
+
if (resource != null) {
|
|
3846
|
+
const lock = this.#lockService.getLock(packagePath);
|
|
3847
|
+
try {
|
|
3848
|
+
await this.#add(packagePath, resource, diagnostic);
|
|
3849
|
+
await fs.writeFile(readyFilePath, "");
|
|
3850
|
+
}
|
|
3851
|
+
finally {
|
|
3852
|
+
lock.release();
|
|
3853
|
+
}
|
|
3840
3854
|
return modulePath;
|
|
3841
3855
|
}
|
|
3842
|
-
catch (error) {
|
|
3843
|
-
this.#onDiagnostics(Diagnostic.fromError(`Failed to install 'typescript@${compilerVersion}'.`, error));
|
|
3844
|
-
}
|
|
3845
|
-
finally {
|
|
3846
|
-
lock.release();
|
|
3847
|
-
}
|
|
3848
3856
|
return;
|
|
3849
3857
|
}
|
|
3850
|
-
async #
|
|
3851
|
-
const
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
});
|
|
3859
|
-
spawnedNpm.on("error", (error) => {
|
|
3860
|
-
reject(error);
|
|
3861
|
-
});
|
|
3862
|
-
spawnedNpm.on("close", (code, signal) => {
|
|
3863
|
-
if (code === 0) {
|
|
3864
|
-
resolve();
|
|
3858
|
+
async #add(targetPath, resource, diagnostic) {
|
|
3859
|
+
const request = new Request(resource.tarball, { integrity: resource.integrity });
|
|
3860
|
+
const response = await this.#fetcher.get(request, this.#timeout, diagnostic);
|
|
3861
|
+
if (response?.body != null) {
|
|
3862
|
+
const decompressedStream = response.body.pipeThrough(new DecompressionStream("gzip"));
|
|
3863
|
+
for await (const file of TarReader.extract(decompressedStream)) {
|
|
3864
|
+
if (!file.name.startsWith("package/")) {
|
|
3865
|
+
continue;
|
|
3865
3866
|
}
|
|
3866
|
-
|
|
3867
|
-
|
|
3867
|
+
const filePath = Path.join(targetPath, file.name.replace("package/", ""));
|
|
3868
|
+
const directoryPath = Path.dirname(filePath);
|
|
3869
|
+
if (!existsSync(directoryPath)) {
|
|
3870
|
+
await fs.mkdir(directoryPath, { recursive: true });
|
|
3868
3871
|
}
|
|
3869
|
-
|
|
3870
|
-
}
|
|
3871
|
-
}
|
|
3872
|
+
await fs.writeFile(filePath, file.contents);
|
|
3873
|
+
}
|
|
3874
|
+
}
|
|
3872
3875
|
}
|
|
3873
3876
|
}
|
|
3874
3877
|
|
|
3875
3878
|
class StoreService {
|
|
3876
3879
|
#compilerInstanceCache = new Map();
|
|
3880
|
+
#fetcher;
|
|
3881
|
+
#lockService;
|
|
3877
3882
|
#manifest;
|
|
3878
3883
|
#manifestWorker;
|
|
3879
|
-
#
|
|
3884
|
+
#packageService;
|
|
3885
|
+
#npmRegistry = Environment.npmRegistry;
|
|
3880
3886
|
#storePath;
|
|
3881
3887
|
constructor() {
|
|
3882
3888
|
this.#storePath = Environment.storePath;
|
|
3883
|
-
this.#
|
|
3884
|
-
this.#
|
|
3889
|
+
this.#fetcher = new Fetcher(this.#onDiagnostics);
|
|
3890
|
+
this.#lockService = new LockService(this.#onDiagnostics);
|
|
3891
|
+
this.#packageService = new PackageService(this.#storePath, this.#fetcher, this.#lockService);
|
|
3892
|
+
this.#manifestWorker = new ManifestWorker(this.#storePath, this.#npmRegistry, this.#fetcher);
|
|
3885
3893
|
}
|
|
3886
3894
|
async getSupportedTags() {
|
|
3887
3895
|
await this.open();
|
|
@@ -3890,18 +3898,22 @@ class StoreService {
|
|
|
3890
3898
|
}
|
|
3891
3899
|
return [...Object.keys(this.#manifest.resolutions), ...this.#manifest.versions, "current"].sort();
|
|
3892
3900
|
}
|
|
3893
|
-
async install(tag
|
|
3901
|
+
async install(tag) {
|
|
3894
3902
|
if (tag === "current") {
|
|
3895
3903
|
return;
|
|
3896
3904
|
}
|
|
3897
|
-
|
|
3905
|
+
await this.open();
|
|
3906
|
+
if (!this.#manifest) {
|
|
3907
|
+
return;
|
|
3908
|
+
}
|
|
3909
|
+
const version = this.#resolveTag(tag, this.#manifest);
|
|
3898
3910
|
if (!version) {
|
|
3899
|
-
this.#onDiagnostics(Diagnostic.error(
|
|
3911
|
+
this.#onDiagnostics(Diagnostic.error(StoreDiagnosticText.cannotAddTypeScriptPackage(tag)));
|
|
3900
3912
|
return;
|
|
3901
3913
|
}
|
|
3902
|
-
return this.#
|
|
3914
|
+
return this.#packageService.ensure(version, this.#manifest);
|
|
3903
3915
|
}
|
|
3904
|
-
async load(tag
|
|
3916
|
+
async load(tag) {
|
|
3905
3917
|
let compilerInstance = this.#compilerInstanceCache.get(tag);
|
|
3906
3918
|
if (compilerInstance != null) {
|
|
3907
3919
|
return compilerInstance;
|
|
@@ -3911,16 +3923,20 @@ class StoreService {
|
|
|
3911
3923
|
modulePath = Environment.typescriptPath;
|
|
3912
3924
|
}
|
|
3913
3925
|
else {
|
|
3914
|
-
|
|
3926
|
+
await this.open();
|
|
3927
|
+
if (!this.#manifest) {
|
|
3928
|
+
return;
|
|
3929
|
+
}
|
|
3930
|
+
const version = this.#resolveTag(tag, this.#manifest);
|
|
3915
3931
|
if (!version) {
|
|
3916
|
-
this.#onDiagnostics(Diagnostic.error(
|
|
3932
|
+
this.#onDiagnostics(Diagnostic.error(StoreDiagnosticText.cannotAddTypeScriptPackage(tag)));
|
|
3917
3933
|
return;
|
|
3918
3934
|
}
|
|
3919
3935
|
compilerInstance = this.#compilerInstanceCache.get(version);
|
|
3920
3936
|
if (compilerInstance != null) {
|
|
3921
3937
|
return compilerInstance;
|
|
3922
3938
|
}
|
|
3923
|
-
modulePath = await this.#
|
|
3939
|
+
modulePath = await this.#packageService.ensure(version, this.#manifest);
|
|
3924
3940
|
}
|
|
3925
3941
|
if (modulePath != null) {
|
|
3926
3942
|
compilerInstance = await this.#loadModule(modulePath);
|
|
@@ -3939,6 +3955,7 @@ class StoreService {
|
|
|
3939
3955
|
continue;
|
|
3940
3956
|
}
|
|
3941
3957
|
const toExpose = [
|
|
3958
|
+
"getTypeOfSymbol",
|
|
3942
3959
|
"isTypeRelatedTo",
|
|
3943
3960
|
"relation: { assignable: assignableRelation, identity: identityRelation, subtype: strictSubtypeRelation }",
|
|
3944
3961
|
];
|
|
@@ -3958,15 +3975,11 @@ class StoreService {
|
|
|
3958
3975
|
}
|
|
3959
3976
|
this.#manifest = await this.#manifestWorker.open();
|
|
3960
3977
|
}
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
if (!this.#manifest) {
|
|
3964
|
-
return;
|
|
3965
|
-
}
|
|
3966
|
-
if (this.#manifest.versions.includes(tag)) {
|
|
3978
|
+
#resolveTag(tag, manifest) {
|
|
3979
|
+
if (manifest.versions.includes(tag)) {
|
|
3967
3980
|
return tag;
|
|
3968
3981
|
}
|
|
3969
|
-
return
|
|
3982
|
+
return manifest.resolutions[tag];
|
|
3970
3983
|
}
|
|
3971
3984
|
async update() {
|
|
3972
3985
|
await this.#manifestWorker.open({ refresh: true });
|
|
@@ -3984,8 +3997,8 @@ class StoreService {
|
|
|
3984
3997
|
(this.#manifest.resolutions["latest"] != null &&
|
|
3985
3998
|
Version.isGreaterThan(tag, this.#manifest.resolutions["latest"])))) {
|
|
3986
3999
|
this.#onDiagnostics(Diagnostic.warning([
|
|
3987
|
-
|
|
3988
|
-
|
|
4000
|
+
StoreDiagnosticText.failedToUpdateMetadata(this.#npmRegistry),
|
|
4001
|
+
StoreDiagnosticText.maybeOutdatedResolution(tag),
|
|
3989
4002
|
]));
|
|
3990
4003
|
}
|
|
3991
4004
|
return tag in this.#manifest.resolutions || this.#manifest.versions.includes(tag);
|
|
@@ -4049,6 +4062,7 @@ class Cli {
|
|
|
4049
4062
|
this.#outputService.writeMessage(formattedText({
|
|
4050
4063
|
noColor: Environment.noColor,
|
|
4051
4064
|
noInteractive: Environment.noInteractive,
|
|
4065
|
+
npmRegistry: Environment.npmRegistry,
|
|
4052
4066
|
storePath: Environment.storePath,
|
|
4053
4067
|
timeout: Environment.timeout,
|
|
4054
4068
|
typescriptPath: Environment.typescriptPath,
|