Remove unnecessary wrapper classes in ts.formatting.Rule (#19744)
* Remove unnecessary wrapper classes in ts.formatting.Rule * RulesProvider -> immutable FormatContext * Remove Rules class, just use a list of rules * Remove Shared namespace, replace Shared.TokenRange with TokenRange * Simplify TokenRange * Separate Rule and RuleSpec * Move FormattingRequestKind to formattingContext.ts * Simplify references * Fix lint * Revert removal of trailing newlines
This commit is contained in:
parent
20e36dba53
commit
5ad7e9516b
|
@ -60,20 +60,11 @@
|
|||
"../services/jsTyping.ts",
|
||||
"../services/formatting/formatting.ts",
|
||||
"../services/formatting/formattingContext.ts",
|
||||
"../services/formatting/formattingRequestKind.ts",
|
||||
"../services/formatting/formattingScanner.ts",
|
||||
"../services/formatting/references.ts",
|
||||
"../services/formatting/rule.ts",
|
||||
"../services/formatting/ruleAction.ts",
|
||||
"../services/formatting/ruleDescriptor.ts",
|
||||
"../services/formatting/ruleFlag.ts",
|
||||
"../services/formatting/ruleOperation.ts",
|
||||
"../services/formatting/ruleOperationContext.ts",
|
||||
"../services/formatting/rules.ts",
|
||||
"../services/formatting/rulesMap.ts",
|
||||
"../services/formatting/rulesProvider.ts",
|
||||
"../services/formatting/smartIndenter.ts",
|
||||
"../services/formatting/tokenRange.ts",
|
||||
"../services/codeFixProvider.ts",
|
||||
"../services/codefixes/fixes.ts",
|
||||
"../services/codefixes/helpers.ts",
|
||||
|
|
|
@ -67,33 +67,27 @@ namespace ts {
|
|||
}
|
||||
|
||||
export const newLineCharacter = "\n";
|
||||
export const getRuleProvider = memoize(getRuleProviderInternal);
|
||||
function getRuleProviderInternal() {
|
||||
const options = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
const rulesProvider = new formatting.RulesProvider();
|
||||
rulesProvider.ensureUpToDate(options);
|
||||
return rulesProvider;
|
||||
}
|
||||
export const testFormatOptions: ts.FormatCodeSettings = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
|
||||
const notImplementedHost: LanguageServiceHost = {
|
||||
getCompilationSettings: notImplemented,
|
||||
|
@ -133,7 +127,7 @@ namespace ts {
|
|||
startPosition: selectionRange.start,
|
||||
endPosition: selectionRange.end,
|
||||
host: notImplementedHost,
|
||||
rulesProvider: getRuleProvider()
|
||||
formatContext: formatting.getFormatContext(testFormatOptions),
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
|
||||
|
@ -197,7 +191,7 @@ namespace ts {
|
|||
startPosition: selectionRange.start,
|
||||
endPosition: selectionRange.end,
|
||||
host: notImplementedHost,
|
||||
rulesProvider: getRuleProvider()
|
||||
formatContext: formatting.getFormatContext(testFormatOptions),
|
||||
};
|
||||
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
|
||||
assert.isUndefined(rangeToExtract.errors, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
|
||||
|
|
|
@ -23,60 +23,8 @@ namespace ts {
|
|||
const printerOptions = { newLine: NewLineKind.LineFeed };
|
||||
const newLineCharacter = getNewLineCharacter(printerOptions);
|
||||
|
||||
const getRuleProviderDefault = memoize(() => {
|
||||
const options = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: false,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
const rulesProvider = new formatting.RulesProvider();
|
||||
rulesProvider.ensureUpToDate(options);
|
||||
return rulesProvider;
|
||||
});
|
||||
const getRuleProviderNewlineBrace = memoize(() => {
|
||||
const options = {
|
||||
indentSize: 4,
|
||||
tabSize: 4,
|
||||
newLineCharacter,
|
||||
convertTabsToSpaces: true,
|
||||
indentStyle: ts.IndentStyle.Smart,
|
||||
insertSpaceAfterConstructor: false,
|
||||
insertSpaceAfterCommaDelimiter: true,
|
||||
insertSpaceAfterSemicolonInForStatements: true,
|
||||
insertSpaceBeforeAndAfterBinaryOperators: true,
|
||||
insertSpaceAfterKeywordsInControlFlowStatements: true,
|
||||
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
insertSpaceBeforeFunctionParenthesis: false,
|
||||
placeOpenBraceOnNewLineForFunctions: true,
|
||||
placeOpenBraceOnNewLineForControlBlocks: false,
|
||||
};
|
||||
const rulesProvider = new formatting.RulesProvider();
|
||||
rulesProvider.ensureUpToDate(options);
|
||||
return rulesProvider;
|
||||
});
|
||||
function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean) {
|
||||
return placeOpenBraceOnNewLineForFunctions ? getRuleProviderNewlineBrace() : getRuleProviderDefault();
|
||||
function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean): formatting.FormatContext {
|
||||
return formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...testFormatOptions, placeOpenBraceOnNewLineForFunctions: true } : testFormatOptions);
|
||||
}
|
||||
|
||||
// validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed.
|
||||
|
|
|
@ -166,7 +166,7 @@ namespace ts.codefix {
|
|||
return {
|
||||
host: context.host,
|
||||
newLineCharacter: context.newLineCharacter,
|
||||
rulesProvider: context.rulesProvider,
|
||||
formatContext: context.formatContext,
|
||||
sourceFile: context.sourceFile,
|
||||
checker,
|
||||
compilerOptions: context.program.getCompilerOptions(),
|
||||
|
|
|
@ -415,7 +415,7 @@ namespace ts.Completions {
|
|||
entryId: CompletionEntryIdentifier,
|
||||
allSourceFiles: ReadonlyArray<SourceFile>,
|
||||
host: LanguageServiceHost,
|
||||
rulesProvider: formatting.RulesProvider,
|
||||
formatContext: formatting.FormatContext,
|
||||
): CompletionEntryDetails {
|
||||
const { name, source } = entryId;
|
||||
// Compute all the completion symbols again.
|
||||
|
@ -436,7 +436,7 @@ namespace ts.Completions {
|
|||
}
|
||||
case "symbol": {
|
||||
const { symbol, location, symbolToOriginInfoMap } = symbolCompletion;
|
||||
const codeActions = getCompletionEntryCodeActions(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, rulesProvider);
|
||||
const codeActions = getCompletionEntryCodeActions(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, formatContext);
|
||||
const kindModifiers = SymbolDisplay.getSymbolModifiers(symbol);
|
||||
const { displayParts, documentation, symbolKind, tags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All);
|
||||
return { name, kindModifiers, kind: symbolKind, displayParts, documentation, tags, codeActions, source: source === undefined ? undefined : [textPart(source)] };
|
||||
|
@ -467,7 +467,7 @@ namespace ts.Completions {
|
|||
host: LanguageServiceHost,
|
||||
compilerOptions: CompilerOptions,
|
||||
sourceFile: SourceFile,
|
||||
rulesProvider: formatting.RulesProvider,
|
||||
formatContext: formatting.FormatContext,
|
||||
): CodeAction[] | undefined {
|
||||
const symbolOriginInfo = symbolToOriginInfoMap[getSymbolId(symbol)];
|
||||
if (!symbolOriginInfo) {
|
||||
|
@ -481,7 +481,7 @@ namespace ts.Completions {
|
|||
newLineCharacter: host.getNewLine(),
|
||||
compilerOptions,
|
||||
sourceFile,
|
||||
rulesProvider,
|
||||
formatContext,
|
||||
symbolName: symbol.name,
|
||||
getCanonicalFileName: createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : false),
|
||||
symbolToken: undefined,
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
///<reference path='..\services.ts' />
|
||||
///<reference path='formattingScanner.ts' />
|
||||
///<reference path='rulesProvider.ts' />
|
||||
///<reference path='references.ts' />
|
||||
/// <reference path="formattingContext.ts" />
|
||||
/// <reference path="formattingScanner.ts" />
|
||||
/// <reference path="rule.ts" />
|
||||
/// <reference path="rulesMap.ts" />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export interface FormatContext {
|
||||
readonly options: ts.FormatCodeSettings;
|
||||
readonly getRule: ts.formatting.RulesMap;
|
||||
}
|
||||
|
||||
export interface TextRangeWithKind extends TextRange {
|
||||
kind: SyntaxKind;
|
||||
|
@ -67,7 +71,7 @@ namespace ts.formatting {
|
|||
delta: number;
|
||||
}
|
||||
|
||||
export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
|
||||
export function formatOnEnter(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
|
||||
const line = sourceFile.getLineAndCharacterOfPosition(position).line;
|
||||
if (line === 0) {
|
||||
return [];
|
||||
|
@ -93,15 +97,15 @@ namespace ts.formatting {
|
|||
// end value is exclusive so add 1 to the result
|
||||
end: endOfFormatSpan + 1
|
||||
};
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnEnter);
|
||||
return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatOnEnter);
|
||||
}
|
||||
|
||||
export function formatOnSemicolon(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
|
||||
export function formatOnSemicolon(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
|
||||
const semicolon = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.SemicolonToken, sourceFile);
|
||||
return formatNodeLines(findOutermostNodeWithinListLevel(semicolon), sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnSemicolon);
|
||||
return formatNodeLines(findOutermostNodeWithinListLevel(semicolon), sourceFile, formatContext, FormattingRequestKind.FormatOnSemicolon);
|
||||
}
|
||||
|
||||
export function formatOnOpeningCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
|
||||
export function formatOnOpeningCurly(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
|
||||
const openingCurly = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.OpenBraceToken, sourceFile);
|
||||
if (!openingCurly) {
|
||||
return [];
|
||||
|
@ -126,29 +130,29 @@ namespace ts.formatting {
|
|||
end: position
|
||||
};
|
||||
|
||||
return formatSpan(textRange, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnOpeningCurlyBrace);
|
||||
return formatSpan(textRange, sourceFile, formatContext, FormattingRequestKind.FormatOnOpeningCurlyBrace);
|
||||
}
|
||||
|
||||
export function formatOnClosingCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
|
||||
export function formatOnClosingCurly(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
|
||||
const precedingToken = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.CloseBraceToken, sourceFile);
|
||||
return formatNodeLines(findOutermostNodeWithinListLevel(precedingToken), sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnClosingCurlyBrace);
|
||||
return formatNodeLines(findOutermostNodeWithinListLevel(precedingToken), sourceFile, formatContext, FormattingRequestKind.FormatOnClosingCurlyBrace);
|
||||
}
|
||||
|
||||
export function formatDocument(sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
|
||||
export function formatDocument(sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
|
||||
const span = {
|
||||
pos: 0,
|
||||
end: sourceFile.text.length
|
||||
};
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatDocument);
|
||||
return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatDocument);
|
||||
}
|
||||
|
||||
export function formatSelection(start: number, end: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
|
||||
export function formatSelection(start: number, end: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
|
||||
// format from the beginning of the line
|
||||
const span = {
|
||||
pos: getLineStartPositionForPosition(start, sourceFile),
|
||||
end,
|
||||
};
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatSelection);
|
||||
return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatSelection);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -337,7 +341,7 @@ namespace ts.formatting {
|
|||
}
|
||||
|
||||
/* @internal */
|
||||
export function formatNodeGivenIndentation(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, rulesProvider: RulesProvider): TextChange[] {
|
||||
export function formatNodeGivenIndentation(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, formatContext: FormatContext): TextChange[] {
|
||||
const range = { pos: 0, end: sourceFileLike.text.length };
|
||||
return getFormattingScanner(sourceFileLike.text, languageVariant, range.pos, range.end, scanner => formatSpanWorker(
|
||||
range,
|
||||
|
@ -345,14 +349,13 @@ namespace ts.formatting {
|
|||
initialIndentation,
|
||||
delta,
|
||||
scanner,
|
||||
rulesProvider.getFormatOptions(),
|
||||
rulesProvider,
|
||||
formatContext,
|
||||
FormattingRequestKind.FormatSelection,
|
||||
_ => false, // assume that node does not have any errors
|
||||
sourceFileLike));
|
||||
}
|
||||
|
||||
function formatNodeLines(node: Node, sourceFile: SourceFile, options: FormatCodeSettings, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[] {
|
||||
function formatNodeLines(node: Node, sourceFile: SourceFile, formatContext: FormatContext, requestKind: FormattingRequestKind): TextChange[] {
|
||||
if (!node) {
|
||||
return [];
|
||||
}
|
||||
|
@ -362,24 +365,19 @@ namespace ts.formatting {
|
|||
end: node.end
|
||||
};
|
||||
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, requestKind);
|
||||
return formatSpan(span, sourceFile, formatContext, requestKind);
|
||||
}
|
||||
|
||||
function formatSpan(originalRange: TextRange,
|
||||
sourceFile: SourceFile,
|
||||
options: FormatCodeSettings,
|
||||
rulesProvider: RulesProvider,
|
||||
requestKind: FormattingRequestKind): TextChange[] {
|
||||
function formatSpan(originalRange: TextRange, sourceFile: SourceFile, formatContext: FormatContext, requestKind: FormattingRequestKind): TextChange[] {
|
||||
// find the smallest node that fully wraps the range and compute the initial indentation for the node
|
||||
const enclosingNode = findEnclosingNode(originalRange, sourceFile);
|
||||
return getFormattingScanner(sourceFile.text, sourceFile.languageVariant, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end, scanner => formatSpanWorker(
|
||||
originalRange,
|
||||
enclosingNode,
|
||||
SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options),
|
||||
getOwnOrInheritedDelta(enclosingNode, options, sourceFile),
|
||||
SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, formatContext.options),
|
||||
getOwnOrInheritedDelta(enclosingNode, formatContext.options, sourceFile),
|
||||
scanner,
|
||||
options,
|
||||
rulesProvider,
|
||||
formatContext,
|
||||
requestKind,
|
||||
prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange),
|
||||
sourceFile));
|
||||
|
@ -390,8 +388,7 @@ namespace ts.formatting {
|
|||
initialIndentation: number,
|
||||
delta: number,
|
||||
formattingScanner: FormattingScanner,
|
||||
options: FormatCodeSettings,
|
||||
rulesProvider: RulesProvider,
|
||||
{ options, getRule }: FormatContext,
|
||||
requestKind: FormattingRequestKind,
|
||||
rangeContainsError: (r: TextRange) => boolean,
|
||||
sourceFile: SourceFileLike): TextChange[] {
|
||||
|
@ -917,14 +914,14 @@ namespace ts.formatting {
|
|||
|
||||
formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode);
|
||||
|
||||
const rule = rulesProvider.getRulesMap().GetRule(formattingContext);
|
||||
const rule = getRule(formattingContext);
|
||||
|
||||
let trimTrailingWhitespaces: boolean;
|
||||
let lineAdded: boolean;
|
||||
if (rule) {
|
||||
applyRuleEdits(rule, previousItem, previousStartLine, currentItem, currentStartLine);
|
||||
|
||||
if (rule.operation.action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) {
|
||||
if (rule.action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) {
|
||||
lineAdded = false;
|
||||
// Handle the case where the next line is moved to be the end of this line.
|
||||
// In this case we don't indent the next line in the next pass.
|
||||
|
@ -932,7 +929,7 @@ namespace ts.formatting {
|
|||
dynamicIndentation.recomputeIndentation(/*lineAddedByFormatting*/ false);
|
||||
}
|
||||
}
|
||||
else if (rule.operation.action & RuleAction.NewLine && currentStartLine === previousStartLine) {
|
||||
else if (rule.action & RuleAction.NewLine && currentStartLine === previousStartLine) {
|
||||
lineAdded = true;
|
||||
// Handle the case where token2 is moved to the new line.
|
||||
// In this case we indent token2 in the next pass but we set
|
||||
|
@ -943,7 +940,7 @@ namespace ts.formatting {
|
|||
}
|
||||
|
||||
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
||||
trimTrailingWhitespaces = !(rule.operation.action & RuleAction.Delete) && rule.flag !== RuleFlags.CanDeleteNewLines;
|
||||
trimTrailingWhitespaces = !(rule.action & RuleAction.Delete) && rule.flags !== RuleFlags.CanDeleteNewLines;
|
||||
}
|
||||
else {
|
||||
trimTrailingWhitespaces = true;
|
||||
|
@ -1118,7 +1115,7 @@ namespace ts.formatting {
|
|||
currentRange: TextRangeWithKind,
|
||||
currentStartLine: number): void {
|
||||
|
||||
switch (rule.operation.action) {
|
||||
switch (rule.action) {
|
||||
case RuleAction.Ignore:
|
||||
// no action required
|
||||
return;
|
||||
|
@ -1132,7 +1129,7 @@ namespace ts.formatting {
|
|||
// exit early if we on different lines and rule cannot change number of newlines
|
||||
// if line1 and line2 are on subsequent lines then no edits are required - ok to exit
|
||||
// if line1 and line2 are separated with more than one newline - ok to exit since we cannot delete extra new lines
|
||||
if (rule.flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
|
||||
if (rule.flags !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1144,7 +1141,7 @@ namespace ts.formatting {
|
|||
break;
|
||||
case RuleAction.Space:
|
||||
// exit early if we on different lines and rule cannot change number of newlines
|
||||
if (rule.flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
|
||||
if (rule.flags !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
/// <reference path="references.ts"/>
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export const enum FormattingRequestKind {
|
||||
FormatDocument,
|
||||
FormatSelection,
|
||||
FormatOnEnter,
|
||||
FormatOnSemicolon,
|
||||
FormatOnOpeningCurlyBrace,
|
||||
FormatOnClosingCurlyBrace
|
||||
}
|
||||
|
||||
export class FormattingContext {
|
||||
public currentTokenSpan: TextRangeWithKind;
|
||||
public nextTokenSpan: TextRangeWithKind;
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
/// <reference path="references.ts"/>
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export const enum FormattingRequestKind {
|
||||
FormatDocument,
|
||||
FormatSelection,
|
||||
FormatOnEnter,
|
||||
FormatOnSemicolon,
|
||||
FormatOnOpeningCurlyBrace,
|
||||
FormatOnClosingCurlyBrace
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
///<reference path='..\services.ts' />
|
||||
///<reference path='formattingContext.ts' />
|
||||
///<reference path='formattingRequestKind.ts' />
|
||||
///<reference path='rule.ts' />
|
||||
///<reference path='ruleAction.ts' />
|
||||
///<reference path='ruleDescriptor.ts' />
|
||||
///<reference path='ruleFlag.ts' />
|
||||
///<reference path='ruleOperation.ts' />
|
||||
///<reference path='ruleOperationContext.ts' />
|
||||
///<reference path='rules.ts' />
|
||||
///<reference path='rulesMap.ts' />
|
||||
///<reference path='tokenRange.ts' />
|
|
@ -1,14 +1,30 @@
|
|||
///<reference path='references.ts' />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export class Rule {
|
||||
export interface Rule {
|
||||
// Used for debugging to identify each rule based on the property name it's assigned to.
|
||||
public debugName?: string;
|
||||
constructor(
|
||||
readonly descriptor: RuleDescriptor,
|
||||
readonly operation: RuleOperation,
|
||||
readonly flag: RuleFlags = RuleFlags.None) {
|
||||
}
|
||||
readonly debugName: string;
|
||||
readonly context: ReadonlyArray<ContextPredicate>;
|
||||
readonly action: RuleAction;
|
||||
readonly flags: RuleFlags;
|
||||
}
|
||||
|
||||
export type ContextPredicate = (context: FormattingContext) => boolean;
|
||||
export const anyContext: ReadonlyArray<ContextPredicate> = emptyArray;
|
||||
|
||||
export const enum RuleAction {
|
||||
Ignore = 1 << 0,
|
||||
Space = 1 << 1,
|
||||
NewLine = 1 << 2,
|
||||
Delete = 1 << 3,
|
||||
}
|
||||
|
||||
export const enum RuleFlags {
|
||||
None,
|
||||
CanDeleteNewLines,
|
||||
}
|
||||
|
||||
export interface TokenRange {
|
||||
readonly tokens: ReadonlyArray<SyntaxKind>;
|
||||
readonly isSpecific: boolean;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
///<reference path='references.ts' />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export const enum RuleAction {
|
||||
Ignore = 0x00000001,
|
||||
Space = 0x00000002,
|
||||
NewLine = 0x00000004,
|
||||
Delete = 0x00000008
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
///<reference path='references.ts' />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export class RuleDescriptor {
|
||||
constructor(public leftTokenRange: Shared.TokenRange, public rightTokenRange: Shared.TokenRange) {
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return "[leftRange=" + this.leftTokenRange + "," +
|
||||
"rightRange=" + this.rightTokenRange + "]";
|
||||
}
|
||||
|
||||
static create1(left: SyntaxKind, right: SyntaxKind): RuleDescriptor {
|
||||
return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), Shared.TokenRange.FromToken(right));
|
||||
}
|
||||
|
||||
static create2(left: Shared.TokenRange, right: SyntaxKind): RuleDescriptor {
|
||||
return RuleDescriptor.create4(left, Shared.TokenRange.FromToken(right));
|
||||
}
|
||||
|
||||
static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor {
|
||||
return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right);
|
||||
}
|
||||
|
||||
static create4(left: Shared.TokenRange, right: Shared.TokenRange): RuleDescriptor {
|
||||
return new RuleDescriptor(left, right);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
///<reference path='references.ts' />
|
||||
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export const enum RuleFlags {
|
||||
None,
|
||||
CanDeleteNewLines
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
///<reference path='references.ts' />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export class RuleOperation {
|
||||
constructor(readonly context: RuleOperationContext, readonly action: RuleAction) {}
|
||||
|
||||
public toString(): string {
|
||||
return "[context=" + this.context + "," +
|
||||
"action=" + this.action + "]";
|
||||
}
|
||||
|
||||
static create1(action: RuleAction) {
|
||||
return RuleOperation.create2(RuleOperationContext.any, action);
|
||||
}
|
||||
|
||||
static create2(context: RuleOperationContext, action: RuleAction) {
|
||||
return new RuleOperation(context, action);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
///<reference path='references.ts' />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
|
||||
export class RuleOperationContext {
|
||||
private readonly customContextChecks: ((context: FormattingContext) => boolean)[];
|
||||
|
||||
constructor(...funcs: ((context: FormattingContext) => boolean)[]) {
|
||||
this.customContextChecks = funcs;
|
||||
}
|
||||
|
||||
static readonly any: RuleOperationContext = new RuleOperationContext();
|
||||
|
||||
public IsAny(): boolean {
|
||||
return this === RuleOperationContext.any;
|
||||
}
|
||||
|
||||
public InContext(context: FormattingContext): boolean {
|
||||
if (this.IsAny()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const check of this.customContextChecks) {
|
||||
if (!check(context)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,60 +1,59 @@
|
|||
///<reference path='references.ts' />
|
||||
/// <reference path="rules.ts" />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export class RulesMap {
|
||||
public map: RulesBucket[];
|
||||
public mapRowLength: number;
|
||||
export function getFormatContext(options: FormatCodeSettings): formatting.FormatContext {
|
||||
return { options, getRule: getRulesMap() };
|
||||
}
|
||||
|
||||
constructor(rules: ReadonlyArray<Rule>) {
|
||||
this.mapRowLength = SyntaxKind.LastToken + 1;
|
||||
this.map = new Array<RulesBucket>(this.mapRowLength * this.mapRowLength);
|
||||
let rulesMapCache: RulesMap | undefined;
|
||||
|
||||
// This array is used only during construction of the rulesbucket in the map
|
||||
const rulesBucketConstructionStateList: RulesBucketConstructionState[] = new Array<RulesBucketConstructionState>(this.map.length);
|
||||
for (const rule of rules) {
|
||||
this.FillRule(rule, rulesBucketConstructionStateList);
|
||||
}
|
||||
function getRulesMap(): RulesMap {
|
||||
if (rulesMapCache === undefined) {
|
||||
rulesMapCache = createRulesMap(getAllRules());
|
||||
}
|
||||
return rulesMapCache;
|
||||
}
|
||||
|
||||
private GetRuleBucketIndex(row: number, column: number): number {
|
||||
Debug.assert(row <= SyntaxKind.LastKeyword && column <= SyntaxKind.LastKeyword, "Must compute formatting context from tokens");
|
||||
return (row * this.mapRowLength) + column;
|
||||
}
|
||||
export type RulesMap = (context: FormattingContext) => Rule | undefined;
|
||||
function createRulesMap(rules: ReadonlyArray<RuleSpec>): RulesMap {
|
||||
const map = buildMap(rules);
|
||||
return context => {
|
||||
const bucket = map[getRuleBucketIndex(context.currentTokenSpan.kind, context.nextTokenSpan.kind)];
|
||||
return bucket && find(bucket, rule => every(rule.context, c => c(context)));
|
||||
};
|
||||
}
|
||||
|
||||
private FillRule(rule: Rule, rulesBucketConstructionStateList: RulesBucketConstructionState[]): void {
|
||||
const specificRule = rule.descriptor.leftTokenRange.isSpecific() && rule.descriptor.rightTokenRange.isSpecific();
|
||||
function buildMap(rules: ReadonlyArray<RuleSpec>): ReadonlyArray<ReadonlyArray<Rule>> {
|
||||
// Map from bucket index to array of rules
|
||||
const map: Rule[][] = new Array(mapRowLength * mapRowLength);
|
||||
// This array is used only during construction of the rulesbucket in the map
|
||||
const rulesBucketConstructionStateList = new Array<number>(map.length);
|
||||
for (const rule of rules) {
|
||||
const specificRule = rule.leftTokenRange.isSpecific && rule.rightTokenRange.isSpecific;
|
||||
|
||||
rule.descriptor.leftTokenRange.GetTokens().forEach((left) => {
|
||||
rule.descriptor.rightTokenRange.GetTokens().forEach((right) => {
|
||||
const rulesBucketIndex = this.GetRuleBucketIndex(left, right);
|
||||
|
||||
let rulesBucket = this.map[rulesBucketIndex];
|
||||
for (const left of rule.leftTokenRange.tokens) {
|
||||
for (const right of rule.rightTokenRange.tokens) {
|
||||
const index = getRuleBucketIndex(left, right);
|
||||
let rulesBucket = map[index];
|
||||
if (rulesBucket === undefined) {
|
||||
rulesBucket = this.map[rulesBucketIndex] = new RulesBucket();
|
||||
}
|
||||
|
||||
rulesBucket.AddRule(rule, specificRule, rulesBucketConstructionStateList, rulesBucketIndex);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public GetRule(context: FormattingContext): Rule | undefined {
|
||||
const bucketIndex = this.GetRuleBucketIndex(context.currentTokenSpan.kind, context.nextTokenSpan.kind);
|
||||
const bucket = this.map[bucketIndex];
|
||||
if (bucket) {
|
||||
for (const rule of bucket.Rules()) {
|
||||
if (rule.operation.context.InContext(context)) {
|
||||
return rule;
|
||||
rulesBucket = map[index] = [];
|
||||
}
|
||||
addRule(rulesBucket, rule.rule, specificRule, rulesBucketConstructionStateList, index);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
function getRuleBucketIndex(row: number, column: number): number {
|
||||
Debug.assert(row <= SyntaxKind.LastKeyword && column <= SyntaxKind.LastKeyword, "Must compute formatting context from tokens");
|
||||
return (row * mapRowLength) + column;
|
||||
}
|
||||
|
||||
const maskBitSize = 5;
|
||||
const mask = 0x1f;
|
||||
const mask = 0b11111; // MaskBitSize bits
|
||||
const mapRowLength = SyntaxKind.LastToken + 1;
|
||||
|
||||
enum RulesPosition {
|
||||
IgnoreRulesSpecific = 0,
|
||||
|
@ -65,92 +64,44 @@ namespace ts.formatting {
|
|||
NoContextRulesAny = maskBitSize * 5
|
||||
}
|
||||
|
||||
export class RulesBucketConstructionState {
|
||||
private rulesInsertionIndexBitmap: number;
|
||||
|
||||
constructor() {
|
||||
//// The Rules list contains all the inserted rules into a rulebucket in the following order:
|
||||
//// 1- Ignore rules with specific token combination
|
||||
//// 2- Ignore rules with any token combination
|
||||
//// 3- Context rules with specific token combination
|
||||
//// 4- Context rules with any token combination
|
||||
//// 5- Non-context rules with specific token combination
|
||||
//// 6- Non-context rules with any token combination
|
||||
////
|
||||
//// The member rulesInsertionIndexBitmap is used to describe the number of rules
|
||||
//// in each sub-bucket (above) hence can be used to know the index of where to insert
|
||||
//// the next rule. It's a bitmap which contains 6 different sections each is given 5 bits.
|
||||
////
|
||||
//// Example:
|
||||
//// In order to insert a rule to the end of sub-bucket (3), we get the index by adding
|
||||
//// the values in the bitmap segments 3rd, 2nd, and 1st.
|
||||
this.rulesInsertionIndexBitmap = 0;
|
||||
}
|
||||
|
||||
public GetInsertionIndex(maskPosition: RulesPosition): number {
|
||||
let index = 0;
|
||||
|
||||
let pos = 0;
|
||||
let indexBitmap = this.rulesInsertionIndexBitmap;
|
||||
|
||||
while (pos <= maskPosition) {
|
||||
index += (indexBitmap & mask);
|
||||
indexBitmap >>= maskBitSize;
|
||||
pos += maskBitSize;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public IncreaseInsertionIndex(maskPosition: RulesPosition): void {
|
||||
let value = (this.rulesInsertionIndexBitmap >> maskPosition) & mask;
|
||||
value++;
|
||||
Debug.assert((value & mask) === value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules.");
|
||||
|
||||
let temp = this.rulesInsertionIndexBitmap & ~(mask << maskPosition);
|
||||
temp |= value << maskPosition;
|
||||
|
||||
this.rulesInsertionIndexBitmap = temp;
|
||||
}
|
||||
// The Rules list contains all the inserted rules into a rulebucket in the following order:
|
||||
// 1- Ignore rules with specific token combination
|
||||
// 2- Ignore rules with any token combination
|
||||
// 3- Context rules with specific token combination
|
||||
// 4- Context rules with any token combination
|
||||
// 5- Non-context rules with specific token combination
|
||||
// 6- Non-context rules with any token combination
|
||||
//
|
||||
// The member rulesInsertionIndexBitmap is used to describe the number of rules
|
||||
// in each sub-bucket (above) hence can be used to know the index of where to insert
|
||||
// the next rule. It's a bitmap which contains 6 different sections each is given 5 bits.
|
||||
//
|
||||
// Example:
|
||||
// In order to insert a rule to the end of sub-bucket (3), we get the index by adding
|
||||
// the values in the bitmap segments 3rd, 2nd, and 1st.
|
||||
function addRule(rules: Rule[], rule: Rule, specificTokens: boolean, constructionState: number[], rulesBucketIndex: number): void {
|
||||
const position = rule.action === RuleAction.Ignore
|
||||
? specificTokens ? RulesPosition.IgnoreRulesSpecific : RulesPosition.IgnoreRulesAny
|
||||
: rule.context !== anyContext
|
||||
? specificTokens ? RulesPosition.ContextRulesSpecific : RulesPosition.ContextRulesAny
|
||||
: specificTokens ? RulesPosition.NoContextRulesSpecific : RulesPosition.NoContextRulesAny;
|
||||
const state = constructionState[rulesBucketIndex] || 0;
|
||||
rules.splice(getInsertionIndex(state, position), 0, rule);
|
||||
constructionState[rulesBucketIndex] = increaseInsertionIndex(state, position);
|
||||
}
|
||||
|
||||
export class RulesBucket {
|
||||
private rules: Rule[];
|
||||
|
||||
constructor() {
|
||||
this.rules = [];
|
||||
function getInsertionIndex(indexBitmap: number, maskPosition: RulesPosition) {
|
||||
let index = 0;
|
||||
for (let pos = 0; pos <= maskPosition; pos += maskBitSize) {
|
||||
index += indexBitmap & mask;
|
||||
indexBitmap >>= maskBitSize;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public Rules(): Rule[] {
|
||||
return this.rules;
|
||||
}
|
||||
|
||||
public AddRule(rule: Rule, specificTokens: boolean, constructionState: RulesBucketConstructionState[], rulesBucketIndex: number): void {
|
||||
let position: RulesPosition;
|
||||
|
||||
if (rule.operation.action === RuleAction.Ignore) {
|
||||
position = specificTokens ?
|
||||
RulesPosition.IgnoreRulesSpecific :
|
||||
RulesPosition.IgnoreRulesAny;
|
||||
}
|
||||
else if (!rule.operation.context.IsAny()) {
|
||||
position = specificTokens ?
|
||||
RulesPosition.ContextRulesSpecific :
|
||||
RulesPosition.ContextRulesAny;
|
||||
}
|
||||
else {
|
||||
position = specificTokens ?
|
||||
RulesPosition.NoContextRulesSpecific :
|
||||
RulesPosition.NoContextRulesAny;
|
||||
}
|
||||
|
||||
let state = constructionState[rulesBucketIndex];
|
||||
if (state === undefined) {
|
||||
state = constructionState[rulesBucketIndex] = new RulesBucketConstructionState();
|
||||
}
|
||||
const index = state.GetInsertionIndex(position);
|
||||
this.rules.splice(index, 0, rule);
|
||||
state.IncreaseInsertionIndex(position);
|
||||
}
|
||||
function increaseInsertionIndex(indexBitmap: number, maskPosition: RulesPosition): number {
|
||||
const value = ((indexBitmap >> maskPosition) & mask) + 1;
|
||||
Debug.assert((value & mask) === value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules.");
|
||||
return (indexBitmap & ~(mask << maskPosition)) | (value << maskPosition);
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/// <reference path="references.ts"/>
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export class RulesProvider {
|
||||
private globalRules: Rules;
|
||||
private options: ts.FormatCodeSettings;
|
||||
private rulesMap: RulesMap;
|
||||
|
||||
constructor() {
|
||||
this.globalRules = new Rules();
|
||||
const activeRules = this.globalRules.HighPriorityCommonRules.concat(this.globalRules.UserConfigurableRules).concat(this.globalRules.LowPriorityCommonRules);
|
||||
this.rulesMap = new RulesMap(activeRules);
|
||||
}
|
||||
|
||||
public getRulesMap() {
|
||||
return this.rulesMap;
|
||||
}
|
||||
|
||||
public getFormatOptions(): Readonly<ts.FormatCodeSettings> {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
public ensureUpToDate(options: ts.FormatCodeSettings) {
|
||||
if (!this.options || !ts.compareDataObjects(this.options, options)) {
|
||||
this.options = ts.clone(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
///<reference path='..\services.ts' />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export namespace SmartIndenter {
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
///<reference path='references.ts' />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export namespace Shared {
|
||||
const allTokens: SyntaxKind[] = [];
|
||||
for (let token = SyntaxKind.FirstToken; token <= SyntaxKind.LastToken; token++) {
|
||||
allTokens.push(token);
|
||||
}
|
||||
|
||||
class TokenValuesAccess implements TokenRange {
|
||||
constructor(private readonly tokens: SyntaxKind[] = []) { }
|
||||
|
||||
public GetTokens(): SyntaxKind[] {
|
||||
return this.tokens;
|
||||
}
|
||||
|
||||
public Contains(token: SyntaxKind): boolean {
|
||||
return this.tokens.indexOf(token) >= 0;
|
||||
}
|
||||
|
||||
public isSpecific() { return true; }
|
||||
}
|
||||
|
||||
class TokenSingleValueAccess implements TokenRange {
|
||||
constructor(private readonly token: SyntaxKind) {}
|
||||
|
||||
public GetTokens(): SyntaxKind[] {
|
||||
return [this.token];
|
||||
}
|
||||
|
||||
public Contains(tokenValue: SyntaxKind): boolean {
|
||||
return tokenValue === this.token;
|
||||
}
|
||||
|
||||
public isSpecific() { return true; }
|
||||
}
|
||||
|
||||
class TokenAllAccess implements TokenRange {
|
||||
public GetTokens(): SyntaxKind[] {
|
||||
return allTokens;
|
||||
}
|
||||
|
||||
public Contains(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return "[allTokens]";
|
||||
}
|
||||
|
||||
public isSpecific() { return false; }
|
||||
}
|
||||
|
||||
class TokenAllExceptAccess implements TokenRange {
|
||||
constructor(private readonly except: SyntaxKind) {}
|
||||
|
||||
public GetTokens(): SyntaxKind[] {
|
||||
return allTokens.filter(t => t !== this.except);
|
||||
}
|
||||
|
||||
public Contains(token: SyntaxKind): boolean {
|
||||
return token !== this.except;
|
||||
}
|
||||
|
||||
public isSpecific() { return false; }
|
||||
}
|
||||
|
||||
export interface TokenRange {
|
||||
GetTokens(): SyntaxKind[];
|
||||
Contains(token: SyntaxKind): boolean;
|
||||
isSpecific(): boolean;
|
||||
}
|
||||
|
||||
export namespace TokenRange {
|
||||
export function FromToken(token: SyntaxKind): TokenRange {
|
||||
return new TokenSingleValueAccess(token);
|
||||
}
|
||||
|
||||
export function FromTokens(tokens: SyntaxKind[]): TokenRange {
|
||||
return new TokenValuesAccess(tokens);
|
||||
}
|
||||
|
||||
export function FromRange(from: SyntaxKind, to: SyntaxKind, except: SyntaxKind[] = []): TokenRange {
|
||||
const tokens: SyntaxKind[] = [];
|
||||
for (let token = from; token <= to; token++) {
|
||||
if (ts.indexOf(except, token) < 0) {
|
||||
tokens.push(token);
|
||||
}
|
||||
}
|
||||
return new TokenValuesAccess(tokens);
|
||||
}
|
||||
|
||||
export function AnyExcept(token: SyntaxKind): TokenRange {
|
||||
return new TokenAllExceptAccess(token);
|
||||
}
|
||||
|
||||
// tslint:disable variable-name (TODO)
|
||||
export const Any: TokenRange = new TokenAllAccess();
|
||||
export const AnyIncludingMultilineComments = TokenRange.FromTokens([...allTokens, SyntaxKind.MultiLineCommentTrivia]);
|
||||
export const Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword);
|
||||
export const BinaryOperators = TokenRange.FromRange(SyntaxKind.FirstBinaryOperator, SyntaxKind.LastBinaryOperator);
|
||||
export const BinaryKeywordOperators = TokenRange.FromTokens([
|
||||
SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword, SyntaxKind.OfKeyword, SyntaxKind.AsKeyword, SyntaxKind.IsKeyword]);
|
||||
export const UnaryPrefixOperators = TokenRange.FromTokens([
|
||||
SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]);
|
||||
export const UnaryPrefixExpressions = TokenRange.FromTokens([
|
||||
SyntaxKind.NumericLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken,
|
||||
SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
export const UnaryPreincrementExpressions = TokenRange.FromTokens([
|
||||
SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
export const UnaryPostincrementExpressions = TokenRange.FromTokens([
|
||||
SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||
export const UnaryPredecrementExpressions = TokenRange.FromTokens([
|
||||
SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
export const UnaryPostdecrementExpressions = TokenRange.FromTokens([
|
||||
SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||
export const Comments = TokenRange.FromTokens([SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]);
|
||||
export const TypeNames = TokenRange.FromTokens([
|
||||
SyntaxKind.Identifier, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword,
|
||||
SyntaxKind.SymbolKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ namespace ts.refactor.convertFunctionToES6Class {
|
|||
|
||||
const { file: sourceFile } = context;
|
||||
const ctorSymbol = getConstructorSymbol(context);
|
||||
const newLine = context.rulesProvider.getFormatOptions().newLineCharacter;
|
||||
const newLine = context.formatContext.options.newLineCharacter;
|
||||
|
||||
const deletedNodes: Node[] = [];
|
||||
const deletes: (() => any)[] = [];
|
||||
|
|
|
@ -33,9 +33,6 @@ namespace ts {
|
|||
/** The version of the language service API */
|
||||
export const servicesVersion = "0.7";
|
||||
|
||||
/* @internal */
|
||||
let ruleProvider: formatting.RulesProvider;
|
||||
|
||||
function createNode<TKind extends SyntaxKind>(kind: TKind, pos: number, end: number, parent?: Node): NodeObject | TokenObject<TKind> | IdentifierObject {
|
||||
const node = isNodeKind(kind) ? new NodeObject(kind, pos, end) :
|
||||
kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) :
|
||||
|
@ -1157,7 +1154,6 @@ namespace ts {
|
|||
documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory())): LanguageService {
|
||||
|
||||
const syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host);
|
||||
ruleProvider = ruleProvider || new formatting.RulesProvider();
|
||||
let program: Program;
|
||||
let lastProjectVersion: string;
|
||||
let lastTypesRootVersion = 0;
|
||||
|
@ -1187,11 +1183,6 @@ namespace ts {
|
|||
return sourceFile;
|
||||
}
|
||||
|
||||
function getRuleProvider(options: FormatCodeSettings) {
|
||||
ruleProvider.ensureUpToDate(options);
|
||||
return ruleProvider;
|
||||
}
|
||||
|
||||
function synchronizeHostData(): void {
|
||||
// perform fast check if host supports it
|
||||
if (host.getProjectVersion) {
|
||||
|
@ -1429,7 +1420,6 @@ namespace ts {
|
|||
|
||||
function getCompletionEntryDetails(fileName: string, position: number, name: string, formattingOptions?: FormatCodeSettings, source?: string): CompletionEntryDetails {
|
||||
synchronizeHostData();
|
||||
const ruleProvider = formattingOptions ? getRuleProvider(formattingOptions) : undefined;
|
||||
return Completions.getCompletionEntryDetails(
|
||||
program.getTypeChecker(),
|
||||
log,
|
||||
|
@ -1439,7 +1429,7 @@ namespace ts {
|
|||
{ name, source },
|
||||
program.getSourceFiles(),
|
||||
host,
|
||||
ruleProvider);
|
||||
formattingOptions && formatting.getFormatContext(formattingOptions));
|
||||
}
|
||||
|
||||
function getCompletionEntrySymbol(fileName: string, position: number, name: string, source?: string): Symbol {
|
||||
|
@ -1838,32 +1828,27 @@ namespace ts {
|
|||
|
||||
function getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions | FormatCodeSettings): TextChange[] {
|
||||
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
const settings = toEditorSettings(options);
|
||||
return formatting.formatSelection(start, end, sourceFile, getRuleProvider(settings), settings);
|
||||
return formatting.formatSelection(start, end, sourceFile, formatting.getFormatContext(toEditorSettings(options)));
|
||||
}
|
||||
|
||||
function getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] {
|
||||
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
const settings = toEditorSettings(options);
|
||||
return formatting.formatDocument(sourceFile, getRuleProvider(settings), settings);
|
||||
return formatting.formatDocument(syntaxTreeCache.getCurrentSourceFile(fileName), formatting.getFormatContext(toEditorSettings(options)));
|
||||
}
|
||||
|
||||
function getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] {
|
||||
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
const settings = toEditorSettings(options);
|
||||
const formatContext = formatting.getFormatContext(toEditorSettings(options));
|
||||
|
||||
if (!isInComment(sourceFile, position)) {
|
||||
if (key === "{") {
|
||||
return formatting.formatOnOpeningCurly(position, sourceFile, getRuleProvider(settings), settings);
|
||||
}
|
||||
else if (key === "}") {
|
||||
return formatting.formatOnClosingCurly(position, sourceFile, getRuleProvider(settings), settings);
|
||||
}
|
||||
else if (key === ";") {
|
||||
return formatting.formatOnSemicolon(position, sourceFile, getRuleProvider(settings), settings);
|
||||
}
|
||||
else if (key === "\n") {
|
||||
return formatting.formatOnEnter(position, sourceFile, getRuleProvider(settings), settings);
|
||||
switch (key) {
|
||||
case "{":
|
||||
return formatting.formatOnOpeningCurly(position, sourceFile, formatContext);
|
||||
case "}":
|
||||
return formatting.formatOnClosingCurly(position, sourceFile, formatContext);
|
||||
case ";":
|
||||
return formatting.formatOnSemicolon(position, sourceFile, formatContext);
|
||||
case "\n":
|
||||
return formatting.formatOnEnter(position, sourceFile, formatContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1875,11 +1860,11 @@ namespace ts {
|
|||
const sourceFile = getValidSourceFile(fileName);
|
||||
const span = createTextSpanFromBounds(start, end);
|
||||
const newLineCharacter = getNewLineOrDefaultFromHost(host);
|
||||
const rulesProvider = getRuleProvider(formatOptions);
|
||||
const formatContext = formatting.getFormatContext(formatOptions);
|
||||
|
||||
return flatMap(deduplicate(errorCodes, equateValues, compareValues), errorCode => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
return codefix.getFixes({ errorCode, sourceFile, span, program, newLineCharacter, host, cancellationToken, rulesProvider });
|
||||
return codefix.getFixes({ errorCode, sourceFile, span, program, newLineCharacter, host, cancellationToken, formatContext });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2104,7 +2089,7 @@ namespace ts {
|
|||
program: getProgram(),
|
||||
newLineCharacter: formatOptions ? formatOptions.newLineCharacter : host.getNewLine(),
|
||||
host,
|
||||
rulesProvider: getRuleProvider(formatOptions),
|
||||
formatContext: formatting.getFormatContext(formatOptions),
|
||||
cancellationToken,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ namespace ts.textChanges {
|
|||
|
||||
export interface TextChangesContext {
|
||||
newLineCharacter: string;
|
||||
rulesProvider: formatting.RulesProvider;
|
||||
formatContext: ts.formatting.FormatContext;
|
||||
}
|
||||
|
||||
export class ChangeTracker {
|
||||
|
@ -196,7 +196,7 @@ namespace ts.textChanges {
|
|||
private readonly newLineCharacter: string;
|
||||
|
||||
public static fromContext(context: TextChangesContext): ChangeTracker {
|
||||
return new ChangeTracker(context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed, context.rulesProvider);
|
||||
return new ChangeTracker(context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed, context.formatContext);
|
||||
}
|
||||
|
||||
public static with(context: TextChangesContext, cb: (tracker: ChangeTracker) => void): FileTextChanges[] {
|
||||
|
@ -207,7 +207,7 @@ namespace ts.textChanges {
|
|||
|
||||
constructor(
|
||||
private readonly newLine: NewLineKind,
|
||||
private readonly rulesProvider: formatting.RulesProvider,
|
||||
private readonly formatContext: ts.formatting.FormatContext,
|
||||
private readonly validator?: (text: NonFormattedText) => void) {
|
||||
this.newLineCharacter = getNewLineCharacter({ newLine });
|
||||
}
|
||||
|
@ -475,7 +475,7 @@ namespace ts.textChanges {
|
|||
options: {}
|
||||
});
|
||||
// use the same indentation as 'after' item
|
||||
const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(afterStartLinePosition, afterStart, sourceFile, this.rulesProvider.getFormatOptions());
|
||||
const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(afterStartLinePosition, afterStart, sourceFile, this.formatContext.options);
|
||||
// insert element before the line break on the line that contains 'after' element
|
||||
let insertPos = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true, /*stopAtComments*/ false);
|
||||
if (insertPos !== end && isLineBreak(sourceFile.text.charCodeAt(insertPos - 1))) {
|
||||
|
@ -562,7 +562,7 @@ namespace ts.textChanges {
|
|||
this.validator(nonformattedText);
|
||||
}
|
||||
|
||||
const formatOptions = this.rulesProvider.getFormatOptions();
|
||||
const { options: formatOptions } = this.formatContext;
|
||||
const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos;
|
||||
|
||||
const initialIndentation =
|
||||
|
@ -578,7 +578,7 @@ namespace ts.textChanges {
|
|||
? (formatOptions.indentSize || 0)
|
||||
: 0;
|
||||
|
||||
return applyFormatting(nonformattedText, sourceFile, initialIndentation, delta, this.rulesProvider);
|
||||
return applyFormatting(nonformattedText, sourceFile, initialIndentation, delta, this.formatContext);
|
||||
}
|
||||
|
||||
private static normalize(changes: Change[]): Change[] {
|
||||
|
@ -605,14 +605,14 @@ namespace ts.textChanges {
|
|||
return { text: writer.getText(), node: assignPositionsToNode(node) };
|
||||
}
|
||||
|
||||
function applyFormatting(nonFormattedText: NonFormattedText, sourceFile: SourceFile, initialIndentation: number, delta: number, rulesProvider: formatting.RulesProvider) {
|
||||
function applyFormatting(nonFormattedText: NonFormattedText, sourceFile: SourceFile, initialIndentation: number, delta: number, formatContext: ts.formatting.FormatContext) {
|
||||
const lineMap = computeLineStarts(nonFormattedText.text);
|
||||
const file: SourceFileLike = {
|
||||
text: nonFormattedText.text,
|
||||
lineMap,
|
||||
getLineAndCharacterOfPosition: pos => computeLineAndCharacterOfPosition(lineMap, pos)
|
||||
};
|
||||
const changes = formatting.formatNodeGivenIndentation(nonFormattedText.node, file, sourceFile.languageVariant, initialIndentation, delta, rulesProvider);
|
||||
const changes = formatting.formatNodeGivenIndentation(nonFormattedText.node, file, sourceFile.languageVariant, initialIndentation, delta, formatContext);
|
||||
return applyChanges(nonFormattedText.text, changes);
|
||||
}
|
||||
|
||||
|
|
|
@ -1068,20 +1068,19 @@ namespace ts {
|
|||
return createTextSpanFromBounds(range.pos, range.end);
|
||||
}
|
||||
|
||||
export const typeKeywords: ReadonlyArray<SyntaxKind> = [
|
||||
SyntaxKind.AnyKeyword,
|
||||
SyntaxKind.BooleanKeyword,
|
||||
SyntaxKind.NeverKeyword,
|
||||
SyntaxKind.NumberKeyword,
|
||||
SyntaxKind.ObjectKeyword,
|
||||
SyntaxKind.StringKeyword,
|
||||
SyntaxKind.SymbolKeyword,
|
||||
SyntaxKind.VoidKeyword,
|
||||
];
|
||||
|
||||
export function isTypeKeyword(kind: SyntaxKind): boolean {
|
||||
switch (kind) {
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.VoidKeyword:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return contains(typeKeywords, kind);
|
||||
}
|
||||
|
||||
/** True if the symbol is for an external module, as opposed to a namespace. */
|
||||
|
|
Loading…
Reference in a new issue