Skip to content

Commit a78342a

Browse files
authored
Move most harness globals into namespaces (#35530)
* Move most harness globals into namespaces * Remove forward declaration from `createMapShim` and move all `Map` declarations into one file * A small pile of more changes to get the harness transforming
1 parent 2b567b2 commit a78342a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1353
-1294
lines changed

src/compiler/core.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,8 @@
22
/* @internal */
33
namespace ts {
44

5-
/**
6-
* Returns the native Map implementation if it is available and compatible (i.e. supports iteration).
7-
*/
8-
export function tryGetNativeMap(): MapConstructor | undefined {
9-
// Internet Explorer's Map doesn't support iteration, so don't use it.
10-
// Natives
11-
// NOTE: TS doesn't strictly allow in-line declares, but if we suppress the error, the declaration
12-
// is still used for typechecking _and_ correctly elided, which is out goal, as this prevents us from
13-
// needing to pollute an outer scope with a declaration of `Map` just to satisfy the checks in this function
14-
//@ts-ignore
15-
declare const Map: (new <T>() => Map<T>) | undefined;
16-
// eslint-disable-next-line no-in-operator
17-
return typeof Map !== "undefined" && "entries" in Map.prototype ? Map : undefined;
18-
}
19-
205
export const emptyArray: never[] = [] as never[];
216

22-
export const Map: MapConstructor = tryGetNativeMap() || (() => {
23-
// NOTE: createMapShim will be defined for typescriptServices.js but not for tsc.js, so we must test for it.
24-
if (typeof createMapShim === "function") {
25-
return createMapShim();
26-
}
27-
throw new Error("TypeScript requires an environment that provides a compatible native Map implementation.");
28-
})();
29-
307
/** Create a new map. */
318
export function createMap<T>(): Map<T> {
329
return new Map<T>();

src/compiler/corePublic.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,31 @@ namespace ts {
4646
new <T>(): Map<T>;
4747
}
4848

49+
/**
50+
* Returns the native Map implementation if it is available and compatible (i.e. supports iteration).
51+
*/
52+
/* @internal */
53+
export function tryGetNativeMap(): MapConstructor | undefined {
54+
// Internet Explorer's Map doesn't support iteration, so don't use it.
55+
// Natives
56+
// NOTE: TS doesn't strictly allow in-line declares, but if we suppress the error, the declaration
57+
// is still used for typechecking _and_ correctly elided, which is out goal, as this prevents us from
58+
// needing to pollute an outer scope with a declaration of `Map` just to satisfy the checks in this function
59+
//@ts-ignore
60+
declare const Map: (new <T>() => Map<T>) | undefined;
61+
// eslint-disable-next-line no-in-operator
62+
return typeof Map !== "undefined" && "entries" in Map.prototype ? Map : undefined;
63+
}
64+
65+
/* @internal */
66+
export const Map: MapConstructor = tryGetNativeMap() || (() => {
67+
// NOTE: createMapShim will be defined for typescriptServices.js but not for tsc.js, so we must test for it.
68+
if (typeof createMapShim === "function") {
69+
return createMapShim();
70+
}
71+
throw new Error("TypeScript requires an environment that provides a compatible native Map implementation.");
72+
})();
73+
4974
/** ES6 Iterator type. */
5075
export interface Iterator<T> {
5176
next(): { value: T, done?: false } | { value: never, done: true };
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

src/harness/fakes.ts renamed to src/harness/fakesHosts.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ namespace fakes {
3939
public readFile(path: string) {
4040
try {
4141
const content = this.vfs.readFileSync(path, "utf8");
42-
return content === undefined ? undefined : utils.removeByteOrderMark(content);
42+
return content === undefined ? undefined : Utils.removeByteOrderMark(content);
4343
}
4444
catch {
4545
return undefined;
@@ -48,7 +48,7 @@ namespace fakes {
4848

4949
public writeFile(path: string, data: string, writeByteOrderMark?: boolean): void {
5050
this.vfs.mkdirpSync(vpath.dirname(path));
51-
this.vfs.writeFileSync(path, writeByteOrderMark ? utils.addUTF8ByteOrderMark(data) : data);
51+
this.vfs.writeFileSync(path, writeByteOrderMark ? Utils.addUTF8ByteOrderMark(data) : data);
5252
}
5353

5454
public deleteFile(path: string) {
@@ -289,7 +289,7 @@ namespace fakes {
289289
}
290290

291291
public writeFile(fileName: string, content: string, writeByteOrderMark: boolean) {
292-
if (writeByteOrderMark) content = utils.addUTF8ByteOrderMark(content);
292+
if (writeByteOrderMark) content = Utils.addUTF8ByteOrderMark(content);
293293
this.sys.writeFile(fileName, content);
294294

295295
const document = new documents.TextDocument(fileName, content);

src/harness/fourslash.ts renamed to src/harness/fourslashImpl.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
namespace FourSlash {
2-
ts.disableIncrementalParsing = false;
3-
42
import ArrayOrSingle = FourSlashInterface.ArrayOrSingle;
53

64
export const enum FourSlashTestType {

src/harness/harnessGlobals.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
/* eslint-disable no-var */
33

44
// this will work in the browser via browserify
5-
var _chai: typeof chai = require("chai");
6-
var assert: typeof _chai.assert = _chai.assert;
5+
declare var assert: typeof _chai.assert;
6+
var _chai: typeof import("chai") = require("chai");
7+
globalThis.assert = _chai.assert;
78
{
89
// chai's builtin `assert.isFalse` is featureful but slow - we don't use those features,
910
// so we'll just overwrite it as an alterative to migrating a bunch of code off of chai
@@ -27,4 +28,7 @@ var assert: typeof _chai.assert = _chai.assert;
2728
}
2829
};
2930
}
30-
/* eslint-enable no-var */
31+
/* eslint-enable no-var */
32+
// empty ts namespace so this file is included in the `ts.ts` namespace file generated by the module swapover
33+
// This way, everything that ends up importing `ts` downstream also imports this file and picks up its augmentation
34+
namespace ts {}

src/harness/harnessIO.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ namespace Harness {
2929
}
3030

3131
export let IO: IO;
32+
export function setHarnessIO(io: IO) {
33+
IO = io;
34+
}
3235

3336
// harness always uses one kind of new line
3437
// But note that `parseTestData` in `fourslash.ts` uses "\n"
@@ -185,6 +188,9 @@ namespace Harness {
185188
export let userSpecifiedRoot = "";
186189
export let lightMode = false;
187190
/* eslint-enable prefer-const */
191+
export function setLightMode(flag: boolean) {
192+
lightMode = flag;
193+
}
188194

189195
/** Functionality for compiling TypeScript code */
190196
export namespace Compiler {
@@ -467,7 +473,7 @@ namespace Harness {
467473
else if (vpath.isTypeScript(file.unitName) || (vpath.isJavaScript(file.unitName) && options.allowJs)) {
468474
const declFile = findResultCodeFile(file.unitName);
469475
if (declFile && !findUnit(declFile.file, declInputFiles) && !findUnit(declFile.file, declOtherFiles)) {
470-
dtsFiles.push({ unitName: declFile.file, content: utils.removeByteOrderMark(declFile.text) });
476+
dtsFiles.push({ unitName: declFile.file, content: Utils.removeByteOrderMark(declFile.text) });
471477
}
472478
}
473479
}
@@ -557,7 +563,7 @@ namespace Harness {
557563
function outputErrorText(error: ts.Diagnostic) {
558564
const message = ts.flattenDiagnosticMessageText(error.messageText, IO.newLine());
559565

560-
const errLines = utils.removeTestPathPrefixes(message)
566+
const errLines = Utils.removeTestPathPrefixes(message)
561567
.split("\n")
562568
.map(s => s.length > 0 && s.charAt(s.length - 1) === "\r" ? s.substr(0, s.length - 1) : s)
563569
.filter(s => s.length > 0)
@@ -580,7 +586,7 @@ namespace Harness {
580586
}
581587
}
582588

583-
yield [diagnosticSummaryMarker, utils.removeTestPathPrefixes(minimalDiagnosticsToString(diagnostics, options && options.pretty)) + IO.newLine() + IO.newLine(), diagnostics.length];
589+
yield [diagnosticSummaryMarker, Utils.removeTestPathPrefixes(minimalDiagnosticsToString(diagnostics, options && options.pretty)) + IO.newLine() + IO.newLine(), diagnostics.length];
584590

585591
// Report global errors
586592
const globalErrors = diagnostics.filter(err => !err.file);
@@ -595,7 +601,7 @@ namespace Harness {
595601
// Filter down to the errors in the file
596602
const fileErrors = diagnostics.filter((e): e is ts.DiagnosticWithLocation => {
597603
const errFn = e.file;
598-
return !!errFn && ts.comparePaths(utils.removeTestPathPrefixes(errFn.fileName), utils.removeTestPathPrefixes(inputFile.unitName), options && options.currentDirectory || "", !(options && options.caseSensitive)) === ts.Comparison.EqualTo;
604+
return !!errFn && ts.comparePaths(Utils.removeTestPathPrefixes(errFn.fileName), Utils.removeTestPathPrefixes(inputFile.unitName), options && options.currentDirectory || "", !(options && options.caseSensitive)) === ts.Comparison.EqualTo;
599605
});
600606

601607

@@ -812,7 +818,7 @@ namespace Harness {
812818
}
813819
typeLines += "\r\n";
814820
}
815-
yield [checkDuplicatedFileName(unitName, dupeCase), utils.removeTestPathPrefixes(typeLines)];
821+
yield [checkDuplicatedFileName(unitName, dupeCase), Utils.removeTestPathPrefixes(typeLines)];
816822
}
817823
}
818824
}
@@ -901,8 +907,8 @@ namespace Harness {
901907
}
902908

903909
function fileOutput(file: documents.TextDocument, harnessSettings: TestCaseParser.CompilerSettings): string {
904-
const fileName = harnessSettings.fullEmitPaths ? utils.removeTestPathPrefixes(file.file) : ts.getBaseFileName(file.file);
905-
return "//// [" + fileName + "]\r\n" + utils.removeTestPathPrefixes(file.text);
910+
const fileName = harnessSettings.fullEmitPaths ? Utils.removeTestPathPrefixes(file.file) : ts.getBaseFileName(file.file);
911+
return "//// [" + fileName + "]\r\n" + Utils.removeTestPathPrefixes(file.text);
906912
}
907913

908914
export function collateOutputs(outputFiles: readonly documents.TextDocument[]): string {
@@ -928,7 +934,7 @@ namespace Harness {
928934
const dupeCase = ts.createMap<number>();
929935
// Yield them
930936
for (const outputFile of files) {
931-
yield [checkDuplicatedFileName(outputFile.file, dupeCase), "/*====== " + outputFile.file + " ======*/\r\n" + utils.removeByteOrderMark(outputFile.text)];
937+
yield [checkDuplicatedFileName(outputFile.file, dupeCase), "/*====== " + outputFile.file + " ======*/\r\n" + Utils.removeByteOrderMark(outputFile.text)];
932938
}
933939

934940
function cleanName(fn: string) {

src/harness/loggedIO.ts

Lines changed: 78 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,86 @@
1-
interface FileInformation {
2-
contents?: string;
3-
contentsPath?: string;
4-
codepage: number;
5-
bom?: string;
6-
}
7-
8-
interface FindFileResult {
9-
}
10-
11-
interface IoLogFile {
12-
path: string;
13-
codepage: number;
14-
result?: FileInformation;
15-
}
16-
17-
interface IoLog {
18-
timestamp: string;
19-
arguments: string[];
20-
executingPath: string;
21-
currentDirectory: string;
22-
useCustomLibraryFile?: boolean;
23-
filesRead: IoLogFile[];
24-
filesWritten: {
25-
path: string;
26-
contents?: string;
27-
contentsPath?: string;
28-
bom: boolean;
29-
}[];
30-
filesDeleted: string[];
31-
filesAppended: {
32-
path: string;
1+
namespace Playback {
2+
interface FileInformation {
333
contents?: string;
344
contentsPath?: string;
35-
}[];
36-
fileExists: {
37-
path: string;
38-
result?: boolean;
39-
}[];
40-
filesFound: {
41-
path: string;
42-
pattern: string;
43-
result?: FindFileResult;
44-
}[];
45-
dirs: {
46-
path: string;
47-
re: string;
48-
re_m: boolean;
49-
re_g: boolean;
50-
re_i: boolean;
51-
opts: { recursive?: boolean; };
52-
result?: string[];
53-
}[];
54-
dirExists: {
55-
path: string;
56-
result?: boolean;
57-
}[];
58-
dirsCreated: string[];
59-
pathsResolved: {
5+
codepage: number;
6+
bom?: string;
7+
}
8+
9+
interface FindFileResult {
10+
}
11+
12+
interface IoLogFile {
6013
path: string;
61-
result?: string;
62-
}[];
63-
directoriesRead: {
64-
path: string,
65-
extensions: readonly string[] | undefined,
66-
exclude: readonly string[] | undefined,
67-
include: readonly string[] | undefined,
68-
depth: number | undefined,
69-
result: readonly string[],
70-
}[];
71-
useCaseSensitiveFileNames?: boolean;
72-
}
14+
codepage: number;
15+
result?: FileInformation;
16+
}
7317

74-
interface PlaybackControl {
75-
startReplayFromFile(logFileName: string): void;
76-
startReplayFromString(logContents: string): void;
77-
startReplayFromData(log: IoLog): void;
78-
endReplay(): void;
79-
startRecord(logFileName: string): void;
80-
endRecord(): void;
81-
}
18+
export interface IoLog {
19+
timestamp: string;
20+
arguments: string[];
21+
executingPath: string;
22+
currentDirectory: string;
23+
useCustomLibraryFile?: boolean;
24+
filesRead: IoLogFile[];
25+
filesWritten: {
26+
path: string;
27+
contents?: string;
28+
contentsPath?: string;
29+
bom: boolean;
30+
}[];
31+
filesDeleted: string[];
32+
filesAppended: {
33+
path: string;
34+
contents?: string;
35+
contentsPath?: string;
36+
}[];
37+
fileExists: {
38+
path: string;
39+
result?: boolean;
40+
}[];
41+
filesFound: {
42+
path: string;
43+
pattern: string;
44+
result?: FindFileResult;
45+
}[];
46+
dirs: {
47+
path: string;
48+
re: string;
49+
re_m: boolean;
50+
re_g: boolean;
51+
re_i: boolean;
52+
opts: { recursive?: boolean; };
53+
result?: string[];
54+
}[];
55+
dirExists: {
56+
path: string;
57+
result?: boolean;
58+
}[];
59+
dirsCreated: string[];
60+
pathsResolved: {
61+
path: string;
62+
result?: string;
63+
}[];
64+
directoriesRead: {
65+
path: string,
66+
extensions: readonly string[] | undefined,
67+
exclude: readonly string[] | undefined,
68+
include: readonly string[] | undefined,
69+
depth: number | undefined,
70+
result: readonly string[],
71+
}[];
72+
useCaseSensitiveFileNames?: boolean;
73+
}
74+
75+
interface PlaybackControl {
76+
startReplayFromFile(logFileName: string): void;
77+
startReplayFromString(logContents: string): void;
78+
startReplayFromData(log: IoLog): void;
79+
endReplay(): void;
80+
startRecord(logFileName: string): void;
81+
endRecord(): void;
82+
}
8283

83-
namespace Playback {
8484
let recordLog: IoLog | undefined;
8585
let replayLog: IoLog | undefined;
8686
let replayFilesRead: ts.Map<IoLogFile> | undefined;

0 commit comments

Comments
 (0)