Skip to content

Commit a97fa08

Browse files
committed
feat: add highly customizable arrayMethodsSnippets!
No reason to not enable them! Disabled by defeault, just to not suprprise everyone!
1 parent 679700e commit a97fa08

File tree

8 files changed

+107
-10
lines changed

8 files changed

+107
-10
lines changed

README.MD

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,18 @@ You can turn off emmet integration in JSX and stable emmet suggestion will be *a
3737

3838
- supports only tag expansion for now, have 2 modes
3939

40+
### Array Method Snippets
41+
42+
(*disabled by default*)
43+
44+
Edits array suggestions that receive predicate in the following way:
45+
46+
```ts
47+
const usersList = []
48+
49+
usersList.map // -> usersList.map((user) => )
50+
```
51+
4052
### Remove Definition From References
4153

4254
(*enabled by default*)

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@
5454
"type-fest": "^2.13.1",
5555
"typed-jsonfile": "^0.2.1",
5656
"typescript": "^4.8.3",
57-
"typescript-essential-plugins": "workspace:*",
5857
"typescript-old": "npm:[email protected]",
5958
"vitest": "^0.15.1",
6059
"vscode-manifest": "^0.0.4"
@@ -64,6 +63,7 @@
6463
"@types/glob": "^8.0.0",
6564
"@types/lodash": "^4.14.182",
6665
"@types/mocha": "^9.1.1",
66+
"@types/pluralize": "^0.0.29",
6767
"@vscode/emmet-helper": "^2.8.4",
6868
"@vscode/test-electron": "^2.1.5",
6969
"@zardoy/utils": "^0.0.9",
@@ -81,6 +81,7 @@
8181
"lodash.throttle": "^4.1.1",
8282
"mocha": "^10.0.0",
8383
"modify-json-file": "^1.2.2",
84+
"pluralize": "github:plurals/pluralize#36f03cd2d573fa6d23e12e1529fa4627e2af74b4",
8485
"require-from-string": "^2.0.2",
8586
"string-dedent": "^3.0.1",
8687
"vscode-framework": "^0.0.18"

pnpm-lock.yaml

Lines changed: 15 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/configurationType.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,26 @@ export type Configuration = {
5555
'suggestions.keywordsInsertText': 'none' | 'space'
5656
// TODO! corrent watching!
5757
/**
58-
*
58+
* Wether to enable snippets for array methods like `items.map(item => )`
59+
* @default false
60+
*/
61+
'arrayMethodsSnippets.enable': boolean
62+
/**
63+
* Add tabstop at arg so you can easily change it or add `i`
64+
* If set to `false`, arg is added without parentheses
5965
* @default true
6066
*/
61-
// 'patchArrayMethods.enable': boolean
67+
'arrayMethodsSnippets.addArgTabStop': boolean
68+
/**
69+
* Add outer tabstop so you can easily pass callback instead
70+
* @default false
71+
*/
72+
'arrayMethodsSnippets.addOuterTabStop': boolean
73+
/**
74+
* If set to `false` and singular item name can't be inffered, feature will be disabled
75+
* @default item
76+
*/
77+
'arrayMethodsSnippets.defaultItemName': string | false
6278
/**
6379
* Highlight and lift non-function methods. Also applies for static class methods. Uses `bind`, `call`, `caller` detection.
6480
* @default true
@@ -136,7 +152,7 @@ export type Configuration = {
136152
/** Diagnostics (if not handled by eslint) & completions */
137153
// 'dotImportsMap.enable': boolean,
138154
/**
139-
* One of the most powerful setting here. It lets you remove/edit any suggestion that comes from TS.
155+
* One of the most powerful setting here. It lets you remove/edit any suggestion that comes from TS. However its' experimental and can conflict with our completion changes.
140156
* **Please** try to always specify kind (e.g. variable) of the suggestion to ensure you don't remove word-suggestion or postfix snippet
141157
* @default []
142158
*/
@@ -178,7 +194,7 @@ export type Configuration = {
178194
*/
179195
supportTsDiagnosticDisableComment: boolean
180196
/**
181-
* Patch TypeScript outline!
197+
* Extend TypeScript outline!
182198
* Extend outline with:
183199
* - JSX Elements
184200
* more coming soon...
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { GetConfig } from '../types'
2+
import { findChildContainingPosition, getLineTextBeforePos } from '../utils'
3+
import { singular } from 'pluralize'
4+
5+
export default (entries: ts.CompletionEntry[], _node: ts.Node | undefined, position: number, sourceFile: ts.SourceFile, c: GetConfig): ts.CompletionEntry[] => {
6+
if (!c('arrayMethodsSnippets.enable')) return entries
7+
/** Methods to patch */
8+
const arrayMethods = [
9+
'forEach',
10+
'map',
11+
'flatMap',
12+
'filter',
13+
'find',
14+
'findIndex',
15+
// 'reduce',
16+
// 'reduceRight',
17+
'some',
18+
'every',
19+
]
20+
const fullText = sourceFile.getText()
21+
if (fullText.slice(position, position + 1) === '(') return entries
22+
const isSeemsArray = arrayMethods.every(comparingName =>
23+
entries.some(({ name, isSnippet, kind }) => name === comparingName && !isSnippet && kind === ts.ScriptElementKind.memberFunctionElement),
24+
)
25+
if (!isSeemsArray) return entries
26+
const lineTextBefore = getLineTextBeforePos(sourceFile, position)
27+
const postfixRemoveLength = /\.\w*$/.exec(lineTextBefore)?.[0]?.length
28+
if (postfixRemoveLength === undefined) return entries
29+
const nodeBeforeDot = findChildContainingPosition(ts, sourceFile, position - postfixRemoveLength - 1)
30+
if (!nodeBeforeDot) return entries
31+
if (!ts.isIdentifier(nodeBeforeDot)) return entries
32+
const cleanSourceText = nodeBeforeDot.text.replace(/^(?:all)?(.+?)(?:List)?$/, '$1')
33+
let inferredName = singular(cleanSourceText)
34+
const defaultItemName = c('arrayMethodsSnippets.defaultItemName')
35+
if (inferredName === cleanSourceText) {
36+
if (defaultItemName === false) return entries
37+
inferredName = defaultItemName
38+
}
39+
return entries.map(entry => {
40+
if (!arrayMethods.includes(entry.name)) return entry
41+
const arrayItemSnippet = c('arrayMethodsSnippets.addArgTabStop') ? `(\${2:${inferredName}})` : inferredName
42+
let insertInnerSnippet = `${arrayItemSnippet} => $3`
43+
if (c('arrayMethodsSnippets.addOuterTabStop')) insertInnerSnippet = `\${1:${insertInnerSnippet}}`
44+
return {
45+
...entry,
46+
insertText: `${entry.insertText ?? entry.name}(${insertInnerSnippet})`,
47+
isSnippet: true,
48+
}
49+
})
50+
}

typescript/src/completionsAtPosition.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import indexSignatureAccessCompletions from './completions/indexSignatureAccess'
88
import fixPropertiesSorting from './completions/fixPropertiesSorting'
99
import { isGoodPositionBuiltinMethodCompletion } from './completions/isGoodPositionMethodCompletion'
1010
import improveJsxCompletions from './completions/jsxAttributes'
11+
import arrayMethods from './completions/arrayMethods'
1112

1213
export type PrevCompletionMap = Record<string, { originalName?: string; documentationOverride?: string | tslib.SymbolDisplayPart[] }>
1314

@@ -208,6 +209,8 @@ export const getCompletionsAtPosition = (
208209
})
209210
}
210211

212+
prior.entries = arrayMethods(prior.entries, node, position, sourceFile, c)
213+
211214
if (c('improveJsxCompletions') && leftNode) prior.entries = improveJsxCompletions(ts, prior.entries, leftNode, position, sourceFile, c('jsxCompletionsMap'))
212215

213216
for (const rule of c('replaceSuggestions')) {

typescript/src/utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,8 @@ export const findClosestParent = (ts: typeof tslib, node: tslib.Node, stopKinds:
5252

5353
return node
5454
}
55+
56+
export const getLineTextBeforePos = (sourceFile: ts.SourceFile, position: number) => {
57+
const { character } = sourceFile.getLineAndCharacterOfPosition(position)
58+
return sourceFile.getText().slice(position - character, position)
59+
}

0 commit comments

Comments
 (0)