Skip to content

Commit 84087d0

Browse files
authored
Use shorthand property assignment in convert parameters to object (#30468)
* create shorthand property assignment in argument object when possible * add shorthand property assignment test * don't offer refactor on jsdoc comment * add jsdoc test * improve jsdoc test * use crlf
1 parent 9e28a81 commit 84087d0

4 files changed

+69
-3
lines changed

src/services/refactors/convertParamsToDestructuredObject.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ namespace ts.refactor.convertParamsToDestructuredObject {
233233
function getFunctionDeclarationAtPosition(file: SourceFile, startPosition: number, checker: TypeChecker): ValidFunctionDeclaration | undefined {
234234
const node = getTouchingToken(file, startPosition);
235235
const functionDeclaration = getContainingFunction(node);
236+
237+
// don't offer refactor on top-level JSDoc
238+
if (isTopLevelJSDoc(node)) return undefined;
239+
236240
if (functionDeclaration
237241
&& isValidFunctionDeclaration(functionDeclaration, checker)
238242
&& rangeContainsRange(functionDeclaration, node)
@@ -241,6 +245,15 @@ namespace ts.refactor.convertParamsToDestructuredObject {
241245
return undefined;
242246
}
243247

248+
function isTopLevelJSDoc(node: Node): boolean {
249+
const containingJSDoc = findAncestor(node, isJSDocNode);
250+
if (containingJSDoc) {
251+
const containingNonJSDoc = findAncestor(containingJSDoc, n => !isJSDocNode(n));
252+
return !!containingNonJSDoc && isFunctionLikeDeclaration(containingNonJSDoc);
253+
}
254+
return false;
255+
}
256+
244257
function isValidFunctionDeclaration(
245258
functionDeclaration: SignatureDeclaration,
246259
checker: TypeChecker): functionDeclaration is ValidFunctionDeclaration {
@@ -308,13 +321,23 @@ namespace ts.refactor.convertParamsToDestructuredObject {
308321
return parameters;
309322
}
310323

324+
function createPropertyOrShorthandAssignment(name: string, initializer: Expression): PropertyAssignment | ShorthandPropertyAssignment {
325+
if (isIdentifier(initializer) && getTextOfIdentifierOrLiteral(initializer) === name) {
326+
return createShorthandPropertyAssignment(name);
327+
}
328+
return createPropertyAssignment(name, initializer);
329+
}
330+
311331
function createNewArgument(functionDeclaration: ValidFunctionDeclaration, functionArguments: NodeArray<Expression>): ObjectLiteralExpression {
312332
const parameters = getRefactorableParameters(functionDeclaration.parameters);
313333
const hasRestParameter = isRestParameter(last(parameters));
314334
const nonRestArguments = hasRestParameter ? functionArguments.slice(0, parameters.length - 1) : functionArguments;
315335
const properties = map(nonRestArguments, (arg, i) => {
316-
const property = createPropertyAssignment(getParameterName(parameters[i]), arg);
317-
suppressLeadingAndTrailingTrivia(property.initializer);
336+
const parameterName = getParameterName(parameters[i]);
337+
const property = createPropertyOrShorthandAssignment(parameterName, arg);
338+
339+
suppressLeadingAndTrailingTrivia(property.name);
340+
if (isPropertyAssignment(property)) suppressLeadingAndTrailingTrivia(property.initializer);
318341
copyComments(arg, property);
319342
return property;
320343
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
/////**
4+
//// * Return the boolean state of attribute from an element
5+
//// * /*a*/@param/*b*/ el The source of the attributes.
6+
//// * @param atty Name of the attribute or a string of candidate attribute names.
7+
//// * @param def Default boolean value when attribute is undefined.
8+
//// */
9+
////export function /*c*/getBoolFromAttribute/*d*/(
10+
//// /*e*//** inline JSDoc *//*f*/ attr: string | string[],
11+
//// def: boolean = false): boolean { }
12+
13+
goTo.select("a", "b");
14+
verify.not.refactorAvailable("Convert parameters to destructured object");
15+
goTo.select("c", "d");
16+
verify.refactorAvailable("Convert parameters to destructured object");
17+
goTo.select("e", "f");
18+
verify.refactorAvailable("Convert parameters to destructured object");
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: f.ts
4+
////function /*a*/f/*b*/(a: number, b: number, ...rest: string[]) { }
5+
////const a = 4;
6+
////const b = 5;
7+
////f(a, b);
8+
////const rest = ["a", "b", "c"];
9+
////f(a, b, ...rest);
10+
////f(/** a */ a /** aa */, /** b */ b /** bb */);
11+
12+
13+
goTo.select("a", "b");
14+
edit.applyRefactor({
15+
refactorName: "Convert parameters to destructured object",
16+
actionName: "Convert parameters to destructured object",
17+
actionDescription: "Convert parameters to destructured object",
18+
newContent: `function f({ a, b, rest = [] }: { a: number; b: number; rest?: string[]; }) { }
19+
const a = 4;
20+
const b = 5;
21+
f({ a, b });
22+
const rest = ["a", "b", "c"];
23+
f({ a, b, rest: [...rest] });
24+
f({ /** a */ a /** aa */, /** b */ b /** bb */ });`
25+
});

tests/cases/fourslash/refactorConvertParamsToDestructuredObject_superCall.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ edit.applyRefactor({
1919
}
2020
class B extends A {
2121
constructor(a: string, b: string, c: string) {
22-
super({ a: a, b: b });
22+
super({ a, b });
2323
}
2424
}`
2525
});

0 commit comments

Comments
 (0)