Skip to content
36 changes: 30 additions & 6 deletions src/services/refactors/extractSymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,38 @@ namespace ts.refactor.extractSymbol {

const functionActions: RefactorActionInfo[] = [];
const usedFunctionNames: Map<boolean> = createMap();
let innermostErrorFunctionAction: ts.RefactorActionInfo | undefined;

const constantActions: RefactorActionInfo[] = [];
const usedConstantNames: Map<boolean> = createMap();
let innermostErrorConstantAction: ts.RefactorActionInfo | undefined;


let i = 0;
for (const {functionExtraction, constantExtraction} of extractions) {
// Skip these since we don't have a way to report errors yet
const description = functionExtraction.description;
if (functionExtraction.errors.length === 0) {
// Don't issue refactorings with duplicated names.
// Scopes come back in "innermost first" order, so extractions will
// preferentially go into nearer scopes
const description = functionExtraction.description;
if (!usedFunctionNames.has(description)) {
usedFunctionNames.set(description, true);
functionActions.push({
description,
name: `function_scope_${i}`
});
}
} else if (!innermostErrorFunctionAction) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess the "innermost" error is the only one we care about?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, this is probably the most relevant since it's lexically closest to problem.

let error = functionExtraction.errors[0].messageText;
if (typeof error !== 'string') {
error = error.messageText;
}

innermostErrorFunctionAction = {
description,
name: `function_scope_${i}`,
error: error
}
}

// Skip these since we don't have a way to report errors yet
Expand All @@ -57,6 +70,17 @@ namespace ts.refactor.extractSymbol {
name: `constant_scope_${i}`
});
}
} else if (!innermostErrorConstantAction) {
let error = constantExtraction.errors[0].messageText;
if (typeof error !== 'string') {
error = error.messageText;
}

innermostErrorConstantAction = {
description,
name: `constant_scope_${i}`,
error: error
}
}

// *do* increment i anyway because we'll look for the i-th scope
Expand All @@ -66,19 +90,19 @@ namespace ts.refactor.extractSymbol {

const infos: ApplicableRefactorInfo[] = [];

if (functionActions.length) {
if (functionActions.length || innermostErrorFunctionAction) {
infos.push({
name: refactorName,
description: getLocaleSpecificMessage(Diagnostics.Extract_function),
actions: functionActions
actions: functionActions.length ? functionActions : [ innermostErrorFunctionAction! ]
});
}

if (constantActions.length) {
if (constantActions.length || innermostErrorConstantAction) {
infos.push({
name: refactorName,
description: getLocaleSpecificMessage(Diagnostics.Extract_constant),
actions: constantActions
actions: constantActions.length ? constantActions : [ innermostErrorConstantAction! ]
});
}

Expand Down
2 changes: 2 additions & 0 deletions src/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,8 @@ namespace ts {
* so this description should make sense by itself if the parent is inlineable=true
*/
description: string;

error?: string;
}

/**
Expand Down