https://github.com/Microsoft/TypeScript
Tip revision: dcaad61583ef89b131b71c81af90b4ab0c1c9c98 authored by Mohamed Hegazy on 11 November 2016, 01:00:14 UTC
Update LKG
Update LKG
Tip revision: dcaad61
utilities.ts
/// <reference path="types.d.ts" />
/// <reference path="shared.ts" />
namespace ts.server {
export enum LogLevel {
terse,
normal,
requestTime,
verbose
}
export const emptyArray: ReadonlyArray<any> = [];
export interface Logger {
close(): void;
hasLevel(level: LogLevel): boolean;
loggingEnabled(): boolean;
perftrc(s: string): void;
info(s: string): void;
startGroup(): void;
endGroup(): void;
msg(s: string, type?: Msg.Types): void;
getLogFileName(): string;
}
export namespace Msg {
export type Err = "Err";
export const Err: Err = "Err";
export type Info = "Info";
export const Info: Info = "Info";
export type Perf = "Perf";
export const Perf: Perf = "Perf";
export type Types = Err | Info | Perf;
}
function getProjectRootPath(project: Project): Path {
switch (project.projectKind) {
case ProjectKind.Configured:
return <Path>getDirectoryPath(project.getProjectName());
case ProjectKind.Inferred:
// TODO: fixme
return <Path>"";
case ProjectKind.External:
const projectName = normalizeSlashes(project.getProjectName());
return project.projectService.host.fileExists(projectName) ? <Path>getDirectoryPath(projectName) : <Path>projectName;
}
}
export function createInstallTypingsRequest(project: Project, typingOptions: TypingOptions, cachePath?: string): DiscoverTypings {
return {
projectName: project.getProjectName(),
fileNames: project.getFileNames(/*excludeFilesFromExternalLibraries*/ true),
compilerOptions: project.getCompilerOptions(),
typingOptions,
projectRootPath: getProjectRootPath(project),
cachePath,
kind: "discover"
};
}
export namespace Errors {
export function ThrowNoProject(): never {
throw new Error("No Project.");
}
export function ThrowProjectLanguageServiceDisabled(): never {
throw new Error("The project's language service is disabled.");
}
export function ThrowProjectDoesNotContainDocument(fileName: string, project: Project): never {
throw new Error(`Project '${project.getProjectName()}' does not contain document '${fileName}'`);
}
}
export function getDefaultFormatCodeSettings(host: ServerHost): FormatCodeSettings {
return {
indentSize: 4,
tabSize: 4,
newLineCharacter: host.newLine || "\n",
convertTabsToSpaces: true,
indentStyle: ts.IndentStyle.Smart,
insertSpaceAfterCommaDelimiter: true,
insertSpaceAfterSemicolonInForStatements: true,
insertSpaceBeforeAndAfterBinaryOperators: true,
insertSpaceAfterKeywordsInControlFlowStatements: true,
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
placeOpenBraceOnNewLineForFunctions: false,
placeOpenBraceOnNewLineForControlBlocks: false,
};
}
export function mergeMaps(target: MapLike<any>, source: MapLike <any>): void {
for (const key in source) {
if (hasProperty(source, key)) {
target[key] = source[key];
}
}
}
export function removeItemFromSet<T>(items: T[], itemToRemove: T) {
if (items.length === 0) {
return;
}
const index = items.indexOf(itemToRemove);
if (index < 0) {
return;
}
if (index === items.length - 1) {
// last item - pop it
items.pop();
}
else {
// non-last item - replace it with the last one
items[index] = items.pop();
}
}
export type NormalizedPath = string & { __normalizedPathTag: any };
export function toNormalizedPath(fileName: string): NormalizedPath {
return <NormalizedPath>normalizePath(fileName);
}
export function normalizedPathToPath(normalizedPath: NormalizedPath, currentDirectory: string, getCanonicalFileName: (f: string) => string): Path {
const f = isRootedDiskPath(normalizedPath) ? normalizedPath : getNormalizedAbsolutePath(normalizedPath, currentDirectory);
return <Path>getCanonicalFileName(f);
}
export function asNormalizedPath(fileName: string): NormalizedPath {
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");
}
export const nullLanguageService: LanguageService = {
cleanupSemanticCache: throwLanguageServiceIsDisabledError,
getSyntacticDiagnostics: throwLanguageServiceIsDisabledError,
getSemanticDiagnostics: throwLanguageServiceIsDisabledError,
getCompilerOptionsDiagnostics: throwLanguageServiceIsDisabledError,
getSyntacticClassifications: throwLanguageServiceIsDisabledError,
getEncodedSyntacticClassifications: throwLanguageServiceIsDisabledError,
getSemanticClassifications: throwLanguageServiceIsDisabledError,
getEncodedSemanticClassifications: throwLanguageServiceIsDisabledError,
getCompletionsAtPosition: throwLanguageServiceIsDisabledError,
findReferences: throwLanguageServiceIsDisabledError,
getCompletionEntryDetails: throwLanguageServiceIsDisabledError,
getQuickInfoAtPosition: throwLanguageServiceIsDisabledError,
findRenameLocations: throwLanguageServiceIsDisabledError,
getNameOrDottedNameSpan: throwLanguageServiceIsDisabledError,
getBreakpointStatementAtPosition: throwLanguageServiceIsDisabledError,
getBraceMatchingAtPosition: throwLanguageServiceIsDisabledError,
getSignatureHelpItems: throwLanguageServiceIsDisabledError,
getDefinitionAtPosition: throwLanguageServiceIsDisabledError,
getRenameInfo: throwLanguageServiceIsDisabledError,
getTypeDefinitionAtPosition: throwLanguageServiceIsDisabledError,
getReferencesAtPosition: throwLanguageServiceIsDisabledError,
getDocumentHighlights: throwLanguageServiceIsDisabledError,
getOccurrencesAtPosition: throwLanguageServiceIsDisabledError,
getNavigateToItems: throwLanguageServiceIsDisabledError,
getNavigationBarItems: throwLanguageServiceIsDisabledError,
getNavigationTree: throwLanguageServiceIsDisabledError,
getOutliningSpans: throwLanguageServiceIsDisabledError,
getTodoComments: throwLanguageServiceIsDisabledError,
getIndentationAtPosition: throwLanguageServiceIsDisabledError,
getFormattingEditsForRange: throwLanguageServiceIsDisabledError,
getFormattingEditsForDocument: throwLanguageServiceIsDisabledError,
getFormattingEditsAfterKeystroke: throwLanguageServiceIsDisabledError,
getDocCommentTemplateAtPosition: throwLanguageServiceIsDisabledError,
isValidBraceCompletionAtPosition: throwLanguageServiceIsDisabledError,
getEmitOutput: throwLanguageServiceIsDisabledError,
getProgram: throwLanguageServiceIsDisabledError,
getNonBoundSourceFile: throwLanguageServiceIsDisabledError,
dispose: throwLanguageServiceIsDisabledError,
};
export interface ServerLanguageServiceHost {
setCompilationSettings(options: CompilerOptions): void;
notifyFileRemoved(info: ScriptInfo): void;
}
export const nullLanguageServiceHost: ServerLanguageServiceHost = {
setCompilationSettings: () => undefined,
notifyFileRemoved: () => undefined
};
export interface ProjectOptions {
/**
* true if config file explicitly listed files
**/
configHasFilesProperty?: boolean;
/**
* these fields can be present in the project file
**/
files?: string[];
wildcardDirectories?: Map<WatchDirectoryFlags>;
compilerOptions?: CompilerOptions;
typingOptions?: TypingOptions;
compileOnSave?: boolean;
}
export function isInferredProjectName(name: string) {
// POSIX defines /dev/null as a device - there should be no file with this prefix
return /dev\/null\/inferredProject\d+\*/.test(name);
}
export function makeInferredProjectName(counter: number) {
return `/dev/null/inferredProject${counter}*`;
}
export class ThrottledOperations {
private pendingTimeouts: Map<any> = createMap<any>();
constructor(private readonly host: ServerHost) {
}
public schedule(operationId: string, delay: number, cb: () => void) {
if (hasProperty(this.pendingTimeouts, operationId)) {
// another operation was already scheduled for this id - cancel it
this.host.clearTimeout(this.pendingTimeouts[operationId]);
}
// schedule new operation, pass arguments
this.pendingTimeouts[operationId] = this.host.setTimeout(ThrottledOperations.run, delay, this, operationId, cb);
}
private static run(self: ThrottledOperations, operationId: string, cb: () => void) {
delete self.pendingTimeouts[operationId];
cb();
}
}
export class GcTimer {
private timerId: any;
constructor(private readonly host: ServerHost, private readonly delay: number, private readonly logger: Logger) {
}
public scheduleCollect() {
if (!this.host.gc || this.timerId != undefined) {
// no global.gc or collection was already scheduled - skip this request
return;
}
this.timerId = this.host.setTimeout(GcTimer.run, this.delay, this);
}
private static run(self: GcTimer) {
self.timerId = undefined;
const log = self.logger.hasLevel(LogLevel.requestTime);
const before = log && self.host.getMemoryUsage();
self.host.gc();
if (log) {
const after = self.host.getMemoryUsage();
self.logger.perftrc(`GC::before ${before}, after ${after}`);
}
}
}
}