Skip to content

Conversation

jramsay
Copy link
Member

@jramsay jramsay commented Apr 25, 2017

  1. Add all rules to the RulesProvider’s RulesMap regardless of user options
  2. Pass FormatCodeSettings to the FormattingContext
  3. Update RuleOperationContext's InContext to check if a rule should be applied based on the FormattingCodeOptions
  4. Update rules to consume new RuleOperationContext options check
  5. compareDataObjects fix to check if the object has the same number of keys

Fixes:
• TS: [TSServer] Formatting RulesProvider (re)initialization performance issues
• VS: Bug 373219: [TypeScript Perf] WebForms_DDRIT.0300.Typing HTML5 HTML regressed Duration_AccumulatedElapsedTime (60ms)

private rulesMap: RulesMap;

constructor() {
this.globalRules = new Rules();
const activeRules = this.createActiveRules();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit. i would inline this function, since it is only used here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -31,6 +31,8 @@ namespace ts {
/** The version of the language service API */
export const servicesVersion = "0.5";

const ruleProvider: formatting.RulesProvider = new formatting.RulesProvider();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will force users of the services, even ones who never use formatting, to allocate this large data structure. how about doing on first request instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could call this in server/editorServices.ts to initialize the provider instead of doing it here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also mark it as /** @internal **/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved the initialization to createLanguageService()

static Create1(...funcs: { (context: FormattingContext): boolean; }[]) {
return new RuleOperationContext(undefined, undefined, funcs);
}
static Create2(optionName: string, checkApplyRuleOperation: { (optionName: string, options: FormatCodeSettings): boolean }, ...funcs: { (context: FormattingContext): boolean; }[]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider not adding the new two options here, and leaving it as a set of functions as it was.

Under this assumption, your input for:

Create2("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces", Rules.IsOptionEnabledOrUndefined, Rules.IsBraceWrappedContext)

would be:

new RuleOperationContext(Rules.IsOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), Rules.IsBraceWrappedContext)

where IsOptionEnabledOrUndefined is defined as:

    static IsOptionEnabledOrUndefined(optionName: string): (option) => boolean {
             return (options) => !options.hasOwnProperty(optionName) || (<any>options)[optionName];
    }

Copy link
Member Author

@jramsay jramsay Apr 26, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! I like this better. done

// Insert space after function keyword for anonymous functions
this.SpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
this.NoSpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Delete));
static IsOptionEnabled(optionName: string, options: FormatCodeSettings): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type of optionName should be keyof FormatCodeSettings. this will catch issues of misspelled configurations and avoids the cast to any.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks - done

// No space after type assertion
this.NoSpaceAfterTypeAssertion = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeAssertionContext), RuleAction.Delete));
this.SpaceAfterTypeAssertion = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeAssertionContext), RuleAction.Space));
static IsOptionDisabled(optionName: string, options: FormatCodeSettings): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here too

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

///
/// Contexts
///
static IsOptionDisabledOrUndefined(optionName: string, options: FormatCodeSettings): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -31,6 +31,8 @@ namespace ts {
/** The version of the language service API */
export const servicesVersion = "0.5";

const ruleProvider: formatting.RulesProvider = new formatting.RulesProvider();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could call this in server/editorServices.ts to initialize the provider instead of doing it here.

@@ -31,6 +31,8 @@ namespace ts {
/** The version of the language service API */
export const servicesVersion = "0.5";

const ruleProvider: formatting.RulesProvider = new formatting.RulesProvider();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also mark it as /** @internal **/

@jramsay jramsay force-pushed the RulesProviderPerformance branch from f8e44ee to 257a4dc Compare April 27, 2017 18:41
@jramsay jramsay merged commit aa11ab1 into master Apr 27, 2017
@mhegazy mhegazy deleted the RulesProviderPerformance branch November 2, 2017 21:04
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants