ponicode
Version:
Ponicode is a quick and easy AI-powered solution for Javascript unit testing.
1,356 lines (1,323 loc) • 103 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var ts = require('typescript');
var path = require('path');
var toAbsoluteGlob = require('@dsherret/to-absolute-glob');
var isNegatedGlob = require('is-negated-glob');
var multimatch = require('multimatch');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () {
return e[k];
}
});
}
});
}
n['default'] = e;
return Object.freeze(n);
}
var ts__namespace = /*#__PURE__*/_interopNamespace(ts);
var toAbsoluteGlob__default = /*#__PURE__*/_interopDefaultLegacy(toAbsoluteGlob);
var isNegatedGlob__default = /*#__PURE__*/_interopDefaultLegacy(isNegatedGlob);
var multimatch__default = /*#__PURE__*/_interopDefaultLegacy(multimatch);
class KeyValueCache {
constructor() {
this.cacheItems = new Map();
}
getSize() {
return this.cacheItems.size;
}
getValues() {
return this.cacheItems.values();
}
getValuesAsArray() {
return Array.from(this.getValues());
}
getKeys() {
return this.cacheItems.keys();
}
getEntries() {
return this.cacheItems.entries();
}
getOrCreate(key, createFunc) {
let item = this.get(key);
if (item == null) {
item = createFunc();
this.set(key, item);
}
return item;
}
has(key) {
return this.cacheItems.has(key);
}
get(key) {
return this.cacheItems.get(key);
}
set(key, value) {
this.cacheItems.set(key, value);
}
replaceKey(key, newKey) {
if (!this.cacheItems.has(key))
throw new Error("Key not found.");
const value = this.cacheItems.get(key);
this.cacheItems.delete(key);
this.cacheItems.set(newKey, value);
}
removeByKey(key) {
this.cacheItems.delete(key);
}
clear() {
this.cacheItems.clear();
}
}
class ArrayUtils {
constructor() {
}
static isReadonlyArray(a) {
return a instanceof Array;
}
static isNullOrEmpty(a) {
return !(a instanceof Array) || a.length === 0;
}
static getUniqueItems(a) {
return a.filter((item, index) => a.indexOf(item) === index);
}
static removeFirst(a, item) {
const index = a.indexOf(item);
if (index === -1)
return false;
a.splice(index, 1);
return true;
}
static removeAll(a, isMatch) {
const removedItems = [];
for (let i = a.length - 1; i >= 0; i--) {
if (isMatch(a[i])) {
removedItems.push(a[i]);
a.splice(i, 1);
}
}
return removedItems;
}
static flatten(items) {
return items.reduce((a, b) => a.concat(b), []);
}
static from(items) {
const a = [];
for (const item of items)
a.push(item);
return a;
}
static *toIterator(items) {
for (const item of items)
yield item;
}
static sortByProperty(items, getProp) {
items.sort((a, b) => getProp(a) <= getProp(b) ? -1 : 1);
return items;
}
static groupBy(items, getGroup) {
const result = [];
const groups = {};
for (const item of items) {
const group = getGroup(item).toString();
if (groups[group] == null) {
groups[group] = [];
result.push(groups[group]);
}
groups[group].push(item);
}
return result;
}
static binaryInsertWithOverwrite(items, newItem, comparer) {
let top = items.length - 1;
let bottom = 0;
while (bottom <= top) {
const mid = Math.floor((top + bottom) / 2);
if (comparer.compareTo(newItem, items[mid]) < 0)
top = mid - 1;
else
bottom = mid + 1;
}
if (items[top] != null && comparer.compareTo(newItem, items[top]) === 0)
items[top] = newItem;
else
items.splice(top + 1, 0, newItem);
}
static binarySearch(items, storedComparer) {
let top = items.length - 1;
let bottom = 0;
while (bottom <= top) {
const mid = Math.floor((top + bottom) / 2);
const comparisonResult = storedComparer.compareTo(items[mid]);
if (comparisonResult === 0)
return mid;
else if (comparisonResult < 0)
top = mid - 1;
else
bottom = mid + 1;
}
return -1;
}
static containsSubArray(items, subArray) {
let findIndex = 0;
for (const item of items) {
if (subArray[findIndex] === item) {
findIndex++;
if (findIndex === subArray.length)
return true;
}
else {
findIndex = 0;
}
}
return false;
}
}
function deepClone(objToClone) {
return clone(objToClone);
function clone(obj) {
const newObj = Object.create(obj.constructor.prototype);
for (const propName of Object.keys(obj))
newObj[propName] = cloneItem(obj[propName]);
return newObj;
}
function cloneArray(array) {
return array.map(cloneItem);
}
function cloneItem(item) {
if (item instanceof Array)
return cloneArray(item);
else if (typeof item === "object")
return item === null ? item : clone(item);
return item;
}
}
class EventContainer {
constructor() {
this.subscriptions = [];
}
subscribe(subscription) {
const index = this.getIndex(subscription);
if (index === -1)
this.subscriptions.push(subscription);
}
unsubscribe(subscription) {
const index = this.getIndex(subscription);
if (index >= 0)
this.subscriptions.splice(index, 1);
}
fire(arg) {
for (const subscription of this.subscriptions)
subscription(arg);
}
getIndex(subscription) {
return this.subscriptions.indexOf(subscription);
}
}
class IterableUtils {
static find(items, condition) {
for (const item of items) {
if (condition(item))
return item;
}
return undefined;
}
}
class ObjectUtils {
constructor() {
}
static clone(obj) {
if (obj == null)
return undefined;
if (obj instanceof Array)
return cloneArray(obj);
return ObjectUtils.assign({}, obj);
function cloneArray(a) {
return a.map(item => ObjectUtils.clone(item));
}
}
static assign(a, b, c) {
if (Object.assign != null) {
if (c == null)
return Object.assign(a, b);
else
return Object.assign(a, b, c);
}
if (c == null)
return this.es5Assign(a, b);
else
return this.es5Assign(a, b, c);
}
static es5Assign(a, b, c) {
const to = Object(a);
for (let index = 1; index < arguments.length; index++) {
const nextSource = arguments[index];
if (nextSource == null)
continue;
for (const nextKey in nextSource) {
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey))
to[nextKey] = nextSource[nextKey];
}
}
return to;
}
}
function matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, currentDirectory, depth, getEntries, realpath) {
return ts.matchFiles.apply(this, arguments);
}
function getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory) {
return ts.getFileMatcherPatterns.apply(this, arguments);
}
function getEmitModuleResolutionKind(compilerOptions) {
return ts.getEmitModuleResolutionKind.apply(this, arguments);
}
function getSyntaxKindName(kind) {
return getKindCache()[kind];
}
let kindCache = undefined;
function getKindCache() {
if (kindCache != null)
return kindCache;
kindCache = {};
for (const name of Object.keys(ts.SyntaxKind).filter(k => isNaN(parseInt(k, 10)))) {
const value = ts.SyntaxKind[name];
if (kindCache[value] == null)
kindCache[value] = name;
}
return kindCache;
}
(function (errors) {
class BaseError extends Error {
constructor(message) {
super(message);
this.message = message;
this.message = message;
}
}
errors.BaseError = BaseError;
class ArgumentError extends BaseError {
constructor(argName, message) {
super(`Argument Error (${argName}): ${message}`);
}
}
errors.ArgumentError = ArgumentError;
class ArgumentNullOrWhitespaceError extends ArgumentError {
constructor(argName) {
super(argName, "Cannot be null or whitespace.");
}
}
errors.ArgumentNullOrWhitespaceError = ArgumentNullOrWhitespaceError;
class ArgumentOutOfRangeError extends ArgumentError {
constructor(argName, value, range) {
super(argName, `Range is ${range[0]} to ${range[1]}, but ${value} was provided.`);
}
}
errors.ArgumentOutOfRangeError = ArgumentOutOfRangeError;
class ArgumentTypeError extends ArgumentError {
constructor(argName, expectedType, actualType) {
super(argName, `Expected type '${expectedType}', but was '${actualType}'.`);
}
}
errors.ArgumentTypeError = ArgumentTypeError;
class PathNotFoundError extends BaseError {
constructor(path, prefix = "Path") {
super(`${prefix} not found: ${path}`);
this.path = path;
this.code = "ENOENT";
}
}
errors.PathNotFoundError = PathNotFoundError;
class DirectoryNotFoundError extends PathNotFoundError {
constructor(dirPath) {
super(dirPath, "Directory");
}
}
errors.DirectoryNotFoundError = DirectoryNotFoundError;
class FileNotFoundError extends PathNotFoundError {
constructor(filePath) {
super(filePath, "File");
}
}
errors.FileNotFoundError = FileNotFoundError;
class InvalidOperationError extends BaseError {
constructor(message) {
super(message);
}
}
errors.InvalidOperationError = InvalidOperationError;
class NotImplementedError extends BaseError {
constructor(message = "Not implemented.") {
super(message);
}
}
errors.NotImplementedError = NotImplementedError;
class NotSupportedError extends BaseError {
constructor(message) {
super(message);
}
}
errors.NotSupportedError = NotSupportedError;
function throwIfNotType(value, expectedType, argName) {
if (typeof value !== expectedType)
throw new ArgumentTypeError(argName, expectedType, typeof value);
}
errors.throwIfNotType = throwIfNotType;
function throwIfNotString(value, argName) {
if (typeof value !== "string")
throw new ArgumentTypeError(argName, "string", typeof value);
}
errors.throwIfNotString = throwIfNotString;
function throwIfWhitespaceOrNotString(value, argName) {
throwIfNotString(value, argName);
if (value.trim().length === 0)
throw new ArgumentNullOrWhitespaceError(argName);
}
errors.throwIfWhitespaceOrNotString = throwIfWhitespaceOrNotString;
function throwIfOutOfRange(value, range, argName) {
if (value < range[0] || value > range[1])
throw new ArgumentOutOfRangeError(argName, value, range);
}
errors.throwIfOutOfRange = throwIfOutOfRange;
function throwIfRangeOutOfRange(actualRange, range, argName) {
if (actualRange[0] > actualRange[1])
throw new ArgumentError(argName, `The start of a range must not be greater than the end: [${actualRange[0]}, ${actualRange[1]}]`);
throwIfOutOfRange(actualRange[0], range, argName);
throwIfOutOfRange(actualRange[1], range, argName);
}
errors.throwIfRangeOutOfRange = throwIfRangeOutOfRange;
function throwNotImplementedForSyntaxKindError(kind) {
throw new NotImplementedError(`Not implemented feature for syntax kind '${getSyntaxKindName(kind)}'.`);
}
errors.throwNotImplementedForSyntaxKindError = throwNotImplementedForSyntaxKindError;
function throwIfNegative(value, argName) {
if (value < 0)
throw new ArgumentError(argName, "Expected a non-negative value.");
}
errors.throwIfNegative = throwIfNegative;
function throwIfNullOrUndefined(value, errorMessage) {
if (value == null)
throw new InvalidOperationError(typeof errorMessage === "string" ? errorMessage : errorMessage());
return value;
}
errors.throwIfNullOrUndefined = throwIfNullOrUndefined;
function throwNotImplementedForNeverValueError(value) {
const node = value;
if (node != null && typeof node.kind === "string")
return throwNotImplementedForSyntaxKindError(node.kind);
throw new NotImplementedError(`Not implemented value: ${JSON.stringify(value)}`);
}
errors.throwNotImplementedForNeverValueError = throwNotImplementedForNeverValueError;
function throwIfNotEqual(actual, expected, description) {
if (actual !== expected)
throw new InvalidOperationError(`Expected ${actual} to equal ${expected}. ${description}`);
}
errors.throwIfNotEqual = throwIfNotEqual;
function throwIfTrue(value, errorMessage) {
if (value === true)
throw new InvalidOperationError(errorMessage);
}
errors.throwIfTrue = throwIfTrue;
})(exports.errors || (exports.errors = {}));
const CharCodes = {
ASTERISK: "*".charCodeAt(0),
NEWLINE: "\n".charCodeAt(0),
CARRIAGE_RETURN: "\r".charCodeAt(0),
SPACE: " ".charCodeAt(0),
TAB: "\t".charCodeAt(0),
CLOSE_BRACE: "}".charCodeAt(0),
};
const regExWhitespaceSet = new Set([" ", "\f", "\n", "\r", "\t", "\v", "\u00A0", "\u2028", "\u2029"].map(c => c.charCodeAt(0)));
class StringUtils {
constructor() {
}
static isWhitespaceCharCode(charCode) {
return regExWhitespaceSet.has(charCode);
}
static isSpaces(text) {
if (text == null || text.length === 0)
return false;
for (let i = 0; i < text.length; i++) {
if (text.charCodeAt(i) !== CharCodes.SPACE)
return false;
}
return true;
}
static hasBom(text) {
return text.charCodeAt(0) === 0xFEFF;
}
static stripBom(text) {
if (StringUtils.hasBom(text))
return text.slice(1);
return text;
}
static isNullOrWhitespace(str) {
return typeof str !== "string" || StringUtils.isWhitespace(str);
}
static isNullOrEmpty(str) {
return typeof str !== "string" || str.length === 0;
}
static isWhitespace(text) {
if (text == null)
return true;
for (let i = 0; i < text.length; i++) {
if (!StringUtils.isWhitespaceCharCode(text.charCodeAt(i)))
return false;
}
return true;
}
static startsWithNewLine(str) {
if (str == null)
return false;
return str.charCodeAt(0) === CharCodes.NEWLINE || str.charCodeAt(0) === CharCodes.CARRIAGE_RETURN && str.charCodeAt(1) === CharCodes.NEWLINE;
}
static endsWithNewLine(str) {
if (str == null)
return false;
return str.charCodeAt(str.length - 1) === CharCodes.NEWLINE;
}
static insertAtLastNonWhitespace(str, insertText) {
let i = str.length;
while (i > 0 && StringUtils.isWhitespaceCharCode(str.charCodeAt(i - 1)))
i--;
return str.substring(0, i) + insertText + str.substring(i);
}
static getLineNumberAtPos(str, pos) {
exports.errors.throwIfOutOfRange(pos, [0, str.length], "pos");
let count = 0;
for (let i = 0; i < pos; i++) {
if (str.charCodeAt(i) === CharCodes.NEWLINE)
count++;
}
return count + 1;
}
static getLengthFromLineStartAtPos(str, pos) {
exports.errors.throwIfOutOfRange(pos, [0, str.length], "pos");
return pos - StringUtils.getLineStartFromPos(str, pos);
}
static getLineStartFromPos(str, pos) {
exports.errors.throwIfOutOfRange(pos, [0, str.length], "pos");
while (pos > 0) {
const previousCharCode = str.charCodeAt(pos - 1);
if (previousCharCode === CharCodes.NEWLINE || previousCharCode === CharCodes.CARRIAGE_RETURN)
break;
pos--;
}
return pos;
}
static getLineEndFromPos(str, pos) {
exports.errors.throwIfOutOfRange(pos, [0, str.length], "pos");
while (pos < str.length) {
const currentChar = str.charCodeAt(pos);
if (currentChar === CharCodes.NEWLINE || currentChar === CharCodes.CARRIAGE_RETURN)
break;
pos++;
}
return pos;
}
static escapeForWithinString(str, quoteKind) {
return StringUtils.escapeChar(str, quoteKind).replace(/(\r?\n)/g, "\\$1");
}
static escapeChar(str, char) {
if (char.length !== 1)
throw new exports.errors.InvalidOperationError(`Specified char must be one character long.`);
let result = "";
for (const currentChar of str) {
if (currentChar === char)
result += "\\";
result += currentChar;
}
return result;
}
static removeIndentation(str, opts) {
const { isInStringAtPos, indentSizeInSpaces } = opts;
const startPositions = [];
const endPositions = [];
let minIndentWidth;
analyze();
return buildString();
function analyze() {
let isAtStartOfLine = str.charCodeAt(0) === CharCodes.SPACE || str.charCodeAt(0) === CharCodes.TAB;
for (let i = 0; i < str.length; i++) {
if (!isAtStartOfLine) {
if (str.charCodeAt(i) === CharCodes.NEWLINE && !isInStringAtPos(i + 1))
isAtStartOfLine = true;
continue;
}
startPositions.push(i);
let spacesCount = 0;
let tabsCount = 0;
while (true) {
if (str.charCodeAt(i) === CharCodes.SPACE)
spacesCount++;
else if (str.charCodeAt(i) === CharCodes.TAB)
tabsCount++;
else
break;
i++;
}
const indentWidth = Math.ceil(spacesCount / indentSizeInSpaces) * indentSizeInSpaces + tabsCount * indentSizeInSpaces;
if (minIndentWidth == null || indentWidth < minIndentWidth)
minIndentWidth = indentWidth;
endPositions.push(i);
isAtStartOfLine = false;
}
}
function buildString() {
if (startPositions.length === 0)
return str;
if (minIndentWidth == null || minIndentWidth === 0)
return str;
const deindentWidth = minIndentWidth;
let result = "";
result += str.substring(0, startPositions[0]);
let lastEndPos = startPositions[0];
for (let i = 0; i < startPositions.length; i++) {
const startPosition = startPositions[i];
const endPosition = endPositions[i];
let indentCount = 0;
let pos;
for (pos = startPosition; pos < endPosition; pos++) {
if (indentCount >= deindentWidth)
break;
if (str.charCodeAt(pos) === CharCodes.SPACE)
indentCount++;
else if (str.charCodeAt(pos) === CharCodes.TAB)
indentCount += indentSizeInSpaces;
}
lastEndPos = startPositions[i + 1] == null ? str.length : startPositions[i + 1];
result += str.substring(pos, lastEndPos);
}
result += str.substring(lastEndPos);
return result;
}
}
static indent(str, times, options) {
if (times === 0)
return str;
const { indentText, indentSizeInSpaces, isInStringAtPos } = options;
const fullIndentationText = times > 0 ? indentText.repeat(times) : undefined;
const totalIndentSpaces = Math.abs(times * indentSizeInSpaces);
let result = "";
let lineStart = 0;
let lineEnd = 0;
for (let i = 0; i < str.length; i++) {
lineStart = i;
while (i < str.length && str.charCodeAt(i) !== CharCodes.NEWLINE)
i++;
lineEnd = i === str.length ? i : i + 1;
appendLine();
}
return result;
function appendLine() {
if (isInStringAtPos(lineStart))
result += str.substring(lineStart, lineEnd);
else if (times > 0)
result += fullIndentationText + str.substring(lineStart, lineEnd);
else {
let start = lineStart;
let indentSpaces = 0;
for (start = lineStart; start < str.length; start++) {
if (indentSpaces >= totalIndentSpaces)
break;
if (str.charCodeAt(start) === CharCodes.SPACE)
indentSpaces++;
else if (str.charCodeAt(start) === CharCodes.TAB)
indentSpaces += indentSizeInSpaces;
else
break;
}
result += str.substring(start, lineEnd);
}
}
}
}
class ComparerToStoredComparer {
constructor(comparer, storedValue) {
this.comparer = comparer;
this.storedValue = storedValue;
}
compareTo(value) {
return this.comparer.compareTo(this.storedValue, value);
}
}
class LocaleStringComparer {
compareTo(a, b) {
const comparisonResult = a.localeCompare(b, "en-us-u-kf-upper");
if (comparisonResult < 0)
return -1;
else if (comparisonResult === 0)
return 0;
return 1;
}
}
LocaleStringComparer.instance = new LocaleStringComparer();
class PropertyComparer {
constructor(getProperty, comparer) {
this.getProperty = getProperty;
this.comparer = comparer;
}
compareTo(a, b) {
return this.comparer.compareTo(this.getProperty(a), this.getProperty(b));
}
}
class PropertyStoredComparer {
constructor(getProperty, comparer) {
this.getProperty = getProperty;
this.comparer = comparer;
}
compareTo(value) {
return this.comparer.compareTo(this.getProperty(value));
}
}
class SortedKeyValueArray {
constructor(getKey, comparer) {
this.getKey = getKey;
this.comparer = comparer;
this.array = [];
}
set(value) {
ArrayUtils.binaryInsertWithOverwrite(this.array, value, new PropertyComparer(this.getKey, this.comparer));
}
removeByValue(value) {
this.removeByKey(this.getKey(value));
}
removeByKey(key) {
const storedComparer = new ComparerToStoredComparer(this.comparer, key);
const index = ArrayUtils.binarySearch(this.array, new PropertyStoredComparer(this.getKey, storedComparer));
if (index >= 0)
this.array.splice(index, 1);
}
getArrayCopy() {
return [...this.array];
}
hasItems() {
return this.array.length > 0;
}
*entries() {
yield* this.array;
}
}
class WeakCache {
constructor() {
this.cacheItems = new WeakMap();
}
getOrCreate(key, createFunc) {
let item = this.get(key);
if (item == null) {
item = createFunc();
this.set(key, item);
}
return item;
}
has(key) {
return this.cacheItems.has(key);
}
get(key) {
return this.cacheItems.get(key);
}
set(key, value) {
this.cacheItems.set(key, value);
}
removeByKey(key) {
this.cacheItems.delete(key);
}
}
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __decorate(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
}
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __await(v) {
return this instanceof __await ? (this.v = v, this) : new __await(v);
}
function __asyncGenerator(thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
}
const isWindowsRootDirRegex = /^[A-Z]+:\/$/i;
class FileUtils {
constructor() {
}
static isNotExistsError(err) {
return err != null && err.code === FileUtils.ENOENT;
}
static pathJoin(basePath, ...paths) {
if (FileUtils.pathIsAbsolute(basePath)) {
return FileUtils.standardizeSlashes(path.normalize(path.join(basePath, ...paths)));
}
return FileUtils.standardizeSlashes(path.join(basePath, ...paths));
}
static pathIsAbsolute(fileOrDirPath) {
return path.isAbsolute(fileOrDirPath);
}
static getStandardizedAbsolutePath(fileSystem, fileOrDirPath, relativeBase) {
return FileUtils.standardizeSlashes(path.normalize(getAbsolutePath()));
function getAbsolutePath() {
const isAbsolutePath = path.isAbsolute(fileOrDirPath);
if (isAbsolutePath)
return fileOrDirPath;
if (!fileOrDirPath.startsWith("./") && relativeBase != null)
return path.join(relativeBase, fileOrDirPath);
return path.join(fileSystem.getCurrentDirectory(), fileOrDirPath);
}
}
static getDirPath(fileOrDirPath) {
return FileUtils.standardizeSlashes(path.dirname(fileOrDirPath));
}
static getBaseName(fileOrDirPath) {
return path.basename(fileOrDirPath);
}
static getExtension(fileOrDirPath) {
const baseName = FileUtils.getBaseName(fileOrDirPath);
const lastDotIndex = baseName.lastIndexOf(".");
if (lastDotIndex <= 0)
return "";
const lastExt = baseName.substring(lastDotIndex);
const lastExtLowerCase = lastExt.toLowerCase();
if (lastExtLowerCase === ".ts" && baseName.substring(lastDotIndex - 2, lastDotIndex).toLowerCase() === ".d")
return baseName.substring(lastDotIndex - 2);
if (lastExtLowerCase === ".map" && baseName.substring(lastDotIndex - 3, lastDotIndex).toLowerCase() === ".js")
return baseName.substring(lastDotIndex - 3);
return lastExt;
}
static standardizeSlashes(fileOrDirPath) {
let result = fileOrDirPath.replace(this.standardizeSlashesRegex, "/");
if (result !== "/" && !isWindowsRootDirRegex.test(result) && result.endsWith("/"))
result = result.substring(0, result.length - 1);
return result;
}
static pathEndsWith(fileOrDirPath, endsWithPath) {
const pathItems = FileUtils.splitPathBySlashes(fileOrDirPath);
const endsWithItems = FileUtils.splitPathBySlashes(endsWithPath);
if (endsWithItems.length > pathItems.length)
return false;
for (let i = 0; i < endsWithItems.length; i++) {
if (endsWithItems[endsWithItems.length - i - 1] !== pathItems[pathItems.length - i - 1])
return false;
}
return endsWithItems.length > 0;
}
static pathStartsWith(fileOrDirPath, startsWithPath) {
const isfileOrDirPathEmpty = StringUtils.isNullOrWhitespace(fileOrDirPath);
const isStartsWithPathEmpty = StringUtils.isNullOrWhitespace(startsWithPath);
const pathItems = FileUtils.splitPathBySlashes(fileOrDirPath);
const startsWithItems = FileUtils.splitPathBySlashes(startsWithPath);
if (isfileOrDirPathEmpty && isStartsWithPathEmpty)
return true;
if (isStartsWithPathEmpty || startsWithItems.length > pathItems.length)
return false;
if (startsWithItems.length === 1 && startsWithItems[0].length === 0)
return true;
for (let i = 0; i < startsWithItems.length; i++) {
if (startsWithItems[i] !== pathItems[i])
return false;
}
return startsWithItems.length > 0;
}
static splitPathBySlashes(fileOrDirPath) {
fileOrDirPath = (fileOrDirPath || "").replace(FileUtils.trimSlashStartRegex, "").replace(FileUtils.trimSlashEndRegex, "");
return FileUtils.standardizeSlashes(fileOrDirPath).replace(/^\//, "").split("/");
}
static getParentMostPaths(paths) {
const finalPaths = [];
for (const fileOrDirPath of ArrayUtils.sortByProperty(paths, p => p.length)) {
if (finalPaths.every(p => !FileUtils.pathStartsWith(fileOrDirPath, p)))
finalPaths.push(fileOrDirPath);
}
return finalPaths;
}
static readFileOrNotExists(fileSystem, filePath, encoding) {
return __awaiter(this, void 0, void 0, function* () {
try {
return yield fileSystem.readFile(filePath, encoding);
}
catch (err) {
if (!FileUtils.isNotExistsError(err))
throw err;
return false;
}
});
}
static readFileOrNotExistsSync(fileSystem, filePath, encoding) {
try {
return fileSystem.readFileSync(filePath, encoding);
}
catch (err) {
if (!FileUtils.isNotExistsError(err))
throw err;
return false;
}
}
static getTextWithByteOrderMark(text) {
if (StringUtils.hasBom(text))
return text;
return "\uFEFF" + text;
}
static getRelativePathTo(absoluteDirPathFrom, absolutePathTo) {
const relativePath = path.relative(absoluteDirPathFrom, path.dirname(absolutePathTo));
return FileUtils.standardizeSlashes(path.join(relativePath, path.basename(absolutePathTo)));
}
static isRootDirPath(dirOrFilePath) {
return dirOrFilePath === FileUtils.getDirPath(dirOrFilePath);
}
static *getDescendantDirectories(fileSystemWrapper, dirPath) {
for (const subDirPath of fileSystemWrapper.readDirSync(dirPath)) {
if (!fileSystemWrapper.directoryExistsSync(subDirPath))
continue;
yield subDirPath;
yield* FileUtils.getDescendantDirectories(fileSystemWrapper, subDirPath);
}
}
static toAbsoluteGlob(glob, cwd) {
return toAbsoluteGlob__default['default'](glob, { cwd });
}
static isNegatedGlob(glob) {
return isNegatedGlob__default['default'](glob).negated;
}
}
FileUtils.standardizeSlashesRegex = /\\/g;
FileUtils.trimSlashStartRegex = /^\//;
FileUtils.trimSlashEndRegex = /\/$/;
FileUtils.ENOENT = "ENOENT";
class RealFileSystemHost {
constructor() {
this.fs = require("fs");
this.fastGlob = require("fast-glob");
this.mkdirp = require("mkdirp");
}
delete(path) {
return new Promise((resolve, reject) => {
this.fs.unlink(path, err => {
if (err)
reject(this.getFileNotFoundErrorIfNecessary(err, path));
else
resolve();
});
});
}
deleteSync(path) {
try {
this.fs.unlinkSync(path);
}
catch (err) {
throw this.getFileNotFoundErrorIfNecessary(err, path);
}
}
readDirSync(dirPath) {
try {
return this.fs.readdirSync(dirPath).map(name => FileUtils.pathJoin(dirPath, name));
}
catch (err) {
throw this.getDirectoryNotFoundErrorIfNecessary(err, dirPath);
}
}
readFile(filePath, encoding = "utf-8") {
return new Promise((resolve, reject) => {
this.fs.readFile(filePath, encoding, (err, data) => {
if (err)
reject(this.getFileNotFoundErrorIfNecessary(err, filePath));
else
resolve(data);
});
});
}
readFileSync(filePath, encoding = "utf-8") {
try {
return this.fs.readFileSync(filePath, encoding);
}
catch (err) {
throw this.getFileNotFoundErrorIfNecessary(err, filePath);
}
}
writeFile(filePath, fileText) {
return __awaiter(this, void 0, void 0, function* () {
yield new Promise((resolve, reject) => {
this.fs.writeFile(filePath, fileText, err => {
if (err)
reject(err);
else
resolve();
});
});
});
}
writeFileSync(filePath, fileText) {
this.fs.writeFileSync(filePath, fileText);
}
mkdir(dirPath) {
return __awaiter(this, void 0, void 0, function* () {
yield this.mkdirp(dirPath);
});
}
mkdirSync(dirPath) {
this.mkdirp.sync(dirPath);
}
move(srcPath, destPath) {
return new Promise((resolve, reject) => {
this.fs.rename(srcPath, destPath, err => {
if (err)
reject(err);
else
resolve();
});
});
}
moveSync(srcPath, destPath) {
this.fs.renameSync(srcPath, destPath);
}
copy(srcPath, destPath) {
return new Promise((resolve, reject) => {
this.fs.copyFile(srcPath, destPath, err => {
if (err)
reject(err);
else
resolve();
});
});
}
copySync(srcPath, destPath) {
this.fs.copyFileSync(srcPath, destPath);
}
fileExists(filePath) {
return new Promise(resolve => {
this.fs.stat(filePath, (err, stat) => {
if (err)
resolve(false);
else
resolve(stat.isFile());
});
});
}
fileExistsSync(filePath) {
try {
return this.fs.statSync(filePath).isFile();
}
catch (err) {
return false;
}
}
directoryExists(dirPath) {
return new Promise(resolve => {
this.fs.stat(dirPath, (err, stat) => {
if (err)
resolve(false);
else
resolve(stat.isDirectory());
});
});
}
directoryExistsSync(dirPath) {
try {
return this.fs.statSync(dirPath).isDirectory();
}
catch (err) {
return false;
}
}
realpathSync(path) {
return this.fs.realpathSync(path);
}
getCurrentDirectory() {
return FileUtils.standardizeSlashes(path.resolve());
}
glob(patterns) {
return this.fastGlob(backSlashesToForward(patterns), {
cwd: this.getCurrentDirectory(),
absolute: true,
});
}
globSync(patterns) {
return this.fastGlob.sync(backSlashesToForward(patterns), {
cwd: this.getCurrentDirectory(),
absolute: true,
});
}
isCaseSensitive() {
const platform = process.platform;
return platform !== "win32" && platform !== "darwin";
}
getDirectoryNotFoundErrorIfNecessary(err, path) {
return FileUtils.isNotExistsError(err) ? new exports.errors.DirectoryNotFoundError(FileUtils.getStandardizedAbsolutePath(this, path)) : err;
}
getFileNotFoundErrorIfNecessary(err, path) {
return FileUtils.isNotExistsError(err) ? new exports.errors.FileNotFoundError(FileUtils.getStandardizedAbsolutePath(this, path)) : err;
}
}
function backSlashesToForward(patterns) {
return patterns.map(p => p.replace(/\\/g, "/"));
}
class Directory {
constructor(path) {
this.path = path;
this.operations = [];
this.inboundOperations = [];
this.isDeleted = false;
this.wasEverDeleted = false;
this.childDirs = new SortedKeyValueArray(item => item.path, LocaleStringComparer.instance);
}
getExternalOperations() {
return [
...ArrayUtils.flatten(this.getAncestors().map(a => getMoveCopyOrDeleteOperations(a))).filter(o => isAncestorAffectedOperation(this, o)),
...ArrayUtils.flatten([this, ...this.getDescendants()].map(d => getMoveOrCopyOperations(d))).filter(o => !isInternalOperation(this, o)),
];
function isInternalOperation(thisDir, operation) {
return operation.oldDir.isDescendantOrEqual(thisDir) && operation.newDir.isDescendantOrEqual(thisDir);
}
function isAncestorAffectedOperation(thisDir, operation) {
switch (operation.kind) {
case "move":
case "copy":
return thisDir.isDescendantOrEqual(operation.oldDir) || thisDir.isDescendantOrEqual(operation.newDir);
case "deleteDir":
return thisDir.isDescendantOrEqual(operation.dir);
default:
return exports.errors.throwNotImplementedForNeverValueError(operation);
}
}
function getMoveOrCopyOperations(dir) {
return dir.operations.filter(o => o.kind === "move" || o.kind === "copy");
}
function getMoveCopyOrDeleteOperations(dir) {
return dir.operations.filter(o => o.kind === "move" || o.kind === "deleteDir" || o.kind === "copy");
}
}
isDescendantOrEqual(directory) {
return this.isDescendant(directory) || this === directory;
}
isDescendant(directory) {
return FileUtils.pathStartsWith(this.path, directory.path);
}
getIsDeleted() {
return this.isDeleted;
}
getWasEverDeleted() {
if (this.wasEverDeleted)
return true;
for (const ancestor of this.getAncestorsIterator()) {
if (ancestor.wasEverDeleted)
return true;
}
return false;
}
setIsDeleted(isDeleted) {
if (this.isDeleted === isDeleted)
return;
if (isDeleted) {
this.wasEverDeleted = true;
for (const child of this.childDirs.entries())
child.setIsDeleted(true);
}
else {
if (this.parent != null)
this.parent.setIsDeleted(false);
}
this.isDeleted = isDeleted;
}
getParent() {
return this.parent;
}
setParent(parent) {
if (this.parent != null)
throw new exports.errors.InvalidOperationError("For some reason, a parent was being set when the directory already had a parent. Please open an issue.");
this.parent = parent;
parent.childDirs.set(this);
if (parent.isDeleted && !this.isDeleted)
parent.setIsDeleted(false);
}
removeParent() {
const parent = this.parent;
if (parent == null)
return;
parent.childDirs.removeByValue(this);
this.parent = undefined;
}
getAncestors() {
return Array.from(this.getAncestorsIterator());
}
*getAncestorsIterator() {
let parent = this.parent;
while (parent != null) {
yield parent;
parent = parent.parent;
}
}
*getChildrenPathsIterator() {
for (const childDir of this.childDirs.entries())
yield childDir.path;
}
getDescendants() {
const descendants = [];
for (const child of this.childDirs.entries()) {
descendants.push(child);
descendants.push(...child.getDescendants());
}
return descendants;
}
isFileQueuedForDelete(filePath) {
return this.hasOperation(operation => operation.kind === "deleteFile" && operation.filePath === filePath);
}
hasOperation(operationMatches) {
for (const operation of this.operations) {
if (operationMatches(operation))
return true;
}
return false;
}
dequeueFileDelete(filePath) {
this.removeMatchingOperations(operation => operation.kind === "deleteFile" && operation.filePath === filePath);
}
dequeueDirDelete(dirPath) {
this.removeMatchingOperations(operation => operation.kind === "deleteDir" && operation.dir.path === dirPath);
}
isRootDir() {
return FileUtils.isRootDirPath(this.path);
}
removeMatchingOperations(operationMatches) {
ArrayUtils.removeAll(this.operations, operationMatches);
}
}
class TransactionalFileSystem {
constructor(fileSystem) {
this.fileSystem = fileSystem;
this.directories = new KeyValueCache();
this.operationIndex = 0;
this.pathCasingMaintainer = new PathCasingMaintainer(fileSystem);
}
queueFileDelete(filePath) {
const parentDir = this.getOrCreateParentDirectory(filePath);
parentDir.operations.push({
kind: "deleteFile",
index: this.getNextOperationIndex(),
filePath,
});
this.pathCasingMaintainer.removePath(filePath);
}
removeFileDelete(filePath) {
this.getOrCreateParentDirectory(filePath).dequeueFileDelete(filePath);
}
queueMkdir(dirPath) {
const dir = this.getOrCreateDirectory(dirPath);
dir.setIsDeleted(false);
const parentDir = this.getOrCreateParentDirectory(dirPath);
parentDir.operations.push({
kind: "mkdir",
index: this.getNextOperationIndex(),
dir,
});
}
queueDirectoryDelete(dirPath) {
const dir = this.getOrCreateDirectory(dirPath);
dir.setIsDeleted(true);
const parentDir = this.getOrCreateParentDirectory(dirPath);
parentDir.operations.push({
kind: "deleteDir",
index: this.getNextOperationIndex(),
dir,
});
this.pathCasingMaintainer.removePath(dirPath);
}
queueMoveDirectory(srcPath, destPath) {
const parentDir = this.getOrCreateParentDirectory(srcPath);
const moveDir = this.getOrCreateDirectory(srcPath);
const destinationDir = this.getOrCreateDirectory(destPath);
const moveOperation = {
kind: "move",
index: this.getNextOperationIndex(),
oldDir: moveDir,
newDir: destinationDir,
};
parentDir.operations.push(moveOperation);
(destinationDir.getParent() || destinationDir).inboundOperations.push(moveOperation);
moveDir.setIsDeleted(true);
this.pathCasingMaintainer.removePath(srcPath);
}
queueCopyDirectory(srcPath, destPath) {
const parentDir = this.getOrCreateParentDirectory(srcPath);
const copyDir = this.getOrCreateDirectory(srcPath);
const destinationDir = this.getOrCreateDirectory(destPath);
const copyOperation = {
kind: "copy",
index: this.getNextOperationIndex(),
oldDir: copyDir,
newDir: destinationDir,
};
parentDir.operations.push(copyOperation);
(destinationDir.getParent() || destinationDir).inboundOperations.push(copyOperation);
}
flush() {
return __awaiter(this, void 0, void 0, function* () {
const operations = this.getAndClearOperations();
for (const operation of operations)
yield this.executeOperation(operation);
});
}
flushSync() {
for (const operation of this.getAndClearOperations())
this.executeOperationSync(operation);
}
saveForDirectory(dirPath) {
return __awaiter(this, void 0, void 0, function* () {
const dir = this.getOrCreateDirectory(dirPath);
this.throwIfHasExternalOperations(dir, "save directory");
const operations = this.getAndClearOperationsForDir(dir);
yield this.ensureDirectoryExists(dir);
for (const operation of operations)
yield this.executeOperation(operation);
});
}
saveForDirectorySync(dirPath) {
const dir = this.getOrCreateDirectory(dirPath);
this.throwIfHasExternalOperations(dir, "save directory");
this.ensureDirectoryExistsSync(dir);
for (const operation of this.getAndClearOperationsForDir(dir))
this.executeOperationSync(operation);
}
getAndClearOperationsForDir(dir) {
const operations = getAndClearParentMkDirOperations(dir.getParent(), dir);
for (const currentDir of [dir, ...dir.getDescendants()])
operations.push(...currentDir.operations);
ArrayUtils.sortByProperty(operations, item => item.index);
this.removeDirAndSubDirs(dir);
return operations;
function getAndClearParentMkDirOperations(parentDir, childDir) {
if (parentDir == null)
return [];