Merge pull request #10270 from Microsoft/optimizeMaps

Optimize performance of maps
This commit is contained in:
Anders Hejlsberg 2016-08-12 20:41:40 -07:00 committed by GitHub
commit 5bdde3b284
34 changed files with 324 additions and 337 deletions

View file

@ -69,7 +69,7 @@ function checkForUniqueCodes(messages: string[], diagnosticTable: InputDiagnosti
}
function buildUniqueNameMap(names: string[]): ts.Map<string> {
var nameMap: ts.Map<string> = {};
var nameMap = ts.createMap<string>();
var uniqueNames = NameGenerator.ensureUniqueness(names, /* isCaseSensitive */ false, /* isFixed */ undefined);

View file

@ -135,7 +135,7 @@ namespace ts {
options = opts;
languageVersion = getEmitScriptTarget(options);
inStrictMode = !!file.externalModuleIndicator;
classifiableNames = {};
classifiableNames = createMap<string>();
symbolCount = 0;
Symbol = objectAllocator.getSymbolConstructor();
@ -183,11 +183,11 @@ namespace ts {
symbol.declarations.push(node);
if (symbolFlags & SymbolFlags.HasExports && !symbol.exports) {
symbol.exports = {};
symbol.exports = createMap<Symbol>();
}
if (symbolFlags & SymbolFlags.HasMembers && !symbol.members) {
symbol.members = {};
symbol.members = createMap<Symbol>();
}
if (symbolFlags & SymbolFlags.Value) {
@ -318,9 +318,7 @@ namespace ts {
// Otherwise, we'll be merging into a compatible existing symbol (for example when
// you have multiple 'vars' with the same name in the same container). In this case
// just add this node into the declarations list of the symbol.
symbol = hasProperty(symbolTable, name)
? symbolTable[name]
: (symbolTable[name] = createSymbol(SymbolFlags.None, name));
symbol = symbolTable[name] || (symbolTable[name] = createSymbol(SymbolFlags.None, name));
if (name && (includes & SymbolFlags.Classifiable)) {
classifiableNames[name] = name;
@ -434,7 +432,7 @@ namespace ts {
if (containerFlags & ContainerFlags.IsContainer) {
container = blockScopeContainer = node;
if (containerFlags & ContainerFlags.HasLocals) {
container.locals = {};
container.locals = createMap<Symbol>();
}
addToContainerChain(container);
}
@ -1399,7 +1397,8 @@ namespace ts {
const typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type");
addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
typeLiteralSymbol.members = { [symbol.name]: symbol };
typeLiteralSymbol.members = createMap<Symbol>();
typeLiteralSymbol.members[symbol.name] = symbol;
}
function bindObjectLiteralExpression(node: ObjectLiteralExpression) {
@ -1409,7 +1408,7 @@ namespace ts {
}
if (inStrictMode) {
const seen: Map<ElementKind> = {};
const seen = createMap<ElementKind>();
for (const prop of node.properties) {
if (prop.name.kind !== SyntaxKind.Identifier) {
@ -1465,7 +1464,7 @@ namespace ts {
// fall through.
default:
if (!blockScopeContainer.locals) {
blockScopeContainer.locals = {};
blockScopeContainer.locals = createMap<Symbol>();
addToContainerChain(blockScopeContainer);
}
declareSymbol(blockScopeContainer.locals, undefined, node, symbolFlags, symbolExcludes);
@ -1924,7 +1923,7 @@ namespace ts {
}
}
file.symbol.globalExports = file.symbol.globalExports || {};
file.symbol.globalExports = file.symbol.globalExports || createMap<Symbol>();
declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
}
@ -1977,7 +1976,7 @@ namespace ts {
else {
return;
}
assignee.symbol.members = assignee.symbol.members || {};
assignee.symbol.members = assignee.symbol.members || createMap<Symbol>();
// It's acceptable for multiple 'this' assignments of the same identifier to occur
declareSymbol(assignee.symbol.members, assignee.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
}
@ -2003,7 +2002,7 @@ namespace ts {
// Set up the members collection if it doesn't exist already
if (!funcSymbol.members) {
funcSymbol.members = {};
funcSymbol.members = createMap<Symbol>();
}
// Declare the method/property
@ -2052,7 +2051,7 @@ namespace ts {
// module might have an exported variable called 'prototype'. We can't allow that as
// that would clash with the built-in 'prototype' for the class.
const prototypeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Prototype, "prototype");
if (hasProperty(symbol.exports, prototypeSymbol.name)) {
if (symbol.exports[prototypeSymbol.name]) {
if (node.name) {
node.name.parent = node;
}

View file

@ -44,7 +44,7 @@ namespace ts {
let symbolCount = 0;
const emptyArray: any[] = [];
const emptySymbols: SymbolTable = {};
const emptySymbols = createMap<Symbol>();
const compilerOptions = host.getCompilerOptions();
const languageVersion = compilerOptions.target || ScriptTarget.ES3;
@ -106,11 +106,11 @@ namespace ts {
isOptionalParameter
};
const tupleTypes: Map<TupleType> = {};
const unionTypes: Map<UnionType> = {};
const intersectionTypes: Map<IntersectionType> = {};
const stringLiteralTypes: Map<LiteralType> = {};
const numericLiteralTypes: Map<LiteralType> = {};
const tupleTypes = createMap<TupleType>();
const unionTypes = createMap<UnionType>();
const intersectionTypes = createMap<IntersectionType>();
const stringLiteralTypes = createMap<LiteralType>();
const numericLiteralTypes = createMap<LiteralType>();
const unknownSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "unknown");
const resolvingSymbol = createSymbol(SymbolFlags.Transient, "__resolving__");
@ -132,7 +132,7 @@ namespace ts {
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
const emptyGenericType = <GenericType><ObjectType>createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
emptyGenericType.instantiations = {};
emptyGenericType.instantiations = createMap<TypeReference>();
const anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
// The anyFunctionType contains the anyFunctionType by definition. The flag is further propagated
@ -146,7 +146,7 @@ namespace ts {
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
const globals: SymbolTable = {};
const globals = createMap<Symbol>();
/**
* List of every ambient module with a "*" wildcard.
* Unlike other ambient modules, these can't be stored in `globals` because symbol tables only deal with exact matches.
@ -284,7 +284,7 @@ namespace ts {
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy,
}
const typeofEQFacts: Map<TypeFacts> = {
const typeofEQFacts: MapLike<TypeFacts> = {
"string": TypeFacts.TypeofEQString,
"number": TypeFacts.TypeofEQNumber,
"boolean": TypeFacts.TypeofEQBoolean,
@ -294,7 +294,7 @@ namespace ts {
"function": TypeFacts.TypeofEQFunction
};
const typeofNEFacts: Map<TypeFacts> = {
const typeofNEFacts: MapLike<TypeFacts> = {
"string": TypeFacts.TypeofNEString,
"number": TypeFacts.TypeofNENumber,
"boolean": TypeFacts.TypeofNEBoolean,
@ -304,7 +304,7 @@ namespace ts {
"function": TypeFacts.TypeofNEFunction
};
const typeofTypesByName: Map<Type> = {
const typeofTypesByName: MapLike<Type> = {
"string": stringType,
"number": numberType,
"boolean": booleanType,
@ -314,7 +314,7 @@ namespace ts {
let jsxElementType: ObjectType;
/** Things we lazy load from the JSX namespace */
const jsxTypes: Map<ObjectType> = {};
const jsxTypes = createMap<ObjectType>();
const JsxNames = {
JSX: "JSX",
IntrinsicElements: "IntrinsicElements",
@ -325,10 +325,10 @@ namespace ts {
IntrinsicClassAttributes: "IntrinsicClassAttributes"
};
const subtypeRelation: Map<RelationComparisonResult> = {};
const assignableRelation: Map<RelationComparisonResult> = {};
const comparableRelation: Map<RelationComparisonResult> = {};
const identityRelation: Map<RelationComparisonResult> = {};
const subtypeRelation = createMap<RelationComparisonResult>();
const assignableRelation = createMap<RelationComparisonResult>();
const comparableRelation = createMap<RelationComparisonResult>();
const identityRelation = createMap<RelationComparisonResult>();
// This is for caching the result of getSymbolDisplayBuilder. Do not access directly.
let _displayBuilder: SymbolDisplayBuilder;
@ -342,9 +342,8 @@ namespace ts {
ResolvedReturnType
}
const builtinGlobals: SymbolTable = {
[undefinedSymbol.name]: undefinedSymbol
};
const builtinGlobals = createMap<Symbol>();
builtinGlobals[undefinedSymbol.name] = undefinedSymbol;
initializeTypeChecker();
@ -427,11 +426,11 @@ namespace ts {
target.declarations.push(node);
});
if (source.members) {
if (!target.members) target.members = {};
if (!target.members) target.members = createMap<Symbol>();
mergeSymbolTable(target.members, source.members);
}
if (source.exports) {
if (!target.exports) target.exports = {};
if (!target.exports) target.exports = createMap<Symbol>();
mergeSymbolTable(target.exports, source.exports);
}
recordMergedSymbol(target, source);
@ -449,28 +448,24 @@ namespace ts {
}
function cloneSymbolTable(symbolTable: SymbolTable): SymbolTable {
const result: SymbolTable = {};
const result = createMap<Symbol>();
for (const id in symbolTable) {
if (hasProperty(symbolTable, id)) {
result[id] = symbolTable[id];
}
result[id] = symbolTable[id];
}
return result;
}
function mergeSymbolTable(target: SymbolTable, source: SymbolTable) {
for (const id in source) {
if (hasProperty(source, id)) {
if (!hasProperty(target, id)) {
target[id] = source[id];
}
else {
let symbol = target[id];
if (!(symbol.flags & SymbolFlags.Merged)) {
target[id] = symbol = cloneSymbol(symbol);
}
mergeSymbol(symbol, source[id]);
let targetSymbol = target[id];
if (!targetSymbol) {
target[id] = source[id];
}
else {
if (!(targetSymbol.flags & SymbolFlags.Merged)) {
target[id] = targetSymbol = cloneSymbol(targetSymbol);
}
mergeSymbol(targetSymbol, source[id]);
}
}
}
@ -514,14 +509,12 @@ namespace ts {
function addToSymbolTable(target: SymbolTable, source: SymbolTable, message: DiagnosticMessage) {
for (const id in source) {
if (hasProperty(source, id)) {
if (hasProperty(target, id)) {
// Error on redeclarations
forEach(target[id].declarations, addDeclarationDiagnostic(id, message));
}
else {
target[id] = source[id];
}
if (target[id]) {
// Error on redeclarations
forEach(target[id].declarations, addDeclarationDiagnostic(id, message));
}
else {
target[id] = source[id];
}
}
@ -546,18 +539,20 @@ namespace ts {
}
function getSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags): Symbol {
if (meaning && hasProperty(symbols, name)) {
if (meaning) {
const symbol = symbols[name];
Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0, "Should never get an instantiated symbol here.");
if (symbol.flags & meaning) {
return symbol;
}
if (symbol.flags & SymbolFlags.Alias) {
const target = resolveAlias(symbol);
// Unknown symbol means an error occurred in alias resolution, treat it as positive answer to avoid cascading errors
if (target === unknownSymbol || target.flags & meaning) {
if (symbol) {
Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0, "Should never get an instantiated symbol here.");
if (symbol.flags & meaning) {
return symbol;
}
if (symbol.flags & SymbolFlags.Alias) {
const target = resolveAlias(symbol);
// Unknown symbol means an error occurred in alias resolution, treat it as positive answer to avoid cascading errors
if (target === unknownSymbol || target.flags & meaning) {
return symbol;
}
}
}
}
// return undefined if we can't find a symbol.
@ -745,7 +740,7 @@ namespace ts {
// 2. We check === SymbolFlags.Alias in order to check that the symbol is *purely*
// an alias. If we used &, we'd be throwing out symbols that have non alias aspects,
// which is not the desired behavior.
if (hasProperty(moduleExports, name) &&
if (moduleExports[name] &&
moduleExports[name].flags === SymbolFlags.Alias &&
getDeclarationOfKind(moduleExports[name], SyntaxKind.ExportSpecifier)) {
break;
@ -1105,9 +1100,9 @@ namespace ts {
function getExportOfModule(symbol: Symbol, name: string): Symbol {
if (symbol.flags & SymbolFlags.Module) {
const exports = getExportsOfSymbol(symbol);
if (hasProperty(exports, name)) {
return resolveSymbol(exports[name]);
const exportedSymbol = getExportsOfSymbol(symbol)[name];
if (exportedSymbol) {
return resolveSymbol(exportedSymbol);
}
}
}
@ -1425,7 +1420,7 @@ namespace ts {
*/
function extendExportSymbols(target: SymbolTable, source: SymbolTable, lookupTable?: Map<ExportCollisionTracker>, exportNode?: ExportDeclaration) {
for (const id in source) {
if (id !== "default" && !hasProperty(target, id)) {
if (id !== "default" && !target[id]) {
target[id] = source[id];
if (lookupTable && exportNode) {
lookupTable[id] = {
@ -1433,7 +1428,7 @@ namespace ts {
} as ExportCollisionTracker;
}
}
else if (lookupTable && exportNode && id !== "default" && hasProperty(target, id) && resolveSymbol(target[id]) !== resolveSymbol(source[id])) {
else if (lookupTable && exportNode && id !== "default" && target[id] && resolveSymbol(target[id]) !== resolveSymbol(source[id])) {
if (!lookupTable[id].exportsWithDuplicate) {
lookupTable[id].exportsWithDuplicate = [exportNode];
}
@ -1459,8 +1454,8 @@ namespace ts {
// All export * declarations are collected in an __export symbol by the binder
const exportStars = symbol.exports["__export"];
if (exportStars) {
const nestedSymbols: SymbolTable = {};
const lookupTable: Map<ExportCollisionTracker> = {};
const nestedSymbols = createMap<Symbol>();
const lookupTable = createMap<ExportCollisionTracker>();
for (const node of exportStars.declarations) {
const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier);
const exportedSymbols = visit(resolvedModule);
@ -1474,7 +1469,7 @@ namespace ts {
for (const id in lookupTable) {
const { exportsWithDuplicate } = lookupTable[id];
// It's not an error if the file with multiple `export *`s with duplicate names exports a member with that name itself
if (id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) || hasProperty(symbols, id)) {
if (id === "export=" || !(exportsWithDuplicate && exportsWithDuplicate.length) || symbols[id]) {
continue;
}
for (const node of exportsWithDuplicate) {
@ -1580,13 +1575,11 @@ namespace ts {
function getNamedMembers(members: SymbolTable): Symbol[] {
let result: Symbol[];
for (const id in members) {
if (hasProperty(members, id)) {
if (!isReservedMemberName(id)) {
if (!result) result = [];
const symbol = members[id];
if (symbolIsValue(symbol)) {
result.push(symbol);
}
if (!isReservedMemberName(id)) {
if (!result) result = [];
const symbol = members[id];
if (symbolIsValue(symbol)) {
result.push(symbol);
}
}
}
@ -1702,12 +1695,12 @@ namespace ts {
let qualify = false;
forEachSymbolTableInScope(enclosingDeclaration, symbolTable => {
// If symbol of this name is not available in the symbol table we are ok
if (!hasProperty(symbolTable, symbol.name)) {
let symbolFromSymbolTable = symbolTable[symbol.name];
if (!symbolFromSymbolTable) {
// Continue to the next symbol table
return false;
}
// If the symbol with this name is present it should refer to the symbol
let symbolFromSymbolTable = symbolTable[symbol.name];
if (symbolFromSymbolTable === symbol) {
// No need to qualify
return true;
@ -3125,7 +3118,7 @@ namespace ts {
// Return the type implied by an object binding pattern
function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type {
const members: SymbolTable = {};
const members = createMap<Symbol>();
let hasComputedProperties = false;
forEach(pattern.elements, e => {
const name = e.propertyName || <Identifier>e.name;
@ -3713,7 +3706,7 @@ namespace ts {
type.typeParameters = concatenate(outerTypeParameters, localTypeParameters);
type.outerTypeParameters = outerTypeParameters;
type.localTypeParameters = localTypeParameters;
(<GenericType>type).instantiations = {};
(<GenericType>type).instantiations = createMap<TypeReference>();
(<GenericType>type).instantiations[getTypeListId(type.typeParameters)] = <GenericType>type;
(<GenericType>type).target = <GenericType>type;
(<GenericType>type).typeArguments = type.typeParameters;
@ -3755,7 +3748,7 @@ namespace ts {
if (typeParameters) {
// Initialize the instantiation cache for generic type aliases. The declared type corresponds to
// an instantiation of the type alias with the type parameters supplied as type arguments.
links.instantiations = {};
links.instantiations = createMap<Type>();
links.instantiations[getTypeListId(links.typeParameters)] = type;
}
}
@ -3776,7 +3769,7 @@ namespace ts {
return expr.kind === SyntaxKind.NumericLiteral ||
expr.kind === SyntaxKind.PrefixUnaryExpression && (<PrefixUnaryExpression>expr).operator === SyntaxKind.MinusToken &&
(<PrefixUnaryExpression>expr).operand.kind === SyntaxKind.NumericLiteral ||
expr.kind === SyntaxKind.Identifier && hasProperty(symbol.exports, (<Identifier>expr).text);
expr.kind === SyntaxKind.Identifier && !!symbol.exports[(<Identifier>expr).text];
}
function enumHasLiteralMembers(symbol: Symbol) {
@ -3799,7 +3792,7 @@ namespace ts {
enumType.symbol = symbol;
if (enumHasLiteralMembers(symbol)) {
const memberTypeList: Type[] = [];
const memberTypes: Map<EnumLiteralType> = {};
const memberTypes = createMap<EnumLiteralType>();
for (const declaration of enumType.symbol.declarations) {
if (declaration.kind === SyntaxKind.EnumDeclaration) {
computeEnumMemberValues(<EnumDeclaration>declaration);
@ -3962,7 +3955,7 @@ namespace ts {
}
function createSymbolTable(symbols: Symbol[]): SymbolTable {
const result: SymbolTable = {};
const result = createMap<Symbol>();
for (const symbol of symbols) {
result[symbol.name] = symbol;
}
@ -3972,7 +3965,7 @@ namespace ts {
// The mappingThisOnly flag indicates that the only type parameter being mapped is "this". When the flag is true,
// we check symbols to see if we can quickly conclude they are free of "this" references, thus needing no instantiation.
function createInstantiatedSymbolTable(symbols: Symbol[], mapper: TypeMapper, mappingThisOnly: boolean): SymbolTable {
const result: SymbolTable = {};
const result = createMap<Symbol>();
for (const symbol of symbols) {
result[symbol.name] = mappingThisOnly && isIndependentMember(symbol) ? symbol : instantiateSymbol(symbol, mapper);
}
@ -3981,7 +3974,7 @@ namespace ts {
function addInheritedMembers(symbols: SymbolTable, baseSymbols: Symbol[]) {
for (const s of baseSymbols) {
if (!hasProperty(symbols, s.name)) {
if (!symbols[s.name]) {
symbols[s.name] = s;
}
}
@ -4098,7 +4091,7 @@ namespace ts {
}
function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable {
const members: SymbolTable = {};
const members = createMap<Symbol>();
for (let i = 0; i < memberTypes.length; i++) {
const symbol = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i);
symbol.type = memberTypes[i];
@ -4321,11 +4314,9 @@ namespace ts {
function getPropertyOfObjectType(type: Type, name: string): Symbol {
if (type.flags & TypeFlags.ObjectType) {
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
if (hasProperty(resolved.members, name)) {
const symbol = resolved.members[name];
if (symbolIsValue(symbol)) {
return symbol;
}
const symbol = resolved.members[name];
if (symbol && symbolIsValue(symbol)) {
return symbol;
}
}
}
@ -4454,13 +4445,13 @@ namespace ts {
}
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: string): Symbol {
const properties = type.resolvedProperties || (type.resolvedProperties = {});
if (hasProperty(properties, name)) {
return properties[name];
}
const property = createUnionOrIntersectionProperty(type, name);
if (property) {
properties[name] = property;
const properties = type.resolvedProperties || (type.resolvedProperties = createMap<Symbol>());
let property = properties[name];
if (!property) {
property = createUnionOrIntersectionProperty(type, name);
if (property) {
properties[name] = property;
}
}
return property;
}
@ -4477,11 +4468,9 @@ namespace ts {
type = getApparentType(type);
if (type.flags & TypeFlags.ObjectType) {
const resolved = resolveStructuredTypeMembers(type);
if (hasProperty(resolved.members, name)) {
const symbol = resolved.members[name];
if (symbolIsValue(symbol)) {
return symbol;
}
const symbol = resolved.members[name];
if (symbol && symbolIsValue(symbol)) {
return symbol;
}
if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
const symbol = getPropertyOfObjectType(globalFunctionType, name);
@ -5487,7 +5476,7 @@ namespace ts {
function getLiteralTypeForText(flags: TypeFlags, text: string) {
const map = flags & TypeFlags.StringLiteral ? stringLiteralTypes : numericLiteralTypes;
return hasProperty(map, text) ? map[text] : map[text] = createLiteralType(flags, text);
return map[text] || (map[text] = createLiteralType(flags, text));
}
function getTypeFromLiteralTypeNode(node: LiteralTypeNode): Type {
@ -6602,7 +6591,7 @@ namespace ts {
}
sourceStack[depth] = source;
targetStack[depth] = target;
maybeStack[depth] = {};
maybeStack[depth] = createMap<RelationComparisonResult>();
maybeStack[depth][id] = RelationComparisonResult.Succeeded;
depth++;
const saveExpandingFlags = expandingFlags;
@ -7243,7 +7232,7 @@ namespace ts {
}
function transformTypeOfMembers(type: Type, f: (propertyType: Type) => Type) {
const members: SymbolTable = {};
const members = createMap<Symbol>();
for (const property of getPropertiesOfObjectType(type)) {
const original = getTypeOfSymbol(property);
const updated = f(original);
@ -7467,7 +7456,7 @@ namespace ts {
let targetStack: Type[];
let depth = 0;
let inferiority = 0;
const visited: Map<boolean> = {};
const visited = createMap<boolean>();
inferFromTypes(source, target);
function isInProcess(source: Type, target: Type) {
@ -7601,7 +7590,7 @@ namespace ts {
return;
}
const key = source.id + "," + target.id;
if (hasProperty(visited, key)) {
if (visited[key]) {
return;
}
visited[key] = true;
@ -8356,7 +8345,7 @@ namespace ts {
// If we have previously computed the control flow type for the reference at
// this flow loop junction, return the cached type.
const id = getFlowNodeId(flow);
const cache = flowLoopCaches[id] || (flowLoopCaches[id] = {});
const cache = flowLoopCaches[id] || (flowLoopCaches[id] = createMap<Type>());
if (!key) {
key = getFlowCacheKey(reference);
}
@ -9951,7 +9940,7 @@ namespace ts {
// Grammar checking
checkGrammarObjectLiteralExpression(node, inDestructuringPattern);
const propertiesTable: SymbolTable = {};
const propertiesTable = createMap<Symbol>();
const propertiesArray: Symbol[] = [];
const contextualType = getApparentTypeOfContextualType(node);
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
@ -10042,7 +10031,7 @@ namespace ts {
// type with those properties for which the binding pattern specifies a default value.
if (contextualTypeHasPattern) {
for (const prop of getPropertiesOfType(contextualType)) {
if (!hasProperty(propertiesTable, prop.name)) {
if (!propertiesTable[prop.name]) {
if (!(prop.flags & SymbolFlags.Optional)) {
error(prop.valueDeclaration || (<TransientSymbol>prop).bindingElement,
Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value);
@ -10170,7 +10159,7 @@ namespace ts {
for (const prop of props) {
// Is there a corresponding property in the element attributes type? Skip checking of properties
// that have already been assigned to, as these are not actually pushed into the resulting type
if (!hasProperty(nameTable, prop.name)) {
if (!nameTable[prop.name]) {
const targetPropSym = getPropertyOfType(elementAttributesType, prop.name);
if (targetPropSym) {
const msg = chainDiagnosticMessages(undefined, Diagnostics.Property_0_of_JSX_spread_attribute_is_not_assignable_to_target_property, prop.name);
@ -10492,7 +10481,7 @@ namespace ts {
const targetAttributesType = getJsxElementAttributesType(node);
const nameTable: Map<boolean> = {};
const nameTable = createMap<boolean>();
// Process this array in right-to-left order so we know which
// attributes (mostly from spreads) are being overwritten and
// thus should have their types ignored
@ -10516,7 +10505,7 @@ namespace ts {
const targetProperties = getPropertiesOfType(targetAttributesType);
for (let i = 0; i < targetProperties.length; i++) {
if (!(targetProperties[i].flags & SymbolFlags.Optional) &&
!hasProperty(nameTable, targetProperties[i].name)) {
!nameTable[targetProperties[i].name]) {
error(node, Diagnostics.Property_0_is_missing_in_type_1, targetProperties[i].name, typeToString(targetAttributesType));
}
@ -13800,8 +13789,8 @@ namespace ts {
function checkClassForDuplicateDeclarations(node: ClassLikeDeclaration) {
const getter = 1, setter = 2, property = getter | setter;
const instanceNames: Map<number> = {};
const staticNames: Map<number> = {};
const instanceNames = createMap<number>();
const staticNames = createMap<number>();
for (const member of node.members) {
if (member.kind === SyntaxKind.Constructor) {
for (const param of (member as ConstructorDeclaration).parameters) {
@ -13834,8 +13823,8 @@ namespace ts {
}
function addName(names: Map<number>, location: Node, name: string, meaning: number) {
if (hasProperty(names, name)) {
const prev = names[name];
const prev = names[name];
if (prev) {
if (prev & meaning) {
error(location, Diagnostics.Duplicate_identifier_0, getTextOfNode(location));
}
@ -13850,7 +13839,7 @@ namespace ts {
}
function checkObjectTypeForDuplicateDeclarations(node: TypeLiteralNode | InterfaceDeclaration) {
const names: Map<boolean> = {};
const names = createMap<boolean>();
for (const member of node.members) {
if (member.kind == SyntaxKind.PropertySignature) {
let memberName: string;
@ -13864,7 +13853,7 @@ namespace ts {
continue;
}
if (hasProperty(names, memberName)) {
if (names[memberName]) {
error(member.symbol.valueDeclaration.name, Diagnostics.Duplicate_identifier_0, memberName);
error(member.name, Diagnostics.Duplicate_identifier_0, memberName);
}
@ -15076,22 +15065,20 @@ namespace ts {
function checkUnusedLocalsAndParameters(node: Node): void {
if (node.parent.kind !== SyntaxKind.InterfaceDeclaration && noUnusedIdentifiers && !isInAmbientContext(node)) {
for (const key in node.locals) {
if (hasProperty(node.locals, key)) {
const local = node.locals[key];
if (!local.isReferenced) {
if (local.valueDeclaration && local.valueDeclaration.kind === SyntaxKind.Parameter) {
const parameter = <ParameterDeclaration>local.valueDeclaration;
if (compilerOptions.noUnusedParameters &&
!isParameterPropertyDeclaration(parameter) &&
!parameterIsThisKeyword(parameter) &&
!parameterNameStartsWithUnderscore(parameter)) {
error(local.valueDeclaration.name, Diagnostics._0_is_declared_but_never_used, local.name);
}
}
else if (compilerOptions.noUnusedLocals) {
forEach(local.declarations, d => error(d.name || d, Diagnostics._0_is_declared_but_never_used, local.name));
const local = node.locals[key];
if (!local.isReferenced) {
if (local.valueDeclaration && local.valueDeclaration.kind === SyntaxKind.Parameter) {
const parameter = <ParameterDeclaration>local.valueDeclaration;
if (compilerOptions.noUnusedParameters &&
!isParameterPropertyDeclaration(parameter) &&
!parameterIsThisKeyword(parameter) &&
!parameterNameStartsWithUnderscore(parameter)) {
error(local.valueDeclaration.name, Diagnostics._0_is_declared_but_never_used, local.name);
}
}
else if (compilerOptions.noUnusedLocals) {
forEach(local.declarations, d => error(d.name || d, Diagnostics._0_is_declared_but_never_used, local.name));
}
}
}
}
@ -15148,13 +15135,11 @@ namespace ts {
function checkUnusedModuleMembers(node: ModuleDeclaration | SourceFile): void {
if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) {
for (const key in node.locals) {
if (hasProperty(node.locals, key)) {
const local = node.locals[key];
if (!local.isReferenced && !local.exportSymbol) {
for (const declaration of local.declarations) {
if (!isAmbientModule(declaration)) {
error(declaration.name, Diagnostics._0_is_declared_but_never_used, local.name);
}
const local = node.locals[key];
if (!local.isReferenced && !local.exportSymbol) {
for (const declaration of local.declarations) {
if (!isAmbientModule(declaration)) {
error(declaration.name, Diagnostics._0_is_declared_but_never_used, local.name);
}
}
}
@ -16163,7 +16148,7 @@ namespace ts {
else {
const identifierName = (<Identifier>catchClause.variableDeclaration.name).text;
const locals = catchClause.block.locals;
if (locals && hasProperty(locals, identifierName)) {
if (locals) {
const localSymbol = locals[identifierName];
if (localSymbol && (localSymbol.flags & SymbolFlags.BlockScopedVariable) !== 0) {
grammarErrorOnNode(localSymbol.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, identifierName);
@ -16584,18 +16569,18 @@ namespace ts {
return true;
}
const seen: Map<{ prop: Symbol; containingType: Type }> = {};
const seen = createMap<{ prop: Symbol; containingType: Type }>();
forEach(resolveDeclaredMembers(type).declaredProperties, p => { seen[p.name] = { prop: p, containingType: type }; });
let ok = true;
for (const base of baseTypes) {
const properties = getPropertiesOfObjectType(getTypeWithThisArgument(base, type.thisType));
for (const prop of properties) {
if (!hasProperty(seen, prop.name)) {
const existing = seen[prop.name];
if (!existing) {
seen[prop.name] = { prop: prop, containingType: base };
}
else {
const existing = seen[prop.name];
const isInheritedProperty = existing.containingType !== type;
if (isInheritedProperty && !isPropertyIdenticalTo(existing.prop, prop)) {
ok = false;
@ -17654,7 +17639,7 @@ namespace ts {
}
function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[] {
const symbols: SymbolTable = {};
const symbols = createMap<Symbol>();
let memberFlags: NodeFlags = 0;
if (isInsideWithStatementBody(location)) {
@ -17732,7 +17717,7 @@ namespace ts {
// We will copy all symbol regardless of its reserved name because
// symbolsToArray will check whether the key is a reserved name and
// it will not copy symbol with reserved name to the array
if (!hasProperty(symbols, id)) {
if (!symbols[id]) {
symbols[id] = symbol;
}
}
@ -18151,7 +18136,7 @@ namespace ts {
const propsByName = createSymbolTable(getPropertiesOfType(type));
if (getSignaturesOfType(type, SignatureKind.Call).length || getSignaturesOfType(type, SignatureKind.Construct).length) {
forEach(getPropertiesOfType(globalFunctionType), p => {
if (!hasProperty(propsByName, p.name)) {
if (!propsByName[p.name]) {
propsByName[p.name] = p;
}
});
@ -18499,7 +18484,7 @@ namespace ts {
}
function hasGlobalName(name: string): boolean {
return hasProperty(globals, name);
return !!globals[name];
}
function getReferencedValueSymbol(reference: Identifier): Symbol {
@ -18523,9 +18508,6 @@ namespace ts {
// populate reverse mapping: file path -> type reference directive that was resolved to this file
fileToDirective = createFileMap<string>();
for (const key in resolvedTypeReferenceDirectives) {
if (!hasProperty(resolvedTypeReferenceDirectives, key)) {
continue;
}
const resolvedDirective = resolvedTypeReferenceDirectives[key];
if (!resolvedDirective) {
continue;
@ -19314,7 +19296,7 @@ namespace ts {
}
function checkGrammarObjectLiteralExpression(node: ObjectLiteralExpression, inDestructuring: boolean) {
const seen: Map<SymbolFlags> = {};
const seen = createMap<SymbolFlags>();
const Property = 1;
const GetAccessor = 2;
const SetAccessor = 4;
@ -19376,7 +19358,7 @@ namespace ts {
continue;
}
if (!hasProperty(seen, effectiveName)) {
if (!seen[effectiveName]) {
seen[effectiveName] = currentKind;
}
else {
@ -19400,7 +19382,7 @@ namespace ts {
}
function checkGrammarJsxElement(node: JsxOpeningLikeElement) {
const seen: Map<boolean> = {};
const seen = createMap<boolean>();
for (const attr of node.attributes) {
if (attr.kind === SyntaxKind.JsxSpreadAttribute) {
continue;
@ -19408,7 +19390,7 @@ namespace ts {
const jsxAttr = (<JsxAttribute>attr);
const name = jsxAttr.name;
if (!hasProperty(seen, name.text)) {
if (!seen[name.text]) {
seen[name.text] = true;
}
else {

View file

@ -470,8 +470,8 @@ namespace ts {
return optionNameMapCache;
}
const optionNameMap: Map<CommandLineOption> = {};
const shortOptionNames: Map<string> = {};
const optionNameMap = createMap<CommandLineOption>();
const shortOptionNames = createMap<string>();
forEach(optionDeclarations, option => {
optionNameMap[option.name.toLowerCase()] = option;
if (option.shortName) {
@ -958,12 +958,12 @@ namespace ts {
// Literal file names (provided via the "files" array in tsconfig.json) are stored in a
// file map with a possibly case insensitive key. We use this map later when when including
// wildcard paths.
const literalFileMap: Map<string> = {};
const literalFileMap = createMap<string>();
// Wildcard paths (provided via the "includes" array in tsconfig.json) are stored in a
// file map with a possibly case insensitive key. We use this map to store paths matched
// via wildcard, and to handle extension priority.
const wildcardFileMap: Map<string> = {};
const wildcardFileMap = createMap<string>();
if (include) {
include = validateSpecs(include, errors, /*allowTrailingRecursion*/ false);
@ -1063,7 +1063,7 @@ namespace ts {
// /a/b/a?z - Watch /a/b directly to catch any new file matching a?z
const rawExcludeRegex = getRegularExpressionForWildcard(exclude, path, "exclude");
const excludeRegex = rawExcludeRegex && new RegExp(rawExcludeRegex, useCaseSensitiveFileNames ? "" : "i");
const wildcardDirectories: Map<WatchDirectoryFlags> = {};
const wildcardDirectories = createMap<WatchDirectoryFlags>();
if (include !== undefined) {
const recursiveKeys: string[] = [];
for (const file of include) {

View file

@ -19,8 +19,24 @@ namespace ts {
True = -1
}
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 */
// 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
// constantly changing shape.
map["__"] = undefined;
delete map["__"];
return map;
}
export function createFileMap<T>(keyMapper?: (key: string) => string): FileMap<T> {
let files: Map<T> = {};
let files = createMap<T>();
return {
get,
set,
@ -55,7 +71,7 @@ namespace ts {
}
function clear() {
files = {};
files = createMap<T>();
}
function toKey(path: Path): string {
@ -334,11 +350,11 @@ namespace ts {
const hasOwnProperty = Object.prototype.hasOwnProperty;
export function hasProperty<T>(map: Map<T>, key: string): boolean {
export function hasProperty<T>(map: MapLike<T>, key: string): boolean {
return hasOwnProperty.call(map, key);
}
export function getKeys<T>(map: Map<T>): string[] {
export function getKeys<T>(map: MapLike<T>): string[] {
const keys: string[] = [];
for (const key in map) {
keys.push(key);
@ -346,15 +362,15 @@ namespace ts {
return keys;
}
export function getProperty<T>(map: Map<T>, key: string): T | undefined {
export function getProperty<T>(map: MapLike<T>, key: string): T | undefined {
return hasProperty(map, key) ? map[key] : undefined;
}
export function getOrUpdateProperty<T>(map: Map<T>, key: string, makeValue: () => T): T {
export function getOrUpdateProperty<T>(map: MapLike<T>, key: string, makeValue: () => T): T {
return hasProperty(map, key) ? map[key] : map[key] = makeValue();
}
export function isEmpty<T>(map: Map<T>) {
export function isEmpty<T>(map: MapLike<T>) {
for (const id in map) {
if (hasProperty(map, id)) {
return false;
@ -371,7 +387,7 @@ namespace ts {
return <T>result;
}
export function extend<T1 extends Map<{}>, T2 extends Map<{}>>(first: T1 , second: T2): T1 & T2 {
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];
@ -384,7 +400,7 @@ namespace ts {
return result;
}
export function forEachValue<T, U>(map: Map<T>, callback: (value: T) => U): U {
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;
@ -392,7 +408,7 @@ namespace ts {
return result;
}
export function forEachKey<T, U>(map: Map<T>, callback: (key: string) => U): U {
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;
@ -400,11 +416,11 @@ namespace ts {
return result;
}
export function lookUp<T>(map: Map<T>, key: string): T {
export function lookUp<T>(map: MapLike<T>, key: string): T {
return hasProperty(map, key) ? map[key] : undefined;
}
export function copyMap<T>(source: Map<T>, target: Map<T>): void {
export function copyMap<T>(source: MapLike<T>, target: MapLike<T>): void {
for (const p in source) {
target[p] = source[p];
}
@ -421,7 +437,7 @@ namespace ts {
* 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: Map<T> = {};
const result = createMap<T>();
forEach(array, value => {
result[makeKey(value)] = value;
@ -437,7 +453,7 @@ namespace ts {
* @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 {
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) {
@ -477,9 +493,7 @@ namespace ts {
export let localizedDiagnosticMessages: Map<string> = undefined;
export function getLocaleSpecificMessage(message: DiagnosticMessage) {
return localizedDiagnosticMessages && localizedDiagnosticMessages[message.key]
? localizedDiagnosticMessages[message.key]
: message.message;
return localizedDiagnosticMessages && localizedDiagnosticMessages[message.key] || message.message;
}
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: any[]): Diagnostic;

View file

@ -269,7 +269,7 @@ namespace ts {
}
if (!usedTypeDirectiveReferences) {
usedTypeDirectiveReferences = {};
usedTypeDirectiveReferences = createMap<string>();
}
for (const directive of typeReferenceDirectives) {
if (!hasProperty(usedTypeDirectiveReferences, directive)) {

View file

@ -24,7 +24,7 @@ namespace ts {
Return = 1 << 3
}
const entities: Map<number> = {
const entities: MapLike<number> = {
"quot": 0x0022,
"amp": 0x0026,
"apos": 0x0027,
@ -489,13 +489,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function setLabeledJump(state: ConvertedLoopState, isBreak: boolean, labelText: string, labelMarker: string): void {
if (isBreak) {
if (!state.labeledNonLocalBreaks) {
state.labeledNonLocalBreaks = {};
state.labeledNonLocalBreaks = createMap<string>();
}
state.labeledNonLocalBreaks[labelText] = labelMarker;
}
else {
if (!state.labeledNonLocalContinues) {
state.labeledNonLocalContinues = {};
state.labeledNonLocalContinues = createMap<string>();
}
state.labeledNonLocalContinues[labelText] = labelMarker;
}
@ -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: Map<string>;
let renamedDependencies: MapLike<string>;
let isEs6Module: boolean;
let isCurrentFileExternalModule: boolean;
@ -577,7 +577,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
const setSourceMapWriterEmit = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? changeSourceMapEmit : function (writer: SourceMapWriter) { };
const moduleEmitDelegates: Map<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
const moduleEmitDelegates: MapLike<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
[ModuleKind.ES6]: emitES6Module,
[ModuleKind.AMD]: emitAMDModule,
[ModuleKind.System]: emitSystemModule,
@ -585,7 +585,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
[ModuleKind.CommonJS]: emitCommonJSModule,
};
const bundleEmitDelegates: Map<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
const bundleEmitDelegates: MapLike<(node: SourceFile, emitRelativePathAsModuleName?: boolean) => void> = {
[ModuleKind.ES6]() {},
[ModuleKind.AMD]: emitAMDModule,
[ModuleKind.System]: emitSystemModule,
@ -597,7 +597,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function doEmit(jsFilePath: string, sourceMapFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
generatedNameSet = {};
generatedNameSet = createMap<string>();
nodeToGeneratedName = [];
decoratedClassAliases = [];
isOwnFileEmit = !isBundledEmit;
@ -3257,7 +3257,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
// Don't initialize seen unless we have at least one element.
// Emit a comma to separate for all but the first element.
if (!seen) {
seen = {};
seen = createMap<string>();
}
else {
write(", ");
@ -3856,7 +3856,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
if (convertedLoopState) {
if (!convertedLoopState.labels) {
convertedLoopState.labels = {};
convertedLoopState.labels = createMap<string>();
}
convertedLoopState.labels[node.label.text] = node.label.text;
}
@ -6803,7 +6803,7 @@ const _super = (function (geti, seti) {
function collectExternalModuleInfo(sourceFile: SourceFile) {
externalImports = [];
exportSpecifiers = {};
exportSpecifiers = createMap<ExportSpecifier[]>();
exportEquals = undefined;
hasExportStarsToExportValues = false;
for (const node of sourceFile.statements) {
@ -7081,7 +7081,7 @@ const _super = (function (geti, seti) {
if (hoistedVars) {
writeLine();
write("var ");
const seen: Map<string> = {};
const seen = createMap<string>();
for (let i = 0; i < hoistedVars.length; i++) {
const local = hoistedVars[i];
const name = local.kind === SyntaxKind.Identifier
@ -7447,7 +7447,7 @@ const _super = (function (geti, seti) {
writeModuleName(node, emitRelativePathAsModuleName);
write("[");
const groupIndices: Map<number> = {};
const groupIndices = createMap<number>();
const dependencyGroups: DependencyGroup[] = [];
for (let i = 0; i < externalImports.length; i++) {

View file

@ -595,7 +595,7 @@ namespace ts {
parseDiagnostics = [];
parsingContext = 0;
identifiers = {};
identifiers = createMap<string>();
identifierCount = 0;
nodeCount = 0;
@ -1084,7 +1084,7 @@ namespace ts {
function internIdentifier(text: string): string {
text = escapeIdentifier(text);
return hasProperty(identifiers, text) ? identifiers[text] : (identifiers[text] = text);
return identifiers[text] || (identifiers[text] = text);
}
// An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues

View file

@ -10,8 +10,8 @@ namespace ts.performance {
/** Performance measurements for the compiler. */
declare const onProfilerEvent: { (markName: string): void; profiler: boolean; };
let profilerEvent: (markName: string) => void;
let counters: Map<number>;
let measures: Map<number>;
let counters: MapLike<number>;
let measures: MapLike<number>;
/**
* Emit a performance event if ts-profiler is connected. This is primarily used

View file

@ -843,7 +843,7 @@ namespace ts {
}
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
const existingDirectories: Map<boolean> = {};
const existingDirectories = createMap<boolean>();
function getCanonicalFileName(fileName: string): string {
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
@ -896,7 +896,7 @@ namespace ts {
function writeFileIfUpdated(fileName: string, data: string, writeByteOrderMark: boolean): void {
if (!outputFingerprints) {
outputFingerprints = {};
outputFingerprints = createMap<OutputFingerprint>();
}
const hash = sys.createHash(data);
@ -1037,7 +1037,7 @@ namespace ts {
return [];
}
const resolutions: T[] = [];
const cache: Map<T> = {};
const cache = createMap<T>();
for (const name of names) {
let result: T;
if (hasProperty(cache, name)) {
@ -1098,7 +1098,7 @@ namespace ts {
let noDiagnosticsTypeChecker: TypeChecker;
let classifiableNames: Map<string>;
let resolvedTypeReferenceDirectives: Map<ResolvedTypeReferenceDirective> = {};
let resolvedTypeReferenceDirectives = createMap<ResolvedTypeReferenceDirective>();
let fileProcessingDiagnostics = createDiagnosticCollection();
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
@ -1113,10 +1113,10 @@ namespace ts {
// If a module has some of its imports skipped due to being at the depth limit under node_modules, then track
// this, as it may be imported at a shallower depth later, and then it will need its skipped imports processed.
const modulesWithElidedImports: Map<boolean> = {};
const modulesWithElidedImports = createMap<boolean>();
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
const sourceFilesFoundSearchingNodeModules: Map<boolean> = {};
const sourceFilesFoundSearchingNodeModules = createMap<boolean>();
const start = performance.mark();
@ -1244,7 +1244,7 @@ namespace ts {
if (!classifiableNames) {
// Initialize a checker so that all our files are bound.
getTypeChecker();
classifiableNames = {};
classifiableNames = createMap<string>();
for (const sourceFile of files) {
copyMap(sourceFile.classifiableNames, classifiableNames);
@ -2085,7 +2085,7 @@ namespace ts {
function processImportedModules(file: SourceFile, basePath: string) {
collectExternalModuleReferences(file);
if (file.imports.length || file.moduleAugmentations.length) {
file.resolvedModules = {};
file.resolvedModules = createMap<ResolvedModule>();
const moduleNames = map(concatenate(file.imports, file.moduleAugmentations), getTextOfLiteral);
const resolutions = resolveModuleNamesWorker(moduleNames, getNormalizedAbsolutePath(file.fileName, currentDirectory));
for (let i = 0; i < moduleNames.length; i++) {

View file

@ -55,7 +55,7 @@ namespace ts {
tryScan<T>(callback: () => T): T;
}
const textToToken: Map<SyntaxKind> = {
const textToToken: MapLike<SyntaxKind> = {
"abstract": SyntaxKind.AbstractKeyword,
"any": SyntaxKind.AnyKeyword,
"as": SyntaxKind.AsKeyword,
@ -271,7 +271,7 @@ namespace ts {
lookupInUnicodeMap(code, unicodeES3IdentifierPart);
}
function makeReverseMap(source: Map<number>): string[] {
function makeReverseMap(source: MapLike<number>): string[] {
const result: string[] = [];
for (const name in source) {
if (source.hasOwnProperty(name)) {

View file

@ -233,15 +233,15 @@ namespace ts {
const useNonPollingWatchers = process.env["TSC_NONPOLLING_WATCHER"];
function createWatchedFileSet() {
const dirWatchers: Map<DirectoryWatcher> = {};
const dirWatchers = createMap<DirectoryWatcher>();
// One file can have multiple watchers
const fileWatcherCallbacks: Map<FileWatcherCallback[]> = {};
const fileWatcherCallbacks = createMap<FileWatcherCallback[]>();
return { addFile, removeFile };
function reduceDirWatcherRefCountForFile(fileName: string) {
const dirName = getDirectoryPath(fileName);
if (hasProperty(dirWatchers, dirName)) {
const watcher = dirWatchers[dirName];
const watcher = dirWatchers[dirName];
if (watcher) {
watcher.referenceCount -= 1;
if (watcher.referenceCount <= 0) {
watcher.close();
@ -251,13 +251,12 @@ namespace ts {
}
function addDirWatcher(dirPath: string): void {
if (hasProperty(dirWatchers, dirPath)) {
const watcher = dirWatchers[dirPath];
let watcher = dirWatchers[dirPath];
if (watcher) {
watcher.referenceCount += 1;
return;
}
const watcher: DirectoryWatcher = _fs.watch(
watcher = _fs.watch(
dirPath,
{ persistent: true },
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
@ -268,12 +267,7 @@ namespace ts {
}
function addFileWatcherCallback(filePath: string, callback: FileWatcherCallback): void {
if (hasProperty(fileWatcherCallbacks, filePath)) {
fileWatcherCallbacks[filePath].push(callback);
}
else {
fileWatcherCallbacks[filePath] = [callback];
}
(fileWatcherCallbacks[filePath] || (fileWatcherCallbacks[filePath] = [])).push(callback);
}
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
@ -289,8 +283,9 @@ namespace ts {
}
function removeFileWatcherCallback(filePath: string, callback: FileWatcherCallback) {
if (hasProperty(fileWatcherCallbacks, filePath)) {
const newCallbacks = copyListRemovingItem(callback, fileWatcherCallbacks[filePath]);
const callbacks = fileWatcherCallbacks[filePath];
if (callbacks) {
const newCallbacks = copyListRemovingItem(callback, callbacks);
if (newCallbacks.length === 0) {
delete fileWatcherCallbacks[filePath];
}
@ -306,7 +301,7 @@ namespace ts {
? undefined
: ts.getNormalizedAbsolutePath(relativeFileName, baseDirPath);
// Some applications save a working file via rename operations
if ((eventName === "change" || eventName === "rename") && hasProperty(fileWatcherCallbacks, fileName)) {
if ((eventName === "change" || eventName === "rename") && fileWatcherCallbacks[fileName]) {
for (const fileCallback of fileWatcherCallbacks[fileName]) {
fileCallback(fileName);
}

View file

@ -122,7 +122,7 @@ namespace ts {
const gutterSeparator = " ";
const resetEscapeSequence = "\u001b[0m";
const ellipsis = "...";
const categoryFormatMap: Map<string> = {
const categoryFormatMap: MapLike<string> = {
[DiagnosticCategory.Warning]: yellowForegroundEscapeSequence,
[DiagnosticCategory.Error]: redForegroundEscapeSequence,
[DiagnosticCategory.Message]: blueForegroundEscapeSequence,
@ -432,7 +432,7 @@ namespace ts {
}
// reset the cache of existing files
cachedExistingFiles = {};
cachedExistingFiles = createMap<boolean>();
const compileResult = compile(rootFileNames, compilerOptions, compilerHost);
@ -676,7 +676,7 @@ namespace ts {
const usageColumn: string[] = []; // Things like "-d, --declaration" go in here.
const descriptionColumn: string[] = [];
const optionsDescriptionMap: Map<string[]> = {}; // Map between option.description and list of option.type if it is a kind
const optionsDescriptionMap = createMap<string[]>(); // Map between option.description and list of option.type if it is a kind
for (let i = 0; i < optsList.length; i++) {
const option = optsList[i];
@ -786,7 +786,7 @@ namespace ts {
return;
function serializeCompilerOptions(options: CompilerOptions): Map<string | number | boolean> {
const result: Map<string | number | boolean> = {};
const result = createMap<string | number | boolean>();
const optionsNameMap = getOptionNameMap().optionNameMap;
for (const name in options) {

View file

@ -1,9 +1,13 @@
namespace ts {
export interface Map<T> {
export interface MapLike<T> {
[index: string]: T;
}
export interface Map<T> extends MapLike<T> {
__mapBrand: any;
}
// branded string type used to store absolute, normalized and canonicalized paths
// arbitrary file name can be converted to Path via toPath function
export type Path = string & { __pathBrand: any };
@ -1646,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?: Map<string>;
renamedDependencies?: MapLike<string>;
/**
* lib.d.ts should have a reference comment like
@ -2178,9 +2182,7 @@ namespace ts {
/* @internal */
export interface TransientSymbol extends Symbol, SymbolLinks { }
export interface SymbolTable {
[index: string]: Symbol;
}
export type SymbolTable = Map<Symbol>;
/** Represents a "prefix*suffix" pattern. */
/* @internal */
@ -2564,7 +2566,7 @@ namespace ts {
}
export type RootPaths = string[];
export type PathSubstitutions = Map<string[]>;
export type PathSubstitutions = MapLike<string[]>;
export type TsConfigOnlyOptions = RootPaths | PathSubstitutions;
export type CompilerOptionsValue = string | number | boolean | (string | number)[] | TsConfigOnlyOptions;
@ -2724,7 +2726,7 @@ namespace ts {
fileNames: string[];
raw?: any;
errors: Diagnostic[];
wildcardDirectories?: Map<WatchDirectoryFlags>;
wildcardDirectories?: MapLike<WatchDirectoryFlags>;
}
export const enum WatchDirectoryFlags {
@ -2734,13 +2736,13 @@ namespace ts {
export interface ExpandResult {
fileNames: string[];
wildcardDirectories: Map<WatchDirectoryFlags>;
wildcardDirectories: MapLike<WatchDirectoryFlags>;
}
/* @internal */
export interface CommandLineOptionBase {
name: string;
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
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
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
@ -2756,7 +2758,7 @@ namespace ts {
/* @internal */
export interface CommandLineOptionOfCustomType extends CommandLineOptionBase {
type: Map<number | string>; // an object literal mapping named values to actual values
type: MapLike<number | string>; // an object literal mapping named values to actual values
}
/* @internal */

View file

@ -87,14 +87,14 @@ namespace ts {
return node.end - node.pos;
}
export function mapIsEqualTo<T>(map1: Map<T>, map2: Map<T>): boolean {
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: Map<T>, other: Map<T>): boolean {
function containsAll<T>(map: MapLike<T>, other: MapLike<T>): boolean {
for (const key in map) {
if (!hasProperty(map, key)) {
continue;
@ -126,7 +126,7 @@ namespace ts {
}
export function hasResolvedModule(sourceFile: SourceFile, moduleNameText: string): boolean {
return sourceFile.resolvedModules && hasProperty(sourceFile.resolvedModules, moduleNameText);
return !!(sourceFile.resolvedModules && sourceFile.resolvedModules[moduleNameText]);
}
export function getResolvedModule(sourceFile: SourceFile, moduleNameText: string): ResolvedModule {
@ -135,7 +135,7 @@ namespace ts {
export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModule): void {
if (!sourceFile.resolvedModules) {
sourceFile.resolvedModules = {};
sourceFile.resolvedModules = createMap<ResolvedModule>();
}
sourceFile.resolvedModules[moduleNameText] = resolvedModule;
@ -143,7 +143,7 @@ namespace ts {
export function setResolvedTypeReferenceDirective(sourceFile: SourceFile, typeReferenceDirectiveName: string, resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective): void {
if (!sourceFile.resolvedTypeReferenceDirectiveNames) {
sourceFile.resolvedTypeReferenceDirectiveNames = {};
sourceFile.resolvedTypeReferenceDirectiveNames = createMap<ResolvedTypeReferenceDirective>();
}
sourceFile.resolvedTypeReferenceDirectiveNames[typeReferenceDirectiveName] = resolvedTypeReferenceDirective;
@ -166,7 +166,7 @@ namespace ts {
}
for (let i = 0; i < names.length; i++) {
const newResolution = newResolutions[i];
const oldResolution = oldResolutions && hasProperty(oldResolutions, names[i]) ? oldResolutions[names[i]] : undefined;
const oldResolution = oldResolutions && oldResolutions[names[i]];
const changed =
oldResolution
? !newResolution || !comparer(oldResolution, newResolution)
@ -1970,7 +1970,7 @@ namespace ts {
export function createDiagnosticCollection(): DiagnosticCollection {
let nonFileDiagnostics: Diagnostic[] = [];
const fileDiagnostics: Map<Diagnostic[]> = {};
const fileDiagnostics = createMap<Diagnostic[]>();
let diagnosticsModified = false;
let modificationCount = 0;
@ -1988,12 +1988,11 @@ namespace ts {
}
function reattachFileDiagnostics(newFile: SourceFile): void {
if (!hasProperty(fileDiagnostics, newFile.fileName)) {
return;
}
for (const diagnostic of fileDiagnostics[newFile.fileName]) {
diagnostic.file = newFile;
const diagnostics = fileDiagnostics[newFile.fileName];
if (diagnostics) {
for (const diagnostic of diagnostics) {
diagnostic.file = newFile;
}
}
}
@ -2034,9 +2033,7 @@ namespace ts {
forEach(nonFileDiagnostics, pushDiagnostic);
for (const key in fileDiagnostics) {
if (hasProperty(fileDiagnostics, key)) {
forEach(fileDiagnostics[key], pushDiagnostic);
}
forEach(fileDiagnostics[key], pushDiagnostic);
}
return sortAndDeduplicateDiagnostics(allDiagnostics);
@ -2051,9 +2048,7 @@ namespace ts {
nonFileDiagnostics = sortAndDeduplicateDiagnostics(nonFileDiagnostics);
for (const key in fileDiagnostics) {
if (hasProperty(fileDiagnostics, key)) {
fileDiagnostics[key] = sortAndDeduplicateDiagnostics(fileDiagnostics[key]);
}
fileDiagnostics[key] = sortAndDeduplicateDiagnostics(fileDiagnostics[key]);
}
}
}
@ -2064,7 +2059,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: Map<string> = {
const escapedCharsMap: MapLike<string> = {
"\0": "\\0",
"\t": "\\t",
"\v": "\\v",

View file

@ -291,8 +291,8 @@ class CompilerBaselineRunner extends RunnerBase {
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
const fullResults: ts.Map<TypeWriterResult[]> = {};
const pullResults: ts.Map<TypeWriterResult[]> = {};
const fullResults: ts.MapLike<TypeWriterResult[]> = {};
const pullResults: ts.MapLike<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.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
function generateBaseLine(typeWriterResults: ts.MapLike<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
const typeLines: string[] = [];
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};

View file

@ -95,7 +95,7 @@ namespace FourSlash {
export import IndentStyle = ts.IndentStyle;
const entityMap: ts.Map<string> = {
const entityMap: ts.MapLike<string> = {
"&": "&amp;",
"\"": "&quot;",
"'": "&#39;",
@ -204,7 +204,7 @@ namespace FourSlash {
public formatCodeOptions: ts.FormatCodeOptions;
private inputFiles: ts.Map<string> = {}; // Map between inputFile's fileName and its content for easily looking up when resolving references
private inputFiles: ts.MapLike<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
@ -594,7 +594,7 @@ namespace FourSlash {
public noItemsWithSameNameButDifferentKind(): void {
const completions = this.getCompletionListAtCaret();
const uniqueItems: ts.Map<string> = {};
const uniqueItems: ts.MapLike<string> = {};
for (const item of completions.entries) {
if (!ts.hasProperty(uniqueItems, item.name)) {
uniqueItems[item.name] = item.kind;
@ -1631,8 +1631,8 @@ namespace FourSlash {
return this.testData.ranges;
}
public rangesByText(): ts.Map<Range[]> {
const result: ts.Map<Range[]> = {};
public rangesByText(): ts.MapLike<Range[]> {
const result: ts.MapLike<Range[]> = {};
for (const range of this.getRanges()) {
const text = this.rangeText(range);
(ts.getProperty(result, text) || (result[text] = [])).push(range);
@ -1890,7 +1890,7 @@ namespace FourSlash {
public verifyBraceCompletionAtPosition(negative: boolean, openingBrace: string) {
const openBraceMap: ts.Map<ts.CharacterCodes> = {
const openBraceMap: ts.MapLike<ts.CharacterCodes> = {
"(": ts.CharacterCodes.openParen,
"{": ts.CharacterCodes.openBrace,
"[": ts.CharacterCodes.openBracket,
@ -2738,7 +2738,7 @@ namespace FourSlashInterface {
return this.state.getRanges();
}
public rangesByText(): ts.Map<FourSlash.Range[]> {
public rangesByText(): ts.MapLike<FourSlash.Range[]> {
return this.state.rangesByText();
}

View file

@ -848,7 +848,7 @@ namespace Harness {
export const defaultLibFileName = "lib.d.ts";
export const es2015DefaultLibFileName = "lib.es2015.d.ts";
const libFileNameSourceFileMap: ts.Map<ts.SourceFile> = {
const libFileNameSourceFileMap: ts.MapLike<ts.SourceFile> = {
[defaultLibFileName]: createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.es5.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest)
};
@ -1002,7 +1002,7 @@ namespace Harness {
{ name: "symlink", type: "string" }
];
let optionsIndex: ts.Map<ts.CommandLineOption>;
let optionsIndex: ts.MapLike<ts.CommandLineOption>;
function getCommandLineOption(name: string): ts.CommandLineOption {
if (!optionsIndex) {
optionsIndex = {};

View file

@ -123,7 +123,7 @@ namespace Harness.LanguageService {
}
export class LanguageServiceAdapterHost {
protected fileNameToScript: ts.Map<ScriptInfo> = {};
protected fileNameToScript: ts.MapLike<ScriptInfo> = {};
constructor(protected cancellationToken = DefaultHostCancellationToken.Instance,
protected settings = ts.getDefaultCompilerOptions()) {
@ -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.Map<string> = {};
const imports: ts.MapLike<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.Map<ts.ResolvedTypeReferenceDirective> = {};
const resolutions: ts.MapLike<ts.ResolvedTypeReferenceDirective> = {};
const settings = this.nativeHost.getCompilationSettings();
for (const typeReferenceDirective of preprocessInfo.typeReferenceDirectives) {
const resolutionInfo = ts.resolveTypeReferenceDirective(typeReferenceDirective.fileName, fileName, settings, moduleResolutionHost);

View file

@ -253,7 +253,7 @@ 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.Map<ts.CommandLineOption> = {};
const optionNameMap: ts.MapLike<ts.CommandLineOption> = {};
ts.forEach(ts.optionDeclarations, option => {
optionNameMap[option.name] = option;
});

View file

@ -6,8 +6,8 @@ namespace ts {
content: string;
}
function createDefaultServerHost(fileMap: Map<File>): server.ServerHost {
const existingDirectories: Map<boolean> = {};
function createDefaultServerHost(fileMap: MapLike<File>): server.ServerHost {
const existingDirectories: MapLike<boolean> = {};
forEachValue(fileMap, v => {
let dir = getDirectoryPath(v.name);
let previous: string;
@ -193,7 +193,7 @@ namespace ts {
content: `export var y = 1`
};
const fileMap: Map<File> = { [root.name]: root };
const fileMap: MapLike<File> = { [root.name]: root };
const serverHost = createDefaultServerHost(fileMap);
const originalFileExists = serverHost.fileExists;

View file

@ -10,7 +10,7 @@ namespace ts {
const map = arrayToMap(files, f => f.name);
if (hasDirectoryExists) {
const directories: Map<string> = {};
const directories: MapLike<string> = {};
for (const f of files) {
let name = getDirectoryPath(f.name);
while (true) {
@ -282,7 +282,7 @@ namespace ts {
});
describe("Module resolution - relative imports", () => {
function test(files: Map<string>, currentDirectory: string, rootFiles: string[], expectedFilesCount: number, relativeNamesToCheck: string[]) {
function test(files: MapLike<string>, currentDirectory: string, rootFiles: string[], expectedFilesCount: number, relativeNamesToCheck: string[]) {
const options: CompilerOptions = { module: ModuleKind.CommonJS };
const host: CompilerHost = {
getSourceFile: (fileName: string, languageVersion: ScriptTarget) => {
@ -318,7 +318,7 @@ namespace ts {
}
it("should find all modules", () => {
const files: Map<string> = {
const files: MapLike<string> = {
"/a/b/c/first/shared.ts": `
class A {}
export = A`,
@ -337,7 +337,7 @@ export = C;
});
it("should find modules in node_modules", () => {
const files: Map<string> = {
const files: MapLike<string> = {
"/parent/node_modules/mod/index.d.ts": "export var x",
"/parent/app/myapp.ts": `import {x} from "mod"`
};
@ -345,7 +345,7 @@ export = C;
});
it("should find file referenced via absolute and relative names", () => {
const files: Map<string> = {
const files: MapLike<string> = {
"/a/b/c.ts": `/// <reference path="b.ts"/>`,
"/a/b/b.ts": "var x"
};
@ -355,10 +355,10 @@ export = C;
describe("Files with different casing", () => {
const library = createSourceFile("lib.d.ts", "", ScriptTarget.ES5);
function test(files: Map<string>, options: CompilerOptions, currentDirectory: string, useCaseSensitiveFileNames: boolean, rootFiles: string[], diagnosticCodes: number[]): void {
function test(files: MapLike<string>, options: CompilerOptions, currentDirectory: string, useCaseSensitiveFileNames: boolean, rootFiles: string[], diagnosticCodes: number[]): void {
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
if (!useCaseSensitiveFileNames) {
const f: Map<string> = {};
const f: MapLike<string> = {};
for (const fileName in files) {
f[getCanonicalFileName(fileName)] = files[fileName];
}
@ -395,7 +395,7 @@ export = C;
}
it("should succeed when the same file is referenced using absolute and relative names", () => {
const files: Map<string> = {
const files: MapLike<string> = {
"/a/b/c.ts": `/// <reference path="d.ts"/>`,
"/a/b/d.ts": "var x"
};
@ -403,7 +403,7 @@ export = C;
});
it("should fail when two files used in program differ only in casing (tripleslash references)", () => {
const files: Map<string> = {
const files: MapLike<string> = {
"/a/b/c.ts": `/// <reference path="D.ts"/>`,
"/a/b/d.ts": "var x"
};
@ -411,7 +411,7 @@ export = C;
});
it("should fail when two files used in program differ only in casing (imports)", () => {
const files: Map<string> = {
const files: MapLike<string> = {
"/a/b/c.ts": `import {x} from "D"`,
"/a/b/d.ts": "export var x"
};
@ -419,7 +419,7 @@ export = C;
});
it("should fail when two files used in program differ only in casing (imports, relative module names)", () => {
const files: Map<string> = {
const files: MapLike<string> = {
"moduleA.ts": `import {x} from "./ModuleB"`,
"moduleB.ts": "export var x"
};
@ -427,7 +427,7 @@ export = C;
});
it("should fail when two files exist on disk that differs only in casing", () => {
const files: Map<string> = {
const files: MapLike<string> = {
"/a/b/c.ts": `import {x} from "D"`,
"/a/b/D.ts": "export var x",
"/a/b/d.ts": "export var y"
@ -436,7 +436,7 @@ export = C;
});
it("should fail when module name in 'require' calls has inconsistent casing", () => {
const files: Map<string> = {
const files: MapLike<string> = {
"moduleA.ts": `import a = require("./ModuleC")`,
"moduleB.ts": `import a = require("./moduleC")`,
"moduleC.ts": "export var x"
@ -445,7 +445,7 @@ export = C;
});
it("should fail when module names in 'require' calls has inconsistent casing and current directory has uppercase chars", () => {
const files: Map<string> = {
const files: MapLike<string> = {
"/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",
@ -457,7 +457,7 @@ 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: Map<string> = {
const files: MapLike<string> = {
"/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",

View file

@ -96,7 +96,7 @@ namespace ts {
}
function createTestCompilerHost(texts: NamedSourceText[], target: ScriptTarget): CompilerHost {
const files: Map<SourceFileWithText> = {};
const files: MapLike<SourceFileWithText> = {};
for (const t of texts) {
const file = <SourceFileWithText>createSourceFile(t.name, t.text.getFullText(), target);
file.sourceText = t.text;
@ -152,7 +152,7 @@ namespace ts {
return program;
}
function getSizeOfMap(map: Map<any>): number {
function getSizeOfMap(map: MapLike<any>): number {
let size = 0;
for (const id in map) {
if (hasProperty(map, id)) {
@ -174,7 +174,7 @@ namespace ts {
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: Map<T>, getCache: (f: SourceFile) => Map<T>, entryChecker: (expected: T, original: T) => void): void {
function checkCache<T>(caption: string, program: Program, fileName: string, expectedContent: MapLike<T>, getCache: (f: SourceFile) => MapLike<T>, entryChecker: (expected: T, original: T) => void): void {
const file = program.getSourceFile(fileName);
assert.isTrue(file !== undefined, `cannot find file ${fileName}`);
const cache = getCache(file);
@ -203,11 +203,11 @@ namespace ts {
}
}
function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: Map<ResolvedModule>): void {
function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: MapLike<ResolvedModule>): void {
checkCache("resolved modules", program, fileName, expectedContent, f => f.resolvedModules, checkResolvedModule);
}
function checkResolvedTypeDirectivesCache(program: Program, fileName: string, expectedContent: Map<ResolvedTypeReferenceDirective>): void {
function checkResolvedTypeDirectivesCache(program: Program, fileName: string, expectedContent: MapLike<ResolvedTypeReferenceDirective>): void {
checkCache("resolved type directives", program, fileName, expectedContent, f => f.resolvedTypeReferenceDirectiveNames, checkResolvedTypeDirective);
}

View file

@ -362,8 +362,8 @@ namespace ts.server {
class InProcClient {
private server: InProcSession;
private seq = 0;
private callbacks: ts.Map<(resp: protocol.Response) => void> = {};
private eventHandlers: ts.Map<(args: any) => void> = {};
private callbacks: ts.MapLike<(resp: protocol.Response) => void> = {};
private eventHandlers: ts.MapLike<(args: any) => void> = {};
handle(msg: protocol.Message): void {
if (msg.type === "response") {

View file

@ -68,7 +68,7 @@ namespace ts {
return entry;
}
function sizeOfMap(map: Map<any>): number {
function sizeOfMap(map: MapLike<any>): number {
let n = 0;
for (const name in map) {
if (hasProperty(map, name)) {
@ -78,7 +78,7 @@ namespace ts {
return n;
}
function checkMapKeys(caption: string, map: Map<any>, expectedKeys: string[]) {
function checkMapKeys(caption: string, map: MapLike<any>, expectedKeys: string[]) {
assert.equal(sizeOfMap(map), 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)}`);
@ -126,8 +126,8 @@ namespace ts {
private getCanonicalFileName: (s: string) => string;
private toPath: (f: string) => Path;
private callbackQueue: TimeOutCallback[] = [];
readonly watchedDirectories: Map<{ cb: DirectoryWatcherCallback, recursive: boolean }[]> = {};
readonly watchedFiles: Map<FileWatcherCallback[]> = {};
readonly watchedDirectories: MapLike<{ cb: DirectoryWatcherCallback, recursive: boolean }[]> = {};
readonly watchedFiles: MapLike<FileWatcherCallback[]> = {};
constructor(public useCaseSensitiveFileNames: boolean, private executingFilePath: string, private currentDirectory: string, fileOrFolderList: FileOrFolder[]) {
this.getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);

View file

@ -21,7 +21,7 @@ namespace ts.server {
export class SessionClient implements LanguageService {
private sequence: number = 0;
private lineMaps: ts.Map<number[]> = {};
private lineMaps: ts.Map<number[]> = ts.createMap<number[]>();
private messages: string[] = [];
private lastRenameEntry: RenameEntry;

View file

@ -130,7 +130,7 @@ namespace ts.server {
const path = toPath(containingFile, this.host.getCurrentDirectory(), this.getCanonicalFileName);
const currentResolutionsInFile = cache.get(path);
const newResolutions: Map<T> = {};
const newResolutions = createMap<T>();
const resolvedModules: R[] = [];
const compilerOptions = this.getCompilationSettings();
@ -378,7 +378,7 @@ namespace ts.server {
export interface ProjectOptions {
// these fields can be present in the project file
files?: string[];
wildcardDirectories?: ts.Map<ts.WatchDirectoryFlags>;
wildcardDirectories?: ts.MapLike<ts.WatchDirectoryFlags>;
compilerOptions?: ts.CompilerOptions;
}
@ -391,7 +391,7 @@ namespace ts.server {
// Used to keep track of what directories are watched for this project
directoriesWatchedForTsconfig: string[] = [];
program: ts.Program;
filenameToSourceFile: ts.Map<ts.SourceFile> = {};
filenameToSourceFile = ts.createMap<ts.SourceFile>();
updateGraphSeq = 0;
/** Used for configured projects which may have multiple open roots */
openRefCount = 0;
@ -504,7 +504,7 @@ namespace ts.server {
return;
}
this.filenameToSourceFile = {};
this.filenameToSourceFile = createMap<SourceFile>();
const sourceFiles = this.program.getSourceFiles();
for (let i = 0, len = sourceFiles.length; i < len; i++) {
const normFilename = ts.normalizePath(sourceFiles[i].fileName);
@ -613,7 +613,7 @@ namespace ts.server {
}
export class ProjectService {
filenameToScriptInfo: ts.Map<ScriptInfo> = {};
filenameToScriptInfo = ts.createMap<ScriptInfo>();
// open, non-configured root files
openFileRoots: ScriptInfo[] = [];
// projects built from openFileRoots
@ -625,12 +625,12 @@ namespace ts.server {
// open files that are roots of a configured project
openFileRootsConfigured: ScriptInfo[] = [];
// a path to directory watcher map that detects added tsconfig files
directoryWatchersForTsconfig: ts.Map<FileWatcher> = {};
directoryWatchersForTsconfig = ts.createMap<FileWatcher>();
// count of how many projects are using the directory watcher. If the
// number becomes 0 for a watcher, then we should close it.
directoryWatchersRefCount: ts.Map<number> = {};
directoryWatchersRefCount = ts.createMap<number>();
hostConfiguration: HostConfiguration;
timerForDetectingProjectFileListChanges: Map<any> = {};
timerForDetectingProjectFileListChanges = createMap<any>();
constructor(public host: ServerHost, public psLogger: Logger, public eventHandler?: ProjectServiceEventHandler) {
// ts.disableIncrementalParsing = true;

View file

@ -1061,7 +1061,7 @@ namespace ts.server {
return { response, responseRequired: true };
}
private handlers: Map<(request: protocol.Request) => { response?: any, responseRequired?: boolean }> = {
private handlers: MapLike<(request: protocol.Request) => { response?: any, responseRequired?: boolean }> = {
[CommandNames.Exit]: () => {
this.exit();
return { responseRequired: false };

View file

@ -47,7 +47,7 @@ namespace ts.JsTyping {
{ cachedTypingPaths: string[], newTypingNames: string[], filesToWatch: string[] } {
// A typing name to typing file path mapping
const inferredTypings: Map<string> = {};
const inferredTypings = createMap<string>();
if (!typingOptions || !typingOptions.enableAutoDiscovery) {
return { cachedTypingPaths: [], newTypingNames: [], filesToWatch: [] };
@ -62,7 +62,7 @@ namespace ts.JsTyping {
safeList = result.config;
}
else {
safeList = {};
safeList = createMap<string>();
};
}

View file

@ -234,7 +234,7 @@ namespace ts.NavigationBar {
/** Merge declarations of the same kind. */
function mergeChildren(children: NavigationBarNode[]): void {
const nameToItems: Map<NavigationBarNode | NavigationBarNode[]> = {};
const nameToItems = createMap<NavigationBarNode | NavigationBarNode[]>();
filterMutate(children, child => {
const decl = <Declaration>child.node;
const name = decl.name && nodeText(decl.name);

View file

@ -113,7 +113,7 @@ namespace ts {
// we see the name of a module that is used everywhere, or the name of an overload). As
// such, we cache the information we compute about the candidate for the life of this
// pattern matcher so we don't have to compute it multiple times.
const stringToWordSpans: Map<TextSpan[]> = {};
const stringToWordSpans = createMap<TextSpan[]>();
pattern = pattern.trim();

View file

@ -975,7 +975,7 @@ namespace ts {
}
private computeNamedDeclarations(): Map<Declaration[]> {
const result: Map<Declaration[]> = {};
const result = createMap<Declaration[]>();
forEachChild(this, visit);
@ -2025,7 +2025,7 @@ namespace ts {
fileName?: string;
reportDiagnostics?: boolean;
moduleName?: string;
renamedDependencies?: Map<string>;
renamedDependencies?: MapLike<string>;
}
export interface TranspileOutput {
@ -2243,7 +2243,7 @@ namespace ts {
export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory = ""): DocumentRegistry {
// Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have
// for those settings.
const buckets: Map<FileMap<DocumentRegistryEntry>> = {};
const buckets = createMap<FileMap<DocumentRegistryEntry>>();
const getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames);
function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey {
@ -4102,7 +4102,7 @@ namespace ts {
* do not occur at the current position and have not otherwise been typed.
*/
function filterNamedImportOrExportCompletionItems(exportsOfModule: Symbol[], namedImportsOrExports: ImportOrExportSpecifier[]): Symbol[] {
const existingImportsOrExports: Map<boolean> = {};
const existingImportsOrExports = createMap<boolean>();
for (const element of namedImportsOrExports) {
// If this is the current item we are editing right now, do not filter it out
@ -4132,7 +4132,7 @@ namespace ts {
return contextualMemberSymbols;
}
const existingMemberNames: Map<boolean> = {};
const existingMemberNames = createMap<boolean>();
for (const m of existingMembers) {
// Ignore omitted expressions for missing members
if (m.kind !== SyntaxKind.PropertyAssignment &&
@ -4175,7 +4175,7 @@ namespace ts {
* do not occur at the current position and have not otherwise been typed.
*/
function filterJsxAttributes(symbols: Symbol[], attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>): Symbol[] {
const seenNames: Map<boolean> = {};
const seenNames = createMap<boolean>();
for (const attr of attributes) {
// If this is the current item we are editing right now, do not filter it out
if (attr.getStart() <= position && position <= attr.getEnd()) {
@ -4317,7 +4317,7 @@ namespace ts {
function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map<string> {
const start = timestamp();
const uniqueNames: Map<string> = {};
const uniqueNames = createMap<string>();
if (symbols) {
for (const symbol of symbols) {
const entry = createCompletionEntry(symbol, location, performCharacterChecks);
@ -5318,7 +5318,7 @@ namespace ts {
return undefined;
}
const fileNameToDocumentHighlights: Map<DocumentHighlights> = {};
const fileNameToDocumentHighlights = createMap<DocumentHighlights>();
const result: DocumentHighlights[] = [];
for (const referencedSymbol of referencedSymbols) {
for (const referenceEntry of referencedSymbol.references) {
@ -6713,7 +6713,7 @@ namespace ts {
// Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ {});
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>());
}
});
@ -6834,7 +6834,7 @@ namespace ts {
// see if any is in the list
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
const result: Symbol[] = [];
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ {});
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>());
return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
}
@ -8318,7 +8318,7 @@ namespace ts {
}
function initializeNameTable(sourceFile: SourceFile): void {
const nameTable: Map<number> = {};
const nameTable = createMap<number>();
walk(sourceFile);
sourceFile.nameTable = nameTable;

View file

@ -20,7 +20,7 @@ declare var path: any;
import * as ts from "typescript";
function watch(rootFileNames: string[], options: ts.CompilerOptions) {
const files: ts.Map<{ version: number }> = {};
const files: ts.MapLike<{ version: number }> = {};
// initialize the list of files
rootFileNames.forEach(fileName => {

View file

@ -23,7 +23,7 @@ declare var path: any;
import * as ts from "typescript";
function watch(rootFileNames: string[], options: ts.CompilerOptions) {
const files: ts.Map<{ version: number }> = {};
const files: ts.MapLike<{ version: number }> = {};
// initialize the list of files
rootFileNames.forEach(fileName => {