Merge pull request #10359 from Microsoft/optimizeMoreMaps

Migrate more MapLikes to Maps
This commit is contained in:
Ron Buckton
2016-08-16 20:11:35 -07:00
committed by GitHub
31 changed files with 445 additions and 432 deletions
+17 -25
View File
@@ -284,7 +284,7 @@ namespace ts {
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy,
}
const typeofEQFacts: MapLike<TypeFacts> = {
const typeofEQFacts = createMap({
"string": TypeFacts.TypeofEQString,
"number": TypeFacts.TypeofEQNumber,
"boolean": TypeFacts.TypeofEQBoolean,
@@ -292,9 +292,9 @@ namespace ts {
"undefined": TypeFacts.EQUndefined,
"object": TypeFacts.TypeofEQObject,
"function": TypeFacts.TypeofEQFunction
};
});
const typeofNEFacts: MapLike<TypeFacts> = {
const typeofNEFacts = createMap({
"string": TypeFacts.TypeofNEString,
"number": TypeFacts.TypeofNENumber,
"boolean": TypeFacts.TypeofNEBoolean,
@@ -302,15 +302,15 @@ namespace ts {
"undefined": TypeFacts.NEUndefined,
"object": TypeFacts.TypeofNEObject,
"function": TypeFacts.TypeofNEFunction
};
});
const typeofTypesByName: MapLike<Type> = {
const typeofTypesByName = createMap<Type>({
"string": stringType,
"number": numberType,
"boolean": booleanType,
"symbol": esSymbolType,
"undefined": undefinedType
};
});
let jsxElementType: ObjectType;
/** Things we lazy load from the JSX namespace */
@@ -403,8 +403,8 @@ namespace ts {
result.parent = symbol.parent;
if (symbol.valueDeclaration) result.valueDeclaration = symbol.valueDeclaration;
if (symbol.constEnumOnlyModule) result.constEnumOnlyModule = true;
if (symbol.members) result.members = cloneSymbolTable(symbol.members);
if (symbol.exports) result.exports = cloneSymbolTable(symbol.exports);
if (symbol.members) result.members = cloneMap(symbol.members);
if (symbol.exports) result.exports = cloneMap(symbol.exports);
recordMergedSymbol(result, symbol);
return result;
}
@@ -447,14 +447,6 @@ namespace ts {
}
}
function cloneSymbolTable(symbolTable: SymbolTable): SymbolTable {
const result = createMap<Symbol>();
for (const id in symbolTable) {
result[id] = symbolTable[id];
}
return result;
}
function mergeSymbolTable(target: SymbolTable, source: SymbolTable) {
for (const id in source) {
let targetSymbol = target[id];
@@ -1450,7 +1442,7 @@ namespace ts {
return;
}
visitedSymbols.push(symbol);
const symbols = cloneSymbolTable(symbol.exports);
const symbols = cloneMap(symbol.exports);
// All export * declarations are collected in an __export symbol by the binder
const exportStars = symbol.exports["__export"];
if (exportStars) {
@@ -1655,12 +1647,12 @@ namespace ts {
}
// If symbol is directly available by its name in the symbol table
if (isAccessible(lookUp(symbols, symbol.name))) {
if (isAccessible(symbols[symbol.name])) {
return [symbol];
}
// Check if symbol is any of the alias
return forEachValue(symbols, symbolFromSymbolTable => {
return forEachProperty(symbols, symbolFromSymbolTable => {
if (symbolFromSymbolTable.flags & SymbolFlags.Alias
&& symbolFromSymbolTable.name !== "export="
&& !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)) {
@@ -6629,7 +6621,7 @@ namespace ts {
const maybeCache = maybeStack[depth];
// If result is definitely true, copy assumptions to global cache, else copy to next level up
const destinationCache = (result === Ternary.True || depth === 0) ? relation : maybeStack[depth - 1];
copyMap(maybeCache, destinationCache);
copyProperties(maybeCache, destinationCache);
}
else {
// A false result goes straight into global cache (when something is false under assumptions it
@@ -7941,7 +7933,7 @@ namespace ts {
// check. This gives us a quicker out in the common case where an object type is not a function.
const resolved = resolveStructuredTypeMembers(type);
return !!(resolved.callSignatures.length || resolved.constructSignatures.length ||
hasProperty(resolved.members, "bind") && isTypeSubtypeOf(type, globalFunctionType));
resolved.members["bind"] && isTypeSubtypeOf(type, globalFunctionType));
}
function getTypeFacts(type: Type): TypeFacts {
@@ -8517,14 +8509,14 @@ namespace ts {
// We narrow a non-union type to an exact primitive type if the non-union type
// is a supertype of that primitive type. For example, type 'any' can be narrowed
// to one of the primitive types.
const targetType = getProperty(typeofTypesByName, literal.text);
const targetType = typeofTypesByName[literal.text];
if (targetType && isTypeSubtypeOf(targetType, type)) {
return targetType;
}
}
const facts = assumeTrue ?
getProperty(typeofEQFacts, literal.text) || TypeFacts.TypeofEQHostObject :
getProperty(typeofNEFacts, literal.text) || TypeFacts.TypeofNEHostObject;
typeofEQFacts[literal.text] || TypeFacts.TypeofEQHostObject :
typeofNEFacts[literal.text] || TypeFacts.TypeofNEHostObject;
return getTypeWithFacts(type, facts);
}
@@ -18266,7 +18258,7 @@ namespace ts {
// otherwise - check if at least one export is value
symbolLinks.exportsSomeValue = hasExportAssignment
? !!(moduleSymbol.flags & SymbolFlags.Value)
: forEachValue(getExportsOfModule(moduleSymbol), isValue);
: forEachProperty(getExportsOfModule(moduleSymbol), isValue);
}
return symbolLinks.exportsSomeValue;
+25 -28
View File
@@ -61,10 +61,10 @@ namespace ts {
},
{
name: "jsx",
type: {
type: createMap({
"preserve": JsxEmit.Preserve,
"react": JsxEmit.React
},
}),
paramType: Diagnostics.KIND,
description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_or_react,
},
@@ -91,7 +91,7 @@ namespace ts {
{
name: "module",
shortName: "m",
type: {
type: createMap({
"none": ModuleKind.None,
"commonjs": ModuleKind.CommonJS,
"amd": ModuleKind.AMD,
@@ -99,16 +99,16 @@ namespace ts {
"umd": ModuleKind.UMD,
"es6": ModuleKind.ES6,
"es2015": ModuleKind.ES2015,
},
}),
description: Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_or_es2015,
paramType: Diagnostics.KIND,
},
{
name: "newLine",
type: {
type: createMap({
"crlf": NewLineKind.CarriageReturnLineFeed,
"lf": NewLineKind.LineFeed
},
}),
description: Diagnostics.Specify_the_end_of_line_sequence_to_be_used_when_emitting_files_Colon_CRLF_dos_or_LF_unix,
paramType: Diagnostics.NEWLINE,
},
@@ -250,12 +250,12 @@ namespace ts {
{
name: "target",
shortName: "t",
type: {
type: createMap({
"es3": ScriptTarget.ES3,
"es5": ScriptTarget.ES5,
"es6": ScriptTarget.ES6,
"es2015": ScriptTarget.ES2015,
},
}),
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES2015,
paramType: Diagnostics.VERSION,
},
@@ -284,10 +284,10 @@ namespace ts {
},
{
name: "moduleResolution",
type: {
type: createMap({
"node": ModuleResolutionKind.NodeJs,
"classic": ModuleResolutionKind.Classic,
},
}),
description: Diagnostics.Specify_module_resolution_strategy_Colon_node_Node_js_or_classic_TypeScript_pre_1_6,
},
{
@@ -392,7 +392,7 @@ namespace ts {
type: "list",
element: {
name: "lib",
type: {
type: createMap({
// JavaScript only
"es5": "lib.es5.d.ts",
"es6": "lib.es2015.d.ts",
@@ -417,7 +417,7 @@ namespace ts {
"es2016.array.include": "lib.es2016.array.include.d.ts",
"es2017.object": "lib.es2017.object.d.ts",
"es2017.sharedmemory": "lib.es2017.sharedmemory.d.ts"
},
}),
},
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation_Colon
},
@@ -486,10 +486,9 @@ namespace ts {
/* @internal */
export function createCompilerDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType): Diagnostic {
const namesOfType: string[] = [];
forEachKey(opt.type, key => {
for (const key in opt.type) {
namesOfType.push(` '${key}'`);
});
}
return createCompilerDiagnostic(Diagnostics.Argument_for_0_option_must_be_Colon_1, `--${opt.name}`, namesOfType);
}
@@ -497,7 +496,7 @@ namespace ts {
export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
const key = trimString((value || "")).toLowerCase();
const map = opt.type;
if (hasProperty(map, key)) {
if (key in map) {
return map[key];
}
else {
@@ -551,11 +550,11 @@ namespace ts {
s = s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase();
// Try to translate short option names to their full equivalents.
if (hasProperty(shortOptionNames, s)) {
if (s in shortOptionNames) {
s = shortOptionNames[s];
}
if (hasProperty(optionNameMap, s)) {
if (s in optionNameMap) {
const opt = optionNameMap[s];
if (opt.isTSConfigOnly) {
@@ -811,7 +810,7 @@ namespace ts {
const optionNameMap = arrayToMap(optionDeclarations, opt => opt.name);
for (const id in jsonOptions) {
if (hasProperty(optionNameMap, id)) {
if (id in optionNameMap) {
const opt = optionNameMap[id];
defaultOptions[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors);
}
@@ -848,7 +847,7 @@ namespace ts {
function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
const key = value.toLowerCase();
if (hasProperty(opt.type, key)) {
if (key in opt.type) {
return opt.type[key];
}
else {
@@ -1011,7 +1010,7 @@ namespace ts {
removeWildcardFilesWithLowerPriorityExtension(file, wildcardFileMap, supportedExtensions, keyMapper);
const key = keyMapper(file);
if (!hasProperty(literalFileMap, key) && !hasProperty(wildcardFileMap, key)) {
if (!(key in literalFileMap) && !(key in wildcardFileMap)) {
wildcardFileMap[key] = file;
}
}
@@ -1076,7 +1075,7 @@ namespace ts {
if (match) {
const key = useCaseSensitiveFileNames ? match[0] : match[0].toLowerCase();
const flags = watchRecursivePattern.test(name) ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None;
const existingFlags = getProperty(wildcardDirectories, key);
const existingFlags = wildcardDirectories[key];
if (existingFlags === undefined || existingFlags < flags) {
wildcardDirectories[key] = flags;
if (flags === WatchDirectoryFlags.Recursive) {
@@ -1088,11 +1087,9 @@ namespace ts {
// Remove any subpaths under an existing recursively watched directory.
for (const key in wildcardDirectories) {
if (hasProperty(wildcardDirectories, key)) {
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
}
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
}
}
}
@@ -1115,7 +1112,7 @@ namespace ts {
for (let i = ExtensionPriority.Highest; i < adjustedExtensionPriority; i++) {
const higherPriorityExtension = extensions[i];
const higherPriorityPath = keyMapper(changeExtension(file, higherPriorityExtension));
if (hasProperty(literalFiles, higherPriorityPath) || hasProperty(wildcardFiles, higherPriorityPath)) {
if (higherPriorityPath in literalFiles || higherPriorityPath in wildcardFiles) {
return true;
}
}
+170 -84
View File
@@ -21,10 +21,8 @@ namespace ts {
const createObject = Object.create;
export function createMap<T>(): Map<T> {
/* tslint:disable:no-null-keyword */
const map: Map<T> = createObject(null);
/* tslint:enable:no-null-keyword */
export function createMap<T>(template?: MapLike<T>): Map<T> {
const map: Map<T> = createObject(null); // tslint:disable-line:no-null-keyword
// Using 'delete' on an object causes V8 to put the object in dictionary mode.
// This disables creation of hidden classes, which are expensive when an object is
@@ -32,6 +30,12 @@ namespace ts {
map["__"] = undefined;
delete map["__"];
// Copies keys/values from template. Note that for..in will not throw if
// template is undefined, and instead will just exit the loop.
for (const key in template) if (hasOwnProperty.call(template, key)) {
map[key] = template[key];
}
return map;
}
@@ -62,7 +66,7 @@ namespace ts {
}
function contains(path: Path) {
return hasProperty(files, toKey(path));
return toKey(path) in files;
}
function remove(path: Path) {
@@ -188,6 +192,21 @@ namespace ts {
return array;
}
export function removeWhere<T>(array: T[], f: (x: T) => boolean): boolean {
let outIndex = 0;
for (const item of array) {
if (!f(item)) {
array[outIndex] = item;
outIndex++;
}
}
if (outIndex !== array.length) {
array.length = outIndex;
return true;
}
return false;
}
export function filterMutate<T>(array: T[], f: (x: T) => boolean): void {
let outIndex = 0;
for (const item of array) {
@@ -350,82 +369,142 @@ namespace ts {
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Indicates whether a map-like contains an own property with the specified key.
*
* NOTE: This is intended for use only with MapLike<T> objects. For Map<T> objects, use
* the 'in' operator.
*
* @param map A map-like.
* @param key A property key.
*/
export function hasProperty<T>(map: MapLike<T>, key: string): boolean {
return hasOwnProperty.call(map, key);
}
export function getKeys<T>(map: MapLike<T>): string[] {
/**
* Gets the value of an owned property in a map-like.
*
* NOTE: This is intended for use only with MapLike<T> objects. For Map<T> objects, use
* an indexer.
*
* @param map A map-like.
* @param key A property key.
*/
export function getProperty<T>(map: MapLike<T>, key: string): T | undefined {
return hasOwnProperty.call(map, key) ? map[key] : undefined;
}
/**
* Gets the owned, enumerable property keys of a map-like.
*
* NOTE: This is intended for use with MapLike<T> objects. For Map<T> objects, use
* Object.keys instead as it offers better performance.
*
* @param map A map-like.
*/
export function getOwnKeys<T>(map: MapLike<T>): string[] {
const keys: string[] = [];
for (const key in map) {
for (const key in map) if (hasOwnProperty.call(map, key)) {
keys.push(key);
}
return keys;
}
export function getProperty<T>(map: MapLike<T>, key: string): T | undefined {
return hasProperty(map, key) ? map[key] : undefined;
/**
* Enumerates the properties of a Map<T>, invoking a callback and returning the first truthy result.
*
* @param map A map for which properties should be enumerated.
* @param callback A callback to invoke for each property.
*/
export function forEachProperty<T, U>(map: Map<T>, callback: (value: T, key: string) => U): U {
let result: U;
for (const key in map) {
if (result = callback(map[key], key)) break;
}
return result;
}
export function getOrUpdateProperty<T>(map: MapLike<T>, key: string, makeValue: () => T): T {
return hasProperty(map, key) ? map[key] : map[key] = makeValue();
/**
* Returns true if a Map<T> has some matching property.
*
* @param map A map whose properties should be tested.
* @param predicate An optional callback used to test each property.
*/
export function someProperties<T>(map: Map<T>, predicate?: (value: T, key: string) => boolean) {
for (const key in map) {
if (!predicate || predicate(map[key], key)) return true;
}
return false;
}
export function isEmpty<T>(map: MapLike<T>) {
for (const id in map) {
if (hasProperty(map, id)) {
return false;
}
/**
* Performs a shallow copy of the properties from a source Map<T> to a target MapLike<T>
*
* @param source A map from which properties should be copied.
* @param target A map to which properties should be copied.
*/
export function copyProperties<T>(source: Map<T>, target: MapLike<T>): void {
for (const key in source) {
target[key] = source[key];
}
}
/**
* Reduce the properties of a map.
*
* NOTE: This is intended for use with Map<T> objects. For MapLike<T> objects, use
* reduceOwnProperties instead as it offers better runtime safety.
*
* @param map The map to reduce
* @param callback An aggregation function that is called for each entry in the map
* @param initial The initial value for the reduction.
*/
export function reduceProperties<T, U>(map: Map<T>, callback: (aggregate: U, value: T, key: string) => U, initial: U): U {
let result = initial;
for (const key in map) {
result = callback(result, map[key], String(key));
}
return result;
}
/**
* Reduce the properties defined on a map-like (but not from its prototype chain).
*
* NOTE: This is intended for use with MapLike<T> objects. For Map<T> objects, use
* reduceProperties instead as it offers better performance.
*
* @param map The map-like to reduce
* @param callback An aggregation function that is called for each entry in the map
* @param initial The initial value for the reduction.
*/
export function reduceOwnProperties<T, U>(map: MapLike<T>, callback: (aggregate: U, value: T, key: string) => U, initial: U): U {
let result = initial;
for (const key in map) if (hasOwnProperty.call(map, key)) {
result = callback(result, map[key], String(key));
}
return result;
}
/**
* Performs a shallow equality comparison of the contents of two map-likes.
*
* @param left A map-like whose properties should be compared.
* @param right A map-like whose properties should be compared.
*/
export function equalOwnProperties<T>(left: MapLike<T>, right: MapLike<T>, equalityComparer?: (left: T, right: T) => boolean) {
if (left === right) return true;
if (!left || !right) return false;
for (const key in left) if (hasOwnProperty.call(left, key)) {
if (!hasOwnProperty.call(right, key) === undefined) return false;
if (equalityComparer ? !equalityComparer(left[key], right[key]) : left[key] !== right[key]) return false;
}
for (const key in right) if (hasOwnProperty.call(right, key)) {
if (!hasOwnProperty.call(left, key)) return false;
}
return true;
}
export function clone<T>(object: T): T {
const result: any = {};
for (const id in object) {
result[id] = (<any>object)[id];
}
return <T>result;
}
export function extend<T1 extends MapLike<{}>, T2 extends MapLike<{}>>(first: T1 , second: T2): T1 & T2 {
const result: T1 & T2 = <any>{};
for (const id in first) {
(result as any)[id] = first[id];
}
for (const id in second) {
if (!hasProperty(result, id)) {
(result as any)[id] = second[id];
}
}
return result;
}
export function forEachValue<T, U>(map: MapLike<T>, callback: (value: T) => U): U {
let result: U;
for (const id in map) {
if (result = callback(map[id])) break;
}
return result;
}
export function forEachKey<T, U>(map: MapLike<T>, callback: (key: string) => U): U {
let result: U;
for (const id in map) {
if (result = callback(id)) break;
}
return result;
}
export function lookUp<T>(map: MapLike<T>, key: string): T {
return hasProperty(map, key) ? map[key] : undefined;
}
export function copyMap<T>(source: MapLike<T>, target: MapLike<T>): void {
for (const p in source) {
target[p] = source[p];
}
}
/**
* Creates a map from the elements of an array.
*
@@ -436,33 +515,40 @@ namespace ts {
* the same key with the given 'makeKey' function, then the element with the higher
* index in the array will be the one associated with the produced key.
*/
export function arrayToMap<T>(array: T[], makeKey: (value: T) => string): Map<T> {
const result = createMap<T>();
forEach(array, value => {
result[makeKey(value)] = value;
});
export function arrayToMap<T>(array: T[], makeKey: (value: T) => string): Map<T>;
export function arrayToMap<T, U>(array: T[], makeKey: (value: T) => string, makeValue: (value: T) => U): Map<U>;
export function arrayToMap<T, U>(array: T[], makeKey: (value: T) => string, makeValue?: (value: T) => U): Map<T | U> {
const result = createMap<T | U>();
for (const value of array) {
result[makeKey(value)] = makeValue ? makeValue(value) : value;
}
return result;
}
/**
* Reduce the properties of a map.
*
* @param map The map to reduce
* @param callback An aggregation function that is called for each entry in the map
* @param initial The initial value for the reduction.
*/
export function reduceProperties<T, U>(map: MapLike<T>, callback: (aggregate: U, value: T, key: string) => U, initial: U): U {
let result = initial;
if (map) {
for (const key in map) {
if (hasProperty(map, key)) {
result = callback(result, map[key], String(key));
}
export function cloneMap<T>(map: Map<T>) {
const clone = createMap<T>();
copyProperties(map, clone);
return clone;
}
export function clone<T>(object: T): T {
const result: any = {};
for (const id in object) {
if (hasOwnProperty.call(object, id)) {
result[id] = (<any>object)[id];
}
}
return result;
}
export function extend<T1, T2>(first: T1 , second: T2): T1 & T2 {
const result: T1 & T2 = <any>{};
for (const id in second) if (hasOwnProperty.call(second, id)) {
(result as any)[id] = (second as any)[id];
}
for (const id in first) if (hasOwnProperty.call(first, id)) {
(result as any)[id] = (first as any)[id];
}
return result;
}
+4 -6
View File
@@ -157,9 +157,7 @@ namespace ts {
if (usedTypeDirectiveReferences) {
for (const directive in usedTypeDirectiveReferences) {
if (hasProperty(usedTypeDirectiveReferences, directive)) {
referencesOutput += `/// <reference types="${directive}" />${newLine}`;
}
referencesOutput += `/// <reference types="${directive}" />${newLine}`;
}
}
@@ -272,7 +270,7 @@ namespace ts {
usedTypeDirectiveReferences = createMap<string>();
}
for (const directive of typeReferenceDirectives) {
if (!hasProperty(usedTypeDirectiveReferences, directive)) {
if (!(directive in usedTypeDirectiveReferences)) {
usedTypeDirectiveReferences[directive] = directive;
}
}
@@ -537,14 +535,14 @@ namespace ts {
// do not need to keep track of created temp names.
function getExportDefaultTempVariableName(): string {
const baseName = "_default";
if (!hasProperty(currentIdentifiers, baseName)) {
if (!(baseName in currentIdentifiers)) {
return baseName;
}
let count = 0;
while (true) {
count++;
const name = baseName + "_" + count;
if (!hasProperty(currentIdentifiers, name)) {
if (!(name in currentIdentifiers)) {
return name;
}
}
+18 -18
View File
@@ -24,7 +24,7 @@ namespace ts {
Return = 1 << 3
}
const entities: MapLike<number> = {
const entities = createMap({
"quot": 0x0022,
"amp": 0x0026,
"apos": 0x0027,
@@ -278,7 +278,7 @@ namespace ts {
"clubs": 0x2663,
"hearts": 0x2665,
"diams": 0x2666
};
});
// Flags enum to track count of temp variables and a few dedicated names
const enum TempFlags {
@@ -407,7 +407,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function isUniqueLocalName(name: string, container: Node): boolean {
for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) {
if (node.locals && hasProperty(node.locals, name)) {
if (node.locals && name in node.locals) {
// We conservatively include alias symbols to cover cases where they're emitted as locals
if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
return false;
@@ -531,7 +531,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
let currentText: string;
let currentLineMap: number[];
let currentFileIdentifiers: Map<string>;
let renamedDependencies: MapLike<string>;
let renamedDependencies: Map<string>;
let isEs6Module: boolean;
let isCurrentFileExternalModule: boolean;
@@ -577,21 +577,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
const setSourceMapWriterEmit = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? changeSourceMapEmit : function (writer: SourceMapWriter) { };
const moduleEmitDelegates: MapLike<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
const moduleEmitDelegates = createMap<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void>({
[ModuleKind.ES6]: emitES6Module,
[ModuleKind.AMD]: emitAMDModule,
[ModuleKind.System]: emitSystemModule,
[ModuleKind.UMD]: emitUMDModule,
[ModuleKind.CommonJS]: emitCommonJSModule,
};
});
const bundleEmitDelegates: MapLike<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
const bundleEmitDelegates = createMap<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void>({
[ModuleKind.ES6]() {},
[ModuleKind.AMD]: emitAMDModule,
[ModuleKind.System]: emitSystemModule,
[ModuleKind.UMD]() {},
[ModuleKind.CommonJS]() {},
};
});
return doEmit;
@@ -669,8 +669,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function isUniqueName(name: string): boolean {
return !resolver.hasGlobalName(name) &&
!hasProperty(currentFileIdentifiers, name) &&
!hasProperty(generatedNameSet, name);
!(name in currentFileIdentifiers) &&
!(name in generatedNameSet);
}
// Return the next available name in the pattern _a ... _z, _0, _1, ...
@@ -2646,7 +2646,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
return false;
}
return !exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, (<Identifier>node).text);
return !exportEquals && exportSpecifiers && (<Identifier>node).text in exportSpecifiers;
}
function emitPrefixUnaryExpression(node: PrefixUnaryExpression) {
@@ -3263,7 +3263,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
write(", ");
}
if (!hasProperty(seen, id.text)) {
if (!(id.text in seen)) {
emit(id);
seen[id.text] = id.text;
}
@@ -3970,7 +3970,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
return;
}
if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) {
if (!exportEquals && exportSpecifiers && name.text in exportSpecifiers) {
for (const specifier of exportSpecifiers[name.text]) {
writeLine();
emitStart(specifier.name);
@@ -6450,7 +6450,7 @@ const _super = (function (geti, seti) {
* Here we check if alternative name was provided for a given moduleName and return it if possible.
*/
function tryRenameExternalModule(moduleName: LiteralExpression): string {
if (renamedDependencies && hasProperty(renamedDependencies, moduleName.text)) {
if (renamedDependencies && moduleName.text in renamedDependencies) {
return `"${renamedDependencies[moduleName.text]}"`;
}
return undefined;
@@ -6831,7 +6831,7 @@ const _super = (function (geti, seti) {
// export { x, y }
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
const name = (specifier.propertyName || specifier.name).text;
getOrUpdateProperty(exportSpecifiers, name, () => []).push(specifier);
(exportSpecifiers[name] || (exportSpecifiers[name] = [])).push(specifier);
}
}
break;
@@ -6930,7 +6930,7 @@ const _super = (function (geti, seti) {
}
// local names set should only be added if we have anything exported
if (!exportedDeclarations && isEmpty(exportSpecifiers)) {
if (!exportedDeclarations && !someProperties(exportSpecifiers)) {
// no exported declarations (export var ...) or export specifiers (export {x})
// check if we have any non star export declarations.
let hasExportDeclarationWithExportClause = false;
@@ -7080,7 +7080,7 @@ const _super = (function (geti, seti) {
if (name) {
// do not emit duplicate entries (in case of declaration merging) in the list of hoisted variables
const text = unescapeIdentifier(name.text);
if (hasProperty(seen, text)) {
if (text in seen) {
continue;
}
else {
@@ -7449,7 +7449,7 @@ const _super = (function (geti, seti) {
// for deduplication purposes in key remove leading and trailing quotes so 'a' and "a" will be considered the same
const key = text.substr(1, text.length - 2);
if (hasProperty(groupIndices, key)) {
if (key in groupIndices) {
// deduplicate/group entries in dependency list by the dependency name
const groupIndex = groupIndices[key];
dependencyGroups[groupIndex].push(externalImports[i]);
+11 -16
View File
@@ -501,7 +501,7 @@ namespace ts {
if (state.traceEnabled) {
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
}
matchedPattern = matchPatternOrExact(getKeys(state.compilerOptions.paths), moduleName);
matchedPattern = matchPatternOrExact(getOwnKeys(state.compilerOptions.paths), moduleName);
}
if (matchedPattern) {
@@ -875,7 +875,7 @@ namespace ts {
}
function directoryExists(directoryPath: string): boolean {
if (hasProperty(existingDirectories, directoryPath)) {
if (directoryPath in existingDirectories) {
return true;
}
if (sys.directoryExists(directoryPath)) {
@@ -903,7 +903,7 @@ namespace ts {
const hash = sys.createHash(data);
const mtimeBefore = sys.getModifiedTime(fileName);
if (mtimeBefore && hasProperty(outputFingerprints, fileName)) {
if (mtimeBefore && fileName in outputFingerprints) {
const fingerprint = outputFingerprints[fileName];
// If output has not been changed, and the file has no external modification
@@ -1041,14 +1041,9 @@ namespace ts {
const resolutions: T[] = [];
const cache = createMap<T>();
for (const name of names) {
let result: T;
if (hasProperty(cache, name)) {
result = cache[name];
}
else {
result = loader(name, containingFile);
cache[name] = result;
}
const result = name in cache
? cache[name]
: cache[name] = loader(name, containingFile);
resolutions.push(result);
}
return resolutions;
@@ -1249,7 +1244,7 @@ namespace ts {
classifiableNames = createMap<string>();
for (const sourceFile of files) {
copyMap(sourceFile.classifiableNames, classifiableNames);
copyProperties(sourceFile.classifiableNames, classifiableNames);
}
}
@@ -1277,7 +1272,7 @@ namespace ts {
(oldOptions.maxNodeModuleJsDepth !== options.maxNodeModuleJsDepth) ||
!arrayIsEqualTo(oldOptions.typeRoots, oldOptions.typeRoots) ||
!arrayIsEqualTo(oldOptions.rootDirs, options.rootDirs) ||
!mapIsEqualTo(oldOptions.paths, options.paths)) {
!equalOwnProperties(oldOptions.paths, options.paths)) {
return false;
}
@@ -1399,7 +1394,7 @@ namespace ts {
getSourceFile: program.getSourceFile,
getSourceFileByPath: program.getSourceFileByPath,
getSourceFiles: program.getSourceFiles,
isSourceFileFromExternalLibrary: (file: SourceFile) => !!lookUp(sourceFilesFoundSearchingNodeModules, file.path),
isSourceFileFromExternalLibrary: (file: SourceFile) => !!sourceFilesFoundSearchingNodeModules[file.path],
writeFile: writeFileCallback || (
(fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)),
isEmitBlocked,
@@ -1937,7 +1932,7 @@ namespace ts {
// If the file was previously found via a node_modules search, but is now being processed as a root file,
// then everything it sucks in may also be marked incorrectly, and needs to be checked again.
if (file && lookUp(sourceFilesFoundSearchingNodeModules, file.path) && currentNodeModulesDepth == 0) {
if (file && sourceFilesFoundSearchingNodeModules[file.path] && currentNodeModulesDepth == 0) {
sourceFilesFoundSearchingNodeModules[file.path] = false;
if (!options.noResolve) {
processReferencedFiles(file, getDirectoryPath(fileName), isDefaultLib);
@@ -1948,7 +1943,7 @@ namespace ts {
processImportedModules(file, getDirectoryPath(fileName));
}
// See if we need to reprocess the imports due to prior skipped imports
else if (file && lookUp(modulesWithElidedImports, file.path)) {
else if (file && modulesWithElidedImports[file.path]) {
if (currentNodeModulesDepth < maxNodeModulesJsDepth) {
modulesWithElidedImports[file.path] = false;
processImportedModules(file, getDirectoryPath(fileName));
+4 -6
View File
@@ -55,7 +55,7 @@ namespace ts {
tryScan<T>(callback: () => T): T;
}
const textToToken: MapLike<SyntaxKind> = {
const textToToken = createMap({
"abstract": SyntaxKind.AbstractKeyword,
"any": SyntaxKind.AnyKeyword,
"as": SyntaxKind.AsKeyword,
@@ -179,7 +179,7 @@ namespace ts {
"|=": SyntaxKind.BarEqualsToken,
"^=": SyntaxKind.CaretEqualsToken,
"@": SyntaxKind.AtToken,
};
});
/*
As per ECMAScript Language Specification 3th Edition, Section 7.6: Identifiers
@@ -271,12 +271,10 @@ namespace ts {
lookupInUnicodeMap(code, unicodeES3IdentifierPart);
}
function makeReverseMap(source: MapLike<number>): string[] {
function makeReverseMap(source: Map<number>): string[] {
const result: string[] = [];
for (const name in source) {
if (source.hasOwnProperty(name)) {
result[source[name]] = name;
}
result[source[name]] = name;
}
return result;
}
+10 -11
View File
@@ -122,11 +122,11 @@ namespace ts {
const gutterSeparator = " ";
const resetEscapeSequence = "\u001b[0m";
const ellipsis = "...";
const categoryFormatMap: MapLike<string> = {
const categoryFormatMap = createMap<string>({
[DiagnosticCategory.Warning]: yellowForegroundEscapeSequence,
[DiagnosticCategory.Error]: redForegroundEscapeSequence,
[DiagnosticCategory.Message]: blueForegroundEscapeSequence,
};
});
function formatAndReset(text: string, formatStyle: string) {
return formatStyle + text + resetEscapeSequence;
@@ -445,10 +445,9 @@ namespace ts {
}
function cachedFileExists(fileName: string): boolean {
if (hasProperty(cachedExistingFiles, fileName)) {
return cachedExistingFiles[fileName];
}
return cachedExistingFiles[fileName] = hostFileExists(fileName);
return fileName in cachedExistingFiles
? cachedExistingFiles[fileName]
: cachedExistingFiles[fileName] = hostFileExists(fileName);
}
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void) {
@@ -704,9 +703,10 @@ namespace ts {
description = getDiagnosticText(option.description);
const options: string[] = [];
const element = (<CommandLineOptionOfListType>option).element;
forEachKey(<Map<number | string>>element.type, key => {
const typeMap = <Map<number | string>>element.type;
for (const key in typeMap) {
options.push(`'${key}'`);
});
}
optionsDescriptionMap[description] = options;
}
else {
@@ -812,9 +812,8 @@ namespace ts {
// Enum
const typeMap = <Map<number>>optionDefinition.type;
for (const key in typeMap) {
if (hasProperty(typeMap, key)) {
if (typeMap[key] === value)
result[name] = key;
if (typeMap[key] === value) {
result[name] = key;
}
}
}
+3 -3
View File
@@ -1650,7 +1650,7 @@ namespace ts {
// this map is used by transpiler to supply alternative names for dependencies (i.e. in case of bundling)
/* @internal */
renamedDependencies?: MapLike<string>;
renamedDependencies?: Map<string>;
/**
* lib.d.ts should have a reference comment like
@@ -2744,7 +2744,7 @@ namespace ts {
/* @internal */
export interface CommandLineOptionBase {
name: string;
type: "string" | "number" | "boolean" | "object" | "list" | MapLike<number | string>; // a value of a primitive type, or an object literal mapping named values to actual values
type: "string" | "number" | "boolean" | "object" | "list" | Map<number | string>; // a value of a primitive type, or an object literal mapping named values to actual values
isFilePath?: boolean; // True if option value is a path or fileName
shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help'
description?: DiagnosticMessage; // The message describing what the command line switch does
@@ -2760,7 +2760,7 @@ namespace ts {
/* @internal */
export interface CommandLineOptionOfCustomType extends CommandLineOptionBase {
type: MapLike<number | string>; // an object literal mapping named values to actual values
type: Map<number | string>; // an object literal mapping named values to actual values
}
/* @internal */
+3 -22
View File
@@ -87,25 +87,6 @@ namespace ts {
return node.end - node.pos;
}
export function mapIsEqualTo<T>(map1: MapLike<T>, map2: MapLike<T>): boolean {
if (!map1 || !map2) {
return map1 === map2;
}
return containsAll(map1, map2) && containsAll(map2, map1);
}
function containsAll<T>(map: MapLike<T>, other: MapLike<T>): boolean {
for (const key in map) {
if (!hasProperty(map, key)) {
continue;
}
if (!hasProperty(other, key) || map[key] !== other[key]) {
return false;
}
}
return true;
}
export function arrayIsEqualTo<T>(array1: T[], array2: T[], equaler?: (a: T, b: T) => boolean): boolean {
if (!array1 || !array2) {
return array1 === array2;
@@ -2059,7 +2040,7 @@ namespace ts {
// the map below must be updated. Note that this regexp *does not* include the 'delete' character.
// There is no reason for this other than that JSON.stringify does not handle it either.
const escapedCharsRegExp = /[\\\"\u0000-\u001f\t\v\f\b\r\n\u2028\u2029\u0085]/g;
const escapedCharsMap: MapLike<string> = {
const escapedCharsMap = createMap({
"\0": "\\0",
"\t": "\\t",
"\v": "\\v",
@@ -2072,7 +2053,7 @@ namespace ts {
"\u2028": "\\u2028", // lineSeparator
"\u2029": "\\u2029", // paragraphSeparator
"\u0085": "\\u0085" // nextLine
};
});
/**
@@ -2792,7 +2773,7 @@ namespace ts {
}
function stringifyObject(value: any) {
return `{${reduceProperties(value, stringifyProperty, "")}}`;
return `{${reduceOwnProperties(value, stringifyProperty, "")}}`;
}
function stringifyProperty(memo: string, value: any, key: string) {
+3 -3
View File
@@ -291,8 +291,8 @@ class CompilerBaselineRunner extends RunnerBase {
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
const fullResults: ts.MapLike<TypeWriterResult[]> = {};
const pullResults: ts.MapLike<TypeWriterResult[]> = {};
const fullResults = ts.createMap<TypeWriterResult[]>();
const pullResults = ts.createMap<TypeWriterResult[]>();
for (const sourceFile of allFiles) {
fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
@@ -338,7 +338,7 @@ class CompilerBaselineRunner extends RunnerBase {
}
}
function generateBaseLine(typeWriterResults: ts.MapLike<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
const typeLines: string[] = [];
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
+15 -14
View File
@@ -95,14 +95,14 @@ namespace FourSlash {
export import IndentStyle = ts.IndentStyle;
const entityMap: ts.MapLike<string> = {
const entityMap = ts.createMap({
"&": "&amp;",
"\"": "&quot;",
"'": "&#39;",
"/": "&#47;",
"<": "&lt;",
">": "&gt;"
};
});
export function escapeXmlAttributeValue(s: string) {
return s.replace(/[&<>"'\/]/g, ch => entityMap[ch]);
@@ -204,7 +204,7 @@ namespace FourSlash {
public formatCodeOptions: ts.FormatCodeOptions;
private inputFiles: ts.MapLike<string> = {}; // Map between inputFile's fileName and its content for easily looking up when resolving references
private inputFiles = ts.createMap<string>(); // Map between inputFile's fileName and its content for easily looking up when resolving references
// Add input file which has matched file name with the given reference-file path.
// This is necessary when resolveReference flag is specified
@@ -301,11 +301,11 @@ namespace FourSlash {
}
else {
// resolveReference file-option is not specified then do not resolve any files and include all inputFiles
ts.forEachKey(this.inputFiles, fileName => {
for (const fileName in this.inputFiles) {
if (!Harness.isDefaultLibraryFile(fileName)) {
this.languageServiceAdapterHost.addScript(fileName, this.inputFiles[fileName], /*isRootFile*/ true);
}
});
}
this.languageServiceAdapterHost.addScript(Harness.Compiler.defaultLibFileName,
Harness.Compiler.getDefaultLibrarySourceFile().text, /*isRootFile*/ false);
}
@@ -594,9 +594,9 @@ namespace FourSlash {
public noItemsWithSameNameButDifferentKind(): void {
const completions = this.getCompletionListAtCaret();
const uniqueItems: ts.MapLike<string> = {};
const uniqueItems = ts.createMap<string>();
for (const item of completions.entries) {
if (!ts.hasProperty(uniqueItems, item.name)) {
if (!(item.name in uniqueItems)) {
uniqueItems[item.name] = item.kind;
}
else {
@@ -774,7 +774,7 @@ namespace FourSlash {
}
public verifyRangesWithSameTextReferenceEachOther() {
ts.forEachValue(this.rangesByText(), ranges => this.verifyRangesReferenceEachOther(ranges));
ts.forEachProperty(this.rangesByText(), ranges => this.verifyRangesReferenceEachOther(ranges));
}
private verifyReferencesWorker(references: ts.ReferenceEntry[], fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
@@ -1631,11 +1631,12 @@ namespace FourSlash {
return this.testData.ranges;
}
public rangesByText(): ts.MapLike<Range[]> {
const result: ts.MapLike<Range[]> = {};
public rangesByText(): ts.Map<Range[]> {
const result = ts.createMap<Range[]>();
for (const range of this.getRanges()) {
const text = this.rangeText(range);
(ts.getProperty(result, text) || (result[text] = [])).push(range);
const ranges = result[text] || (result[text] = []);
ranges.push(range);
}
return result;
}
@@ -1890,7 +1891,7 @@ namespace FourSlash {
public verifyBraceCompletionAtPosition(negative: boolean, openingBrace: string) {
const openBraceMap: ts.MapLike<ts.CharacterCodes> = {
const openBraceMap = ts.createMap<ts.CharacterCodes>({
"(": ts.CharacterCodes.openParen,
"{": ts.CharacterCodes.openBrace,
"[": ts.CharacterCodes.openBracket,
@@ -1898,7 +1899,7 @@ namespace FourSlash {
'"': ts.CharacterCodes.doubleQuote,
"`": ts.CharacterCodes.backtick,
"<": ts.CharacterCodes.lessThan
};
});
const charCode = openBraceMap[openingBrace];
@@ -2738,7 +2739,7 @@ namespace FourSlashInterface {
return this.state.getRanges();
}
public rangesByText(): ts.MapLike<FourSlash.Range[]> {
public rangesByText(): ts.Map<FourSlash.Range[]> {
return this.state.rangesByText();
}
+5 -5
View File
@@ -848,9 +848,9 @@ namespace Harness {
export const defaultLibFileName = "lib.d.ts";
export const es2015DefaultLibFileName = "lib.es2015.d.ts";
const libFileNameSourceFileMap: ts.MapLike<ts.SourceFile> = {
const libFileNameSourceFileMap= ts.createMap<ts.SourceFile>({
[defaultLibFileName]: createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.es5.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest)
};
});
export function getDefaultLibrarySourceFile(fileName = defaultLibFileName): ts.SourceFile {
if (!isDefaultLibraryFile(fileName)) {
@@ -1002,16 +1002,16 @@ namespace Harness {
{ name: "symlink", type: "string" }
];
let optionsIndex: ts.MapLike<ts.CommandLineOption>;
let optionsIndex: ts.Map<ts.CommandLineOption>;
function getCommandLineOption(name: string): ts.CommandLineOption {
if (!optionsIndex) {
optionsIndex = {};
optionsIndex = ts.createMap<ts.CommandLineOption>();
const optionDeclarations = harnessOptionDeclarations.concat(ts.optionDeclarations);
for (const option of optionDeclarations) {
optionsIndex[option.name.toLowerCase()] = option;
}
}
return ts.lookUp(optionsIndex, name.toLowerCase());
return optionsIndex[name.toLowerCase()];
}
export function setCompilerOptionsFromHarnessSetting(settings: Harness.TestCaseParser.CompilerSettings, options: ts.CompilerOptions & HarnessOptions): void {
+5 -5
View File
@@ -123,7 +123,7 @@ namespace Harness.LanguageService {
}
export class LanguageServiceAdapterHost {
protected fileNameToScript: ts.MapLike<ScriptInfo> = {};
protected fileNameToScript = ts.createMap<ScriptInfo>();
constructor(protected cancellationToken = DefaultHostCancellationToken.Instance,
protected settings = ts.getDefaultCompilerOptions()) {
@@ -135,7 +135,7 @@ namespace Harness.LanguageService {
public getFilenames(): string[] {
const fileNames: string[] = [];
ts.forEachValue(this.fileNameToScript, (scriptInfo) => {
ts.forEachProperty(this.fileNameToScript, (scriptInfo) => {
if (scriptInfo.isRootFile) {
// only include root files here
// usually it means that we won't include lib.d.ts in the list of root files so it won't mess the computation of compilation root dir.
@@ -146,7 +146,7 @@ namespace Harness.LanguageService {
}
public getScriptInfo(fileName: string): ScriptInfo {
return ts.lookUp(this.fileNameToScript, fileName);
return this.fileNameToScript[fileName];
}
public addScript(fileName: string, content: string, isRootFile: boolean): void {
@@ -235,7 +235,7 @@ namespace Harness.LanguageService {
this.getModuleResolutionsForFile = (fileName) => {
const scriptInfo = this.getScriptInfo(fileName);
const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ true);
const imports: ts.MapLike<string> = {};
const imports = ts.createMap<string>();
for (const module of preprocessInfo.importedFiles) {
const resolutionInfo = ts.resolveModuleName(module.fileName, fileName, compilerOptions, moduleResolutionHost);
if (resolutionInfo.resolvedModule) {
@@ -248,7 +248,7 @@ namespace Harness.LanguageService {
const scriptInfo = this.getScriptInfo(fileName);
if (scriptInfo) {
const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ false);
const resolutions: ts.MapLike<ts.ResolvedTypeReferenceDirective> = {};
const resolutions = ts.createMap<ts.ResolvedTypeReferenceDirective>();
const settings = this.nativeHost.getCompilationSettings();
for (const typeReferenceDirective of preprocessInfo.typeReferenceDirectives) {
const resolutionInfo = ts.resolveTypeReferenceDirective(typeReferenceDirective.fileName, fileName, settings, moduleResolutionHost);
+3 -6
View File
@@ -253,18 +253,15 @@ class ProjectRunner extends RunnerBase {
moduleResolution: ts.ModuleResolutionKind.Classic, // currently all tests use classic module resolution kind, this will change in the future
};
// Set the values specified using json
const optionNameMap: ts.MapLike<ts.CommandLineOption> = {};
ts.forEach(ts.optionDeclarations, option => {
optionNameMap[option.name] = option;
});
const optionNameMap = ts.arrayToMap(ts.optionDeclarations, option => option.name);
for (const name in testCase) {
if (name !== "mapRoot" && name !== "sourceRoot" && ts.hasProperty(optionNameMap, name)) {
if (name !== "mapRoot" && name !== "sourceRoot" && name in optionNameMap) {
const option = optionNameMap[name];
const optType = option.type;
let value = <any>testCase[name];
if (typeof optType !== "string") {
const key = value.toLowerCase();
if (ts.hasProperty(optType, key)) {
if (key in optType) {
value = optType[key];
}
}
+10 -10
View File
@@ -6,17 +6,17 @@ namespace ts {
content: string;
}
function createDefaultServerHost(fileMap: MapLike<File>): server.ServerHost {
const existingDirectories: MapLike<boolean> = {};
forEachValue(fileMap, v => {
let dir = getDirectoryPath(v.name);
function createDefaultServerHost(fileMap: Map<File>): server.ServerHost {
const existingDirectories = createMap<boolean>();
for (const name in fileMap) {
let dir = getDirectoryPath(name);
let previous: string;
do {
existingDirectories[dir] = true;
previous = dir;
dir = getDirectoryPath(dir);
} while (dir !== previous);
});
}
return {
args: <string[]>[],
newLine: "\r\n",
@@ -24,7 +24,7 @@ namespace ts {
write: (s: string) => {
},
readFile: (path: string, encoding?: string): string => {
return hasProperty(fileMap, path) && fileMap[path].content;
return path in fileMap ? fileMap[path].content : undefined;
},
writeFile: (path: string, data: string, writeByteOrderMark?: boolean) => {
throw new Error("NYI");
@@ -33,10 +33,10 @@ namespace ts {
throw new Error("NYI");
},
fileExists: (path: string): boolean => {
return hasProperty(fileMap, path);
return path in fileMap;
},
directoryExists: (path: string): boolean => {
return hasProperty(existingDirectories, path);
return existingDirectories[path] || false;
},
createDirectory: (path: string) => {
},
@@ -101,7 +101,7 @@ namespace ts {
content: `foo()`
};
const serverHost = createDefaultServerHost({ [root.name]: root, [imported.name]: imported });
const serverHost = createDefaultServerHost(createMap({ [root.name]: root, [imported.name]: imported }));
const { project, rootScriptInfo } = createProject(root.name, serverHost);
// ensure that imported file was found
@@ -193,7 +193,7 @@ namespace ts {
content: `export var y = 1`
};
const fileMap: MapLike<File> = { [root.name]: root };
const fileMap = createMap({ [root.name]: root });
const serverHost = createDefaultServerHost(fileMap);
const originalFileExists = serverHost.fileExists;
+37 -41
View File
@@ -10,7 +10,7 @@ namespace ts {
const map = arrayToMap(files, f => f.name);
if (hasDirectoryExists) {
const directories: MapLike<string> = {};
const directories = createMap<string>();
for (const f of files) {
let name = getDirectoryPath(f.name);
while (true) {
@@ -25,19 +25,19 @@ namespace ts {
return {
readFile,
directoryExists: path => {
return hasProperty(directories, path);
return path in directories;
},
fileExists: path => {
assert.isTrue(hasProperty(directories, getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`);
return hasProperty(map, path);
assert.isTrue(getDirectoryPath(path) in directories, `'fileExists' '${path}' request in non-existing directory`);
return path in map;
}
};
}
else {
return { readFile, fileExists: path => hasProperty(map, path), };
return { readFile, fileExists: path => path in map, };
}
function readFile(path: string): string {
return hasProperty(map, path) ? map[path].content : undefined;
return path in map ? map[path].content : undefined;
}
}
@@ -282,12 +282,12 @@ namespace ts {
});
describe("Module resolution - relative imports", () => {
function test(files: MapLike<string>, currentDirectory: string, rootFiles: string[], expectedFilesCount: number, relativeNamesToCheck: string[]) {
function test(files: Map<string>, currentDirectory: string, rootFiles: string[], expectedFilesCount: number, relativeNamesToCheck: string[]) {
const options: CompilerOptions = { module: ModuleKind.CommonJS };
const host: CompilerHost = {
getSourceFile: (fileName: string, languageVersion: ScriptTarget) => {
const path = normalizePath(combinePaths(currentDirectory, fileName));
return hasProperty(files, path) ? createSourceFile(fileName, files[path], languageVersion) : undefined;
return path in files ? createSourceFile(fileName, files[path], languageVersion) : undefined;
},
getDefaultLibFileName: () => "lib.d.ts",
writeFile: (fileName, content): void => { throw new Error("NotImplemented"); },
@@ -298,7 +298,7 @@ namespace ts {
useCaseSensitiveFileNames: () => false,
fileExists: fileName => {
const path = normalizePath(combinePaths(currentDirectory, fileName));
return hasProperty(files, path);
return path in files;
},
readFile: (fileName): string => { throw new Error("NotImplemented"); }
};
@@ -318,7 +318,7 @@ namespace ts {
}
it("should find all modules", () => {
const files: MapLike<string> = {
const files = createMap({
"/a/b/c/first/shared.ts": `
class A {}
export = A`,
@@ -332,37 +332,33 @@ import Shared = require('../first/shared');
class C {}
export = C;
`
};
});
test(files, "/a/b/c/first/second", ["class_a.ts"], 3, ["../../../c/third/class_c.ts"]);
});
it("should find modules in node_modules", () => {
const files: MapLike<string> = {
const files = createMap({
"/parent/node_modules/mod/index.d.ts": "export var x",
"/parent/app/myapp.ts": `import {x} from "mod"`
};
});
test(files, "/parent/app", ["myapp.ts"], 2, []);
});
it("should find file referenced via absolute and relative names", () => {
const files: MapLike<string> = {
const files = createMap({
"/a/b/c.ts": `/// <reference path="b.ts"/>`,
"/a/b/b.ts": "var x"
};
});
test(files, "/a/b", ["c.ts", "/a/b/b.ts"], 2, []);
});
});
describe("Files with different casing", () => {
const library = createSourceFile("lib.d.ts", "", ScriptTarget.ES5);
function test(files: MapLike<string>, options: CompilerOptions, currentDirectory: string, useCaseSensitiveFileNames: boolean, rootFiles: string[], diagnosticCodes: number[]): void {
function test(files: Map<string>, options: CompilerOptions, currentDirectory: string, useCaseSensitiveFileNames: boolean, rootFiles: string[], diagnosticCodes: number[]): void {
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
if (!useCaseSensitiveFileNames) {
const f: MapLike<string> = {};
for (const fileName in files) {
f[getCanonicalFileName(fileName)] = files[fileName];
}
files = f;
files = reduceProperties(files, (files, file, fileName) => (files[getCanonicalFileName(fileName)] = file, files), createMap<string>());
}
const host: CompilerHost = {
@@ -371,7 +367,7 @@ export = C;
return library;
}
const path = getCanonicalFileName(normalizePath(combinePaths(currentDirectory, fileName)));
return hasProperty(files, path) ? createSourceFile(fileName, files[path], languageVersion) : undefined;
return path in files ? createSourceFile(fileName, files[path], languageVersion) : undefined;
},
getDefaultLibFileName: () => "lib.d.ts",
writeFile: (fileName, content): void => { throw new Error("NotImplemented"); },
@@ -382,7 +378,7 @@ export = C;
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
fileExists: fileName => {
const path = getCanonicalFileName(normalizePath(combinePaths(currentDirectory, fileName)));
return hasProperty(files, path);
return path in files;
},
readFile: (fileName): string => { throw new Error("NotImplemented"); }
};
@@ -395,57 +391,57 @@ export = C;
}
it("should succeed when the same file is referenced using absolute and relative names", () => {
const files: MapLike<string> = {
const files = createMap({
"/a/b/c.ts": `/// <reference path="d.ts"/>`,
"/a/b/d.ts": "var x"
};
});
test(files, { module: ts.ModuleKind.AMD }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "/a/b/d.ts"], []);
});
it("should fail when two files used in program differ only in casing (tripleslash references)", () => {
const files: MapLike<string> = {
const files = createMap({
"/a/b/c.ts": `/// <reference path="D.ts"/>`,
"/a/b/d.ts": "var x"
};
});
test(files, { module: ts.ModuleKind.AMD, forceConsistentCasingInFileNames: true }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "d.ts"], [1149]);
});
it("should fail when two files used in program differ only in casing (imports)", () => {
const files: MapLike<string> = {
const files = createMap({
"/a/b/c.ts": `import {x} from "D"`,
"/a/b/d.ts": "export var x"
};
});
test(files, { module: ts.ModuleKind.AMD, forceConsistentCasingInFileNames: true }, "/a/b", /*useCaseSensitiveFileNames*/ false, ["c.ts", "d.ts"], [1149]);
});
it("should fail when two files used in program differ only in casing (imports, relative module names)", () => {
const files: MapLike<string> = {
const files = createMap({
"moduleA.ts": `import {x} from "./ModuleB"`,
"moduleB.ts": "export var x"
};
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", /*useCaseSensitiveFileNames*/ false, ["moduleA.ts", "moduleB.ts"], [1149]);
});
it("should fail when two files exist on disk that differs only in casing", () => {
const files: MapLike<string> = {
const files = createMap({
"/a/b/c.ts": `import {x} from "D"`,
"/a/b/D.ts": "export var x",
"/a/b/d.ts": "export var y"
};
});
test(files, { module: ts.ModuleKind.AMD }, "/a/b", /*useCaseSensitiveFileNames*/ true, ["c.ts", "d.ts"], [1149]);
});
it("should fail when module name in 'require' calls has inconsistent casing", () => {
const files: MapLike<string> = {
const files = createMap({
"moduleA.ts": `import a = require("./ModuleC")`,
"moduleB.ts": `import a = require("./moduleC")`,
"moduleC.ts": "export var x"
};
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "", /*useCaseSensitiveFileNames*/ false, ["moduleA.ts", "moduleB.ts", "moduleC.ts"], [1149, 1149]);
});
it("should fail when module names in 'require' calls has inconsistent casing and current directory has uppercase chars", () => {
const files: MapLike<string> = {
const files = createMap({
"/a/B/c/moduleA.ts": `import a = require("./ModuleC")`,
"/a/B/c/moduleB.ts": `import a = require("./moduleC")`,
"/a/B/c/moduleC.ts": "export var x",
@@ -453,11 +449,11 @@ export = C;
import a = require("./moduleA.ts");
import b = require("./moduleB.ts");
`
};
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], [1149]);
});
it("should not fail when module names in 'require' calls has consistent casing and current directory has uppercase chars", () => {
const files: MapLike<string> = {
const files = createMap({
"/a/B/c/moduleA.ts": `import a = require("./moduleC")`,
"/a/B/c/moduleB.ts": `import a = require("./moduleC")`,
"/a/B/c/moduleC.ts": "export var x",
@@ -465,7 +461,7 @@ import b = require("./moduleB.ts");
import a = require("./moduleA.ts");
import b = require("./moduleB.ts");
`
};
});
test(files, { module: ts.ModuleKind.CommonJS, forceConsistentCasingInFileNames: true }, "/a/B/c", /*useCaseSensitiveFileNames*/ false, ["moduleD.ts"], []);
});
});
@@ -1023,7 +1019,7 @@ import b = require("./moduleB.ts");
const names = map(files, f => f.name);
const sourceFiles = arrayToMap(map(files, f => createSourceFile(f.name, f.content, ScriptTarget.ES6)), f => f.fileName);
const compilerHost: CompilerHost = {
fileExists : fileName => hasProperty(sourceFiles, fileName),
fileExists : fileName => fileName in sourceFiles,
getSourceFile: fileName => sourceFiles[fileName],
getDefaultLibFileName: () => "lib.d.ts",
writeFile(file, text) {
@@ -1034,7 +1030,7 @@ import b = require("./moduleB.ts");
getCanonicalFileName: f => f.toLowerCase(),
getNewLine: () => "\r\n",
useCaseSensitiveFileNames: () => false,
readFile: fileName => hasProperty(sourceFiles, fileName) ? sourceFiles[fileName].text : undefined
readFile: fileName => fileName in sourceFiles ? sourceFiles[fileName].text : undefined
};
const program1 = createProgram(names, {}, compilerHost);
const diagnostics1 = program1.getFileProcessingDiagnostics().getDiagnostics();
+37 -51
View File
@@ -95,13 +95,14 @@ namespace ts {
}
}
function createSourceFileWithText(fileName: string, sourceText: SourceText, target: ScriptTarget) {
const file = <SourceFileWithText>createSourceFile(fileName, sourceText.getFullText(), target);
file.sourceText = sourceText;
return file;
}
function createTestCompilerHost(texts: NamedSourceText[], target: ScriptTarget): CompilerHost {
const files: MapLike<SourceFileWithText> = {};
for (const t of texts) {
const file = <SourceFileWithText>createSourceFile(t.name, t.text.getFullText(), target);
file.sourceText = t.text;
files[t.name] = file;
}
const files = arrayToMap(texts, t => t.name, t => createSourceFileWithText(t.name, t.text, target));
return {
getSourceFile(fileName): SourceFile {
@@ -128,10 +129,9 @@ namespace ts {
getNewLine(): string {
return sys ? sys.newLine : newLine;
},
fileExists: fileName => hasProperty(files, fileName),
fileExists: fileName => fileName in files,
readFile: fileName => {
const file = lookUp(files, fileName);
return file && file.text;
return fileName in files ? files[fileName].text : undefined;
}
};
}
@@ -152,29 +152,29 @@ namespace ts {
return program;
}
function getSizeOfMap(map: MapLike<any>): number {
let size = 0;
for (const id in map) {
if (hasProperty(map, id)) {
size++;
function checkResolvedModule(expected: ResolvedModule, actual: ResolvedModule): boolean {
if (!expected === !actual) {
if (expected) {
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
assert.isTrue(expected.isExternalLibraryImport === actual.isExternalLibraryImport, `'isExternalLibraryImport': expected '${expected.isExternalLibraryImport}' to be equal to '${actual.isExternalLibraryImport}'`);
}
return true;
}
return size;
return false;
}
function checkResolvedModule(expected: ResolvedModule, actual: ResolvedModule): void {
assert.isTrue(actual !== undefined);
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
assert.isTrue(expected.isExternalLibraryImport === actual.isExternalLibraryImport, `'isExternalLibraryImport': expected '${expected.isExternalLibraryImport}' to be equal to '${actual.isExternalLibraryImport}'`);
function checkResolvedTypeDirective(expected: ResolvedTypeReferenceDirective, actual: ResolvedTypeReferenceDirective): boolean {
if (!expected === !actual) {
if (expected) {
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
assert.isTrue(expected.primary === actual.primary, `'primary': expected '${expected.primary}' to be equal to '${actual.primary}'`);
}
return true;
}
return false;
}
function checkResolvedTypeDirective(expected: ResolvedTypeReferenceDirective, actual: ResolvedTypeReferenceDirective): void {
assert.isTrue(actual !== undefined);
assert.isTrue(expected.resolvedFileName === actual.resolvedFileName, `'resolvedFileName': expected '${expected.resolvedFileName}' to be equal to '${actual.resolvedFileName}'`);
assert.isTrue(expected.primary === actual.primary, `'primary': expected '${expected.primary}' to be equal to '${actual.primary}'`);
}
function checkCache<T>(caption: string, program: Program, fileName: string, expectedContent: MapLike<T>, getCache: (f: SourceFile) => MapLike<T>, entryChecker: (expected: T, original: T) => void): void {
function checkCache<T>(caption: string, program: Program, fileName: string, expectedContent: Map<T>, getCache: (f: SourceFile) => Map<T>, entryChecker: (expected: T, original: T) => boolean): void {
const file = program.getSourceFile(fileName);
assert.isTrue(file !== undefined, `cannot find file ${fileName}`);
const cache = getCache(file);
@@ -183,31 +183,15 @@ namespace ts {
}
else {
assert.isTrue(cache !== undefined, `expected ${caption} to be set`);
const actualCacheSize = getSizeOfMap(cache);
const expectedSize = getSizeOfMap(expectedContent);
assert.isTrue(actualCacheSize === expectedSize, `expected actual size: ${actualCacheSize} to be equal to ${expectedSize}`);
for (const id in expectedContent) {
if (hasProperty(expectedContent, id)) {
if (expectedContent[id]) {
const expected = expectedContent[id];
const actual = cache[id];
entryChecker(expected, actual);
}
}
else {
assert.isTrue(cache[id] === undefined);
}
}
assert.isTrue(equalOwnProperties(expectedContent, cache, entryChecker), `contents of ${caption} did not match the expected contents.`);
}
}
function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: MapLike<ResolvedModule>): void {
function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: Map<ResolvedModule>): void {
checkCache("resolved modules", program, fileName, expectedContent, f => f.resolvedModules, checkResolvedModule);
}
function checkResolvedTypeDirectivesCache(program: Program, fileName: string, expectedContent: MapLike<ResolvedTypeReferenceDirective>): void {
function checkResolvedTypeDirectivesCache(program: Program, fileName: string, expectedContent: Map<ResolvedTypeReferenceDirective>): void {
checkCache("resolved type directives", program, fileName, expectedContent, f => f.resolvedTypeReferenceDirectiveNames, checkResolvedTypeDirective);
}
@@ -313,6 +297,8 @@ namespace ts {
});
it("resolution cache follows imports", () => {
(<any>Error).stackTraceLimit = Infinity;
const files = [
{ name: "a.ts", text: SourceText.New("", "import {_} from 'b'", "var x = 1") },
{ name: "b.ts", text: SourceText.New("", "", "var y = 2") },
@@ -320,7 +306,7 @@ namespace ts {
const options: CompilerOptions = { target };
const program_1 = newProgram(files, ["a.ts"], options);
checkResolvedModulesCache(program_1, "a.ts", { "b": { resolvedFileName: "b.ts" } });
checkResolvedModulesCache(program_1, "a.ts", createMap({ "b": { resolvedFileName: "b.ts" } }));
checkResolvedModulesCache(program_1, "b.ts", undefined);
const program_2 = updateProgram(program_1, ["a.ts"], options, files => {
@@ -329,7 +315,7 @@ namespace ts {
assert.isTrue(program_1.structureIsReused);
// content of resolution cache should not change
checkResolvedModulesCache(program_1, "a.ts", { "b": { resolvedFileName: "b.ts" } });
checkResolvedModulesCache(program_1, "a.ts", createMap({ "b": { resolvedFileName: "b.ts" } }));
checkResolvedModulesCache(program_1, "b.ts", undefined);
// imports has changed - program is not reused
@@ -346,7 +332,7 @@ namespace ts {
files[0].text = files[0].text.updateImportsAndExports(newImports);
});
assert.isTrue(!program_3.structureIsReused);
checkResolvedModulesCache(program_4, "a.ts", { "b": { resolvedFileName: "b.ts" }, "c": undefined });
checkResolvedModulesCache(program_4, "a.ts", createMap({ "b": { resolvedFileName: "b.ts" }, "c": undefined }));
});
it("resolved type directives cache follows type directives", () => {
@@ -357,7 +343,7 @@ namespace ts {
const options: CompilerOptions = { target, typeRoots: ["/types"] };
const program_1 = newProgram(files, ["/a.ts"], options);
checkResolvedTypeDirectivesCache(program_1, "/a.ts", { "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } });
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMap({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
checkResolvedTypeDirectivesCache(program_1, "/types/typedefs/index.d.ts", undefined);
const program_2 = updateProgram(program_1, ["/a.ts"], options, files => {
@@ -366,7 +352,7 @@ namespace ts {
assert.isTrue(program_1.structureIsReused);
// content of resolution cache should not change
checkResolvedTypeDirectivesCache(program_1, "/a.ts", { "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } });
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMap({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
checkResolvedTypeDirectivesCache(program_1, "/types/typedefs/index.d.ts", undefined);
// type reference directives has changed - program is not reused
@@ -384,7 +370,7 @@ namespace ts {
files[0].text = files[0].text.updateReferences(newReferences);
});
assert.isTrue(!program_3.structureIsReused);
checkResolvedTypeDirectivesCache(program_1, "/a.ts", { "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } });
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMap({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
});
});
+4 -4
View File
@@ -362,13 +362,13 @@ namespace ts.server {
class InProcClient {
private server: InProcSession;
private seq = 0;
private callbacks: ts.MapLike<(resp: protocol.Response) => void> = {};
private eventHandlers: ts.MapLike<(args: any) => void> = {};
private callbacks = createMap<(resp: protocol.Response) => void>();
private eventHandlers = createMap<(args: any) => void>();
handle(msg: protocol.Message): void {
if (msg.type === "response") {
const response = <protocol.Response>msg;
if (this.callbacks[response.request_seq]) {
if (response.request_seq in this.callbacks) {
this.callbacks[response.request_seq](response);
delete this.callbacks[response.request_seq];
}
@@ -380,7 +380,7 @@ namespace ts.server {
}
emit(name: string, args: any): void {
if (this.eventHandlers[name]) {
if (name in this.eventHandlers) {
this.eventHandlers[name](args);
}
}
+11 -21
View File
@@ -68,20 +68,10 @@ namespace ts {
return entry;
}
function sizeOfMap(map: MapLike<any>): number {
let n = 0;
for (const name in map) {
if (hasProperty(map, name)) {
n++;
}
}
return n;
}
function checkMapKeys(caption: string, map: MapLike<any>, expectedKeys: string[]) {
assert.equal(sizeOfMap(map), expectedKeys.length, `${caption}: incorrect size of map`);
function checkMapKeys(caption: string, map: Map<any>, expectedKeys: string[]) {
assert.equal(reduceProperties(map, count => count + 1, 0), expectedKeys.length, `${caption}: incorrect size of map`);
for (const name of expectedKeys) {
assert.isTrue(hasProperty(map, name), `${caption} is expected to contain ${name}, actual keys: ${getKeys(map)}`);
assert.isTrue(name in map, `${caption} is expected to contain ${name}, actual keys: ${Object.keys(map)}`);
}
}
@@ -126,8 +116,8 @@ namespace ts {
private getCanonicalFileName: (s: string) => string;
private toPath: (f: string) => Path;
private callbackQueue: TimeOutCallback[] = [];
readonly watchedDirectories: MapLike<{ cb: DirectoryWatcherCallback, recursive: boolean }[]> = {};
readonly watchedFiles: MapLike<FileWatcherCallback[]> = {};
readonly watchedDirectories = createMap<{ cb: DirectoryWatcherCallback, recursive: boolean }[]>();
readonly watchedFiles = createMap<FileWatcherCallback[]>();
constructor(public useCaseSensitiveFileNames: boolean, private executingFilePath: string, private currentDirectory: string, fileOrFolderList: FileOrFolder[]) {
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
@@ -208,7 +198,7 @@ namespace ts {
watchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean): DirectoryWatcher {
const path = this.toPath(directoryName);
const callbacks = lookUp(this.watchedDirectories, path) || (this.watchedDirectories[path] = []);
const callbacks = this.watchedDirectories[path] || (this.watchedDirectories[path] = []);
callbacks.push({ cb: callback, recursive });
return {
referenceCount: 0,
@@ -229,7 +219,7 @@ namespace ts {
triggerDirectoryWatcherCallback(directoryName: string, fileName: string): void {
const path = this.toPath(directoryName);
const callbacks = lookUp(this.watchedDirectories, path);
const callbacks = this.watchedDirectories[path];
if (callbacks) {
for (const callback of callbacks) {
callback.cb(fileName);
@@ -239,7 +229,7 @@ namespace ts {
triggerFileWatcherCallback(fileName: string, removed?: boolean): void {
const path = this.toPath(fileName);
const callbacks = lookUp(this.watchedFiles, path);
const callbacks = this.watchedFiles[path];
if (callbacks) {
for (const callback of callbacks) {
callback(path, removed);
@@ -249,7 +239,7 @@ namespace ts {
watchFile(fileName: string, callback: FileWatcherCallback) {
const path = this.toPath(fileName);
const callbacks = lookUp(this.watchedFiles, path) || (this.watchedFiles[path] = []);
const callbacks = this.watchedFiles[path] || (this.watchedFiles[path] = []);
callbacks.push(callback);
return {
close: () => {
@@ -594,7 +584,7 @@ namespace ts {
content: `{
"compilerOptions": {
"target": "es6"
},
},
"files": [ "main.ts" ]
}`
};
@@ -621,7 +611,7 @@ namespace ts {
content: `{
"compilerOptions": {
"target": "es6"
},
},
"files": [ "main.ts" ]
}`
};
+1 -1
View File
@@ -37,7 +37,7 @@ namespace ts.server {
}
private getLineMap(fileName: string): number[] {
let lineMap = ts.lookUp(this.lineMaps, fileName);
let lineMap = this.lineMaps[fileName];
if (!lineMap) {
const scriptSnapshot = this.host.getScriptSnapshot(fileName);
lineMap = this.lineMaps[fileName] = ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength()));
+10 -10
View File
@@ -136,9 +136,9 @@ namespace ts.server {
for (const name of names) {
// check if this is a duplicate entry in the list
let resolution = lookUp(newResolutions, name);
let resolution = newResolutions[name];
if (!resolution) {
const existingResolution = currentResolutionsInFile && ts.lookUp(currentResolutionsInFile, name);
const existingResolution = currentResolutionsInFile && currentResolutionsInFile[name];
if (moduleResolutionIsValid(existingResolution)) {
// ok, it is safe to use existing name resolution results
resolution = existingResolution;
@@ -563,7 +563,7 @@ namespace ts.server {
}
let strBuilder = "";
ts.forEachValue(this.filenameToSourceFile,
ts.forEachProperty(this.filenameToSourceFile,
sourceFile => { strBuilder += sourceFile.fileName + "\n"; });
return strBuilder;
}
@@ -857,7 +857,7 @@ namespace ts.server {
if (project.isConfiguredProject()) {
project.projectFileWatcher.close();
project.directoryWatcher.close();
forEachValue(project.directoriesWatchedForWildcards, watcher => { watcher.close(); });
forEachProperty(project.directoriesWatchedForWildcards, watcher => { watcher.close(); });
delete project.directoriesWatchedForWildcards;
this.configuredProjects = copyListRemovingItem(project, this.configuredProjects);
}
@@ -1124,7 +1124,7 @@ namespace ts.server {
getScriptInfo(filename: string) {
filename = ts.normalizePath(filename);
return ts.lookUp(this.filenameToScriptInfo, filename);
return this.filenameToScriptInfo[filename];
}
/**
@@ -1133,7 +1133,7 @@ namespace ts.server {
*/
openFile(fileName: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind) {
fileName = ts.normalizePath(fileName);
let info = ts.lookUp(this.filenameToScriptInfo, fileName);
let info = this.filenameToScriptInfo[fileName];
if (!info) {
let content: string;
if (this.host.fileExists(fileName)) {
@@ -1246,7 +1246,7 @@ namespace ts.server {
* @param filename is absolute pathname
*/
closeClientFile(filename: string) {
const info = ts.lookUp(this.filenameToScriptInfo, filename);
const info = this.filenameToScriptInfo[filename];
if (info) {
this.closeOpenFile(info);
info.isOpen = false;
@@ -1255,14 +1255,14 @@ namespace ts.server {
}
getProjectForFile(filename: string) {
const scriptInfo = ts.lookUp(this.filenameToScriptInfo, filename);
const scriptInfo = this.filenameToScriptInfo[filename];
if (scriptInfo) {
return scriptInfo.defaultProject;
}
}
printProjectsForFile(filename: string) {
const scriptInfo = ts.lookUp(this.filenameToScriptInfo, filename);
const scriptInfo = this.filenameToScriptInfo[filename];
if (scriptInfo) {
this.psLogger.startGroup();
this.psLogger.info("Projects for " + filename);
@@ -1419,7 +1419,7 @@ namespace ts.server {
/*recursive*/ true
);
project.directoriesWatchedForWildcards = reduceProperties(projectOptions.wildcardDirectories, (watchers, flag, directory) => {
project.directoriesWatchedForWildcards = reduceProperties(createMap(projectOptions.wildcardDirectories), (watchers, flag, directory) => {
if (comparePaths(configDirectoryPath, directory, ".", !this.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) {
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
this.log(`Add ${ recursive ? "recursive " : ""}watcher for: ${directory}`);
+4 -3
View File
@@ -1061,7 +1061,7 @@ namespace ts.server {
return { response, responseRequired: true };
}
private handlers: MapLike<(request: protocol.Request) => { response?: any, responseRequired?: boolean }> = {
private handlers = createMap<(request: protocol.Request) => { response?: any, responseRequired?: boolean }>({
[CommandNames.Exit]: () => {
this.exit();
return { responseRequired: false };
@@ -1198,9 +1198,10 @@ namespace ts.server {
this.reloadProjects();
return { responseRequired: false };
}
};
});
public addProtocolHandler(command: string, handler: (request: protocol.Request) => { response?: any, responseRequired: boolean }) {
if (this.handlers[command]) {
if (command in this.handlers) {
throw new Error(`Protocol handler already exists for command "${command}"`);
}
this.handlers[command] = handler;
+8 -13
View File
@@ -58,12 +58,7 @@ namespace ts.JsTyping {
if (!safeList) {
const result = readConfigFile(safeListPath, (path: string) => host.readFile(path));
if (result.config) {
safeList = result.config;
}
else {
safeList = createMap<string>();
};
safeList = createMap<string>(result.config);
}
const filesToWatch: string[] = [];
@@ -93,7 +88,7 @@ namespace ts.JsTyping {
// Add the cached typing locations for inferred typings that are already installed
for (const name in packageNameToTypingLocation) {
if (hasProperty(inferredTypings, name) && !inferredTypings[name]) {
if (name in inferredTypings && !inferredTypings[name]) {
inferredTypings[name] = packageNameToTypingLocation[name];
}
}
@@ -124,7 +119,7 @@ namespace ts.JsTyping {
}
for (const typing of typingNames) {
if (!hasProperty(inferredTypings, typing)) {
if (!(typing in inferredTypings)) {
inferredTypings[typing] = undefined;
}
}
@@ -139,16 +134,16 @@ namespace ts.JsTyping {
const jsonConfig: PackageJson = result.config;
filesToWatch.push(jsonPath);
if (jsonConfig.dependencies) {
mergeTypings(getKeys(jsonConfig.dependencies));
mergeTypings(getOwnKeys(jsonConfig.dependencies));
}
if (jsonConfig.devDependencies) {
mergeTypings(getKeys(jsonConfig.devDependencies));
mergeTypings(getOwnKeys(jsonConfig.devDependencies));
}
if (jsonConfig.optionalDependencies) {
mergeTypings(getKeys(jsonConfig.optionalDependencies));
mergeTypings(getOwnKeys(jsonConfig.optionalDependencies));
}
if (jsonConfig.peerDependencies) {
mergeTypings(getKeys(jsonConfig.peerDependencies));
mergeTypings(getOwnKeys(jsonConfig.peerDependencies));
}
}
}
@@ -167,7 +162,7 @@ namespace ts.JsTyping {
mergeTypings(cleanedTypingNames);
}
else {
mergeTypings(filter(cleanedTypingNames, f => hasProperty(safeList, f)));
mergeTypings(filter(cleanedTypingNames, f => f in safeList));
}
const hasJsxFile = forEach(fileNames, f => scriptKindIs(f, /*LanguageServiceHost*/ undefined, ScriptKind.JSX));
+1 -1
View File
@@ -15,7 +15,7 @@ namespace ts.NavigateTo {
const nameToDeclarations = sourceFile.getNamedDeclarations();
for (const name in nameToDeclarations) {
const declarations = getProperty(nameToDeclarations, name);
const declarations = nameToDeclarations[name];
if (declarations) {
// First do a quick check to see if the name of the declaration matches the
// last portion of the (possibly) dotted name they're searching for.
+1 -1
View File
@@ -243,7 +243,7 @@ namespace ts.NavigationBar {
return true;
}
const itemsWithSameName = getProperty(nameToItems, name);
const itemsWithSameName = nameToItems[name];
if (!itemsWithSameName) {
nameToItems[name] = child;
return true;
+1 -1
View File
@@ -188,7 +188,7 @@ namespace ts {
}
function getWordSpans(word: string): TextSpan[] {
if (!hasProperty(stringToWordSpans, word)) {
if (!(word in stringToWordSpans)) {
stringToWordSpans[word] = breakIntoWordSpans(word);
}
+18 -16
View File
@@ -990,7 +990,7 @@ namespace ts {
}
function getDeclarations(name: string) {
return getProperty(result, name) || (result[name] = []);
return result[name] || (result[name] = []);
}
function getDeclarationName(declaration: Declaration) {
@@ -2042,7 +2042,7 @@ namespace ts {
function fixupCompilerOptions(options: CompilerOptions, diagnostics: Diagnostic[]): CompilerOptions {
// Lazily create this value to fix module loading errors.
commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || <CommandLineOptionOfCustomType[]>filter(optionDeclarations, o =>
typeof o.type === "object" && !forEachValue(<Map<any>>o.type, v => typeof v !== "number"));
typeof o.type === "object" && !forEachProperty(o.type, v => typeof v !== "number"));
options = clone(options);
@@ -2058,7 +2058,7 @@ namespace ts {
options[opt.name] = parseCustomTypeOption(opt, value, diagnostics);
}
else {
if (!forEachValue(opt.type, v => v === value)) {
if (!forEachProperty(opt.type, v => v === value)) {
// Supplied value isn't a valid enum value.
diagnostics.push(createCompilerDiagnosticForInvalidCustomType(opt));
}
@@ -2117,7 +2117,9 @@ namespace ts {
sourceFile.moduleName = transpileOptions.moduleName;
}
sourceFile.renamedDependencies = transpileOptions.renamedDependencies;
if (transpileOptions.renamedDependencies) {
sourceFile.renamedDependencies = createMap(transpileOptions.renamedDependencies);
}
const newLine = getNewLineCharacter(options);
@@ -2251,7 +2253,7 @@ namespace ts {
}
function getBucketForCompilationSettings(key: DocumentRegistryBucketKey, createIfMissing: boolean): FileMap<DocumentRegistryEntry> {
let bucket = lookUp(buckets, key);
let bucket = buckets[key];
if (!bucket && createIfMissing) {
buckets[key] = bucket = createFileMap<DocumentRegistryEntry>();
}
@@ -2260,7 +2262,7 @@ namespace ts {
function reportStats() {
const bucketInfoArray = Object.keys(buckets).filter(name => name && name.charAt(0) === "_").map(name => {
const entries = lookUp(buckets, name);
const entries = buckets[name];
const sourceFiles: { name: string; refCount: number; references: string[]; }[] = [];
entries.forEachValue((key, entry) => {
sourceFiles.push({
@@ -3099,7 +3101,7 @@ namespace ts {
oldSettings.allowJs !== newSettings.allowJs ||
oldSettings.disableSizeLimit !== oldSettings.disableSizeLimit ||
oldSettings.baseUrl !== newSettings.baseUrl ||
!mapIsEqualTo(oldSettings.paths, newSettings.paths));
!equalOwnProperties(oldSettings.paths, newSettings.paths));
// Now create a new compiler
const compilerHost: CompilerHost = {
@@ -4114,11 +4116,11 @@ namespace ts {
existingImportsOrExports[name.text] = true;
}
if (isEmpty(existingImportsOrExports)) {
if (!someProperties(existingImportsOrExports)) {
return filter(exportsOfModule, e => e.name !== "default");
}
return filter(exportsOfModule, e => e.name !== "default" && !lookUp(existingImportsOrExports, e.name));
return filter(exportsOfModule, e => e.name !== "default" && !existingImportsOrExports[e.name]);
}
/**
@@ -4165,7 +4167,7 @@ namespace ts {
existingMemberNames[existingName] = true;
}
return filter(contextualMemberSymbols, m => !lookUp(existingMemberNames, m.name));
return filter(contextualMemberSymbols, m => !existingMemberNames[m.name]);
}
/**
@@ -4187,7 +4189,7 @@ namespace ts {
}
}
return filter(symbols, a => !lookUp(seenNames, a.name));
return filter(symbols, a => !seenNames[a.name]);
}
}
@@ -4323,7 +4325,7 @@ namespace ts {
const entry = createCompletionEntry(symbol, location, performCharacterChecks);
if (entry) {
const id = escapeIdentifier(entry.name);
if (!lookUp(uniqueNames, id)) {
if (!uniqueNames[id]) {
entries.push(entry);
uniqueNames[id] = id;
}
@@ -5151,7 +5153,7 @@ namespace ts {
// Type reference directives
const typeReferenceDirective = findReferenceInPosition(sourceFile.typeReferenceDirectives, position);
if (typeReferenceDirective) {
const referenceFile = lookUp(program.getResolvedTypeReferenceDirectives(), typeReferenceDirective.fileName);
const referenceFile = program.getResolvedTypeReferenceDirectives()[typeReferenceDirective.fileName];
if (referenceFile && referenceFile.resolvedFileName) {
return [getDefinitionInfoForFileReference(typeReferenceDirective.fileName, referenceFile.resolvedFileName)];
}
@@ -5323,7 +5325,7 @@ namespace ts {
for (const referencedSymbol of referencedSymbols) {
for (const referenceEntry of referencedSymbol.references) {
const fileName = referenceEntry.fileName;
let documentHighlights = getProperty(fileNameToDocumentHighlights, fileName);
let documentHighlights = fileNameToDocumentHighlights[fileName];
if (!documentHighlights) {
documentHighlights = { fileName, highlightSpans: [] };
@@ -6068,7 +6070,7 @@ namespace ts {
const nameTable = getNameTable(sourceFile);
if (lookUp(nameTable, internedName) !== undefined) {
if (nameTable[internedName] !== undefined) {
result = result || [];
getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex);
}
@@ -6745,7 +6747,7 @@ namespace ts {
// the function will add any found symbol of the property-name, then its sub-routine will call
// getPropertySymbolsFromBaseTypes again to walk up any base types to prevent revisiting already
// visited symbol, interface "C", the sub-routine will pass the current symbol as previousIterationSymbol.
if (hasProperty(previousIterationSymbolsCache, symbol.name)) {
if (symbol.name in previousIterationSymbolsCache) {
return;
}
+4 -4
View File
@@ -311,9 +311,9 @@ namespace ts {
// 'in' does not have this effect.
if ("getModuleResolutionsForFile" in this.shimHost) {
this.resolveModuleNames = (moduleNames: string[], containingFile: string) => {
const resolutionsInFile = <Map<string>>JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile));
const resolutionsInFile = <MapLike<string>>JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile));
return map(moduleNames, name => {
const result = lookUp(resolutionsInFile, name);
const result = getProperty(resolutionsInFile, name);
return result ? { resolvedFileName: result } : undefined;
});
};
@@ -323,8 +323,8 @@ namespace ts {
}
if ("getTypeReferenceDirectiveResolutionsForFile" in this.shimHost) {
this.resolveTypeReferenceDirectives = (typeDirectiveNames: string[], containingFile: string) => {
const typeDirectivesForFile = <Map<ResolvedTypeReferenceDirective>>JSON.parse(this.shimHost.getTypeReferenceDirectiveResolutionsForFile(containingFile));
return map(typeDirectiveNames, name => lookUp(typeDirectivesForFile, name));
const typeDirectivesForFile = <MapLike<ResolvedTypeReferenceDirective>>JSON.parse(this.shimHost.getTypeReferenceDirectiveResolutionsForFile(containingFile));
return map(typeDirectiveNames, name => getProperty(typeDirectivesForFile, name));
};
}
}
+1 -1
View File
@@ -237,7 +237,7 @@ namespace ts.SignatureHelp {
const typeChecker = program.getTypeChecker();
for (const sourceFile of program.getSourceFiles()) {
const nameToDeclarations = sourceFile.getNamedDeclarations();
const declarations = getProperty(nameToDeclarations, name.text);
const declarations = nameToDeclarations[name.text];
if (declarations) {
for (const declaration of declarations) {
+1 -2
View File
@@ -32,7 +32,7 @@
"property-declaration": "nospace",
"variable-declaration": "nospace"
}],
"next-line": [true,
"next-line": [true,
"check-catch",
"check-else"
],
@@ -44,7 +44,6 @@
"boolean-trivia": true,
"type-operator-spacing": true,
"prefer-const": true,
"no-in-operator": true,
"no-increment-decrement": true,
"object-literal-surrounding-space": true,
"no-type-assertion-whitespace": true