From 5f40e87aba0ede4d3439b5816c36b00cdac02e5f Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Wed, 23 Jul 2025 10:05:51 -0700 Subject: [PATCH 01/18] test runner --- internal/execute/tsctestrunner_test.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/internal/execute/tsctestrunner_test.go b/internal/execute/tsctestrunner_test.go index 1e04a68231..69c303c660 100644 --- a/internal/execute/tsctestrunner_test.go +++ b/internal/execute/tsctestrunner_test.go @@ -161,13 +161,21 @@ func getDiffForIncremental(incrementalSys *testSys, nonIncrementalSys *testSys) func (test *tscInput) getBaselineSubFolder() string { commandName := "tsc" if slices.ContainsFunc(test.commandLineArgs, func(arg string) bool { - return arg == "--build" || arg == "-b" + switch arg { + case "-b", "--b", "-build", "--build": + return true + } + return false }) { commandName = "tsbuild" } w := "" if slices.ContainsFunc(test.commandLineArgs, func(arg string) bool { - return arg == "--watch" || arg == "-w" + switch arg { + case "-w", "--w", "-watch", "--watch": + return true + } + return false }) { w = "Watch" } From 924fe0409c46cfd3d8b547c68b6a846021db837d Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 19:50:58 -0700 Subject: [PATCH 02/18] write config name when writing incremental program info --- internal/execute/testsys_test.go | 9 ++++++++- internal/incremental/program.go | 2 ++ ...ression-field-with-declaration-emit-enabled.js | 6 ++++++ ...hange-to-modifier-of-class-expression-field.js | 6 ++++++ ...ort-in-another-file-through-indirect-import.js | 2 ++ ...ed-as-global-through-export-in-another-file.js | 2 ++ .../incremental/generates-typerefs-correctly.js | 2 ++ .../incremental/option-changes-with-composite.js | 15 +++++++++++++++ .../option-changes-with-incremental.js | 14 ++++++++++++++ ...ing-types-found-doesnt-crash-under---strict.js | 1 + ...de-with-no-backing-types-found-doesnt-crash.js | 1 + .../incremental/serializing-composite-project.js | 1 + .../tsc/incremental/serializing-error-chain.js | 2 ++ .../tsc/incremental/tsbuildinfo-has-error.js | 2 ++ .../tsc/incremental/when-file-is-deleted.js | 2 ++ ...l-file-is-added,-the-signatures-are-updated.js | 7 +++++++ ...ssing-filename-for-buildinfo-on-commandline.js | 2 ++ .../when-passing-rootDir-from-commandline.js | 2 ++ .../when-passing-rootDir-is-in-the-tsconfig.js | 2 ++ .../tsc/incremental/with-only-dts-files.js | 3 +++ .../tsc/noEmit/when-project-has-strict-true.js | 1 + ...eRelativeImportExtensionsProjectReferences2.js | 1 + ...eRelativeImportExtensionsProjectReferences3.js | 1 + .../parse-tsconfig-with-typeAcquisition.js | 1 + .../commandLine/Parse-watch-interval-option.js | 1 + .../watch-with-tsconfig-and-incremental.js | 1 + .../noEmit/dts-errors-without-dts-enabled.js | 7 +++++++ .../reference/tscWatch/noEmit/dts-errors.js | 7 +++++++ .../reference/tscWatch/noEmit/semantic-errors.js | 7 +++++++ .../reference/tscWatch/noEmit/syntax-errors.js | 7 +++++++ 30 files changed, 116 insertions(+), 1 deletion(-) diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index 8bba8ff082..320fff4280 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -19,6 +19,7 @@ import ( "github.com/microsoft/typescript-go/internal/testutil/incrementaltestutil" "github.com/microsoft/typescript-go/internal/testutil/stringtestutil" "github.com/microsoft/typescript-go/internal/tsoptions" + "github.com/microsoft/typescript-go/internal/tspath" "github.com/microsoft/typescript-go/internal/vfs" "github.com/microsoft/typescript-go/internal/vfs/vfstest" ) @@ -199,8 +200,14 @@ func (s *testSys) baselineProgram(baseline *strings.Builder, program *incrementa return } - baseline.WriteString("SemanticDiagnostics::\n") testingData := program.GetTestingData(program.GetProgram()) + if testingData.ConfigFilePath != "" { + baseline.WriteString(tspath.GetRelativePathFromDirectory(s.cwd, testingData.ConfigFilePath, tspath.ComparePathsOptions{ + UseCaseSensitiveFileNames: s.FS().UseCaseSensitiveFileNames(), + CurrentDirectory: s.GetCurrentDirectory(), + }) + "::\n") + } + baseline.WriteString("SemanticDiagnostics::\n") for _, file := range program.GetProgram().GetSourceFiles() { if diagnostics, ok := testingData.SemanticDiagnosticsPerFile.Load(file.Path()); ok { if oldDiagnostics, ok := testingData.OldProgramSemanticDiagnosticsPerFile.Load(file.Path()); !ok || oldDiagnostics != diagnostics { diff --git a/internal/incremental/program.go b/internal/incremental/program.go index 8750c214e6..362cea8a3c 100644 --- a/internal/incremental/program.go +++ b/internal/incremental/program.go @@ -53,6 +53,7 @@ type TestingData struct { SemanticDiagnosticsPerFile *collections.SyncMap[tspath.Path, *diagnosticsOrBuildInfoDiagnosticsWithFileName] OldProgramSemanticDiagnosticsPerFile *collections.SyncMap[tspath.Path, *diagnosticsOrBuildInfoDiagnosticsWithFileName] UpdatedSignatureKinds map[tspath.Path]SignatureUpdateKind + ConfigFilePath string } func (p *Program) GetTestingData(program *compiler.Program) TestingData { @@ -60,6 +61,7 @@ func (p *Program) GetTestingData(program *compiler.Program) TestingData { SemanticDiagnosticsPerFile: &p.snapshot.semanticDiagnosticsPerFile, OldProgramSemanticDiagnosticsPerFile: p.semanticDiagnosticsPerFile, UpdatedSignatureKinds: p.updatedSignatureKinds, + ConfigFilePath: p.snapshot.options.ConfigFilePath, } } diff --git a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js index b06f24a4fe..d3f3690594 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js @@ -141,6 +141,7 @@ export {}; "size": 2019 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/MessageablePerson.ts @@ -156,6 +157,7 @@ tsgo --incremental ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -299,6 +301,7 @@ Errors Files "size": 2702 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/MessageablePerson.ts *refresh* /home/src/workspaces/project/main.ts @@ -336,6 +339,7 @@ Errors Files //// [/home/src/workspaces/project/tsconfig.tsbuildinfo] *rewrite with same content* //// [/home/src/workspaces/project/tsconfig.tsbuildinfo.readable.baseline.txt] *rewrite with same content* +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -421,6 +425,7 @@ Output:: "size": 2019 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/MessageablePerson.ts *refresh* /home/src/workspaces/project/main.ts @@ -435,5 +440,6 @@ tsgo --incremental ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js index de5b5b24a4..44cd75b955 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js @@ -117,6 +117,7 @@ export {}; "size": 1636 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/MessageablePerson.ts @@ -130,6 +131,7 @@ tsgo --incremental ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -234,6 +236,7 @@ Found 1 error in main.ts:3 "size": 2377 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/MessageablePerson.ts *refresh* /home/src/workspaces/project/main.ts @@ -256,6 +259,7 @@ Output:: Found 1 error in main.ts:3 +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -338,6 +342,7 @@ Output:: "size": 2000 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/MessageablePerson.ts *refresh* /home/src/workspaces/project/main.ts @@ -352,5 +357,6 @@ tsgo --incremental ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js index 557e27d2a1..62e7b7d846 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js @@ -165,6 +165,7 @@ Object.defineProperty(exports, "ConstantNumber", { enumerable: true, get: functi "size": 1816 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/class1.ts @@ -285,6 +286,7 @@ exports.default = 2; "size": 1816 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/constants.ts Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js index 2eed40cb53..3969ab2412 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js @@ -135,6 +135,7 @@ exports.default = 1; "size": 1550 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/class1.ts @@ -235,6 +236,7 @@ exports.default = 2; "size": 1550 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/constants.ts Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/generates-typerefs-correctly.js b/testdata/baselines/reference/tsc/incremental/generates-typerefs-correctly.js index e43878d4ef..e0407c36f9 100644 --- a/testdata/baselines/reference/tsc/incremental/generates-typerefs-correctly.js +++ b/testdata/baselines/reference/tsc/incremental/generates-typerefs-correctly.js @@ -190,6 +190,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); "size": 2078 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/src/box.ts @@ -333,6 +334,7 @@ exports.something = 1; "size": 2141 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/src/bug.js Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/option-changes-with-composite.js b/testdata/baselines/reference/tsc/incremental/option-changes-with-composite.js index 39aadf17e7..d84dcad4b8 100644 --- a/testdata/baselines/reference/tsc/incremental/option-changes-with-composite.js +++ b/testdata/baselines/reference/tsc/incremental/option-changes-with-composite.js @@ -175,6 +175,7 @@ exports.d = b_1.b; "size": 1747 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -323,6 +324,7 @@ exports.d = b_1.b; "size": 1764 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -453,6 +455,7 @@ exports.d = b_1.b; "size": 1747 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -463,6 +466,7 @@ tsgo --declaration ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -473,6 +477,7 @@ tsgo ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -597,6 +602,7 @@ export declare const d = 10; "size": 1788 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -711,6 +717,7 @@ export declare const d = 10; "size": 1747 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -721,6 +728,7 @@ tsgo --emitDeclarationOnly ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -731,6 +739,7 @@ tsgo ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -842,6 +851,7 @@ const aLocal = 100; "size": 1748 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/a.ts Signatures:: @@ -854,6 +864,7 @@ tsgo --declaration ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -985,6 +996,7 @@ exports.d = b_1.b; "size": 1771 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -1121,6 +1133,7 @@ exports.d = b_1.b; "size": 1765 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -1274,6 +1287,7 @@ exports.d = b_1.b; "size": 1770 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -1410,5 +1424,6 @@ exports.d = b_1.b; "size": 1787 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/option-changes-with-incremental.js b/testdata/baselines/reference/tsc/incremental/option-changes-with-incremental.js index ae80d67f90..e0329f64f4 100644 --- a/testdata/baselines/reference/tsc/incremental/option-changes-with-incremental.js +++ b/testdata/baselines/reference/tsc/incremental/option-changes-with-incremental.js @@ -139,6 +139,7 @@ exports.d = b_1.b; "size": 1236 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -261,6 +262,7 @@ exports.d = b_1.b; "size": 1265 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -367,6 +369,7 @@ exports.d = b_1.b; "size": 1236 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -480,6 +483,7 @@ export declare const d = 10; "size": 1715 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: (stored at emit) /home/src/workspaces/project/a.ts @@ -606,6 +610,7 @@ export declare const d = 10; "size": 1737 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -616,6 +621,7 @@ tsgo ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -723,6 +729,7 @@ const aLocal = 100; "size": 1685 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/a.ts Signatures:: @@ -835,6 +842,7 @@ Output:: "size": 1738 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -845,6 +853,7 @@ tsgo ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -974,6 +983,7 @@ exports.d = b_1.b; "size": 1720 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -1108,6 +1118,7 @@ exports.d = b_1.b; "size": 1714 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -1234,6 +1245,7 @@ exports.d = b_1.b; "size": 1685 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -1344,6 +1356,7 @@ Output:: "size": 1738 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -1354,5 +1367,6 @@ tsgo --declaration --declarationMap ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js b/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js index 08093ca69c..d50ad32e52 100644 --- a/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js +++ b/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js @@ -134,6 +134,7 @@ exports.App = App; "size": 1612 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/src/index.tsx diff --git a/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash.js b/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash.js index 6c23a7e822..04165b519c 100644 --- a/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash.js +++ b/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash.js @@ -111,6 +111,7 @@ exports.App = App; "size": 1343 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/src/index.tsx diff --git a/testdata/baselines/reference/tsc/incremental/serializing-composite-project.js b/testdata/baselines/reference/tsc/incremental/serializing-composite-project.js index 05fa2d66da..ac61ce49b9 100644 --- a/testdata/baselines/reference/tsc/incremental/serializing-composite-project.js +++ b/testdata/baselines/reference/tsc/incremental/serializing-composite-project.js @@ -107,6 +107,7 @@ export const b = 2; "size": 1288 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/index.tsx diff --git a/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js b/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js index 9475e70c60..907e86ee11 100644 --- a/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js +++ b/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js @@ -172,6 +172,7 @@ declare const console: { log(msg: any): void; }; "size": 2098 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/index.tsx @@ -200,5 +201,6 @@ Output:: Found 1 error in index.tsx:10 +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/tsbuildinfo-has-error.js b/testdata/baselines/reference/tsc/incremental/tsbuildinfo-has-error.js index fca82548b5..08d10bcd2c 100644 --- a/testdata/baselines/reference/tsc/incremental/tsbuildinfo-has-error.js +++ b/testdata/baselines/reference/tsc/incremental/tsbuildinfo-has-error.js @@ -72,6 +72,7 @@ exports.x = 10; "size": 904 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/main.ts @@ -90,6 +91,7 @@ Output:: {"version":"FakeTSVersion","fileNames":["lib.d.ts","./main.ts"],"fileInfos":[{"version":"8859c12c614ce56ba9a18e58384a198f-/// \ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array { length: number; [n: number]: T; }\ninterface ReadonlyArray {}\ninterface SymbolConstructor {\n (desc?: string | number): symbol;\n for(name: string): symbol;\n readonly toStringTag: symbol;\n}\ndeclare var Symbol: SymbolConstructor;\ninterface Symbol {\n readonly [Symbol.toStringTag]: string;\n}\ndeclare const console: { log(msg: any): void; };","affectsGlobalScope":true,"impliedNodeFormat":1},"28e8748a7acd58f4f59388926e914f86-export const x = 10;"]} //// [/home/src/workspaces/project/tsconfig.tsbuildinfo.readable.baseline.txt] *rewrite with same content* +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/main.ts diff --git a/testdata/baselines/reference/tsc/incremental/when-file-is-deleted.js b/testdata/baselines/reference/tsc/incremental/when-file-is-deleted.js index 6b9d8e9163..2a9453f868 100644 --- a/testdata/baselines/reference/tsc/incremental/when-file-is-deleted.js +++ b/testdata/baselines/reference/tsc/incremental/when-file-is-deleted.js @@ -117,6 +117,7 @@ exports.D = D; "size": 1276 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/file1.ts @@ -174,5 +175,6 @@ Output:: "size": 1097 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/when-global-file-is-added,-the-signatures-are-updated.js b/testdata/baselines/reference/tsc/incremental/when-global-file-is-added,-the-signatures-are-updated.js index 8890070ee2..c23d894001 100644 --- a/testdata/baselines/reference/tsc/incremental/when-global-file-is-added,-the-signatures-are-updated.js +++ b/testdata/baselines/reference/tsc/incremental/when-global-file-is-added,-the-signatures-are-updated.js @@ -153,6 +153,7 @@ function main() { } "size": 1895 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/src/filePresent.ts @@ -170,6 +171,7 @@ tsgo ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -277,6 +279,7 @@ something(); "size": 1907 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/src/main.ts Signatures:: @@ -387,6 +390,7 @@ something(); "size": 1919 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/src/main.ts Signatures:: @@ -528,6 +532,7 @@ function foo() { return 20; } "size": 2201 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/src/newFile.ts @@ -673,6 +678,7 @@ function something2() { return 20; } "size": 2426 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/src/fileNotFound.ts @@ -825,6 +831,7 @@ something(); "size": 2438 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/src/main.ts Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/when-passing-filename-for-buildinfo-on-commandline.js b/testdata/baselines/reference/tsc/incremental/when-passing-filename-for-buildinfo-on-commandline.js index 99ad44a329..ffcb32f40a 100644 --- a/testdata/baselines/reference/tsc/incremental/when-passing-filename-for-buildinfo-on-commandline.js +++ b/testdata/baselines/reference/tsc/incremental/when-passing-filename-for-buildinfo-on-commandline.js @@ -87,6 +87,7 @@ exports.x = void 0; exports.x = 10; +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/src/main.ts @@ -103,5 +104,6 @@ Output:: src/main.ts Matched by include pattern 'src/**/*.ts' in 'tsconfig.json' +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/when-passing-rootDir-from-commandline.js b/testdata/baselines/reference/tsc/incremental/when-passing-rootDir-from-commandline.js index b38e03c510..06eef5bdc8 100644 --- a/testdata/baselines/reference/tsc/incremental/when-passing-rootDir-from-commandline.js +++ b/testdata/baselines/reference/tsc/incremental/when-passing-rootDir-from-commandline.js @@ -79,6 +79,7 @@ exports.x = 10; "size": 956 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/src/main.ts @@ -91,5 +92,6 @@ tsgo --rootDir src ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/when-passing-rootDir-is-in-the-tsconfig.js b/testdata/baselines/reference/tsc/incremental/when-passing-rootDir-is-in-the-tsconfig.js index e80df2ee46..4737fef775 100644 --- a/testdata/baselines/reference/tsc/incremental/when-passing-rootDir-is-in-the-tsconfig.js +++ b/testdata/baselines/reference/tsc/incremental/when-passing-rootDir-is-in-the-tsconfig.js @@ -80,6 +80,7 @@ exports.x = 10; "size": 950 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/src/main.ts @@ -92,5 +93,6 @@ tsgo ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tsc/incremental/with-only-dts-files.js b/testdata/baselines/reference/tsc/incremental/with-only-dts-files.js index ec5b0308e9..9c9887d283 100644 --- a/testdata/baselines/reference/tsc/incremental/with-only-dts-files.js +++ b/testdata/baselines/reference/tsc/incremental/with-only-dts-files.js @@ -73,6 +73,7 @@ declare const console: { log(msg: any): void; }; "size": 987 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/src/another.d.ts @@ -86,6 +87,7 @@ tsgo --incremental ExitStatus:: Success Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -136,6 +138,7 @@ Output:: "size": 1009 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/workspaces/project/src/main.d.ts Signatures:: diff --git a/testdata/baselines/reference/tsc/noEmit/when-project-has-strict-true.js b/testdata/baselines/reference/tsc/noEmit/when-project-has-strict-true.js index 330b9bf419..e9e50e8693 100644 --- a/testdata/baselines/reference/tsc/noEmit/when-project-has-strict-true.js +++ b/testdata/baselines/reference/tsc/noEmit/when-project-has-strict-true.js @@ -79,6 +79,7 @@ declare const console: { log(msg: any): void; }; "size": 965 } +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/class1.ts diff --git a/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences2.js b/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences2.js index e87b5efa7c..fa8c45e57a 100644 --- a/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences2.js +++ b/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences2.js @@ -127,6 +127,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); "size": 1326 } +src/services/tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.esnext.full.d.ts *refresh* /home/src/workspaces/solution/dist/compiler/parser.d.ts diff --git a/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences3.js b/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences3.js index 2256197ade..12041c99a0 100644 --- a/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences3.js +++ b/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences3.js @@ -131,6 +131,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); "size": 1335 } +src/services/tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.esnext.full.d.ts *refresh* /home/src/workspaces/solution/dist/compiler/parser.d.ts diff --git a/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js b/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js index 33a17e206c..0a7f765952 100644 --- a/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js +++ b/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js @@ -35,5 +35,6 @@ Found 1 error. "size": 85 } +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option.js b/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option.js index fbff1dd2bb..257321f12f 100644 --- a/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option.js +++ b/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option.js @@ -38,6 +38,7 @@ interface Symbol { } declare const console: { log(msg: any): void; }; +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/first.ts diff --git a/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-tsconfig-and-incremental.js b/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-tsconfig-and-incremental.js index 408993b951..6c12462d05 100644 --- a/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-tsconfig-and-incremental.js +++ b/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-tsconfig-and-incremental.js @@ -35,6 +35,7 @@ declare const console: { log(msg: any): void; }; //// [/home/src/workspaces/project/index.js] *new* +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/index.ts diff --git a/testdata/baselines/reference/tscWatch/noEmit/dts-errors-without-dts-enabled.js b/testdata/baselines/reference/tscWatch/noEmit/dts-errors-without-dts-enabled.js index a426806d75..7f69e1ad38 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/dts-errors-without-dts-enabled.js +++ b/testdata/baselines/reference/tscWatch/noEmit/dts-errors-without-dts-enabled.js @@ -37,6 +37,7 @@ interface Symbol { } declare const console: { log(msg: any): void; }; +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -50,6 +51,7 @@ const a = "hello"; Output:: +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -71,6 +73,7 @@ Output:: const a = "hello"; +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -87,6 +90,7 @@ Edit [2]:: no emit run after fixing error Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -98,6 +102,7 @@ const a = class { private p = 10; }; Output:: +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -121,6 +126,7 @@ const a = class { }; +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -137,5 +143,6 @@ Edit [5]:: no emit run when error Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js b/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js index 633939b3e4..b77ca27b24 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js @@ -50,6 +50,7 @@ interface Symbol { } declare const console: { log(msg: any): void; }; +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -63,6 +64,7 @@ const a = "hello"; Output:: +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -87,6 +89,7 @@ declare const a = "hello"; const a = "hello"; +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -103,6 +106,7 @@ Edit [2]:: no emit run after fixing error Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -126,6 +130,7 @@ Output:: Found 1 error in a.ts:1 +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -168,6 +173,7 @@ const a = class { }; +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -196,5 +202,6 @@ Output:: Found 1 error in a.ts:1 +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js b/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js index 931f63d408..a8b9727d1c 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js @@ -45,6 +45,7 @@ interface Symbol { } declare const console: { log(msg: any): void; }; +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -58,6 +59,7 @@ const a = "hello"; Output:: +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -79,6 +81,7 @@ Output:: const a = "hello"; +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -95,6 +98,7 @@ Edit [2]:: no emit run after fixing error Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -114,6 +118,7 @@ Output:: Found 1 error in a.ts:1 +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -141,6 +146,7 @@ Found 1 error in a.ts:1 //// [/home/src/workspaces/project/a.js] *rewrite with same content* +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -165,5 +171,6 @@ Output:: Found 1 error in a.ts:1 +tsconfig.json:: SemanticDiagnostics:: Signatures:: diff --git a/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js b/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js index ce5b5071b0..1622804cd9 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js @@ -45,6 +45,7 @@ interface Symbol { } declare const console: { log(msg: any): void; }; +tsconfig.json:: SemanticDiagnostics:: *not cached* /home/src/tslibs/TS/Lib/lib.d.ts *not cached* /home/src/workspaces/project/a.ts @@ -58,6 +59,7 @@ const a = "hello"; Output:: +tsconfig.json:: SemanticDiagnostics:: *refresh* /home/src/tslibs/TS/Lib/lib.d.ts *refresh* /home/src/workspaces/project/a.ts @@ -79,6 +81,7 @@ Output:: const a = "hello"; +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -95,6 +98,7 @@ Edit [2]:: no emit run after fixing error Output:: +tsconfig.json:: SemanticDiagnostics:: Signatures:: @@ -114,6 +118,7 @@ Output:: Found 1 error in a.ts:1 +tsconfig.json:: SemanticDiagnostics:: *not cached* /home/src/workspaces/project/a.ts Signatures:: @@ -141,6 +146,7 @@ Found 1 error in a.ts:1 const a = "hello; +tsconfig.json:: SemanticDiagnostics:: *not cached* /home/src/workspaces/project/a.ts Signatures:: @@ -167,6 +173,7 @@ Output:: Found 1 error in a.ts:1 +tsconfig.json:: SemanticDiagnostics:: *not cached* /home/src/workspaces/project/a.ts Signatures:: From 5b01fc99686c51034354f8823e2d72961237756a Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 15:38:58 -0700 Subject: [PATCH 03/18] Add symlinks to baseline --- internal/execute/testsys_test.go | 30 +++++++++++++++---- internal/vfs/iovfs/iofs.go | 15 ++++++++-- internal/vfs/vfstest/vfstest.go | 50 ++++++++++++++++++++------------ 3 files changed, 69 insertions(+), 26 deletions(-) diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index 320fff4280..a316fcf9c3 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -21,6 +21,7 @@ import ( "github.com/microsoft/typescript-go/internal/tsoptions" "github.com/microsoft/typescript-go/internal/tspath" "github.com/microsoft/typescript-go/internal/vfs" + "github.com/microsoft/typescript-go/internal/vfs/iovfs" "github.com/microsoft/typescript-go/internal/vfs/vfstest" ) @@ -84,8 +85,9 @@ func newTestSys(fileOrFolderList FileMap, cwd string, env map[string]string) *te } type diffEntry struct { - content string - isWritten bool + content string + isWritten bool + symlinkTarget string } type snapshot struct { @@ -127,8 +129,8 @@ func (s *testSys) testFs() *testFs { return s.fs.FS.(*testFs) } -func (s *testSys) fsFromFileMap() vfs.FS { - return s.testFs().FS +func (s *testSys) fsFromFileMap() iovfs.FsWithSys { + return s.testFs().FS.(iovfs.FsWithSys) } func (s *testSys) ensureLibPathExists(path string) { @@ -270,7 +272,19 @@ func (s *testSys) baselineFSwithDiff(baseline io.Writer) { return e } - if !d.Type().IsRegular() { + fileInfo := d.Type() + if fileInfo&fs.ModeSymlink != 0 { + target, ok := s.fsFromFileMap().FSys().(*vfstest.MapFS).GetTargetOfSymlink(path) + if !ok { + panic("Failed to resolve symlink target: " + path) + } + newEntry := &diffEntry{symlinkTarget: target} + snap[path] = newEntry + s.addFsEntryDiff(diffs, newEntry, path) + return nil + } + + if !fileInfo.IsRegular() { return nil } @@ -326,7 +340,11 @@ func (s *testSys) addFsEntryDiff(diffs map[string]string, newDirContent *diffEnt // todo handle more cases of fs changes if oldDirContent == nil { if s.testFs().defaultLibs == nil || !s.testFs().defaultLibs.Has(path) { - diffs[path] = "*new* \n" + newDirContent.content + if newDirContent.symlinkTarget != "" { + diffs[path] = "-> " + newDirContent.symlinkTarget + " *new*" + } else { + diffs[path] = "*new* \n" + newDirContent.content + } } } else if newDirContent == nil { diffs[path] = "*deleted*" diff --git a/internal/vfs/iovfs/iofs.go b/internal/vfs/iovfs/iofs.go index 8b4fd5777d..a5289d4f0b 100644 --- a/internal/vfs/iovfs/iofs.go +++ b/internal/vfs/iovfs/iofs.go @@ -24,6 +24,11 @@ type WritableFS interface { Remove(path string) error } +type FsWithSys interface { + vfs.FS + FSys() fs.FS +} + // From creates a new FS from an [fs.FS]. // // For paths like `c:/foo/bar`, fsys will be used as though it's rooted at `/` and the path is `/c:/foo/bar`. @@ -33,7 +38,7 @@ type WritableFS interface { // // From does not actually handle case-insensitivity; ensure the passed in [fs.FS] // respects case-insensitive file names if needed. Consider using [vfstest.FromMap] for testing. -func From(fsys fs.FS, useCaseSensitiveFileNames bool) vfs.FS { +func From(fsys fs.FS, useCaseSensitiveFileNames bool) FsWithSys { var realpath func(path string) (string, error) if fsys, ok := fsys.(RealpathFS); ok { realpath = func(path string) (string, error) { @@ -107,6 +112,7 @@ func From(fsys fs.FS, useCaseSensitiveFileNames bool) vfs.FS { writeFile: writeFile, mkdirAll: mkdirAll, remove: remove, + fsys: fsys, } } @@ -118,9 +124,10 @@ type ioFS struct { writeFile func(path string, content string, writeByteOrderMark bool) error mkdirAll func(path string) error remove func(path string) error + fsys fs.FS } -var _ vfs.FS = (*ioFS)(nil) +var _ FsWithSys = (*ioFS)(nil) func (vfs *ioFS) UseCaseSensitiveFileNames() bool { return vfs.useCaseSensitiveFileNames @@ -177,3 +184,7 @@ func (vfs *ioFS) WriteFile(path string, content string, writeByteOrderMark bool) } return vfs.writeFile(path, content, writeByteOrderMark) } + +func (vfs *ioFS) FSys() fs.FS { + return vfs.fsys +} diff --git a/internal/vfs/vfstest/vfstest.go b/internal/vfs/vfstest/vfstest.go index 861a8c4212..84a96c685f 100644 --- a/internal/vfs/vfstest/vfstest.go +++ b/internal/vfs/vfstest/vfstest.go @@ -17,7 +17,7 @@ import ( "github.com/microsoft/typescript-go/internal/vfs/iovfs" ) -type mapFS struct { +type MapFS struct { // mu protects m. // A single mutex is sufficient as we only use fstest.Map's Open method. mu sync.RWMutex @@ -31,8 +31,8 @@ type mapFS struct { } var ( - _ iovfs.RealpathFS = (*mapFS)(nil) - _ iovfs.WritableFS = (*mapFS)(nil) + _ iovfs.RealpathFS = (*MapFS)(nil) + _ iovfs.WritableFS = (*MapFS)(nil) ) type sys struct { @@ -103,8 +103,8 @@ func FromMap[File any](m map[string]File, useCaseSensitiveFileNames bool) vfs.FS return iovfs.From(convertMapFS(mfs, useCaseSensitiveFileNames), useCaseSensitiveFileNames) } -func convertMapFS(input fstest.MapFS, useCaseSensitiveFileNames bool) *mapFS { - m := &mapFS{ +func convertMapFS(input fstest.MapFS, useCaseSensitiveFileNames bool) *MapFS { + m := &MapFS{ m: make(fstest.MapFS, len(input)), useCaseSensitiveFileNames: useCaseSensitiveFileNames, } @@ -162,15 +162,15 @@ func comparePathsByParts(a, b string) int { type canonicalPath string -func (m *mapFS) getCanonicalPath(p string) canonicalPath { +func (m *MapFS) getCanonicalPath(p string) canonicalPath { return canonicalPath(tspath.GetCanonicalFileName(p, m.useCaseSensitiveFileNames)) } -func (m *mapFS) open(p canonicalPath) (fs.File, error) { +func (m *MapFS) open(p canonicalPath) (fs.File, error) { return m.m.Open(string(p)) } -func (m *mapFS) remove(path string) error { +func (m *MapFS) remove(path string) error { canonical := m.getCanonicalPath(path) canonicalString := string(canonical) fileInfo := m.m[canonicalString] @@ -200,7 +200,7 @@ func Symlink(target string) *fstest.MapFile { } } -func (m *mapFS) getFollowingSymlinks(p canonicalPath) (*fstest.MapFile, canonicalPath, error) { +func (m *MapFS) getFollowingSymlinks(p canonicalPath) (*fstest.MapFile, canonicalPath, error) { return m.getFollowingSymlinksWorker(p, "", "") } @@ -212,7 +212,7 @@ func (e *brokenSymlinkError) Error() string { return fmt.Sprintf("broken symlink %q -> %q", e.from, e.to) } -func (m *mapFS) getFollowingSymlinksWorker(p canonicalPath, symlinkFrom, symlinkTo canonicalPath) (*fstest.MapFile, canonicalPath, error) { +func (m *MapFS) getFollowingSymlinksWorker(p canonicalPath, symlinkFrom, symlinkTo canonicalPath) (*fstest.MapFile, canonicalPath, error) { if file, ok := m.m[string(p)]; ok && file.Mode&fs.ModeSymlink == 0 { return file, p, nil } @@ -235,11 +235,11 @@ func (m *mapFS) getFollowingSymlinksWorker(p canonicalPath, symlinkFrom, symlink return nil, p, err } -func (m *mapFS) set(p canonicalPath, file *fstest.MapFile) { +func (m *MapFS) set(p canonicalPath, file *fstest.MapFile) { m.m[string(p)] = file } -func (m *mapFS) setEntry(realpath string, canonical canonicalPath, file fstest.MapFile) { +func (m *MapFS) setEntry(realpath string, canonical canonicalPath, file fstest.MapFile) { if realpath == "" || canonical == "" { panic("empty path") } @@ -276,7 +276,7 @@ func baseName(p string) string { return file } -func (m *mapFS) mkdirAll(p string, perm fs.FileMode) error { +func (m *MapFS) mkdirAll(p string, perm fs.FileMode) error { if p == "" { panic("empty path") } @@ -378,7 +378,7 @@ func (f *readDirFile) ReadDir(n int) ([]fs.DirEntry, error) { return entries, nil } -func (m *mapFS) Open(name string) (fs.File, error) { +func (m *MapFS) Open(name string) (fs.File, error) { m.mu.RLock() defer m.mu.RUnlock() @@ -420,7 +420,7 @@ func (m *mapFS) Open(name string) (fs.File, error) { }, nil } -func (m *mapFS) Realpath(name string) (string, error) { +func (m *MapFS) Realpath(name string) (string, error) { m.mu.RLock() defer m.mu.RUnlock() @@ -445,14 +445,14 @@ func convertInfo(info fs.FileInfo) (*fileInfo, bool) { const umask = 0o022 -func (m *mapFS) MkdirAll(path string, perm fs.FileMode) error { +func (m *MapFS) MkdirAll(path string, perm fs.FileMode) error { m.mu.Lock() defer m.mu.Unlock() return m.mkdirAll(path, perm) } -func (m *mapFS) WriteFile(path string, data []byte, perm fs.FileMode) error { +func (m *MapFS) WriteFile(path string, data []byte, perm fs.FileMode) error { m.mu.Lock() defer m.mu.Unlock() @@ -489,13 +489,27 @@ func (m *mapFS) WriteFile(path string, data []byte, perm fs.FileMode) error { return nil } -func (m *mapFS) Remove(path string) error { +func (m *MapFS) Remove(path string) error { m.mu.Lock() defer m.mu.Unlock() return m.remove(path) } +func (m *MapFS) GetTargetOfSymlink(path string) (string, bool) { + path, _ = strings.CutPrefix(path, "/") + m.mu.RLock() + defer m.mu.RUnlock() + canonical := m.getCanonicalPath(path) + canonicalString := string(canonical) + if fileInfo, ok := m.m[canonicalString]; ok { + if fileInfo.Mode&fs.ModeSymlink != 0 { + return "/" + string(fileInfo.Data), true + } + } + return "", false +} + func must[T any](v T, err error) T { if err != nil { panic(err) From 3f8e3cfee199164b18058b1e57118186c17e22cd Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 20:05:51 -0700 Subject: [PATCH 04/18] Write modified times in baseline --- internal/execute/testsys_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index a316fcf9c3..fa3f50d477 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -86,6 +86,7 @@ func newTestSys(fileOrFolderList FileMap, cwd string, env map[string]string) *te type diffEntry struct { content string + mTime time.Time isWritten bool symlinkTarget string } @@ -292,7 +293,11 @@ func (s *testSys) baselineFSwithDiff(baseline io.Writer) { if !ok { return nil } - newEntry := &diffEntry{content: newContents, isWritten: testFs.writtenFiles.Has(path)} + stat := s.fsFromFileMap().Stat(path) + if stat == nil { + panic("stat is nil: " + path) + } + newEntry := &diffEntry{content: newContents, mTime: stat.ModTime(), isWritten: testFs.writtenFiles.Has(path)} snap[path] = newEntry s.addFsEntryDiff(diffs, newEntry, path) @@ -352,6 +357,8 @@ func (s *testSys) addFsEntryDiff(diffs map[string]string, newDirContent *diffEnt diffs[path] = "*modified* \n" + newDirContent.content } else if newDirContent.isWritten { diffs[path] = "*rewrite with same content*" + } else if newDirContent.mTime != oldDirContent.mTime { + diffs[path] = "*mTime changed*" } else if defaultLibs != nil && defaultLibs.Has(path) && s.testFs().defaultLibs != nil && !s.testFs().defaultLibs.Has(path) { // Lib file that was read diffs[path] = "*Lib*\n" + newDirContent.content From 36a29443d07b97aa4fa459228d246dd6868c3e7e Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 20:09:13 -0700 Subject: [PATCH 05/18] directly use tscInput for creating testSys --- internal/execute/testsys_test.go | 9 ++++----- internal/execute/tsctestrunner_test.go | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index fa3f50d477..0ca55bc9b0 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -54,23 +54,23 @@ interface Symbol { declare const console: { log(msg: any): void; }; `) -func newTestSys(fileOrFolderList FileMap, cwd string, env map[string]string) *testSys { +func newTestSys(tscInput *tscInput) *testSys { + cwd := tscInput.cwd if cwd == "" { cwd = "/home/src/workspaces/project" } sys := &testSys{ fs: &incrementaltestutil.FsHandlingBuildInfo{ FS: &testFs{ - FS: vfstest.FromMap(fileOrFolderList, true /*useCaseSensitiveFileNames*/), + FS: vfstest.FromMap(tscInput.files, true /*useCaseSensitiveFileNames*/), }, }, defaultLibraryPath: tscLibPath, cwd: cwd, - files: slices.Collect(maps.Keys(fileOrFolderList)), output: []string{}, currentWrite: &strings.Builder{}, start: time.Now(), - env: env, + env: tscInput.env, } // Ensure the default library file is present @@ -105,7 +105,6 @@ type testSys struct { fs *incrementaltestutil.FsHandlingBuildInfo defaultLibraryPath string cwd string - files []string env map[string]string start time.Time diff --git a/internal/execute/tsctestrunner_test.go b/internal/execute/tsctestrunner_test.go index 69c303c660..72402c5e8f 100644 --- a/internal/execute/tsctestrunner_test.go +++ b/internal/execute/tsctestrunner_test.go @@ -65,7 +65,7 @@ func (test *tscInput) run(t *testing.T, scenario string) { t.Parallel() // initial test tsc compile baselineBuilder := &strings.Builder{} - sys := newTestSys(test.files, test.cwd, test.env) + sys := newTestSys(test) fmt.Fprint( baselineBuilder, "currentDirectory::", @@ -102,7 +102,7 @@ func (test *tscInput) run(t *testing.T, scenario string) { }) wg.Queue(func() { // Compute build with all the edits - nonIncrementalSys = newTestSys(test.files, test.cwd, test.env) + nonIncrementalSys = newTestSys(test) for i := range index + 1 { if test.edits[i].edit != nil { test.edits[i].edit(nonIncrementalSys) From 31fb8eb364ee6803723b6bcbc189e9902da28564 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 20:15:20 -0700 Subject: [PATCH 06/18] Add ignoreCase option on tscInput --- internal/execute/testsys_test.go | 2 +- internal/execute/tsctestrunner_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index 0ca55bc9b0..d93aa5a46d 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -62,7 +62,7 @@ func newTestSys(tscInput *tscInput) *testSys { sys := &testSys{ fs: &incrementaltestutil.FsHandlingBuildInfo{ FS: &testFs{ - FS: vfstest.FromMap(tscInput.files, true /*useCaseSensitiveFileNames*/), + FS: vfstest.FromMap(tscInput.files, !tscInput.ignoreCase), }, }, defaultLibraryPath: tscLibPath, diff --git a/internal/execute/tsctestrunner_test.go b/internal/execute/tsctestrunner_test.go index 72402c5e8f..b5d5b3bb70 100644 --- a/internal/execute/tsctestrunner_test.go +++ b/internal/execute/tsctestrunner_test.go @@ -35,6 +35,7 @@ type tscInput struct { cwd string edits []*testTscEdit env map[string]string + ignoreCase bool } func (test *tscInput) executeCommand(sys *testSys, baselineBuilder *strings.Builder, commandLineArgs []string) execute.CommandLineResult { From 86ad5df53c9bbc6843d61d1393d1262b53091533 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 20:16:07 -0700 Subject: [PATCH 07/18] Add windows style root --- internal/execute/testsys_test.go | 8 ++++++-- internal/execute/tsctestrunner_test.go | 15 ++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index d93aa5a46d..c789d19e4d 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -59,13 +59,17 @@ func newTestSys(tscInput *tscInput) *testSys { if cwd == "" { cwd = "/home/src/workspaces/project" } + libPath := tscLibPath + if tscInput.windowsStyleRoot != "" { + libPath = tscInput.windowsStyleRoot + libPath[1:] + } sys := &testSys{ fs: &incrementaltestutil.FsHandlingBuildInfo{ FS: &testFs{ FS: vfstest.FromMap(tscInput.files, !tscInput.ignoreCase), }, }, - defaultLibraryPath: tscLibPath, + defaultLibraryPath: libPath, cwd: cwd, output: []string{}, currentWrite: &strings.Builder{}, @@ -134,7 +138,7 @@ func (s *testSys) fsFromFileMap() iovfs.FsWithSys { } func (s *testSys) ensureLibPathExists(path string) { - path = tscLibPath + "/" + path + path = s.defaultLibraryPath + "/" + path if _, ok := s.fsFromFileMap().ReadFile(path); !ok { if s.testFs().defaultLibs == nil { s.testFs().defaultLibs = &collections.SyncSet[string]{} diff --git a/internal/execute/tsctestrunner_test.go b/internal/execute/tsctestrunner_test.go index b5d5b3bb70..a72e422359 100644 --- a/internal/execute/tsctestrunner_test.go +++ b/internal/execute/tsctestrunner_test.go @@ -29,13 +29,14 @@ var noChangeOnlyEdit = []*testTscEdit{ } type tscInput struct { - subScenario string - commandLineArgs []string - files FileMap - cwd string - edits []*testTscEdit - env map[string]string - ignoreCase bool + subScenario string + commandLineArgs []string + files FileMap + cwd string + edits []*testTscEdit + env map[string]string + ignoreCase bool + windowsStyleRoot string } func (test *tscInput) executeCommand(sys *testSys, baselineBuilder *strings.Builder, commandLineArgs []string) execute.CommandLineResult { From 9c66d9ef4785b8624ef85821a190ed9ff6aa2502 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 20:17:31 -0700 Subject: [PATCH 08/18] Rename to tscEdit --- internal/execute/tscincremental_test.go | 24 ++++++++++++------------ internal/execute/tsctestrunner_test.go | 8 ++++---- internal/execute/tscwatch_test.go | 6 +++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/internal/execute/tscincremental_test.go b/internal/execute/tscincremental_test.go index 1b277e0bb7..76fe263bbc 100644 --- a/internal/execute/tscincremental_test.go +++ b/internal/execute/tscincremental_test.go @@ -82,7 +82,7 @@ func TestIncremental(t *testing.T) { type InstanceType any> = T extends abstract new (...args: any) => infer R ? R : any;`), }, commandLineArgs: []string{"--incremental"}, - edits: []*testTscEdit{ + edits: []*tscEdit{ noChange, { caption: "modify public to protected", @@ -128,7 +128,7 @@ func TestIncremental(t *testing.T) { type InstanceType any> = T extends abstract new (...args: any) => infer R ? R : any;`), }, commandLineArgs: []string{"--incremental"}, - edits: []*testTscEdit{ + edits: []*tscEdit{ noChange, { caption: "modify public to protected", @@ -187,7 +187,7 @@ func TestIncremental(t *testing.T) { "/home/src/workspaces/project/tsconfig.json": "{}", }, commandLineArgs: []string{"--incremental"}, - edits: []*testTscEdit{ + edits: []*tscEdit{ noChange, { caption: "modify d.ts file", @@ -220,7 +220,7 @@ func TestIncremental(t *testing.T) { "/home/src/workspaces/project/tsconfig.tsbuildinfo": "Some random string", }, commandLineArgs: []string{"-i"}, - edits: []*testTscEdit{ + edits: []*tscEdit{ { caption: "tsbuildinfo written has error", edit: func(sys *testSys) { @@ -250,7 +250,7 @@ func TestIncremental(t *testing.T) { }`), }, commandLineArgs: []string{}, - edits: []*testTscEdit{ + edits: []*tscEdit{ noChange, { caption: "Modify main file", @@ -362,7 +362,7 @@ func TestIncremental(t *testing.T) { "/home/src/workspaces/project/constants.ts": "export default 1;", "/home/src/workspaces/project/types.d.ts": `type MagicNumber = typeof import('./constants').default`, }, - edits: []*testTscEdit{ + edits: []*tscEdit{ { caption: "Modify imports used in global file", edit: func(sys *testSys) { @@ -388,7 +388,7 @@ func TestIncremental(t *testing.T) { "/home/src/workspaces/project/reexport.ts": `export { default as ConstantNumber } from "./constants"`, "/home/src/workspaces/project/types.d.ts": `type MagicNumber = typeof import('./reexport').ConstantNumber`, }, - edits: []*testTscEdit{ + edits: []*tscEdit{ { caption: "Modify imports used in global file", edit: func(sys *testSys) { @@ -411,7 +411,7 @@ func TestIncremental(t *testing.T) { "/home/src/workspaces/project/file1.ts": `export class C { }`, "/home/src/workspaces/project/file2.ts": `export class D { }`, }, - edits: []*testTscEdit{ + edits: []*tscEdit{ { caption: "delete file with imports", edit: func(sys *testSys) { @@ -466,7 +466,7 @@ func TestIncremental(t *testing.T) { } `), }, - edits: []*testTscEdit{ + edits: []*tscEdit{ { caption: "modify js file", edit: func(sys *testSys) { @@ -501,7 +501,7 @@ func TestIncremental(t *testing.T) { "/home/src/workspaces/project/c.ts": `import { a } from "./a";export const c = a;`, "/home/src/workspaces/project/d.ts": `import { b } from "./b";export const d = b;`, }, - edits: []*testTscEdit{ + edits: []*tscEdit{ { caption: "with sourceMap", commandLineArgs: []string{"--sourceMap"}, @@ -582,7 +582,7 @@ func TestIncremental(t *testing.T) { "/home/src/workspaces/project/c.ts": `import { a } from "./a";export const c = a;`, "/home/src/workspaces/project/d.ts": `import { b } from "./b";export const d = b;`, }, - edits: []*testTscEdit{ + edits: []*tscEdit{ { caption: "with sourceMap", commandLineArgs: []string{"--sourceMap"}, @@ -671,7 +671,7 @@ func getConstEnumTest(bdsContents string, changeEnumFile string, testSuffix stri `), }, commandLineArgs: []string{"-i", `a.ts`, "--tsbuildinfofile", "a.tsbuildinfo"}, - edits: []*testTscEdit{ + edits: []*tscEdit{ { caption: "change enum value", edit: func(sys *testSys) { diff --git a/internal/execute/tsctestrunner_test.go b/internal/execute/tsctestrunner_test.go index a72e422359..63dac0ef8b 100644 --- a/internal/execute/tsctestrunner_test.go +++ b/internal/execute/tsctestrunner_test.go @@ -13,18 +13,18 @@ import ( "github.com/microsoft/typescript-go/internal/tspath" ) -type testTscEdit struct { +type tscEdit struct { caption string commandLineArgs []string edit func(*testSys) expectedDiff string } -var noChange = &testTscEdit{ +var noChange = &tscEdit{ caption: "no change", } -var noChangeOnlyEdit = []*testTscEdit{ +var noChangeOnlyEdit = []*tscEdit{ noChange, } @@ -33,7 +33,7 @@ type tscInput struct { commandLineArgs []string files FileMap cwd string - edits []*testTscEdit + edits []*tscEdit env map[string]string ignoreCase bool windowsStyleRoot string diff --git a/internal/execute/tscwatch_test.go b/internal/execute/tscwatch_test.go index c7ce9719c4..eabb675791 100644 --- a/internal/execute/tscwatch_test.go +++ b/internal/execute/tscwatch_test.go @@ -69,7 +69,7 @@ func noEmitWatchTestInput( "/home/src/workspaces/project/a.ts": aText, "/home/src/workspaces/project/tsconfig.json": tsconfigText, }, - edits: []*testTscEdit{ + edits: []*tscEdit{ newTscEdit("fix error", func(sys *testSys) { sys.writeFileNoError("/home/src/workspaces/project/a.ts", `const a = "hello";`, false) }), @@ -92,8 +92,8 @@ func noEmitWatchTestInput( } } -func newTscEdit(name string, edit func(sys *testSys)) *testTscEdit { - return &testTscEdit{name, []string{}, edit, ""} +func newTscEdit(name string, edit func(sys *testSys)) *tscEdit { + return &tscEdit{name, []string{}, edit, ""} } func TestTscNoEmitWatch(t *testing.T) { From 99331234c055dd4b98aad330175383c2e346d769 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 20:38:03 -0700 Subject: [PATCH 09/18] Rename error.txt diff to output.txt --- internal/execute/tsctestrunner_test.go | 18 +++++++++++++----- ...-in-another-file-through-indirect-import.js | 4 ++-- ...as-global-through-export-in-another-file.js | 4 ++-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/internal/execute/tsctestrunner_test.go b/internal/execute/tsctestrunner_test.go index 63dac0ef8b..c50c746b68 100644 --- a/internal/execute/tsctestrunner_test.go +++ b/internal/execute/tsctestrunner_test.go @@ -63,7 +63,7 @@ func (test *tscInput) executeCommand(sys *testSys, baselineBuilder *strings.Buil func (test *tscInput) run(t *testing.T, scenario string) { t.Helper() - t.Run(test.subScenario+" tsc baseline", func(t *testing.T) { + t.Run(test.subScenario, func(t *testing.T) { t.Parallel() // initial test tsc compile baselineBuilder := &strings.Builder{} @@ -80,6 +80,7 @@ func (test *tscInput) run(t *testing.T, scenario string) { result := test.executeCommand(sys, baselineBuilder, test.commandLineArgs) sys.serializeState(baselineBuilder) sys.baselineProgram(baselineBuilder, result.IncrementalProgram, result.Watcher) + var unexpectedDiff string for index, do := range test.edits { sys.clearOutput() @@ -118,11 +119,18 @@ func (test *tscInput) run(t *testing.T, scenario string) { if diff != "" { baselineBuilder.WriteString(fmt.Sprintf("\n\nDiff:: %s\n", core.IfElse(do.expectedDiff == "", "!!! Unexpected diff, please review and either fix or write explanation as expectedDiff !!!", do.expectedDiff))) baselineBuilder.WriteString(diff) + if do.expectedDiff == "" { + unexpectedDiff += fmt.Sprintf("Edit [%d]:: %s\n!!! Unexpected diff, please review and either fix or write explanation as expectedDiff !!!\n%s\n", index, do.caption, diff) + } } else if do.expectedDiff != "" { baselineBuilder.WriteString(fmt.Sprintf("\n\nDiff:: %s !!! Diff not found but explanation present, please review and remove the explanation !!!\n", do.expectedDiff)) + unexpectedDiff += fmt.Sprintf("Edit [%d]:: %s\n!!! Diff not found but explanation present, please review and remove the explanation !!!\n", index, do.caption) } } baseline.Run(t, strings.ReplaceAll(test.subScenario, " ", "-")+".js", baselineBuilder.String(), baseline.Options{Subfolder: filepath.Join(test.getBaselineSubFolder(), scenario)}) + if unexpectedDiff != "" { + t.Errorf("Test %s has unexpected diff %s with incremental build, please review the baseline file", test.subScenario, unexpectedDiff) + } }) } @@ -152,10 +160,10 @@ func getDiffForIncremental(incrementalSys *testSys, nonIncrementalSys *testSys) } } - incrementalErrors := strings.Join(incrementalSys.output, "") - nonIncrementalErrors := strings.Join(nonIncrementalSys.output, "") - if incrementalErrors != nonIncrementalErrors { - diffBuilder.WriteString(baseline.DiffText("nonIncremental errors.txt", "incremental errors.txt", nonIncrementalErrors, incrementalErrors)) + incrementalOutput := strings.Join(incrementalSys.output, "") + nonIncrementalOutput := strings.Join(nonIncrementalSys.output, "") + if incrementalOutput != nonIncrementalOutput { + diffBuilder.WriteString(baseline.DiffText("nonIncremental.output.txt", "incremental.output.txt", nonIncrementalOutput, incrementalOutput)) } return diffBuilder.String() } diff --git a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js index 62e7b7d846..428b5852b9 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js @@ -299,8 +299,8 @@ Diff:: Currently there is issue with d.ts emit for export default = 1 to widen i @@ -1,1 +1,1 @@ -declare const a = 2; +declare const a = 1; ---- nonIncremental errors.txt -+++ incremental errors.txt +--- nonIncremental.output.txt ++++ incremental.output.txt @@ -1,7 +0,0 @@ -class1.ts:1:7 - error TS2322: Type '1' is not assignable to type '2'. - diff --git a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js index 3969ab2412..2ab761560f 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js @@ -249,8 +249,8 @@ Diff:: Currently there is issue with d.ts emit for export default = 1 to widen i @@ -1,1 +1,1 @@ -declare const a = 2; +declare const a = 1; ---- nonIncremental errors.txt -+++ incremental errors.txt +--- nonIncremental.output.txt ++++ incremental.output.txt @@ -1,7 +0,0 @@ -class1.ts:1:7 - error TS2322: Type '1' is not assignable to type '2'. - From f4a79e2f68296b2417936fcacd0c26b9fd686ee0 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 15:38:58 -0700 Subject: [PATCH 10/18] Remove EndWrite and use string builder directly for baselining --- cmd/tsgo/sys.go | 5 -- internal/execute/outputs.go | 5 -- internal/execute/system.go | 1 - internal/execute/testsys_test.go | 48 +++++++------------ internal/execute/tsc.go | 1 - internal/execute/tsctestrunner_test.go | 4 +- .../when-build-not-first-argument.js | 3 +- ...does-not-add-color-when-NO_COLOR-is-set.js | 1 - .../reference/tsc/commandLine/help-all.js | 1 - ...when-host-cannot-provide-terminal-width.js | 1 - ...tatus.DiagnosticsPresent_OutputsSkipped.js | 1 - .../extends/configDir-template-showConfig.js | 26 +++++++++- .../configDir-template-with-commandline.js | 2 - .../tsc/extends/configDir-template.js | 2 - ...ion-field-with-declaration-emit-enabled.js | 4 -- ...e-to-modifier-of-class-expression-field.js | 2 - ...types-found-doesnt-crash-under---strict.js | 1 - .../incremental/serializing-error-chain.js | 2 - .../reference/tsc/noCheck/dts-errors.js | 1 - .../reference/tsc/noCheck/syntax-errors.js | 1 - ...nterop-uses-referenced-project-settings.js | 1 - ...ativeImportExtensionsProjectReferences2.js | 1 - ...ativeImportExtensionsProjectReferences3.js | 1 - ...ject-contains-invalid-project-reference.js | 1 - .../when-project-reference-is-not-built.js | 1 - ...eferences-composite-project-with-noEmit.js | 1 - .../parse-tsconfig-with-typeAcquisition.js | 1 - ...h-interval-option-without-tsconfig.json.js | 1 - .../reference/tscWatch/noEmit/dts-errors.js | 4 -- .../tscWatch/noEmit/semantic-errors.js | 4 -- .../tscWatch/noEmit/syntax-errors.js | 4 -- 31 files changed, 45 insertions(+), 87 deletions(-) diff --git a/cmd/tsgo/sys.go b/cmd/tsgo/sys.go index 741a48bac3..6f28371e77 100644 --- a/cmd/tsgo/sys.go +++ b/cmd/tsgo/sys.go @@ -46,11 +46,6 @@ func (s *osSys) Writer() io.Writer { return s.writer } -func (s *osSys) EndWrite() { - // do nothing, this is needed in the interface for testing - // todo: revisit if improving tsc/build/watch unittest baselines -} - func (s *osSys) WriteOutputIsTTY() bool { return term.IsTerminal(int(os.Stdout.Fd())) } diff --git a/internal/execute/outputs.go b/internal/execute/outputs.go index 4094e3a468..641fbf4f1f 100644 --- a/internal/execute/outputs.go +++ b/internal/execute/outputs.go @@ -40,12 +40,10 @@ func createDiagnosticReporter(sys System, options *core.CompilerOptions) diagnos if !shouldBePretty(sys, options) { return func(diagnostic *ast.Diagnostic) { diagnosticwriter.WriteFormatDiagnostic(sys.Writer(), diagnostic, formatOpts) - sys.EndWrite() } } return func(diagnostic *ast.Diagnostic) { diagnosticwriter.FormatDiagnosticsWithColorAndContext(sys.Writer(), []*ast.Diagnostic{diagnostic}, formatOpts) - sys.EndWrite() } } @@ -132,7 +130,6 @@ func createReportErrorSummary(sys System, options *core.CompilerOptions) func(di formatOpts := getFormatOptsOfSys(sys) return func(diagnostics []*ast.Diagnostic) { diagnosticwriter.WriteErrorSummaryText(sys.Writer(), diagnostics, formatOpts) - sys.EndWrite() } } return func(diagnostics []*ast.Diagnostic) {} @@ -175,7 +172,6 @@ func reportStatistics(sys System, program *compiler.Program, result compileAndEm func printVersion(sys System) { fmt.Fprintln(sys.Writer(), diagnostics.Version_0.Format(core.Version())) - sys.EndWrite() } func printHelp(sys System, commandLine *tsoptions.ParsedCommandLine) { @@ -268,7 +264,6 @@ func printEasyHelp(sys System, simpleOptions []*tsoptions.CommandLineOption) { for _, chunk := range output { fmt.Fprint(sys.Writer(), chunk) } - sys.EndWrite() } func generateSectionOptionsOutput( diff --git a/internal/execute/system.go b/internal/execute/system.go index ad6816db15..db7a40907b 100644 --- a/internal/execute/system.go +++ b/internal/execute/system.go @@ -9,7 +9,6 @@ import ( type System interface { Writer() io.Writer - EndWrite() // needed for testing FS() vfs.FS DefaultLibraryPath() string GetCurrentDirectory() string diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index c789d19e4d..271ea3b42e 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -71,7 +71,6 @@ func newTestSys(tscInput *tscInput) *testSys { }, defaultLibraryPath: libPath, cwd: cwd, - output: []string{}, currentWrite: &strings.Builder{}, start: time.Now(), env: tscInput.env, @@ -101,8 +100,6 @@ type snapshot struct { } type testSys struct { - // todo: original has write to output as a string[] because the separations are needed for baselining - output []string currentWrite *strings.Builder serializedDiff *snapshot @@ -179,23 +176,16 @@ func (s *testSys) GetEnvironmentVariable(name string) string { } func sanitizeSysOutput(output string, prefixLine string, replaceString string) string { - if index := strings.Index(output, prefixLine); index != -1 { - indexOfNewLine := strings.Index(output[index:], "\n") - if indexOfNewLine != -1 { - output = output[:index] + replaceString + output[index+indexOfNewLine+1:] + for { + if index := strings.Index(output, prefixLine); index != -1 { + indexOfNewLine := strings.Index(output[index:], "\n") + if indexOfNewLine != -1 { + output = output[:index] + replaceString + output[index+indexOfNewLine+1:] + continue + } } + return output } - return output -} - -func (s *testSys) EndWrite() { - // todo: revisit if improving tsc/build/watch unittest baselines - output := s.currentWrite.String() - s.currentWrite.Reset() - output = sanitizeSysOutput(output, "Version "+core.Version(), "Version "+harnessutil.FakeTSVersion+"\n") - output = sanitizeSysOutput(output, "build starting at ", "") - output = sanitizeSysOutput(output, "build finished in ", "") - s.output = append(s.output, output) } func (s *testSys) baselineProgram(baseline *strings.Builder, program *incremental.Program, watcher *execute.Watcher) { @@ -253,16 +243,19 @@ func (s *testSys) serializeState(baseline *strings.Builder) { func (s *testSys) baselineOutput(baseline io.Writer) { fmt.Fprint(baseline, "\nOutput::\n") - if len(s.output) == 0 { - fmt.Fprint(baseline, "No output\n") - return - } - // todo screen clears - s.printOutputs(baseline) + fmt.Fprint(baseline, s.getOutput()) +} + +func (s *testSys) getOutput() string { + output := s.currentWrite.String() + output = sanitizeSysOutput(output, "Version "+core.Version(), "Version "+harnessutil.FakeTSVersion+"\n") + output = sanitizeSysOutput(output, "build starting at ", "") + output = sanitizeSysOutput(output, "build finished in ", "") + return output } func (s *testSys) clearOutput() { - s.output = []string{} + s.currentWrite.Reset() } func (s *testSys) baselineFSwithDiff(baseline io.Writer) { @@ -368,11 +361,6 @@ func (s *testSys) addFsEntryDiff(diffs map[string]string, newDirContent *diffEnt } } -func (s *testSys) printOutputs(baseline io.Writer) { - // todo sanitize sys output - fmt.Fprint(baseline, strings.Join(s.output, "\n")) -} - func (s *testSys) writeFileNoError(path string, content string, writeByteOrderMark bool) { if err := s.fsFromFileMap().WriteFile(path, content, writeByteOrderMark); err != nil { panic(err) diff --git a/internal/execute/tsc.go b/internal/execute/tsc.go index cb633671f2..86dfe90331 100644 --- a/internal/execute/tsc.go +++ b/internal/execute/tsc.go @@ -53,7 +53,6 @@ func CommandLine(sys System, commandLineArgs []string, testing bool) CommandLine switch strings.ToLower(commandLineArgs[0]) { case "-b", "--b", "-build", "--build": fmt.Fprintln(sys.Writer(), "Build mode is currently unsupported.") - sys.EndWrite() return CommandLineResult{Status: ExitStatusNotImplemented} // case "-f": // return fmtMain(sys, commandLineArgs[1], commandLineArgs[1]) diff --git a/internal/execute/tsctestrunner_test.go b/internal/execute/tsctestrunner_test.go index c50c746b68..fe71a66ba5 100644 --- a/internal/execute/tsctestrunner_test.go +++ b/internal/execute/tsctestrunner_test.go @@ -160,8 +160,8 @@ func getDiffForIncremental(incrementalSys *testSys, nonIncrementalSys *testSys) } } - incrementalOutput := strings.Join(incrementalSys.output, "") - nonIncrementalOutput := strings.Join(nonIncrementalSys.output, "") + incrementalOutput := incrementalSys.getOutput() + nonIncrementalOutput := nonIncrementalSys.getOutput() if incrementalOutput != nonIncrementalOutput { diffBuilder.WriteString(baseline.DiffText("nonIncremental.output.txt", "incremental.output.txt", nonIncrementalOutput, incrementalOutput)) } diff --git a/testdata/baselines/reference/tsbuild/commandLine/when-build-not-first-argument.js b/testdata/baselines/reference/tsbuild/commandLine/when-build-not-first-argument.js index 608553534e..a2c72720f5 100644 --- a/testdata/baselines/reference/tsbuild/commandLine/when-build-not-first-argument.js +++ b/testdata/baselines/reference/tsbuild/commandLine/when-build-not-first-argument.js @@ -5,5 +5,4 @@ Input:: tsgo --verbose --build ExitStatus:: DiagnosticsPresent_OutputsSkipped Output:: -error TS5093: Compiler option '--verbose' may only be used with '--build'. -error TS6369: Option '--build' must be the first command line argument. +error TS5093: Compiler option '--verbose' may only be used with '--build'.error TS6369: Option '--build' must be the first command line argument. diff --git a/testdata/baselines/reference/tsc/commandLine/does-not-add-color-when-NO_COLOR-is-set.js b/testdata/baselines/reference/tsc/commandLine/does-not-add-color-when-NO_COLOR-is-set.js index d5682e767f..466c49d180 100644 --- a/testdata/baselines/reference/tsc/commandLine/does-not-add-color-when-NO_COLOR-is-set.js +++ b/testdata/baselines/reference/tsc/commandLine/does-not-add-color-when-NO_COLOR-is-set.js @@ -6,7 +6,6 @@ tsgo ExitStatus:: DiagnosticsPresent_OutputsSkipped Output:: Version FakeTSVersion - tsc: The TypeScript Compiler - Version FakeTSVersion COMMON COMMANDS diff --git a/testdata/baselines/reference/tsc/commandLine/help-all.js b/testdata/baselines/reference/tsc/commandLine/help-all.js index ece14ddbf0..b96905a0a7 100644 --- a/testdata/baselines/reference/tsc/commandLine/help-all.js +++ b/testdata/baselines/reference/tsc/commandLine/help-all.js @@ -5,5 +5,4 @@ Input:: tsgo --help --all ExitStatus:: Success Output:: -No output diff --git a/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped-when-host-cannot-provide-terminal-width.js b/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped-when-host-cannot-provide-terminal-width.js index 2985d6a3fa..617b39a1ac 100644 --- a/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped-when-host-cannot-provide-terminal-width.js +++ b/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped-when-host-cannot-provide-terminal-width.js @@ -6,7 +6,6 @@ tsgo ExitStatus:: DiagnosticsPresent_OutputsSkipped Output:: Version FakeTSVersion - tsc: The TypeScript Compiler - Version FakeTSVersion COMMON COMMANDS diff --git a/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js b/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js index 5092b85eee..70411b9b3a 100644 --- a/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js +++ b/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js @@ -6,7 +6,6 @@ tsgo ExitStatus:: DiagnosticsPresent_OutputsSkipped Output:: Version FakeTSVersion - tsc: The TypeScript Compiler - Version FakeTSVersion  TS  COMMON COMMANDS diff --git a/testdata/baselines/reference/tsc/extends/configDir-template-showConfig.js b/testdata/baselines/reference/tsc/extends/configDir-template-showConfig.js index b32d38fcc4..6e13d50e15 100644 --- a/testdata/baselines/reference/tsc/extends/configDir-template-showConfig.js +++ b/testdata/baselines/reference/tsc/extends/configDir-template-showConfig.js @@ -51,5 +51,27 @@ export const x = 10; tsgo --showConfig ExitStatus:: Success Output:: -No output - +{ + "declaration": true, + "declarationDir": "/home/src/projects/myproject/decls", + "outDir": "/home/src/projects/myproject/outDir", + "paths": { + "@myscope/*": [ + "/home/src/projects/myproject/types/*" + ], + "other/*": [ + "other/*" + ] + }, + "traceResolution": true, + "typeRoots": [ + "/home/src/projects/configs/first/root1", + "/home/src/projects/myproject/root2", + "/home/src/projects/configs/first/root3" + ], + "types": [], + "baseUrl": "/home/src/projects/myproject", + "configFilePath": "/home/src/projects/myproject/tsconfig.json", + "pathsBasePath": "/home/src/projects/configs/second", + "showConfig": true +} diff --git a/testdata/baselines/reference/tsc/extends/configDir-template-with-commandline.js b/testdata/baselines/reference/tsc/extends/configDir-template-with-commandline.js index 02de299024..64231aff32 100644 --- a/testdata/baselines/reference/tsc/extends/configDir-template-with-commandline.js +++ b/testdata/baselines/reference/tsc/extends/configDir-template-with-commandline.js @@ -99,13 +99,11 @@ Directory '/node_modules' does not exist, skipping all lookups in it. 3 "compilerOptions": {    ~~~~~~~~~~~~~~~~~ - tsconfig.json:3:5 - error TS5102: Option 'baseUrl' has been removed. Please remove it from your configuration. Use '"paths": {"*": ["./*"]}' instead. 3 "compilerOptions": {    ~~~~~~~~~~~~~~~~~ - ../../tslibs/TS/Lib/lib.d.ts Default library for target 'ES5' types/sometype.ts diff --git a/testdata/baselines/reference/tsc/extends/configDir-template.js b/testdata/baselines/reference/tsc/extends/configDir-template.js index 6a0adf8b7d..2716989b69 100644 --- a/testdata/baselines/reference/tsc/extends/configDir-template.js +++ b/testdata/baselines/reference/tsc/extends/configDir-template.js @@ -99,13 +99,11 @@ Directory '/node_modules' does not exist, skipping all lookups in it. 3 "compilerOptions": {    ~~~~~~~~~~~~~~~~~ - tsconfig.json:3:5 - error TS5102: Option 'baseUrl' has been removed. Please remove it from your configuration. Use '"paths": {"*": ["./*"]}' instead. 3 "compilerOptions": {    ~~~~~~~~~~~~~~~~~ - ../../tslibs/TS/Lib/lib.d.ts Default library for target 'ES5' types/sometype.ts diff --git a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js index d3f3690594..c34e2d2c5b 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js @@ -184,13 +184,11 @@ Output:: MessageablePerson.ts:6:7 - Add a type annotation to the variable wrapper. 6 const wrapper = () => Messageable();    ~~~~~~~ - main.ts:3:25 - error TS2445: Property 'message' is protected and only accessible within class 'MessageableClass' and its subclasses. 3 console.log( person.message );    ~~~~~~~ - Found 2 errors in 2 files. Errors Files @@ -323,13 +321,11 @@ Output:: MessageablePerson.ts:6:7 - Add a type annotation to the variable wrapper. 6 const wrapper = () => Messageable();    ~~~~~~~ - main.ts:3:25 - error TS2445: Property 'message' is protected and only accessible within class 'MessageableClass' and its subclasses. 3 console.log( person.message );    ~~~~~~~ - Found 2 errors in 2 files. Errors Files diff --git a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js index 44cd75b955..5171e60a08 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js @@ -155,7 +155,6 @@ Output:: 3 console.log( person.message );    ~~~~~~~ - Found 1 error in main.ts:3 //// [/home/src/workspaces/project/MessageablePerson.js] *rewrite with same content* @@ -255,7 +254,6 @@ Output:: 3 console.log( person.message );    ~~~~~~~ - Found 1 error in main.ts:3 diff --git a/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js b/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js index d50ad32e52..df65a2996a 100644 --- a/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js +++ b/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js @@ -35,7 +35,6 @@ Output:: 1 export const App = () =>
;    ~~~~~~~~~~~~~~~~~~~~~~~~ - Found 1 error in src/index.tsx:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js b/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js index 907e86ee11..db7a7c306e 100644 --- a/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js +++ b/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js @@ -41,7 +41,6 @@ Output:: 9 declare function Component(props: { children?: number }): any;    ~~~~~~~~~ - Found 1 error in index.tsx:10 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* @@ -197,7 +196,6 @@ Output:: 9 declare function Component(props: { children?: number }): any;    ~~~~~~~~~ - Found 1 error in index.tsx:10 diff --git a/testdata/baselines/reference/tsc/noCheck/dts-errors.js b/testdata/baselines/reference/tsc/noCheck/dts-errors.js index f6a6bd8271..cec33c30eb 100644 --- a/testdata/baselines/reference/tsc/noCheck/dts-errors.js +++ b/testdata/baselines/reference/tsc/noCheck/dts-errors.js @@ -24,7 +24,6 @@ Output:: 1 export const a = class { private p = 10; };    ~ - Found 1 error in a.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/noCheck/syntax-errors.js b/testdata/baselines/reference/tsc/noCheck/syntax-errors.js index 0fa9c55830..a5d197aafe 100644 --- a/testdata/baselines/reference/tsc/noCheck/syntax-errors.js +++ b/testdata/baselines/reference/tsc/noCheck/syntax-errors.js @@ -20,7 +20,6 @@ Output:: 1 export const a = "hello    ~ - Found 1 error in a.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js b/testdata/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js index abc2590be1..6a508b1a77 100644 --- a/testdata/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js +++ b/testdata/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js @@ -56,7 +56,6 @@ tsgo --p app --pretty false ExitStatus:: DiagnosticsPresent_OutputsGenerated Output:: app/src/index.ts(1,8): error TS2613: Module '"/home/src/workspaces/project/app/src/local"' has no default export. Did you mean to use 'import { local } from "/home/src/workspaces/project/app/src/local"' instead? - app/src/index.ts(2,8): error TS2613: Module '"/home/src/workspaces/project/node_modules/esm-package/index"' has no default export. Did you mean to use 'import { esm } from "/home/src/workspaces/project/node_modules/esm-package/index"' instead? //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* /// diff --git a/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences2.js b/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences2.js index fa8c45e57a..fec014724b 100644 --- a/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences2.js +++ b/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences2.js @@ -34,7 +34,6 @@ import {} from "../compiler/parser.ts"; tsgo --p src/services --pretty false ExitStatus:: Success Output:: -No output //// [/home/src/tslibs/TS/Lib/lib.esnext.full.d.ts] *Lib* /// interface Boolean {} diff --git a/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences3.js b/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences3.js index 12041c99a0..8297da6f3f 100644 --- a/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences3.js +++ b/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences3.js @@ -38,7 +38,6 @@ import {} from "../compiler/parser.ts"; tsgo --p src/services --pretty false ExitStatus:: Success Output:: -No output //// [/home/src/tslibs/TS/Lib/lib.esnext.full.d.ts] *Lib* /// interface Boolean {} diff --git a/testdata/baselines/reference/tsc/projectReferences/when-project-contains-invalid-project-reference.js b/testdata/baselines/reference/tsc/projectReferences/when-project-contains-invalid-project-reference.js index b3d59be07e..91c77da1f6 100644 --- a/testdata/baselines/reference/tsc/projectReferences/when-project-contains-invalid-project-reference.js +++ b/testdata/baselines/reference/tsc/projectReferences/when-project-contains-invalid-project-reference.js @@ -18,7 +18,6 @@ Output:: 3 { "path": "../utils" },    ~~~~~~~~~~~~~~~~~~~~~~ - Found 1 error in project/tsconfig.json:3 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/projectReferences/when-project-reference-is-not-built.js b/testdata/baselines/reference/tsc/projectReferences/when-project-reference-is-not-built.js index b7ebae5101..7e1e1b58fb 100644 --- a/testdata/baselines/reference/tsc/projectReferences/when-project-reference-is-not-built.js +++ b/testdata/baselines/reference/tsc/projectReferences/when-project-reference-is-not-built.js @@ -26,7 +26,6 @@ Output:: 1 import { x } from "../utils";    ~~~~~~~~~~ - Found 1 error in project/index.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/projectReferences/when-project-references-composite-project-with-noEmit.js b/testdata/baselines/reference/tsc/projectReferences/when-project-references-composite-project-with-noEmit.js index 38e6f71d13..5886e24484 100644 --- a/testdata/baselines/reference/tsc/projectReferences/when-project-references-composite-project-with-noEmit.js +++ b/testdata/baselines/reference/tsc/projectReferences/when-project-references-composite-project-with-noEmit.js @@ -27,7 +27,6 @@ Output:: 3 { "path": "../utils" },    ~~~~~~~~~~~~~~~~~~~~~~ - Found 1 error in project/tsconfig.json:3 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js b/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js index 0a7f765952..23ffdc74a1 100644 --- a/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js +++ b/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js @@ -19,7 +19,6 @@ tsgo ExitStatus:: DiagnosticsPresent_OutputsSkipped Output:: error TS18003: No inputs were found in config file '/home/src/workspaces/project/tsconfig.json'. Specified 'include' paths were '["**/*"]' and 'exclude' paths were '[]'. - Found 1 error. //// [/home/src/workspaces/project/tsconfig.tsbuildinfo] *new* diff --git a/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option-without-tsconfig.json.js b/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option-without-tsconfig.json.js index caa5ad3c2f..25c01cba5c 100644 --- a/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option-without-tsconfig.json.js +++ b/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option-without-tsconfig.json.js @@ -6,7 +6,6 @@ tsgo -w --watchInterval 1000 ExitStatus:: DiagnosticsPresent_OutputsSkipped Output:: Version FakeTSVersion - tsc: The TypeScript Compiler - Version FakeTSVersion COMMON COMMANDS diff --git a/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js b/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js index b77ca27b24..1ebd90a22b 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js @@ -23,7 +23,6 @@ Output:: 1 const a = class { private p = 10; };    ~ - Found 1 error in a.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* @@ -126,7 +125,6 @@ Output:: 1 const a = class { private p = 10; };    ~ - Found 1 error in a.ts:1 @@ -157,7 +155,6 @@ Output:: 1 const a = class { private p = 10; };    ~ - Found 1 error in a.ts:1 //// [/home/src/workspaces/project/a.d.ts] *modified* @@ -198,7 +195,6 @@ Output:: 1 const a = class { private p = 10; };    ~ - Found 1 error in a.ts:1 diff --git a/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js b/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js index a8b9727d1c..4a44610f96 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js @@ -18,7 +18,6 @@ Output:: 1 const a: number = "hello"    ~ - Found 1 error in a.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* @@ -114,7 +113,6 @@ Output:: 1 const a: number = "hello"    ~ - Found 1 error in a.ts:1 @@ -141,7 +139,6 @@ Output:: 1 const a: number = "hello"    ~ - Found 1 error in a.ts:1 //// [/home/src/workspaces/project/a.js] *rewrite with same content* @@ -167,7 +164,6 @@ Output:: 1 const a: number = "hello"    ~ - Found 1 error in a.ts:1 diff --git a/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js b/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js index 1622804cd9..37c30982a8 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js @@ -18,7 +18,6 @@ Output:: 1 const a = "hello    ~ - Found 1 error in a.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* @@ -114,7 +113,6 @@ Output:: 1 const a = "hello    ~ - Found 1 error in a.ts:1 @@ -139,7 +137,6 @@ Output:: 1 const a = "hello    ~ - Found 1 error in a.ts:1 //// [/home/src/workspaces/project/a.js] *modified* @@ -169,7 +166,6 @@ Output:: 1 const a = "hello    ~ - Found 1 error in a.ts:1 From a29db5dd00e9fd2231980c8612a9bea8cba0fa21 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 15:48:04 -0700 Subject: [PATCH 11/18] Fix new line with error reporting --- internal/diagnosticwriter/diagnosticwriter.go | 55 ++++++++++--------- internal/execute/outputs.go | 13 ++--- .../when-build-not-first-argument.js | 4 +- .../configDir-template-with-commandline.js | 2 + .../tsc/extends/configDir-template.js | 2 + ...ion-field-with-declaration-emit-enabled.js | 4 ++ ...e-to-modifier-of-class-expression-field.js | 2 + ...in-another-file-through-indirect-import.js | 3 +- ...s-global-through-export-in-another-file.js | 3 +- ...types-found-doesnt-crash-under---strict.js | 1 + .../incremental/serializing-error-chain.js | 2 + .../reference/tsc/noCheck/dts-errors.js | 1 + .../reference/tsc/noCheck/syntax-errors.js | 1 + ...nterop-uses-referenced-project-settings.js | 2 + ...erveConstEnums-and-verbatimModuleSyntax.js | 1 + ...ativeImportExtensionsProjectReferences1.js | 1 + ...ject-contains-invalid-project-reference.js | 1 + .../when-project-reference-is-not-built.js | 1 + ...eferences-composite-project-with-noEmit.js | 1 + .../parse-tsconfig-with-typeAcquisition.js | 1 + .../reference/tscWatch/noEmit/dts-errors.js | 4 ++ .../tscWatch/noEmit/semantic-errors.js | 4 ++ .../tscWatch/noEmit/syntax-errors.js | 4 ++ 23 files changed, 77 insertions(+), 36 deletions(-) diff --git a/internal/diagnosticwriter/diagnosticwriter.go b/internal/diagnosticwriter/diagnosticwriter.go index 797e447a44..7001bed49e 100644 --- a/internal/diagnosticwriter/diagnosticwriter.go +++ b/internal/diagnosticwriter/diagnosticwriter.go @@ -44,38 +44,41 @@ func FormatDiagnosticsWithColorAndContext(output io.Writer, diags []*ast.Diagnos if i > 0 { fmt.Fprint(output, formatOpts.NewLine) } + FormatDiagnosticWithColorAndContext(output, diagnostic, formatOpts) + } +} - if diagnostic.File() != nil { - file := diagnostic.File() - pos := diagnostic.Loc().Pos() - WriteLocation(output, file, pos, formatOpts, writeWithStyleAndReset) - fmt.Fprint(output, " - ") - } +func FormatDiagnosticWithColorAndContext(output io.Writer, diagnostic *ast.Diagnostic, formatOpts *FormattingOptions) { + if diagnostic.File() != nil { + file := diagnostic.File() + pos := diagnostic.Loc().Pos() + WriteLocation(output, file, pos, formatOpts, writeWithStyleAndReset) + fmt.Fprint(output, " - ") + } - writeWithStyleAndReset(output, diagnostic.Category().Name(), getCategoryFormat(diagnostic.Category())) - fmt.Fprintf(output, "%s TS%d: %s", foregroundColorEscapeGrey, diagnostic.Code(), resetEscapeSequence) - WriteFlattenedDiagnosticMessage(output, diagnostic, formatOpts.NewLine) + writeWithStyleAndReset(output, diagnostic.Category().Name(), getCategoryFormat(diagnostic.Category())) + fmt.Fprintf(output, "%s TS%d: %s", foregroundColorEscapeGrey, diagnostic.Code(), resetEscapeSequence) + WriteFlattenedDiagnosticMessage(output, diagnostic, formatOpts.NewLine) - if diagnostic.File() != nil && diagnostic.Code() != diagnostics.File_appears_to_be_binary.Code() { - fmt.Fprint(output, formatOpts.NewLine) - writeCodeSnippet(output, diagnostic.File(), diagnostic.Pos(), diagnostic.Len(), getCategoryFormat(diagnostic.Category()), "", formatOpts) - fmt.Fprint(output, formatOpts.NewLine) - } + if diagnostic.File() != nil && diagnostic.Code() != diagnostics.File_appears_to_be_binary.Code() { + fmt.Fprint(output, formatOpts.NewLine) + writeCodeSnippet(output, diagnostic.File(), diagnostic.Pos(), diagnostic.Len(), getCategoryFormat(diagnostic.Category()), "", formatOpts) + fmt.Fprint(output, formatOpts.NewLine) + } - if (diagnostic.RelatedInformation() != nil) && (len(diagnostic.RelatedInformation()) > 0) { - for _, relatedInformation := range diagnostic.RelatedInformation() { - file := relatedInformation.File() - if file != nil { - fmt.Fprint(output, formatOpts.NewLine) - fmt.Fprint(output, " ") - pos := relatedInformation.Pos() - WriteLocation(output, file, pos, formatOpts, writeWithStyleAndReset) - fmt.Fprint(output, " - ") - WriteFlattenedDiagnosticMessage(output, relatedInformation, formatOpts.NewLine) - writeCodeSnippet(output, file, pos, relatedInformation.Len(), foregroundColorEscapeCyan, " ", formatOpts) - } + if (diagnostic.RelatedInformation() != nil) && (len(diagnostic.RelatedInformation()) > 0) { + for _, relatedInformation := range diagnostic.RelatedInformation() { + file := relatedInformation.File() + if file != nil { fmt.Fprint(output, formatOpts.NewLine) + fmt.Fprint(output, " ") + pos := relatedInformation.Pos() + WriteLocation(output, file, pos, formatOpts, writeWithStyleAndReset) + fmt.Fprint(output, " - ") + WriteFlattenedDiagnosticMessage(output, relatedInformation, formatOpts.NewLine) + writeCodeSnippet(output, file, pos, relatedInformation.Len(), foregroundColorEscapeCyan, " ", formatOpts) } + fmt.Fprint(output, formatOpts.NewLine) } } } diff --git a/internal/execute/outputs.go b/internal/execute/outputs.go index 641fbf4f1f..dac0f07801 100644 --- a/internal/execute/outputs.go +++ b/internal/execute/outputs.go @@ -31,19 +31,18 @@ func getFormatOptsOfSys(sys System) *diagnosticwriter.FormattingOptions { type diagnosticReporter = func(*ast.Diagnostic) +func quietDiagnosticReporter(diagnostic *ast.Diagnostic) {} func createDiagnosticReporter(sys System, options *core.CompilerOptions) diagnosticReporter { if options.Quiet.IsTrue() { - return func(diagnostic *ast.Diagnostic) {} + return quietDiagnosticReporter } formatOpts := getFormatOptsOfSys(sys) - if !shouldBePretty(sys, options) { - return func(diagnostic *ast.Diagnostic) { - diagnosticwriter.WriteFormatDiagnostic(sys.Writer(), diagnostic, formatOpts) - } - } + writeDiagnostic := core.IfElse(shouldBePretty(sys, options), diagnosticwriter.FormatDiagnosticWithColorAndContext, diagnosticwriter.WriteFormatDiagnostic) + return func(diagnostic *ast.Diagnostic) { - diagnosticwriter.FormatDiagnosticsWithColorAndContext(sys.Writer(), []*ast.Diagnostic{diagnostic}, formatOpts) + writeDiagnostic(sys.Writer(), diagnostic, formatOpts) + fmt.Fprint(sys.Writer(), formatOpts.NewLine) } } diff --git a/testdata/baselines/reference/tsbuild/commandLine/when-build-not-first-argument.js b/testdata/baselines/reference/tsbuild/commandLine/when-build-not-first-argument.js index a2c72720f5..d44964311b 100644 --- a/testdata/baselines/reference/tsbuild/commandLine/when-build-not-first-argument.js +++ b/testdata/baselines/reference/tsbuild/commandLine/when-build-not-first-argument.js @@ -5,4 +5,6 @@ Input:: tsgo --verbose --build ExitStatus:: DiagnosticsPresent_OutputsSkipped Output:: -error TS5093: Compiler option '--verbose' may only be used with '--build'.error TS6369: Option '--build' must be the first command line argument. +error TS5093: Compiler option '--verbose' may only be used with '--build'. +error TS6369: Option '--build' must be the first command line argument. + diff --git a/testdata/baselines/reference/tsc/extends/configDir-template-with-commandline.js b/testdata/baselines/reference/tsc/extends/configDir-template-with-commandline.js index 64231aff32..02de299024 100644 --- a/testdata/baselines/reference/tsc/extends/configDir-template-with-commandline.js +++ b/testdata/baselines/reference/tsc/extends/configDir-template-with-commandline.js @@ -99,11 +99,13 @@ Directory '/node_modules' does not exist, skipping all lookups in it. 3 "compilerOptions": {    ~~~~~~~~~~~~~~~~~ + tsconfig.json:3:5 - error TS5102: Option 'baseUrl' has been removed. Please remove it from your configuration. Use '"paths": {"*": ["./*"]}' instead. 3 "compilerOptions": {    ~~~~~~~~~~~~~~~~~ + ../../tslibs/TS/Lib/lib.d.ts Default library for target 'ES5' types/sometype.ts diff --git a/testdata/baselines/reference/tsc/extends/configDir-template.js b/testdata/baselines/reference/tsc/extends/configDir-template.js index 2716989b69..6a0adf8b7d 100644 --- a/testdata/baselines/reference/tsc/extends/configDir-template.js +++ b/testdata/baselines/reference/tsc/extends/configDir-template.js @@ -99,11 +99,13 @@ Directory '/node_modules' does not exist, skipping all lookups in it. 3 "compilerOptions": {    ~~~~~~~~~~~~~~~~~ + tsconfig.json:3:5 - error TS5102: Option 'baseUrl' has been removed. Please remove it from your configuration. Use '"paths": {"*": ["./*"]}' instead. 3 "compilerOptions": {    ~~~~~~~~~~~~~~~~~ + ../../tslibs/TS/Lib/lib.d.ts Default library for target 'ES5' types/sometype.ts diff --git a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js index c34e2d2c5b..d3f3690594 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field-with-declaration-emit-enabled.js @@ -184,11 +184,13 @@ Output:: MessageablePerson.ts:6:7 - Add a type annotation to the variable wrapper. 6 const wrapper = () => Messageable();    ~~~~~~~ + main.ts:3:25 - error TS2445: Property 'message' is protected and only accessible within class 'MessageableClass' and its subclasses. 3 console.log( person.message );    ~~~~~~~ + Found 2 errors in 2 files. Errors Files @@ -321,11 +323,13 @@ Output:: MessageablePerson.ts:6:7 - Add a type annotation to the variable wrapper. 6 const wrapper = () => Messageable();    ~~~~~~~ + main.ts:3:25 - error TS2445: Property 'message' is protected and only accessible within class 'MessageableClass' and its subclasses. 3 console.log( person.message );    ~~~~~~~ + Found 2 errors in 2 files. Errors Files diff --git a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js index 5171e60a08..44cd75b955 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-modifier-of-class-expression-field.js @@ -155,6 +155,7 @@ Output:: 3 console.log( person.message );    ~~~~~~~ + Found 1 error in main.ts:3 //// [/home/src/workspaces/project/MessageablePerson.js] *rewrite with same content* @@ -254,6 +255,7 @@ Output:: 3 console.log( person.message );    ~~~~~~~ + Found 1 error in main.ts:3 diff --git a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js index 428b5852b9..0c78cd54c2 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file-through-indirect-import.js @@ -301,11 +301,12 @@ Diff:: Currently there is issue with d.ts emit for export default = 1 to widen i +declare const a = 1; --- nonIncremental.output.txt +++ incremental.output.txt -@@ -1,7 +0,0 @@ +@@ -1,8 +0,0 @@ -class1.ts:1:7 - error TS2322: Type '1' is not assignable to type '2'. - -1 const a: MagicNumber = 1; -   ~ - +- -Found 1 error in class1.ts:1 - \ No newline at end of file diff --git a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js index 2ab761560f..4350dc09ed 100644 --- a/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js +++ b/testdata/baselines/reference/tsc/incremental/change-to-type-that-gets-used-as-global-through-export-in-another-file.js @@ -251,11 +251,12 @@ Diff:: Currently there is issue with d.ts emit for export default = 1 to widen i +declare const a = 1; --- nonIncremental.output.txt +++ incremental.output.txt -@@ -1,7 +0,0 @@ +@@ -1,8 +0,0 @@ -class1.ts:1:7 - error TS2322: Type '1' is not assignable to type '2'. - -1 const a: MagicNumber = 1; -   ~ - +- -Found 1 error in class1.ts:1 - \ No newline at end of file diff --git a/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js b/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js index df65a2996a..d50ad32e52 100644 --- a/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js +++ b/testdata/baselines/reference/tsc/incremental/react-jsx-emit-mode-with-no-backing-types-found-doesnt-crash-under---strict.js @@ -35,6 +35,7 @@ Output:: 1 export const App = () =>
;    ~~~~~~~~~~~~~~~~~~~~~~~~ + Found 1 error in src/index.tsx:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js b/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js index db7a7c306e..907e86ee11 100644 --- a/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js +++ b/testdata/baselines/reference/tsc/incremental/serializing-error-chain.js @@ -41,6 +41,7 @@ Output:: 9 declare function Component(props: { children?: number }): any;    ~~~~~~~~~ + Found 1 error in index.tsx:10 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* @@ -196,6 +197,7 @@ Output:: 9 declare function Component(props: { children?: number }): any;    ~~~~~~~~~ + Found 1 error in index.tsx:10 diff --git a/testdata/baselines/reference/tsc/noCheck/dts-errors.js b/testdata/baselines/reference/tsc/noCheck/dts-errors.js index cec33c30eb..f6a6bd8271 100644 --- a/testdata/baselines/reference/tsc/noCheck/dts-errors.js +++ b/testdata/baselines/reference/tsc/noCheck/dts-errors.js @@ -24,6 +24,7 @@ Output:: 1 export const a = class { private p = 10; };    ~ + Found 1 error in a.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/noCheck/syntax-errors.js b/testdata/baselines/reference/tsc/noCheck/syntax-errors.js index a5d197aafe..0fa9c55830 100644 --- a/testdata/baselines/reference/tsc/noCheck/syntax-errors.js +++ b/testdata/baselines/reference/tsc/noCheck/syntax-errors.js @@ -20,6 +20,7 @@ Output:: 1 export const a = "hello    ~ + Found 1 error in a.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js b/testdata/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js index 6a508b1a77..6c55de0c02 100644 --- a/testdata/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js +++ b/testdata/baselines/reference/tsc/projectReferences/default-import-interop-uses-referenced-project-settings.js @@ -56,7 +56,9 @@ tsgo --p app --pretty false ExitStatus:: DiagnosticsPresent_OutputsGenerated Output:: app/src/index.ts(1,8): error TS2613: Module '"/home/src/workspaces/project/app/src/local"' has no default export. Did you mean to use 'import { local } from "/home/src/workspaces/project/app/src/local"' instead? + app/src/index.ts(2,8): error TS2613: Module '"/home/src/workspaces/project/node_modules/esm-package/index"' has no default export. Did you mean to use 'import { esm } from "/home/src/workspaces/project/node_modules/esm-package/index"' instead? + //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* /// interface Boolean {} diff --git a/testdata/baselines/reference/tsc/projectReferences/importing-const-enum-from-referenced-project-with-preserveConstEnums-and-verbatimModuleSyntax.js b/testdata/baselines/reference/tsc/projectReferences/importing-const-enum-from-referenced-project-with-preserveConstEnums-and-verbatimModuleSyntax.js index 1bb030b983..9d78b51615 100644 --- a/testdata/baselines/reference/tsc/projectReferences/importing-const-enum-from-referenced-project-with-preserveConstEnums-and-verbatimModuleSyntax.js +++ b/testdata/baselines/reference/tsc/projectReferences/importing-const-enum-from-referenced-project-with-preserveConstEnums-and-verbatimModuleSyntax.js @@ -46,6 +46,7 @@ tsgo --p project --pretty false ExitStatus:: DiagnosticsPresent_OutputsGenerated Output:: project/index.ts(2,10): error TS2748: Cannot access ambient const enums when 'verbatimModuleSyntax' is enabled. + //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* /// interface Boolean {} diff --git a/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences1.js b/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences1.js index b0b402f89e..b30f0e41f5 100644 --- a/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences1.js +++ b/testdata/baselines/reference/tsc/projectReferences/rewriteRelativeImportExtensionsProjectReferences1.js @@ -49,6 +49,7 @@ tsgo -p packages/main --pretty false ExitStatus:: DiagnosticsPresent_OutputsGenerated Output:: packages/main/src/index.ts(1,16): error TS2878: This import path is unsafe to rewrite because it resolves to another project, and the relative path between the projects' output files is not the same as the relative path between its input files. + //// [/home/src/tslibs/TS/Lib/lib.esnext.full.d.ts] *Lib* /// interface Boolean {} diff --git a/testdata/baselines/reference/tsc/projectReferences/when-project-contains-invalid-project-reference.js b/testdata/baselines/reference/tsc/projectReferences/when-project-contains-invalid-project-reference.js index 91c77da1f6..b3d59be07e 100644 --- a/testdata/baselines/reference/tsc/projectReferences/when-project-contains-invalid-project-reference.js +++ b/testdata/baselines/reference/tsc/projectReferences/when-project-contains-invalid-project-reference.js @@ -18,6 +18,7 @@ Output:: 3 { "path": "../utils" },    ~~~~~~~~~~~~~~~~~~~~~~ + Found 1 error in project/tsconfig.json:3 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/projectReferences/when-project-reference-is-not-built.js b/testdata/baselines/reference/tsc/projectReferences/when-project-reference-is-not-built.js index 7e1e1b58fb..b7ebae5101 100644 --- a/testdata/baselines/reference/tsc/projectReferences/when-project-reference-is-not-built.js +++ b/testdata/baselines/reference/tsc/projectReferences/when-project-reference-is-not-built.js @@ -26,6 +26,7 @@ Output:: 1 import { x } from "../utils";    ~~~~~~~~~~ + Found 1 error in project/index.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/projectReferences/when-project-references-composite-project-with-noEmit.js b/testdata/baselines/reference/tsc/projectReferences/when-project-references-composite-project-with-noEmit.js index 5886e24484..38e6f71d13 100644 --- a/testdata/baselines/reference/tsc/projectReferences/when-project-references-composite-project-with-noEmit.js +++ b/testdata/baselines/reference/tsc/projectReferences/when-project-references-composite-project-with-noEmit.js @@ -27,6 +27,7 @@ Output:: 3 { "path": "../utils" },    ~~~~~~~~~~~~~~~~~~~~~~ + Found 1 error in project/tsconfig.json:3 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* diff --git a/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js b/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js index 23ffdc74a1..0a7f765952 100644 --- a/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js +++ b/testdata/baselines/reference/tsc/typeAcquisition/parse-tsconfig-with-typeAcquisition.js @@ -19,6 +19,7 @@ tsgo ExitStatus:: DiagnosticsPresent_OutputsSkipped Output:: error TS18003: No inputs were found in config file '/home/src/workspaces/project/tsconfig.json'. Specified 'include' paths were '["**/*"]' and 'exclude' paths were '[]'. + Found 1 error. //// [/home/src/workspaces/project/tsconfig.tsbuildinfo] *new* diff --git a/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js b/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js index 1ebd90a22b..b77ca27b24 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js @@ -23,6 +23,7 @@ Output:: 1 const a = class { private p = 10; };    ~ + Found 1 error in a.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* @@ -125,6 +126,7 @@ Output:: 1 const a = class { private p = 10; };    ~ + Found 1 error in a.ts:1 @@ -155,6 +157,7 @@ Output:: 1 const a = class { private p = 10; };    ~ + Found 1 error in a.ts:1 //// [/home/src/workspaces/project/a.d.ts] *modified* @@ -195,6 +198,7 @@ Output:: 1 const a = class { private p = 10; };    ~ + Found 1 error in a.ts:1 diff --git a/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js b/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js index 4a44610f96..a8b9727d1c 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js @@ -18,6 +18,7 @@ Output:: 1 const a: number = "hello"    ~ + Found 1 error in a.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* @@ -113,6 +114,7 @@ Output:: 1 const a: number = "hello"    ~ + Found 1 error in a.ts:1 @@ -139,6 +141,7 @@ Output:: 1 const a: number = "hello"    ~ + Found 1 error in a.ts:1 //// [/home/src/workspaces/project/a.js] *rewrite with same content* @@ -164,6 +167,7 @@ Output:: 1 const a: number = "hello"    ~ + Found 1 error in a.ts:1 diff --git a/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js b/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js index 37c30982a8..1622804cd9 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js @@ -18,6 +18,7 @@ Output:: 1 const a = "hello    ~ + Found 1 error in a.ts:1 //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* @@ -113,6 +114,7 @@ Output:: 1 const a = "hello    ~ + Found 1 error in a.ts:1 @@ -137,6 +139,7 @@ Output:: 1 const a = "hello    ~ + Found 1 error in a.ts:1 //// [/home/src/workspaces/project/a.js] *modified* @@ -166,6 +169,7 @@ Output:: 1 const a = "hello    ~ + Found 1 error in a.ts:1 From 4a8c488b6eaa1df94484397010180f0e0004bf5b Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 15:38:58 -0700 Subject: [PATCH 12/18] Use command line testing interface to sanitize output --- cmd/tsgo/main.go | 2 +- internal/execute/outputs.go | 6 +- internal/execute/testsys_test.go | 117 +++++++++++++++--- internal/execute/tsc.go | 43 ++++--- internal/execute/tsctestrunner_test.go | 8 +- internal/execute/watcher.go | 10 +- ...tatus.DiagnosticsPresent_OutputsSkipped.js | 2 +- .../Parse-watch-interval-option.js | 2 + .../watch-with-no-tsconfig.js | 2 + .../watch-with-tsconfig-and-incremental.js | 2 + .../noEmit/dts-errors-without-dts-enabled.js | 14 +++ .../reference/tscWatch/noEmit/dts-errors.js | 14 +++ .../tscWatch/noEmit/semantic-errors.js | 14 +++ .../tscWatch/noEmit/syntax-errors.js | 14 +++ 14 files changed, 204 insertions(+), 46 deletions(-) diff --git a/cmd/tsgo/main.go b/cmd/tsgo/main.go index fbc694c2df..5eabc96df9 100644 --- a/cmd/tsgo/main.go +++ b/cmd/tsgo/main.go @@ -20,6 +20,6 @@ func runMain() int { return runAPI(args[1:]) } } - result := execute.CommandLine(newSystem(), args, false) + result := execute.CommandLine(newSystem(), args, nil) return int(result.Status) } diff --git a/internal/execute/outputs.go b/internal/execute/outputs.go index dac0f07801..29b1e4c825 100644 --- a/internal/execute/outputs.go +++ b/internal/execute/outputs.go @@ -134,9 +134,13 @@ func createReportErrorSummary(sys System, options *core.CompilerOptions) func(di return func(diagnostics []*ast.Diagnostic) {} } -func reportStatistics(sys System, program *compiler.Program, result compileAndEmitResult, memStats *runtime.MemStats) { +func reportStatistics(sys System, program *compiler.Program, result compileAndEmitResult, memStats *runtime.MemStats, testing CommandLineTesting) { var stats table + if testing != nil { + testing.OnStatisticsStart() + defer testing.OnStatisticsEnd() + } stats.add("Files", len(program.SourceFiles())) stats.add("Lines", program.LineCount()) stats.add("Identifiers", program.IdentifierCount()) diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index 271ea3b42e..00ab158335 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -111,7 +111,10 @@ type testSys struct { start time.Time } -var _ execute.System = (*testSys)(nil) +var ( + _ execute.System = (*testSys)(nil) + _ execute.CommandLineTesting = (*testSys)(nil) +) func (s *testSys) Now() time.Time { // todo: make a "test time" structure @@ -175,17 +178,20 @@ func (s *testSys) GetEnvironmentVariable(name string) string { return s.env[name] } -func sanitizeSysOutput(output string, prefixLine string, replaceString string) string { - for { - if index := strings.Index(output, prefixLine); index != -1 { - indexOfNewLine := strings.Index(output[index:], "\n") - if indexOfNewLine != -1 { - output = output[:index] + replaceString + output[index+indexOfNewLine+1:] - continue - } - } - return output - } +func (s *testSys) OnListFilesStart() { + fmt.Fprintln(s.Writer(), listFileStart) +} + +func (s *testSys) OnListFilesEnd() { + fmt.Fprintln(s.Writer(), listFileEnd) +} + +func (s *testSys) OnStatisticsStart() { + fmt.Fprintln(s.Writer(), statisticsStart) +} + +func (s *testSys) OnStatisticsEnd() { + fmt.Fprintln(s.Writer(), statisticsEnd) } func (s *testSys) baselineProgram(baseline *strings.Builder, program *incremental.Program, watcher *execute.Watcher) { @@ -241,17 +247,90 @@ func (s *testSys) serializeState(baseline *strings.Builder) { // this.service?.baseline(); } +var ( + fakeTimeStamp = "HH:MM:SS AM" + fakeDuration = "d.ddds" + + buildStartingAt = "build starting at " + buildFinishedIn = "build finished in " + listFileStart = "!!! List files start" + listFileEnd = "!!! List files end" + statisticsStart = "!!! Statistics start" + statisticsEnd = "!!! Statistics end" +) + func (s *testSys) baselineOutput(baseline io.Writer) { fmt.Fprint(baseline, "\nOutput::\n") - fmt.Fprint(baseline, s.getOutput()) + output := s.getOutput(false) + fmt.Fprint(baseline, output) +} + +type outputSanitizer struct { + forComparing bool + lines []string + index int + outputLines []string +} + +func (o *outputSanitizer) addOutputLine(s string) { + o.outputLines = append(o.outputLines, s) } -func (s *testSys) getOutput() string { - output := s.currentWrite.String() - output = sanitizeSysOutput(output, "Version "+core.Version(), "Version "+harnessutil.FakeTSVersion+"\n") - output = sanitizeSysOutput(output, "build starting at ", "") - output = sanitizeSysOutput(output, "build finished in ", "") - return output +func (o *outputSanitizer) transformLines() string { + for ; o.index < len(o.lines); o.index++ { + line := o.lines[o.index] + if change := strings.Replace(line, "Version "+core.Version(), "Version "+harnessutil.FakeTSVersion, 1); change != line { + o.addOutputLine(change) + continue + } + if strings.HasPrefix(line, buildStartingAt) { + if !o.forComparing { + o.addOutputLine(buildStartingAt + fakeTimeStamp) + } + continue + } + if strings.HasPrefix(line, buildFinishedIn) { + if !o.forComparing { + o.addOutputLine(buildFinishedIn + fakeDuration) + } + continue + } + if !o.addOrSkipLinesForComparing(listFileStart, listFileEnd, false) && + !o.addOrSkipLinesForComparing(statisticsStart, statisticsEnd, true) { + o.addOutputLine(line) + } + } + return strings.Join(o.outputLines, "\n") +} + +func (o *outputSanitizer) addOrSkipLinesForComparing( + lineStart string, + lineEnd string, + skipEvenIfNotComparing bool, +) bool { + if o.lines[o.index] != lineStart { + return false + } + o.index++ + for ; o.index < len(o.lines); o.index++ { + if o.lines[o.index] == lineEnd { + return true + } + if !o.forComparing && !skipEvenIfNotComparing { + o.addOutputLine(o.lines[o.index]) + } + } + panic("Expected lineEnd" + lineEnd + " not found after " + lineStart) +} + +func (s *testSys) getOutput(forComparing bool) string { + lines := strings.Split(s.currentWrite.String(), "\n") + transformer := &outputSanitizer{ + forComparing: forComparing, + lines: lines, + outputLines: make([]string, 0, len(lines)), + } + return transformer.transformLines() } func (s *testSys) clearOutput() { diff --git a/internal/execute/tsc.go b/internal/execute/tsc.go index 86dfe90331..a143c06077 100644 --- a/internal/execute/tsc.go +++ b/internal/execute/tsc.go @@ -21,8 +21,6 @@ import ( "github.com/microsoft/typescript-go/internal/tspath" ) -type cbType = func(p any) any - func applyBulkEdits(text string, edits []core.TextChange) string { b := strings.Builder{} b.Grow(len(text)) @@ -47,7 +45,14 @@ type CommandLineResult struct { Watcher *Watcher } -func CommandLine(sys System, commandLineArgs []string, testing bool) CommandLineResult { +type CommandLineTesting interface { + OnListFilesStart() + OnListFilesEnd() + OnStatisticsStart() + OnStatisticsEnd() +} + +func CommandLine(sys System, commandLineArgs []string, testing CommandLineTesting) CommandLineResult { if len(commandLineArgs) > 0 { // !!! build mode switch strings.ToLower(commandLineArgs[0]) { @@ -88,7 +93,7 @@ func fmtMain(sys System, input, output string) ExitStatus { return ExitStatusSuccess } -func tscCompilation(sys System, commandLine *tsoptions.ParsedCommandLine, testing bool) CommandLineResult { +func tscCompilation(sys System, commandLine *tsoptions.ParsedCommandLine, testing CommandLineTesting) CommandLineResult { configFileName := "" reportDiagnostic := createDiagnosticReporter(sys, commandLine.CompilerOptions()) // if commandLine.Options().Locale != nil @@ -205,6 +210,7 @@ func tscCompilation(sys System, commandLine *tsoptions.ParsedCommandLine, testin reportDiagnostic, &extendedConfigCache, configTime, + testing, ) } @@ -234,7 +240,7 @@ func performIncrementalCompilation( reportDiagnostic diagnosticReporter, extendedConfigCache *collections.SyncMap[tspath.Path, *tsoptions.ExtendedConfigCacheEntry], configTime time.Duration, - testing bool, + testing CommandLineTesting, ) CommandLineResult { host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache, getTraceFromSys(sys)) buildInfoReadStart := sys.Now() @@ -249,7 +255,7 @@ func performIncrementalCompilation( }) parseTime := sys.Now().Sub(parseStart) changesComputeStart := sys.Now() - incrementalProgram := incremental.NewProgram(program, oldProgram, testing) + incrementalProgram := incremental.NewProgram(program, oldProgram, testing != nil) changesComputeTime := sys.Now().Sub(changesComputeStart) return CommandLineResult{ Status: emitAndReportStatistics( @@ -263,6 +269,7 @@ func performIncrementalCompilation( buildInfoReadTime, changesComputeTime, + testing, ), IncrementalProgram: incrementalProgram, } @@ -274,6 +281,7 @@ func performCompilation( reportDiagnostic diagnosticReporter, extendedConfigCache *collections.SyncMap[tspath.Path, *tsoptions.ExtendedConfigCacheEntry], configTime time.Duration, + testing CommandLineTesting, ) CommandLineResult { host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache, getTraceFromSys(sys)) // todo: cache, statistics, tracing @@ -295,6 +303,7 @@ func performCompilation( parseTime, 0, 0, + testing, ), } } @@ -309,8 +318,9 @@ func emitAndReportStatistics( parseTime time.Duration, buildInfoReadTime time.Duration, changesComputeTime time.Duration, + testing CommandLineTesting, ) ExitStatus { - result := emitFilesAndReportErrors(sys, programLike, program, reportDiagnostic) + result := emitFilesAndReportErrors(sys, programLike, program, reportDiagnostic, testing) if result.status != ExitStatusSuccess { // compile exited early return result.status @@ -329,7 +339,7 @@ func emitAndReportStatistics( runtime.GC() runtime.ReadMemStats(&memStats) - reportStatistics(sys, program, result, &memStats) + reportStatistics(sys, program, result, &memStats, testing) } if result.emitResult.EmitSkipped && len(result.diagnostics) > 0 { @@ -359,6 +369,7 @@ func emitFilesAndReportErrors( programLike compiler.ProgramLike, program *compiler.Program, reportDiagnostic diagnosticReporter, + testing CommandLineTesting, ) (result compileAndEmitResult) { ctx := context.Background() @@ -399,12 +410,7 @@ func emitFilesAndReportErrors( reportDiagnostic(diagnostic) } - if sys.Writer() != nil { - for _, file := range emitResult.EmittedFiles { - fmt.Fprintln(sys.Writer(), "TSFILE: ", tspath.GetNormalizedAbsolutePath(file, sys.GetCurrentDirectory())) - } - listFiles(sys, program) - } + listFiles(sys, program, emitResult, testing) createReportErrorSummary(sys, programLike.Options())(allDiagnostics) result.diagnostics = allDiagnostics @@ -422,7 +428,14 @@ func showConfig(sys System, config *core.CompilerOptions) { _ = jsonutil.MarshalIndentWrite(sys.Writer(), config, "", " ") } -func listFiles(sys System, program *compiler.Program) { +func listFiles(sys System, program *compiler.Program, emitResult *compiler.EmitResult, testing CommandLineTesting) { + if testing != nil { + testing.OnListFilesStart() + defer testing.OnListFilesEnd() + } + for _, file := range emitResult.EmittedFiles { + fmt.Fprintln(sys.Writer(), "TSFILE: ", tspath.GetNormalizedAbsolutePath(file, sys.GetCurrentDirectory())) + } options := program.Options() if options.ExplainFiles.IsTrue() { program.ExplainFiles(sys.Writer()) diff --git a/internal/execute/tsctestrunner_test.go b/internal/execute/tsctestrunner_test.go index fe71a66ba5..d6546c7e06 100644 --- a/internal/execute/tsctestrunner_test.go +++ b/internal/execute/tsctestrunner_test.go @@ -41,7 +41,7 @@ type tscInput struct { func (test *tscInput) executeCommand(sys *testSys, baselineBuilder *strings.Builder, commandLineArgs []string) execute.CommandLineResult { fmt.Fprint(baselineBuilder, "tsgo ", strings.Join(commandLineArgs, " "), "\n") - result := execute.CommandLine(sys, commandLineArgs, true) + result := execute.CommandLine(sys, commandLineArgs, sys) switch result.Status { case execute.ExitStatusSuccess: baselineBuilder.WriteString("ExitStatus:: Success") @@ -111,7 +111,7 @@ func (test *tscInput) run(t *testing.T, scenario string) { test.edits[i].edit(nonIncrementalSys) } } - execute.CommandLine(nonIncrementalSys, commandLineArgs, true) + execute.CommandLine(nonIncrementalSys, commandLineArgs, nonIncrementalSys) }) wg.RunAndWait() @@ -160,8 +160,8 @@ func getDiffForIncremental(incrementalSys *testSys, nonIncrementalSys *testSys) } } - incrementalOutput := incrementalSys.getOutput() - nonIncrementalOutput := nonIncrementalSys.getOutput() + incrementalOutput := incrementalSys.getOutput(true) + nonIncrementalOutput := nonIncrementalSys.getOutput(true) if incrementalOutput != nonIncrementalOutput { diffBuilder.WriteString(baseline.DiffText("nonIncremental.output.txt", "incremental.output.txt", nonIncrementalOutput, incrementalOutput)) } diff --git a/internal/execute/watcher.go b/internal/execute/watcher.go index fddd321389..796a396022 100644 --- a/internal/execute/watcher.go +++ b/internal/execute/watcher.go @@ -19,7 +19,7 @@ type Watcher struct { configFileName string options *tsoptions.ParsedCommandLine reportDiagnostic diagnosticReporter - testing bool + testing CommandLineTesting host compiler.CompilerHost program *incremental.Program @@ -27,7 +27,7 @@ type Watcher struct { configModified bool } -func createWatcher(sys System, configParseResult *tsoptions.ParsedCommandLine, reportDiagnostic diagnosticReporter, testing bool) *Watcher { +func createWatcher(sys System, configParseResult *tsoptions.ParsedCommandLine, reportDiagnostic diagnosticReporter, testing CommandLineTesting) *Watcher { w := &Watcher{ sys: sys, options: configParseResult, @@ -45,7 +45,7 @@ func (w *Watcher) start() { w.host = compiler.NewCompilerHost(w.sys.GetCurrentDirectory(), w.sys.FS(), w.sys.DefaultLibraryPath(), nil, getTraceFromSys(w.sys)) w.program = incremental.ReadBuildInfoProgram(w.options, incremental.NewBuildInfoReader(w.host), w.host) - if !w.testing { + if w.testing == nil { watchInterval := 1000 * time.Millisecond if w.options.ParsedConfig.WatchOptions != nil { watchInterval = time.Duration(*w.options.ParsedConfig.WatchOptions.Interval) * time.Millisecond @@ -72,7 +72,7 @@ func (w *Watcher) DoCycle() { Config: w.options, Host: w.host, JSDocParsingMode: ast.JSDocParsingModeParseForTypeErrors, - }), w.program, w.testing) + }), w.program, w.testing != nil) if w.hasBeenModified(w.program.GetProgram()) { fmt.Fprintln(w.sys.Writer(), "build starting at ", w.sys.Now()) @@ -88,7 +88,7 @@ func (w *Watcher) DoCycle() { func (w *Watcher) compileAndEmit() { // !!! output/error reporting is currently the same as non-watch mode // diagnostics, emitResult, exitStatus := - emitFilesAndReportErrors(w.sys, w.program, w.program.GetProgram(), w.reportDiagnostic) + emitFilesAndReportErrors(w.sys, w.program, w.program.GetProgram(), w.reportDiagnostic, w.testing) } func (w *Watcher) hasErrorsInTsConfig() bool { diff --git a/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js b/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js index 70411b9b3a..9bbaffbc42 100644 --- a/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js +++ b/testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js @@ -6,7 +6,7 @@ tsgo ExitStatus:: DiagnosticsPresent_OutputsSkipped Output:: Version FakeTSVersion -tsc: The TypeScript Compiler - Version FakeTSVersion +tsc: The TypeScript Compiler - Version FakeTSVersion    TS  COMMON COMMANDS diff --git a/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option.js b/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option.js index 257321f12f..ee2b9ae875 100644 --- a/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option.js +++ b/testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option.js @@ -14,6 +14,8 @@ export const a = 1 tsgo -w --watchInterval 1000 ExitStatus:: Success Output:: +build starting at HH:MM:SS AM +build finished in d.ddds //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* /// interface Boolean {} diff --git a/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-no-tsconfig.js b/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-no-tsconfig.js index fcf71f7645..522610da63 100644 --- a/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-no-tsconfig.js +++ b/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-no-tsconfig.js @@ -7,6 +7,8 @@ Input:: tsgo index.ts --watch ExitStatus:: Success Output:: +build starting at HH:MM:SS AM +build finished in d.ddds //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* /// interface Boolean {} diff --git a/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-tsconfig-and-incremental.js b/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-tsconfig-and-incremental.js index 6c12462d05..67055b1897 100644 --- a/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-tsconfig-and-incremental.js +++ b/testdata/baselines/reference/tscWatch/commandLineWatch/watch-with-tsconfig-and-incremental.js @@ -9,6 +9,8 @@ Input:: tsgo --watch --incremental ExitStatus:: Success Output:: +build starting at HH:MM:SS AM +build finished in d.ddds //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* /// interface Boolean {} diff --git a/testdata/baselines/reference/tscWatch/noEmit/dts-errors-without-dts-enabled.js b/testdata/baselines/reference/tscWatch/noEmit/dts-errors-without-dts-enabled.js index 7f69e1ad38..44b0893a86 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/dts-errors-without-dts-enabled.js +++ b/testdata/baselines/reference/tscWatch/noEmit/dts-errors-without-dts-enabled.js @@ -13,6 +13,8 @@ const a = class { private p = 10; }; tsgo -w ExitStatus:: Success Output:: +build starting at HH:MM:SS AM +build finished in d.ddds //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* /// interface Boolean {} @@ -50,6 +52,8 @@ const a = "hello"; Output:: +build starting at HH:MM:SS AM +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -69,6 +73,8 @@ Edit [1]:: emit after fixing error Output:: +build starting at HH:MM:SS AM +build finished in d.ddds //// [/home/src/workspaces/project/a.js] *new* const a = "hello"; @@ -89,6 +95,8 @@ Edit [2]:: no emit run after fixing error Output:: +build starting at HH:MM:SS AM +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -101,6 +109,8 @@ const a = class { private p = 10; }; Output:: +build starting at HH:MM:SS AM +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -120,6 +130,8 @@ Edit [4]:: emit when error Output:: +build starting at HH:MM:SS AM +build finished in d.ddds //// [/home/src/workspaces/project/a.js] *modified* const a = class { p = 10; @@ -142,6 +154,8 @@ Edit [5]:: no emit run when error Output:: +build starting at HH:MM:SS AM +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: diff --git a/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js b/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js index b77ca27b24..7b11ad2b8d 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/dts-errors.js @@ -14,6 +14,7 @@ const a = class { private p = 10; }; tsgo -w ExitStatus:: Success Output:: +build starting at HH:MM:SS AM a.ts:1:7 - error TS4094: Property 'p' of exported anonymous class type may not be private or protected. 1 const a = class { private p = 10; }; @@ -26,6 +27,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* /// interface Boolean {} @@ -63,6 +65,8 @@ const a = "hello"; Output:: +build starting at HH:MM:SS AM +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -82,6 +86,8 @@ Edit [1]:: emit after fixing error Output:: +build starting at HH:MM:SS AM +build finished in d.ddds //// [/home/src/workspaces/project/a.d.ts] *new* declare const a = "hello"; @@ -105,6 +111,8 @@ Edit [2]:: no emit run after fixing error Output:: +build starting at HH:MM:SS AM +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -117,6 +125,7 @@ const a = class { private p = 10; }; Output:: +build starting at HH:MM:SS AM a.ts:1:7 - error TS4094: Property 'p' of exported anonymous class type may not be private or protected. 1 const a = class { private p = 10; }; @@ -129,6 +138,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -148,6 +158,7 @@ Edit [4]:: emit when error Output:: +build starting at HH:MM:SS AM a.ts:1:7 - error TS4094: Property 'p' of exported anonymous class type may not be private or protected. 1 const a = class { private p = 10; }; @@ -160,6 +171,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds //// [/home/src/workspaces/project/a.d.ts] *modified* declare const a: { new (): { @@ -189,6 +201,7 @@ Edit [5]:: no emit run when error Output:: +build starting at HH:MM:SS AM a.ts:1:7 - error TS4094: Property 'p' of exported anonymous class type may not be private or protected. 1 const a = class { private p = 10; }; @@ -201,6 +214,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: diff --git a/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js b/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js index a8b9727d1c..2fbce1bdd8 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/semantic-errors.js @@ -13,6 +13,7 @@ const a: number = "hello" tsgo -w ExitStatus:: Success Output:: +build starting at HH:MM:SS AM a.ts:1:7 - error TS2322: Type 'string' is not assignable to type 'number'. 1 const a: number = "hello" @@ -21,6 +22,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* /// interface Boolean {} @@ -58,6 +60,8 @@ const a = "hello"; Output:: +build starting at HH:MM:SS AM +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -77,6 +81,8 @@ Edit [1]:: emit after fixing error Output:: +build starting at HH:MM:SS AM +build finished in d.ddds //// [/home/src/workspaces/project/a.js] *new* const a = "hello"; @@ -97,6 +103,8 @@ Edit [2]:: no emit run after fixing error Output:: +build starting at HH:MM:SS AM +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -109,6 +117,7 @@ const a: number = "hello" Output:: +build starting at HH:MM:SS AM a.ts:1:7 - error TS2322: Type 'string' is not assignable to type 'number'. 1 const a: number = "hello" @@ -117,6 +126,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -136,6 +146,7 @@ Edit [4]:: emit when error Output:: +build starting at HH:MM:SS AM a.ts:1:7 - error TS2322: Type 'string' is not assignable to type 'number'. 1 const a: number = "hello" @@ -144,6 +155,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds //// [/home/src/workspaces/project/a.js] *rewrite with same content* tsconfig.json:: @@ -162,6 +174,7 @@ Edit [5]:: no emit run when error Output:: +build starting at HH:MM:SS AM a.ts:1:7 - error TS2322: Type 'string' is not assignable to type 'number'. 1 const a: number = "hello" @@ -170,6 +183,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: diff --git a/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js b/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js index 1622804cd9..7139f74304 100644 --- a/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js +++ b/testdata/baselines/reference/tscWatch/noEmit/syntax-errors.js @@ -13,6 +13,7 @@ const a = "hello tsgo -w ExitStatus:: Success Output:: +build starting at HH:MM:SS AM a.ts:1:17 - error TS1002: Unterminated string literal. 1 const a = "hello @@ -21,6 +22,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds //// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib* /// interface Boolean {} @@ -58,6 +60,8 @@ const a = "hello"; Output:: +build starting at HH:MM:SS AM +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -77,6 +81,8 @@ Edit [1]:: emit after fixing error Output:: +build starting at HH:MM:SS AM +build finished in d.ddds //// [/home/src/workspaces/project/a.js] *new* const a = "hello"; @@ -97,6 +103,8 @@ Edit [2]:: no emit run after fixing error Output:: +build starting at HH:MM:SS AM +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -109,6 +117,7 @@ const a = "hello Output:: +build starting at HH:MM:SS AM a.ts:1:17 - error TS1002: Unterminated string literal. 1 const a = "hello @@ -117,6 +126,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: @@ -134,6 +144,7 @@ Edit [4]:: emit when error Output:: +build starting at HH:MM:SS AM a.ts:1:17 - error TS1002: Unterminated string literal. 1 const a = "hello @@ -142,6 +153,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds //// [/home/src/workspaces/project/a.js] *modified* const a = "hello; @@ -164,6 +176,7 @@ Edit [5]:: no emit run when error Output:: +build starting at HH:MM:SS AM a.ts:1:17 - error TS1002: Unterminated string literal. 1 const a = "hello @@ -172,6 +185,7 @@ Output:: Found 1 error in a.ts:1 +build finished in d.ddds tsconfig.json:: SemanticDiagnostics:: From d8ca80e3fcfa3227fefca916692fa6ba5ac22652 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 14 Aug 2025 12:21:38 -0700 Subject: [PATCH 13/18] sanitize tracing in tsc tests --- internal/execute/testsys_test.go | 26 +++++++++-- internal/execute/tsc.go | 15 ++++-- internal/execute/watcher.go | 6 +-- internal/testutil/harnessutil/harnessutil.go | 48 +++++++++++++------- 4 files changed, 66 insertions(+), 29 deletions(-) diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index 00ab158335..f96bcba2c2 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -63,6 +63,7 @@ func newTestSys(tscInput *tscInput) *testSys { if tscInput.windowsStyleRoot != "" { libPath = tscInput.windowsStyleRoot + libPath[1:] } + currentWrite := &strings.Builder{} sys := &testSys{ fs: &incrementaltestutil.FsHandlingBuildInfo{ FS: &testFs{ @@ -71,9 +72,13 @@ func newTestSys(tscInput *tscInput) *testSys { }, defaultLibraryPath: libPath, cwd: cwd, - currentWrite: &strings.Builder{}, - start: time.Now(), - env: tscInput.env, + currentWrite: currentWrite, + tracer: harnessutil.NewTracerForBaselining(tspath.ComparePathsOptions{ + UseCaseSensitiveFileNames: !tscInput.ignoreCase, + CurrentDirectory: cwd, + }, currentWrite), + start: time.Now(), + env: tscInput.env, } // Ensure the default library file is present @@ -101,6 +106,7 @@ type snapshot struct { type testSys struct { currentWrite *strings.Builder + tracer *harnessutil.TracerForBaselining serializedDiff *snapshot fs *incrementaltestutil.FsHandlingBuildInfo @@ -194,6 +200,14 @@ func (s *testSys) OnStatisticsEnd() { fmt.Fprintln(s.Writer(), statisticsEnd) } +func (s *testSys) GetTrace() func(str string) { + return func(str string) { + fmt.Fprintln(s.currentWrite, traceStart) + defer fmt.Fprintln(s.currentWrite, traceEnd) + s.tracer.Trace(str) + } +} + func (s *testSys) baselineProgram(baseline *strings.Builder, program *incremental.Program, watcher *execute.Watcher) { if watcher != nil { program = watcher.GetProgram() @@ -257,6 +271,8 @@ var ( listFileEnd = "!!! List files end" statisticsStart = "!!! Statistics start" statisticsEnd = "!!! Statistics end" + traceStart = "!!! Trace start" + traceEnd = "!!! Trace end" ) func (s *testSys) baselineOutput(baseline io.Writer) { @@ -296,7 +312,8 @@ func (o *outputSanitizer) transformLines() string { continue } if !o.addOrSkipLinesForComparing(listFileStart, listFileEnd, false) && - !o.addOrSkipLinesForComparing(statisticsStart, statisticsEnd, true) { + !o.addOrSkipLinesForComparing(statisticsStart, statisticsEnd, true) && + !o.addOrSkipLinesForComparing(traceStart, traceEnd, false) { o.addOutputLine(line) } } @@ -335,6 +352,7 @@ func (s *testSys) getOutput(forComparing bool) string { func (s *testSys) clearOutput() { s.currentWrite.Reset() + s.tracer.Reset() } func (s *testSys) baselineFSwithDiff(baseline io.Writer) { diff --git a/internal/execute/tsc.go b/internal/execute/tsc.go index a143c06077..066685a34e 100644 --- a/internal/execute/tsc.go +++ b/internal/execute/tsc.go @@ -50,6 +50,7 @@ type CommandLineTesting interface { OnListFilesEnd() OnStatisticsStart() OnStatisticsEnd() + GetTrace() func(str string) } func CommandLine(sys System, commandLineArgs []string, testing CommandLineTesting) CommandLineResult { @@ -228,9 +229,13 @@ func findConfigFile(searchPath string, fileExists func(string) bool, configName return result } -func getTraceFromSys(sys System) func(msg string) { - return func(msg string) { - fmt.Fprintln(sys.Writer(), msg) +func getTraceFromSys(sys System, testing CommandLineTesting) func(msg string) { + if testing == nil { + return func(msg string) { + fmt.Fprintln(sys.Writer(), msg) + } + } else { + return testing.GetTrace() } } @@ -242,7 +247,7 @@ func performIncrementalCompilation( configTime time.Duration, testing CommandLineTesting, ) CommandLineResult { - host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache, getTraceFromSys(sys)) + host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache, getTraceFromSys(sys, testing)) buildInfoReadStart := sys.Now() oldProgram := incremental.ReadBuildInfoProgram(config, incremental.NewBuildInfoReader(host), host) buildInfoReadTime := sys.Now().Sub(buildInfoReadStart) @@ -283,7 +288,7 @@ func performCompilation( configTime time.Duration, testing CommandLineTesting, ) CommandLineResult { - host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache, getTraceFromSys(sys)) + host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache, getTraceFromSys(sys, testing)) // todo: cache, statistics, tracing parseStart := sys.Now() program := compiler.NewProgram(compiler.ProgramOptions{ diff --git a/internal/execute/watcher.go b/internal/execute/watcher.go index 796a396022..738c24ae17 100644 --- a/internal/execute/watcher.go +++ b/internal/execute/watcher.go @@ -42,7 +42,7 @@ func createWatcher(sys System, configParseResult *tsoptions.ParsedCommandLine, r } func (w *Watcher) start() { - w.host = compiler.NewCompilerHost(w.sys.GetCurrentDirectory(), w.sys.FS(), w.sys.DefaultLibraryPath(), nil, getTraceFromSys(w.sys)) + w.host = compiler.NewCompilerHost(w.sys.GetCurrentDirectory(), w.sys.FS(), w.sys.DefaultLibraryPath(), nil, getTraceFromSys(w.sys, w.testing)) w.program = incremental.ReadBuildInfoProgram(w.options, incremental.NewBuildInfoReader(w.host), w.host) if w.testing == nil { @@ -93,8 +93,8 @@ func (w *Watcher) compileAndEmit() { func (w *Watcher) hasErrorsInTsConfig() bool { // only need to check and reparse tsconfig options/update host if we are watching a config file + extendedConfigCache := collections.SyncMap[tspath.Path, *tsoptions.ExtendedConfigCacheEntry]{} if w.configFileName != "" { - extendedConfigCache := collections.SyncMap[tspath.Path, *tsoptions.ExtendedConfigCacheEntry]{} // !!! need to check that this merges compileroptions correctly. This differs from non-watch, since we allow overriding of previous options configParseResult, errors := tsoptions.GetParsedCommandLineOfConfigFile(w.configFileName, &core.CompilerOptions{}, w.sys, &extendedConfigCache) if len(errors) > 0 { @@ -109,8 +109,8 @@ func (w *Watcher) hasErrorsInTsConfig() bool { w.configModified = true } w.options = configParseResult - w.host = compiler.NewCompilerHost(w.sys.GetCurrentDirectory(), w.sys.FS(), w.sys.DefaultLibraryPath(), &extendedConfigCache, getTraceFromSys(w.sys)) } + w.host = compiler.NewCompilerHost(w.sys.GetCurrentDirectory(), w.sys.FS(), w.sys.DefaultLibraryPath(), &extendedConfigCache, getTraceFromSys(w.sys, w.testing)) return false } diff --git a/internal/testutil/harnessutil/harnessutil.go b/internal/testutil/harnessutil/harnessutil.go index 804a18e137..b885996dea 100644 --- a/internal/testutil/harnessutil/harnessutil.go +++ b/internal/testutil/harnessutil/harnessutil.go @@ -223,7 +223,7 @@ func CompileFilesEx( Errors: errors, }, harnessOptions) result.Symlinks = symlinks - result.Trace = host.tracer.string() + result.Trace = host.tracer.String() result.Repeat = func(testConfig TestConfiguration) *CompilationResult { newHarnessOptions := *harnessOptions newCompilerOptions := compilerOptions.Clone() @@ -474,7 +474,7 @@ func getOptionValue(t *testing.T, option *tsoptions.CommandLineOption, value str type cachedCompilerHost struct { compiler.CompilerHost - tracer *tracer + tracer *TracerForBaselining } var sourceFileCache collections.SyncMap[SourceFileCacheKey, *ast.SourceFile] @@ -515,18 +515,25 @@ func (h *cachedCompilerHost) GetSourceFile(opts ast.SourceFileParseOptions) *ast return result } -type tracer struct { - fs vfs.FS - currentDirectory string +type TracerForBaselining struct { + opts tspath.ComparePathsOptions packageJsonCache map[tspath.Path]bool - builder strings.Builder + builder *strings.Builder } -func (t *tracer) trace(msg string) { - fmt.Fprintln(&t.builder, t.sanitizeTrace(msg)) +func NewTracerForBaselining(opts tspath.ComparePathsOptions, builder *strings.Builder) *TracerForBaselining { + return &TracerForBaselining{ + opts: opts, + packageJsonCache: make(map[tspath.Path]bool), + builder: builder, + } +} + +func (t *TracerForBaselining) Trace(msg string) { + fmt.Fprintln(t.builder, t.sanitizeTrace(msg)) } -func (t *tracer) sanitizeTrace(msg string) string { +func (t *TracerForBaselining) sanitizeTrace(msg string) string { // Version if str := strings.Replace(msg, "'"+core.Version()+"'", "'"+FakeTSVersion+"'", 1); str != msg { return str @@ -534,7 +541,7 @@ func (t *tracer) sanitizeTrace(msg string) string { // caching of fs in trace to be replaces with non caching version if str := strings.TrimSuffix(msg, "' does not exist according to earlier cached lookups."); str != msg { file := strings.TrimPrefix(str, "File '") - filePath := tspath.ToPath(file, t.currentDirectory, t.fs.UseCaseSensitiveFileNames()) + filePath := tspath.ToPath(file, t.opts.CurrentDirectory, t.opts.UseCaseSensitiveFileNames) if _, has := t.packageJsonCache[filePath]; has { return msg } else { @@ -544,7 +551,7 @@ func (t *tracer) sanitizeTrace(msg string) string { } if str := strings.TrimSuffix(msg, "' does not exist."); str != msg { file := strings.TrimPrefix(str, "File '") - filePath := tspath.ToPath(file, t.currentDirectory, t.fs.UseCaseSensitiveFileNames()) + filePath := tspath.ToPath(file, t.opts.CurrentDirectory, t.opts.UseCaseSensitiveFileNames) if _, has := t.packageJsonCache[filePath]; !has { t.packageJsonCache[filePath] = false return msg @@ -554,7 +561,7 @@ func (t *tracer) sanitizeTrace(msg string) string { } if str := strings.TrimSuffix(msg, "' exists according to earlier cached lookups."); str != msg { file := strings.TrimPrefix(str, "File '") - filePath := tspath.ToPath(file, t.currentDirectory, t.fs.UseCaseSensitiveFileNames()) + filePath := tspath.ToPath(file, t.opts.CurrentDirectory, t.opts.UseCaseSensitiveFileNames) if _, has := t.packageJsonCache[filePath]; has { return msg } else { @@ -564,7 +571,7 @@ func (t *tracer) sanitizeTrace(msg string) string { } if str := strings.TrimPrefix(msg, "Found 'package.json' at '"); str != msg { file := strings.TrimSuffix(str, "'.") - filePath := tspath.ToPath(file, t.currentDirectory, t.fs.UseCaseSensitiveFileNames()) + filePath := tspath.ToPath(file, t.opts.CurrentDirectory, t.opts.UseCaseSensitiveFileNames) if _, has := t.packageJsonCache[filePath]; !has { t.packageJsonCache[filePath] = true return msg @@ -575,15 +582,22 @@ func (t *tracer) sanitizeTrace(msg string) string { return msg } -func (t *tracer) string() string { +func (t *TracerForBaselining) String() string { return t.builder.String() } +func (t *TracerForBaselining) Reset() { + t.packageJsonCache = make(map[tspath.Path]bool) +} + func createCompilerHost(fs vfs.FS, defaultLibraryPath string, currentDirectory string) *cachedCompilerHost { - tracer := tracer{fs: fs, currentDirectory: currentDirectory, packageJsonCache: make(map[tspath.Path]bool)} + tracer := NewTracerForBaselining(tspath.ComparePathsOptions{ + UseCaseSensitiveFileNames: fs.UseCaseSensitiveFileNames(), + CurrentDirectory: currentDirectory, + }, &strings.Builder{}) return &cachedCompilerHost{ - CompilerHost: compiler.NewCompilerHost(currentDirectory, fs, defaultLibraryPath, nil, tracer.trace), - tracer: &tracer, + CompilerHost: compiler.NewCompilerHost(currentDirectory, fs, defaultLibraryPath, nil, tracer.Trace), + tracer: tracer, } } From b09de2736b4bdc67911aa78fb3d2fb5993082dc5 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 14 Aug 2025 10:24:37 -0700 Subject: [PATCH 14/18] Dont add "/" to path when walking windows os --- internal/vfs/internal/internal.go | 6 +++++- internal/vfs/vfstest/vfstest_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/internal/vfs/internal/internal.go b/internal/vfs/internal/internal.go index c761e20388..26be39b836 100644 --- a/internal/vfs/internal/internal.go +++ b/internal/vfs/internal/internal.go @@ -132,7 +132,11 @@ func (vfs *Common) WalkDir(root string, walkFn fs.WalkDirFunc) error { if path == "." { path = "" } - return walkFn(rootName+path, d, err) + walkPath := rootName + path + if rest, ok := strings.CutPrefix(walkPath, "/"); ok && tspath.PathIsAbsolute(rest) { + walkPath = rest + } + return walkFn(walkPath, d, err) }) } diff --git a/internal/vfs/vfstest/vfstest_test.go b/internal/vfs/vfstest/vfstest_test.go index a0c0da026a..b211a7f593 100644 --- a/internal/vfs/vfstest/vfstest_test.go +++ b/internal/vfs/vfstest/vfstest_test.go @@ -332,6 +332,20 @@ func TestFromMap(t *testing.T) { content, ok = fs.ReadFile("/mapfile") assert.Assert(t, ok) assert.Equal(t, content, "hello, world") + + var files []string + err := fs.WalkDir("/", func(path string, d vfs.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() { + files = append(files, path) + } + return nil + }) + assert.NilError(t, err) + slices.Sort(files) + assert.DeepEqual(t, files, []string{"/bytes", "/mapfile", "/string"}) }) t.Run("Windows", func(t *testing.T) { @@ -356,6 +370,20 @@ func TestFromMap(t *testing.T) { content, ok = fs.ReadFile("e:/mapfile") assert.Assert(t, ok) assert.Equal(t, content, "hello, world") + + var files []string + err := fs.WalkDir("/", func(path string, d vfs.DirEntry, err error) error { + if err != nil { + return err + } + if !d.IsDir() { + files = append(files, path) + } + return nil + }) + assert.NilError(t, err) + slices.Sort(files) + assert.DeepEqual(t, files, []string{"c:/string", "d:/bytes", "e:/mapfile"}) }) t.Run("Mixed", func(t *testing.T) { From c781a1786df5bf528d73e17b4e011add8c665d46 Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Tue, 12 Aug 2025 16:26:01 -0700 Subject: [PATCH 15/18] Add clock implementation to vfs and tsc test --- internal/execute/testsys_test.go | 40 ++++++++++++++++---- internal/vfs/vfstest/vfstest.go | 56 ++++++++++++++++++++++++---- internal/vfs/vfstest/vfstest_test.go | 12 +++--- 3 files changed, 86 insertions(+), 22 deletions(-) diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index f96bcba2c2..1b80379bcf 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -9,6 +9,7 @@ import ( "slices" "strconv" "strings" + "sync" "time" "github.com/microsoft/typescript-go/internal/collections" @@ -54,6 +55,26 @@ interface Symbol { declare const console: { log(msg: any): void; }; `) +type TestClock struct { + start time.Time + now time.Time + nowMu sync.Mutex +} + +func (t *TestClock) Now() time.Time { + t.nowMu.Lock() + defer t.nowMu.Unlock() + if t.now.IsZero() { + t.now = t.start + } + t.now = t.now.Add(1 * time.Second) // Simulate some time passing + return t.now +} + +func (t *TestClock) SinceStart() time.Duration { + return t.Now().Sub(t.start) +} + func newTestSys(tscInput *tscInput) *testSys { cwd := tscInput.cwd if cwd == "" { @@ -64,10 +85,11 @@ func newTestSys(tscInput *tscInput) *testSys { libPath = tscInput.windowsStyleRoot + libPath[1:] } currentWrite := &strings.Builder{} + clock := &TestClock{start: time.Now()} sys := &testSys{ fs: &incrementaltestutil.FsHandlingBuildInfo{ FS: &testFs{ - FS: vfstest.FromMap(tscInput.files, !tscInput.ignoreCase), + FS: vfstest.FromMapWithClock(tscInput.files, !tscInput.ignoreCase, clock), }, }, defaultLibraryPath: libPath, @@ -77,7 +99,7 @@ func newTestSys(tscInput *tscInput) *testSys { UseCaseSensitiveFileNames: !tscInput.ignoreCase, CurrentDirectory: cwd, }, currentWrite), - start: time.Now(), + clock: clock, env: tscInput.env, } @@ -113,8 +135,7 @@ type testSys struct { defaultLibraryPath string cwd string env map[string]string - - start time.Time + clock *TestClock } var ( @@ -123,12 +144,11 @@ var ( ) func (s *testSys) Now() time.Time { - // todo: make a "test time" structure - return time.Now() + return s.clock.Now() } func (s *testSys) SinceStart() time.Duration { - return time.Since(s.start) + return s.clock.SinceStart() } func (s *testSys) FS() vfs.FS { @@ -143,6 +163,10 @@ func (s *testSys) fsFromFileMap() iovfs.FsWithSys { return s.testFs().FS.(iovfs.FsWithSys) } +func (s *testSys) mapFs() *vfstest.MapFS { + return s.fsFromFileMap().FSys().(*vfstest.MapFS) +} + func (s *testSys) ensureLibPathExists(path string) { path = s.defaultLibraryPath + "/" + path if _, ok := s.fsFromFileMap().ReadFile(path); !ok { @@ -368,7 +392,7 @@ func (s *testSys) baselineFSwithDiff(baseline io.Writer) { fileInfo := d.Type() if fileInfo&fs.ModeSymlink != 0 { - target, ok := s.fsFromFileMap().FSys().(*vfstest.MapFS).GetTargetOfSymlink(path) + target, ok := s.mapFs().GetTargetOfSymlink(path) if !ok { panic("Failed to resolve symlink target: " + path) } diff --git a/internal/vfs/vfstest/vfstest.go b/internal/vfs/vfstest/vfstest.go index 84a96c685f..87ba0f9031 100644 --- a/internal/vfs/vfstest/vfstest.go +++ b/internal/vfs/vfstest/vfstest.go @@ -28,6 +28,25 @@ type MapFS struct { useCaseSensitiveFileNames bool symlinks map[canonicalPath]canonicalPath + + clock Clock +} + +type Clock interface { + Now() time.Time + SinceStart() time.Duration +} + +type clockImpl struct { + start time.Time +} + +func (c *clockImpl) Now() time.Time { + return time.Now() +} + +func (c *clockImpl) SinceStart() time.Duration { + return time.Since(c.start) } var ( @@ -47,6 +66,16 @@ type sys struct { // without trailing directory separators. // The paths must be all POSIX-style or all Windows-style, but not both. func FromMap[File any](m map[string]File, useCaseSensitiveFileNames bool) vfs.FS { + return FromMapWithClock(m, useCaseSensitiveFileNames, &clockImpl{start: time.Now()}) +} + +// FromMap creates a new [vfs.FS] from a map of paths to file contents. +// Those file contents may be strings, byte slices, or [fstest.MapFile]s. +// +// The paths must be normalized absolute paths according to the tspath package, +// without trailing directory separators. +// The paths must be all POSIX-style or all Windows-style, but not both. +func FromMapWithClock[File any](m map[string]File, useCaseSensitiveFileNames bool, clock Clock) vfs.FS { posix := false windows := false @@ -67,17 +96,23 @@ func FromMap[File any](m map[string]File, useCaseSensitiveFileNames bool) vfs.FS } mfs := make(fstest.MapFS, len(m)) - for p, f := range m { + // Sorted creation to ensure times are always guaranteed to be in order. + keys := slices.Collect(maps.Keys(m)) + slices.SortFunc(keys, comparePathsByParts) + for _, p := range keys { + f := m[p] checkPath(p) var file *fstest.MapFile switch f := any(f).(type) { case string: - file = &fstest.MapFile{Data: []byte(f)} + file = &fstest.MapFile{Data: []byte(f), ModTime: clock.Now()} case []byte: - file = &fstest.MapFile{Data: f} + file = &fstest.MapFile{Data: f, ModTime: clock.Now()} case *fstest.MapFile: - file = f + fCopy := *f + fCopy.ModTime = clock.Now() + file = &fCopy default: panic(fmt.Sprintf("invalid file type %T", f)) } @@ -100,13 +135,17 @@ func FromMap[File any](m map[string]File, useCaseSensitiveFileNames bool) vfs.FS panic("mixed posix and windows paths") } - return iovfs.From(convertMapFS(mfs, useCaseSensitiveFileNames), useCaseSensitiveFileNames) + return iovfs.From(convertMapFS(mfs, useCaseSensitiveFileNames, clock), useCaseSensitiveFileNames) } -func convertMapFS(input fstest.MapFS, useCaseSensitiveFileNames bool) *MapFS { +func convertMapFS(input fstest.MapFS, useCaseSensitiveFileNames bool, clock Clock) *MapFS { + if clock == nil { + clock = &clockImpl{start: time.Now()} + } m := &MapFS{ m: make(fstest.MapFS, len(input)), useCaseSensitiveFileNames: useCaseSensitiveFileNames, + clock: clock, } // Verify that the input is well-formed. @@ -320,7 +359,8 @@ func (m *MapFS) mkdirAll(p string, perm fs.FileMode) error { for _, dir := range toCreate { m.setEntry(dir, m.getCanonicalPath(dir), fstest.MapFile{ - Mode: fs.ModeDir | perm&^umask, + Mode: fs.ModeDir | perm&^umask, + ModTime: m.clock.Now(), }) } @@ -482,7 +522,7 @@ func (m *MapFS) WriteFile(path string, data []byte, perm fs.FileMode) error { m.setEntry(path, cp, fstest.MapFile{ Data: data, - ModTime: time.Now(), + ModTime: m.clock.Now(), Mode: perm &^ umask, }) diff --git a/internal/vfs/vfstest/vfstest_test.go b/internal/vfs/vfstest/vfstest_test.go index b211a7f593..a582b4d0de 100644 --- a/internal/vfs/vfstest/vfstest_test.go +++ b/internal/vfs/vfstest/vfstest_test.go @@ -34,7 +34,7 @@ func TestInsensitive(t *testing.T) { Data: contents, Sys: 1234, }, - }, false /*useCaseSensitiveFileNames*/) + }, false /*useCaseSensitiveFileNames*/, nil) sensitive, err := fs.ReadFile(vfs, "foo/bar/baz") assert.NilError(t, err) @@ -97,7 +97,7 @@ func TestInsensitiveUpper(t *testing.T) { Data: contents, Sys: 1234, }, - }, false /*useCaseSensitiveFileNames*/) + }, false /*useCaseSensitiveFileNames*/, nil) sensitive, err := fs.ReadFile(vfs, "foo/bar/baz") assert.NilError(t, err) @@ -142,7 +142,7 @@ func TestSensitive(t *testing.T) { Data: contents, Sys: 1234, }, - }, true /*useCaseSensitiveFileNames*/) + }, true /*useCaseSensitiveFileNames*/, nil) sensitive, err := fs.ReadFile(vfs, "foo/bar/baz") assert.NilError(t, err) @@ -170,7 +170,7 @@ func TestSensitiveDuplicatePath(t *testing.T) { } testutil.AssertPanics(t, func() { - convertMapFS(testfs, false /*useCaseSensitiveFileNames*/) + convertMapFS(testfs, false /*useCaseSensitiveFileNames*/, nil) }, `duplicate path: "Foo" and "foo" have the same canonical path`) } @@ -186,7 +186,7 @@ func TestInsensitiveDuplicatePath(t *testing.T) { }, } - convertMapFS(testfs, true /*useCaseSensitiveFileNames*/) + convertMapFS(testfs, true /*useCaseSensitiveFileNames*/, nil) } func dirEntriesToNames(entries []fs.DirEntry) []string { @@ -303,7 +303,7 @@ func TestParentDirFile(t *testing.T) { } testutil.AssertPanics(t, func() { - convertMapFS(testfs, false /*useCaseSensitiveFileNames*/) + convertMapFS(testfs, false /*useCaseSensitiveFileNames*/, nil) }, `failed to create intermediate directories for "foo/oops": mkdir "foo": path exists but is not a directory`) } From edde1e1ad03b22120c2592cdeeac05551084896d Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 14 Aug 2025 14:25:02 -0700 Subject: [PATCH 16/18] Revert "Dont add "/" to path when walking windows os" This reverts commit 65194a77bfb747e8e11211dfbf1f6e7f4d606d45. --- internal/vfs/internal/internal.go | 6 +----- internal/vfs/vfstest/vfstest_test.go | 28 ---------------------------- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/internal/vfs/internal/internal.go b/internal/vfs/internal/internal.go index 26be39b836..c761e20388 100644 --- a/internal/vfs/internal/internal.go +++ b/internal/vfs/internal/internal.go @@ -132,11 +132,7 @@ func (vfs *Common) WalkDir(root string, walkFn fs.WalkDirFunc) error { if path == "." { path = "" } - walkPath := rootName + path - if rest, ok := strings.CutPrefix(walkPath, "/"); ok && tspath.PathIsAbsolute(rest) { - walkPath = rest - } - return walkFn(walkPath, d, err) + return walkFn(rootName+path, d, err) }) } diff --git a/internal/vfs/vfstest/vfstest_test.go b/internal/vfs/vfstest/vfstest_test.go index a582b4d0de..0e2337fb84 100644 --- a/internal/vfs/vfstest/vfstest_test.go +++ b/internal/vfs/vfstest/vfstest_test.go @@ -332,20 +332,6 @@ func TestFromMap(t *testing.T) { content, ok = fs.ReadFile("/mapfile") assert.Assert(t, ok) assert.Equal(t, content, "hello, world") - - var files []string - err := fs.WalkDir("/", func(path string, d vfs.DirEntry, err error) error { - if err != nil { - return err - } - if !d.IsDir() { - files = append(files, path) - } - return nil - }) - assert.NilError(t, err) - slices.Sort(files) - assert.DeepEqual(t, files, []string{"/bytes", "/mapfile", "/string"}) }) t.Run("Windows", func(t *testing.T) { @@ -370,20 +356,6 @@ func TestFromMap(t *testing.T) { content, ok = fs.ReadFile("e:/mapfile") assert.Assert(t, ok) assert.Equal(t, content, "hello, world") - - var files []string - err := fs.WalkDir("/", func(path string, d vfs.DirEntry, err error) error { - if err != nil { - return err - } - if !d.IsDir() { - files = append(files, path) - } - return nil - }) - assert.NilError(t, err) - slices.Sort(files) - assert.DeepEqual(t, files, []string{"c:/string", "d:/bytes", "e:/mapfile"}) }) t.Run("Mixed", func(t *testing.T) { From fbfa9ded43f8e1248b4ade0fd0569674ba92658e Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 14 Aug 2025 14:21:50 -0700 Subject: [PATCH 17/18] Use iteration on map to baseline vfs from map --- internal/execute/testsys_test.go | 36 +++++++------------------------- internal/vfs/vfstest/vfstest.go | 21 +++++++++++++++++++ 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/internal/execute/testsys_test.go b/internal/execute/testsys_test.go index 1b80379bcf..44875635a9 100644 --- a/internal/execute/testsys_test.go +++ b/internal/execute/testsys_test.go @@ -1,7 +1,6 @@ package execute_test import ( - "errors" "fmt" "io" "io/fs" @@ -385,13 +384,9 @@ func (s *testSys) baselineFSwithDiff(baseline io.Writer) { testFs := s.testFs() diffs := map[string]string{} - err := s.fsFromFileMap().WalkDir("/", func(path string, d vfs.DirEntry, e error) error { - if e != nil { - return e - } - fileInfo := d.Type() - if fileInfo&fs.ModeSymlink != 0 { + for path, file := range s.mapFs().Entries() { + if file.Mode&fs.ModeSymlink != 0 { target, ok := s.mapFs().GetTargetOfSymlink(path) if !ok { panic("Failed to resolve symlink target: " + path) @@ -399,29 +394,12 @@ func (s *testSys) baselineFSwithDiff(baseline io.Writer) { newEntry := &diffEntry{symlinkTarget: target} snap[path] = newEntry s.addFsEntryDiff(diffs, newEntry, path) - return nil - } - - if !fileInfo.IsRegular() { - return nil - } - - newContents, ok := s.fsFromFileMap().ReadFile(path) - if !ok { - return nil - } - stat := s.fsFromFileMap().Stat(path) - if stat == nil { - panic("stat is nil: " + path) + continue + } else if file.Mode.IsRegular() { + newEntry := &diffEntry{content: string(file.Data), mTime: file.ModTime, isWritten: testFs.writtenFiles.Has(path)} + snap[path] = newEntry + s.addFsEntryDiff(diffs, newEntry, path) } - newEntry := &diffEntry{content: newContents, mTime: stat.ModTime(), isWritten: testFs.writtenFiles.Has(path)} - snap[path] = newEntry - s.addFsEntryDiff(diffs, newEntry, path) - - return nil - }) - if err != nil && !errors.Is(err, fs.ErrNotExist) { - panic("walkdir error during diff: " + err.Error()) } if s.serializedDiff != nil { for path := range s.serializedDiff.snap { diff --git a/internal/vfs/vfstest/vfstest.go b/internal/vfs/vfstest/vfstest.go index 87ba0f9031..9546b3d85b 100644 --- a/internal/vfs/vfstest/vfstest.go +++ b/internal/vfs/vfstest/vfstest.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io/fs" + "iter" "maps" "path" "slices" @@ -550,6 +551,26 @@ func (m *MapFS) GetTargetOfSymlink(path string) (string, bool) { return "", false } +func (m *MapFS) Entries() iter.Seq2[string, *fstest.MapFile] { + return func(yield func(string, *fstest.MapFile) bool) { + m.mu.RLock() + defer m.mu.RUnlock() + inputKeys := slices.Collect(maps.Keys(m.m)) + slices.SortFunc(inputKeys, comparePathsByParts) + + for _, p := range inputKeys { + file := m.m[p] + path := file.Sys.(*sys).realpath + if !tspath.PathIsAbsolute(path) { + path = "/" + path + } + if !yield(path, file) { + break + } + } + } +} + func must[T any](v T, err error) T { if err != nil { panic(err) From 92ae3825952f83e88b543eebe55a3c9ce3fab6cd Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Thu, 14 Aug 2025 20:59:44 -0700 Subject: [PATCH 18/18] Fix comment --- internal/vfs/vfstest/vfstest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/vfs/vfstest/vfstest.go b/internal/vfs/vfstest/vfstest.go index 9546b3d85b..e051b0c347 100644 --- a/internal/vfs/vfstest/vfstest.go +++ b/internal/vfs/vfstest/vfstest.go @@ -70,7 +70,7 @@ func FromMap[File any](m map[string]File, useCaseSensitiveFileNames bool) vfs.FS return FromMapWithClock(m, useCaseSensitiveFileNames, &clockImpl{start: time.Now()}) } -// FromMap creates a new [vfs.FS] from a map of paths to file contents. +// FromMapWithClock creates a new [vfs.FS] from a map of paths to file contents. // Those file contents may be strings, byte slices, or [fstest.MapFile]s. // // The paths must be normalized absolute paths according to the tspath package,