@dxup/vanilla 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -12
- package/dist/index.cjs +200 -25
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -36,15 +36,23 @@ Add the following to your `tsconfig.json`:
|
|
|
36
36
|
|
|
37
37
|
### 1. signature
|
|
38
38
|
|
|
39
|
-
Go to definition for signature parameters.
|
|
40
|
-
|
|
41
|
-
```ts
|
|
42
|
-
export default defineConfig({
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
});
|
|
50
|
-
```
|
|
39
|
+
- Go to definition for signature parameters.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
export default defineConfig({
|
|
43
|
+
plugins: [{
|
|
44
|
+
name: "testify",
|
|
45
|
+
transform(code, id, options) {
|
|
46
|
+
// ^^^^^^^
|
|
47
|
+
},
|
|
48
|
+
}],
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- Rewrite refactor for signature parameters.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
function swap(foo: number, bar: string, baz: boolean, qux: symbol) {}
|
|
56
|
+
// ^^^ Refactor > Move parameter right
|
|
57
|
+
swap(2, "3", true, Symbol(5));
|
|
58
|
+
```
|
package/dist/index.cjs
CHANGED
|
@@ -12,33 +12,65 @@ function* binaryVisit(ts, sourceFile, node, position) {
|
|
|
12
12
|
let right = nodes.length - 1;
|
|
13
13
|
while (left <= right) {
|
|
14
14
|
const mid = Math.floor((left + right) / 2);
|
|
15
|
-
const node
|
|
16
|
-
if (position > node
|
|
17
|
-
else if (position < node
|
|
15
|
+
const node = nodes[mid];
|
|
16
|
+
if (position > node.getEnd()) left = mid + 1;
|
|
17
|
+
else if (position < node.getStart(sourceFile)) right = mid - 1;
|
|
18
18
|
else {
|
|
19
|
-
yield node
|
|
20
|
-
yield* binaryVisit(ts, sourceFile, node
|
|
19
|
+
yield node;
|
|
20
|
+
yield* binaryVisit(ts, sourceFile, node, position);
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
//#endregion
|
|
27
|
-
//#region src/
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
27
|
+
//#region src/shared.ts
|
|
28
|
+
const refactors = { rewrite: { parameter: {
|
|
29
|
+
forward: {
|
|
30
|
+
name: "Move parameter left",
|
|
31
|
+
description: "Move parameter left",
|
|
32
|
+
kind: "refactor.rewrite.parameter.forward"
|
|
33
|
+
},
|
|
34
|
+
backward: {
|
|
35
|
+
name: "Move parameter right",
|
|
36
|
+
description: "Move parameter right",
|
|
37
|
+
kind: "refactor.rewrite.parameter.backward"
|
|
38
|
+
},
|
|
39
|
+
remove: {
|
|
40
|
+
name: "Remove parameter",
|
|
41
|
+
description: "Remove parameter",
|
|
42
|
+
kind: "refactor.rewrite.parameter.remove"
|
|
43
|
+
}
|
|
44
|
+
} } };
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/features/getApplicableRefactors.ts
|
|
48
|
+
function getApplicableRefactors(ts, info, getApplicableRefactors) {
|
|
49
|
+
return (...args) => {
|
|
50
|
+
const result = getApplicableRefactors(...args);
|
|
51
|
+
const sourceFile = info.languageService.getProgram().getSourceFile(args[0]);
|
|
52
|
+
if (!sourceFile) return result;
|
|
53
|
+
let node;
|
|
54
|
+
const position = typeof args[1] === "number" ? args[1] : args[1].pos;
|
|
55
|
+
for (const child of forEachTouchingNode(ts, sourceFile, position)) if (ts.isParameter(child)) node = child;
|
|
56
|
+
if (node?.parent.name) result.push({
|
|
57
|
+
name: "Dxup",
|
|
58
|
+
description: "Dxup refactor actions",
|
|
59
|
+
actions: [
|
|
60
|
+
refactors.rewrite.parameter.forward,
|
|
61
|
+
refactors.rewrite.parameter.backward,
|
|
62
|
+
refactors.rewrite.parameter.remove
|
|
63
|
+
]
|
|
64
|
+
});
|
|
65
|
+
return result;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/features/getDefinitionAndBoundSpan.ts
|
|
71
|
+
function getDefinitionAndBoundSpan(ts, info, getDefinitionAndBoundSpan) {
|
|
40
72
|
return (...args) => {
|
|
41
|
-
const result = getDefinitionAndBoundSpan
|
|
73
|
+
const result = getDefinitionAndBoundSpan(...args);
|
|
42
74
|
if (!result?.definitions?.length) return result;
|
|
43
75
|
if (result.definitions[0].kind === ts.ScriptElementKind.parameterElement && result.definitions[0].textSpan.start === result.textSpan.start) {
|
|
44
76
|
const program = info.languageService.getProgram();
|
|
@@ -56,15 +88,15 @@ function getDefinitionAndBoundSpan(ts, info, getDefinitionAndBoundSpan$1) {
|
|
|
56
88
|
for (const declaration of forEachParameter(checker, signature)) {
|
|
57
89
|
if (i++ !== index) continue;
|
|
58
90
|
if (declaration) {
|
|
59
|
-
const sourceFile
|
|
91
|
+
const sourceFile = declaration.getSourceFile();
|
|
60
92
|
definitions.push({
|
|
61
|
-
fileName: sourceFile
|
|
93
|
+
fileName: sourceFile.fileName,
|
|
62
94
|
textSpan: {
|
|
63
|
-
start: declaration.getStart(sourceFile
|
|
64
|
-
length: declaration.getWidth(sourceFile
|
|
95
|
+
start: declaration.getStart(sourceFile),
|
|
96
|
+
length: declaration.getWidth(sourceFile)
|
|
65
97
|
},
|
|
66
98
|
kind: ts.ScriptElementKind.parameterElement,
|
|
67
|
-
name: declaration.getText(sourceFile
|
|
99
|
+
name: declaration.getText(sourceFile),
|
|
68
100
|
containerKind: ts.ScriptElementKind.unknown,
|
|
69
101
|
containerName: ""
|
|
70
102
|
});
|
|
@@ -110,4 +142,147 @@ function* forEachParameter(checker, signature) {
|
|
|
110
142
|
}
|
|
111
143
|
|
|
112
144
|
//#endregion
|
|
113
|
-
|
|
145
|
+
//#region src/features/getEditsForRefactor.ts
|
|
146
|
+
function getEditsForRefactor(ts, info, getEditsForRefactor) {
|
|
147
|
+
return (...args) => {
|
|
148
|
+
if (args[3] !== "Dxup") return getEditsForRefactor(...args);
|
|
149
|
+
const sourceFile = info.languageService.getProgram().getSourceFile(args[0]);
|
|
150
|
+
const position = typeof args[2] === "number" ? args[2] : args[2].pos;
|
|
151
|
+
const direction = args[4] === refactors.rewrite.parameter.forward.name ? -1 : args[4] === refactors.rewrite.parameter.backward.name ? 1 : args[4] === refactors.rewrite.parameter.remove.name ? 0 : null;
|
|
152
|
+
if (direction === null) return;
|
|
153
|
+
let node;
|
|
154
|
+
for (const child of forEachTouchingNode(ts, sourceFile, position)) if (ts.isParameter(child)) node = child;
|
|
155
|
+
if (!node?.parent.name) return;
|
|
156
|
+
const firstArg = node.parent.parameters[0];
|
|
157
|
+
const withThis = ts.isIdentifier(firstArg.name) && firstArg.name.text === "this";
|
|
158
|
+
const index = node.parent.parameters.indexOf(node) - Number(withThis);
|
|
159
|
+
if (index === -1 || index + direction < 0 || index + direction === node.parent.parameters.length || direction !== 0 && (node.dotDotDotToken || node.parent.parameters[index + direction].dotDotDotToken)) return;
|
|
160
|
+
const modifier = direction === 0 && node.dotDotDotToken ? Infinity : direction;
|
|
161
|
+
const fileTextChanges = {};
|
|
162
|
+
const references = forEachSignatureReference(ts, info.languageService, args[0], node.parent.name.getStart(sourceFile));
|
|
163
|
+
for (const node of references) {
|
|
164
|
+
const sourceFile = node.getSourceFile();
|
|
165
|
+
const textChanges = fileTextChanges[sourceFile.fileName] ??= [];
|
|
166
|
+
if (ts.isCallExpression(node)) textChanges.push(...calculateTextChanges(ts, sourceFile, node.arguments, index, modifier));
|
|
167
|
+
else {
|
|
168
|
+
let index2 = index;
|
|
169
|
+
const firstArg = node.parameters[0];
|
|
170
|
+
if (ts.isIdentifier(firstArg.name) && firstArg.name.text === "this") index2++;
|
|
171
|
+
textChanges.push(...calculateTextChanges(ts, sourceFile, node.parameters, index2, modifier));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { edits: Object.entries(fileTextChanges).map(([fileName, textChanges]) => ({
|
|
175
|
+
fileName,
|
|
176
|
+
textChanges
|
|
177
|
+
})) };
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function* forEachSignatureReference(ts, languageService, fileName, position, visited = /* @__PURE__ */ new Set()) {
|
|
181
|
+
const program = languageService.getProgram();
|
|
182
|
+
const references = languageService.getReferencesAtPosition(fileName, position) ?? [];
|
|
183
|
+
outer: for (const { fileName, textSpan } of references) {
|
|
184
|
+
const key = fileName + "@" + textSpan.start;
|
|
185
|
+
if (visited.has(key)) continue;
|
|
186
|
+
visited.add(key);
|
|
187
|
+
const sourceFile = program.getSourceFile(fileName);
|
|
188
|
+
let node;
|
|
189
|
+
for (const child of forEachTouchingNode(ts, sourceFile, textSpan.start)) if (ts.isIdentifier(child)) {
|
|
190
|
+
node = child;
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
if (!node) continue;
|
|
194
|
+
if (ts.isCallExpression(node.parent) && node === node.parent.expression) {
|
|
195
|
+
yield node.parent;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (ts.isPropertyAccessExpression(node.parent) && node === node.parent.name && ts.isCallExpression(node.parent.parent) && node.parent === node.parent.parent.expression) {
|
|
199
|
+
yield node.parent.parent;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (ts.isFunctionLike(node.parent) && node === node.parent.name) {
|
|
203
|
+
yield node.parent;
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if ((ts.isPropertyAssignment(node.parent) || ts.isPropertyDeclaration(node.parent)) && node === node.parent.name && node.parent.initializer) {
|
|
207
|
+
const expression = getUnwrappedExpression(ts, node.parent.initializer);
|
|
208
|
+
if (ts.isFunctionLike(expression)) {
|
|
209
|
+
yield expression;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
let start;
|
|
214
|
+
let curr = node;
|
|
215
|
+
inner: while (curr) {
|
|
216
|
+
if (ts.isVariableDeclaration(curr.parent) && curr === curr.parent.initializer) start = curr.parent.name.getStart(sourceFile);
|
|
217
|
+
else if ((ts.isPropertyAssignment(curr.parent) || ts.isPropertyDeclaration(curr.parent)) && curr === curr.parent.initializer) start = curr.parent.name.getStart(sourceFile);
|
|
218
|
+
else if (ts.isShorthandPropertyAssignment(curr.parent)) start = curr.getStart(sourceFile);
|
|
219
|
+
else if (ts.isTypeQueryNode(curr.parent) && curr === curr.parent.exprName && ts.isVariableDeclaration(curr.parent.parent) && curr.parent.parent.initializer) {
|
|
220
|
+
const expression = getUnwrappedExpression(ts, curr.parent.parent.initializer);
|
|
221
|
+
if (ts.isFunctionLike(expression)) yield expression;
|
|
222
|
+
start = curr.parent.parent.name.getStart(sourceFile);
|
|
223
|
+
} else if (ts.isTypeQueryNode(curr.parent) && curr === curr.parent.exprName && ts.isAsExpression(curr.parent.parent) && curr.parent.parent.expression) {
|
|
224
|
+
const expression = getUnwrappedExpression(ts, curr.parent.parent.expression);
|
|
225
|
+
if (ts.isFunctionLike(expression)) yield expression;
|
|
226
|
+
curr = curr.parent.parent;
|
|
227
|
+
continue inner;
|
|
228
|
+
} else if (ts.isTypeQueryNode(curr.parent) && curr === curr.parent.exprName && ts.isPropertySignature(curr.parent.parent)) start = curr.parent.parent.name.getStart(sourceFile);
|
|
229
|
+
else continue outer;
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
yield* forEachSignatureReference(ts, languageService, fileName, start, visited);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function getUnwrappedExpression(ts, node) {
|
|
236
|
+
while (ts.isParenthesizedExpression(node)) {
|
|
237
|
+
node = node.expression;
|
|
238
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.CommaToken) node = node.right;
|
|
239
|
+
}
|
|
240
|
+
return node;
|
|
241
|
+
}
|
|
242
|
+
function* calculateTextChanges(ts, sourceFile, args, index, modifier) {
|
|
243
|
+
const spreadIndex = args.findIndex((arg) => ts.isSpreadElement(arg));
|
|
244
|
+
if (spreadIndex !== -1 && spreadIndex <= Math.max(index, index + modifier)) return;
|
|
245
|
+
if (modifier === 0 || modifier === Infinity) {
|
|
246
|
+
const from = index;
|
|
247
|
+
const to = modifier === Infinity ? args.length - 1 : Math.min(args.length - 1, index);
|
|
248
|
+
const [start, end] = from ? [args[from - 1].end, args[to].end] : [args[from].getStart(sourceFile), args[to + 1]?.getStart(sourceFile) ?? args[to].end];
|
|
249
|
+
yield {
|
|
250
|
+
span: {
|
|
251
|
+
start,
|
|
252
|
+
length: end - start
|
|
253
|
+
},
|
|
254
|
+
newText: ""
|
|
255
|
+
};
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
for (let i = index; modifier === -1 ? i >= index + modifier : i <= index + modifier; i += modifier) yield {
|
|
259
|
+
span: {
|
|
260
|
+
start: args[i].getStart(sourceFile),
|
|
261
|
+
length: args[i].getWidth(sourceFile)
|
|
262
|
+
},
|
|
263
|
+
newText: args[i === index ? i + modifier : index].getText(sourceFile)
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
//#endregion
|
|
268
|
+
//#region src/index.ts
|
|
269
|
+
const plugin = (module) => {
|
|
270
|
+
const { typescript: ts } = module;
|
|
271
|
+
return { create(info) {
|
|
272
|
+
const methods = {};
|
|
273
|
+
for (const [key, method] of [
|
|
274
|
+
["getApplicableRefactors", getApplicableRefactors],
|
|
275
|
+
["getEditsForRefactor", getEditsForRefactor],
|
|
276
|
+
["getDefinitionAndBoundSpan", getDefinitionAndBoundSpan]
|
|
277
|
+
]) {
|
|
278
|
+
const original = info.languageService[key];
|
|
279
|
+
methods[key] = method(ts, info, original);
|
|
280
|
+
}
|
|
281
|
+
return new Proxy(info.languageService, { get(target, p, receiver) {
|
|
282
|
+
return methods[p] ?? Reflect.get(target, p, receiver);
|
|
283
|
+
} });
|
|
284
|
+
} };
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
//#endregion
|
|
288
|
+
module.exports = plugin;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxup/vanilla",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.2",
|
|
5
5
|
"description": "TypeScript plugin for Vanilla JS",
|
|
6
6
|
"author": "KazariEX",
|
|
7
7
|
"license": "MIT",
|
|
@@ -15,9 +15,12 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"dist"
|
|
17
17
|
],
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"typescript": "*"
|
|
20
|
+
},
|
|
18
21
|
"devDependencies": {
|
|
19
|
-
"
|
|
20
|
-
"
|
|
22
|
+
"typescript": "^5.9.3",
|
|
23
|
+
"@dxup/shared": "0.0.0"
|
|
21
24
|
},
|
|
22
25
|
"scripts": {
|
|
23
26
|
"build": "tsdown",
|