Skip to content

Move most harness globals into namespaces #35530

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,8 @@
/* @internal */
namespace ts {

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

export const emptyArray: never[] = [] as never[];

export const Map: MapConstructor = tryGetNativeMap() || (() => {
// NOTE: createMapShim will be defined for typescriptServices.js but not for tsc.js, so we must test for it.
if (typeof createMapShim === "function") {
return createMapShim();
}
throw new Error("TypeScript requires an environment that provides a compatible native Map implementation.");
})();

/** Create a new map. */
export function createMap<T>(): Map<T> {
return new Map<T>();
Expand Down
25 changes: 25 additions & 0 deletions src/compiler/corePublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,31 @@ namespace ts {
new <T>(): Map<T>;
}

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

/* @internal */
export const Map: MapConstructor = tryGetNativeMap() || (() => {
// NOTE: createMapShim will be defined for typescriptServices.js but not for tsc.js, so we must test for it.
if (typeof createMapShim === "function") {
return createMapShim();
}
throw new Error("TypeScript requires an environment that provides a compatible native Map implementation.");
})();

/** ES6 Iterator type. */
export interface Iterator<T> {
next(): { value: T, done?: false } | { value: never, done: true };
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions src/harness/fakes.ts → src/harness/fakesHosts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace fakes {
public readFile(path: string) {
try {
const content = this.vfs.readFileSync(path, "utf8");
return content === undefined ? undefined : utils.removeByteOrderMark(content);
return content === undefined ? undefined : Utils.removeByteOrderMark(content);
}
catch {
return undefined;
Expand All @@ -48,7 +48,7 @@ namespace fakes {

public writeFile(path: string, data: string, writeByteOrderMark?: boolean): void {
this.vfs.mkdirpSync(vpath.dirname(path));
this.vfs.writeFileSync(path, writeByteOrderMark ? utils.addUTF8ByteOrderMark(data) : data);
this.vfs.writeFileSync(path, writeByteOrderMark ? Utils.addUTF8ByteOrderMark(data) : data);
}

public deleteFile(path: string) {
Expand Down Expand Up @@ -289,7 +289,7 @@ namespace fakes {
}

public writeFile(fileName: string, content: string, writeByteOrderMark: boolean) {
if (writeByteOrderMark) content = utils.addUTF8ByteOrderMark(content);
if (writeByteOrderMark) content = Utils.addUTF8ByteOrderMark(content);
this.sys.writeFile(fileName, content);

const document = new documents.TextDocument(fileName, content);
Expand Down
2 changes: 0 additions & 2 deletions src/harness/fourslash.ts → src/harness/fourslashImpl.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
namespace FourSlash {
ts.disableIncrementalParsing = false;

import ArrayOrSingle = FourSlashInterface.ArrayOrSingle;

export const enum FourSlashTestType {
Expand Down
10 changes: 7 additions & 3 deletions src/harness/harnessGlobals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
/* eslint-disable no-var */

// this will work in the browser via browserify
var _chai: typeof chai = require("chai");
var assert: typeof _chai.assert = _chai.assert;
declare var assert: typeof _chai.assert;
var _chai: typeof import("chai") = require("chai");
globalThis.assert = _chai.assert;
{
// chai's builtin `assert.isFalse` is featureful but slow - we don't use those features,
// so we'll just overwrite it as an alterative to migrating a bunch of code off of chai
Expand All @@ -27,4 +28,7 @@ var assert: typeof _chai.assert = _chai.assert;
}
};
}
/* eslint-enable no-var */
/* eslint-enable no-var */
// empty ts namespace so this file is included in the `ts.ts` namespace file generated by the module swapover
// This way, everything that ends up importing `ts` downstream also imports this file and picks up its augmentation
namespace ts {}
22 changes: 14 additions & 8 deletions src/harness/harnessIO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ namespace Harness {
}

export let IO: IO;
export function setHarnessIO(io: IO) {
IO = io;
}

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

/** Functionality for compiling TypeScript code */
export namespace Compiler {
Expand Down Expand Up @@ -467,7 +473,7 @@ namespace Harness {
else if (vpath.isTypeScript(file.unitName) || (vpath.isJavaScript(file.unitName) && options.allowJs)) {
const declFile = findResultCodeFile(file.unitName);
if (declFile && !findUnit(declFile.file, declInputFiles) && !findUnit(declFile.file, declOtherFiles)) {
dtsFiles.push({ unitName: declFile.file, content: utils.removeByteOrderMark(declFile.text) });
dtsFiles.push({ unitName: declFile.file, content: Utils.removeByteOrderMark(declFile.text) });
}
}
}
Expand Down Expand Up @@ -557,7 +563,7 @@ namespace Harness {
function outputErrorText(error: ts.Diagnostic) {
const message = ts.flattenDiagnosticMessageText(error.messageText, IO.newLine());

const errLines = utils.removeTestPathPrefixes(message)
const errLines = Utils.removeTestPathPrefixes(message)
.split("\n")
.map(s => s.length > 0 && s.charAt(s.length - 1) === "\r" ? s.substr(0, s.length - 1) : s)
.filter(s => s.length > 0)
Expand All @@ -580,7 +586,7 @@ namespace Harness {
}
}

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

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


Expand Down Expand Up @@ -812,7 +818,7 @@ namespace Harness {
}
typeLines += "\r\n";
}
yield [checkDuplicatedFileName(unitName, dupeCase), utils.removeTestPathPrefixes(typeLines)];
yield [checkDuplicatedFileName(unitName, dupeCase), Utils.removeTestPathPrefixes(typeLines)];
}
}
}
Expand Down Expand Up @@ -901,8 +907,8 @@ namespace Harness {
}

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

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

function cleanName(fn: string) {
Expand Down
156 changes: 78 additions & 78 deletions src/harness/loggedIO.ts
Original file line number Diff line number Diff line change
@@ -1,86 +1,86 @@
interface FileInformation {
contents?: string;
contentsPath?: string;
codepage: number;
bom?: string;
}

interface FindFileResult {
}

interface IoLogFile {
path: string;
codepage: number;
result?: FileInformation;
}

interface IoLog {
timestamp: string;
arguments: string[];
executingPath: string;
currentDirectory: string;
useCustomLibraryFile?: boolean;
filesRead: IoLogFile[];
filesWritten: {
path: string;
contents?: string;
contentsPath?: string;
bom: boolean;
}[];
filesDeleted: string[];
filesAppended: {
path: string;
namespace Playback {
interface FileInformation {
contents?: string;
contentsPath?: string;
}[];
fileExists: {
path: string;
result?: boolean;
}[];
filesFound: {
path: string;
pattern: string;
result?: FindFileResult;
}[];
dirs: {
path: string;
re: string;
re_m: boolean;
re_g: boolean;
re_i: boolean;
opts: { recursive?: boolean; };
result?: string[];
}[];
dirExists: {
path: string;
result?: boolean;
}[];
dirsCreated: string[];
pathsResolved: {
codepage: number;
bom?: string;
}

interface FindFileResult {
}

interface IoLogFile {
path: string;
result?: string;
}[];
directoriesRead: {
path: string,
extensions: readonly string[] | undefined,
exclude: readonly string[] | undefined,
include: readonly string[] | undefined,
depth: number | undefined,
result: readonly string[],
}[];
useCaseSensitiveFileNames?: boolean;
}
codepage: number;
result?: FileInformation;
}

interface PlaybackControl {
startReplayFromFile(logFileName: string): void;
startReplayFromString(logContents: string): void;
startReplayFromData(log: IoLog): void;
endReplay(): void;
startRecord(logFileName: string): void;
endRecord(): void;
}
export interface IoLog {
timestamp: string;
arguments: string[];
executingPath: string;
currentDirectory: string;
useCustomLibraryFile?: boolean;
filesRead: IoLogFile[];
filesWritten: {
path: string;
contents?: string;
contentsPath?: string;
bom: boolean;
}[];
filesDeleted: string[];
filesAppended: {
path: string;
contents?: string;
contentsPath?: string;
}[];
fileExists: {
path: string;
result?: boolean;
}[];
filesFound: {
path: string;
pattern: string;
result?: FindFileResult;
}[];
dirs: {
path: string;
re: string;
re_m: boolean;
re_g: boolean;
re_i: boolean;
opts: { recursive?: boolean; };
result?: string[];
}[];
dirExists: {
path: string;
result?: boolean;
}[];
dirsCreated: string[];
pathsResolved: {
path: string;
result?: string;
}[];
directoriesRead: {
path: string,
extensions: readonly string[] | undefined,
exclude: readonly string[] | undefined,
include: readonly string[] | undefined,
depth: number | undefined,
result: readonly string[],
}[];
useCaseSensitiveFileNames?: boolean;
}

interface PlaybackControl {
startReplayFromFile(logFileName: string): void;
startReplayFromString(logContents: string): void;
startReplayFromData(log: IoLog): void;
endReplay(): void;
startRecord(logFileName: string): void;
endRecord(): void;
}

namespace Playback {
let recordLog: IoLog | undefined;
let replayLog: IoLog | undefined;
let replayFilesRead: ts.Map<IoLogFile> | undefined;
Expand Down
Loading