-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(refactoring): add/from destructure bug fixes,
this
keyword sup…
…port (#183)
- Loading branch information
Showing
21 changed files
with
950 additions
and
924 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
49 changes: 49 additions & 0 deletions
49
typescript/src/codeActions/custom/addDestructure/addDestructure.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { getChangesTracker, isValidInitializerForDestructure } from '../../../utils' | ||
import { CodeAction } from '../../getCodeActions' | ||
import createDestructuredDeclaration from './createDestructuredDeclaration' | ||
import addSplittedDestructure from './addSplittedDestructure' | ||
|
||
export default { | ||
id: 'addDestruct', | ||
name: 'Add Destruct', | ||
kind: 'refactor.rewrite.add-destruct', | ||
tryToApply(sourceFile, position, _range, node, formatOptions, languageService) { | ||
if (!node || !position) return | ||
const initialDeclaration = ts.findAncestor(node, n => ts.isVariableDeclaration(n)) as ts.VariableDeclaration | undefined | ||
|
||
if (initialDeclaration && !ts.isObjectBindingPattern(initialDeclaration.name)) { | ||
const { initializer, type, name } = initialDeclaration | ||
|
||
const result = addSplittedDestructure(node, sourceFile, formatOptions, languageService) | ||
|
||
if (result) return result | ||
|
||
if (!initializer || !isValidInitializerForDestructure(initializer)) return | ||
|
||
const tracker = getChangesTracker(formatOptions ?? {}) | ||
const createdDeclaration = createDestructuredDeclaration(initializer, type, name) | ||
if (createdDeclaration) { | ||
tracker.replaceRange( | ||
sourceFile, | ||
{ | ||
pos: initialDeclaration.pos + initialDeclaration.getLeadingTriviaWidth(), | ||
end: initialDeclaration.end, | ||
}, | ||
createdDeclaration, | ||
) | ||
|
||
const changes = tracker.getChanges() | ||
if (!changes) return undefined | ||
return { | ||
edits: [ | ||
{ | ||
fileName: sourceFile.fileName, | ||
textChanges: changes[0]!.textChanges, | ||
}, | ||
], | ||
} | ||
} | ||
} | ||
return addSplittedDestructure(node, sourceFile, formatOptions, languageService) | ||
}, | ||
} satisfies CodeAction |
85 changes: 85 additions & 0 deletions
85
typescript/src/codeActions/custom/addDestructure/addSplittedDestructure.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { findChildContainingExactPosition, getChangesTracker, getPositionHighlights, isValidInitializerForDestructure, makeUniqueName } from '../../../utils' | ||
|
||
export default (node: ts.Node, sourceFile: ts.SourceFile, formatOptions: ts.FormatCodeSettings | undefined, languageService: ts.LanguageService) => { | ||
const isValidInitializer = ts.isVariableDeclaration(node.parent) && node.parent.initializer && isValidInitializerForDestructure(node.parent.initializer) | ||
|
||
// Make sure it only triggers on the destructuring object or parameter | ||
if (!ts.isIdentifier(node) || !(isValidInitializer || ts.isParameter(node.parent))) return | ||
|
||
const highlightPositions = getPositionHighlights(node.getStart(), sourceFile, languageService) | ||
|
||
if (!highlightPositions) return | ||
const tracker = getChangesTracker(formatOptions ?? {}) | ||
|
||
const propertyNames: Array<{ initial: string; unique: string | undefined }> = [] | ||
let nodeToReplaceWithBindingPattern: ts.Identifier | undefined | ||
|
||
for (const pos of highlightPositions) { | ||
const highlightedNode = findChildContainingExactPosition(sourceFile, pos) | ||
|
||
if (!highlightedNode) continue | ||
|
||
if ( | ||
ts.isElementAccessExpression(highlightedNode.parent) || | ||
ts.isCallExpression(highlightedNode.parent.parent) || | ||
ts.isTypeQueryNode(highlightedNode.parent) | ||
) | ||
return | ||
|
||
if (ts.isIdentifier(highlightedNode) && ts.isPropertyAccessExpression(highlightedNode.parent)) { | ||
const accessorName = highlightedNode.parent.name.getText() | ||
|
||
if (!accessorName) continue | ||
|
||
const uniqueName = makeUniqueName(accessorName, node, languageService, sourceFile) | ||
|
||
propertyNames.push({ initial: accessorName, unique: uniqueName === accessorName ? undefined : uniqueName }) | ||
const range = | ||
ts.isPropertyAssignment(highlightedNode.parent.parent) && highlightedNode.parent.parent.name.getText() === accessorName | ||
? { | ||
pos: highlightedNode.parent.parent.pos + highlightedNode.parent.parent.getLeadingTriviaWidth(), | ||
end: highlightedNode.parent.parent.end, | ||
} | ||
: { pos, end: highlightedNode.parent.end } | ||
|
||
tracker.replaceRangeWithText(sourceFile, range, uniqueName) | ||
continue | ||
} | ||
|
||
if (ts.isIdentifier(highlightedNode) && (ts.isVariableDeclaration(highlightedNode.parent) || ts.isParameter(highlightedNode.parent))) { | ||
// Already met a target node - abort as we encountered direct use of the potential destructured variable | ||
if (nodeToReplaceWithBindingPattern) return | ||
nodeToReplaceWithBindingPattern = highlightedNode | ||
continue | ||
} | ||
} | ||
|
||
if (!nodeToReplaceWithBindingPattern || propertyNames.length === 0) return | ||
|
||
const bindings = propertyNames.map(({ initial, unique }) => { | ||
return ts.factory.createBindingElement(undefined, unique ? initial : undefined, unique ?? initial) | ||
}) | ||
|
||
const bindingPattern = ts.factory.createObjectBindingPattern(bindings) | ||
const { pos, end } = nodeToReplaceWithBindingPattern | ||
|
||
tracker.replaceRange( | ||
sourceFile, | ||
{ | ||
pos: pos + nodeToReplaceWithBindingPattern.getLeadingTriviaWidth(), | ||
end, | ||
}, | ||
bindingPattern, | ||
) | ||
|
||
const changes = tracker.getChanges() | ||
if (!changes) return undefined | ||
return { | ||
edits: [ | ||
{ | ||
fileName: sourceFile.fileName, | ||
textChanges: changes[0]!.textChanges, | ||
}, | ||
], | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
typescript/src/codeActions/custom/addDestructure/createDestructuredDeclaration.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
export default (initializer: ts.Expression, type: ts.TypeNode | undefined, declarationName: ts.BindingName) => { | ||
if (!ts.isPropertyAccessExpression(initializer)) return | ||
|
||
const propertyName = initializer.name.text | ||
const { factory } = ts | ||
|
||
const bindingElement = factory.createBindingElement( | ||
undefined, | ||
declarationName.getText() === propertyName ? undefined : propertyName, | ||
declarationName.getText(), | ||
) | ||
|
||
return factory.createVariableDeclaration( | ||
factory.createObjectBindingPattern([bindingElement]), | ||
undefined, | ||
type ? factory.createTypeLiteralNode([factory.createPropertySignature(undefined, factory.createIdentifier(propertyName), undefined, type)]) : undefined, | ||
initializer.expression, | ||
) | ||
} |
Oops, something went wrong.