Migrate core.ts

This commit is contained in:
Ron Buckton
2018-01-30 11:57:47 -08:00
parent d0988b8078
commit 4d8d51452c
21 changed files with 1004 additions and 1357 deletions

View File

@@ -611,57 +611,23 @@ gulp.task("LKG", "Makes a new LKG out of the built js files", ["clean", "dontUse
return runSequence("LKGInternal", "VerifyLKG");
});
gulp.task("typemock", () => {
const project = tsc.createProject("scripts/typemock/tsconfig.json", getCompilerSettings({}, /*useBuiltCompiler*/ false));
function compilePrivatePackage(packageName) {
const project = tsc.createProject(`scripts/${packageName}/tsconfig.json`, getCompilerSettings({}, /*useBuiltCompiler*/ false));
return project.src()
.pipe(sourcemaps.init())
.pipe(newer("scripts/typemock/dist/index.js"))
.pipe(newer(`scripts/${packageName}/dist/index.js`))
.pipe(project())
.pipe(sourcemaps.write(".", <any>{ sourceRoot: "../src", includeContent: false, destPath: "scripts/typemock/dist" }))
.pipe(gulp.dest("scripts/typemock/dist"));
});
.pipe(sourcemaps.write(".", <any>{ sourceRoot: "../src", includeContent: false, destPath: `scripts/${packageName}/dist` }))
.pipe(gulp.dest(`scripts/${packageName}/dist`));
}
gulp.task("vfs-core", () => {
const project = tsc.createProject("scripts/vfs-core/tsconfig.json", getCompilerSettings({}, /*useBuiltCompiler*/ false));
return project.src()
.pipe(sourcemaps.init())
.pipe(newer("scripts/vfs-core/dist/index.js"))
.pipe(project())
.pipe(sourcemaps.write(".", <any>{ sourceRoot: "../src", includeContent: false, destPath: "scripts/vfs-core/dist" }))
.pipe(gulp.dest("scripts/vfs-core/dist"));
});
gulp.task("vfs-errors", () => {
const project = tsc.createProject("scripts/vfs-errors/tsconfig.json", getCompilerSettings({}, /*useBuiltCompiler*/ false));
return project.src()
.pipe(sourcemaps.init())
.pipe(newer("scripts/vfs-errors/dist/index.js"))
.pipe(project())
.pipe(sourcemaps.write(".", <any>{ sourceRoot: "../src", includeContent: false, destPath: "scripts/vfs-errors/dist" }))
.pipe(gulp.dest("scripts/vfs-errors/dist"));
});
gulp.task("vfs-path", ["vfs-core", "vfs-errors"], () => {
const project = tsc.createProject("scripts/vfs-path/tsconfig.json", getCompilerSettings({}, /*useBuiltCompiler*/ false));
return project.src()
.pipe(sourcemaps.init())
.pipe(newer("scripts/vfs-path/dist/index.js"))
.pipe(project())
.pipe(sourcemaps.write(".", <any>{ sourceRoot: "../src", includeContent: false, destPath: "scripts/vfs-path/dist" }))
.pipe(gulp.dest("scripts/vfs-path/dist"));
});
gulp.task("vfs", ["vfs-core", "vfs-errors", "vfs-path"], () => {
const project = tsc.createProject("scripts/vfs/tsconfig.json", getCompilerSettings({}, /*useBuiltCompiler*/ false));
return project.src()
.pipe(sourcemaps.init())
.pipe(newer("scripts/vfs/dist/index.js"))
.pipe(project())
.pipe(sourcemaps.write(".", <any>{ sourceRoot: "../src", includeContent: false, destPath: "scripts/vfs/dist" }))
.pipe(gulp.dest("scripts/vfs/dist"));
});
gulp.task("private-packages", ["typemock", "vfs"]);
gulp.task("typemock", () => compilePrivatePackage("typemock"));
gulp.task("vfs-core", () => compilePrivatePackage("vfs-core"));
gulp.task("vfs-errors", () => compilePrivatePackage("vfs-errors"));
gulp.task("vfs-path", ["vfs-core", "vfs-errors"], () => compilePrivatePackage("vfs-path"));
gulp.task("vfs", ["vfs-core", "vfs-errors", "vfs-path", "typemock"], () => compilePrivatePackage("vfs"));
gulp.task("harness-core", ["vfs-core"], () => compilePrivatePackage("harness-core"));
gulp.task("private-packages", ["typemock", "vfs", "harness-core"]);
// Task to build the tests infrastructure using the built compiler
const run = path.join(builtLocalDirectory, "run.js");

View File

@@ -803,72 +803,28 @@ task("LKG", ["clean", "release", "local"].concat(libraryTargets), function () {
// Test directory
directory(builtLocalDirectory);
task("typemock", function () {
var startCompileTime = mark();
execCompiler(/*useBuiltCompiler*/ false, ["-p", "scripts/typemock/tsconfig.json"], function (error) {
if (error) {
fail("Compilation unsuccessful.");
}
else {
complete();
}
measure(startCompileTime);
});
}, { async: true });
function privatePackage(packageName, prereqs) {
task(packageName, prereqs, function () {
var startCompileTime = mark();
execCompiler(/*useBuiltCompiler*/ false, ["-p", `scripts/${packageName}/tsconfig.json`], function (error) {
if (error) {
fail("Compilation unsuccessful.");
}
else {
complete();
}
measure(startCompileTime);
});
}, { async: true });
}
task("vfs-core", function () {
var startCompileTime = mark();
execCompiler(/*useBuiltCompiler*/ false, ["-p", "scripts/vfs-core/tsconfig.json"], function (error) {
if (error) {
fail("Compilation unsuccessful.");
}
else {
complete();
}
measure(startCompileTime);
});
}, { async: true });
task("vfs-errors", function () {
var startCompileTime = mark();
execCompiler(/*useBuiltCompiler*/ false, ["-p", "scripts/vfs-errors/tsconfig.json"], function (error) {
if (error) {
fail("Compilation unsuccessful.");
}
else {
complete();
}
measure(startCompileTime);
});
}, { async: true });
task("vfs-path", ["vfs-core", "vfs-errors"], function () {
var startCompileTime = mark();
execCompiler(/*useBuiltCompiler*/ false, ["-p", "scripts/vfs-path/tsconfig.json"], function (error) {
if (error) {
fail("Compilation unsuccessful.");
}
else {
complete();
}
measure(startCompileTime);
});
}, { async: true });
task("vfs", ["vfs-core", "vfs-errors", "vfs-path", "typemock"], function () {
var startCompileTime = mark();
execCompiler(/*useBuiltCompiler*/ false, ["-p", "scripts/vfs/tsconfig.json"], function (error) {
if (error) {
fail("Compilation unsuccessful.");
}
else {
complete();
}
measure(startCompileTime);
});
}, { async: true });
task("private-packages", ["typemock", "vfs"]);
privatePackage("typemock");
privatePackage("vfs-core");
privatePackage("vfs-errors");
privatePackage("vfs-path", ["vfs-core", "vfs-errors"]);
privatePackage("vfs", ["vfs-path", "typemock"]);
privatePackage("harness-core", ["vfs-core"]);
task("private-packages", ["typemock", "vfs", "harness-core"]);
// Task to build the tests infrastructure using the built compiler
var run = path.join(builtLocalDirectory, "run.js");

View File

@@ -1,9 +1,14 @@
#!/usr/bin/env bash
if [ "$1" = "6" ]; then
echo "NodeJS v6 is no longer supported, build skipped.";
exit;
fi;
# Set up NVM
export NVM_DIR="/home/dotnet-bot/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
nvm install $1
npm uninstall typescript --no-save

View File

@@ -53,6 +53,7 @@
"@types/xml2js": "^0.4.0",
"@typescript/vfs-path": "file:scripts/vfs-path",
"@typescript/vfs": "file:scripts/vfs",
"@typescript/harness-core": "file:scripts/harness-core",
"browser-resolve": "^1.11.2",
"browserify": "latest",
"chai": "latest",

View File

@@ -0,0 +1,18 @@
const gulp = require("gulp");
const sourcemaps = require("gulp-sourcemaps");
const tsb = require("gulp-tsb");
const del = require("del");
const project = tsb.create("tsconfig.json")
gulp.task("clean", () => del(["dist/**/*"]));
gulp.task("build", () => gulp.src(["src/**/*.ts"])
.pipe(sourcemaps.init())
.pipe(project())
.pipe(sourcemaps.write(".", { sourceRoot: "../src", includeContent: false, destPath: "dist" }))
.pipe(gulp.dest("dist")));
gulp.task("watch", () => gulp.watch(["src/**/*", "tsconfig.json"], ["build"]));
gulp.task("default", ["build"]);

View File

@@ -0,0 +1,23 @@
{
"private": true,
"name": "@typescript/harness-core",
"version": "0.0.0",
"description": "TypeScript test harness core",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"author": "Ron Buckton (ron.buckton@microsoft.com)",
"license": "Apache-2.0",
"dependencies": {
"@typescript/vfs-core": "file:../vfs-core"
},
"devDependencies": {
"@types/node": "^8.0.20",
"@types/source-map-support": "^0.4.0",
"del": "^2.0.2",
"gulp": "^3.9.1",
"gulp-sourcemaps": "^2.6.1",
"gulp-tsb": "^2.0.5",
"source-map-support": "^0.5.0",
"typescript": "^2.6.1"
}
}

View File

@@ -0,0 +1,67 @@
const H = new Uint32Array(5);
const W = new Uint8Array(80);
const B = new Uint8Array(64);
const BLOCK_SIZE = 64;
export function sha1(message: string): string {
let buffer = B;
const textSize = message.length;
const messageSize = textSize * 2;
const finalBlockSize = messageSize % BLOCK_SIZE;
const padSize = (finalBlockSize < BLOCK_SIZE - 8 - 1 ? BLOCK_SIZE : BLOCK_SIZE * 2) - finalBlockSize;
const byteLength = messageSize + padSize;
if (byteLength > BLOCK_SIZE) {
buffer = new Uint8Array(byteLength);
}
const bufferView = new DataView(buffer.buffer);
for (let i = 0; i < textSize; ++i) {
bufferView.setUint16(i * 2, message.charCodeAt(i));
}
buffer[messageSize] = 0x80;
bufferView.setUint32(byteLength - 4, messageSize * 8);
H[0] = 0x67452301, H[1] = 0xefcdab89, H[2] = 0x98badcfe, H[3] = 0x10325476, H[4] = 0xc3d2e1f0;
for (let offset = 0; offset < byteLength; offset += BLOCK_SIZE) {
let a = H[0], b = H[1], c = H[2], d = H[3], e = H[4];
for (let i = 0; i < 80; ++i) {
if (i < 16) {
const x = offset + i * 4;
W[i] = buffer[x] << 24 | buffer[x + 1] << 16 | buffer[x + 2] << 8 | buffer[x + 3];
}
else {
const x = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
W[i] = (x << 1 | x >>> 31) >>> 0;
}
let t = (a << 5 | a >>> 27) >>> 0 + e + W[i];
if (i < 20) {
t += ((b & c) | (~b & d)) + 0x5A827999;
}
else if (i < 40) {
t += (b ^ c ^ d) + 0x6ED9EBA1;
}
else if (i < 60) {
t += ((b & c) | (b & d) | (c & d)) + 0x8F1BBCDC;
}
else {
t += (b ^ c ^ d) + 0xCA62C1D6;
}
e = d, d = c, c = (b << 30 | b >>> 2) >>> 0, b = a, a = t;
}
H[0] += a, H[1] += b, H[2] += c, H[3] += d, H[4] += e;
}
for (let i = 0; i < 5; ++i) {
bufferView.setUint32(i * 4, H[i]);
}
let result = "";
for (let i = 0; i < 20; ++i) {
result += (buffer[i] < 16 ? "0" : "") + buffer[i].toString(16);
}
return result;
}

View File

@@ -0,0 +1,3 @@
export * from "@typescript/vfs-core";
export * from "./strings";
export * from "./crypto";

View File

@@ -0,0 +1,132 @@
export function padLeft(text: string, size: number, ch = " "): string {
while (text.length < size) text = ch + text;
return text;
}
export function padRight(text: string, size: number, ch = " "): string {
while (text.length < size) text += ch;
return text;
}
export function getByteOrderMark(text: string): string {
const length = getByteOrderMarkLength(text);
return length > 0 ? text.slice(0, length) : "";
}
export function getByteOrderMarkLength(text: string): number {
if (text.length >= 2) {
const ch0 = text.charCodeAt(0);
const ch1 = text.charCodeAt(1);
if ((ch0 === 0xff && ch1 === 0xfe) ||
(ch0 === 0xfe && ch1 === 0xff)) {
return 2;
}
if (text.length >= 3 && ch0 === 0xef && ch1 === 0xbb && text.charCodeAt(2) === 0xbf) {
return 3;
}
}
return 0;
}
export function removeByteOrderMark(text: string): string {
const length = getByteOrderMarkLength(text);
return length ? text.slice(length) : text;
}
export function addUTF8ByteOrderMark(text: string) {
return getByteOrderMarkLength(text) === 0 ? "\u00EF\u00BB\u00BF" + text : text;
}
function splitLinesWorker(text: string, lineStarts: number[] | undefined, lines: string[] | undefined, removeEmptyElements: boolean) {
let pos = 0;
let end = 0;
let lineStart = 0;
let nonWhiteSpace = false;
while (pos < text.length) {
const ch = text.charCodeAt(pos);
end = pos;
pos++;
switch (ch) {
// LineTerminator
case 0x000d: // <CR> carriage return
if (pos < text.length && text.charCodeAt(pos) === 0x000a) {
pos++;
}
// falls through
case 0x000a: // <LF> line feed
case 0x2028: // <LS> line separator
case 0x2029: // <PS> paragraph separator
if (lineStarts) {
lineStarts.push(lineStart);
}
if (lines && (!removeEmptyElements || nonWhiteSpace)) {
lines.push(text.slice(lineStart, end));
}
lineStart = pos;
nonWhiteSpace = false;
break;
// WhiteSpace
case 0x0009: // <TAB> tab
case 0x000b: // <VT> vertical tab
case 0x000c: // <FF> form feed
case 0x0020: // <SP> space
case 0x00a0: // <NBSP> no-break space
case 0xfeff: // <ZWNBSP> zero width no-break space
case 0x1680: // <USP> ogham space mark
case 0x2000: // <USP> en quad
case 0x2001: // <USP> em quad
case 0x2002: // <USP> en space
case 0x2003: // <USP> em space
case 0x2004: // <USP> three-per-em space
case 0x2005: // <USP> four-per-em space
case 0x2006: // <USP> six-per-em space
case 0x2007: // <USP> figure space
case 0x2008: // <USP> punctuation space
case 0x2009: // <USP> thin space
case 0x200a: // <USP> hair space
case 0x202f: // <USP> narrow no-break space
case 0x205f: // <USP> medium mathematical space
case 0x3000: // <USP> ideographic space
case 0x0085: // next-line (not strictly per spec, but used by the compiler)
break;
default:
nonWhiteSpace = true;
break;
}
}
if (lineStarts) {
lineStarts.push(lineStart);
}
if (lines && (!removeEmptyElements || nonWhiteSpace)) {
lines.push(text.slice(lineStart, text.length));
}
}
export type LineStarts = ReadonlyArray<number>;
export interface LinesAndLineStarts {
readonly lines: ReadonlyArray<string>;
readonly lineStarts: LineStarts;
}
export function getLinesAndLineStarts(text: string): LinesAndLineStarts {
const lines: string[] = [];
const lineStarts: number[] = [];
splitLinesWorker(text, lineStarts, lines, /*removeEmptyElements*/ false);
return { lines, lineStarts };
}
export function splitLines(text: string, removeEmptyElements = false): string[] {
const lines: string[] = [];
splitLinesWorker(text, /*lineStarts*/ undefined, lines, removeEmptyElements);
return lines;
}
export function computeLineStarts(text: string): LineStarts {
const lineStarts: number[] = [];
splitLinesWorker(text, lineStarts, /*lines*/ undefined, /*removeEmptyElements*/ false);
return lineStarts;
}

View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"outDir": "dist",
"types": ["node"],
"declaration": true,
"sourceMap": true,
"strict": true,
"preserveConstEnums": true
},
"include": [
"src/**/*"
]
}

View File

@@ -0,0 +1,509 @@
import { identity } from "./functions";
export interface SortOptions<T> {
comparer: (a: T, b: T) => number;
sort: "insertion" | "comparison";
}
export class SortedMap<K, V> {
private _comparer: (a: K, b: K) => number;
private _keys: K[] = [];
private _values: V[] = [];
private _order: number[] | undefined;
private _version = 0;
private _copyOnWrite = false;
constructor(comparer: ((a: K, b: K) => number) | SortOptions<K>, iterable?: Iterable<[K, V]>) {
this._comparer = typeof comparer === "object" ? comparer.comparer : comparer;
this._order = typeof comparer === "object" && comparer.sort === "insertion" ? [] : undefined;
if (iterable) {
for (const [key, value] of iterable) {
this.set(key, value);
}
}
}
public get size() {
return this._keys.length;
}
public get [Symbol.toStringTag]() {
return "SortedMap";
}
public has(key: K) {
return binarySearch(this._keys, key, identity, this._comparer) >= 0;
}
public get(key: K) {
const index = binarySearch(this._keys, key, identity, this._comparer);
return index >= 0 ? this._values[index] : undefined;
}
public set(key: K, value: V) {
const index = binarySearch(this._keys, key, identity, this._comparer);
if (index >= 0) {
this._values[index] = value;
}
else {
this.writePreamble();
insertAt(this._keys, ~index, key);
insertAt(this._values, ~index, value);
if (this._order) insertAt(this._order, ~index, this._version);
this.writePostScript();
}
return this;
}
public delete(key: K) {
const index = binarySearch(this._keys, key, identity, this._comparer);
if (index >= 0) {
this.writePreamble();
removeAt(this._keys, index);
removeAt(this._values, index);
if (this._order) removeAt(this._order, index);
this.writePostScript();
return true;
}
return false;
}
public clear() {
if (this.size > 0) {
this.writePreamble();
this._keys.length = 0;
this._values.length = 0;
if (this._order) this._order.length = 0;
this.writePostScript();
}
}
public forEach(callback: (value: V, key: K, collection: this) => void, thisArg?: any) {
const keys = this._keys;
const values = this._values;
const indices = this.getIterationOrder();
const version = this._version;
this._copyOnWrite = true;
try {
if (indices) {
for (const i of indices) {
callback.call(thisArg, values[i], keys[i], this);
}
}
else {
for (let i = 0; i < keys.length; i++) {
callback.call(thisArg, values[i], keys[i], this);
}
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public * keys() {
const keys = this._keys;
const indices = this.getIterationOrder();
const version = this._version;
this._copyOnWrite = true;
try {
if (indices) {
for (const i of indices) {
yield keys[i];
}
}
else {
for (let i = 0; i < keys.length; i++) {
yield keys[i];
}
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public * values() {
const values = this._values;
const indices = this.getIterationOrder();
const version = this._version;
this._copyOnWrite = true;
try {
if (indices) {
for (const i of indices) {
yield values[i];
}
}
else {
for (let i = 0; i < values.length; i++) {
yield values[i];
}
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public * entries() {
const keys = this._keys;
const values = this._values;
const indices = this.getIterationOrder();
const version = this._version;
this._copyOnWrite = true;
try {
if (indices) {
for (const i of indices) {
yield [keys[i], values[i]] as [K, V];
}
}
else {
for (let i = 0; i < keys.length; i++) {
yield [keys[i], values[i]] as [K, V];
}
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public [Symbol.iterator]() {
return this.entries();
}
private writePreamble() {
if (this._copyOnWrite) {
this._keys = this._keys.slice();
this._values = this._values.slice();
if (this._order) this._order = this._order.slice();
this._copyOnWrite = false;
}
}
private writePostScript() {
this._version++;
}
private getIterationOrder() {
if (this._order) {
const order = this._order;
return this._order
.map((_, i) => i)
.sort((x, y) => order[x] - order[y]);
}
return undefined;
}
}
export class SortedSet<T> {
private _comparer: (a: T, b: T) => number;
private _values: T[] = [];
private _order: number[] | undefined;
private _version = 0;
private _copyOnWrite = false;
constructor(comparer: ((a: T, b: T) => number) | SortOptions<T>, iterable?: Iterable<T>) {
this._comparer = typeof comparer === "object" ? comparer.comparer : comparer;
this._order = typeof comparer === "object" && comparer.sort === "insertion" ? [] : undefined;
if (iterable) {
for (const value of iterable) {
this.add(value);
}
}
}
public get size() {
return this._values.length;
}
public get [Symbol.toStringTag]() {
return "SortedSet";
}
public has(value: T) {
return binarySearch(this._values, value, identity, this._comparer) >= 0;
}
public add(value: T) {
const index = binarySearch(this._values, value, identity, this._comparer);
if (index < 0) {
this.writePreamble();
insertAt(this._values, ~index, value);
if (this._order) insertAt(this._order, ~index, this._version);
this.writePostScript();
}
return this;
}
public delete(value: T) {
const index = binarySearch(this._values, value, identity, this._comparer);
if (index >= 0) {
this.writePreamble();
removeAt(this._values, index);
if (this._order) removeAt(this._order, index);
this.writePostScript();
return true;
}
return false;
}
public clear() {
if (this.size > 0) {
this.writePreamble();
this._values.length = 0;
if (this._order) this._order.length = 0;
this.writePostScript();
}
}
public forEach(callback: (value: T, key: T, collection: this) => void, thisArg?: any) {
const values = this._values;
const indices = this.getIterationOrder();
const version = this._version;
this._copyOnWrite = true;
try {
if (indices) {
for (const i of indices) {
callback.call(thisArg, values[i], values[i], this);
}
}
else {
for (const value of values) {
callback.call(thisArg, value, value, this);
}
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public keys() {
return this.values();
}
public * values() {
const values = this._values;
const indices = this.getIterationOrder();
const version = this._version;
this._copyOnWrite = true;
try {
if (indices) {
for (const i of indices) {
yield values[i];
}
}
else {
for (const value of values) {
yield value;
}
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public * entries() {
const values = this._values;
const indices = this.getIterationOrder();
const version = this._version;
this._copyOnWrite = true;
try {
if (indices) {
for (const i of indices) {
yield [values[i], values[i]] as [T, T];
}
}
else {
for (const value of values) {
yield [value, value] as [T, T];
}
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public [Symbol.iterator]() {
return this.values();
}
private writePreamble() {
if (this._copyOnWrite) {
this._values = this._values.slice();
if (this._order) this._order = this._order.slice();
this._copyOnWrite = false;
}
}
private writePostScript() {
this._version++;
}
private getIterationOrder() {
if (this._order) {
const order = this._order;
return this._order
.map((_, i) => i)
.sort((x, y) => order[x] - order[y]);
}
return undefined;
}
}
export function binarySearch<T, U>(array: ReadonlyArray<T>, value: T, keySelector: (v: T) => U, keyComparer: (a: U, b: U) => number, offset?: number): number {
if (!array || array.length === 0) {
return -1;
}
let low = offset || 0;
let high = array.length - 1;
const key = keySelector(value);
while (low <= high) {
const middle = low + ((high - low) >> 1);
const midKey = keySelector(array[middle]);
const result = keyComparer(midKey, key);
if (result < 0) {
low = middle + 1;
}
else if (result > 0) {
high = middle - 1;
}
else {
return middle;
}
}
return ~low;
}
export function removeAt<T>(array: T[], index: number): void {
if (index < 0 || index >= array.length) {
return;
}
else if (index === 0) {
array.shift();
}
else if (index === array.length - 1) {
array.pop();
}
else {
for (let i = index; i < array.length - 1; i++) {
array[i] = array[i + 1];
}
array.length--;
}
}
export function insertAt<T>(array: T[], index: number, value: T): void {
if (index === 0) {
array.unshift(value);
}
else if (index === array.length) {
array.push(value);
}
else {
for (let i = array.length; i > index; i--) {
array[i] = array[i - 1];
}
array[index] = value;
}
}
/**
* A collection of metadata that supports inheritance.
*/
export class Metadata {
private static readonly _undefinedValue = {};
private _parent: Metadata | undefined;
private _map: { [key: string]: any };
private _version = 0;
private _size = -1;
private _parentVersion: number | undefined;
constructor(parent?: Metadata) {
this._parent = parent;
this._map = Object.create(parent ? parent._map : null); // tslint:disable-line:no-null-keyword
}
public get size(): number {
if (this._size === -1 || (this._parent && this._parent._version !== this._parentVersion)) {
let size = 0;
for (const _ in this._map) size++;
this._size = size;
if (this._parent) {
this._parentVersion = this._parent._version;
}
}
return this._size;
}
public get parent() {
return this._parent;
}
public has(key: string): boolean {
return this._map[Metadata._escapeKey(key)] !== undefined;
}
public get(key: string): any {
const value = this._map[Metadata._escapeKey(key)];
return value === Metadata._undefinedValue ? undefined : value;
}
public set(key: string, value: any): this {
this._map[Metadata._escapeKey(key)] = value === undefined ? Metadata._undefinedValue : value;
this._size = -1;
this._version++;
return this;
}
public delete(key: string): boolean {
const escapedKey = Metadata._escapeKey(key);
if (this._map[escapedKey] !== undefined) {
delete this._map[escapedKey];
this._size = -1;
this._version++;
return true;
}
return false;
}
public clear(): void {
this._map = Object.create(this._parent ? this._parent._map : null); // tslint:disable-line:no-null-keyword
this._size = -1;
this._version++;
}
public forEach(callback: (value: any, key: string, map: this) => void) {
for (const key in this._map) {
callback(this._map[key], Metadata._unescapeKey(key), this);
}
}
private static _escapeKey(text: string) {
return (text.length >= 2 && text.charAt(0) === "_" && text.charAt(1) === "_" ? "_" + text : text);
}
private static _unescapeKey(text: string) {
return (text.length >= 3 && text.charAt(0) === "_" && text.charAt(1) === "_" && text.charAt(2) === "_" ? text.slice(1) : text);
}
}

View File

@@ -0,0 +1,41 @@
export function compareNumbers(a: number, b: number): number {
if (a === b) return 0;
if (a === undefined) return -1;
if (b === undefined) return +1;
return a < b ? -1 : +1;
}
export function compareStrings(a: string, b: string, ignoreCase: boolean): number {
return ignoreCase
? compareStringsCaseInsensitive(a, b)
: compareStringsCaseSensitive(a, b);
}
// NOTE: This is a duplicate of `compareNumbers` above, but is intended to be used only with
// strings to reduce polymorphism.
export function compareStringsCaseSensitive(a: string, b: string): number {
if (a === b) return 0;
if (a === undefined) return -1;
if (b === undefined) return +1;
return a < b ? -1 : +1;
}
export function compareStringsCaseInsensitive(a: string, b: string): number {
if (a === b) return 0;
if (a === undefined) return -1;
if (b === undefined) return +1;
a = a.toUpperCase();
b = b.toUpperCase();
return a < b ? -1 : a > b ? +1 : 0;
}
export function equateStringsCaseSensitive(a: string, b: string): boolean {
return a === b;
}
export function equateStringsCaseInsensitive(a: string, b: string): boolean {
return a === b
|| a !== undefined
&& b !== undefined
&& a.toUpperCase() === b.toUpperCase();
}

View File

@@ -0,0 +1 @@
export function identity<T>(v: T): T { return v; }

View File

@@ -1,466 +1,3 @@
export function identity<T>(v: T): T { return v; }
//
// Comparers
//
export function compareNumbers(a: number, b: number): number {
if (a === b) return 0;
if (a === undefined) return -1;
if (b === undefined) return +1;
return a < b ? -1 : +1;
}
export function compareStrings(a: string, b: string, ignoreCase: boolean): number {
return ignoreCase
? compareStringsCaseInsensitive(a, b)
: compareStringsCaseSensitive(a, b);
}
// NOTE: This is a duplicate of `compareNumbers` above, but is intended to be used only with
// strings to reduce polymorphism.
export function compareStringsCaseSensitive(a: string, b: string): number {
if (a === b) return 0;
if (a === undefined) return -1;
if (b === undefined) return +1;
return a < b ? -1 : +1;
}
export function compareStringsCaseInsensitive(a: string, b: string): number {
if (a === b) return 0;
if (a === undefined) return -1;
if (b === undefined) return +1;
a = a.toUpperCase();
b = b.toUpperCase();
return a < b ? -1 : a > b ? +1 : 0;
}
export function equateStringsCaseSensitive(a: string, b: string): boolean {
return a === b;
}
export function equateStringsCaseInsensitive(a: string, b: string): boolean {
return a === b
|| a !== undefined
&& b !== undefined
&& a.toUpperCase() === b.toUpperCase();
}
//
// Collections
//
export class SortedMap<K, V> {
private _comparer: (a: K, b: K) => number;
private _keys: K[] = [];
private _values: V[] = [];
private _version = 0;
private _copyOnWrite = false;
constructor(comparer: (a: K, b: K) => number, iterable?: Iterable<[K, V]>) {
this._comparer = comparer;
if (iterable) {
for (const [key, value] of iterable) {
this.set(key, value);
}
}
}
public get size() {
return this._keys.length;
}
public get [Symbol.toStringTag]() {
return "SortedMap";
}
public has(key: K) {
return binarySearch(this._keys, key, identity, this._comparer) >= 0;
}
public get(key: K) {
const index = binarySearch(this._keys, key, identity, this._comparer);
return index >= 0 ? this._values[index] : undefined;
}
public set(key: K, value: V) {
const index = binarySearch(this._keys, key, identity, this._comparer);
if (index >= 0) {
this._values[index] = value;
}
else {
this.writePreamble();
insertAt(this._keys, ~index, key);
insertAt(this._values, ~index, value);
this.writePostScript();
}
return this;
}
public delete(key: K) {
const index = binarySearch(this._keys, key, identity, this._comparer);
if (index >= 0) {
this.writePreamble();
removeAt(this._keys, index);
removeAt(this._values, index);
this.writePostScript();
return true;
}
return false;
}
public clear() {
if (this.size > 0) {
this.writePreamble();
this._keys.length = 0;
this._values.length = 0;
this.writePostScript();
}
}
public forEach(callback: (value: V, key: K, collection: this) => void, thisArg?: any) {
const keys = this._keys;
const values = this._values;
const version = this._version;
this._copyOnWrite = true;
try {
for (let i = 0; i < keys.length; i++) {
callback.call(thisArg, values[i], keys[i], this);
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public * keys() {
const keys = this._keys;
const version = this._version;
this._copyOnWrite = true;
try {
for (let i = 0; i < keys.length; i++) {
yield keys[i];
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public * values() {
const values = this._values;
const version = this._version;
this._copyOnWrite = true;
try {
for (let i = 0; i < values.length; i++) {
yield values[i];
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public * entries() {
const keys = this._keys;
const values = this._values;
const version = this._version;
this._copyOnWrite = true;
try {
for (let i = 0; i < keys.length; i++) {
yield [keys[i], values[i]] as [K, V];
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public [Symbol.iterator]() {
return this.entries();
}
private writePreamble() {
if (this._copyOnWrite) {
this._keys = this._keys.slice();
this._values = this._values.slice();
this._copyOnWrite = false;
}
}
private writePostScript() {
this._version++;
}
}
export class SortedSet<T> {
private _comparer: (a: T, b: T) => number;
private _values: T[] = [];
private _version = 0;
private _copyOnWrite = false;
constructor(comparer: (a: T, b: T) => number, iterable?: Iterable<T>) {
this._comparer = comparer;
if (iterable) {
for (const value of iterable) {
this.add(value);
}
}
}
public get size() {
return this._values.length;
}
public get [Symbol.toStringTag]() {
return "SortedSet";
}
public has(value: T) {
return binarySearch(this._values, value, identity, this._comparer) >= 0;
}
public add(value: T) {
const index = binarySearch(this._values, value, identity, this._comparer);
if (index < 0) {
this.writePreamble();
insertAt(this._values, ~index, value);
this.writePostScript();
}
return this;
}
public delete(value: T) {
const index = binarySearch(this._values, value, identity, this._comparer);
if (index >= 0) {
this.writePreamble();
removeAt(this._values, index);
this.writePostScript();
return true;
}
return false;
}
public clear() {
if (this.size > 0) {
this.writePreamble();
this._values.length = 0;
this.writePostScript();
}
}
public forEach(callback: (value: T, key: T, collection: this) => void, thisArg?: any) {
const values = this._values;
const version = this._version;
this._copyOnWrite = true;
try {
for (const value of values) {
callback.call(thisArg, value, value, this);
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public keys() {
return this.values();
}
public * values() {
const values = this._values;
const version = this._version;
this._copyOnWrite = true;
try {
for (const value of values) {
yield value;
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public * entries() {
const values = this._values;
const version = this._version;
this._copyOnWrite = true;
try {
for (const value of values) {
yield [value, value] as [T, T];
}
}
finally {
if (version === this._version) {
this._copyOnWrite = false;
}
}
}
public [Symbol.iterator]() {
return this.values();
}
private writePreamble() {
if (this._copyOnWrite) {
this._values = this._values.slice();
this._copyOnWrite = false;
}
}
private writePostScript() {
this._version++;
}
}
export function binarySearch<T, U>(array: ReadonlyArray<T>, value: T, keySelector: (v: T) => U, keyComparer: (a: U, b: U) => number, offset?: number): number {
if (!array || array.length === 0) {
return -1;
}
let low = offset || 0;
let high = array.length - 1;
const key = keySelector(value);
while (low <= high) {
const middle = low + ((high - low) >> 1);
const midKey = keySelector(array[middle]);
const result = keyComparer(midKey, key);
if (result < 0) {
low = middle + 1;
}
else if (result > 0) {
high = middle - 1;
}
else {
return middle;
}
}
return ~low;
}
export function removeAt<T>(array: T[], index: number): void {
if (index < 0 || index >= array.length) {
return;
}
else if (index === 0) {
array.shift();
}
else if (index === array.length - 1) {
array.pop();
}
else {
for (let i = index; i < array.length - 1; i++) {
array[i] = array[i + 1];
}
array.length--;
}
}
export function insertAt<T>(array: T[], index: number, value: T): void {
if (index === 0) {
array.unshift(value);
}
else if (index === array.length) {
array.push(value);
}
else {
for (let i = array.length; i > index; i--) {
array[i] = array[i - 1];
}
array[index] = value;
}
}
/**
* A collection of metadata that supports inheritance.
*/
export class Metadata {
private static readonly _undefinedValue = {};
private _parent: Metadata | undefined;
private _map: { [key: string]: any };
private _version = 0;
private _size = -1;
private _parentVersion: number | undefined;
constructor(parent?: Metadata) {
this._parent = parent;
this._map = Object.create(parent ? parent._map : null); // tslint:disable-line:no-null-keyword
}
public get size(): number {
if (this._size === -1 || (this._parent && this._parent._version !== this._parentVersion)) {
let size = 0;
for (const _ in this._map) size++;
this._size = size;
if (this._parent) {
this._parentVersion = this._parent._version;
}
}
return this._size;
}
public get parent() {
return this._parent;
}
public has(key: string): boolean {
return this._map[Metadata._escapeKey(key)] !== undefined;
}
public get(key: string): any {
const value = this._map[Metadata._escapeKey(key)];
return value === Metadata._undefinedValue ? undefined : value;
}
public set(key: string, value: any): this {
this._map[Metadata._escapeKey(key)] = value === undefined ? Metadata._undefinedValue : value;
this._size = -1;
this._version++;
return this;
}
public delete(key: string): boolean {
const escapedKey = Metadata._escapeKey(key);
if (this._map[escapedKey] !== undefined) {
delete this._map[escapedKey];
this._size = -1;
this._version++;
return true;
}
return false;
}
public clear(): void {
this._map = Object.create(this._parent ? this._parent._map : null); // tslint:disable-line:no-null-keyword
this._size = -1;
this._version++;
}
public forEach(callback: (value: any, key: string, map: this) => void) {
for (const key in this._map) {
callback(this._map[key], Metadata._unescapeKey(key), this);
}
}
private static _escapeKey(text: string) {
return (text.length >= 2 && text.charAt(0) === "_" && text.charAt(1) === "_" ? "_" + text : text);
}
private static _unescapeKey(text: string) {
return (text.length >= 3 && text.charAt(0) === "_" && text.charAt(1) === "_" && text.charAt(2) === "_" ? text.slice(1) : text);
}
}
export * from "./functions";
export * from "./comparers";
export * from "./collections";

View File

@@ -21,14 +21,14 @@ namespace compiler {
public readonly shouldAssertInvariants = !Harness.lightMode;
private _setParentNodes: boolean;
private _sourceFiles: core.KeyedCollection<string, ts.SourceFile>;
private _sourceFiles: core.SortedMap<string, ts.SourceFile>;
private _newLine: string;
private _parseConfigHost: ParseConfigHost;
constructor(vfs: vfs.FileSystem, options: ts.CompilerOptions, setParentNodes = false) {
this.vfs = vfs;
this.defaultLibLocation = vfs.meta.get("defaultLibLocation") || "";
this._sourceFiles = new core.KeyedCollection<string, ts.SourceFile>(this.vfs.stringComparer);
this._sourceFiles = new core.SortedMap<string, ts.SourceFile>({ comparer: this.vfs.stringComparer, sort: "insertion" });
this._newLine = options.newLine === ts.NewLineKind.LineFeed ? "\n" : "\r\n";
this._setParentNodes = setParentNodes;
}
@@ -270,12 +270,12 @@ namespace compiler {
public readonly result: ts.EmitResult | undefined;
public readonly options: ts.CompilerOptions;
public readonly diagnostics: ReadonlyArray<ts.Diagnostic>;
public readonly js: core.ReadonlyKeyedCollection<string, documents.TextDocument>;
public readonly dts: core.ReadonlyKeyedCollection<string, documents.TextDocument>;
public readonly maps: core.ReadonlyKeyedCollection<string, documents.TextDocument>;
public readonly js: ReadonlyMap<string, documents.TextDocument>;
public readonly dts: ReadonlyMap<string, documents.TextDocument>;
public readonly maps: ReadonlyMap<string, documents.TextDocument>;
private _inputs: documents.TextDocument[] = [];
private _inputsAndOutputs: core.KeyedCollection<string, CompilationOutput>;
private _inputsAndOutputs: core.SortedMap<string, CompilationOutput>;
constructor(host: CompilerHost, options: ts.CompilerOptions, program: ts.Program | undefined, result: ts.EmitResult | undefined, diagnostics: ts.Diagnostic[]) {
this.host = host;
@@ -285,9 +285,9 @@ namespace compiler {
this.options = program ? program.getCompilerOptions() : options;
// collect outputs
const js = this.js = new core.KeyedCollection<string, documents.TextDocument>(this.vfs.stringComparer);
const dts = this.dts = new core.KeyedCollection<string, documents.TextDocument>(this.vfs.stringComparer);
const maps = this.maps = new core.KeyedCollection<string, documents.TextDocument>(this.vfs.stringComparer);
const js = this.js = new core.SortedMap<string, documents.TextDocument>({ comparer: this.vfs.stringComparer, sort: "insertion" });
const dts = this.dts = new core.SortedMap<string, documents.TextDocument>({ comparer: this.vfs.stringComparer, sort: "insertion" });
const maps = this.maps = new core.SortedMap<string, documents.TextDocument>({ comparer: this.vfs.stringComparer, sort: "insertion" });
for (const document of this.host.outputs) {
if (vfsutils.isJavaScript(document.file)) {
js.set(document.file, document);
@@ -301,7 +301,7 @@ namespace compiler {
}
// correlate inputs and outputs
this._inputsAndOutputs = new core.KeyedCollection<string, CompilationOutput>(this.vfs.stringComparer);
this._inputsAndOutputs = new core.SortedMap<string, CompilationOutput>({ comparer: this.vfs.stringComparer, sort: "insertion" });
if (program) {
if (this.options.out || this.options.outFile) {
const outFile = vpath.resolve(this.vfs.cwd(), this.options.outFile || this.options.out);

View File

@@ -1,671 +1,62 @@
// NOTE: The contents of this file are all exported from the namespace 'core'. This is to
// support the eventual conversion of harness into a modular system.
// NOTE: Some of the functions here duplicate functionality from compiler/core.ts. They have been added
// to reduce the number of direct dependencies on compiler and services to eventually break away
// from depending directly on the compiler to speed up compilation time.
// NOTE: This namespace re-exports all of the exports from the @typescript/harness-core private package.
namespace core {
export function identity<T>(v: T): T { return v; }
const _core = require("@typescript/harness-core");
core.identity = _core.identity;
core.compareNumbers = _core.compareNumbers;
core.compareStrings = _core.compareStrings;
core.compareStringsCaseSensitive = _core.compareStringsCaseSensitive;
core.compareStringsCaseInsensitive = _core.compareStringsCaseInsensitive;
core.equateStringsCaseSensitive = _core.equateStringsCaseSensitive;
core.equateStringsCaseInsensitive = _core.equateStringsCaseInsensitive;
core.SortedMap = _core.SortedMap;
core.SortedSet = _core.SortedSet;
core.binarySearch = _core.binarySearch;
core.removeAt = _core.removeAt;
core.insertAt = _core.insertAt;
core.Metadata = _core.Metadata;
core.padLeft = _core.padLeft;
core.padRight = _core.padRight;
core.getByteOrderMark = _core.getByteOrderMark;
core.getByteOrderMarkLength = _core.getByteOrderMarkLength;
core.removeByteOrderMark = _core.removeByteOrderMark;
core.addUTF8ByteOrderMark = _core.addUTF8ByteOrderMark;
core.getLinesAndLineStarts = _core.getLinesAndLineStarts;
core.splitLines = _core.splitLines;
core.computeLineStarts = _core.computeLineStarts;
core.sha1 = _core.sha1;
}
//
// Comparers
//
export type Comparer<T> = (x: T, y: T) => number;
export type EqualityComparer<T> = (x: T, y: T) => boolean;
export function compareNumbers(a: number, b: number): number {
if (a === b) return 0;
if (a === undefined) return -1;
if (b === undefined) return +1;
return a < b ? -1 : +1;
}
export function compareStrings(a: string, b: string, ignoreCase: boolean): number {
return ignoreCase
? compareStringsCaseInsensitive(a, b)
: compareStringsCaseSensitive(a, b);
}
// NOTE: This is a duplicate of `compareNumbers` above, but is intended to be used only with
// strings to reduce polymorphism.
export function compareStringsCaseSensitive(a: string, b: string): number {
if (a === b) return 0;
if (a === undefined) return -1;
if (b === undefined) return +1;
return a < b ? -1 : +1;
}
export function compareStringsCaseInsensitive(a: string, b: string): number {
if (a === b) return 0;
if (a === undefined) return -1;
if (b === undefined) return +1;
a = a.toUpperCase();
b = b.toUpperCase();
return a < b ? -1 : a > b ? +1 : 0;
}
export function equateStringsCaseSensitive(a: string, b: string): boolean {
return a === b;
}
export function equateStringsCaseInsensitive(a: string, b: string): boolean {
return a === b
|| a !== undefined
&& b !== undefined
&& a.toUpperCase() === b.toUpperCase();
}
//
// Collections
//
export interface ReadonlyKeyedCollection<K, V> {
readonly size: number;
has(key: K): boolean;
get(key: K): V | undefined;
forEach(callback: (value: V, key: K, collection: this) => void): void;
keys(): IterableIterator<K>;
values(): IterableIterator<V>;
entries(): IterableIterator<[K, V]>;
}
/**
* A collection of key/value pairs internally sorted by key.
*/
export class KeyedCollection<K, V> implements ReadonlyKeyedCollection<K, V> {
private _comparer: (a: K, b: K) => number;
private _keys: K[] = [];
private _values: V[] = [];
private _order: number[] = [];
private _version = 0;
private _copyOnWrite = false;
constructor(comparer: (a: K, b: K) => number) {
this._comparer = comparer;
declare module "_core" {
import * as _core from "@typescript/harness-core";
global {
namespace core {
export import identity = _core.identity;
export import compareNumbers = _core.compareNumbers;
export import compareStrings = _core.compareStrings;
export import compareStringsCaseSensitive = _core.compareStringsCaseSensitive;
export import compareStringsCaseInsensitive = _core.compareStringsCaseInsensitive;
export import equateStringsCaseSensitive = _core.equateStringsCaseSensitive;
export import equateStringsCaseInsensitive = _core.equateStringsCaseInsensitive;
export import SortOptions = _core.SortOptions;
export import SortedMap = _core.SortedMap;
export import SortedSet = _core.SortedSet;
export import binarySearch = _core.binarySearch;
export import removeAt = _core.removeAt;
export import insertAt = _core.insertAt;
export import Metadata = _core.Metadata;
export import padLeft = _core.padLeft;
export import padRight = _core.padRight;
export import getByteOrderMark = _core.getByteOrderMark;
export import getByteOrderMarkLength = _core.getByteOrderMarkLength;
export import removeByteOrderMark = _core.removeByteOrderMark;
export import addUTF8ByteOrderMark = _core.addUTF8ByteOrderMark;
export import LineStarts = _core.LineStarts;
export import LinesAndLineStarts = _core.LinesAndLineStarts;
export import getLinesAndLineStarts = _core.getLinesAndLineStarts;
export import splitLines = _core.splitLines;
export import computeLineStarts = _core.computeLineStarts;
export import sha1 = _core.sha1;
}
public get size() {
return this._keys.length;
}
public has(key: K) {
return binarySearch(this._keys, key, identity, this._comparer) >= 0;
}
public get(key: K) {
const index = binarySearch(this._keys, key, identity, this._comparer);
return index >= 0 ? this._values[index] : undefined;
}
public set(key: K, value: V) {
const index = binarySearch(this._keys, key, identity, this._comparer);
if (index >= 0) {
this._values[index] = value;
}
else {
this.writePreamble();
insertAt(this._keys, ~index, key);
insertAt(this._values, ~index, value);
insertAt(this._order, ~index, this._version);
this.writePostScript();
}
return this;
}
public delete(key: K) {
const index = binarySearch(this._keys, key, identity, this._comparer);
if (index >= 0) {
this.writePreamble();
removeAt(this._keys, index);
removeAt(this._values, index);
removeAt(this._order, index);
this.writePostScript();
return true;
}
return false;
}
public clear() {
if (this.size > 0) {
this.writePreamble();
this._keys.length = 0;
this._values.length = 0;
this._order.length = 0;
this.writePostScript();
}
}
public forEach(callback: (value: V, key: K, collection: this) => void) {
const keys = this._keys;
const values = this._values;
const order = this.getInsertionOrder();
const version = this._version;
this._copyOnWrite = true;
for (const index of order) {
callback(values[index], keys[index], this);
}
if (version === this._version) {
this._copyOnWrite = false;
}
}
public * keys() {
const keys = this._keys;
const order = this.getInsertionOrder();
const version = this._version;
this._copyOnWrite = true;
for (const index of order) {
yield keys[index];
}
if (version === this._version) {
this._copyOnWrite = false;
}
}
public * values() {
const values = this._values;
const order = this.getInsertionOrder();
const version = this._version;
this._copyOnWrite = true;
for (const index of order) {
yield values[index];
}
if (version === this._version) {
this._copyOnWrite = false;
}
}
public * entries() {
const keys = this._keys;
const values = this._values;
const order = this.getInsertionOrder();
const version = this._version;
this._copyOnWrite = true;
for (const index of order) {
yield [keys[index], values[index]] as [K, V];
}
if (version === this._version) {
this._copyOnWrite = false;
}
}
public [Symbol.iterator]() {
return this.entries();
}
private writePreamble() {
if (this._copyOnWrite) {
this._keys = this._keys.slice();
this._values = this._values.slice();
this._order = this._order.slice();
this._copyOnWrite = false;
}
}
private writePostScript() {
this._version++;
}
private getInsertionOrder() {
return this._order
.map((_, i) => i)
.sort((x, y) => this._order[x] - this._order[y]);
}
}
export class SortedSet<T> implements ReadonlySet<T> {
private _comparer: (a: T, b: T) => number;
private _values: T[] = [];
private _version = 0;
private _copyOnWrite = false;
constructor(comparer: (a: T, b: T) => number) {
this._comparer = comparer;
}
public get size() {
return this._values.length;
}
public has(value: T) {
return binarySearch(this._values, value, identity, this._comparer) >= 0;
}
public add(value: T) {
const index = binarySearch(this._values, value, identity, this._comparer);
if (index < 0) {
this.writePreamble();
insertAt(this._values, ~index, value);
this.writePostScript();
}
return this;
}
public delete(value: T) {
const index = binarySearch(this._values, value, identity, this._comparer);
if (index >= 0) {
this.writePreamble();
removeAt(this._values, index);
this.writePostScript();
return true;
}
return false;
}
public clear() {
if (this.size > 0) {
this.writePreamble();
this._values.length = 0;
this.writePostScript();
}
}
public forEach(callback: (value: T, key: T, collection: this) => void) {
const values = this._values;
const version = this._version;
this._copyOnWrite = true;
for (const value of values) {
callback(value, value, this);
}
if (version === this._version) {
this._copyOnWrite = false;
}
}
public keys() {
return this.values();
}
public * values() {
const values = this._values;
const version = this._version;
this._copyOnWrite = true;
for (const value of values) {
yield value;
}
if (version === this._version) {
this._copyOnWrite = false;
}
}
public * entries() {
const values = this._values;
const version = this._version;
this._copyOnWrite = true;
for (const value of values) {
yield [value, value] as [T, T];
}
if (version === this._version) {
this._copyOnWrite = false;
}
}
public [Symbol.iterator]() {
return this.values();
}
private writePreamble() {
if (this._copyOnWrite) {
this._values = this._values.slice();
this._copyOnWrite = false;
}
}
private writePostScript() {
this._version++;
}
}
/**
* A collection of metadata that supports inheritance.
*/
export class Metadata {
private static readonly _undefinedValue = {};
private _parent: Metadata | undefined;
private _map: { [key: string]: any };
private _version = 0;
private _size = -1;
private _parentVersion: number | undefined;
constructor(parent?: Metadata) {
this._parent = parent;
this._map = Object.create(parent ? parent._map : null); // tslint:disable-line:no-null-keyword
}
public get size(): number {
if (this._size === -1 || (this._parent && this._parent._version !== this._parentVersion)) {
let size = 0;
for (const _ in this._map) size++;
this._size = size;
if (this._parent) {
this._parentVersion = this._parent._version;
}
}
return this._size;
}
public has(key: string): boolean {
return this._map[Metadata._escapeKey(key)] !== undefined;
}
public get(key: string): any {
const value = this._map[Metadata._escapeKey(key)];
return value === Metadata._undefinedValue ? undefined : value;
}
public set(key: string, value: any): this {
this._map[Metadata._escapeKey(key)] = value === undefined ? Metadata._undefinedValue : value;
this._size = -1;
this._version++;
return this;
}
public delete(key: string): boolean {
const escapedKey = Metadata._escapeKey(key);
if (this._map[escapedKey] !== undefined) {
delete this._map[escapedKey];
this._size = -1;
this._version++;
return true;
}
return false;
}
public clear(): void {
this._map = Object.create(this._parent ? this._parent._map : null); // tslint:disable-line:no-null-keyword
this._size = -1;
this._version++;
}
public forEach(callback: (value: any, key: string, map: this) => void) {
for (const key in this._map) {
callback(this._map[key], Metadata._unescapeKey(key), this);
}
}
private static _escapeKey(text: string) {
return (text.length >= 2 && text.charAt(0) === "_" && text.charAt(1) === "_" ? "_" + text : text);
}
private static _unescapeKey(text: string) {
return (text.length >= 3 && text.charAt(0) === "_" && text.charAt(1) === "_" && text.charAt(2) === "_" ? text.slice(1) : text);
}
}
export function binarySearch<T, U>(array: ReadonlyArray<T>, value: T, keySelector: (v: T) => U, keyComparer: Comparer<U>, offset?: number): number {
if (!array || array.length === 0) {
return -1;
}
let low = offset || 0;
let high = array.length - 1;
const key = keySelector(value);
while (low <= high) {
const middle = low + ((high - low) >> 1);
const midKey = keySelector(array[middle]);
const result = keyComparer(midKey, key);
if (result < 0) {
low = middle + 1;
}
else if (result > 0) {
high = middle - 1;
}
else {
return middle;
}
}
return ~low;
}
export function removeAt<T>(array: T[], index: number): void {
if (index < 0 || index >= array.length) {
return;
}
else if (index === 0) {
array.shift();
}
else if (index === array.length - 1) {
array.pop();
}
else {
for (let i = index; i < array.length - 1; i++) {
array[i] = array[i + 1];
}
array.length--;
}
}
export function insertAt<T>(array: T[], index: number, value: T): void {
if (index === 0) {
array.unshift(value);
}
else if (index === array.length) {
array.push(value);
}
else {
for (let i = array.length; i > index; i--) {
array[i] = array[i - 1];
}
array[index] = value;
}
}
export function stableSort<T>(array: T[], comparer: (x: T, y: T) => number): T[] {
return array
.map((_, i) => i) // create array of indices
.sort((x, y) => comparer(array[x], array[y]) || x - y) // sort indices by value then position
.map(i => array[i]); // get sorted array
}
//
// Strings
//
export function padLeft(text: string, size: number, ch = " "): string {
while (text.length < size) text = ch + text;
return text;
}
export function padRight(text: string, size: number, ch = " "): string {
while (text.length < size) text += ch;
return text;
}
export function getByteOrderMark(text: string): string {
const length = getByteOrderMarkLength(text);
return length > 0 ? text.slice(0, length) : "";
}
export function getByteOrderMarkLength(text: string): number {
if (text.length >= 2) {
const ch0 = text.charCodeAt(0);
const ch1 = text.charCodeAt(1);
if ((ch0 === 0xff && ch1 === 0xfe) ||
(ch0 === 0xfe && ch1 === 0xff)) {
return 2;
}
if (text.length >= 3 && ch0 === 0xef && ch1 === 0xbb && text.charCodeAt(2) === 0xbf) {
return 3;
}
}
return 0;
}
export function removeByteOrderMark(text: string): string {
const length = getByteOrderMarkLength(text);
return length ? text.slice(length) : text;
}
export function addUTF8ByteOrderMark(text: string) {
return getByteOrderMarkLength(text) === 0 ? "\u00EF\u00BB\u00BF" + text : text;
}
function splitLinesWorker(text: string, lineStarts: number[] | undefined, lines: string[] | undefined, removeEmptyElements: boolean) {
let pos = 0;
let end = 0;
let lineStart = 0;
let nonWhiteSpace = false;
while (pos < text.length) {
const ch = text.charCodeAt(pos);
end = pos;
pos++;
switch (ch) {
// LineTerminator
case 0x000d: // <CR> carriage return
if (pos < text.length && text.charCodeAt(pos) === 0x000a) {
pos++;
}
// falls through
case 0x000a: // <LF> line feed
case 0x2028: // <LS> line separator
case 0x2029: // <PS> paragraph separator
if (lineStarts) {
lineStarts.push(lineStart);
}
if (lines && (!removeEmptyElements || nonWhiteSpace)) {
lines.push(text.slice(lineStart, end));
}
lineStart = pos;
nonWhiteSpace = false;
break;
// WhiteSpace
case 0x0009: // <TAB> tab
case 0x000b: // <VT> vertical tab
case 0x000c: // <FF> form feed
case 0x0020: // <SP> space
case 0x00a0: // <NBSP> no-break space
case 0xfeff: // <ZWNBSP> zero width no-break space
case 0x1680: // <USP> ogham space mark
case 0x2000: // <USP> en quad
case 0x2001: // <USP> em quad
case 0x2002: // <USP> en space
case 0x2003: // <USP> em space
case 0x2004: // <USP> three-per-em space
case 0x2005: // <USP> four-per-em space
case 0x2006: // <USP> six-per-em space
case 0x2007: // <USP> figure space
case 0x2008: // <USP> punctuation space
case 0x2009: // <USP> thin space
case 0x200a: // <USP> hair space
case 0x202f: // <USP> narrow no-break space
case 0x205f: // <USP> medium mathematical space
case 0x3000: // <USP> ideographic space
case 0x0085: // next-line (not strictly per spec, but used by the compiler)
break;
default:
nonWhiteSpace = true;
break;
}
}
if (lineStarts) {
lineStarts.push(lineStart);
}
if (lines && (!removeEmptyElements || nonWhiteSpace)) {
lines.push(text.slice(lineStart, text.length));
}
}
export type LineStarts = ReadonlyArray<number>;
export interface LinesAndLineStarts {
readonly lines: ReadonlyArray<string>;
readonly lineStarts: LineStarts;
}
export function getLinesAndLineStarts(text: string): LinesAndLineStarts {
const lines: string[] = [];
const lineStarts: number[] = [];
splitLinesWorker(text, lineStarts, lines, /*removeEmptyElements*/ false);
return { lines, lineStarts };
}
export function splitLines(text: string, removeEmptyElements = false): string[] {
const lines: string[] = [];
splitLinesWorker(text, /*lineStarts*/ undefined, lines, removeEmptyElements);
return lines;
}
export function computeLineStarts(text: string): LineStarts {
const lineStarts: number[] = [];
splitLinesWorker(text, lineStarts, /*lines*/ undefined, /*removeEmptyElements*/ false);
return lineStarts;
}
//
// Cryptography
//
const H = new Uint32Array(5);
const W = new Uint8Array(80);
const B = new Uint8Array(64);
const BLOCK_SIZE = 64;
export function sha1(message: string): string {
let buffer = B;
const textSize = message.length;
const messageSize = textSize * 2;
const finalBlockSize = messageSize % BLOCK_SIZE;
const padSize = (finalBlockSize < BLOCK_SIZE - 8 - 1 ? BLOCK_SIZE : BLOCK_SIZE * 2) - finalBlockSize;
const byteLength = messageSize + padSize;
if (byteLength > BLOCK_SIZE) {
buffer = new Uint8Array(byteLength);
}
const bufferView = new DataView(buffer.buffer);
for (let i = 0; i < textSize; ++i) {
bufferView.setUint16(i * 2, message.charCodeAt(i));
}
buffer[messageSize] = 0x80;
bufferView.setUint32(byteLength - 4, messageSize * 8);
H[0] = 0x67452301, H[1] = 0xefcdab89, H[2] = 0x98badcfe, H[3] = 0x10325476, H[4] = 0xc3d2e1f0;
for (let offset = 0; offset < byteLength; offset += BLOCK_SIZE) {
let a = H[0], b = H[1], c = H[2], d = H[3], e = H[4];
for (let i = 0; i < 80; ++i) {
if (i < 16) {
const x = offset + i * 4;
W[i] = buffer[x] << 24 | buffer[x + 1] << 16 | buffer[x + 2] << 8 | buffer[x + 3];
}
else {
const x = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
W[i] = (x << 1 | x >>> 31) >>> 0;
}
let t = (a << 5 | a >>> 27) >>> 0 + e + W[i];
if (i < 20) {
t += ((b & c) | (~b & d)) + 0x5A827999;
}
else if (i < 40) {
t += (b ^ c ^ d) + 0x6ED9EBA1;
}
else if (i < 60) {
t += ((b & c) | (b & d) | (c & d)) + 0x8F1BBCDC;
}
else {
t += (b ^ c ^ d) + 0xCA62C1D6;
}
e = d, d = c, c = (b << 30 | b >>> 2) >>> 0, b = a, a = t;
}
H[0] += a, H[1] += b, H[2] += c, H[3] += d, H[4] += e;
}
for (let i = 0; i < 5; ++i) {
bufferView.setUint32(i * 4, H[i]);
}
let result = "";
for (let i = 0; i < 20; ++i) {
result += (buffer[i] < 16 ? "0" : "") + buffer[i].toString(16);
}
return result;
}
}

View File

@@ -78,11 +78,11 @@ namespace fakes {
private readonly _executingFilePath: string;
private readonly _getCanonicalFileName: (file: string) => string;
private _screenClears = 0;
private _watchedFiles: core.KeyedCollection<string, number> | undefined;
private _watchedFiles: core.SortedMap<string, number> | undefined;
private _watchedFilesSet: core.SortedSet<string> | undefined;
private _watchedRecursiveDirectories: core.KeyedCollection<string, number> | undefined;
private _watchedRecursiveDirectories: core.SortedMap<string, number> | undefined;
private _watchedRecursiveDirectoriesSet: core.SortedSet<string> | undefined;
private _watchedNonRecursiveDirectories: core.KeyedCollection<string, number> | undefined;
private _watchedNonRecursiveDirectories: core.SortedMap<string, number> | undefined;
private _watchedNonRecursiveDirectoriesSet: core.SortedSet<string> | undefined;
constructor(options: FakeServerHostOptions = {}, files?: vfs.FileSet) {
@@ -201,7 +201,7 @@ namespace fakes {
}
public watchFile(path: string, cb: ts.FileWatcherCallback) {
if (!this._watchedFiles) this._watchedFiles = new core.KeyedCollection<string, number>(this.vfs.stringComparer);
if (!this._watchedFiles) this._watchedFiles = new core.SortedMap<string, number>({ comparer: this.vfs.stringComparer, sort: "insertion" });
if (!this._watchedFilesSet) this._watchedFilesSet = new core.SortedSet<string>(this.vfs.stringComparer);
const previousCount = this._watchedFiles.get(path) || 0;
@@ -235,8 +235,8 @@ namespace fakes {
public watchDirectory(path: string, cb: ts.DirectoryWatcherCallback, recursive?: boolean): ts.FileWatcher {
const watchedDirectories = recursive
? this._watchedRecursiveDirectories || (this._watchedRecursiveDirectories = new core.KeyedCollection(this.vfs.stringComparer))
: this._watchedNonRecursiveDirectories || (this._watchedNonRecursiveDirectories = new core.KeyedCollection(this.vfs.stringComparer));
? this._watchedRecursiveDirectories || (this._watchedRecursiveDirectories = new core.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }))
: this._watchedNonRecursiveDirectories || (this._watchedNonRecursiveDirectories = new core.SortedMap({ comparer: this.vfs.stringComparer, sort: "insertion" }));
const watchedDirectoriesSet = recursive
? this._watchedRecursiveDirectoriesSet || (this._watchedRecursiveDirectoriesSet = new core.SortedSet(this.vfs.stringComparer))

View File

@@ -1,9 +1,4 @@
/// <reference path="./core.ts" />
/// <reference path="./utils.ts" />
/// <reference path="./vfs.ts" />
// NOTE: The contents of this file are all exported from the namespace 'typemock'. This is to
// support the eventual conversion of harness into a modular system.
// NOTE: This namespace re-exports all of the exports from the typemock private package.
// typemock library
namespace typemock {

View File

@@ -1,6 +1,6 @@
/// <reference path="./core.ts" />
// NOTE: The contents of this file are all exported from the namespace 'core'. This is to
// NOTE: The contents of this file are all exported from the namespace 'utils'. This is to
// support the eventual conversion of harness into a modular system.
namespace utils {

View File

@@ -1,43 +1,35 @@
/// <reference path="../compiler/commandLineParser.ts"/>
/// <reference path="./harness.ts" />
/// <reference path="./core.ts" />
/// <reference path="./events.ts" />
/// <reference path="./vpath.ts" />
/// <reference path="./documents.ts" />
// NOTE: The contents of this file are all exported from the namespace 'vfs'. This is to
// support the eventual conversion of harness into a modular system.
// NOTE: This namespace re-exports all of the exports from the @typescript/vfs private package.
namespace vfs {
const module = require("@typescript/vfs");
vfs.Directory = module.Directory;
vfs.File = module.File;
vfs.Link = module.Link;
vfs.Symlink = module.Symlink;
vfs.Mount = module.Mount;
vfs.FileSystem = module.FileSystem;
vfs.Stats = module.Stats;
vfs.FSWatcher = module.FSWatcher;
const _vfs = require("@typescript/vfs");
vfs.Directory = _vfs.Directory;
vfs.File = _vfs.File;
vfs.Link = _vfs.Link;
vfs.Symlink = _vfs.Symlink;
vfs.Mount = _vfs.Mount;
vfs.FileSystem = _vfs.FileSystem;
vfs.Stats = _vfs.Stats;
vfs.FSWatcher = _vfs.FSWatcher;
}
declare module "vfs_" {
import * as vfs_ from "@typescript/vfs";
declare module "_vfs" {
import * as _vfs from "@typescript/vfs";
global {
namespace vfs {
export import FileSystemResolver = vfs_.FileSystemResolver;
export import FileSystemTimers = vfs_.FileSystemTimers;
export import FileSet = vfs_.FileSet;
export import Directory = vfs_.Directory;
export import DirectoryLike = vfs_.DirectoryLike;
export import File = vfs_.File;
export import FileLike = vfs_.FileLike;
export import Link = vfs_.Link;
export import Symlink = vfs_.Symlink;
export import Mount = vfs_.Mount;
export import FileSystemOptions = vfs_.FileSystemOptions;
export import FileSystem = vfs_.FileSystem;
export import Stats = vfs_.Stats;
export import FSWatcher = vfs_.FSWatcher;
export import FileSystemResolver = _vfs.FileSystemResolver;
export import FileSystemTimers = _vfs.FileSystemTimers;
export import FileSet = _vfs.FileSet;
export import Directory = _vfs.Directory;
export import DirectoryLike = _vfs.DirectoryLike;
export import File = _vfs.File;
export import FileLike = _vfs.FileLike;
export import Link = _vfs.Link;
export import Symlink = _vfs.Symlink;
export import Mount = _vfs.Mount;
export import FileSystemOptions = _vfs.FileSystemOptions;
export import FileSystem = _vfs.FileSystem;
export import Stats = _vfs.Stats;
export import FSWatcher = _vfs.FSWatcher;
}
}
}

View File

@@ -1,66 +1,61 @@
// NOTE: The contents of this file are all exported from the namespace 'vpath'. This is to
// support the eventual conversion of harness into a modular system.
// NOTE: Some of the functions here duplicate functionality from compiler/core.ts. They have been
// added to reduce the number of direct dependencies on compiler and services to eventually
// break away from depending directly on the compiler to speed up compilation time.
// NOTE: This namespace re-exports all of the exports from the @typescript/vfs-path private package.
namespace vpath {
const module = require("@typescript/vfs-path");
vpath.sep = module.sep;
vpath.normalizeSeparators = module.normalizeSeparators;
(<any>vpath).ValidationFlags = module.ValidationFlags;
vpath.valid = module.valid;
vpath.validate = module.validate;
vpath.isAbsolute = module.isAbsolute;
vpath.hasTrailingSeparator = module.hasTrailingSeparator;
vpath.addTrailingSeparator = module.addTrailingSeparator;
vpath.removeTrailingSeparator = module.removeTrailingSeparator;
vpath.normalize = module.normalize;
vpath.combine = module.combine;
vpath.resolve = module.resolve;
vpath.relative = module.relative;
vpath.compareCaseSensitive = module.compareCaseSensitive;
vpath.compareCaseInsensitive = module.compareCaseInsensitive;
vpath.compare = module.compare;
vpath.equals = module.equals;
vpath.beneath = module.beneath;
vpath.parse = module.parse;
vpath.format = module.format;
vpath.dirname = module.dirname;
vpath.basename = module.basename;
vpath.extname = module.extname;
vpath.changeExtension = module.changeExtension;
const _vpath = require("@typescript/vfs-path") as typeof vpath;
vpath.sep = _vpath.sep;
vpath.normalizeSeparators = _vpath.normalizeSeparators;
(<any>vpath).ValidationFlags = (<any>_vpath).ValidationFlags;
vpath.valid = _vpath.valid;
vpath.validate = _vpath.validate;
vpath.isAbsolute = _vpath.isAbsolute;
vpath.hasTrailingSeparator = _vpath.hasTrailingSeparator;
vpath.addTrailingSeparator = _vpath.addTrailingSeparator;
vpath.removeTrailingSeparator = _vpath.removeTrailingSeparator;
vpath.normalize = _vpath.normalize;
vpath.combine = _vpath.combine;
vpath.resolve = _vpath.resolve;
vpath.relative = _vpath.relative;
vpath.compareCaseSensitive = _vpath.compareCaseSensitive;
vpath.compareCaseInsensitive = _vpath.compareCaseInsensitive;
vpath.compare = _vpath.compare;
vpath.equals = _vpath.equals;
vpath.beneath = _vpath.beneath;
vpath.parse = _vpath.parse;
vpath.format = _vpath.format;
vpath.dirname = _vpath.dirname;
vpath.basename = _vpath.basename;
vpath.extname = _vpath.extname;
vpath.changeExtension = _vpath.changeExtension;
}
declare module "vpath_" {
import * as vpath_ from "@typescript/vfs-path";
declare module "_vpath" {
import * as _vpath from "@typescript/vfs-path";
global {
namespace vpath {
export import sep = vpath_.sep;
export import normalizeSeparators = vpath_.normalizeSeparators;
export import ValidationFlags = vpath_.ValidationFlags;
export import valid = vpath_.valid;
export import validate = vpath_.validate;
export import isAbsolute = vpath_.isAbsolute;
export import hasTrailingSeparator = vpath_.hasTrailingSeparator;
export import addTrailingSeparator = vpath_.addTrailingSeparator;
export import removeTrailingSeparator = vpath_.removeTrailingSeparator;
export import normalize = vpath_.normalize;
export import combine = vpath_.combine;
export import resolve = vpath_.resolve;
export import relative = vpath_.relative;
export import compareCaseSensitive = vpath_.compareCaseSensitive;
export import compareCaseInsensitive = vpath_.compareCaseInsensitive;
export import compare = vpath_.compare;
export import equals = vpath_.equals;
export import beneath = vpath_.beneath;
export import parse = vpath_.parse;
export import format = vpath_.format;
export import dirname = vpath_.dirname;
export import basename = vpath_.basename;
export import extname = vpath_.extname;
export import changeExtension = vpath_.changeExtension;
export import sep = _vpath.sep;
export import normalizeSeparators = _vpath.normalizeSeparators;
export import ValidationFlags = _vpath.ValidationFlags;
export import valid = _vpath.valid;
export import validate = _vpath.validate;
export import isAbsolute = _vpath.isAbsolute;
export import hasTrailingSeparator = _vpath.hasTrailingSeparator;
export import addTrailingSeparator = _vpath.addTrailingSeparator;
export import removeTrailingSeparator = _vpath.removeTrailingSeparator;
export import normalize = _vpath.normalize;
export import combine = _vpath.combine;
export import resolve = _vpath.resolve;
export import relative = _vpath.relative;
export import compareCaseSensitive = _vpath.compareCaseSensitive;
export import compareCaseInsensitive = _vpath.compareCaseInsensitive;
export import compare = _vpath.compare;
export import equals = _vpath.equals;
export import beneath = _vpath.beneath;
export import parse = _vpath.parse;
export import format = _vpath.format;
export import dirname = _vpath.dirname;
export import basename = _vpath.basename;
export import extname = _vpath.extname;
export import changeExtension = _vpath.changeExtension;
}
}
}