Use native maps when they're available

This commit is contained in:
Andy Hanson 2016-09-26 11:33:25 -07:00
parent 3212e25a3a
commit aadcbcc083
66 changed files with 1678 additions and 1326 deletions

View File

@ -57,6 +57,7 @@ function measure(marker) {
}
var compilerSources = [
"dataStructures.ts",
"core.ts",
"performance.ts",
"sys.ts",
@ -91,6 +92,7 @@ var compilerSources = [
});
var servicesSources = [
"dataStructures.ts",
"core.ts",
"performance.ts",
"sys.ts",

View File

@ -27,7 +27,7 @@ function main(): void {
var inputFilePath = sys.args[0].replace(/\\/g, "/");
var inputStr = sys.readFile(inputFilePath);
var diagnosticMessages: InputDiagnosticMessageTable = JSON.parse(inputStr);
var names = Utilities.getObjectKeys(diagnosticMessages);
@ -44,7 +44,7 @@ function main(): void {
function checkForUniqueCodes(messages: string[], diagnosticTable: InputDiagnosticMessageTable) {
const originalMessageForCode: string[] = [];
let numConflicts = 0;
for (const currentMessage of messages) {
const code = diagnosticTable[currentMessage].code;
@ -68,19 +68,19 @@ function checkForUniqueCodes(messages: string[], diagnosticTable: InputDiagnosti
}
}
function buildUniqueNameMap(names: string[]): ts.Map<string> {
var nameMap = ts.createMap<string>();
function buildUniqueNameMap(names: string[]): ts.Map<string, string> {
var nameMap = new ts.StringMap<string>();
var uniqueNames = NameGenerator.ensureUniqueness(names, /* isCaseSensitive */ false, /* isFixed */ undefined);
for (var i = 0; i < names.length; i++) {
nameMap[names[i]] = uniqueNames[i];
nameMap.set(names[i], uniqueNames[i]);
}
return nameMap;
}
function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, nameMap: ts.Map<string>): string {
function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, nameMap: ts.Map<string, string>): string {
var result =
'// <auto-generated />\r\n' +
'/// <reference path="types.ts" />\r\n' +
@ -91,7 +91,7 @@ function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, nameMap:
for (var i = 0; i < names.length; i++) {
var name = names[i];
var diagnosticDetails = messageTable[name];
var propName = convertPropertyName(nameMap[name]);
var propName = convertPropertyName(nameMap.get(name));
result +=
' ' + propName +
@ -107,14 +107,14 @@ function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, nameMap:
return result;
}
function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable, nameMap: ts.Map<string>): string {
function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable, nameMap: ts.Map<string, string>): string {
var result =
'{';
var names = Utilities.getObjectKeys(messageTable);
for (var i = 0; i < names.length; i++) {
var name = names[i];
var diagnosticDetails = messageTable[name];
var propName = convertPropertyName(nameMap[name]);
var propName = convertPropertyName(nameMap.get(name));
result += '\r\n "' + createKey(propName, diagnosticDetails.code) + '"' + ' : "' + name.replace(/[\"]/g, '\\"') + '"';
if (i !== names.length - 1) {

View File

@ -126,7 +126,7 @@ namespace ts {
let symbolCount = 0;
let Symbol: { new (flags: SymbolFlags, name: string): Symbol };
let classifiableNames: Map<string>;
let classifiableNames: Set<string>;
const unreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
const reportedUnreachableFlow: FlowNode = { flags: FlowFlags.Unreachable };
@ -140,7 +140,7 @@ namespace ts {
options = opts;
languageVersion = getEmitScriptTarget(options);
inStrictMode = !!file.externalModuleIndicator;
classifiableNames = createMap<string>();
classifiableNames = new StringSet();
symbolCount = 0;
skipTransformFlagAggregation = isDeclarationFile(file);
@ -190,11 +190,11 @@ namespace ts {
symbol.declarations.push(node);
if (symbolFlags & SymbolFlags.HasExports && !symbol.exports) {
symbol.exports = createMap<Symbol>();
symbol.exports = new StringMap<Symbol>();
}
if (symbolFlags & SymbolFlags.HasMembers && !symbol.members) {
symbol.members = createMap<Symbol>();
symbol.members = new StringMap<Symbol>();
}
if (symbolFlags & SymbolFlags.Value) {
@ -332,17 +332,17 @@ 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 = symbolTable[name] || (symbolTable[name] = createSymbol(SymbolFlags.None, name));
symbol = getOrUpdate(symbolTable, name, name => createSymbol(SymbolFlags.None, name));
if (name && (includes & SymbolFlags.Classifiable)) {
classifiableNames[name] = name;
classifiableNames.add(name);
}
if (symbol.flags & excludes) {
if (symbol.isReplaceableByMethod) {
// Javascript constructor-declared symbols can be discarded in favor of
// prototype symbols like methods.
symbol = symbolTable[name] = createSymbol(SymbolFlags.None, name);
symbol = setAndReturn(symbolTable, name, createSymbol(SymbolFlags.None, name));
}
else {
if (node.name) {
@ -450,7 +450,7 @@ namespace ts {
if (containerFlags & ContainerFlags.IsContainer) {
container = blockScopeContainer = node;
if (containerFlags & ContainerFlags.HasLocals) {
container.locals = createMap<Symbol>();
container.locals = new StringMap<Symbol>();
}
addToContainerChain(container);
}
@ -1447,8 +1447,7 @@ namespace ts {
const typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type");
addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
typeLiteralSymbol.members = createMap<Symbol>();
typeLiteralSymbol.members[symbol.name] = symbol;
typeLiteralSymbol.members = createMapWithEntry(symbol.name, symbol);
}
function bindObjectLiteralExpression(node: ObjectLiteralExpression) {
@ -1458,7 +1457,7 @@ namespace ts {
}
if (inStrictMode) {
const seen = createMap<ElementKind>();
const seen = new StringMap<ElementKind>();
for (const prop of node.properties) {
if (prop.name.kind !== SyntaxKind.Identifier) {
@ -1479,9 +1478,9 @@ namespace ts {
? ElementKind.Property
: ElementKind.Accessor;
const existingKind = seen[identifier.text];
const existingKind = seen.get(identifier.text);
if (!existingKind) {
seen[identifier.text] = currentKind;
seen.set(identifier.text, currentKind);
continue;
}
@ -1514,7 +1513,7 @@ namespace ts {
// fall through.
default:
if (!blockScopeContainer.locals) {
blockScopeContainer.locals = createMap<Symbol>();
blockScopeContainer.locals = new StringMap<Symbol>();
addToContainerChain(blockScopeContainer);
}
declareSymbol(blockScopeContainer.locals, undefined, node, symbolFlags, symbolExcludes);
@ -1976,7 +1975,7 @@ namespace ts {
}
}
file.symbol.globalExports = file.symbol.globalExports || createMap<Symbol>();
file.symbol.globalExports = file.symbol.globalExports || new StringMap<Symbol>();
declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
}
@ -2021,7 +2020,7 @@ namespace ts {
Debug.assert(isInJavaScriptFile(node));
// Declare a 'member' if the container is an ES5 class or ES6 constructor
if (container.kind === SyntaxKind.FunctionDeclaration || container.kind === SyntaxKind.FunctionExpression) {
container.symbol.members = container.symbol.members || createMap<Symbol>();
container.symbol.members = container.symbol.members || new StringMap<Symbol>();
// It's acceptable for multiple 'this' assignments of the same identifier to occur
declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
}
@ -2053,14 +2052,14 @@ namespace ts {
constructorFunction.parent = classPrototype;
classPrototype.parent = leftSideOfAssignment;
const funcSymbol = container.locals[constructorFunction.text];
const funcSymbol = container.locals.get(constructorFunction.text);
if (!funcSymbol || !(funcSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(funcSymbol))) {
return;
}
// Set up the members collection if it doesn't exist already
if (!funcSymbol.members) {
funcSymbol.members = createMap<Symbol>();
funcSymbol.members = new StringMap<Symbol>();
}
// Declare the method/property
@ -2093,7 +2092,7 @@ namespace ts {
bindAnonymousDeclaration(node, SymbolFlags.Class, bindingName);
// Add name of class expression into the map for semantic classifier
if (node.name) {
classifiableNames[node.name.text] = node.name.text;
classifiableNames.add(node.name.text);
}
}
@ -2109,14 +2108,15 @@ 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 (symbol.exports[prototypeSymbol.name]) {
const symbolExport = symbol.exports.get(prototypeSymbol.name);
if (symbolExport) {
if (node.name) {
node.name.parent = node;
}
file.bindDiagnostics.push(createDiagnosticForNode(symbol.exports[prototypeSymbol.name].declarations[0],
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0],
Diagnostics.Duplicate_identifier_0, prototypeSymbol.name));
}
symbol.exports[prototypeSymbol.name] = prototypeSymbol;
symbol.exports.set(prototypeSymbol.name, prototypeSymbol);
prototypeSymbol.parent = symbol;
}

File diff suppressed because it is too large Load Diff

View File

@ -65,7 +65,7 @@ namespace ts {
},
{
name: "jsx",
type: createMap({
type: mapOfMapLike({
"preserve": JsxEmit.Preserve,
"react": JsxEmit.React
}),
@ -95,7 +95,7 @@ namespace ts {
{
name: "module",
shortName: "m",
type: createMap({
type: mapOfMapLike({
"none": ModuleKind.None,
"commonjs": ModuleKind.CommonJS,
"amd": ModuleKind.AMD,
@ -109,7 +109,7 @@ namespace ts {
},
{
name: "newLine",
type: createMap({
type: mapOfMapLike({
"crlf": NewLineKind.CarriageReturnLineFeed,
"lf": NewLineKind.LineFeed
}),
@ -258,7 +258,7 @@ namespace ts {
{
name: "target",
shortName: "t",
type: createMap({
type: mapOfMapLike({
"es3": ScriptTarget.ES3,
"es5": ScriptTarget.ES5,
"es6": ScriptTarget.ES6,
@ -292,7 +292,7 @@ namespace ts {
},
{
name: "moduleResolution",
type: createMap({
type: mapOfMapLike({
"node": ModuleResolutionKind.NodeJs,
"classic": ModuleResolutionKind.Classic,
}),
@ -401,7 +401,7 @@ namespace ts {
type: "list",
element: {
name: "lib",
type: createMap({
type: mapOfMapLike({
// JavaScript only
"es5": "lib.es5.d.ts",
"es6": "lib.es2015.d.ts",
@ -473,8 +473,8 @@ namespace ts {
/* @internal */
export interface OptionNameMap {
optionNameMap: Map<CommandLineOption>;
shortOptionNames: Map<string>;
optionNameMap: Map<string, CommandLineOption>;
shortOptionNames: Map<string, string>;
}
/* @internal */
@ -493,12 +493,12 @@ namespace ts {
return optionNameMapCache;
}
const optionNameMap = createMap<CommandLineOption>();
const shortOptionNames = createMap<string>();
const optionNameMap = new StringMap<CommandLineOption>();
const shortOptionNames = new StringMap<string>();
forEach(optionDeclarations, option => {
optionNameMap[option.name.toLowerCase()] = option;
optionNameMap.set(option.name.toLowerCase(), option);
if (option.shortName) {
shortOptionNames[option.shortName] = option.name;
shortOptionNames.set(option.shortName, option.name);
}
});
@ -509,18 +509,16 @@ namespace ts {
/* @internal */
export function createCompilerDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType): Diagnostic {
const namesOfType: string[] = [];
for (const key in opt.type) {
namesOfType.push(` '${key}'`);
}
forEachKeyInMap(opt.type, key => namesOfType.push(` '${key}'`));
return createCompilerDiagnostic(Diagnostics.Argument_for_0_option_must_be_Colon_1, `--${opt.name}`, namesOfType);
}
/* @internal */
export function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
const key = trimString((value || "")).toLowerCase();
const map = opt.type;
if (key in map) {
return map[key];
const customType = opt.type.get(key);
if (customType !== undefined) {
return customType;
}
else {
errors.push(createCompilerDiagnosticForInvalidCustomType(opt));
@ -573,13 +571,13 @@ namespace ts {
s = s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1).toLowerCase();
// Try to translate short option names to their full equivalents.
if (s in shortOptionNames) {
s = shortOptionNames[s];
const short = shortOptionNames.get(s);
if (short !== undefined) {
s = short;
}
if (s in optionNameMap) {
const opt = optionNameMap[s];
const opt = optionNameMap.get(s);
if (opt !== undefined) {
if (opt.isTSConfigOnly) {
errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file, opt.name));
}
@ -696,7 +694,7 @@ namespace ts {
* @param fileNames array of filenames to be generated into tsconfig.json
*/
/* @internal */
export function generateTSConfig(options: CompilerOptions, fileNames: string[]): { compilerOptions: Map<CompilerOptionsValue> } {
export function generateTSConfig(options: CompilerOptions, fileNames: string[]): { compilerOptions: MapLike<CompilerOptionsValue> } {
const compilerOptions = extend(options, defaultInitCompilerOptions);
const configurations: any = {
compilerOptions: serializeCompilerOptions(compilerOptions)
@ -708,7 +706,7 @@ namespace ts {
return configurations;
function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): Map<string | number> | undefined {
function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): Map<string, string | number> | undefined {
if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean") {
// this is of a type CommandLineOptionOfPrimitiveType
return undefined;
@ -721,18 +719,17 @@ namespace ts {
}
}
function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: MapLike<string | number>): string | undefined {
function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: Map<string, string | number>): string | undefined {
// There is a typeMap associated with this command-line option so use it to map value back to its name
for (const key in customTypeMap) {
if (customTypeMap[key] === value) {
return findInMap(customTypeMap, (customValue, key) => {
if (customValue === value) {
return key;
}
}
return undefined;
});
}
function serializeCompilerOptions(options: CompilerOptions): Map<CompilerOptionsValue> {
const result = createMap<CompilerOptionsValue>();
function serializeCompilerOptions(options: CompilerOptions): MapLike<CompilerOptionsValue> {
const result = new StringMap<CompilerOptionsValue>();
const optionsNameMap = getOptionNameMap().optionNameMap;
for (const name in options) {
@ -748,13 +745,13 @@ namespace ts {
break;
default:
const value = options[name];
let optionDefinition = optionsNameMap[name.toLowerCase()];
let optionDefinition = optionsNameMap.get(name.toLowerCase());
if (optionDefinition) {
const customTypeMap = getCustomTypeMapOfCommandLineOption(optionDefinition);
if (!customTypeMap) {
// There is no map associated with this compiler option then use the value as-is
// This is the case if the value is expect to be string, number, boolean or list of string
result[name] = value;
result.set(name, value);
}
else {
if (optionDefinition.type === "list") {
@ -762,11 +759,11 @@ namespace ts {
for (const element of value as (string | number)[]) {
convertedValue.push(getNameOfCompilerOptionValue(element, customTypeMap));
}
result[name] = convertedValue;
result.set(name, convertedValue);
}
else {
// There is a typeMap associated with this command-line option so use it to map value back to its name
result[name] = getNameOfCompilerOptionValue(value, customTypeMap);
result.set(name, getNameOfCompilerOptionValue(value, customTypeMap));
}
}
}
@ -774,7 +771,7 @@ namespace ts {
}
}
}
return result;
return mapLikeOfMap(result);
}
}
@ -1001,8 +998,8 @@ namespace ts {
const optionNameMap = arrayToMap(optionDeclarations, opt => opt.name);
for (const id in jsonOptions) {
if (id in optionNameMap) {
const opt = optionNameMap[id];
const opt = optionNameMap.get(id);
if (opt !== undefined) {
defaultOptions[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors);
}
else {
@ -1038,8 +1035,9 @@ namespace ts {
function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
const key = value.toLowerCase();
if (key in opt.type) {
return opt.type[key];
const val = opt.type.get(key);
if (val !== undefined) {
return val;
}
else {
errors.push(createCompilerDiagnosticForInvalidCustomType(opt));
@ -1148,12 +1146,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 = createMap<string>();
const literalFileMap = new StringMap<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 = createMap<string>();
const wildcardFileMap = new StringMap<string>();
if (include) {
include = validateSpecs(include, errors, /*allowTrailingRecursion*/ false);
@ -1167,7 +1165,7 @@ namespace ts {
// file map that marks whether it was a regular wildcard match (with a `*` or `?` token),
// or a recursive directory. This information is used by filesystem watchers to monitor for
// new entries in these paths.
const wildcardDirectories: Map<WatchDirectoryFlags> = getWildcardDirectories(include, exclude, basePath, host.useCaseSensitiveFileNames);
const wildcardDirectories: Map<string, WatchDirectoryFlags> = getWildcardDirectories(include, exclude, basePath, host.useCaseSensitiveFileNames);
// Rather than requery this for each file and filespec, we query the supported extensions
// once and store it on the expansion context.
@ -1178,7 +1176,7 @@ namespace ts {
if (fileNames) {
for (const fileName of fileNames) {
const file = combinePaths(basePath, fileName);
literalFileMap[keyMapper(file)] = file;
literalFileMap.set(keyMapper(file), file);
}
}
@ -1201,18 +1199,17 @@ namespace ts {
removeWildcardFilesWithLowerPriorityExtension(file, wildcardFileMap, supportedExtensions, keyMapper);
const key = keyMapper(file);
if (!(key in literalFileMap) && !(key in wildcardFileMap)) {
wildcardFileMap[key] = file;
if (!literalFileMap.has(key)) {
setIfNotSet(wildcardFileMap, key, file);
}
}
}
const literalFiles = reduceProperties(literalFileMap, addFileToOutput, []);
const wildcardFiles = reduceProperties(wildcardFileMap, addFileToOutput, []);
wildcardFiles.sort(host.useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
const literalFiles = valuesOfMap(literalFileMap);
const wildcardFiles = valuesOfMap(wildcardFileMap).sort(host.useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
return {
fileNames: literalFiles.concat(wildcardFiles),
wildcardDirectories
wildcardDirectories: mapLikeOfMap(wildcardDirectories)
};
}
@ -1253,7 +1250,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 = createMap<WatchDirectoryFlags>();
const wildcardDirectories = new StringMap<WatchDirectoryFlags>();
if (include !== undefined) {
const recursiveKeys: string[] = [];
for (const file of include) {
@ -1266,9 +1263,9 @@ namespace ts {
if (match) {
const key = useCaseSensitiveFileNames ? match[0] : match[0].toLowerCase();
const flags = watchRecursivePattern.test(name) ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None;
const existingFlags = wildcardDirectories[key];
const existingFlags = wildcardDirectories.get(key);
if (existingFlags === undefined || existingFlags < flags) {
wildcardDirectories[key] = flags;
wildcardDirectories.set(key, flags);
if (flags === WatchDirectoryFlags.Recursive) {
recursiveKeys.push(key);
}
@ -1277,13 +1274,13 @@ namespace ts {
}
// Remove any subpaths under an existing recursively watched directory.
for (const key in wildcardDirectories) {
forEachKeyInMap(wildcardDirectories, key => {
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
wildcardDirectories.delete(key);
}
}
}
});
}
return wildcardDirectories;
@ -1297,13 +1294,13 @@ namespace ts {
* @param extensionPriority The priority of the extension.
* @param context The expansion context.
*/
function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<string>, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<string, string>, wildcardFiles: Map<string, string>, extensions: string[], keyMapper: (value: string) => string) {
const extensionPriority = getExtensionPriority(file, extensions);
const adjustedExtensionPriority = adjustExtensionPriority(extensionPriority);
for (let i = ExtensionPriority.Highest; i < adjustedExtensionPriority; i++) {
const higherPriorityExtension = extensions[i];
const higherPriorityPath = keyMapper(changeExtension(file, higherPriorityExtension));
if (higherPriorityPath in literalFiles || higherPriorityPath in wildcardFiles) {
if (literalFiles.has(higherPriorityPath) || wildcardFiles.has(higherPriorityPath)) {
return true;
}
}
@ -1319,27 +1316,16 @@ namespace ts {
* @param extensionPriority The priority of the extension.
* @param context The expansion context.
*/
function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: Map<string, string>, extensions: string[], keyMapper: (value: string) => string) {
const extensionPriority = getExtensionPriority(file, extensions);
const nextExtensionPriority = getNextLowestExtensionPriority(extensionPriority);
for (let i = nextExtensionPriority; i < extensions.length; i++) {
const lowerPriorityExtension = extensions[i];
const lowerPriorityPath = keyMapper(changeExtension(file, lowerPriorityExtension));
delete wildcardFiles[lowerPriorityPath];
wildcardFiles.delete(lowerPriorityPath);
}
}
/**
* Adds a file to an array of files.
*
* @param output The output array.
* @param file The file path.
*/
function addFileToOutput(output: string[], file: string) {
output.push(file);
return output;
}
/**
* Gets a case sensitive key.
*

View File

@ -1,4 +1,5 @@
/// <reference path="types.ts"/>
/// <reference path="dataStructures.ts" />
/// <reference path="types.ts"/>
/// <reference path="performance.ts" />
/* @internal */
@ -18,28 +19,8 @@ namespace ts {
True = -1
}
const createObject = Object.create;
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
// constantly changing shape.
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;
}
export function createFileMap<T>(keyMapper?: (key: string) => string): FileMap<T> {
let files = createMap<T>();
const files = new StringMap<T>();
return {
get,
set,
@ -51,39 +32,33 @@ namespace ts {
};
function forEachValueInMap(f: (key: Path, value: T) => void) {
for (const key in files) {
f(<Path>key, files[key]);
}
files.forEach((value, key) => f(key as Path, value));
}
function getKeys() {
const keys: Path[] = [];
for (const key in files) {
keys.push(<Path>key);
}
return keys;
function getKeys(): Path[] {
return keysOfMap(files) as Path[];
}
// path should already be well-formed so it does not need to be normalized
function get(path: Path): T {
return files[toKey(path)];
return files.get(toKey(path));
}
function set(path: Path, value: T) {
files[toKey(path)] = value;
files.set(toKey(path), value);
}
function contains(path: Path) {
return toKey(path) in files;
return files.has(toKey(path));
}
function remove(path: Path) {
const key = toKey(path);
delete files[key];
files.delete(key);
}
function clear() {
files = createMap<T>();
files.clear();
}
function toKey(path: Path): string {
@ -586,242 +561,6 @@ namespace ts {
return initial;
}
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);
}
/**
* 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) if (hasOwnProperty.call(map, key)) {
keys.push(key);
}
return keys;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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];
}
}
export function assign<T1 extends MapLike<{}>, T2, T3>(t: T1, arg1: T2, arg2: T3): T1 & T2 & T3;
export function assign<T1 extends MapLike<{}>, T2>(t: T1, arg1: T2): T1 & T2;
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]): any;
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]) {
for (const arg of args) {
for (const p of getOwnKeys(arg)) {
t[p] = arg[p];
}
}
return t;
}
/**
* 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;
}
/**
* Creates a map from the elements of an array.
*
* @param array the array of input elements.
* @param makeKey a function that produces a key for a given element.
*
* This function makes no effort to avoid collisions; if any two elements produce
* 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>;
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;
}
export function isEmpty<T>(map: Map<T>) {
for (const id in map) {
if (hasProperty(map, id)) {
return false;
}
}
return true;
}
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;
}
/**
* Adds the value to an array of values associated with the key, and returns the array.
* Creates the array if it does not already exist.
*/
export function multiMapAdd<V>(map: Map<V[]>, key: string, value: V): V[] {
const values = map[key];
if (values) {
values.push(value);
return values;
}
else {
return map[key] = [value];
}
}
/**
* Removes a value from an array of values associated with the key.
* Does not preserve the order of those values.
* Does nothing if `key` is not in `map`, or `value` is not in `map[key]`.
*/
export function multiMapRemove<V>(map: Map<V[]>, key: string, value: V): void {
const values = map[key];
if (values) {
unorderedRemoveItem(values, value);
if (!values.length) {
delete map[key];
}
}
}
/**
* Tests whether a value is an array.
*/
@ -912,10 +651,10 @@ namespace ts {
return text.replace(/{(\d+)}/g, (match, index?) => args[+index + baseIndex]);
}
export let localizedDiagnosticMessages: Map<string> = undefined;
export let localizedDiagnosticMessages: Map<string, string> = undefined;
export function getLocaleSpecificMessage(message: DiagnosticMessage) {
return localizedDiagnosticMessages && localizedDiagnosticMessages[message.key] || message.message;
return localizedDiagnosticMessages && localizedDiagnosticMessages.get(message.key) || message.message;
}
export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: any[]): Diagnostic;

View File

@ -0,0 +1,624 @@
// NumberMap, StringMap, and StringSet shims
/* @internal */
namespace ts {
// The global Map object. This may not be available, so we must test for it.
declare const Map: NumberMapConstructor & StringMapConstructor | undefined;
const usingNativeMaps = typeof Map !== "undefined";
// tslint:disable-next-line:no-in-operator
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;
/** Extra Map methods that may not be available, so we must provide fallbacks. */
interface FullyFeaturedMap<K, V> extends Map<K, V> {
keys(): Iterator<K>;
values(): Iterator<V>;
entries(): Iterator<[K, V]>;
}
/** Simplified ES6 Iterator interface. */
interface Iterator<T> {
next(): { value: T, done: false } | { value: never, done: true };
}
export interface NumberMapConstructor {
/**
* Creates a new Map with number keys.
* If `pairs` is provided, each [key, value] pair will be added to the map.
*/
new<K extends number, V>(pairs?: [K, V][]): Map<K, V>;
}
/**
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {
private data: { [key: number]: V } = [];
constructor(pairs?: [K, V][]) {
if (pairs) {
for (const [key, value] of pairs) {
this.data[key as number] = value;
}
}
}
clear() {
this.data = [];
}
delete(key: K) {
delete this.data[key as number];
}
get(key: K) {
return this.data[key as number];
}
has(key: K) {
// tslint:disable-next-line:no-in-operator
return (key as number) in this.data;
}
set(key: K, value: V) {
this.data[key as number] = value;
}
forEach(action: (value: V, key: K) => void) {
for (const key in this.data) {
action(this.data[key], key as any as K);
}
}
};
export interface StringMapConstructor {
new<T>(): Map<string, T>;
}
/** In runtimes without Maps, this is implemented using an object. */
export const StringMap: StringMapConstructor = usingNativeMaps ? Map : class ShimStringMap<T> implements Map<string, T> {
private data = createDictionaryModeObject<T>();
constructor() {}
clear() {
this.data = createDictionaryModeObject<T>();
}
delete(key: string) {
delete this.data[key];
}
get(key: string) {
return this.data[key];
}
has(key: string) {
// tslint:disable-next-line:no-in-operator
return key in this.data;
}
set(key: string, value: T) {
this.data[key] = value;
}
forEach(f: (value: T, key: string) => void) {
for (const key in this.data) {
f(this.data[key], key);
}
}
};
const createObject = Object.create;
function createDictionaryModeObject<T>(): MapLike<T> {
const map = 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
// constantly changing shape.
map["__"] = undefined;
delete map["__"];
return map;
}
/** Iterates over entries in the map, returning the first output of `getResult` that is not `undefined`. */
export const findInMap: <K, V, U>(map: Map<K, V>, getResult: (value: V, key: K) => U | undefined) => U | undefined = fullyFeaturedMaps
? <K, V, U>(map: FullyFeaturedMap<K, V>, f: (value: V, key: K) => U | undefined) => {
const iter = map.entries();
while (true) {
const { value: pair, done } = iter.next();
if (done) {
return undefined;
}
const [key, value] = pair;
const result = f(value, key);
if (result !== undefined) {
return result;
}
}
}
: <K, V, U>(map: Map<K, V>, f: (value: V, key: K) => U | undefined) => {
let result: U | undefined;
map.forEach((value, key) => {
if (result === undefined)
result = f(value, key);
});
return result;
};
/** Whether `predicate` is true for at least one entry in the map. */
export const someInMap: <K, V>(map: Map<K, V>, predicate: (value: V, key: K) => boolean) => boolean = fullyFeaturedMaps
? <K, V>(map: FullyFeaturedMap<K, V>, predicate: (value: V, key: K) => boolean) =>
someInIterator(map.entries(), ([key, value]) => predicate(value, key))
: <K, V>(map: Map<K, V>, predicate: (value: V, key: K) => boolean) => {
let found = false;
map.forEach((value, key) => {
found = found || predicate(value, key);
});
return found;
};
/** Whether `predicate` is true for at least one key in the map. */
export const someKeyInMap: <K>(map: Map<K, any>, predicate: (key: K) => boolean) => boolean = fullyFeaturedMaps
? <K>(map: FullyFeaturedMap<K, any>, predicate: (key: K) => boolean) => someInIterator(map.keys(), predicate)
: <K>(map: Map<K, any>, predicate: (key: K) => boolean) =>
someInMap(map, (_value, key) => predicate(key));
/** Whether `predicate` is true for at least one value in the map. */
export const someValueInMap: <T>(map: Map<any, T>, predicate: (value: T) => boolean) => boolean = fullyFeaturedMaps
? <T>(map: FullyFeaturedMap<any, T>, predicate: (value: T) => boolean) =>
someInIterator(map.values(), predicate)
: someInMap;
function someInIterator<T>(iterator: Iterator<T>, predicate: (value: T) => boolean): boolean {
while (true) {
const { value, done } = iterator.next();
if (done) {
return false;
}
if (predicate(value)) {
return true;
}
}
}
/**
* Equivalent to the ES6 code:
* `for (const key of map.keys()) action(key);`
*/
export const forEachKeyInMap: <K>(map: Map<K, any>, action: (key: K) => void) => void = fullyFeaturedMaps
? <K>(map: FullyFeaturedMap<K, any>, f: (key: K) => void) => {
const iter: Iterator<K> = map.keys();
while (true) {
const { value: key, done } = iter.next();
if (done) {
return;
}
f(key);
}
}
: <K>(map: Map<K, any>, action: (key: K) => void) => {
map.forEach((_value, key) => action(key));
};
/** Size of a map. */
export const mapSize: (map: Map<any, any>) => number = usingNativeMaps
? map => (map as any).size
: map => {
let size = 0;
map.forEach(() => { size++; });
return size;
};
/** Convert a Map to a MapLike. */
export function mapLikeOfMap<T>(map: Map<string, T>): MapLike<T> {
const obj = createDictionaryModeObject<T>();
map.forEach((value, key) => {
obj[key] = value;
});
return obj;
}
/** Create a map from a MapLike. This is useful for writing large maps as object literals. */
export function mapOfMapLike<T>(object: MapLike<T>): Map<string, T> {
const map = new StringMap<T>();
// 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 object) if (hasProperty(object, key)) {
map.set(key, object[key]);
}
return map;
}
class ShimStringSet implements Set<string> {
private data = createDictionaryModeObject<true>();
constructor() {}
add(value: string) {
this.data[value] = true;
}
clear() {
this.data = createDictionaryModeObject<true>();
}
delete(value: string) {
delete this.data[value];
}
forEach(action: (value: string) => void) {
for (const value in this.data) {
action(value);
}
}
has(value: string) {
// tslint:disable-next-line:no-in-operator
return value in this.data;
}
isEmpty() {
// tslint:disable-next-line:no-unused-variable
for (const _ in this.data) {
return false;
}
return true;
}
}
declare const Set: { new(): Set<string> } | undefined;
const usingNativeSets = typeof Set !== "undefined";
/** In runtimes without Sets, this is implemented using an object. */
export const StringSet: { new(): Set<string> } = usingNativeSets ? Set : ShimStringSet;
/** False if there are any values in the set. */
export const setIsEmpty: (set: Set<string>) => boolean = usingNativeSets
? set => (set as any).size === 0
: (set: ShimStringSet) => set.isEmpty();
}
// Map utilities
namespace ts {
/** Create a map containing a single entry key -> value. */
export function createMapWithEntry<T>(key: string, value: T): Map<string, T> {
const map = new StringMap<T>();
map.set(key, value);
return map;
}
/** Set a value in a map, then return that value. */
export function setAndReturn<K, V>(map: Map<K, V>, key: K, value: V): V {
map.set(key, value);
return value;
}
/** False if there are any entries in the map. */
export function mapIsEmpty(map: Map<any, any>): boolean {
return !someKeyInMap(map, () => true);
}
/** Create a new copy of a Map. */
export function cloneMap<T>(map: Map<string, T>) {
const clone = new StringMap<T>();
copyMapEntriesFromTo(map, clone);
return clone;
}
/**
* Performs a shallow copy of the properties from a source Map to a target Map
*
* @param source A map from which properties should be copied.
* @param target A map to which properties should be copied.
*/
export function copyMapEntriesFromTo<K, V>(source: Map<K, V>, target: Map<K, V>): void {
source.forEach((value, key) => {
target.set(key, value);
});
}
/** Equivalent to `Array.from(map.keys())`. */
export function keysOfMap<K>(map: Map<K, any>): K[] {
const keys: K[] = [];
forEachKeyInMap(map, key => { keys.push(key); });
return keys;
}
/** Equivalent to `Array.from(map.values())`. */
export function valuesOfMap<V>(map: Map<any, V>): V[] {
const values: V[] = [];
map.forEach((value) => { values.push(value); });
return values;
}
/** Return a new map with each key transformed by `getNewKey`. */
export function transformKeys<T>(map: Map<string, T>, getNewKey: (key: string) => string): Map<string, T> {
const newMap = new StringMap<T>();
map.forEach((value, key) => {
newMap.set(getNewKey(key), value);
});
return newMap;
}
/** Replace each value with the result of calling `getNewValue`. */
export function updateMapValues<V>(map: Map<any, V>, getNewValue: (value: V) => V): void {
map.forEach((value, key) => {
map.set(key, getNewValue(value));
});
}
/**
* Change the value at `key` by applying the given function to it.
* If there is no value at `key` then `getNewValue` will be passed `undefined`.
*/
export function modifyValue<K, V>(map: Map<K, V>, key: K, getNewValue: (value: V) => V) {
map.set(key, getNewValue(map.get(key)));
}
/**
* Get a value in the map, or if not already present, set and return it.
* Treats entries set to `undefined` as equivalent to not being set (saving a call to `has`).
*/
export function getOrUpdate<K, V>(map: Map<K, V>, key: K, getValue: (key: K) => V): V {
const value = map.get(key);
return value !== undefined ? value : setAndReturn(map, key, getValue(key));
}
/** Like `getOrUpdate`, but recognizes `undefined` as having been already set. */
export function getOrUpdateAndAllowUndefined<K, V>(map: Map<K, V>, key: K, getValue: (key: K) => V): V {
return map.has(key) ? map.get(key) : setAndReturn(map, key, getValue(key));
}
/**
* Sets the the value if the key is not already in the map.
* Returns whether the value was set.
*/
export function setIfNotSet<K, V>(map: Map<K, V>, key: K, value: V): boolean {
const shouldSet = !map.has(key);
if (shouldSet) {
map.set(key, value);
}
return shouldSet;
}
/** Deletes an entry from a map and returns it; or returns undefined if the key was not in the map. */
export function tryDelete<K, V>(map: Map<K, V>, key: K): V | undefined {
const current = map.get(key);
if (current !== undefined) {
map.delete(key);
return current;
}
else {
return undefined;
}
}
/**
* Creates a map from the elements of an array.
*
* @param array the array of input elements.
* @param makeKey a function that produces a key for a given element.
*
* This function makes no effort to avoid collisions; if any two elements produce
* 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<string, T>;
export function arrayToMap<T, U>(array: T[], makeKey: (value: T) => string, makeValue: (value: T) => U): Map<string, U>;
export function arrayToMap<T, U>(array: T[], makeKey: (value: T) => string, makeValue?: (value: T) => U): Map<string, T | U> {
const result = new StringMap<T | U>();
for (const value of array) {
result.set(makeKey(value), makeValue ? makeValue(value) : value);
}
return result;
}
/**
* Adds the value to an array of values associated with the key, and returns the array.
* Creates the array if it does not already exist.
*/
export function multiMapAdd<K, V>(map: Map<K, V[]>, key: K, value: V): V[] {
const values = map.get(key);
if (values) {
values.push(value);
return values;
}
else {
return setAndReturn(map, key, [value]);
}
}
/**
* Removes a value from an array of values associated with the key.
* Does not preserve the order of those values.
* Does nothing if `key` is not in `map`, or `value` is not in `map[key]`.
*/
export function multiMapRemove<K, V>(map: Map<K, V[]>, key: K, value: V): void {
const values = map.get(key);
if (values) {
unorderedRemoveItem(values, value);
if (!values.length) {
map.delete(key);
}
}
}
/** True if the maps have the same keys and values. */
export function mapsAreEqual<K, V>(left: Map<K, V>, right: Map<K, V>, valuesAreEqual?: (left: V, right: V) => boolean): boolean {
if (left === right) return true;
if (!left || !right) return false;
const someInLeftHasNoMatch = someInMap(left, (leftValue, leftKey) => {
if (!right.has(leftKey)) return true;
const rightValue = right.get(leftKey);
return !(valuesAreEqual ? valuesAreEqual(leftValue, rightValue) : leftValue === rightValue);
});
if (someInLeftHasNoMatch) return false;
const someInRightHasNoMatch = someKeyInMap(right, rightKey => !left.has(rightKey));
return !someInRightHasNoMatch;
}
/**
* Creates a sorted array of keys.
* Sorts keys according to the iteration order they would have if they were in an object, instead of from a Map.
* This is so that tests run consistently whether or not we have a Map shim in place.
* The difference between Map iteration order and V8 object insertion order is that V8 moves natrual-number-like keys to the front.
*/
export function sortInV8ObjectInsertionOrder<T>(values: T[], toKey: (t: T) => string): T[] {
const naturalNumberKeys: T[] = [];
const allOtherKeys: T[] = [];
for (const value of values) {
// "0" looks like a natural but "08" doesn't.
const looksLikeNatural = /^(0|([1-9]\d*))$/.test(toKey(value));
(looksLikeNatural ? naturalNumberKeys : allOtherKeys).push(value);
}
function toInt(value: T): number {
return parseInt(toKey(value), 10);
}
naturalNumberKeys.sort((a, b) => toInt(a) - toInt(b));
return naturalNumberKeys.concat(allOtherKeys);
}
}
// Set utilities
/* @internal */
namespace ts {
/** Union of the `getSet` of each element in the array. */
export function setAggregate<T>(array: T[], getSet: (t: T) => Set<string>): Set<string> {
const result = new StringSet();
for (const value of array) {
copySetValuesFromTo(getSet(value), result);
}
return result;
}
/** Adds all values in `source` to `target`. */
function copySetValuesFromTo<T>(source: Set<T>, target: Set<T>): void {
source.forEach(value => target.add(value));
}
/** Returns the values in `set` satisfying `predicate`. */
export function filterSetToArray<T>(set: Set<T>, predicate: (value: T) => boolean): T[] {
const result: T[] = [];
set.forEach(value => {
if (predicate(value)) {
result.push(value);
}
});
return result;
}
}
// MapLike utilities
/* @internal */
namespace ts {
const hasOwnProperty = Object.prototype.hasOwnProperty;
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;
}
/**
* 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);
}
/**
* 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) if (hasOwnProperty.call(map, key)) {
keys.push(key);
}
return keys;
}
export function assign<T1 extends MapLike<{}>, T2, T3>(t: T1, arg1: T2, arg2: T3): T1 & T2 & T3;
export function assign<T1 extends MapLike<{}>, T2>(t: T1, arg1: T2): T1 & T2;
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]): any;
export function assign<T1 extends MapLike<{}>>(t: T1, ...args: any[]) {
for (const arg of args) {
for (const p of getOwnKeys(arg)) {
t[p] = arg[p];
}
}
return t;
}
/**
* Reduce the properties defined on a map-like (but not from its prototype chain).
*
* @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 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;
}
}

View File

@ -59,7 +59,7 @@ namespace ts {
let resultHasExternalModuleIndicator: boolean;
let currentText: string;
let currentLineMap: number[];
let currentIdentifiers: Map<string>;
let currentIdentifiers: Map<string, string>;
let isCurrentFileExternalModule: boolean;
let reportedDeclarationError = false;
let errorNameNode: DeclarationName;
@ -75,7 +75,7 @@ namespace ts {
// and we could be collecting these paths from multiple files into single one with --out option
let referencesOutput = "";
let usedTypeDirectiveReferences: Map<string>;
let usedTypeDirectiveReferences: Set<string>;
// Emit references corresponding to each file
const emittedReferencedFiles: SourceFile[] = [];
@ -156,9 +156,9 @@ namespace ts {
});
if (usedTypeDirectiveReferences) {
for (const directive in usedTypeDirectiveReferences) {
usedTypeDirectiveReferences.forEach(directive => {
referencesOutput += `/// <reference types="${directive}" />${newLine}`;
}
});
}
return {
@ -267,11 +267,11 @@ namespace ts {
}
if (!usedTypeDirectiveReferences) {
usedTypeDirectiveReferences = createMap<string>();
usedTypeDirectiveReferences = new StringSet();
}
for (const directive of typeReferenceDirectives) {
if (!(directive in usedTypeDirectiveReferences)) {
usedTypeDirectiveReferences[directive] = directive;
if (!usedTypeDirectiveReferences.has(directive)) {
usedTypeDirectiveReferences.add(directive);
}
}
}
@ -535,14 +535,14 @@ namespace ts {
// do not need to keep track of created temp names.
function getExportDefaultTempVariableName(): string {
const baseName = "_default";
if (!(baseName in currentIdentifiers)) {
if (!currentIdentifiers.has(baseName)) {
return baseName;
}
let count = 0;
while (true) {
count++;
const name = baseName + "_" + count;
if (!(name in currentIdentifiers)) {
if (!currentIdentifiers.has(name)) {
return name;
}
}

View File

@ -219,11 +219,11 @@ const _super = (function (geti, seti) {
let nodeIdToGeneratedName: string[];
let autoGeneratedIdToGeneratedName: string[];
let generatedNameSet: Map<string>;
let generatedNameSet: Set<string>;
let tempFlags: TempFlags;
let currentSourceFile: SourceFile;
let currentText: string;
let currentFileIdentifiers: Map<string>;
let currentFileIdentifiers: Map<string, string>;
let extendsEmitted: boolean;
let assignEmitted: boolean;
let decorateEmitted: boolean;
@ -292,7 +292,7 @@ const _super = (function (geti, seti) {
sourceMap.initialize(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
nodeIdToGeneratedName = [];
autoGeneratedIdToGeneratedName = [];
generatedNameSet = createMap<string>();
generatedNameSet = new StringSet();
isOwnFileEmit = !isBundledEmit;
// Emit helpers from all the files
@ -2621,15 +2621,16 @@ const _super = (function (geti, seti) {
function isUniqueName(name: string): boolean {
return !resolver.hasGlobalName(name) &&
!hasProperty(currentFileIdentifiers, name) &&
!hasProperty(generatedNameSet, name);
!currentFileIdentifiers.has(name) &&
!generatedNameSet.has(name);
}
function isUniqueLocalName(name: string, container: Node): boolean {
for (let node = container; isNodeDescendantOf(node, container); node = node.nextContainer) {
if (node.locals && hasProperty(node.locals, name)) {
if (node.locals) {
const local = node.locals.get(name);
// 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)) {
if (local && local.flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
return false;
}
}
@ -2678,7 +2679,8 @@ const _super = (function (geti, seti) {
while (true) {
const generatedName = baseName + i;
if (isUniqueName(generatedName)) {
return generatedNameSet[generatedName] = generatedName;
generatedNameSet.add(generatedName);
return generatedName;
}
i++;
}

View File

@ -2659,9 +2659,9 @@ namespace ts {
return destEmitNode;
}
function mergeTokenSourceMapRanges(sourceRanges: Map<TextRange>, destRanges: Map<TextRange>) {
if (!destRanges) destRanges = createMap<TextRange>();
copyProperties(sourceRanges, destRanges);
function mergeTokenSourceMapRanges(sourceRanges: Map<SyntaxKind, TextRange>, destRanges: Map<SyntaxKind, TextRange>): Map<SyntaxKind, TextRange> {
if (!destRanges) destRanges = new NumberMap<SyntaxKind, TextRange>();
copyMapEntriesFromTo(sourceRanges, destRanges);
return destRanges;
}
@ -2753,8 +2753,8 @@ namespace ts {
*/
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: TextRange) {
const emitNode = getOrCreateEmitNode(node);
const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = createMap<TextRange>());
tokenSourceMapRanges[token] = range;
const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = new NumberMap<SyntaxKind, TextRange>());
tokenSourceMapRanges.set(token, range);
return node;
}
@ -2795,7 +2795,7 @@ namespace ts {
export function getTokenSourceMapRange(node: Node, token: SyntaxKind) {
const emitNode = node.emitNode;
const tokenSourceMapRanges = emitNode && emitNode.tokenSourceMapRanges;
return tokenSourceMapRanges && tokenSourceMapRanges[token];
return tokenSourceMapRanges && tokenSourceMapRanges.get(token);
}
/**
@ -2880,10 +2880,8 @@ namespace ts {
* Here we check if alternative name was provided for a given moduleName and return it if possible.
*/
function tryRenameExternalModule(moduleName: LiteralExpression, sourceFile: SourceFile) {
if (sourceFile.renamedDependencies && hasProperty(sourceFile.renamedDependencies, moduleName.text)) {
return createLiteral(sourceFile.renamedDependencies[moduleName.text]);
}
return undefined;
const rename = sourceFile.renamedDependencies && sourceFile.renamedDependencies.get(moduleName.text);
return rename && createLiteral(rename);
}
/**

View File

@ -490,7 +490,7 @@ namespace ts {
let currentToken: SyntaxKind;
let sourceText: string;
let nodeCount: number;
let identifiers: Map<string>;
let identifiers: Map<string, string>;
let identifierCount: number;
let parsingContext: ParsingContext;
@ -600,7 +600,7 @@ namespace ts {
parseDiagnostics = [];
parsingContext = 0;
identifiers = createMap<string>();
identifiers = new StringMap<string>();
identifierCount = 0;
nodeCount = 0;
@ -1101,7 +1101,7 @@ namespace ts {
function internIdentifier(text: string): string {
text = escapeIdentifier(text);
return identifiers[text] || (identifiers[text] = text);
return getOrUpdate(identifiers, text, text => text);
}
// An identifier that starts with two underscores has an extra underscore character prepended to it to avoid issues

View File

@ -16,9 +16,9 @@ namespace ts.performance {
let enabled = false;
let profilerStart = 0;
let counts: Map<number>;
let marks: Map<number>;
let measures: Map<number>;
let counts: Map<string, number>;
let marks: Map<string, number>;
let measures: Map<string, number>;
/**
* Marks a performance event.
@ -27,8 +27,8 @@ namespace ts.performance {
*/
export function mark(markName: string) {
if (enabled) {
marks[markName] = timestamp();
counts[markName] = (counts[markName] || 0) + 1;
marks.set(markName, timestamp());
counts.set(markName, (counts.get(markName) || 0) + 1);
profilerEvent(markName);
}
}
@ -44,9 +44,9 @@ namespace ts.performance {
*/
export function measure(measureName: string, startMarkName?: string, endMarkName?: string) {
if (enabled) {
const end = endMarkName && marks[endMarkName] || timestamp();
const start = startMarkName && marks[startMarkName] || profilerStart;
measures[measureName] = (measures[measureName] || 0) + (end - start);
const end = endMarkName && marks.get(endMarkName) || timestamp();
const start = startMarkName && marks.get(startMarkName) || profilerStart;
measures.set(measureName, (measures.get(measureName) || 0) + (end - start));
}
}
@ -56,7 +56,7 @@ namespace ts.performance {
* @param markName The name of the mark.
*/
export function getCount(markName: string) {
return counts && counts[markName] || 0;
return counts && counts.get(markName) || 0;
}
/**
@ -65,7 +65,7 @@ namespace ts.performance {
* @param measureName The name of the measure whose durations should be accumulated.
*/
export function getDuration(measureName: string) {
return measures && measures[measureName] || 0;
return measures && measures.get(measureName) || 0;
}
/**
@ -74,16 +74,14 @@ namespace ts.performance {
* @param cb The action to perform for each measure
*/
export function forEachMeasure(cb: (measureName: string, duration: number) => void) {
for (const key in measures) {
cb(key, measures[key]);
}
measures.forEach((duration, measureName) => cb(measureName, duration));
}
/** Enables (and resets) performance measurements for the compiler. */
export function enable() {
counts = createMap<number>();
marks = createMap<number>();
measures = createMap<number>();
counts = new StringMap<number>();
marks = new StringMap<number>();
measures = new StringMap<number>();
enabled = true;
profilerStart = timestamp();
}

View File

@ -82,7 +82,7 @@ namespace ts {
}
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
const existingDirectories = createMap<boolean>();
const existingDirectories = new StringSet();
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.
@ -114,11 +114,11 @@ namespace ts {
}
function directoryExists(directoryPath: string): boolean {
if (directoryPath in existingDirectories) {
if (existingDirectories.has(directoryPath)) {
return true;
}
if (sys.directoryExists(directoryPath)) {
existingDirectories[directoryPath] = true;
existingDirectories.add(directoryPath);
return true;
}
return false;
@ -132,21 +132,21 @@ namespace ts {
}
}
let outputFingerprints: Map<OutputFingerprint>;
let outputFingerprints: Map<string, OutputFingerprint>;
function writeFileIfUpdated(fileName: string, data: string, writeByteOrderMark: boolean): void {
if (!outputFingerprints) {
outputFingerprints = createMap<OutputFingerprint>();
outputFingerprints = new StringMap<OutputFingerprint>();
}
const hash = sys.createHash(data);
const mtimeBefore = sys.getModifiedTime(fileName);
if (mtimeBefore && fileName in outputFingerprints) {
const fingerprint = outputFingerprints[fileName];
if (mtimeBefore) {
const fingerprint = outputFingerprints.get(fileName);
// If output has not been changed, and the file has no external modification
if (fingerprint.byteOrderMark === writeByteOrderMark &&
if (fingerprint !== undefined && fingerprint.byteOrderMark === writeByteOrderMark &&
fingerprint.hash === hash &&
fingerprint.mtime.getTime() === mtimeBefore.getTime()) {
return;
@ -157,11 +157,11 @@ namespace ts {
const mtimeAfter = sys.getModifiedTime(fileName);
outputFingerprints[fileName] = {
outputFingerprints.set(fileName, {
hash,
byteOrderMark: writeByteOrderMark,
mtime: mtimeAfter
};
});
}
function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {
@ -279,11 +279,11 @@ namespace ts {
return [];
}
const resolutions: T[] = [];
const cache = createMap<T>();
const cache = new StringMap<T>();
for (const name of names) {
const result = name in cache
? cache[name]
: cache[name] = loader(name, containingFile);
const result = cache.has(name)
? cache.get(name)
: setAndReturn(cache, name, loader(name, containingFile));
resolutions.push(result);
}
return resolutions;
@ -295,9 +295,9 @@ namespace ts {
let commonSourceDirectory: string;
let diagnosticsProducingTypeChecker: TypeChecker;
let noDiagnosticsTypeChecker: TypeChecker;
let classifiableNames: Map<string>;
let classifiableNames: Set<string>;
let resolvedTypeReferenceDirectives = createMap<ResolvedTypeReferenceDirective>();
let resolvedTypeReferenceDirectives = new StringMap<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.
@ -312,10 +312,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 = createMap<boolean>();
const modulesWithElidedImports = new StringMap<boolean>();
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
const sourceFilesFoundSearchingNodeModules = createMap<boolean>();
const sourceFilesFoundSearchingNodeModules = new StringMap<boolean>();
performance.mark("beforeProgram");
@ -440,15 +440,11 @@ namespace ts {
return commonSourceDirectory;
}
function getClassifiableNames() {
function getClassifiableNames(): Set<string> {
if (!classifiableNames) {
// Initialize a checker so that all our files are bound.
getTypeChecker();
classifiableNames = createMap<string>();
for (const sourceFile of files) {
copyProperties(sourceFile.classifiableNames, classifiableNames);
}
classifiableNames = setAggregate(files, sourceFile => sourceFile.classifiableNames);
}
return classifiableNames;
@ -598,7 +594,7 @@ namespace ts {
getSourceFile: program.getSourceFile,
getSourceFileByPath: program.getSourceFileByPath,
getSourceFiles: program.getSourceFiles,
isSourceFileFromExternalLibrary: (file: SourceFile) => !!sourceFilesFoundSearchingNodeModules[file.path],
isSourceFileFromExternalLibrary: (file: SourceFile) => !!sourceFilesFoundSearchingNodeModules.get(file.path),
writeFile: writeFileCallback || (
(fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)),
isEmitBlocked,
@ -1142,8 +1138,8 @@ namespace ts {
// Get source file from normalized fileName
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, isReference: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
if (filesByName.contains(path)) {
const file = filesByName.get(path);
let file = filesByName.get(path);
if (file !== undefined) {
// try to check if we've already seen this file but with a different casing in path
// NOTE: this only makes sense for case-insensitive file systems
if (file && options.forceConsistentCasingInFileNames && getNormalizedAbsolutePath(file.fileName, currentDirectory) !== getNormalizedAbsolutePath(fileName, currentDirectory)) {
@ -1152,20 +1148,20 @@ 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 && sourceFilesFoundSearchingNodeModules[file.path] && currentNodeModulesDepth == 0) {
sourceFilesFoundSearchingNodeModules[file.path] = false;
if (file && sourceFilesFoundSearchingNodeModules.get(file.path) && currentNodeModulesDepth == 0) {
sourceFilesFoundSearchingNodeModules.set(file.path, false);
if (!options.noResolve) {
processReferencedFiles(file, getDirectoryPath(fileName), isDefaultLib);
processTypeReferenceDirectives(file);
}
modulesWithElidedImports[file.path] = false;
modulesWithElidedImports.set(file.path, false);
processImportedModules(file, getDirectoryPath(fileName));
}
// See if we need to reprocess the imports due to prior skipped imports
else if (file && modulesWithElidedImports[file.path]) {
else if (file && modulesWithElidedImports.get(file.path)) {
if (currentNodeModulesDepth < maxNodeModulesJsDepth) {
modulesWithElidedImports[file.path] = false;
modulesWithElidedImports.set(file.path, false);
processImportedModules(file, getDirectoryPath(fileName));
}
}
@ -1174,7 +1170,7 @@ namespace ts {
}
// We haven't looked for this file, do so now and cache result
const file = host.getSourceFile(fileName, options.target, hostErrorMessage => {
file = host.getSourceFile(fileName, options.target, hostErrorMessage => {
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
@ -1186,7 +1182,7 @@ namespace ts {
filesByName.set(path, file);
if (file) {
sourceFilesFoundSearchingNodeModules[path] = (currentNodeModulesDepth > 0);
sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
file.path = path;
if (host.useCaseSensitiveFileNames()) {
@ -1248,7 +1244,7 @@ namespace ts {
refFile?: SourceFile, refPos?: number, refEnd?: number): void {
// If we already found this library as a primary reference - nothing to do
const previousResolution = resolvedTypeReferenceDirectives[typeReferenceDirective];
const previousResolution = resolvedTypeReferenceDirectives.get(typeReferenceDirective);
if (previousResolution && previousResolution.primary) {
return;
}
@ -1285,7 +1281,7 @@ namespace ts {
}
if (saveResolution) {
resolvedTypeReferenceDirectives[typeReferenceDirective] = resolvedTypeReferenceDirective;
resolvedTypeReferenceDirectives.set(typeReferenceDirective, resolvedTypeReferenceDirective);
}
}
@ -1305,7 +1301,7 @@ namespace ts {
function processImportedModules(file: SourceFile, basePath: string) {
collectExternalModuleReferences(file);
if (file.imports.length || file.moduleAugmentations.length) {
file.resolvedModules = createMap<ResolvedModule>();
file.resolvedModules = new StringMap<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++) {
@ -1329,7 +1325,7 @@ namespace ts {
const shouldAddFile = resolution && !options.noResolve && i < file.imports.length && !elideImport;
if (elideImport) {
modulesWithElidedImports[file.path] = true;
modulesWithElidedImports.set(file.path, true);
}
else if (shouldAddFile) {
findSourceFile(resolution.resolvedFileName,

View File

@ -56,7 +56,7 @@ namespace ts {
tryScan<T>(callback: () => T): T;
}
const textToToken = createMap({
const textToToken = mapOfMapLike({
"abstract": SyntaxKind.AbstractKeyword,
"any": SyntaxKind.AnyKeyword,
"as": SyntaxKind.AsKeyword,
@ -272,11 +272,11 @@ namespace ts {
lookupInUnicodeMap(code, unicodeES3IdentifierPart);
}
function makeReverseMap(source: Map<number>): string[] {
function makeReverseMap(source: Map<string, number>): string[] {
const result: string[] = [];
for (const name in source) {
result[source[name]] = name;
}
source.forEach((num, name) => {
result[num] = name;
});
return result;
}
@ -288,7 +288,7 @@ namespace ts {
/* @internal */
export function stringToToken(s: string): SyntaxKind {
return textToToken[s];
return textToToken.get(s);
}
/* @internal */
@ -362,8 +362,6 @@ namespace ts {
return computeLineAndCharacterOfPosition(getLineStarts(sourceFile), position);
}
const hasOwnProperty = Object.prototype.hasOwnProperty;
export function isWhiteSpace(ch: number): boolean {
return isWhiteSpaceSingleLine(ch) || isLineBreak(ch);
}
@ -1182,8 +1180,11 @@ namespace ts {
const len = tokenValue.length;
if (len >= 2 && len <= 11) {
const ch = tokenValue.charCodeAt(0);
if (ch >= CharacterCodes.a && ch <= CharacterCodes.z && hasOwnProperty.call(textToToken, tokenValue)) {
return token = textToToken[tokenValue];
if (ch >= CharacterCodes.a && ch <= CharacterCodes.z) {
token = textToToken.get(tokenValue);
if (token !== undefined) {
return token;
}
}
}
return token = SyntaxKind.Identifier;

View File

@ -362,7 +362,7 @@ namespace ts {
const emitNode = node && node.emitNode;
const emitFlags = emitNode && emitNode.flags;
const range = emitNode && emitNode.tokenSourceMapRanges && emitNode.tokenSourceMapRanges[token];
const range = emitNode && emitNode.tokenSourceMapRanges && emitNode.tokenSourceMapRanges.get(token);
tokenPos = skipTrivia(currentSourceText, range ? range.pos : tokenPos);
if ((emitFlags & EmitFlags.NoTokenLeadingSourceMaps) === 0 && tokenPos >= 0) {

View File

@ -239,25 +239,25 @@ namespace ts {
const useNonPollingWatchers = process.env["TSC_NONPOLLING_WATCHER"];
function createWatchedFileSet() {
const dirWatchers = createMap<DirectoryWatcher>();
const dirWatchers = new StringMap<DirectoryWatcher>();
// One file can have multiple watchers
const fileWatcherCallbacks = createMap<FileWatcherCallback[]>();
const fileWatcherCallbacks = new StringMap<FileWatcherCallback[]>();
return { addFile, removeFile };
function reduceDirWatcherRefCountForFile(fileName: string) {
const dirName = getDirectoryPath(fileName);
const watcher = dirWatchers[dirName];
const watcher = dirWatchers.get(dirName);
if (watcher) {
watcher.referenceCount -= 1;
if (watcher.referenceCount <= 0) {
watcher.close();
delete dirWatchers[dirName];
dirWatchers.delete(dirName);
}
}
}
function addDirWatcher(dirPath: string): void {
let watcher = dirWatchers[dirPath];
let watcher = dirWatchers.get(dirPath);
if (watcher) {
watcher.referenceCount += 1;
return;
@ -268,7 +268,7 @@ namespace ts {
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
);
watcher.referenceCount = 1;
dirWatchers[dirPath] = watcher;
dirWatchers.set(dirPath, watcher);
return;
}
@ -298,9 +298,12 @@ namespace ts {
? undefined
: ts.getNormalizedAbsolutePath(relativeFileName, baseDirPath);
// Some applications save a working file via rename operations
if ((eventName === "change" || eventName === "rename") && fileWatcherCallbacks[fileName]) {
for (const fileCallback of fileWatcherCallbacks[fileName]) {
fileCallback(fileName);
if ((eventName === "change" || eventName === "rename")) {
const callbacks = fileWatcherCallbacks.get(fileName);
if (callbacks) {
for (const fileCallback of fileWatcherCallbacks.get(fileName)) {
fileCallback(fileName);
}
}
}
}

View File

@ -10,14 +10,14 @@
/* @internal */
namespace ts {
const moduleTransformerMap = createMap<Transformer>({
[ModuleKind.ES6]: transformES6Module,
[ModuleKind.System]: transformSystemModule,
[ModuleKind.AMD]: transformModule,
[ModuleKind.CommonJS]: transformModule,
[ModuleKind.UMD]: transformModule,
[ModuleKind.None]: transformModule,
});
const moduleTransformerMap = new NumberMap<ModuleKind, Transformer>([
[ModuleKind.ES6, transformES6Module],
[ModuleKind.System, transformSystemModule],
[ModuleKind.AMD, transformModule],
[ModuleKind.CommonJS, transformModule],
[ModuleKind.UMD, transformModule],
[ModuleKind.None, transformModule],
]);
const enum SyntaxKindFeatureFlags {
Substitution = 1 << 0,
@ -109,7 +109,7 @@ namespace ts {
const transformers: Transformer[] = [];
transformers.push(transformTypeScript);
transformers.push(moduleTransformerMap[moduleKind] || moduleTransformerMap[ModuleKind.None]);
transformers.push(moduleTransformerMap.get(moduleKind) || moduleTransformerMap.get(ModuleKind.None));
if (jsx === JsxEmit.React) {
transformers.push(transformJsx);
@ -339,4 +339,4 @@ namespace ts {
return statements;
}
}
}
}

View File

@ -70,15 +70,15 @@ namespace ts {
* set of labels that occurred inside the converted loop
* used to determine if labeled jump can be emitted as is or it should be dispatched to calling code
*/
labels?: Map<string>;
labels?: Map<string, string>;
/*
* collection of labeled jumps that transfer control outside the converted loop.
* maps store association 'label -> labelMarker' where
* - label - value of label as it appear in code
* - label marker - return value that should be interpreted by calling code as 'jump to <label>'
*/
labeledNonLocalBreaks?: Map<string>;
labeledNonLocalContinues?: Map<string>;
labeledNonLocalBreaks?: Map<string, string>;
labeledNonLocalContinues?: Map<string, string>;
/*
* set of non-labeled jumps that transfer control outside the converted loop
@ -521,7 +521,7 @@ namespace ts {
// - break/continue is non-labeled and located in non-converted loop/switch statement
const jump = node.kind === SyntaxKind.BreakStatement ? Jump.Break : Jump.Continue;
const canUseBreakOrContinue =
(node.label && convertedLoopState.labels && convertedLoopState.labels[node.label.text]) ||
(node.label && convertedLoopState.labels && convertedLoopState.labels.get(node.label.text)) ||
(!node.label && (convertedLoopState.allowedNonLabeledJumps & jump));
if (!canUseBreakOrContinue) {
@ -1849,9 +1849,9 @@ namespace ts {
function visitLabeledStatement(node: LabeledStatement): VisitResult<Statement> {
if (convertedLoopState) {
if (!convertedLoopState.labels) {
convertedLoopState.labels = createMap<string>();
convertedLoopState.labels = new StringMap<string>();
}
convertedLoopState.labels[node.label.text] = node.label.text;
convertedLoopState.labels.set(node.label.text, node.label.text);
}
let result: VisitResult<Statement>;
@ -1863,7 +1863,7 @@ namespace ts {
}
if (convertedLoopState) {
convertedLoopState.labels[node.label.text] = undefined;
convertedLoopState.labels.set(node.label.text, undefined);
}
return result;
@ -2457,29 +2457,28 @@ namespace ts {
function setLabeledJump(state: ConvertedLoopState, isBreak: boolean, labelText: string, labelMarker: string): void {
if (isBreak) {
if (!state.labeledNonLocalBreaks) {
state.labeledNonLocalBreaks = createMap<string>();
state.labeledNonLocalBreaks = new StringMap<string>();
}
state.labeledNonLocalBreaks[labelText] = labelMarker;
state.labeledNonLocalBreaks.set(labelText, labelMarker);
}
else {
if (!state.labeledNonLocalContinues) {
state.labeledNonLocalContinues = createMap<string>();
state.labeledNonLocalContinues = new StringMap<string>();
}
state.labeledNonLocalContinues[labelText] = labelMarker;
state.labeledNonLocalContinues.set(labelText, labelMarker);
}
}
function processLabeledJumps(table: Map<string>, isBreak: boolean, loopResultName: Identifier, outerLoop: ConvertedLoopState, caseClauses: CaseClause[]): void {
function processLabeledJumps(table: Map<string, string>, isBreak: boolean, loopResultName: Identifier, outerLoop: ConvertedLoopState, caseClauses: CaseClause[]): void {
if (!table) {
return;
}
for (const labelText in table) {
const labelMarker = table[labelText];
table.forEach((labelMarker, labelText) => {
const statements: Statement[] = [];
// if there are no outer converted loop or outer label in question is located inside outer converted loop
// then emit labeled break\continue
// otherwise propagate pair 'label -> marker' to outer converted loop and emit 'return labelMarker' so outer loop can later decide what to do
if (!outerLoop || (outerLoop.labels && outerLoop.labels[labelText])) {
if (!outerLoop || (outerLoop.labels && outerLoop.labels.get(labelText))) {
const label = createIdentifier(labelText);
statements.push(isBreak ? createBreak(label) : createContinue(label));
}
@ -2488,7 +2487,7 @@ namespace ts {
statements.push(createReturn(loopResultName));
}
caseClauses.push(createCaseClause(createLiteral(labelMarker), statements));
}
});
}
function processLoopVariableDeclaration(decl: VariableDeclaration | BindingElement, loopParameters: ParameterDeclaration[], loopOutParameters: LoopOutParameter[]) {

View File

@ -217,13 +217,13 @@ namespace ts {
Endfinally = 7,
}
const instructionNames = createMap<string>({
[Instruction.Return]: "return",
[Instruction.Break]: "break",
[Instruction.Yield]: "yield",
[Instruction.YieldStar]: "yield*",
[Instruction.Endfinally]: "endfinally",
});
const instructionNames = new NumberMap<Instruction, string>([
[Instruction.Return, "return"],
[Instruction.Break, "break"],
[Instruction.Yield, "yield"],
[Instruction.YieldStar, "yield*"],
[Instruction.Endfinally, "endfinally"],
]);
export function transformGenerators(context: TransformationContext) {
const {
@ -240,8 +240,8 @@ namespace ts {
context.onSubstituteNode = onSubstituteNode;
let currentSourceFile: SourceFile;
let renamedCatchVariables: Map<boolean>;
let renamedCatchVariableDeclarations: Map<Identifier>;
let renamedCatchVariables: Set<string>;
let renamedCatchVariableDeclarations: Map<number, Identifier>;
let inGeneratorFunctionBody: boolean;
let inStatementContainingYield: boolean;
@ -1907,12 +1907,12 @@ namespace ts {
}
function substituteExpressionIdentifier(node: Identifier) {
if (renamedCatchVariables && hasProperty(renamedCatchVariables, node.text)) {
if (renamedCatchVariables && renamedCatchVariables.has(node.text)) {
const original = getOriginalNode(node);
if (isIdentifier(original) && original.parent) {
const declaration = resolver.getReferencedValueDeclaration(original);
if (declaration) {
const name = getProperty(renamedCatchVariableDeclarations, String(getOriginalNodeId(declaration)));
const name = renamedCatchVariableDeclarations.get(getOriginalNodeId(declaration));
if (name) {
const clone = getMutableClone(name);
setSourceMapRange(clone, node);
@ -2077,13 +2077,13 @@ namespace ts {
const name = declareLocal(text);
if (!renamedCatchVariables) {
renamedCatchVariables = createMap<boolean>();
renamedCatchVariableDeclarations = createMap<Identifier>();
renamedCatchVariables = new StringSet();
renamedCatchVariableDeclarations = new NumberMap<number, Identifier>();
context.enableSubstitution(SyntaxKind.Identifier);
}
renamedCatchVariables[text] = true;
renamedCatchVariableDeclarations[getOriginalNodeId(variable)] = name;
renamedCatchVariables.add(text);
renamedCatchVariableDeclarations.set(getOriginalNodeId(variable), name);
const exception = <ExceptionBlock>peekBlock();
Debug.assert(exception.state < ExceptionBlockState.Catch);
@ -2387,7 +2387,7 @@ namespace ts {
*/
function createInstruction(instruction: Instruction): NumericLiteral {
const literal = createLiteral(instruction);
literal.trailingComment = instructionNames[instruction];
literal.trailingComment = instructionNames.get(instruction);
return literal;
}

View File

@ -3,7 +3,7 @@
/*@internal*/
namespace ts {
const entities: Map<number> = createEntitiesMap();
const entities: Map<string, number> = createEntitiesMap();
export function transformJsx(context: TransformationContext) {
const compilerOptions = context.getCompilerOptions();
@ -227,7 +227,7 @@ namespace ts {
return String.fromCharCode(parseInt(hex, 16));
}
else {
const ch = entities[word];
const ch = entities.get(word);
// If this is not a valid entity, then just use `match` (replace it with itself, i.e. don't replace)
return ch ? String.fromCharCode(ch) : match;
}
@ -275,8 +275,8 @@ namespace ts {
}
}
function createEntitiesMap(): Map<number> {
return createMap<number>({
function createEntitiesMap(): Map<string, number> {
return mapOfMapLike<number>({
"quot": 0x0022,
"amp": 0x0026,
"apos": 0x0027,

View File

@ -4,12 +4,12 @@
/*@internal*/
namespace ts {
export function transformModule(context: TransformationContext) {
const transformModuleDelegates = createMap<(node: SourceFile) => SourceFile>({
[ModuleKind.None]: transformCommonJSModule,
[ModuleKind.CommonJS]: transformCommonJSModule,
[ModuleKind.AMD]: transformAMDModule,
[ModuleKind.UMD]: transformUMDModule,
});
const transformModuleDelegates = new NumberMap<ModuleKind, (node: SourceFile) => SourceFile>([
[ModuleKind.None, transformCommonJSModule],
[ModuleKind.CommonJS, transformCommonJSModule],
[ModuleKind.AMD, transformAMDModule],
[ModuleKind.UMD, transformUMDModule],
]);
const {
startLexicalEnvironment,
@ -35,12 +35,12 @@ namespace ts {
let currentSourceFile: SourceFile;
let externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[];
let exportSpecifiers: Map<ExportSpecifier[]>;
let exportSpecifiers: Map<string, ExportSpecifier[]>;
let exportEquals: ExportAssignment;
let bindingNameExportSpecifiersMap: Map<ExportSpecifier[]>;
let bindingNameExportSpecifiersMap: Map<string, ExportSpecifier[]>;
// Subset of exportSpecifiers that is a binding-name.
// This is to reduce amount of memory we have to keep around even after we done with module-transformer
const bindingNameExportSpecifiersForFileMap = createMap<Map<ExportSpecifier[]>>();
const bindingNameExportSpecifiersForFileMap = new NumberMap<number, Map<string, ExportSpecifier[]>>();
let hasExportStarsToExportValues: boolean;
return transformSourceFile;
@ -62,7 +62,7 @@ namespace ts {
({ externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues } = collectExternalModuleInfo(node, resolver));
// Perform the transformation.
const transformModule = transformModuleDelegates[moduleKind] || transformModuleDelegates[ModuleKind.None];
const transformModule = transformModuleDelegates.get(moduleKind) || transformModuleDelegates.get(ModuleKind.None);
const updated = transformModule(node);
aggregateTransformFlags(updated);
@ -524,7 +524,7 @@ namespace ts {
const original = getOriginalNode(currentSourceFile);
Debug.assert(original.kind === SyntaxKind.SourceFile);
if (!original.symbol.exports["___esModule"]) {
if (!original.symbol.exports.get("___esModule")) {
if (languageVersion === ScriptTarget.ES3) {
statements.push(
createStatement(
@ -579,8 +579,9 @@ namespace ts {
}
function addExportMemberAssignments(statements: Statement[], name: Identifier): void {
if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) {
for (const specifier of exportSpecifiers[name.text]) {
const specifiers = !exportEquals && exportSpecifiers && exportSpecifiers.get(name.text);
if (specifiers) {
for (const specifier of exportSpecifiers.get(name.text)) {
statements.push(
startOnNewLine(
createStatement(
@ -667,12 +668,11 @@ namespace ts {
}
}
else {
if (!exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, name.text)) {
const specifiers = !exportEquals && exportSpecifiers && exportSpecifiers.get(name.text);
if (specifiers) {
const sourceFileId = getOriginalNodeId(currentSourceFile);
if (!bindingNameExportSpecifiersForFileMap[sourceFileId]) {
bindingNameExportSpecifiersForFileMap[sourceFileId] = createMap<ExportSpecifier[]>();
}
bindingNameExportSpecifiersForFileMap[sourceFileId][name.text] = exportSpecifiers[name.text];
const bindingNameExportSpecifiers = getOrUpdate(bindingNameExportSpecifiersForFileMap, sourceFileId, () => new StringMap());
bindingNameExportSpecifiers.set(name.text, exportSpecifiers.get(name.text));
addExportMemberAssignments(resultStatements, name);
}
}
@ -824,7 +824,7 @@ namespace ts {
function onEmitNode(emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void): void {
if (node.kind === SyntaxKind.SourceFile) {
bindingNameExportSpecifiersMap = bindingNameExportSpecifiersForFileMap[getOriginalNodeId(node)];
bindingNameExportSpecifiersMap = bindingNameExportSpecifiersForFileMap.get(getOriginalNodeId(node));
previousOnEmitNode(emitContext, node, emitCallback);
bindingNameExportSpecifiersMap = undefined;
}
@ -890,10 +890,11 @@ namespace ts {
const left = node.left;
// If the left-hand-side of the binaryExpression is an identifier and its is export through export Specifier
if (isIdentifier(left) && isAssignmentOperator(node.operatorToken.kind)) {
if (bindingNameExportSpecifiersMap && hasProperty(bindingNameExportSpecifiersMap, left.text)) {
const bindingNameExportSpecifiers = bindingNameExportSpecifiersMap && bindingNameExportSpecifiersMap.get(left.text);
if (bindingNameExportSpecifiers) {
setEmitFlags(node, EmitFlags.NoSubstitution);
let nestedExportAssignment: BinaryExpression;
for (const specifier of bindingNameExportSpecifiersMap[left.text]) {
for (const specifier of bindingNameExportSpecifiers) {
nestedExportAssignment = nestedExportAssignment ?
createExportAssignment(specifier.name, nestedExportAssignment) :
createExportAssignment(specifier.name, node);
@ -910,7 +911,8 @@ namespace ts {
const operator = node.operator;
const operand = node.operand;
if (isIdentifier(operand) && bindingNameExportSpecifiersForFileMap) {
if (bindingNameExportSpecifiersMap && hasProperty(bindingNameExportSpecifiersMap, operand.text)) {
const bindingNameExportSpecifiers = bindingNameExportSpecifiersMap && bindingNameExportSpecifiersMap.get(operand.text);
if (bindingNameExportSpecifiers) {
setEmitFlags(node, EmitFlags.NoSubstitution);
let transformedUnaryExpression: BinaryExpression;
if (node.kind === SyntaxKind.PostfixUnaryExpression) {
@ -924,7 +926,7 @@ namespace ts {
setEmitFlags(transformedUnaryExpression, EmitFlags.NoSubstitution);
}
let nestedExportAssignment: BinaryExpression;
for (const specifier of bindingNameExportSpecifiersMap[operand.text]) {
for (const specifier of bindingNameExportSpecifiersMap.get(operand.text)) {
nestedExportAssignment = nestedExportAssignment ?
createExportAssignment(specifier.name, nestedExportAssignment) :
createExportAssignment(specifier.name, transformedUnaryExpression || node);

View File

@ -33,7 +33,7 @@ namespace ts {
const exportFunctionForFileMap: Identifier[] = [];
let currentSourceFile: SourceFile;
let externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[];
let exportSpecifiers: Map<ExportSpecifier[]>;
let exportSpecifiers: Map<string, ExportSpecifier[]>;
let exportEquals: ExportAssignment;
let hasExportStarsToExportValues: boolean;
let exportFunctionForFile: Identifier;
@ -273,7 +273,7 @@ namespace ts {
// this set is used to filter names brought by star expors.
// local names set should only be added if we have anything exported
if (!exportedLocalNames && isEmpty(exportSpecifiers)) {
if (!exportedLocalNames && mapIsEmpty(exportSpecifiers)) {
// no exported declarations (export var ...) or export specifiers (export {x})
// check if we have any non star export declarations.
let hasExportDeclarationWithExportClause = false;
@ -1326,20 +1326,20 @@ namespace ts {
}
function collectDependencyGroups(externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]) {
const groupIndices = createMap<number>();
const groupIndices = new StringMap<number>();
const dependencyGroups: DependencyGroup[] = [];
for (let i = 0; i < externalImports.length; i++) {
const externalImport = externalImports[i];
const externalModuleName = getExternalModuleNameLiteral(externalImport, currentSourceFile, host, resolver, compilerOptions);
const text = externalModuleName.text;
if (hasProperty(groupIndices, text)) {
const groupIndex = groupIndices.get(text);
if (groupIndex !== undefined) {
// deduplicate/group entries in dependency list by the dependency name
const groupIndex = groupIndices[text];
dependencyGroups[groupIndex].externalImports.push(externalImport);
continue;
}
else {
groupIndices[text] = dependencyGroups.length;
groupIndices.set(text, dependencyGroups.length);
dependencyGroups.push({
name: externalModuleName,
externalImports: [externalImport]

View File

@ -51,7 +51,7 @@ namespace ts {
let currentNamespace: ModuleDeclaration;
let currentNamespaceContainerName: Identifier;
let currentScope: SourceFile | Block | ModuleBlock | CaseBlock;
let currentScopeFirstDeclarationsOfName: Map<Node>;
let currentScopeFirstDeclarationsOfName: Map<string, Node> | undefined;
let currentSourceFileExternalHelpersModuleName: Identifier;
/**
@ -64,7 +64,7 @@ namespace ts {
* A map that keeps track of aliases created for classes with decorators to avoid issues
* with the double-binding behavior of classes.
*/
let classAliases: Map<Identifier>;
let classAliases: Map<number, Identifier>;
/**
* Keeps track of whether we are within any containing namespaces when performing
@ -706,7 +706,7 @@ namespace ts {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
enableSubstitutionForClassAliases();
classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? node.name.text : "default");
classAliases[getOriginalNodeId(node)] = classAlias;
classAliases.set(getOriginalNodeId(node), classAlias);
}
const declaredName = getDeclarationName(node, /*allowComments*/ true);
@ -790,7 +790,7 @@ namespace ts {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
// record an alias as the class name is not in scope for statics.
enableSubstitutionForClassAliases();
classAliases[getOriginalNodeId(node)] = getSynthesizedClone(temp);
classAliases.set(getOriginalNodeId(node), getSynthesizedClone(temp));
}
// To preserve the behavior of the old emitter, we explicitly indent
@ -2744,12 +2744,10 @@ namespace ts {
const name = node.symbol && node.symbol.name;
if (name) {
if (!currentScopeFirstDeclarationsOfName) {
currentScopeFirstDeclarationsOfName = createMap<Node>();
currentScopeFirstDeclarationsOfName = new StringMap<Node>();
}
if (!(name in currentScopeFirstDeclarationsOfName)) {
currentScopeFirstDeclarationsOfName[name] = node;
}
setIfNotSet(currentScopeFirstDeclarationsOfName, name, node);
}
}
@ -2761,7 +2759,7 @@ namespace ts {
if (currentScopeFirstDeclarationsOfName) {
const name = node.symbol && node.symbol.name;
if (name) {
return currentScopeFirstDeclarationsOfName[name] === node;
return currentScopeFirstDeclarationsOfName.get(name) === node;
}
}
@ -3276,7 +3274,7 @@ namespace ts {
context.enableSubstitution(SyntaxKind.Identifier);
// Keep track of class aliases.
classAliases = createMap<Identifier>();
classAliases = new NumberMap<number, Identifier>();
}
}
@ -3410,7 +3408,7 @@ namespace ts {
// constructor references in static property initializers.
const declaration = resolver.getReferencedValueDeclaration(node);
if (declaration) {
const classAlias = classAliases[declaration.id];
const classAlias = classAliases.get(declaration.id);
if (classAlias) {
const clone = getSynthesizedClone(classAlias);
setSourceMapRange(clone, node);

View File

@ -93,7 +93,7 @@ namespace ts {
return false;
}
try {
ts.localizedDiagnosticMessages = JSON.parse(fileContents);
ts.localizedDiagnosticMessages = mapOfMapLike<string>(JSON.parse(fileContents));
}
catch (e) {
errors.push(createCompilerDiagnostic(Diagnostics.Corrupted_locale_file_0, filePath));
@ -127,11 +127,11 @@ namespace ts {
const gutterSeparator = " ";
const resetEscapeSequence = "\u001b[0m";
const ellipsis = "...";
const categoryFormatMap = createMap<string>({
[DiagnosticCategory.Warning]: yellowForegroundEscapeSequence,
[DiagnosticCategory.Error]: redForegroundEscapeSequence,
[DiagnosticCategory.Message]: blueForegroundEscapeSequence,
});
const categoryFormatMap = new NumberMap<DiagnosticCategory, string>([
[DiagnosticCategory.Warning, yellowForegroundEscapeSequence],
[DiagnosticCategory.Error, redForegroundEscapeSequence],
[DiagnosticCategory.Message, blueForegroundEscapeSequence],
]);
function formatAndReset(text: string, formatStyle: string) {
return formatStyle + text + resetEscapeSequence;
@ -199,7 +199,7 @@ namespace ts {
output += `${ relativeFileName }(${ firstLine + 1 },${ firstLineChar + 1 }): `;
}
const categoryColor = categoryFormatMap[diagnostic.category];
const categoryColor = categoryFormatMap.get(diagnostic.category);
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
output += `${ formatAndReset(category, categoryColor) } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }`;
output += sys.newLine + sys.newLine;
@ -255,7 +255,7 @@ namespace ts {
// This map stores and reuses results of fileExists check that happen inside 'createProgram'
// This allows to save time in module resolution heavy scenarios when existence of the same file might be checked multiple times.
let cachedExistingFiles: Map<boolean>;
let cachedExistingFiles: Map<string, boolean>;
let hostFileExists: typeof compilerHost.fileExists;
if (commandLine.options.locale) {
@ -425,7 +425,7 @@ namespace ts {
}
// reset the cache of existing files
cachedExistingFiles = createMap<boolean>();
cachedExistingFiles = new StringMap<boolean>();
const compileResult = compile(rootFileNames, compilerOptions, compilerHost);
@ -438,9 +438,7 @@ namespace ts {
}
function cachedFileExists(fileName: string): boolean {
return fileName in cachedExistingFiles
? cachedExistingFiles[fileName]
: cachedExistingFiles[fileName] = hostFileExists(fileName);
return getOrUpdate(cachedExistingFiles, fileName, hostFileExists);
}
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void) {
@ -700,7 +698,7 @@ namespace ts {
const usageColumn: string[] = []; // Things like "-d, --declaration" go in here.
const descriptionColumn: string[] = [];
const optionsDescriptionMap = createMap<string[]>(); // Map between option.description and list of option.type if it is a kind
const optionsDescriptionMap = new StringMap<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];
@ -728,11 +726,11 @@ namespace ts {
description = getDiagnosticText(option.description);
const options: string[] = [];
const element = (<CommandLineOptionOfListType>option).element;
const typeMap = <Map<number | string>>element.type;
for (const key in typeMap) {
const typeMap = <Map<string, number | string>>element.type;
forEachKeyInMap(typeMap, key => {
options.push(`'${key}'`);
}
optionsDescriptionMap[description] = options;
});
optionsDescriptionMap.set(description, options);
}
else {
description = getDiagnosticText(option.description);
@ -754,7 +752,7 @@ namespace ts {
for (let i = 0; i < usageColumn.length; i++) {
const usage = usageColumn[i];
const description = descriptionColumn[i];
const kindsList = optionsDescriptionMap[description];
const kindsList = optionsDescriptionMap.get(description);
output.push(usage + makePadding(marginLength - usage.length + 2) + description + sys.newLine);
if (kindsList) {

View File

@ -12,6 +12,7 @@
},
"files": [
"core.ts",
"dataStructures.ts",
"performance.ts",
"sys.ts",
"types.ts",

View File

@ -1,11 +1,42 @@
namespace ts {
/**
* Type of objects whose values are all of the same type.
* The `in` and `for-in` operators can *not* be safely used,
* since `Object.prototype` may be modified by outside code.
*/
export interface MapLike<T> {
[index: string]: T;
}
export interface Map<T> extends MapLike<T> {
__mapBrand: any;
/**
* This contains just the parts of ES6's `Map` interface that we allow.
* Map can only be instantiated using NumberMap and StringMap, which come with shims.
*
* Internet Explorer does not support iterator-returning methods, so those are not allowed here.
* But map-using functions in dataStructures.ts check for these features and use them where possible.
*/
export interface Map<K, V> {
clear(): void;
delete(key: K): void;
forEach(action: (value: V, key: K) => void): void;
get(key: K): V;
/**
* Whether the key is in the map.
* Note: It is better to ask forgiveness than permission. Consider calling `get` and checking if the result is undefined.
*/
has(key: K): boolean;
set(key: K, value: V): void;
}
/**
* This contains just the parts of ES6's `Set` interface that we allow.
*/
export interface Set<T> {
add(value: T): void;
clear(): void;
delete(value: T): void;
forEach(action: (value: T) => void): void;
has(value: T): boolean;
}
// branded string type used to store absolute, normalized and canonicalized paths
@ -1757,7 +1788,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?: Map<string, string>;
/**
* lib.d.ts should have a reference comment like
@ -1777,7 +1808,7 @@ namespace ts {
// The first node that causes this file to be a CommonJS module
/* @internal */ commonJsModuleIndicator: Node;
/* @internal */ identifiers: Map<string>;
/* @internal */ identifiers: Map<string, string>;
/* @internal */ nodeCount: number;
/* @internal */ identifierCount: number;
/* @internal */ symbolCount: number;
@ -1792,12 +1823,12 @@ namespace ts {
// Stores a line map for the file.
// This field should never be used directly to obtain line map, use getLineMap function instead.
/* @internal */ lineMap: number[];
/* @internal */ classifiableNames?: Map<string>;
/* @internal */ classifiableNames?: Set<string>;
// Stores a mapping 'external module reference text' -> 'resolved file name' | undefined
// It is used to resolve module names in the checker.
// Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
/* @internal */ resolvedModules: Map<ResolvedModule>;
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
/* @internal */ resolvedModules: Map<string, ResolvedModule>;
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<string, ResolvedTypeReferenceDirective>;
/* @internal */ imports: LiteralExpression[];
/* @internal */ moduleAugmentations: LiteralExpression[];
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
@ -1881,7 +1912,7 @@ namespace ts {
/* @internal */ getDiagnosticsProducingTypeChecker(): TypeChecker;
/* @internal */ dropDiagnosticsProducingTypeChecker(): void;
/* @internal */ getClassifiableNames(): Map<string>;
/* @internal */ getClassifiableNames(): Set<string>;
/* @internal */ getNodeCount(): number;
/* @internal */ getIdentifierCount(): number;
@ -1889,7 +1920,7 @@ namespace ts {
/* @internal */ getTypeCount(): number;
/* @internal */ getFileProcessingDiagnostics(): DiagnosticCollection;
/* @internal */ getResolvedTypeReferenceDirectives(): Map<ResolvedTypeReferenceDirective>;
/* @internal */ getResolvedTypeReferenceDirectives(): Map<string, ResolvedTypeReferenceDirective>;
// For testing purposes only.
/* @internal */ structureIsReused?: boolean;
}
@ -1950,7 +1981,7 @@ namespace ts {
getSourceFiles(): SourceFile[];
getSourceFile(fileName: string): SourceFile;
getResolvedTypeReferenceDirectives(): Map<ResolvedTypeReferenceDirective>;
getResolvedTypeReferenceDirectives(): Map<string, ResolvedTypeReferenceDirective>;
}
export interface TypeChecker {
@ -2285,7 +2316,7 @@ namespace ts {
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic)
inferredClassType?: Type; // Type of an inferred ES5 class
instantiations?: Map<Type>; // Instantiations of generic type alias (undefined if non-generic)
instantiations?: Map<string, Type>; // Instantiations of generic type alias (undefined if non-generic)
mapper?: TypeMapper; // Type mapper for instantiation alias
referenced?: boolean; // True if alias symbol has been referenced as a value
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
@ -2302,7 +2333,7 @@ namespace ts {
/* @internal */
export interface TransientSymbol extends Symbol, SymbolLinks { }
export type SymbolTable = Map<Symbol>;
export type SymbolTable = Map<string, Symbol>;
/** Represents a "prefix*suffix" pattern. */
/* @internal */
@ -2452,7 +2483,7 @@ namespace ts {
// Enum types (TypeFlags.Enum)
export interface EnumType extends Type {
memberTypes: Map<EnumLiteralType>;
memberTypes: Map<number, EnumLiteralType>;
}
// Enum types (TypeFlags.EnumLiteral)
@ -2501,7 +2532,7 @@ namespace ts {
// Generic class and interface types
export interface GenericType extends InterfaceType, TypeReference {
/* @internal */
instantiations: Map<TypeReference>; // Generic instantiation cache
instantiations: Map<string, TypeReference>; // Generic instantiation cache
}
export interface UnionOrIntersectionType extends Type {
@ -2785,7 +2816,7 @@ namespace ts {
fileNames: string[]; // The file names that belong to the same project.
projectRootPath: string; // The path to the project root directory
safeListPath: string; // The path used to retrieve the safe list
packageNameToTypingLocation: Map<string>; // The map of package names to their cached typing locations
packageNameToTypingLocation: MapLike<string>; // The map of package names to their cached typing locations
typingOptions: TypingOptions; // Used to customize the typing inference process
compilerOptions: CompilerOptions; // Used as a source for typing inference
}
@ -2869,7 +2900,7 @@ namespace ts {
/* @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" | Map<string, 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
@ -2885,7 +2916,7 @@ namespace ts {
/* @internal */
export interface CommandLineOptionOfCustomType extends CommandLineOptionBase {
type: Map<number | string>; // an object literal mapping named values to actual values
type: Map<string, number | string>; // an object literal mapping named values to actual values
}
/* @internal */
@ -3178,7 +3209,7 @@ namespace ts {
flags?: EmitFlags;
commentRange?: TextRange;
sourceMapRange?: TextRange;
tokenSourceMapRanges?: Map<TextRange>;
tokenSourceMapRanges?: Map<SyntaxKind, TextRange>;
annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup.
constantValue?: number;
}

View File

@ -103,27 +103,27 @@ namespace ts {
}
export function hasResolvedModule(sourceFile: SourceFile, moduleNameText: string): boolean {
return !!(sourceFile && sourceFile.resolvedModules && sourceFile.resolvedModules[moduleNameText]);
return !!(sourceFile && sourceFile.resolvedModules && sourceFile.resolvedModules.get(moduleNameText));
}
export function getResolvedModule(sourceFile: SourceFile, moduleNameText: string): ResolvedModule {
return hasResolvedModule(sourceFile, moduleNameText) ? sourceFile.resolvedModules[moduleNameText] : undefined;
return hasResolvedModule(sourceFile, moduleNameText) ? sourceFile.resolvedModules.get(moduleNameText) : undefined;
}
export function setResolvedModule(sourceFile: SourceFile, moduleNameText: string, resolvedModule: ResolvedModule): void {
if (!sourceFile.resolvedModules) {
sourceFile.resolvedModules = createMap<ResolvedModule>();
sourceFile.resolvedModules = new StringMap<ResolvedModule>();
}
sourceFile.resolvedModules[moduleNameText] = resolvedModule;
sourceFile.resolvedModules.set(moduleNameText, resolvedModule);
}
export function setResolvedTypeReferenceDirective(sourceFile: SourceFile, typeReferenceDirectiveName: string, resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective): void {
if (!sourceFile.resolvedTypeReferenceDirectiveNames) {
sourceFile.resolvedTypeReferenceDirectiveNames = createMap<ResolvedTypeReferenceDirective>();
sourceFile.resolvedTypeReferenceDirectiveNames = new StringMap<ResolvedTypeReferenceDirective>();
}
sourceFile.resolvedTypeReferenceDirectiveNames[typeReferenceDirectiveName] = resolvedTypeReferenceDirective;
sourceFile.resolvedTypeReferenceDirectiveNames.set(typeReferenceDirectiveName, resolvedTypeReferenceDirective);
}
/* @internal */
@ -137,13 +137,13 @@ namespace ts {
}
/* @internal */
export function hasChangesInResolutions<T>(names: string[], newResolutions: T[], oldResolutions: Map<T>, comparer: (oldResolution: T, newResolution: T) => boolean): boolean {
export function hasChangesInResolutions<T>(names: string[], newResolutions: T[], oldResolutions: Map<string, T>, comparer: (oldResolution: T, newResolution: T) => boolean): boolean {
if (names.length !== newResolutions.length) {
return false;
}
for (let i = 0; i < names.length; i++) {
const newResolution = newResolutions[i];
const oldResolution = oldResolutions && oldResolutions[names[i]];
const oldResolution = oldResolutions && oldResolutions.get(names[i]);
const changed =
oldResolution
? !newResolution || !comparer(oldResolution, newResolution)
@ -2207,7 +2207,7 @@ namespace ts {
export function createDiagnosticCollection(): DiagnosticCollection {
let nonFileDiagnostics: Diagnostic[] = [];
const fileDiagnostics = createMap<Diagnostic[]>();
const fileDiagnostics = new StringMap<Diagnostic[]>();
let diagnosticsModified = false;
let modificationCount = 0;
@ -2225,11 +2225,12 @@ namespace ts {
}
function reattachFileDiagnostics(newFile: SourceFile): void {
if (!hasProperty(fileDiagnostics, newFile.fileName)) {
const diagnostics = fileDiagnostics.get(newFile.fileName);
if (!diagnostics) {
return;
}
for (const diagnostic of fileDiagnostics[newFile.fileName]) {
for (const diagnostic of diagnostics) {
diagnostic.file = newFile;
}
}
@ -2237,10 +2238,10 @@ namespace ts {
function add(diagnostic: Diagnostic): void {
let diagnostics: Diagnostic[];
if (diagnostic.file) {
diagnostics = fileDiagnostics[diagnostic.file.fileName];
diagnostics = fileDiagnostics.get(diagnostic.file.fileName);
if (!diagnostics) {
diagnostics = [];
fileDiagnostics[diagnostic.file.fileName] = diagnostics;
fileDiagnostics.set(diagnostic.file.fileName, diagnostics);
}
}
else {
@ -2260,7 +2261,7 @@ namespace ts {
function getDiagnostics(fileName?: string): Diagnostic[] {
sortAndDeduplicate();
if (fileName) {
return fileDiagnostics[fileName] || [];
return fileDiagnostics.get(fileName) || [];
}
const allDiagnostics: Diagnostic[] = [];
@ -2270,9 +2271,9 @@ namespace ts {
forEach(nonFileDiagnostics, pushDiagnostic);
for (const key in fileDiagnostics) {
forEach(fileDiagnostics[key], pushDiagnostic);
}
fileDiagnostics.forEach(diagnostics => {
forEach(diagnostics, pushDiagnostic);
});
return sortAndDeduplicateDiagnostics(allDiagnostics);
}
@ -2285,9 +2286,7 @@ namespace ts {
diagnosticsModified = false;
nonFileDiagnostics = sortAndDeduplicateDiagnostics(nonFileDiagnostics);
for (const key in fileDiagnostics) {
fileDiagnostics[key] = sortAndDeduplicateDiagnostics(fileDiagnostics[key]);
}
updateMapValues(fileDiagnostics, sortAndDeduplicateDiagnostics);
}
}
@ -2297,7 +2296,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 = createMap({
const escapedCharsMap = mapOfMapLike({
"\0": "\\0",
"\t": "\\t",
"\v": "\\v",
@ -2324,7 +2323,7 @@ namespace ts {
return s;
function getReplacement(c: string) {
return escapedCharsMap[c] || get16BitUnicodeEscapeSequence(c.charCodeAt(0));
return escapedCharsMap.get(c) || get16BitUnicodeEscapeSequence(c.charCodeAt(0));
}
}
@ -3350,18 +3349,19 @@ namespace ts {
return false;
}
const syntaxKindCache = createMap<string>();
const syntaxKindCache = new NumberMap<SyntaxKind, string>();
export function formatSyntaxKind(kind: SyntaxKind): string {
const syntaxKindEnum = (<any>ts).SyntaxKind;
if (syntaxKindEnum) {
if (syntaxKindCache[kind]) {
return syntaxKindCache[kind];
const cached = syntaxKindCache.get(kind);
if (cached !== undefined) {
return cached;
}
for (const name in syntaxKindEnum) {
if (syntaxKindEnum[name] === kind) {
return syntaxKindCache[kind] = kind.toString() + " (" + name + ")";
return setAndReturn(syntaxKindCache, kind, `${kind}(${name})`);
}
}
}
@ -3498,7 +3498,7 @@ namespace ts {
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver) {
const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = [];
const exportSpecifiers = createMap<ExportSpecifier[]>();
const exportSpecifiers = new StringMap<ExportSpecifier[]>();
let exportEquals: ExportAssignment = undefined;
let hasExportStarsToExportValues = false;
for (const node of sourceFile.statements) {
@ -3539,7 +3539,7 @@ namespace ts {
// export { x, y }
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
const name = (specifier.propertyName || specifier.name).text;
(exportSpecifiers[name] || (exportSpecifiers[name] = [])).push(specifier);
multiMapAdd(exportSpecifiers, name, specifier);
}
}
break;

View File

@ -46,54 +46,54 @@ namespace ts {
* supplant the existing `forEachChild` implementation if performance is not
* significantly impacted.
*/
const nodeEdgeTraversalMap = createMap<NodeTraversalPath>({
[SyntaxKind.QualifiedName]: [
const nodeEdgeTraversalMap = new NumberMap<SyntaxKind, NodeTraversalPath>([
[SyntaxKind.QualifiedName, [
{ name: "left", test: isEntityName },
{ name: "right", test: isIdentifier }
],
[SyntaxKind.Decorator]: [
]],
[SyntaxKind.Decorator, [
{ name: "expression", test: isLeftHandSideExpression }
],
[SyntaxKind.TypeAssertionExpression]: [
]],
[SyntaxKind.TypeAssertionExpression, [
{ name: "type", test: isTypeNode },
{ name: "expression", test: isUnaryExpression }
],
[SyntaxKind.AsExpression]: [
]],
[SyntaxKind.AsExpression, [
{ name: "expression", test: isExpression },
{ name: "type", test: isTypeNode }
],
[SyntaxKind.NonNullExpression]: [
]],
[SyntaxKind.NonNullExpression, [
{ name: "expression", test: isLeftHandSideExpression }
],
[SyntaxKind.EnumDeclaration]: [
]],
[SyntaxKind.EnumDeclaration, [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isIdentifier },
{ name: "members", test: isEnumMember }
],
[SyntaxKind.ModuleDeclaration]: [
]],
[SyntaxKind.ModuleDeclaration, [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isModuleName },
{ name: "body", test: isModuleBody }
],
[SyntaxKind.ModuleBlock]: [
]],
[SyntaxKind.ModuleBlock, [
{ name: "statements", test: isStatement }
],
[SyntaxKind.ImportEqualsDeclaration]: [
]],
[SyntaxKind.ImportEqualsDeclaration, [
{ name: "decorators", test: isDecorator },
{ name: "modifiers", test: isModifier },
{ name: "name", test: isIdentifier },
{ name: "moduleReference", test: isModuleReference }
],
[SyntaxKind.ExternalModuleReference]: [
]],
[SyntaxKind.ExternalModuleReference, [
{ name: "expression", test: isExpression, optional: true }
],
[SyntaxKind.EnumMember]: [
]],
[SyntaxKind.EnumMember, [
{ name: "name", test: isPropertyName },
{ name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList }
]
});
]]
]);
function reduceNode<T>(node: Node, f: (memo: T, node: Node) => T, initial: T) {
return node ? f(initial, node) : initial;
@ -520,7 +520,7 @@ namespace ts {
break;
default:
const edgeTraversalPath = nodeEdgeTraversalMap[kind];
const edgeTraversalPath = nodeEdgeTraversalMap.get(kind);
if (edgeTraversalPath) {
for (const edge of edgeTraversalPath) {
const value = (<MapLike<any>>node)[edge.name];
@ -1141,10 +1141,10 @@ namespace ts {
default:
let updated: Node & MapLike<any>;
const edgeTraversalPath = nodeEdgeTraversalMap[kind];
const edgeTraversalPath = nodeEdgeTraversalMap.get(kind);
if (edgeTraversalPath) {
for (const edge of edgeTraversalPath) {
const value = <Node | NodeArray<Node>>(<Node & Map<any>>node)[edge.name];
const value = <Node | NodeArray<Node>>(<Node & MapLike<any>>node)[edge.name];
if (value !== undefined) {
const visited = isArray(value)
? visitNodes(value, visitor, edge.test, 0, value.length, edge.parenthesize, node)

View File

@ -99,7 +99,7 @@ namespace FourSlash {
export import IndentStyle = ts.IndentStyle;
const entityMap = ts.createMap({
const entityMap = ts.mapOfMapLike({
"&": "&amp;",
"\"": "&quot;",
"'": "&#39;",
@ -109,7 +109,7 @@ namespace FourSlash {
});
export function escapeXmlAttributeValue(s: string) {
return s.replace(/[&<>"'\/]/g, ch => entityMap[ch]);
return s.replace(/[&<>"'\/]/g, ch => entityMap.get(ch));
}
// Name of testcase metadata including ts.CompilerOptions properties that will be used by globalOptions
@ -208,7 +208,7 @@ namespace FourSlash {
public formatCodeSettings: ts.FormatCodeSettings;
private inputFiles = ts.createMap<string>(); // Map between inputFile's fileName and its content for easily looking up when resolving references
private inputFiles = new ts.StringMap<string>(); // Map between inputFile's fileName and its content for easily looking up when resolving references
private static getDisplayPartsJson(displayParts: ts.SymbolDisplayPart[]) {
let result = "";
@ -241,7 +241,7 @@ namespace FourSlash {
}
function tryAdd(path: string) {
const inputFile = inputFiles[path];
const inputFile = inputFiles.get(path);
if (inputFile && !Harness.isDefaultLibraryFile(path)) {
languageServiceAdapterHost.addScript(path, inputFile, /*isRootFile*/ true);
return true;
@ -275,7 +275,7 @@ namespace FourSlash {
ts.forEach(testData.files, file => {
// Create map between fileName and its content for easily looking up when resolveReference flag is specified
this.inputFiles[file.fileName] = file.content;
this.inputFiles.set(file.fileName, file.content);
if (ts.getBaseFileName(file.fileName).toLowerCase() === "tsconfig.json") {
const configJson = ts.parseConfigFileTextToJson(file.fileName, file.content);
@ -341,11 +341,11 @@ namespace FourSlash {
}
else {
// resolveReference file-option is not specified then do not resolve any files and include all inputFiles
for (const fileName in this.inputFiles) {
this.inputFiles.forEach((inputFile, fileName) => {
if (!Harness.isDefaultLibraryFile(fileName)) {
this.languageServiceAdapterHost.addScript(fileName, this.inputFiles[fileName], /*isRootFile*/ true);
this.languageServiceAdapterHost.addScript(fileName, inputFile, /*isRootFile*/ true);
}
}
});
this.languageServiceAdapterHost.addScript(Harness.Compiler.defaultLibFileName,
Harness.Compiler.getDefaultLibrarySourceFile().text, /*isRootFile*/ false);
}
@ -697,13 +697,10 @@ namespace FourSlash {
public noItemsWithSameNameButDifferentKind(): void {
const completions = this.getCompletionListAtCaret();
const uniqueItems = ts.createMap<string>();
const uniqueItems = new ts.StringMap<string>();
for (const item of completions.entries) {
if (!(item.name in uniqueItems)) {
uniqueItems[item.name] = item.kind;
}
else {
assert.equal(item.kind, uniqueItems[item.name], `Items should have the same kind, got ${item.kind} and ${uniqueItems[item.name]}`);
if (!ts.setIfNotSet(uniqueItems, item.name, item.kind)) {
assert.equal(item.kind, uniqueItems.get(item.name), `Items should have the same kind, got ${item.kind} and ${uniqueItems.get(item.name)}`);
}
}
}
@ -895,7 +892,7 @@ namespace FourSlash {
}
public verifyRangesWithSameTextReferenceEachOther() {
ts.forEachProperty(this.rangesByText(), ranges => this.verifyRangesReferenceEachOther(ranges));
this.rangesByTextMap().forEach(ranges => this.verifyRangesReferenceEachOther(ranges));
}
public verifyDisplayPartsOfReferencedSymbol(expected: ts.SymbolDisplayPart[]) {
@ -972,7 +969,8 @@ namespace FourSlash {
}
public verifyQuickInfos(namesAndTexts: { [name: string]: string | [string, string] }) {
ts.forEachProperty(ts.createMap(namesAndTexts), (text, name) => {
for (const name in namesAndTexts) {
const text = namesAndTexts[name];
if (text instanceof Array) {
assert(text.length === 2);
const [expectedText, expectedDocumentation] = text;
@ -981,7 +979,7 @@ namespace FourSlash {
else {
this.verifyQuickInfoAt(name, text);
}
});
}
}
public verifyQuickInfoString(expectedText: string, expectedDocumentation?: string) {
@ -1818,8 +1816,8 @@ namespace FourSlash {
return this.testData.ranges;
}
public rangesByText(): ts.Map<Range[]> {
const result = ts.createMap<Range[]>();
private rangesByTextMap(): ts.Map<string, Range[]> {
const result = new ts.StringMap<Range[]>();
for (const range of this.getRanges()) {
const text = this.rangeText(range);
ts.multiMapAdd(result, text, range);
@ -1827,6 +1825,10 @@ namespace FourSlash {
return result;
}
public rangesByText(): ts.MapLike<Range[]> {
return ts.mapLikeOfMap(this.rangesByTextMap());
}
private rangeText({fileName, start, end}: Range, more = false): string {
return this.getFileContent(fileName).slice(start, end);
}
@ -2073,7 +2075,7 @@ namespace FourSlash {
public verifyBraceCompletionAtPosition(negative: boolean, openingBrace: string) {
const openBraceMap = ts.createMap<ts.CharacterCodes>({
const openBraceMap = ts.mapOfMapLike<ts.CharacterCodes>({
"(": ts.CharacterCodes.openParen,
"{": ts.CharacterCodes.openBrace,
"[": ts.CharacterCodes.openBracket,
@ -2083,7 +2085,7 @@ namespace FourSlash {
"<": ts.CharacterCodes.lessThan
});
const charCode = openBraceMap[openingBrace];
const charCode = openBraceMap.get(openingBrace);
if (!charCode) {
this.raiseError(`Invalid openingBrace '${openingBrace}' specified.`);
@ -2950,7 +2952,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

@ -925,19 +925,18 @@ namespace Harness {
export const defaultLibFileName = "lib.d.ts";
export const es2015DefaultLibFileName = "lib.es2015.d.ts";
const libFileNameSourceFileMap = ts.createMap<ts.SourceFile>({
[defaultLibFileName]: createSourceFileAndAssertInvariants(defaultLibFileName, IO.readFile(libFolder + "lib.es5.d.ts"), /*languageVersion*/ ts.ScriptTarget.Latest)
});
const libFileNameSourceFileMap = ts.createMapWithEntry<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)) {
return undefined;
}
if (!libFileNameSourceFileMap[fileName]) {
libFileNameSourceFileMap[fileName] = createSourceFileAndAssertInvariants(fileName, IO.readFile(libFolder + fileName), ts.ScriptTarget.Latest);
if (!libFileNameSourceFileMap.get(fileName)) {
libFileNameSourceFileMap.set(fileName, createSourceFileAndAssertInvariants(fileName, IO.readFile(libFolder + fileName), ts.ScriptTarget.Latest));
}
return libFileNameSourceFileMap[fileName];
return libFileNameSourceFileMap.get(fileName);
}
export function getDefaultLibFileName(options: ts.CompilerOptions): string {
@ -1079,16 +1078,16 @@ namespace Harness {
{ name: "symlink", type: "string" }
];
let optionsIndex: ts.Map<ts.CommandLineOption>;
let optionsIndex: ts.Map<string, ts.CommandLineOption>;
function getCommandLineOption(name: string): ts.CommandLineOption {
if (!optionsIndex) {
optionsIndex = ts.createMap<ts.CommandLineOption>();
optionsIndex = new ts.StringMap<ts.CommandLineOption>();
const optionDeclarations = harnessOptionDeclarations.concat(ts.optionDeclarations);
for (const option of optionDeclarations) {
optionsIndex[option.name.toLowerCase()] = option;
optionsIndex.set(option.name.toLowerCase(), option);
}
}
return optionsIndex[name.toLowerCase()];
return optionsIndex.get(name.toLowerCase());
}
export function setCompilerOptionsFromHarnessSetting(settings: Harness.TestCaseParser.CompilerSettings, options: ts.CompilerOptions & HarnessOptions): void {
@ -1439,10 +1438,10 @@ namespace Harness {
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
const fullResults = ts.createMap<TypeWriterResult[]>();
const fullResults = new ts.StringMap<TypeWriterResult[]>();
for (const sourceFile of allFiles) {
fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
fullResults.set(sourceFile.unitName, fullWalker.getTypeAndSymbols(sourceFile.unitName));
}
// Produce baselines. The first gives the types for all expressions.
@ -1489,13 +1488,13 @@ namespace Harness {
Harness.Baseline.runBaseline(outputFileName, () => fullBaseLine, opts);
}
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
function generateBaseLine(typeWriterResults: ts.Map<string, TypeWriterResult[]>, isSymbolBaseline: boolean): string {
const typeLines: string[] = [];
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
allFiles.forEach(file => {
const codeLines = file.content.split("\n");
typeWriterResults[file.unitName].forEach(result => {
typeWriterResults.get(file.unitName).forEach(result => {
if (isSymbolBaseline && !result.symbol) {
return;
}

View File

@ -262,7 +262,7 @@ namespace Harness.LanguageService {
this.getModuleResolutionsForFile = (fileName) => {
const scriptInfo = this.getScriptInfo(fileName);
const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ true);
const imports = ts.createMap<string>();
const imports: ts.MapLike<string> = {};
for (const module of preprocessInfo.importedFiles) {
const resolutionInfo = ts.resolveModuleName(module.fileName, fileName, compilerOptions, moduleResolutionHost);
if (resolutionInfo.resolvedModule) {
@ -275,7 +275,7 @@ namespace Harness.LanguageService {
const scriptInfo = this.getScriptInfo(fileName);
if (scriptInfo) {
const preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ false);
const resolutions = ts.createMap<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

@ -91,13 +91,11 @@ namespace Playback {
}
function memoize<T>(func: (s: string) => T): Memoized<T> {
let lookup: { [s: string]: T } = {};
const run: Memoized<T> = <Memoized<T>>((s: string) => {
if (lookup.hasOwnProperty(s)) return lookup[s];
return lookup[s] = func(s);
});
const lookup = new ts.StringMap<T>();
const run: Memoized<T> = <Memoized<T>>((s: string) =>
ts.getOrUpdateAndAllowUndefined(lookup, s, func));
run.reset = () => {
lookup = undefined;
lookup.clear();
};
return run;

View File

@ -256,17 +256,20 @@ class ProjectRunner extends RunnerBase {
// Set the values specified using json
const optionNameMap = ts.arrayToMap(ts.optionDeclarations, option => option.name);
for (const name in testCase) {
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 (key in optType) {
value = optType[key];
if (name !== "mapRoot" && name !== "sourceRoot") {
const option = optionNameMap.get(name);
if (option !== undefined) {
const optType = option.type;
let value = <any>testCase[name];
if (typeof optType !== "string") {
const key = value.toLowerCase();
const translation = optType.get(key);
if (translation !== undefined) {
value = translation;
}
}
compilerOptions[option.name] = value;
}
compilerOptions[option.name] = value;
}
}

View File

@ -6,17 +6,17 @@ namespace ts {
content: string;
}
function createDefaultServerHost(fileMap: Map<File>): server.ServerHost {
const existingDirectories = createMap<boolean>();
for (const name in fileMap) {
function createDefaultServerHost(fileMap: Map<string, File>): server.ServerHost {
const existingDirectories = new StringSet();
forEachKeyInMap(fileMap, name => {
let dir = getDirectoryPath(name);
let previous: string;
do {
existingDirectories[dir] = true;
existingDirectories.add(dir);
previous = dir;
dir = getDirectoryPath(dir);
} while (dir !== previous);
}
});
return {
args: <string[]>[],
newLine: "\r\n",
@ -24,7 +24,8 @@ namespace ts {
write: (s: string) => {
},
readFile: (path: string, encoding?: string): string => {
return path in fileMap ? fileMap[path].content : undefined;
const file = fileMap.get(path);
return file !== undefined ? file.content : undefined;
},
writeFile: (path: string, data: string, writeByteOrderMark?: boolean) => {
throw new Error("NYI");
@ -33,10 +34,10 @@ namespace ts {
throw new Error("NYI");
},
fileExists: (path: string): boolean => {
return path in fileMap;
return fileMap.has(path);
},
directoryExists: (path: string): boolean => {
return existingDirectories[path] || false;
return existingDirectories.has(path);
},
createDirectory: (path: string) => {
},
@ -105,7 +106,7 @@ namespace ts {
content: `foo()`
};
const serverHost = createDefaultServerHost(createMap({ [root.name]: root, [imported.name]: imported }));
const serverHost = createDefaultServerHost(mapOfMapLike({ [root.name]: root, [imported.name]: imported }));
const { project, rootScriptInfo } = createProject(root.name, serverHost);
// ensure that imported file was found
@ -192,7 +193,7 @@ namespace ts {
content: `export var y = 1`
};
const fileMap = createMap({ [root.name]: root });
const fileMap = mapOfMapLike({ [root.name]: root });
const serverHost = createDefaultServerHost(fileMap);
const originalFileExists = serverHost.fileExists;
@ -216,7 +217,7 @@ namespace ts {
assert.isTrue(typeof diags[0].messageText === "string" && ((<string>diags[0].messageText).indexOf("Cannot find module") === 0), "should be 'cannot find module' message");
// assert that import will success once file appear on disk
fileMap[imported.name] = imported;
fileMap.set(imported.name, imported);
fileExistsCalledForBar = false;
rootScriptInfo.editContent(0, root.content.length, `import {y} from "bar"`);

View File

@ -10,11 +10,11 @@ namespace ts {
const map = arrayToMap(files, f => f.name);
if (hasDirectoryExists) {
const directories = createMap<string>();
const directories = new StringSet();
for (const f of files) {
let name = getDirectoryPath(f.name);
while (true) {
directories[name] = name;
directories.add(name);
const baseName = getDirectoryPath(name);
if (baseName === name) {
break;
@ -24,20 +24,19 @@ namespace ts {
}
return {
readFile,
directoryExists: path => {
return path in directories;
},
directoryExists: path => directories.has(path),
fileExists: path => {
assert.isTrue(getDirectoryPath(path) in directories, `'fileExists' '${path}' request in non-existing directory`);
return path in map;
assert.isTrue(directories.has(getDirectoryPath(path)), `'fileExists' '${path}' request in non-existing directory`);
return map.has(path);
}
};
}
else {
return { readFile, fileExists: path => path in map, };
return { readFile, fileExists: path => map.has(path) };
}
function readFile(path: string): string {
return path in map ? map[path].content : undefined;
const file = map.get(path);
return file !== undefined ? file.content : undefined;
}
}
@ -282,12 +281,13 @@ namespace ts {
});
describe("Module resolution - relative imports", () => {
function test(files: Map<string>, currentDirectory: string, rootFiles: string[], expectedFilesCount: number, relativeNamesToCheck: string[]) {
function test(files: Map<string, 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 path in files ? createSourceFile(fileName, files[path], languageVersion) : undefined;
const file = files.get(path);
return file !== undefined ? createSourceFile(fileName, file, 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 path in files;
return files.has(path);
},
readFile: (fileName): string => { throw new Error("NotImplemented"); }
};
@ -318,7 +318,7 @@ namespace ts {
}
it("should find all modules", () => {
const files = createMap({
const files = mapOfMapLike({
"/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 = createMap({
const files = mapOfMapLike({
"/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 = createMap({
const files = mapOfMapLike({
"/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: Map<string, string>, options: CompilerOptions, currentDirectory: string, useCaseSensitiveFileNames: boolean, rootFiles: string[], diagnosticCodes: number[]): void {
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
if (!useCaseSensitiveFileNames) {
files = reduceProperties(files, (files, file, fileName) => (files[getCanonicalFileName(fileName)] = file, files), createMap<string>());
files = transformKeys(files, getCanonicalFileName);
}
const host: CompilerHost = {
@ -367,7 +367,8 @@ export = C;
return library;
}
const path = getCanonicalFileName(normalizePath(combinePaths(currentDirectory, fileName)));
return path in files ? createSourceFile(fileName, files[path], languageVersion) : undefined;
const file = files.get(path);
return file !== undefined ? createSourceFile(fileName, file, languageVersion) : undefined;
},
getDefaultLibFileName: () => "lib.d.ts",
writeFile: (fileName, content): void => { throw new Error("NotImplemented"); },
@ -378,7 +379,7 @@ export = C;
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
fileExists: fileName => {
const path = getCanonicalFileName(normalizePath(combinePaths(currentDirectory, fileName)));
return path in files;
return files.has(path);
},
readFile: (fileName): string => { throw new Error("NotImplemented"); }
};
@ -391,7 +392,7 @@ export = C;
}
it("should succeed when the same file is referenced using absolute and relative names", () => {
const files = createMap({
const files = mapOfMapLike({
"/a/b/c.ts": `/// <reference path="d.ts"/>`,
"/a/b/d.ts": "var x"
});
@ -399,7 +400,7 @@ export = C;
});
it("should fail when two files used in program differ only in casing (tripleslash references)", () => {
const files = createMap({
const files = mapOfMapLike({
"/a/b/c.ts": `/// <reference path="D.ts"/>`,
"/a/b/d.ts": "var x"
});
@ -407,7 +408,7 @@ export = C;
});
it("should fail when two files used in program differ only in casing (imports)", () => {
const files = createMap({
const files = mapOfMapLike({
"/a/b/c.ts": `import {x} from "D"`,
"/a/b/d.ts": "export var x"
});
@ -415,7 +416,7 @@ export = C;
});
it("should fail when two files used in program differ only in casing (imports, relative module names)", () => {
const files = createMap({
const files = mapOfMapLike({
"moduleA.ts": `import {x} from "./ModuleB"`,
"moduleB.ts": "export var x"
});
@ -423,7 +424,7 @@ export = C;
});
it("should fail when two files exist on disk that differs only in casing", () => {
const files = createMap({
const files = mapOfMapLike({
"/a/b/c.ts": `import {x} from "D"`,
"/a/b/D.ts": "export var x",
"/a/b/d.ts": "export var y"
@ -432,7 +433,7 @@ export = C;
});
it("should fail when module name in 'require' calls has inconsistent casing", () => {
const files = createMap({
const files = mapOfMapLike({
"moduleA.ts": `import a = require("./ModuleC")`,
"moduleB.ts": `import a = require("./moduleC")`,
"moduleC.ts": "export var x"
@ -441,7 +442,7 @@ export = C;
});
it("should fail when module names in 'require' calls has inconsistent casing and current directory has uppercase chars", () => {
const files = createMap({
const files = mapOfMapLike({
"/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,7 +454,7 @@ import b = require("./moduleB");
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 = createMap({
const files = mapOfMapLike({
"/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",
@ -1019,8 +1020,8 @@ import b = require("./moduleB");
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 => fileName in sourceFiles,
getSourceFile: fileName => sourceFiles[fileName],
fileExists : fileName => sourceFiles.has(fileName),
getSourceFile: fileName => sourceFiles.get(fileName),
getDefaultLibFileName: () => "lib.d.ts",
writeFile(file, text) {
throw new Error("NYI");
@ -1030,7 +1031,10 @@ import b = require("./moduleB");
getCanonicalFileName: f => f.toLowerCase(),
getNewLine: () => "\r\n",
useCaseSensitiveFileNames: () => false,
readFile: fileName => fileName in sourceFiles ? sourceFiles[fileName].text : undefined
readFile: fileName => {
const file = sourceFiles.get(fileName);
return file !== undefined ? file.text : undefined;
}
};
const program1 = createProgram(names, {}, compilerHost);
const diagnostics1 = program1.getFileProcessingDiagnostics().getDiagnostics();

View File

@ -106,7 +106,7 @@ namespace ts {
return {
getSourceFile(fileName): SourceFile {
return files[fileName];
return files.get(fileName);
},
getDefaultLibFileName(): string {
return "lib.d.ts";
@ -129,9 +129,10 @@ namespace ts {
getNewLine(): string {
return sys ? sys.newLine : newLine;
},
fileExists: fileName => fileName in files,
fileExists: fileName => files.has(fileName),
readFile: fileName => {
return fileName in files ? files[fileName].text : undefined;
const file = files.get(fileName);
return file !== undefined ? file.text : undefined;
}
};
}
@ -174,7 +175,7 @@ namespace ts {
return false;
}
function checkCache<T>(caption: string, program: Program, fileName: string, expectedContent: Map<T>, getCache: (f: SourceFile) => Map<T>, entryChecker: (expected: T, original: T) => boolean): void {
function checkCache<T>(caption: string, program: Program, fileName: string, expectedContent: Map<string, T>, getCache: (f: SourceFile) => Map<string, 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,15 +184,15 @@ namespace ts {
}
else {
assert.isTrue(cache !== undefined, `expected ${caption} to be set`);
assert.isTrue(equalOwnProperties(expectedContent, cache, entryChecker), `contents of ${caption} did not match the expected contents.`);
assert.isTrue(mapsAreEqual(expectedContent, cache, entryChecker), `contents of ${caption} did not match the expected contents.`);
}
}
function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: Map<ResolvedModule>): void {
function checkResolvedModulesCache(program: Program, fileName: string, expectedContent: Map<string, 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: Map<string, ResolvedTypeReferenceDirective>): void {
checkCache("resolved type directives", program, fileName, expectedContent, f => f.resolvedTypeReferenceDirectiveNames, checkResolvedTypeDirective);
}
@ -306,7 +307,7 @@ namespace ts {
const options: CompilerOptions = { target };
const program_1 = newProgram(files, ["a.ts"], options);
checkResolvedModulesCache(program_1, "a.ts", createMap({ "b": { resolvedFileName: "b.ts" } }));
checkResolvedModulesCache(program_1, "a.ts", mapOfMapLike({ "b": { resolvedFileName: "b.ts" } }));
checkResolvedModulesCache(program_1, "b.ts", undefined);
const program_2 = updateProgram(program_1, ["a.ts"], options, files => {
@ -315,7 +316,7 @@ namespace ts {
assert.isTrue(program_1.structureIsReused);
// content of resolution cache should not change
checkResolvedModulesCache(program_1, "a.ts", createMap({ "b": { resolvedFileName: "b.ts" } }));
checkResolvedModulesCache(program_1, "a.ts", mapOfMapLike({ "b": { resolvedFileName: "b.ts" } }));
checkResolvedModulesCache(program_1, "b.ts", undefined);
// imports has changed - program is not reused
@ -332,7 +333,7 @@ namespace ts {
files[0].text = files[0].text.updateImportsAndExports(newImports);
});
assert.isTrue(!program_3.structureIsReused);
checkResolvedModulesCache(program_4, "a.ts", createMap({ "b": { resolvedFileName: "b.ts" }, "c": undefined }));
checkResolvedModulesCache(program_4, "a.ts", mapOfMapLike({ "b": { resolvedFileName: "b.ts" }, "c": undefined }));
});
it("resolved type directives cache follows type directives", () => {
@ -343,7 +344,7 @@ namespace ts {
const options: CompilerOptions = { target, typeRoots: ["/types"] };
const program_1 = newProgram(files, ["/a.ts"], options);
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMap({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
checkResolvedTypeDirectivesCache(program_1, "/a.ts", mapOfMapLike({ "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 => {
@ -352,7 +353,7 @@ namespace ts {
assert.isTrue(program_1.structureIsReused);
// content of resolution cache should not change
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMap({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
checkResolvedTypeDirectivesCache(program_1, "/a.ts", mapOfMapLike({ "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
@ -370,7 +371,7 @@ namespace ts {
files[0].text = files[0].text.updateReferences(newReferences);
});
assert.isTrue(!program_3.structureIsReused);
checkResolvedTypeDirectivesCache(program_1, "/a.ts", createMap({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
checkResolvedTypeDirectivesCache(program_1, "/a.ts", mapOfMapLike({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
});
});

View File

@ -112,9 +112,6 @@ namespace ts.server {
it("should not throw when commands are executed with invalid arguments", () => {
let i = 0;
for (const name in CommandNames) {
if (!Object.prototype.hasOwnProperty.call(CommandNames, name)) {
continue;
}
const req: protocol.Request = {
command: name,
seq: i,
@ -367,15 +364,15 @@ namespace ts.server {
class InProcClient {
private server: InProcSession;
private seq = 0;
private callbacks = createMap<(resp: protocol.Response) => void>();
private eventHandlers = createMap<(args: any) => void>();
private callbacks = new NumberMap<number, (resp: protocol.Response) => void>();
private eventHandlers = new StringMap<(args: any) => void>();
handle(msg: protocol.Message): void {
if (msg.type === "response") {
const response = <protocol.Response>msg;
if (response.request_seq in this.callbacks) {
this.callbacks[response.request_seq](response);
delete this.callbacks[response.request_seq];
const callback = tryDelete(this.callbacks, response.request_seq);
if (callback !== undefined) {
callback(response);
}
}
else if (msg.type === "event") {
@ -385,13 +382,14 @@ namespace ts.server {
}
emit(name: string, args: any): void {
if (name in this.eventHandlers) {
this.eventHandlers[name](args);
const handler = this.eventHandlers.get(name);
if (handler !== undefined) {
handler(args);
}
}
on(name: string, handler: (args: any) => void): void {
this.eventHandlers[name] = handler;
this.eventHandlers.set(name, handler);
}
connect(session: InProcSession): void {
@ -409,7 +407,7 @@ namespace ts.server {
command,
arguments: args
});
this.callbacks[this.seq] = callback;
this.callbacks.set(this.seq, callback);
}
};

View File

@ -238,10 +238,10 @@ namespace ts.projectSystem {
return entry;
}
export function checkMapKeys(caption: string, map: Map<any>, expectedKeys: string[]) {
assert.equal(reduceProperties(map, count => count + 1, 0), expectedKeys.length, `${caption}: incorrect size of map`);
export function checkMapKeys(caption: string, map: Map<string, any>, expectedKeys: string[]) {
assert.equal(mapSize(map), expectedKeys.length, `${caption}: incorrect size of map`);
for (const name of expectedKeys) {
assert.isTrue(name in map, `${caption} is expected to contain ${name}, actual keys: ${Object.keys(map)}`);
assert.isTrue(map.has(name), `${caption} is expected to contain ${name}, actual keys: ${keysOfMap(map)}`);
}
}
@ -287,38 +287,28 @@ namespace ts.projectSystem {
}
export class Callbacks {
private map: { [n: number]: TimeOutCallback } = {};
private map = new NumberMap<number, TimeOutCallback>();
private nextId = 1;
register(cb: (...args: any[]) => void, args: any[]) {
const timeoutId = this.nextId;
this.nextId++;
this.map[timeoutId] = cb.bind(undefined, ...args);
this.map.set(timeoutId, cb.bind(undefined, ...args));
return timeoutId;
}
unregister(id: any) {
if (typeof id === "number") {
delete this.map[id];
this.map.delete(id);
}
}
count() {
let n = 0;
/* tslint:disable:no-unused-variable */
for (const _ in this.map) {
/* tslint:enable:no-unused-variable */
n++;
}
return n;
return mapSize(this.map);
}
invoke() {
for (const id in this.map) {
if (hasProperty(this.map, id)) {
this.map[id]();
}
}
this.map = {};
this.map.forEach(callback => { callback(); });
this.map.clear();
}
}
@ -334,8 +324,9 @@ namespace ts.projectSystem {
private timeoutCallbacks = new Callbacks();
private immediateCallbacks = new Callbacks();
readonly watchedDirectories = createMap<{ cb: DirectoryWatcherCallback, recursive: boolean }[]>();
readonly watchedFiles = createMap<FileWatcherCallback[]>();
readonly watchedDirectories = new StringMap<{ cb: DirectoryWatcherCallback, recursive: boolean }[]>();
readonly watchedFiles = new StringMap<FileWatcherCallback[]>();
private filesOrFolders: FileOrFolder[];
@ -430,7 +421,7 @@ namespace ts.projectSystem {
triggerDirectoryWatcherCallback(directoryName: string, fileName: string): void {
const path = this.toPath(directoryName);
const callbacks = this.watchedDirectories[path];
const callbacks = this.watchedDirectories.get(path);
if (callbacks) {
for (const callback of callbacks) {
callback.cb(fileName);
@ -440,7 +431,7 @@ namespace ts.projectSystem {
triggerFileWatcherCallback(fileName: string, removed?: boolean): void {
const path = this.toPath(fileName);
const callbacks = this.watchedFiles[path];
const callbacks = this.watchedFiles.get(path);
if (callbacks) {
for (const callback of callbacks) {
callback(path, removed);
@ -2084,7 +2075,7 @@ namespace ts.projectSystem {
const projectFileName = "externalProject";
const host = createServerHost([f]);
const projectService = createProjectService(host);
// create a project
// create a project
projectService.openExternalProject({ projectFileName, rootFiles: [toExternalFile(f.path)], options: {} });
projectService.checkNumberOfProjects({ externalProjects: 1 });

View File

@ -347,25 +347,26 @@ namespace ts.server {
// Use slice to clone the array to avoid manipulating in place
const queue = fileInfo.referencedBy.slice(0);
const fileNameSet = createMap<ScriptInfo>();
fileNameSet[scriptInfo.fileName] = scriptInfo;
const fileNameSet = new StringMap<ScriptInfo>();
fileNameSet.set(scriptInfo.fileName, scriptInfo);
while (queue.length > 0) {
const processingFileInfo = queue.pop();
if (processingFileInfo.updateShapeSignature() && processingFileInfo.referencedBy.length > 0) {
for (const potentialFileInfo of processingFileInfo.referencedBy) {
if (!fileNameSet[potentialFileInfo.scriptInfo.fileName]) {
if (!fileNameSet.get(potentialFileInfo.scriptInfo.fileName)) {
queue.push(potentialFileInfo);
}
}
}
fileNameSet[processingFileInfo.scriptInfo.fileName] = processingFileInfo.scriptInfo;
fileNameSet.set(processingFileInfo.scriptInfo.fileName, processingFileInfo.scriptInfo);
}
const result: string[] = [];
for (const fileName in fileNameSet) {
if (shouldEmitFile(fileNameSet[fileName])) {
fileNameSet.forEach((scriptInfo, fileName) => {
if (shouldEmitFile(scriptInfo)) {
result.push(fileName);
}
}
});
return result;
}
}

View File

@ -21,7 +21,7 @@ namespace ts.server {
export class SessionClient implements LanguageService {
private sequence: number = 0;
private lineMaps: ts.Map<number[]> = ts.createMap<number[]>();
private lineMaps = new ts.StringMap<number[]>();
private messages: string[] = [];
private lastRenameEntry: RenameEntry;
@ -37,10 +37,10 @@ namespace ts.server {
}
private getLineMap(fileName: string): number[] {
let lineMap = this.lineMaps[fileName];
let lineMap = this.lineMaps.get(fileName);
if (!lineMap) {
const scriptSnapshot = this.host.getScriptSnapshot(fileName);
lineMap = this.lineMaps[fileName] = ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength()));
lineMap = setAndReturn(this.lineMaps, fileName, ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength())));
}
return lineMap;
}
@ -146,7 +146,7 @@ namespace ts.server {
changeFile(fileName: string, start: number, end: number, newText: string): void {
// clear the line map after an edit
this.lineMaps[fileName] = undefined;
this.lineMaps.set(fileName, undefined);
const lineOffset = this.positionToOneBasedLineOffset(fileName, start);
const endLineOffset = this.positionToOneBasedLineOffset(fileName, end);

View File

@ -98,23 +98,24 @@ namespace ts.server {
/**
* a path to directory watcher map that detects added tsconfig files
**/
private readonly directoryWatchersForTsconfig: Map<FileWatcher> = createMap<FileWatcher>();
private readonly directoryWatchersForTsconfig = new StringMap<FileWatcher>();
/**
* count of how many projects are using the directory watcher.
* If the number becomes 0 for a watcher, then we should close it.
**/
private readonly directoryWatchersRefCount: Map<number> = createMap<number>();
private readonly directoryWatchersRefCount = new StringMap<number>();
constructor(private readonly projectService: ProjectService) {
}
stopWatchingDirectory(directory: string) {
// if the ref count for this directory watcher drops to 0, it's time to close it
this.directoryWatchersRefCount[directory]--;
if (this.directoryWatchersRefCount[directory] === 0) {
const refCount = this.directoryWatchersRefCount.get(directory) - 1;
this.directoryWatchersRefCount.set(directory, refCount);
if (refCount === 0) {
this.projectService.logger.info(`Close directory watcher for: ${directory}`);
this.directoryWatchersForTsconfig[directory].close();
delete this.directoryWatchersForTsconfig[directory];
this.directoryWatchersForTsconfig.get(directory).close();
this.directoryWatchersForTsconfig.delete(directory);
}
}
@ -122,13 +123,13 @@ namespace ts.server {
let currentPath = getDirectoryPath(fileName);
let parentPath = getDirectoryPath(currentPath);
while (currentPath != parentPath) {
if (!this.directoryWatchersForTsconfig[currentPath]) {
if (!this.directoryWatchersForTsconfig.get(currentPath)) {
this.projectService.logger.info(`Add watcher for: ${currentPath}`);
this.directoryWatchersForTsconfig[currentPath] = this.projectService.host.watchDirectory(currentPath, callback);
this.directoryWatchersRefCount[currentPath] = 1;
this.directoryWatchersForTsconfig.set(currentPath, this.projectService.host.watchDirectory(currentPath, callback));
this.directoryWatchersRefCount.set(currentPath, 1);
}
else {
this.directoryWatchersRefCount[currentPath] += 1;
modifyValue(this.directoryWatchersRefCount, currentPath, count => count + 1);
}
project.directoriesWatchedForTsconfig.push(currentPath);
currentPath = parentPath;
@ -150,7 +151,7 @@ namespace ts.server {
/**
* maps external project file name to list of config files that were the part of this project
*/
private readonly externalProjectToConfiguredProjectMap: Map<NormalizedPath[]> = createMap<NormalizedPath[]>();
private readonly externalProjectToConfiguredProjectMap = new StringMap<NormalizedPath[]>();
/**
* external projects (configuration and list of root files is not controlled by tsserver)
@ -325,7 +326,7 @@ namespace ts.server {
}
else {
if (info && (!info.isOpen)) {
// file has been changed which might affect the set of referenced files in projects that include
// file has been changed which might affect the set of referenced files in projects that include
// this file and set of inferred projects
info.reloadFromFile();
this.updateProjectGraphs(info.containingProjects);
@ -343,7 +344,7 @@ namespace ts.server {
if (!info.isOpen) {
this.filenameToScriptInfo.remove(info.path);
// capture list of projects since detachAllProjects will wipe out original list
// capture list of projects since detachAllProjects will wipe out original list
const containingProjects = info.containingProjects.slice();
info.detachAllProjects();
@ -493,7 +494,7 @@ namespace ts.server {
const inferredProject = this.createInferredProjectWithRootFileIfNecessary(info);
if (!this.useSingleInferredProject) {
// if useOneInferredProject is not set then try to fixup ownership of open files
// check 'defaultProject !== inferredProject' is necessary to handle cases
// check 'defaultProject !== inferredProject' is necessary to handle cases
// when creation inferred project for some file has added other open files into this project (i.e. as referenced files)
// we definitely don't want to delete the project that was just created
for (const f of this.openFiles) {
@ -503,7 +504,7 @@ namespace ts.server {
}
const defaultProject = f.getDefaultProject();
if (isRootFileInInferredProject(info) && defaultProject !== inferredProject && inferredProject.containsScriptInfo(f)) {
// open file used to be root in inferred project,
// open file used to be root in inferred project,
// this inferred project is different from the one we've just created for current file
// and new inferred project references this open file.
// We should delete old inferred project and attach open file to the new one
@ -715,7 +716,7 @@ namespace ts.server {
files: parsedCommandLine.fileNames,
compilerOptions: parsedCommandLine.options,
configHasFilesProperty: config["files"] !== undefined,
wildcardDirectories: createMap(parsedCommandLine.wildcardDirectories),
wildcardDirectories: parsedCommandLine.wildcardDirectories,
typingOptions: parsedCommandLine.typingOptions,
compileOnSave: parsedCommandLine.compileOnSave
};
@ -771,7 +772,7 @@ namespace ts.server {
this.documentRegistry,
projectOptions.configHasFilesProperty,
projectOptions.compilerOptions,
projectOptions.wildcardDirectories,
mapOfMapLike(projectOptions.wildcardDirectories),
/*languageServiceEnabled*/ !sizeLimitExceeded,
projectOptions.compileOnSave === undefined ? false : projectOptions.compileOnSave);
@ -829,7 +830,7 @@ namespace ts.server {
private updateNonInferredProject<T>(project: ExternalProject | ConfiguredProject, newUncheckedFiles: T[], propertyReader: FilePropertyReader<T>, newOptions: CompilerOptions, newTypingOptions: TypingOptions, compileOnSave: boolean, configFileErrors: Diagnostic[]) {
const oldRootScriptInfos = project.getRootScriptInfos();
const newRootScriptInfos: ScriptInfo[] = [];
const newRootScriptInfoMap: NormalizedPathMap<ScriptInfo> = createNormalizedPathMap<ScriptInfo>();
const newRootScriptInfoMap: Map<NormalizedPath, ScriptInfo> = new StringMap<ScriptInfo>();
let projectErrors: Diagnostic[];
let rootFilesChanged = false;
@ -857,7 +858,7 @@ namespace ts.server {
let toAdd: ScriptInfo[];
let toRemove: ScriptInfo[];
for (const oldFile of oldRootScriptInfos) {
if (!newRootScriptInfoMap.contains(oldFile.fileName)) {
if (!newRootScriptInfoMap.has(oldFile.fileName)) {
(toRemove || (toRemove = [])).push(oldFile);
}
}
@ -874,7 +875,7 @@ namespace ts.server {
if (toAdd) {
for (const f of toAdd) {
if (f.isOpen && isRootFileInInferredProject(f)) {
// if file is already root in some inferred project
// if file is already root in some inferred project
// - remove the file from that project and delete the project if necessary
const inferredProject = f.containingProjects[0];
inferredProject.removeFile(f);
@ -1023,7 +1024,7 @@ namespace ts.server {
this.logger.info(`Host information ${args.hostInfo}`);
}
if (args.formatOptions) {
mergeMaps(this.hostConfiguration.formatCodeOptions, args.formatOptions);
mergeMapLikes(this.hostConfiguration.formatCodeOptions, args.formatOptions);
this.logger.info("Format host information updated");
}
}
@ -1145,7 +1146,7 @@ namespace ts.server {
for (const file of changedFiles) {
const scriptInfo = this.getScriptInfo(file.fileName);
Debug.assert(!!scriptInfo);
// apply changes in reverse order
// apply changes in reverse order
for (let i = file.changes.length - 1; i >= 0; i--) {
const change = file.changes[i];
scriptInfo.editContent(change.span.start, change.span.start + change.span.length, change.newText);
@ -1182,7 +1183,7 @@ namespace ts.server {
closeExternalProject(uncheckedFileName: string, suppressRefresh = false): void {
const fileName = toNormalizedPath(uncheckedFileName);
const configFiles = this.externalProjectToConfiguredProjectMap[fileName];
const configFiles = this.externalProjectToConfiguredProjectMap.get(fileName);
if (configFiles) {
let shouldRefreshInferredProjects = false;
for (const configFile of configFiles) {
@ -1190,7 +1191,7 @@ namespace ts.server {
shouldRefreshInferredProjects = true;
}
}
delete this.externalProjectToConfiguredProjectMap[fileName];
this.externalProjectToConfiguredProjectMap.delete(fileName);
if (shouldRefreshInferredProjects && !suppressRefresh) {
this.refreshInferredProjects();
}
@ -1237,7 +1238,7 @@ namespace ts.server {
// close existing project and later we'll open a set of configured projects for these files
this.closeExternalProject(proj.projectFileName, /*suppressRefresh*/ true);
}
else if (this.externalProjectToConfiguredProjectMap[proj.projectFileName]) {
else if (this.externalProjectToConfiguredProjectMap.get(proj.projectFileName)) {
// this project used to include config files
if (!tsConfigFiles) {
// config files were removed from the project - close existing external project which in turn will close configured projects
@ -1245,7 +1246,7 @@ namespace ts.server {
}
else {
// project previously had some config files - compare them with new set of files and close all configured projects that correspond to unused files
const oldConfigFiles = this.externalProjectToConfiguredProjectMap[proj.projectFileName];
const oldConfigFiles = this.externalProjectToConfiguredProjectMap.get(proj.projectFileName);
let iNew = 0;
let iOld = 0;
while (iNew < tsConfigFiles.length && iOld < oldConfigFiles.length) {
@ -1273,7 +1274,7 @@ namespace ts.server {
}
if (tsConfigFiles) {
// store the list of tsconfig files that belong to the external project
this.externalProjectToConfiguredProjectMap[proj.projectFileName] = tsConfigFiles;
this.externalProjectToConfiguredProjectMap.set(proj.projectFileName, tsConfigFiles);
for (const tsconfigFile of tsConfigFiles) {
let project = this.findConfiguredProjectByProjectName(tsconfigFile);
if (!project) {
@ -1289,7 +1290,7 @@ namespace ts.server {
}
else {
// no config files - remove the item from the collection
delete this.externalProjectToConfiguredProjectMap[proj.projectFileName];
this.externalProjectToConfiguredProjectMap.delete(proj.projectFileName);
this.createAndAddExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typingOptions);
}
this.refreshInferredProjects();

View File

@ -5,8 +5,8 @@
namespace ts.server {
export class LSHost implements ts.LanguageServiceHost, ModuleResolutionHost, ServerLanguageServiceHost {
private compilationSettings: ts.CompilerOptions;
private readonly resolvedModuleNames: ts.FileMap<Map<ResolvedModuleWithFailedLookupLocations>>;
private readonly resolvedTypeReferenceDirectives: ts.FileMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>;
private readonly resolvedModuleNames: ts.FileMap<Map<string, ResolvedModuleWithFailedLookupLocations>>;
private readonly resolvedTypeReferenceDirectives: ts.FileMap<Map<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>;
private readonly getCanonicalFileName: (fileName: string) => string;
private readonly resolveModuleName: typeof resolveModuleName;
@ -14,8 +14,8 @@ namespace ts.server {
constructor(private readonly host: ServerHost, private readonly project: Project, private readonly cancellationToken: HostCancellationToken) {
this.getCanonicalFileName = ts.createGetCanonicalFileName(this.host.useCaseSensitiveFileNames);
this.resolvedModuleNames = createFileMap<Map<ResolvedModuleWithFailedLookupLocations>>();
this.resolvedTypeReferenceDirectives = createFileMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
this.resolvedModuleNames = createFileMap<Map<string, ResolvedModuleWithFailedLookupLocations>>();
this.resolvedTypeReferenceDirectives = createFileMap<Map<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
if (host.trace) {
this.trace = s => host.trace(s);
@ -31,7 +31,7 @@ namespace ts.server {
}
}
// create different collection of failed lookup locations for second pass
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
const secondaryLookupFailedLookupLocations: string[] = [];
const globalCache = this.project.projectService.typingsInstaller.globalTypingsCacheLocation;
if (this.project.getTypingOptions().enableAutoDiscovery && globalCache) {
@ -55,28 +55,28 @@ namespace ts.server {
private resolveNamesWithLocalCache<T extends { failedLookupLocations: string[] }, R>(
names: string[],
containingFile: string,
cache: ts.FileMap<Map<T>>,
cache: ts.FileMap<Map<string, T>>,
loader: (name: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost) => T,
getResult: (s: T) => R): R[] {
const path = toPath(containingFile, this.host.getCurrentDirectory(), this.getCanonicalFileName);
const currentResolutionsInFile = cache.get(path);
const newResolutions: Map<T> = createMap<T>();
const newResolutions = new StringMap<T>();
const resolvedModules: R[] = [];
const compilerOptions = this.getCompilationSettings();
for (const name of names) {
// check if this is a duplicate entry in the list
let resolution = newResolutions[name];
let resolution = newResolutions.get(name);
if (!resolution) {
const existingResolution = currentResolutionsInFile && currentResolutionsInFile[name];
const existingResolution = currentResolutionsInFile && currentResolutionsInFile.get(name);
if (moduleResolutionIsValid(existingResolution)) {
// ok, it is safe to use existing name resolution results
resolution = existingResolution;
}
else {
newResolutions[name] = resolution = loader(name, containingFile, compilerOptions, this);
newResolutions.set(name, resolution = loader(name, containingFile, compilerOptions, this));
}
}

View File

@ -47,7 +47,7 @@ namespace ts.server {
/**
* Set of files that was returned from the last call to getChangesSinceVersion.
*/
private lastReportedFileNames: Map<string>;
private lastReportedFileNames: Map<string, string>;
/**
* Last version that was reported.
*/
@ -437,16 +437,16 @@ namespace ts.server {
const added: string[] = [];
const removed: string[] = [];
for (const id in currentFiles) {
if (!hasProperty(lastReportedFileNames, id)) {
forEachKeyInMap(currentFiles, id => {
if (!lastReportedFileNames.has(id)) {
added.push(id);
}
}
for (const id in lastReportedFileNames) {
if (!hasProperty(currentFiles, id)) {
});
forEachKeyInMap(lastReportedFileNames, id => {
if (!currentFiles.has(id)) {
removed.push(id);
}
}
});
this.lastReportedFileNames = currentFiles;
this.lastReportedVersion = this.projectStructureVersion;
return { info, changes: { added, removed }, projectErrors: this.projectErrors };
@ -472,7 +472,7 @@ namespace ts.server {
// We need to use a set here since the code can contain the same import twice,
// but that will only be one dependency.
// To avoid invernal conversion, the key of the referencedFiles map must be of type Path
const referencedFiles = createMap<boolean>();
const referencedFiles = new StringSet();
if (sourceFile.imports && sourceFile.imports.length > 0) {
const checker: TypeChecker = this.program.getTypeChecker();
for (const importName of sourceFile.imports) {
@ -480,7 +480,7 @@ namespace ts.server {
if (symbol && symbol.declarations && symbol.declarations[0]) {
const declarationSourceFile = symbol.declarations[0].getSourceFile();
if (declarationSourceFile) {
referencedFiles[declarationSourceFile.path] = true;
referencedFiles.add(declarationSourceFile.path);
}
}
}
@ -492,26 +492,24 @@ namespace ts.server {
if (sourceFile.referencedFiles && sourceFile.referencedFiles.length > 0) {
for (const referencedFile of sourceFile.referencedFiles) {
const referencedPath = toPath(referencedFile.fileName, currentDirectory, getCanonicalFileName);
referencedFiles[referencedPath] = true;
referencedFiles.add(referencedPath);
}
}
// Handle type reference directives
if (sourceFile.resolvedTypeReferenceDirectiveNames) {
for (const typeName in sourceFile.resolvedTypeReferenceDirectiveNames) {
const resolvedTypeReferenceDirective = sourceFile.resolvedTypeReferenceDirectiveNames[typeName];
sourceFile.resolvedTypeReferenceDirectiveNames.forEach(resolvedTypeReferenceDirective => {
if (!resolvedTypeReferenceDirective) {
continue;
return;
}
const fileName = resolvedTypeReferenceDirective.resolvedFileName;
const typeFilePath = toPath(fileName, currentDirectory, getCanonicalFileName);
referencedFiles[typeFilePath] = true;
}
referencedFiles.add(typeFilePath);
});
}
const allFileNames = map(Object.keys(referencedFiles), key => <Path>key);
return filter(allFileNames, file => this.projectService.host.fileExists(file));
return filterSetToArray(referencedFiles, file => this.projectService.host.fileExists(file)) as Path[];
}
// remove a root file from project
@ -582,7 +580,7 @@ namespace ts.server {
private typingOptions: TypingOptions;
private projectFileWatcher: FileWatcher;
private directoryWatcher: FileWatcher;
private directoriesWatchedForWildcards: Map<FileWatcher>;
private directoriesWatchedForWildcards: Map<string, FileWatcher>;
private typeRootsWatchers: FileWatcher[];
/** Used for configured projects which may have multiple open roots */
@ -593,7 +591,7 @@ namespace ts.server {
documentRegistry: ts.DocumentRegistry,
hasExplicitListOfFiles: boolean,
compilerOptions: CompilerOptions,
private wildcardDirectories: Map<WatchDirectoryFlags>,
private wildcardDirectories: Map<string, WatchDirectoryFlags>,
languageServiceEnabled: boolean,
public compileOnSaveEnabled: boolean) {
super(ProjectKind.Configured, projectService, documentRegistry, hasExplicitListOfFiles, languageServiceEnabled, compilerOptions, compileOnSaveEnabled);
@ -648,18 +646,19 @@ namespace ts.server {
return;
}
const configDirectoryPath = getDirectoryPath(this.configFileName);
this.directoriesWatchedForWildcards = reduceProperties(this.wildcardDirectories, (watchers, flag, directory) => {
this.directoriesWatchedForWildcards = new StringMap<FileWatcher>();
this.wildcardDirectories.forEach((flag, directory) => {
if (comparePaths(configDirectoryPath, directory, ".", !this.projectService.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) {
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
this.projectService.logger.info(`Add ${recursive ? "recursive " : ""}watcher for: ${directory}`);
watchers[directory] = this.projectService.host.watchDirectory(
this.directoriesWatchedForWildcards.set(directory, this.projectService.host.watchDirectory(
directory,
path => callback(this, path),
recursive
);
));
}
return watchers;
}, <Map<FileWatcher>>{});
});
}
stopWatchingDirectory() {
@ -683,9 +682,7 @@ namespace ts.server {
this.typeRootsWatchers = undefined;
}
for (const id in this.directoriesWatchedForWildcards) {
this.directoriesWatchedForWildcards[id].close();
}
this.directoriesWatchedForWildcards.forEach(watcher => { watcher.close(); });
this.directoriesWatchedForWildcards = undefined;
this.stopWatchingDirectory();

View File

@ -4,7 +4,7 @@ namespace ts.server {
export class ScriptInfo {
/**
* All projects that include this file
* All projects that include this file
*/
readonly containingProjects: Project[] = [];
private formatCodeSettings: ts.FormatCodeSettings;
@ -96,7 +96,7 @@ namespace ts.server {
if (!this.formatCodeSettings) {
this.formatCodeSettings = getDefaultFormatCodeSettings(this.host);
}
mergeMaps(this.formatCodeSettings, formatSettings);
mergeMapLikes(this.formatCodeSettings, formatSettings);
}
}

View File

@ -547,7 +547,7 @@ namespace ts.server {
const scriptInfo = this.projectService.getScriptInfo(args.file);
projects = scriptInfo.containingProjects;
}
// ts.filter handles case when 'projects' is undefined
// ts.filter handles case when 'projects' is undefined
projects = filter(projects, p => p.languageServiceEnabled);
if (!projects || !projects.length) {
return Errors.ThrowNoProject();
@ -1279,7 +1279,7 @@ namespace ts.server {
return { response, responseRequired: true };
}
private handlers = createMap<(request: protocol.Request) => { response?: any, responseRequired?: boolean }>({
private handlers = mapOfMapLike<(request: protocol.Request) => { response?: any, responseRequired?: boolean }>({
[CommandNames.OpenExternalProject]: (request: protocol.OpenExternalProjectRequest) => {
this.projectService.openExternalProject(request.arguments);
// TODO: report errors
@ -1525,14 +1525,14 @@ namespace ts.server {
});
public addProtocolHandler(command: string, handler: (request: protocol.Request) => { response?: any, responseRequired: boolean }) {
if (command in this.handlers) {
if (this.handlers.has(command)) {
throw new Error(`Protocol handler already exists for command "${command}"`);
}
this.handlers[command] = handler;
this.handlers.set(command, handler);
}
public executeCommand(request: protocol.Request): { response?: any, responseRequired?: boolean } {
const handler = this.handlers[request.command];
const handler = this.handlers.get(request.command);
if (handler) {
return handler(request);
}

View File

@ -15,7 +15,7 @@
"utilities.ts",
"scriptVersionCache.ts",
"scriptInfo.ts",
"lshost.ts",
"lsHost.ts",
"typingsCache.ts",
"project.ts",
"editorServices.ts",

View File

@ -29,21 +29,22 @@ namespace ts.server {
if ((arr1 || emptyArray).length === 0 && (arr2 || emptyArray).length === 0) {
return true;
}
const set: Map<boolean> = createMap<boolean>();
const set = new StringMap<boolean>();
let unique = 0;
for (const v of arr1) {
if (set[v] !== true) {
set[v] = true;
if (set.get(v) !== true) {
set.set(v, true);
unique++;
}
}
for (const v of arr2) {
if (!hasProperty(set, v)) {
const isSet = set.get(v);
if (isSet === undefined) {
return false;
}
if (set[v] === true) {
set[v] = false;
if (isSet === true) {
set.set(v, false);
unique--;
}
}
@ -71,7 +72,7 @@ namespace ts.server {
}
export class TypingsCache {
private readonly perProjectCache: Map<TypingsCacheEntry> = createMap<TypingsCacheEntry>();
private readonly perProjectCache = new StringMap<TypingsCacheEntry>();
constructor(private readonly installer: ITypingsInstaller) {
}
@ -83,17 +84,17 @@ namespace ts.server {
return <any>emptyArray;
}
const entry = this.perProjectCache[project.getProjectName()];
const entry = this.perProjectCache.get(project.getProjectName());
const result: TypingsArray = entry ? entry.typings : <any>emptyArray;
if (forceRefresh || !entry || typingOptionsChanged(typingOptions, entry.typingOptions) || compilerOptionsChanged(project.getCompilerOptions(), entry.compilerOptions)) {
// Note: entry is now poisoned since it does not really contain typings for a given combination of compiler options\typings options.
// instead it acts as a placeholder to prevent issuing multiple requests
this.perProjectCache[project.getProjectName()] = {
this.perProjectCache.set(project.getProjectName(), {
compilerOptions: project.getCompilerOptions(),
typingOptions,
typings: result,
poisoned: true
};
});
// something has been changed, issue a request to update typings
this.installer.enqueueInstallTypingsRequest(project, typingOptions);
}
@ -109,16 +110,16 @@ namespace ts.server {
}
updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typingOptions: TypingOptions, newTypings: string[]) {
this.perProjectCache[projectName] = {
this.perProjectCache.set(projectName, {
compilerOptions,
typingOptions,
typings: toTypingsArray(newTypings),
poisoned: false
};
});
}
onProjectClosed(project: Project) {
delete this.perProjectCache[project.getProjectName()];
this.perProjectCache.delete(project.getProjectName());
this.installer.onProjectClosed(project);
}
}

View File

@ -35,7 +35,7 @@ namespace ts.server.typingsInstaller {
export const MaxPackageNameLength = 214;
/**
* Validates package name using rules defined at https://docs.npmjs.com/files/package.json
* Validates package name using rules defined at https://docs.npmjs.com/files/package.json
*/
export function validatePackageName(packageName: string): PackageNameValidationResult {
Debug.assert(!!packageName, "Package name is not specified");
@ -75,10 +75,10 @@ namespace ts.server.typingsInstaller {
};
export abstract class TypingsInstaller {
private readonly packageNameToTypingLocation: Map<string> = createMap<string>();
private readonly missingTypingsSet: Map<true> = createMap<true>();
private readonly knownCachesSet: Map<true> = createMap<true>();
private readonly projectWatchers: Map<FileWatcher[]> = createMap<FileWatcher[]>();
private readonly packageNameToTypingLocation = new StringMap<string>();
private readonly missingTypingsSet = new StringSet();
private readonly knownCachesSet = new StringSet();
private readonly projectWatchers = new StringMap<FileWatcher[]>();
readonly pendingRunRequests: PendingRequest[] = [];
private installRunCount = 1;
@ -109,7 +109,7 @@ namespace ts.server.typingsInstaller {
if (this.log.isEnabled()) {
this.log.writeLine(`Closing file watchers for project '${projectName}'`);
}
const watchers = this.projectWatchers[projectName];
const watchers = this.projectWatchers.get(projectName);
if (!watchers) {
if (this.log.isEnabled()) {
this.log.writeLine(`No watchers are registered for project '${projectName}'`);
@ -120,7 +120,7 @@ namespace ts.server.typingsInstaller {
w.close();
}
delete this.projectWatchers[projectName];
this.projectWatchers.delete(projectName);
if (this.log.isEnabled()) {
this.log.writeLine(`Closing file watchers for project '${projectName}' - done.`);
@ -132,7 +132,7 @@ namespace ts.server.typingsInstaller {
this.log.writeLine(`Got install request ${JSON.stringify(req)}`);
}
// load existing typing information from the cache
// load existing typing information from the cache
if (req.cachePath) {
if (this.log.isEnabled()) {
this.log.writeLine(`Request specifies cache path '${req.cachePath}', loading cached information...`);
@ -174,7 +174,7 @@ namespace ts.server.typingsInstaller {
if (this.log.isEnabled()) {
this.log.writeLine(`Processing cache location '${cacheLocation}'`);
}
if (this.knownCachesSet[cacheLocation]) {
if (this.knownCachesSet.has(cacheLocation)) {
if (this.log.isEnabled()) {
this.log.writeLine(`Cache location was already processed...`);
}
@ -200,7 +200,7 @@ namespace ts.server.typingsInstaller {
if (!typingFile) {
continue;
}
const existingTypingFile = this.packageNameToTypingLocation[packageName];
const existingTypingFile = this.packageNameToTypingLocation.get(packageName);
if (existingTypingFile === typingFile) {
continue;
}
@ -212,14 +212,14 @@ namespace ts.server.typingsInstaller {
if (this.log.isEnabled()) {
this.log.writeLine(`Adding entry into typings cache: '${packageName}' => '${typingFile}'`);
}
this.packageNameToTypingLocation[packageName] = typingFile;
this.packageNameToTypingLocation.set(packageName, typingFile);
}
}
}
if (this.log.isEnabled()) {
this.log.writeLine(`Finished processing cache location '${cacheLocation}'`);
}
this.knownCachesSet[cacheLocation] = true;
this.knownCachesSet.add(cacheLocation);
}
private filterTypings(typingsToInstall: string[]) {
@ -228,7 +228,7 @@ namespace ts.server.typingsInstaller {
}
const result: string[] = [];
for (const typing of typingsToInstall) {
if (this.missingTypingsSet[typing]) {
if (this.missingTypingsSet.has(typing)) {
continue;
}
const validationResult = validatePackageName(typing);
@ -237,7 +237,7 @@ namespace ts.server.typingsInstaller {
}
else {
// add typing name to missing set so we won't process it again
this.missingTypingsSet[typing] = true;
this.missingTypingsSet.add(typing);
if (this.log.isEnabled()) {
switch (validationResult) {
case PackageNameValidationResult.NameTooLong:
@ -291,20 +291,20 @@ namespace ts.server.typingsInstaller {
if (this.log.isEnabled()) {
this.log.writeLine(`Requested to install typings ${JSON.stringify(typingsToInstall)}, installed typings ${JSON.stringify(installedTypings)}`);
}
const installedPackages: Map<true> = createMap<true>();
const installedPackages = new StringSet();
const installedTypingFiles: string[] = [];
for (const t of installedTypings) {
const packageName = getBaseFileName(t);
if (!packageName) {
continue;
}
installedPackages[packageName] = true;
installedPackages.add(packageName);
const typingFile = typingToFileName(cachePath, packageName, this.installTypingHost);
if (!typingFile) {
continue;
}
if (!this.packageNameToTypingLocation[packageName]) {
this.packageNameToTypingLocation[packageName] = typingFile;
if (!this.packageNameToTypingLocation.get(packageName)) {
this.packageNameToTypingLocation.set(packageName, typingFile);
}
installedTypingFiles.push(typingFile);
}
@ -312,11 +312,11 @@ namespace ts.server.typingsInstaller {
this.log.writeLine(`Installed typing files ${JSON.stringify(installedTypingFiles)}`);
}
for (const toInstall of typingsToInstall) {
if (!installedPackages[toInstall]) {
if (!installedPackages.has(toInstall)) {
if (this.log.isEnabled()) {
this.log.writeLine(`New missing typing package '${toInstall}'`);
}
this.missingTypingsSet[toInstall] = true;
this.missingTypingsSet.add(toInstall);
}
}
@ -390,7 +390,7 @@ namespace ts.server.typingsInstaller {
});
watchers.push(w);
}
this.projectWatchers[projectName] = watchers;
this.projectWatchers.set(projectName, watchers);
}
private createSetTypings(request: DiscoverTypings, typings: string[]): SetTypings {

View File

@ -90,7 +90,7 @@ namespace ts.server {
};
}
export function mergeMaps(target: MapLike<any>, source: MapLike <any>): void {
export function mergeMapLikes(target: MapLike<any>, source: MapLike <any>): void {
for (const key in source) {
if (hasProperty(source, key)) {
target[key] = source[key];
@ -131,32 +131,6 @@ namespace ts.server {
return <NormalizedPath>fileName;
}
export interface NormalizedPathMap<T> {
get(path: NormalizedPath): T;
set(path: NormalizedPath, value: T): void;
contains(path: NormalizedPath): boolean;
remove(path: NormalizedPath): void;
}
export function createNormalizedPathMap<T>(): NormalizedPathMap<T> {
/* tslint:disable:no-null-keyword */
const map: Map<T> = Object.create(null);
/* tslint:enable:no-null-keyword */
return {
get(path) {
return map[path];
},
set(path, value) {
map[path] = value;
},
contains(path) {
return hasProperty(map, path);
},
remove(path) {
delete map[path];
}
};
}
function throwLanguageServiceIsDisabledError() {
throw new Error("LanguageService is disabled");
}
@ -223,7 +197,7 @@ namespace ts.server {
* these fields can be present in the project file
**/
files?: string[];
wildcardDirectories?: Map<WatchDirectoryFlags>;
wildcardDirectories?: MapLike<WatchDirectoryFlags>;
compilerOptions?: CompilerOptions;
typingOptions?: TypingOptions;
compileOnSave?: boolean;
@ -239,21 +213,22 @@ namespace ts.server {
}
export class ThrottledOperations {
private pendingTimeouts: Map<any> = createMap<any>();
private pendingTimeouts = new StringMap<any>();
constructor(private readonly host: ServerHost) {
}
public schedule(operationId: string, delay: number, cb: () => void) {
if (hasProperty(this.pendingTimeouts, operationId)) {
const pendingTimeout = this.pendingTimeouts.get(operationId);
if (pendingTimeout !== undefined) {
// another operation was already scheduled for this id - cancel it
this.host.clearTimeout(this.pendingTimeouts[operationId]);
this.host.clearTimeout(pendingTimeout);
}
// schedule new operation, pass arguments
this.pendingTimeouts[operationId] = this.host.setTimeout(ThrottledOperations.run, delay, this, operationId, cb);
// schedule new operation, pass arguments
this.pendingTimeouts.set(operationId, this.host.setTimeout(ThrottledOperations.run, delay, this, operationId, cb));
}
private static run(self: ThrottledOperations, operationId: string, cb: () => void) {
delete self.pendingTimeouts[operationId];
self.pendingTimeouts.delete(operationId);
cb();
}
}

View File

@ -462,7 +462,7 @@ namespace ts {
}
/* @internal */
export function getSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: Map<string>, span: TextSpan): ClassifiedSpan[] {
export function getSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: Set<string>, span: TextSpan): ClassifiedSpan[] {
return convertClassifications(getEncodedSemanticClassifications(typeChecker, cancellationToken, sourceFile, classifiableNames, span));
}
@ -487,7 +487,7 @@ namespace ts {
}
/* @internal */
export function getEncodedSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: Map<string>, span: TextSpan): Classifications {
export function getEncodedSemanticClassifications(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFile: SourceFile, classifiableNames: Set<string>, span: TextSpan): Classifications {
const result: number[] = [];
processNode(sourceFile);
@ -557,7 +557,7 @@ namespace ts {
// Only bother calling into the typechecker if this is an identifier that
// could possibly resolve to a type name. This makes classification run
// in a third of the time it would normally take.
if (classifiableNames[identifier.text]) {
if (classifiableNames.has(identifier.text)) {
const symbol = typeChecker.getSymbolAtLocation(node);
if (symbol) {
const type = classifySymbol(symbol, getMeaningFromLocation(node));

View File

@ -58,18 +58,17 @@ namespace ts.Completions {
return { isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation: isNewIdentifierLocation, entries };
function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Map<string>): CompletionEntry[] {
function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Set<string>): CompletionEntry[] {
const entries: CompletionEntry[] = [];
const nameTable = getNameTable(sourceFile);
for (const name in nameTable) {
getNameTable(sourceFile).forEach((nameTablePosition, name) => {
// Skip identifiers produced only from the current location
if (nameTable[name] === position) {
continue;
if (nameTablePosition === position) {
return;
}
if (!uniqueNames[name]) {
uniqueNames[name] = name;
if (!uniqueNames.has(name)) {
uniqueNames.add(name);
const displayName = getCompletionEntryDisplayName(unescapeIdentifier(name), compilerOptions.target, /*performCharacterChecks*/ true);
if (displayName) {
const entry = {
@ -81,7 +80,7 @@ namespace ts.Completions {
entries.push(entry);
}
}
}
});
return entries;
}
@ -112,17 +111,17 @@ namespace ts.Completions {
}
function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Map<string> {
function getCompletionEntriesFromSymbols(symbols: Symbol[], entries: CompletionEntry[], location: Node, performCharacterChecks: boolean): Set<string> {
const start = timestamp();
const uniqueNames = createMap<string>();
const uniqueNames = new StringSet();
if (symbols) {
for (const symbol of symbols) {
const entry = createCompletionEntry(symbol, location, performCharacterChecks);
if (entry) {
const id = escapeIdentifier(entry.name);
if (!uniqueNames[id]) {
if (!uniqueNames.has(id)) {
entries.push(entry);
uniqueNames[id] = id;
uniqueNames.add(id);
}
}
}
@ -343,7 +342,7 @@ namespace ts.Completions {
const files = tryReadDirectory(host, baseDirectory, extensions, /*exclude*/undefined, /*include*/["./*"]);
if (files) {
const foundFiles = createMap<boolean>();
const foundFiles = new StringSet();
for (let filePath of files) {
filePath = normalizePath(filePath);
if (exclude && comparePaths(filePath, exclude, scriptPath, ignoreCase) === Comparison.EqualTo) {
@ -352,14 +351,14 @@ namespace ts.Completions {
const foundFileName = includeExtensions ? getBaseFileName(filePath) : removeFileExtension(getBaseFileName(filePath));
if (!foundFiles[foundFileName]) {
foundFiles[foundFileName] = true;
if (!foundFiles.has(foundFileName)) {
foundFiles.add(foundFileName);
}
}
for (const foundFile in foundFiles) {
foundFiles.forEach(foundFile => {
result.push(createCompletionEntryForModule(foundFile, ScriptElementKind.scriptElement, span));
}
});
}
// If possible, get folder completion as well
@ -397,7 +396,7 @@ namespace ts.Completions {
if (paths) {
for (const path in paths) {
if (paths.hasOwnProperty(path)) {
if (hasProperty(paths, path)) {
if (path === "*") {
if (paths[path]) {
for (const pattern of paths[path]) {
@ -1521,7 +1520,7 @@ namespace ts.Completions {
* do not occur at the current position and have not otherwise been typed.
*/
function filterNamedImportOrExportCompletionItems(exportsOfModule: Symbol[], namedImportsOrExports: ImportOrExportSpecifier[]): Symbol[] {
const existingImportsOrExports = createMap<boolean>();
const existingImportsOrExports = new StringSet();
for (const element of namedImportsOrExports) {
// If this is the current item we are editing right now, do not filter it out
@ -1530,14 +1529,14 @@ namespace ts.Completions {
}
const name = element.propertyName || element.name;
existingImportsOrExports[name.text] = true;
existingImportsOrExports.add(name.text);
}
if (!someProperties(existingImportsOrExports)) {
if (setIsEmpty(existingImportsOrExports)) {
return filter(exportsOfModule, e => e.name !== "default");
}
return filter(exportsOfModule, e => e.name !== "default" && !existingImportsOrExports[e.name]);
return filter(exportsOfModule, e => e.name !== "default" && !existingImportsOrExports.has(e.name));
}
/**
@ -1551,7 +1550,7 @@ namespace ts.Completions {
return contextualMemberSymbols;
}
const existingMemberNames = createMap<boolean>();
const existingMemberNames = new StringSet();
for (const m of existingMembers) {
// Ignore omitted expressions for missing members
if (m.kind !== SyntaxKind.PropertyAssignment &&
@ -1581,10 +1580,10 @@ namespace ts.Completions {
existingName = (<Identifier>m.name).text;
}
existingMemberNames[existingName] = true;
existingMemberNames.add(existingName);
}
return filter(contextualMemberSymbols, m => !existingMemberNames[m.name]);
return filter(contextualMemberSymbols, m => !existingMemberNames.has(m.name));
}
/**
@ -1594,7 +1593,7 @@ namespace ts.Completions {
* do not occur at the current position and have not otherwise been typed.
*/
function filterJsxAttributes(symbols: Symbol[], attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>): Symbol[] {
const seenNames = createMap<boolean>();
const seenNames = new StringSet();
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()) {
@ -1602,11 +1601,11 @@ namespace ts.Completions {
}
if (attr.kind === SyntaxKind.JsxAttribute) {
seenNames[(<JsxAttribute>attr).name.text] = true;
seenNames.add((<JsxAttribute>attr).name.text);
}
}
return filter(symbols, a => !seenNames[a.name]);
return filter(symbols, a => !seenNames.has(a.name));
}
}

View File

@ -39,16 +39,16 @@ namespace ts.DocumentHighlights {
return undefined;
}
const fileNameToDocumentHighlights = createMap<DocumentHighlights>();
const fileNameToDocumentHighlights = new StringMap<DocumentHighlights>();
const result: DocumentHighlights[] = [];
for (const referencedSymbol of referencedSymbols) {
for (const referenceEntry of referencedSymbol.references) {
const fileName = referenceEntry.fileName;
let documentHighlights = fileNameToDocumentHighlights[fileName];
let documentHighlights = fileNameToDocumentHighlights.get(fileName);
if (!documentHighlights) {
documentHighlights = { fileName, highlightSpans: [] };
fileNameToDocumentHighlights[fileName] = documentHighlights;
fileNameToDocumentHighlights.set(fileName, documentHighlights);
result.push(documentHighlights);
}

View File

@ -105,7 +105,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 = createMap<FileMap<DocumentRegistryEntry>>();
const buckets = new StringMap<FileMap<DocumentRegistryEntry>>();
const getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames);
function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey {
@ -113,30 +113,35 @@ namespace ts {
}
function getBucketForCompilationSettings(key: DocumentRegistryBucketKey, createIfMissing: boolean): FileMap<DocumentRegistryEntry> {
let bucket = buckets[key];
let bucket = buckets.get(key);
if (!bucket && createIfMissing) {
buckets[key] = bucket = createFileMap<DocumentRegistryEntry>();
buckets.set(key, bucket = createFileMap<DocumentRegistryEntry>());
}
return bucket;
}
function reportStats() {
const bucketInfoArray = Object.keys(buckets).filter(name => name && name.charAt(0) === "_").map(name => {
const entries = buckets[name];
const sourceFiles: { name: string; refCount: number; references: string[]; }[] = [];
entries.forEachValue((key, entry) => {
sourceFiles.push({
name: key,
refCount: entry.languageServiceRefCount,
references: entry.owners.slice(0)
type Info = {
bucket: string;
sourceFiles: { name: string, refCount: number, references: string[] }[]
};
const bucketInfoArray: Info[] = [];
buckets.forEach((entries, name) => {
if (name && name.charAt(0) === "_") {
const sourceFiles: { name: string; refCount: number; references: string[]; }[] = [];
entries.forEachValue((key, entry) => {
sourceFiles.push({
name: key,
refCount: entry.languageServiceRefCount,
references: entry.owners
});
});
});
sourceFiles.sort((x, y) => y.refCount - x.refCount);
return {
bucket: name,
sourceFiles
};
sourceFiles.sort((x, y) => y.refCount - x.refCount);
bucketInfoArray.push({ bucket: name, sourceFiles });
}
});
return JSON.stringify(bucketInfoArray, undefined, 2);
}

View File

@ -96,7 +96,7 @@ namespace ts.FindAllReferences {
const nameTable = getNameTable(sourceFile);
if (nameTable[internedName] !== undefined) {
if (nameTable.get(internedName) !== undefined) {
result = result || [];
getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex);
}
@ -378,7 +378,7 @@ namespace ts.FindAllReferences {
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, start, container.getEnd());
const parents = getParentSymbolsOfPropertyAccess();
const inheritsFromCache: Map<boolean> = createMap<boolean>();
const inheritsFromCache = new StringMap<boolean>();
if (possiblePositions.length) {
// Build the set of symbols to search for, initially it has only the current symbol
@ -501,14 +501,14 @@ namespace ts.FindAllReferences {
function findOwnConstructorCalls(classSymbol: Symbol): Node[] {
const result: Node[] = [];
for (const decl of classSymbol.members["__constructor"].declarations) {
for (const decl of classSymbol.members.get("__constructor").declarations) {
Debug.assert(decl.kind === SyntaxKind.Constructor);
const ctrKeyword = decl.getChildAt(0);
Debug.assert(ctrKeyword.kind === SyntaxKind.ConstructorKeyword);
result.push(ctrKeyword);
}
forEachProperty(classSymbol.exports, member => {
classSymbol.exports.forEach(member => {
const decl = member.valueDeclaration;
if (decl && decl.kind === SyntaxKind.MethodDeclaration) {
const body = (<MethodDeclaration>decl).body;
@ -528,7 +528,7 @@ namespace ts.FindAllReferences {
/** Find references to `super` in the constructor of an extending class. */
function superConstructorAccesses(cls: ClassLikeDeclaration): Node[] {
const symbol = cls.symbol;
const ctr = symbol.members["__constructor"];
const ctr = symbol.members.get("__constructor");
if (!ctr) {
return [];
}
@ -705,7 +705,7 @@ namespace ts.FindAllReferences {
* @param parent Another class or interface Symbol
* @param cachedResults A map of symbol id pairs (i.e. "child,parent") to booleans indicating previous results
*/
function explicitlyInheritsFrom(child: Symbol, parent: Symbol, cachedResults: Map<boolean>): boolean {
function explicitlyInheritsFrom(child: Symbol, parent: Symbol, cachedResults: Map<string, boolean>): boolean {
const parentIsInterface = parent.getFlags() & SymbolFlags.Interface;
return searchHierarchy(child);
@ -715,12 +715,13 @@ namespace ts.FindAllReferences {
}
const key = getSymbolId(symbol) + "," + getSymbolId(parent);
if (key in cachedResults) {
return cachedResults[key];
const cachedResult = cachedResults.get(key);
if (cachedResult !== undefined) {
return cachedResult;
}
// Set the key so that we don't infinitely recurse
cachedResults[key] = false;
cachedResults.set(key, false);
const inherits = forEach(symbol.getDeclarations(), declaration => {
if (isClassLike(declaration)) {
@ -744,7 +745,7 @@ namespace ts.FindAllReferences {
return false;
});
cachedResults[key] = inherits;
cachedResults.set(key, inherits);
return inherits;
}
@ -1046,7 +1047,7 @@ namespace ts.FindAllReferences {
// Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
if (!implementations && rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>());
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ new StringMap<Symbol>());
}
});
@ -1078,7 +1079,7 @@ namespace ts.FindAllReferences {
// 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 (symbol.name in previousIterationSymbolsCache) {
if (previousIterationSymbolsCache.has(symbol.name)) {
return;
}
@ -1105,14 +1106,14 @@ namespace ts.FindAllReferences {
}
// Visit the typeReference as well to see if it directly or indirectly use that property
previousIterationSymbolsCache[symbol.name] = symbol;
previousIterationSymbolsCache.set(symbol.name, symbol);
getPropertySymbolsFromBaseTypes(type.symbol, propertyName, result, previousIterationSymbolsCache);
}
}
}
}
function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map<boolean>): Symbol {
function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean, parents: Symbol[] | undefined, cache: Map<string, boolean>): Symbol {
if (contains(searchSymbols, referenceSymbol)) {
// If we are searching for constructor uses, they must be 'new' expressions.
return (!searchLocationIsConstructor || isNewExpressionTarget(referenceLocation)) && referenceSymbol;
@ -1176,7 +1177,7 @@ namespace ts.FindAllReferences {
}
const result: Symbol[] = [];
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>());
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ new StringMap<Symbol>());
return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
}

View File

@ -4,7 +4,7 @@
namespace ts.formatting {
export class Rules {
public getRuleName(rule: Rule) {
const o: ts.Map<any> = <any>this;
const o: ts.MapLike<any> = <any>this;
for (const name in o) {
if (o[name] === rule) {
return name;

View File

@ -14,7 +14,7 @@ namespace ts.GoToDefinition {
// Type reference directives
const typeReferenceDirective = findReferenceInPosition(sourceFile.typeReferenceDirectives, position);
if (typeReferenceDirective) {
const referenceFile = program.getResolvedTypeReferenceDirectives()[typeReferenceDirective.fileName];
const referenceFile = program.getResolvedTypeReferenceDirectives().get(typeReferenceDirective.fileName);
if (referenceFile && referenceFile.resolvedFileName) {
return [getDefinitionInfoForFileReference(typeReferenceDirective.fileName, referenceFile.resolvedFileName)];
}

View File

@ -17,19 +17,19 @@ namespace ts.JsTyping {
interface PackageJson {
_requiredBy?: string[];
dependencies?: Map<string>;
devDependencies?: Map<string>;
dependencies?: MapLike<string>;
devDependencies?: MapLike<string>;
name?: string;
optionalDependencies?: Map<string>;
peerDependencies?: Map<string>;
optionalDependencies?: MapLike<string>;
peerDependencies?: MapLike<string>;
typings?: string;
};
// A map of loose file names to library names
// that we are confident require typings
let safeList: Map<string>;
let safeList: Map<string, string>;
const EmptySafeList: Map<string> = createMap<string>();
const EmptySafeList = new StringMap<string>();
/**
* @param host is the object providing I/O related operations.
@ -45,13 +45,13 @@ namespace ts.JsTyping {
fileNames: string[],
projectRootPath: Path,
safeListPath: Path,
packageNameToTypingLocation: Map<string>,
packageNameToTypingLocation: Map<string, string>,
typingOptions: TypingOptions,
compilerOptions: CompilerOptions):
{ cachedTypingPaths: string[], newTypingNames: string[], filesToWatch: string[] } {
// A typing name to typing file path mapping
const inferredTypings = createMap<string>();
const inferredTypings = new StringMap<string | undefined>();
if (!typingOptions || !typingOptions.enableAutoDiscovery) {
return { cachedTypingPaths: [], newTypingNames: [], filesToWatch: [] };
@ -65,7 +65,7 @@ namespace ts.JsTyping {
if (!safeList) {
const result = readConfigFile(safeListPath, (path: string) => host.readFile(path));
safeList = result.config ? createMap<string>(result.config) : EmptySafeList;
safeList = result.config ? mapOfMapLike<string>(result.config) : EmptySafeList;
}
const filesToWatch: string[] = [];
@ -94,27 +94,28 @@ namespace ts.JsTyping {
getTypingNamesFromSourceFileNames(fileNames);
// Add the cached typing locations for inferred typings that are already installed
for (const name in packageNameToTypingLocation) {
if (name in inferredTypings && !inferredTypings[name]) {
inferredTypings[name] = packageNameToTypingLocation[name];
packageNameToTypingLocation.forEach((typingLocation, name) => {
if (inferredTypings.has(name) && inferredTypings.get(name) === undefined) {
inferredTypings.set(name, typingLocation);
}
}
});
// Remove typings that the user has added to the exclude list
for (const excludeTypingName of exclude) {
delete inferredTypings[excludeTypingName];
inferredTypings.delete(excludeTypingName);
}
const newTypingNames: string[] = [];
const cachedTypingPaths: string[] = [];
for (const typing in inferredTypings) {
if (inferredTypings[typing] !== undefined) {
cachedTypingPaths.push(inferredTypings[typing]);
inferredTypings.forEach((inferredTyping, typing) => {
if (inferredTyping !== undefined) {
cachedTypingPaths.push(inferredTyping);
}
else {
newTypingNames.push(typing);
}
}
});
return { cachedTypingPaths, newTypingNames, filesToWatch };
/**
@ -126,8 +127,8 @@ namespace ts.JsTyping {
}
for (const typing of typingNames) {
if (!(typing in inferredTypings)) {
inferredTypings[typing] = undefined;
if (!inferredTypings.has(typing)) {
inferredTypings.set(typing, undefined);
}
}
}
@ -167,7 +168,7 @@ namespace ts.JsTyping {
const cleanedTypingNames = map(inferredTypingNames, f => f.replace(/((?:\.|-)min(?=\.|$))|((?:-|\.)\d+)/g, ""));
if (safeList !== EmptySafeList) {
mergeTypings(filter(cleanedTypingNames, f => f in safeList));
mergeTypings(filter(cleanedTypingNames, f => safeList.has(f)));
}
const hasJsxFile = forEach(fileNames, f => ensureScriptKind(f, getScriptKindFromFileName(f)) === ScriptKind.JSX);
@ -214,7 +215,7 @@ namespace ts.JsTyping {
}
if (packageJson.typings) {
const absolutePath = getNormalizedAbsolutePath(packageJson.typings, getDirectoryPath(normalizedFileName));
inferredTypings[packageJson.name] = absolutePath;
inferredTypings.set(packageJson.name, absolutePath);
}
else {
typingNames.push(packageJson.name);

View File

@ -10,23 +10,22 @@ namespace ts.NavigateTo {
const baseSensitivity: Intl.CollatorOptions = { sensitivity: "base" };
// Search the declarations in all files and output matched NavigateToItem into array of NavigateToItem[]
forEach(sourceFiles, sourceFile => {
for (const sourceFile of sourceFiles) {
cancellationToken.throwIfCancellationRequested();
if (excludeDtsFiles && fileExtensionIs(sourceFile.fileName, ".d.ts")) {
return;
continue;
}
const nameToDeclarations = sourceFile.getNamedDeclarations();
for (const name in nameToDeclarations) {
const declarations = nameToDeclarations[name];
// Use `someInMap` to break out early.
someInMap(sourceFile.getNamedDeclarations(), (declarations, 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.
let matches = patternMatcher.getMatchesForLastSegmentOfPattern(name);
if (!matches) {
continue;
return false;
}
for (const declaration of declarations) {
@ -35,13 +34,13 @@ namespace ts.NavigateTo {
if (patternMatcher.patternContainsDots) {
const containers = getContainers(declaration);
if (!containers) {
return undefined;
return true; // Go to the next source file.
}
matches = patternMatcher.getMatches(containers, name);
if (!matches) {
continue;
return false;
}
}
@ -50,8 +49,8 @@ namespace ts.NavigateTo {
rawItems.push({ name, fileName, matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration });
}
}
}
});
});
}
// Remove imports when the imported declaration is already in the list and has the same name.
rawItems = filter(rawItems, item => {

View File

@ -232,7 +232,7 @@ namespace ts.NavigationBar {
/** Merge declarations of the same kind. */
function mergeChildren(children: NavigationBarNode[]): void {
const nameToItems = createMap<NavigationBarNode | NavigationBarNode[]>();
const nameToItems = new StringMap<NavigationBarNode | NavigationBarNode[]>();
filterMutate(children, child => {
const decl = <Declaration>child.node;
const name = decl.name && nodeText(decl.name);
@ -241,9 +241,9 @@ namespace ts.NavigationBar {
return true;
}
const itemsWithSameName = nameToItems[name];
const itemsWithSameName = nameToItems.get(name);
if (!itemsWithSameName) {
nameToItems[name] = child;
nameToItems.set(name, child);
return true;
}
@ -261,7 +261,7 @@ namespace ts.NavigationBar {
if (tryMerge(itemWithSameName, child)) {
return false;
}
nameToItems[name] = [itemWithSameName, child];
nameToItems.set(name, [itemWithSameName, child]);
return true;
}

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 = createMap<TextSpan[]>();
const stringToWordSpans = new StringMap<TextSpan[]>();
pattern = pattern.trim();
@ -188,11 +188,7 @@ namespace ts {
}
function getWordSpans(word: string): TextSpan[] {
if (!(word in stringToWordSpans)) {
stringToWordSpans[word] = breakIntoWordSpans(word);
}
return stringToWordSpans[word];
return getOrUpdate(stringToWordSpans, word, breakIntoWordSpans);
}
function matchTextChunk(candidate: string, chunk: TextChunk, punctuationStripped: boolean): PatternMatch {

View File

@ -456,13 +456,13 @@ namespace ts {
public scriptKind: ScriptKind;
public languageVersion: ScriptTarget;
public languageVariant: LanguageVariant;
public identifiers: Map<string>;
public nameTable: Map<number>;
public resolvedModules: Map<ResolvedModule>;
public resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
public identifiers: Map<string, string>;
public nameTable: Map<string, number>;
public resolvedModules: Map<string, ResolvedModule>;
public resolvedTypeReferenceDirectiveNames: Map<string, ResolvedTypeReferenceDirective>;
public imports: LiteralExpression[];
public moduleAugmentations: LiteralExpression[];
private namedDeclarations: Map<Declaration[]>;
private namedDeclarations: Map<string, Declaration[]>;
constructor(kind: SyntaxKind, pos: number, end: number) {
super(kind, pos, end);
@ -484,7 +484,7 @@ namespace ts {
return ts.getPositionOfLineAndCharacter(this, line, character);
}
public getNamedDeclarations(): Map<Declaration[]> {
public getNamedDeclarations(): Map<string, Declaration[]> {
if (!this.namedDeclarations) {
this.namedDeclarations = this.computeNamedDeclarations();
}
@ -492,8 +492,8 @@ namespace ts {
return this.namedDeclarations;
}
private computeNamedDeclarations(): Map<Declaration[]> {
const result = createMap<Declaration[]>();
private computeNamedDeclarations(): Map<string, Declaration[]> {
const result = new StringMap<Declaration[]>();
forEachChild(this, visit);
@ -507,7 +507,7 @@ namespace ts {
}
function getDeclarations(name: string) {
return result[name] || (result[name] = []);
return getOrUpdate(result, name, () => []);
}
function getDeclarationName(declaration: Declaration) {
@ -953,7 +953,7 @@ namespace ts {
const currentDirectory = host.getCurrentDirectory();
// Check if the localized messages json is set, otherwise query the host for it
if (!localizedDiagnosticMessages && host.getLocalizedDiagnosticMessages) {
localizedDiagnosticMessages = host.getLocalizedDiagnosticMessages();
localizedDiagnosticMessages = mapOfMapLike<string>(host.getLocalizedDiagnosticMessages());
}
function log(message: string) {
@ -1876,7 +1876,7 @@ namespace ts {
}
/* @internal */
export function getNameTable(sourceFile: SourceFile): Map<number> {
export function getNameTable(sourceFile: SourceFile): Map<string, number> {
if (!sourceFile.nameTable) {
initializeNameTable(sourceFile);
}
@ -1885,7 +1885,7 @@ namespace ts {
}
function initializeNameTable(sourceFile: SourceFile): void {
const nameTable = createMap<number>();
const nameTable = new StringMap<number>();
walk(sourceFile);
sourceFile.nameTable = nameTable;
@ -1893,7 +1893,7 @@ namespace ts {
function walk(node: Node) {
switch (node.kind) {
case SyntaxKind.Identifier:
nameTable[(<Identifier>node).text] = nameTable[(<Identifier>node).text] === undefined ? node.pos : -1;
nameTable.set((<Identifier>node).text, nameTable.get((<Identifier>node).text) === undefined ? node.pos : -1);
break;
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
@ -1906,7 +1906,7 @@ namespace ts {
isArgumentOfElementAccessExpression(node) ||
isLiteralComputedPropertyDeclarationName(node)) {
nameTable[(<LiteralExpression>node).text] = nameTable[(<LiteralExpression>node).text] === undefined ? node.pos : -1;
nameTable.set((<LiteralExpression>node).text, nameTable.get((<LiteralExpression>node).text) === undefined ? node.pos : -1);
}
break;
default:

View File

@ -1157,7 +1157,7 @@ namespace ts {
info.fileNames,
toPath(info.projectRootPath, info.projectRootPath, getCanonicalFileName),
toPath(info.safeListPath, info.safeListPath, getCanonicalFileName),
info.packageNameToTypingLocation,
mapOfMapLike(info.packageNameToTypingLocation),
info.typingOptions,
info.compilerOptions);
});

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 = nameToDeclarations[name.text];
const declarations = nameToDeclarations.get(name.text);
if (declarations) {
for (const declaration of declarations) {

View File

@ -63,7 +63,7 @@ namespace ts {
}
if (transpileOptions.renamedDependencies) {
sourceFile.renamedDependencies = createMap(transpileOptions.renamedDependencies);
sourceFile.renamedDependencies = mapOfMapLike(transpileOptions.renamedDependencies);
}
const newLine = getNewLineCharacter(options);
@ -126,7 +126,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" && !forEachProperty(o.type, v => typeof v !== "number"));
typeof o.type === "object" && !someValueInMap(o.type, v => typeof v !== "number"));
options = clone(options);
@ -142,7 +142,7 @@ namespace ts {
options[opt.name] = parseCustomTypeOption(opt, value, diagnostics);
}
else {
if (!forEachProperty(opt.type, v => v === value)) {
if (!someValueInMap(opt.type, v => v === value)) {
// Supplied value isn't a valid enum value.
diagnostics.push(createCompilerDiagnosticForInvalidCustomType(opt));
}

View File

@ -48,9 +48,9 @@ namespace ts {
export interface SourceFile {
/* @internal */ version: string;
/* @internal */ scriptSnapshot: IScriptSnapshot;
/* @internal */ nameTable: Map<number>;
/* @internal */ nameTable: Map<string, number>;
/* @internal */ getNamedDeclarations(): Map<Declaration[]>;
/* @internal */ getNamedDeclarations(): Map<string, Declaration[]>;
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
getLineStarts(): number[];

View File

@ -47,6 +47,7 @@
"prefer-const": true,
"no-increment-decrement": true,
"object-literal-surrounding-space": true,
"no-type-assertion-whitespace": true
"no-type-assertion-whitespace": true,
"no-in-operator": true
}
}