diff --git a/package.json b/package.json index fa272e2..95ccd44 100644 --- a/package.json +++ b/package.json @@ -629,6 +629,6 @@ "which": "^2.0.2" }, "dependencies": { - "typescript": "3.9.7" + "typescript": "4.0.3" } } diff --git a/src/server/features/refactor.ts b/src/server/features/refactor.ts index cdebfa4..3371b7f 100644 --- a/src/server/features/refactor.ts +++ b/src/server/features/refactor.ts @@ -12,6 +12,12 @@ import { ITypeScriptServiceClient } from '../typescriptService' import * as typeConverters from '../utils/typeConverters' import FormattingOptionsManager from './fileConfigurationManager' +namespace Experimental { + export interface RefactorActionInfo extends Proto.RefactorActionInfo { + readonly notApplicableReason?: string + } +} + class ApplyRefactoringCommand implements Command { public static readonly ID = '_typescript.applyRefactoring' public readonly id = ApplyRefactoringCommand.ID @@ -142,7 +148,8 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { response.body, document, file, - range + range, + context.only && context.only.some(v => v.includes(CodeActionKind.Refactor)) ) } @@ -150,10 +157,13 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { body: Proto.ApplicableRefactorInfo[], document: TextDocument, file: string, - rangeOrSelection: Range + rangeOrSelection: Range, + setPrefrred: boolean ): CodeAction[] { const actions: CodeAction[] = [] for (const info of body) { + // ignore not refactor that not applicable + if ((info as Experimental.RefactorActionInfo).notApplicableReason) continue if (!info.inlineable) { const codeAction: CodeAction = { title: info.description, @@ -167,15 +177,11 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { actions.push(codeAction) } else { for (const action of info.actions) { - actions.push( - this.refactorActionToCodeAction( - action, - document, - file, - info, - rangeOrSelection - ) - ) + let codeAction = this.refactorActionToCodeAction(action, document, file, info, rangeOrSelection) + if (setPrefrred) { + codeAction.isPreferred = TypeScriptRefactorProvider.isPreferred(action, info.actions) + } + actions.push(codeAction) } } } @@ -204,7 +210,7 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { private shouldTrigger(context: CodeActionContext): boolean { if ( context.only && - context.only.indexOf(CodeActionKind.Refactor) == -1 + context.only.every(o => !o.includes(CodeActionKind.Refactor)) ) { return false } @@ -221,4 +227,34 @@ export default class TypeScriptRefactorProvider implements CodeActionProvider { } return CodeActionKind.Refactor } + + private static isPreferred( + action: Proto.RefactorActionInfo, + allActions: readonly Proto.RefactorActionInfo[], + ): boolean { + let kind = TypeScriptRefactorProvider.getKind(action) + if (TypeScriptRefactorProvider.extractConstantKind == kind) { + // Only mark the action with the lowest scope as preferred + const getScope = (name: string) => { + const scope = name.match(/scope_(\d)/)?.[1] + return scope ? +scope : undefined + } + const scope = getScope(action.name) + if (typeof scope !== 'number') { + return false + } + + return allActions + .filter(otherAtion => otherAtion !== action && otherAtion.name.startsWith('constant_')) + .every(otherAction => { + const otherScope = getScope(otherAction.name) + return typeof otherScope === 'number' ? scope < otherScope : true + }) + } + let { name } = action + if (name.startsWith('Extract to type alias') || name.startsWith('Extract to interface')) { + return true + } + return false + } } diff --git a/src/server/utils/api.ts b/src/server/utils/api.ts index 2c3f29e..c3bb9ba 100644 --- a/src/server/utils/api.ts +++ b/src/server/utils/api.ts @@ -38,6 +38,8 @@ export default class API { public static readonly v380 = API.fromSimpleString('3.8.0') public static readonly v381 = API.fromSimpleString('3.8.1') public static readonly v390 = API.fromSimpleString('3.9.0') + public static readonly v400 = API.fromSimpleString('4.0.0') + public static readonly v401 = API.fromSimpleString('4.0.1'); public static fromVersionString(versionString: string): API { let version = semver.valid(versionString) diff --git a/yarn.lock b/yarn.lock index d4fd3aa..9043ab9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3139,10 +3139,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@3.9.7: - version "3.9.7" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" - integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== +typescript@4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.3.tgz#153bbd468ef07725c1df9c77e8b453f8d36abba5" + integrity sha512-tEu6DGxGgRJPb/mVPIZ48e69xCn2yRmCgYmDugAVwmJ6o+0u1RI18eO7E7WBTLYLaEVVOhwQmcdhQHweux/WPg== union-value@^1.0.0: version "1.0.1"