mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-12 01:48:33 -05:00
Revert "Merge pull request #11354 from Microsoft/map4"
This reverts commitadfdae0dc4, reversing changes made toaad663cebf.
This commit is contained in:
@@ -346,26 +346,25 @@ namespace ts.server {
|
||||
|
||||
// Use slice to clone the array to avoid manipulating in place
|
||||
const queue = fileInfo.referencedBy.slice(0);
|
||||
const fileNameSet = createMap<string, ScriptInfo>();
|
||||
fileNameSet.set(scriptInfo.fileName, scriptInfo);
|
||||
const fileNameSet = createMap<ScriptInfo>();
|
||||
fileNameSet[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.get(potentialFileInfo.scriptInfo.fileName)) {
|
||||
if (!fileNameSet[potentialFileInfo.scriptInfo.fileName]) {
|
||||
queue.push(potentialFileInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
fileNameSet.set(processingFileInfo.scriptInfo.fileName, processingFileInfo.scriptInfo);
|
||||
fileNameSet[processingFileInfo.scriptInfo.fileName] = processingFileInfo.scriptInfo;
|
||||
}
|
||||
|
||||
const result: string[] = [];
|
||||
fileNameSet.forEach((scriptInfo, fileName) => {
|
||||
if (shouldEmitFile(scriptInfo)) {
|
||||
for (const fileName in fileNameSet) {
|
||||
if (shouldEmitFile(fileNameSet[fileName])) {
|
||||
result.push(fileName);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace ts.server {
|
||||
|
||||
export class SessionClient implements LanguageService {
|
||||
private sequence: number = 0;
|
||||
private lineMaps = ts.createMap<string, number[]>();
|
||||
private lineMaps: ts.Map<number[]> = ts.createMap<number[]>();
|
||||
private messages: string[] = [];
|
||||
private lastRenameEntry: RenameEntry;
|
||||
|
||||
@@ -31,10 +31,10 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
private getLineMap(fileName: string): number[] {
|
||||
let lineMap = this.lineMaps.get(fileName);
|
||||
let lineMap = this.lineMaps[fileName];
|
||||
if (!lineMap) {
|
||||
const scriptSnapshot = this.host.getScriptSnapshot(fileName);
|
||||
lineMap = setAndReturn(this.lineMaps, fileName, ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength())));
|
||||
lineMap = this.lineMaps[fileName] = ts.computeLineStarts(scriptSnapshot.getText(0, scriptSnapshot.getLength()));
|
||||
}
|
||||
return lineMap;
|
||||
}
|
||||
@@ -140,7 +140,7 @@ namespace ts.server {
|
||||
|
||||
changeFile(fileName: string, start: number, end: number, newText: string): void {
|
||||
// clear the line map after an edit
|
||||
this.lineMaps.set(fileName, undefined);
|
||||
this.lineMaps[fileName] = undefined;
|
||||
|
||||
const lineOffset = this.positionToOneBasedLineOffset(fileName, start);
|
||||
const endLineOffset = this.positionToOneBasedLineOffset(fileName, end);
|
||||
|
||||
@@ -17,23 +17,23 @@ namespace ts.server {
|
||||
(event: ProjectServiceEvent): void;
|
||||
}
|
||||
|
||||
function prepareConvertersForEnumLikeCompilerOptions(commandLineOptions: CommandLineOption[]): Map<string, Map<string, number>> {
|
||||
const map = createMap<string, Map<string, number>>();
|
||||
function prepareConvertersForEnumLikeCompilerOptions(commandLineOptions: CommandLineOption[]): Map<Map<number>> {
|
||||
const map: Map<Map<number>> = createMap<Map<number>>();
|
||||
for (const option of commandLineOptions) {
|
||||
if (typeof option.type === "object") {
|
||||
const optionMap = <Map<string, number>>option.type;
|
||||
const optionMap = <Map<number>>option.type;
|
||||
// verify that map contains only numbers
|
||||
optionMap.forEach(value => {
|
||||
Debug.assert(typeof value === "number");
|
||||
});
|
||||
map.set(option.name, optionMap);
|
||||
for (const id in optionMap) {
|
||||
Debug.assert(typeof optionMap[id] === "number");
|
||||
}
|
||||
map[option.name] = optionMap;
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
const compilerOptionConverters = prepareConvertersForEnumLikeCompilerOptions(optionDeclarations);
|
||||
const indentStyle = mapOfMapLike({
|
||||
const indentStyle = createMap({
|
||||
"none": IndentStyle.None,
|
||||
"block": IndentStyle.Block,
|
||||
"smart": IndentStyle.Smart
|
||||
@@ -41,20 +41,20 @@ namespace ts.server {
|
||||
|
||||
export function convertFormatOptions(protocolOptions: protocol.FormatCodeSettings): FormatCodeSettings {
|
||||
if (typeof protocolOptions.indentStyle === "string") {
|
||||
protocolOptions.indentStyle = indentStyle.get(protocolOptions.indentStyle.toLowerCase());
|
||||
protocolOptions.indentStyle = indentStyle[protocolOptions.indentStyle.toLowerCase()];
|
||||
Debug.assert(protocolOptions.indentStyle !== undefined);
|
||||
}
|
||||
return <any>protocolOptions;
|
||||
}
|
||||
|
||||
export function convertCompilerOptions(protocolOptions: protocol.ExternalProjectCompilerOptions): CompilerOptions & protocol.CompileOnSaveMixin {
|
||||
forEachKeyInMap(compilerOptionConverters, id => {
|
||||
for (const id in compilerOptionConverters) {
|
||||
const propertyValue = protocolOptions[id];
|
||||
if (typeof propertyValue === "string") {
|
||||
const mappedValues = compilerOptionConverters.get(id);
|
||||
protocolOptions[id] = mappedValues.get(propertyValue.toLowerCase());
|
||||
const mappedValues = compilerOptionConverters[id];
|
||||
protocolOptions[id] = mappedValues[propertyValue.toLowerCase()];
|
||||
}
|
||||
});
|
||||
}
|
||||
return <any>protocolOptions;
|
||||
}
|
||||
|
||||
@@ -159,24 +159,23 @@ namespace ts.server {
|
||||
/**
|
||||
* a path to directory watcher map that detects added tsconfig files
|
||||
**/
|
||||
private readonly directoryWatchersForTsconfig = createMap<string, FileWatcher>();
|
||||
private readonly directoryWatchersForTsconfig: Map<FileWatcher> = createMap<FileWatcher>();
|
||||
/**
|
||||
* count of how many projects are using the directory watcher.
|
||||
* If the number becomes 0 for a watcher, then we should close it.
|
||||
**/
|
||||
private readonly directoryWatchersRefCount = createMap<string, number>();
|
||||
private readonly directoryWatchersRefCount: Map<number> = createMap<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
|
||||
const refCount = this.directoryWatchersRefCount.get(directory) - 1;
|
||||
this.directoryWatchersRefCount.set(directory, refCount);
|
||||
if (refCount === 0) {
|
||||
this.directoryWatchersRefCount[directory]--;
|
||||
if (this.directoryWatchersRefCount[directory] === 0) {
|
||||
this.projectService.logger.info(`Close directory watcher for: ${directory}`);
|
||||
this.directoryWatchersForTsconfig.get(directory).close();
|
||||
this.directoryWatchersForTsconfig.delete(directory);
|
||||
this.directoryWatchersForTsconfig[directory].close();
|
||||
delete this.directoryWatchersForTsconfig[directory];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,13 +183,13 @@ namespace ts.server {
|
||||
let currentPath = getDirectoryPath(fileName);
|
||||
let parentPath = getDirectoryPath(currentPath);
|
||||
while (currentPath != parentPath) {
|
||||
if (!this.directoryWatchersForTsconfig.get(currentPath)) {
|
||||
if (!this.directoryWatchersForTsconfig[currentPath]) {
|
||||
this.projectService.logger.info(`Add watcher for: ${currentPath}`);
|
||||
this.directoryWatchersForTsconfig.set(currentPath, this.projectService.host.watchDirectory(currentPath, callback));
|
||||
this.directoryWatchersRefCount.set(currentPath, 1);
|
||||
this.directoryWatchersForTsconfig[currentPath] = this.projectService.host.watchDirectory(currentPath, callback);
|
||||
this.directoryWatchersRefCount[currentPath] = 1;
|
||||
}
|
||||
else {
|
||||
modifyValue(this.directoryWatchersRefCount, currentPath, count => count + 1);
|
||||
this.directoryWatchersRefCount[currentPath] += 1;
|
||||
}
|
||||
project.directoriesWatchedForTsconfig.push(currentPath);
|
||||
currentPath = parentPath;
|
||||
@@ -212,7 +211,7 @@ namespace ts.server {
|
||||
/**
|
||||
* maps external project file name to list of config files that were the part of this project
|
||||
*/
|
||||
private readonly externalProjectToConfiguredProjectMap = createMap<string, NormalizedPath[]>();
|
||||
private readonly externalProjectToConfiguredProjectMap: Map<NormalizedPath[]> = createMap<NormalizedPath[]>();
|
||||
|
||||
/**
|
||||
* external projects (configuration and list of root files is not controlled by tsserver)
|
||||
@@ -393,7 +392,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);
|
||||
@@ -412,7 +411,7 @@ namespace ts.server {
|
||||
this.filenameToScriptInfo.remove(info.path);
|
||||
this.lastDeletedFile = info;
|
||||
|
||||
// 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();
|
||||
@@ -563,7 +562,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) {
|
||||
@@ -573,7 +572,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
|
||||
@@ -785,7 +784,7 @@ namespace ts.server {
|
||||
files: parsedCommandLine.fileNames,
|
||||
compilerOptions: parsedCommandLine.options,
|
||||
configHasFilesProperty: config["files"] !== undefined,
|
||||
wildcardDirectories: parsedCommandLine.wildcardDirectories,
|
||||
wildcardDirectories: createMap(parsedCommandLine.wildcardDirectories),
|
||||
typingOptions: parsedCommandLine.typingOptions,
|
||||
compileOnSave: parsedCommandLine.compileOnSave
|
||||
};
|
||||
@@ -844,7 +843,7 @@ namespace ts.server {
|
||||
this.documentRegistry,
|
||||
projectOptions.configHasFilesProperty,
|
||||
projectOptions.compilerOptions,
|
||||
mapOfMapLike(projectOptions.wildcardDirectories),
|
||||
projectOptions.wildcardDirectories,
|
||||
/*languageServiceEnabled*/ !sizeLimitExceeded,
|
||||
projectOptions.compileOnSave === undefined ? false : projectOptions.compileOnSave);
|
||||
|
||||
@@ -902,7 +901,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: Map<NormalizedPath, ScriptInfo> = createMap<string, ScriptInfo>();
|
||||
const newRootScriptInfoMap: NormalizedPathMap<ScriptInfo> = createNormalizedPathMap<ScriptInfo>();
|
||||
|
||||
let projectErrors: Diagnostic[];
|
||||
let rootFilesChanged = false;
|
||||
@@ -930,7 +929,7 @@ namespace ts.server {
|
||||
let toAdd: ScriptInfo[];
|
||||
let toRemove: ScriptInfo[];
|
||||
for (const oldFile of oldRootScriptInfos) {
|
||||
if (!newRootScriptInfoMap.has(oldFile.fileName)) {
|
||||
if (!newRootScriptInfoMap.contains(oldFile.fileName)) {
|
||||
(toRemove || (toRemove = [])).push(oldFile);
|
||||
}
|
||||
}
|
||||
@@ -947,7 +946,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);
|
||||
@@ -1096,7 +1095,7 @@ namespace ts.server {
|
||||
this.logger.info(`Host information ${args.hostInfo}`);
|
||||
}
|
||||
if (args.formatOptions) {
|
||||
mergeMapLikes(this.hostConfiguration.formatCodeOptions, convertFormatOptions(args.formatOptions));
|
||||
mergeMaps(this.hostConfiguration.formatCodeOptions, convertFormatOptions(args.formatOptions));
|
||||
this.logger.info("Format host information updated");
|
||||
}
|
||||
}
|
||||
@@ -1218,7 +1217,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);
|
||||
@@ -1255,7 +1254,7 @@ namespace ts.server {
|
||||
|
||||
closeExternalProject(uncheckedFileName: string, suppressRefresh = false): void {
|
||||
const fileName = toNormalizedPath(uncheckedFileName);
|
||||
const configFiles = this.externalProjectToConfiguredProjectMap.get(fileName);
|
||||
const configFiles = this.externalProjectToConfiguredProjectMap[fileName];
|
||||
if (configFiles) {
|
||||
let shouldRefreshInferredProjects = false;
|
||||
for (const configFile of configFiles) {
|
||||
@@ -1263,7 +1262,7 @@ namespace ts.server {
|
||||
shouldRefreshInferredProjects = true;
|
||||
}
|
||||
}
|
||||
this.externalProjectToConfiguredProjectMap.delete(fileName);
|
||||
delete this.externalProjectToConfiguredProjectMap[fileName];
|
||||
if (shouldRefreshInferredProjects && !suppressRefresh) {
|
||||
this.refreshInferredProjects();
|
||||
}
|
||||
@@ -1310,46 +1309,43 @@ 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 {
|
||||
const oldConfigFiles = this.externalProjectToConfiguredProjectMap.get(proj.projectFileName);
|
||||
if (oldConfigFiles) {
|
||||
// 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
|
||||
this.closeExternalProject(proj.projectFileName, /*suppressRefresh*/ true);
|
||||
else if (this.externalProjectToConfiguredProjectMap[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
|
||||
this.closeExternalProject(proj.projectFileName, /*suppressRefresh*/ true);
|
||||
}
|
||||
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];
|
||||
let iNew = 0;
|
||||
let iOld = 0;
|
||||
while (iNew < tsConfigFiles.length && iOld < oldConfigFiles.length) {
|
||||
const newConfig = tsConfigFiles[iNew];
|
||||
const oldConfig = oldConfigFiles[iOld];
|
||||
if (oldConfig < newConfig) {
|
||||
this.closeConfiguredProject(oldConfig);
|
||||
iOld++;
|
||||
}
|
||||
else if (oldConfig > newConfig) {
|
||||
iNew++;
|
||||
}
|
||||
else {
|
||||
// record existing config files so avoid extra add-refs
|
||||
(exisingConfigFiles || (exisingConfigFiles = [])).push(oldConfig);
|
||||
iOld++;
|
||||
iNew++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// project previously had some config files - compare them with new set of files and close all configured projects that correspond to unused files
|
||||
let iNew = 0;
|
||||
let iOld = 0;
|
||||
while (iNew < tsConfigFiles.length && iOld < oldConfigFiles.length) {
|
||||
const newConfig = tsConfigFiles[iNew];
|
||||
const oldConfig = oldConfigFiles[iOld];
|
||||
if (oldConfig < newConfig) {
|
||||
this.closeConfiguredProject(oldConfig);
|
||||
iOld++;
|
||||
}
|
||||
else if (oldConfig > newConfig) {
|
||||
iNew++;
|
||||
}
|
||||
else {
|
||||
// record existing config files so avoid extra add-refs
|
||||
(exisingConfigFiles || (exisingConfigFiles = [])).push(oldConfig);
|
||||
iOld++;
|
||||
iNew++;
|
||||
}
|
||||
}
|
||||
for (let i = iOld; i < oldConfigFiles.length; i++) {
|
||||
// projects for all remaining old config files should be closed
|
||||
this.closeConfiguredProject(oldConfigFiles[i]);
|
||||
}
|
||||
for (let i = iOld; i < oldConfigFiles.length; i++) {
|
||||
// projects for all remaining old config files should be closed
|
||||
this.closeConfiguredProject(oldConfigFiles[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tsConfigFiles) {
|
||||
// store the list of tsconfig files that belong to the external project
|
||||
this.externalProjectToConfiguredProjectMap.set(proj.projectFileName, tsConfigFiles);
|
||||
this.externalProjectToConfiguredProjectMap[proj.projectFileName] = tsConfigFiles;
|
||||
for (const tsconfigFile of tsConfigFiles) {
|
||||
let project = this.findConfiguredProjectByProjectName(tsconfigFile);
|
||||
if (!project) {
|
||||
@@ -1365,7 +1361,7 @@ namespace ts.server {
|
||||
}
|
||||
else {
|
||||
// no config files - remove the item from the collection
|
||||
this.externalProjectToConfiguredProjectMap.delete(proj.projectFileName);
|
||||
delete this.externalProjectToConfiguredProjectMap[proj.projectFileName];
|
||||
this.createAndAddExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typingOptions);
|
||||
}
|
||||
this.refreshInferredProjects();
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
namespace ts.server {
|
||||
export class LSHost implements ts.LanguageServiceHost, ModuleResolutionHost, ServerLanguageServiceHost {
|
||||
private compilationSettings: ts.CompilerOptions;
|
||||
private readonly resolvedModuleNames = createFileMap<Map<string, ResolvedModuleWithFailedLookupLocations>>();
|
||||
private readonly resolvedTypeReferenceDirectives = createFileMap<Map<string, ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
|
||||
private readonly resolvedModuleNames= createFileMap<Map<ResolvedModuleWithFailedLookupLocations>>();
|
||||
private readonly resolvedTypeReferenceDirectives = createFileMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
|
||||
private readonly getCanonicalFileName: (fileName: string) => string;
|
||||
|
||||
private filesWithChangedSetOfUnresolvedImports: Path[];
|
||||
@@ -54,7 +54,7 @@ namespace ts.server {
|
||||
private resolveNamesWithLocalCache<T extends { failedLookupLocations: string[] }, R>(
|
||||
names: string[],
|
||||
containingFile: string,
|
||||
cache: ts.FileMap<Map<string, T>>,
|
||||
cache: ts.FileMap<Map<T>>,
|
||||
loader: (name: string, containingFile: string, options: CompilerOptions, host: ModuleResolutionHost) => T,
|
||||
getResult: (s: T) => R,
|
||||
getResultFileName: (result: R) => string | undefined,
|
||||
@@ -63,22 +63,22 @@ namespace ts.server {
|
||||
const path = toPath(containingFile, this.host.getCurrentDirectory(), this.getCanonicalFileName);
|
||||
const currentResolutionsInFile = cache.get(path);
|
||||
|
||||
const newResolutions = createMap<string, T>();
|
||||
const newResolutions: Map<T> = createMap<T>();
|
||||
const resolvedModules: R[] = [];
|
||||
const compilerOptions = this.getCompilationSettings();
|
||||
const lastDeletedFileName = this.project.projectService.lastDeletedFile && this.project.projectService.lastDeletedFile.fileName;
|
||||
|
||||
for (const name of names) {
|
||||
// check if this is a duplicate entry in the list
|
||||
let resolution = newResolutions.get(name);
|
||||
let resolution = newResolutions[name];
|
||||
if (!resolution) {
|
||||
const existingResolution = currentResolutionsInFile && currentResolutionsInFile.get(name);
|
||||
const existingResolution = currentResolutionsInFile && currentResolutionsInFile[name];
|
||||
if (moduleResolutionIsValid(existingResolution)) {
|
||||
// ok, it is safe to use existing name resolution results
|
||||
resolution = existingResolution;
|
||||
}
|
||||
else {
|
||||
newResolutions.set(name, resolution = loader(name, containingFile, compilerOptions, this));
|
||||
newResolutions[name] = resolution = loader(name, containingFile, compilerOptions, this);
|
||||
}
|
||||
if (logChanges && this.filesWithChangedSetOfUnresolvedImports && !resolutionIsEqualTo(existingResolution, resolution)) {
|
||||
this.filesWithChangedSetOfUnresolvedImports.push(path);
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace ts.server {
|
||||
/**
|
||||
* Set of files that was returned from the last call to getChangesSinceVersion.
|
||||
*/
|
||||
private lastReportedFileNames: Map<string, string>;
|
||||
private lastReportedFileNames: Map<string>;
|
||||
/**
|
||||
* Last version that was reported.
|
||||
*/
|
||||
@@ -385,9 +385,9 @@ namespace ts.server {
|
||||
}
|
||||
let unresolvedImports: string[];
|
||||
if (file.resolvedModules) {
|
||||
file.resolvedModules.forEach((resolvedModule, name) => {
|
||||
for (const name in file.resolvedModules) {
|
||||
// pick unresolved non-relative names
|
||||
if (!resolvedModule && !isExternalModuleNameRelative(name)) {
|
||||
if (!file.resolvedModules[name] && !isExternalModuleNameRelative(name)) {
|
||||
// for non-scoped names extract part up-to the first slash
|
||||
// for scoped names - extract up to the second slash
|
||||
let trimmed = name.trim();
|
||||
@@ -401,7 +401,7 @@ namespace ts.server {
|
||||
(unresolvedImports || (unresolvedImports = [])).push(trimmed);
|
||||
result.push(trimmed);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
this.cachedUnresolvedImportsPerFile.set(file.path, unresolvedImports || emptyArray);
|
||||
}
|
||||
@@ -427,7 +427,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
// 1. no changes in structure, no changes in unresolved imports - do nothing
|
||||
// 2. no changes in structure, unresolved imports were changed - collect unresolved imports for all files
|
||||
// 2. no changes in structure, unresolved imports were changed - collect unresolved imports for all files
|
||||
// (can reuse cached imports for files that were not changed)
|
||||
// 3. new files were added/removed, but compilation settings stays the same - collect unresolved imports for all new/modified files
|
||||
// (can reuse cached imports for files that were not changed)
|
||||
@@ -568,16 +568,16 @@ namespace ts.server {
|
||||
|
||||
const added: string[] = [];
|
||||
const removed: string[] = [];
|
||||
forEachKeyInMap(currentFiles, id => {
|
||||
if (!lastReportedFileNames.has(id)) {
|
||||
for (const id in currentFiles) {
|
||||
if (!hasProperty(lastReportedFileNames, id)) {
|
||||
added.push(id);
|
||||
}
|
||||
});
|
||||
forEachKeyInMap(lastReportedFileNames, id => {
|
||||
if (!currentFiles.has(id)) {
|
||||
}
|
||||
for (const id in lastReportedFileNames) {
|
||||
if (!hasProperty(currentFiles, id)) {
|
||||
removed.push(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.lastReportedFileNames = currentFiles;
|
||||
this.lastReportedVersion = this.projectStructureVersion;
|
||||
return { info, changes: { added, removed }, projectErrors: this.projectErrors };
|
||||
@@ -603,7 +603,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 = createSet();
|
||||
const referencedFiles = createMap<boolean>();
|
||||
if (sourceFile.imports && sourceFile.imports.length > 0) {
|
||||
const checker: TypeChecker = this.program.getTypeChecker();
|
||||
for (const importName of sourceFile.imports) {
|
||||
@@ -611,7 +611,7 @@ namespace ts.server {
|
||||
if (symbol && symbol.declarations && symbol.declarations[0]) {
|
||||
const declarationSourceFile = symbol.declarations[0].getSourceFile();
|
||||
if (declarationSourceFile) {
|
||||
referencedFiles.add(declarationSourceFile.path);
|
||||
referencedFiles[declarationSourceFile.path] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -623,24 +623,26 @@ namespace ts.server {
|
||||
if (sourceFile.referencedFiles && sourceFile.referencedFiles.length > 0) {
|
||||
for (const referencedFile of sourceFile.referencedFiles) {
|
||||
const referencedPath = toPath(referencedFile.fileName, currentDirectory, getCanonicalFileName);
|
||||
referencedFiles.add(referencedPath);
|
||||
referencedFiles[referencedPath] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle type reference directives
|
||||
if (sourceFile.resolvedTypeReferenceDirectiveNames) {
|
||||
sourceFile.resolvedTypeReferenceDirectiveNames.forEach(resolvedTypeReferenceDirective => {
|
||||
for (const typeName in sourceFile.resolvedTypeReferenceDirectiveNames) {
|
||||
const resolvedTypeReferenceDirective = sourceFile.resolvedTypeReferenceDirectiveNames[typeName];
|
||||
if (!resolvedTypeReferenceDirective) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
const fileName = resolvedTypeReferenceDirective.resolvedFileName;
|
||||
const typeFilePath = toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
referencedFiles.add(typeFilePath);
|
||||
});
|
||||
referencedFiles[typeFilePath] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return filterSetToArray(referencedFiles, file => this.projectService.host.fileExists(file)) as Path[];
|
||||
const allFileNames = map(Object.keys(referencedFiles), key => <Path>key);
|
||||
return filter(allFileNames, file => this.projectService.host.fileExists(file));
|
||||
}
|
||||
|
||||
// remove a root file from project
|
||||
@@ -711,7 +713,7 @@ namespace ts.server {
|
||||
private typingOptions: TypingOptions;
|
||||
private projectFileWatcher: FileWatcher;
|
||||
private directoryWatcher: FileWatcher;
|
||||
private directoriesWatchedForWildcards: Map<string, FileWatcher>;
|
||||
private directoriesWatchedForWildcards: Map<FileWatcher>;
|
||||
private typeRootsWatchers: FileWatcher[];
|
||||
|
||||
/** Used for configured projects which may have multiple open roots */
|
||||
@@ -722,7 +724,7 @@ namespace ts.server {
|
||||
documentRegistry: ts.DocumentRegistry,
|
||||
hasExplicitListOfFiles: boolean,
|
||||
compilerOptions: CompilerOptions,
|
||||
private wildcardDirectories: Map<string, WatchDirectoryFlags>,
|
||||
private wildcardDirectories: Map<WatchDirectoryFlags>,
|
||||
languageServiceEnabled: boolean,
|
||||
public compileOnSaveEnabled: boolean) {
|
||||
super(ProjectKind.Configured, projectService, documentRegistry, hasExplicitListOfFiles, languageServiceEnabled, compilerOptions, compileOnSaveEnabled);
|
||||
@@ -777,19 +779,18 @@ namespace ts.server {
|
||||
return;
|
||||
}
|
||||
const configDirectoryPath = getDirectoryPath(this.configFileName);
|
||||
|
||||
this.directoriesWatchedForWildcards = createMap<string, FileWatcher>();
|
||||
this.wildcardDirectories.forEach((flag, directory) => {
|
||||
this.directoriesWatchedForWildcards = reduceProperties(this.wildcardDirectories, (watchers, 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}`);
|
||||
this.directoriesWatchedForWildcards.set(directory, this.projectService.host.watchDirectory(
|
||||
watchers[directory] = this.projectService.host.watchDirectory(
|
||||
directory,
|
||||
path => callback(this, path),
|
||||
recursive
|
||||
));
|
||||
);
|
||||
}
|
||||
});
|
||||
return watchers;
|
||||
}, <Map<FileWatcher>>{});
|
||||
}
|
||||
|
||||
stopWatchingDirectory() {
|
||||
@@ -813,7 +814,9 @@ namespace ts.server {
|
||||
this.typeRootsWatchers = undefined;
|
||||
}
|
||||
|
||||
this.directoriesWatchedForWildcards.forEach(watcher => { watcher.close(); });
|
||||
for (const id in this.directoriesWatchedForWildcards) {
|
||||
this.directoriesWatchedForWildcards[id].close();
|
||||
}
|
||||
this.directoriesWatchedForWildcards = undefined;
|
||||
|
||||
this.stopWatchingDirectory();
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace ts.server {
|
||||
if (!this.formatCodeSettings) {
|
||||
this.formatCodeSettings = getDefaultFormatCodeSettings(this.host);
|
||||
}
|
||||
mergeMapLikes(this.formatCodeSettings, formatSettings);
|
||||
mergeMaps(this.formatCodeSettings, formatSettings);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1351,7 +1351,7 @@ namespace ts.server {
|
||||
return { response, responseRequired: true };
|
||||
}
|
||||
|
||||
private handlers = mapOfMapLike<(request: protocol.Request) => { response?: any, responseRequired?: boolean }>({
|
||||
private handlers = createMap<(request: protocol.Request) => { response?: any, responseRequired?: boolean }>({
|
||||
[CommandNames.OpenExternalProject]: (request: protocol.OpenExternalProjectRequest) => {
|
||||
this.projectService.openExternalProject(request.arguments);
|
||||
// TODO: report errors
|
||||
@@ -1597,14 +1597,14 @@ namespace ts.server {
|
||||
});
|
||||
|
||||
public addProtocolHandler(command: string, handler: (request: protocol.Request) => { response?: any, responseRequired: boolean }) {
|
||||
if (this.handlers.has(command)) {
|
||||
if (command in this.handlers) {
|
||||
throw new Error(`Protocol handler already exists for command "${command}"`);
|
||||
}
|
||||
this.handlers.set(command, handler);
|
||||
this.handlers[command] = handler;
|
||||
}
|
||||
|
||||
public executeCommand(request: protocol.Request): { response?: any, responseRequired?: boolean } {
|
||||
const handler = this.handlers.get(request.command);
|
||||
const handler = this.handlers[request.command];
|
||||
if (handler) {
|
||||
return handler(request);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"utilities.ts",
|
||||
"scriptVersionCache.ts",
|
||||
"scriptInfo.ts",
|
||||
"lsHost.ts",
|
||||
"lshost.ts",
|
||||
"typingsCache.ts",
|
||||
"project.ts",
|
||||
"editorServices.ts",
|
||||
|
||||
@@ -31,22 +31,21 @@ namespace ts.server {
|
||||
if ((arr1 || emptyArray).length === 0 && (arr2 || emptyArray).length === 0) {
|
||||
return true;
|
||||
}
|
||||
const set = createMap<string, boolean>();
|
||||
const set: Map<boolean> = createMap<boolean>();
|
||||
let unique = 0;
|
||||
|
||||
for (const v of arr1) {
|
||||
if (set.get(v) !== true) {
|
||||
set.set(v, true);
|
||||
if (set[v] !== true) {
|
||||
set[v] = true;
|
||||
unique++;
|
||||
}
|
||||
}
|
||||
for (const v of arr2) {
|
||||
const isSet = set.get(v);
|
||||
if (isSet === undefined) {
|
||||
if (!hasProperty(set, v)) {
|
||||
return false;
|
||||
}
|
||||
if (isSet === true) {
|
||||
set.set(v, false);
|
||||
if (set[v] === true) {
|
||||
set[v] = false;
|
||||
unique--;
|
||||
}
|
||||
}
|
||||
@@ -72,7 +71,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
export class TypingsCache {
|
||||
private readonly perProjectCache = createMap<string, TypingsCacheEntry>();
|
||||
private readonly perProjectCache: Map<TypingsCacheEntry> = createMap<TypingsCacheEntry>();
|
||||
|
||||
constructor(private readonly installer: ITypingsInstaller) {
|
||||
}
|
||||
@@ -84,7 +83,7 @@ namespace ts.server {
|
||||
return <any>emptyArray;
|
||||
}
|
||||
|
||||
const entry = this.perProjectCache.get(project.getProjectName());
|
||||
const entry = this.perProjectCache[project.getProjectName()];
|
||||
const result: SortedReadonlyArray<string> = entry ? entry.typings : <any>emptyArray;
|
||||
if (forceRefresh ||
|
||||
!entry ||
|
||||
@@ -93,13 +92,13 @@ namespace ts.server {
|
||||
unresolvedImportsChanged(unresolvedImports, entry.unresolvedImports)) {
|
||||
// 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.set(project.getProjectName(), {
|
||||
this.perProjectCache[project.getProjectName()] = {
|
||||
compilerOptions: project.getCompilerOptions(),
|
||||
typingOptions,
|
||||
typings: result,
|
||||
unresolvedImports,
|
||||
poisoned: true
|
||||
});
|
||||
};
|
||||
// something has been changed, issue a request to update typings
|
||||
this.installer.enqueueInstallTypingsRequest(project, typingOptions, unresolvedImports);
|
||||
}
|
||||
@@ -107,21 +106,21 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
updateTypingsForProject(projectName: string, compilerOptions: CompilerOptions, typingOptions: TypingOptions, unresolvedImports: SortedReadonlyArray<string>, newTypings: string[]) {
|
||||
this.perProjectCache.set(projectName, {
|
||||
this.perProjectCache[projectName] = {
|
||||
compilerOptions,
|
||||
typingOptions,
|
||||
typings: toSortedReadonlyArray(newTypings),
|
||||
unresolvedImports,
|
||||
poisoned: false
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
deleteTypingsForProject(projectName: string) {
|
||||
this.perProjectCache.delete(projectName);
|
||||
delete this.perProjectCache[projectName];
|
||||
}
|
||||
|
||||
onProjectClosed(project: Project) {
|
||||
this.perProjectCache.delete(project.getProjectName());
|
||||
delete this.perProjectCache[project.getProjectName()];
|
||||
this.installer.onProjectClosed(project);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,10 +78,10 @@ namespace ts.server.typingsInstaller {
|
||||
};
|
||||
|
||||
export abstract class TypingsInstaller {
|
||||
private readonly packageNameToTypingLocation = createMap<string, string>();
|
||||
private readonly missingTypingsSet = createSet();
|
||||
private readonly knownCachesSet = createSet();
|
||||
private readonly projectWatchers = createMap<string, FileWatcher[]>();
|
||||
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[]>();
|
||||
readonly pendingRunRequests: PendingRequest[] = [];
|
||||
|
||||
private installRunCount = 1;
|
||||
@@ -111,7 +111,7 @@ namespace ts.server.typingsInstaller {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Closing file watchers for project '${projectName}'`);
|
||||
}
|
||||
const watchers = this.projectWatchers.get(projectName);
|
||||
const watchers = this.projectWatchers[projectName];
|
||||
if (!watchers) {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`No watchers are registered for project '${projectName}'`);
|
||||
@@ -122,7 +122,7 @@ namespace ts.server.typingsInstaller {
|
||||
w.close();
|
||||
}
|
||||
|
||||
this.projectWatchers.delete(projectName);
|
||||
delete this.projectWatchers[projectName];
|
||||
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Closing file watchers for project '${projectName}' - done.`);
|
||||
@@ -176,7 +176,7 @@ namespace ts.server.typingsInstaller {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Processing cache location '${cacheLocation}'`);
|
||||
}
|
||||
if (this.knownCachesSet.has(cacheLocation)) {
|
||||
if (this.knownCachesSet[cacheLocation]) {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Cache location was already processed...`);
|
||||
}
|
||||
@@ -202,7 +202,7 @@ namespace ts.server.typingsInstaller {
|
||||
if (!typingFile) {
|
||||
continue;
|
||||
}
|
||||
const existingTypingFile = this.packageNameToTypingLocation.get(packageName);
|
||||
const existingTypingFile = this.packageNameToTypingLocation[packageName];
|
||||
if (existingTypingFile === typingFile) {
|
||||
continue;
|
||||
}
|
||||
@@ -214,14 +214,14 @@ namespace ts.server.typingsInstaller {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Adding entry into typings cache: '${packageName}' => '${typingFile}'`);
|
||||
}
|
||||
this.packageNameToTypingLocation.set(packageName, typingFile);
|
||||
this.packageNameToTypingLocation[packageName] = typingFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`Finished processing cache location '${cacheLocation}'`);
|
||||
}
|
||||
this.knownCachesSet.add(cacheLocation);
|
||||
this.knownCachesSet[cacheLocation] = true;
|
||||
}
|
||||
|
||||
private filterTypings(typingsToInstall: string[]) {
|
||||
@@ -230,7 +230,7 @@ namespace ts.server.typingsInstaller {
|
||||
}
|
||||
const result: string[] = [];
|
||||
for (const typing of typingsToInstall) {
|
||||
if (this.missingTypingsSet.has(typing)) {
|
||||
if (this.missingTypingsSet[typing]) {
|
||||
continue;
|
||||
}
|
||||
const validationResult = validatePackageName(typing);
|
||||
@@ -239,7 +239,7 @@ namespace ts.server.typingsInstaller {
|
||||
}
|
||||
else {
|
||||
// add typing name to missing set so we won't process it again
|
||||
this.missingTypingsSet.add(typing);
|
||||
this.missingTypingsSet[typing] = true;
|
||||
if (this.log.isEnabled()) {
|
||||
switch (validationResult) {
|
||||
case PackageNameValidationResult.EmptyName:
|
||||
@@ -296,20 +296,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 = createSet();
|
||||
const installedPackages: Map<true> = createMap<true>();
|
||||
const installedTypingFiles: string[] = [];
|
||||
for (const t of installedTypings) {
|
||||
const packageName = getBaseFileName(t);
|
||||
if (!packageName) {
|
||||
continue;
|
||||
}
|
||||
installedPackages.add(packageName);
|
||||
installedPackages[packageName] = true;
|
||||
const typingFile = typingToFileName(cachePath, packageName, this.installTypingHost);
|
||||
if (!typingFile) {
|
||||
continue;
|
||||
}
|
||||
if (!this.packageNameToTypingLocation.get(packageName)) {
|
||||
this.packageNameToTypingLocation.set(packageName, typingFile);
|
||||
if (!this.packageNameToTypingLocation[packageName]) {
|
||||
this.packageNameToTypingLocation[packageName] = typingFile;
|
||||
}
|
||||
installedTypingFiles.push(typingFile);
|
||||
}
|
||||
@@ -317,11 +317,11 @@ namespace ts.server.typingsInstaller {
|
||||
this.log.writeLine(`Installed typing files ${JSON.stringify(installedTypingFiles)}`);
|
||||
}
|
||||
for (const toInstall of typingsToInstall) {
|
||||
if (!installedPackages.has(toInstall)) {
|
||||
if (!installedPackages[toInstall]) {
|
||||
if (this.log.isEnabled()) {
|
||||
this.log.writeLine(`New missing typing package '${toInstall}'`);
|
||||
}
|
||||
this.missingTypingsSet.add(toInstall);
|
||||
this.missingTypingsSet[toInstall] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ namespace ts.server.typingsInstaller {
|
||||
});
|
||||
watchers.push(w);
|
||||
}
|
||||
this.projectWatchers.set(projectName, watchers);
|
||||
this.projectWatchers[projectName] = watchers;
|
||||
}
|
||||
|
||||
private createSetTypings(request: DiscoverTypings, typings: string[]): SetTypings {
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace ts.server {
|
||||
};
|
||||
}
|
||||
|
||||
export function mergeMapLikes(target: MapLike<any>, source: MapLike <any>): void {
|
||||
export function mergeMaps(target: MapLike<any>, source: MapLike <any>): void {
|
||||
for (const key in source) {
|
||||
if (hasProperty(source, key)) {
|
||||
target[key] = source[key];
|
||||
@@ -132,6 +132,32 @@ 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(): never {
|
||||
throw new Error("LanguageService is disabled");
|
||||
}
|
||||
@@ -204,7 +230,7 @@ namespace ts.server {
|
||||
* these fields can be present in the project file
|
||||
**/
|
||||
files?: string[];
|
||||
wildcardDirectories?: MapLike<WatchDirectoryFlags>;
|
||||
wildcardDirectories?: Map<WatchDirectoryFlags>;
|
||||
compilerOptions?: CompilerOptions;
|
||||
typingOptions?: TypingOptions;
|
||||
compileOnSave?: boolean;
|
||||
@@ -225,22 +251,21 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
export class ThrottledOperations {
|
||||
private pendingTimeouts = createMap<string, any>();
|
||||
private pendingTimeouts: Map<any> = createMap<any>();
|
||||
constructor(private readonly host: ServerHost) {
|
||||
}
|
||||
|
||||
public schedule(operationId: string, delay: number, cb: () => void) {
|
||||
const pendingTimeout = this.pendingTimeouts.get(operationId);
|
||||
if (pendingTimeout !== undefined) {
|
||||
if (hasProperty(this.pendingTimeouts, operationId)) {
|
||||
// another operation was already scheduled for this id - cancel it
|
||||
this.host.clearTimeout(pendingTimeout);
|
||||
this.host.clearTimeout(this.pendingTimeouts[operationId]);
|
||||
}
|
||||
// schedule new operation, pass arguments
|
||||
this.pendingTimeouts.set(operationId, this.host.setTimeout(ThrottledOperations.run, delay, this, operationId, cb));
|
||||
this.pendingTimeouts[operationId] = this.host.setTimeout(ThrottledOperations.run, delay, this, operationId, cb);
|
||||
}
|
||||
|
||||
private static run(self: ThrottledOperations, operationId: string, cb: () => void) {
|
||||
self.pendingTimeouts.delete(operationId);
|
||||
delete self.pendingTimeouts[operationId];
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user