Skip to content

Commit d0b9de8

Browse files
authored
Merge pull request #137 from zardoy/develop
2 parents 9941886 + f76e81b commit d0b9de8

File tree

11 files changed

+127
-42
lines changed

11 files changed

+127
-42
lines changed

README.MD

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ TOC:
1616
- [Contributed Code Actions](#contributed-code-actions)
1717
- [Even Even More](#even-even-more)
1818

19-
> *Note* Visit website for list of recommended settings: <https://ts-plugin.zardoy.com/>
19+
> *Note*: You can disable all optional features with `> Disable All Optional Features` setting right after install.
20+
>
21+
> *Note*: Visit website for list of recommended settings: <https://ts-plugin.zardoy.com/>
2022
2123
## Top Features
2224

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@
5858
{
5959
"command": "pasteCodeWithImports",
6060
"title": "Paste Code with Imports"
61+
},
62+
{
63+
"command": "disableAllOptionalFeatures",
64+
"title": "Disable All Optional Features"
6165
}
6266
],
6367
"keybindings": [
@@ -90,7 +94,7 @@
9094
"keywords": [
9195
"ts",
9296
"javascript",
93-
"plugin",
97+
"pro",
9498
"webstorm",
9599
"typescript hero"
96100
],

src/configurationType.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export type Configuration = {
118118
/**
119119
* Will be `format-short` by default in future as super useful!
120120
* Requires TypeScript 5.0+
121+
* @recommended
121122
* @default disable
122123
*/
123124
'suggestions.displayImportedInfo': 'disable' | 'short-format' | 'long-format'
@@ -160,14 +161,15 @@ export type Configuration = {
160161
* */
161162
'correctSorting.enable': boolean
162163
/**
163-
* Try to restore suggestion sorting after `.`
164+
* Try to restore properties (not variables!) sorting as in source
164165
* Experimental and most probably will be changed in future
166+
* @recommended
165167
* @default false
166168
*/
167169
fixSuggestionsSorting: boolean
168-
// TODO
170+
// TODO-low
169171
/**
170-
* Mark QuickFixes & refactorings with 🔵
172+
* Mark refactorings with 🔵
171173
* @default true
172174
*/
173175
'markTsCodeActions.enable': boolean
@@ -205,6 +207,11 @@ export type Configuration = {
205207
* @default true
206208
* */
207209
'removeCodeFixes.enable': boolean
210+
/**
211+
* @default ["fixMissingFunctionDeclaration"]
212+
* @uniqueItems true
213+
* */
214+
'removeCodeFixes.codefixes': FixId[]
208215
/**
209216
* Also rename name of default or namespace import on refactor caused by file move / rename
210217
* Probably will be enabled by default in future
@@ -228,13 +235,8 @@ export type Configuration = {
228235
*/
229236
workspaceSymbolSearchExcludePatterns: string[]
230237
/**
231-
* @default ["fixMissingFunctionDeclaration"]
232-
* @uniqueItems true
233-
* */
234-
'removeCodeFixes.codefixes': FixId[]
235-
/**
236-
* Use full-blown emmet in jsx/tsx files!
237-
* Requires `jsxPseudoEmmet.enabled` to be disabled and `emmet.excludeLanguages` to have `javascriptreact` and `typescriptreact`
238+
* Use strict & precise emmet in jsx/tsx files! Doesn't annoy you everywhere!
239+
* Requires `jsxPseudoEmmet.enabled` to be disabled and `emmet.excludeLanguages` to have `javascriptreact` / `typescriptreact`
238240
* @default true
239241
* */
240242
'jsxEmmet.enable': boolean
@@ -443,11 +445,11 @@ export type Configuration = {
443445
*/
444446
// completionHelpers: boolean
445447
/**
446-
* Extend TypeScript outline!
447-
* Extend outline with:
448+
* Extend TypeScript outline with:
448449
* - JSX Elements
449450
* - Type Alias Declarations
450451
* Should be stable!
452+
* @recommended
451453
* @default false
452454
*/
453455
patchOutline: boolean
@@ -458,6 +460,7 @@ export type Configuration = {
458460
'outline.arraysTuplesNumberedItems': boolean
459461
/**
460462
* Exclude covered strings/enum cases in switch in completions
463+
* @deprecated Will be removed in next release
461464
* @default true
462465
*/
463466
switchExcludeCoveredCases: boolean
@@ -520,12 +523,12 @@ export type Configuration = {
520523
*/
521524
'figIntegration.enableWhenStartsWith': string[]
522525
/**
523-
* Propose additional completions in object. Just like `typescript.suggest.objectLiteralMethodSnippets.enabled`, but also for string, arrays and objects
526+
* Propose additional completions in object. Just like `typescript.suggest.objectLiteralMethodSnippets.enabled`, but also for strings, arrays and objects
524527
* @default true
525528
*/
526529
'objectLiteralCompletions.moreVariants': boolean
527530
/**
528-
* When `moreVariants` enabled, always add as fallback variant if other variant can't be derived
531+
* When `moreVariants` is enabled, always add fallback variant (`: `) if other variant can't be derived
529532
* @default false
530533
*/
531534
'objectLiteralCompletions.fallbackVariant': boolean

src/extension.ts

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/* eslint-disable @typescript-eslint/no-require-imports */
22
import * as vscode from 'vscode'
33
import { defaultJsSupersetLangs } from '@zardoy/vscode-utils/build/langs'
4-
import { extensionCtx, getExtensionSetting, getExtensionSettingId } from 'vscode-framework'
4+
import { Settings, extensionCtx, getExtensionSetting, getExtensionSettingId, registerExtensionCommand } from 'vscode-framework'
55
import { pickObj } from '@zardoy/utils'
66
import { watchExtensionSettings } from '@zardoy/vscode-utils/build/settings'
7+
import { ConditionalPick } from 'type-fest'
78
import webImports from './webImports'
89
import { sendCommand } from './sendCommand'
910
import { registerEmmet } from './emmet'
@@ -90,6 +91,7 @@ export const activateTsPlugin = (tsApi: { configurePlugin; onCompletionAccepted
9091
}
9192

9293
export const activate = async () => {
94+
registerDisableOptionalFeaturesCommand()
9395
migrateSettings()
9496

9597
const possiblyActivateTsPlugin = async () => {
@@ -138,3 +140,55 @@ export const activate = async () => {
138140
})
139141
}
140142
}
143+
144+
const registerDisableOptionalFeaturesCommand = () => {
145+
registerExtensionCommand('disableAllOptionalFeatures', async () => {
146+
const config = vscode.workspace.getConfiguration(process.env.IDS_PREFIX, null)
147+
const toDisable: Array<[keyof Settings, any]> = []
148+
for (const optionalExperience of optionalExperiences) {
149+
const desiredKey = Array.isArray(optionalExperience) ? optionalExperience[0] : optionalExperience
150+
const desiredValue = Array.isArray(optionalExperience) ? optionalExperience[1] : false
151+
if (config.get(desiredKey) !== desiredValue) toDisable.push([desiredKey, desiredValue])
152+
}
153+
154+
const action = await vscode.window.showInformationMessage(
155+
`${toDisable.length} features are going to be disabled`,
156+
{ detail: '', modal: true },
157+
'Write to settings NOW',
158+
'Copy settings',
159+
)
160+
if (!action) return
161+
switch (action) {
162+
case 'Write to settings NOW': {
163+
for (const [key, value] of toDisable) {
164+
void config.update(key, value, vscode.ConfigurationTarget.Global)
165+
}
166+
167+
break
168+
}
169+
170+
case 'Copy settings': {
171+
await vscode.env.clipboard.writeText(JSON.stringify(Object.fromEntries(toDisable), undefined, 4))
172+
break
173+
}
174+
}
175+
})
176+
}
177+
178+
/** Experiences that are enabled out of the box */
179+
const optionalExperiences: Array<keyof ConditionalPick<Settings, boolean> | [keyof Settings, any]> = [
180+
'enableMethodSnippets',
181+
'removeUselessFunctionProps.enable',
182+
'patchToString.enable',
183+
['suggestions.keywordsInsertText', 'none'],
184+
'highlightNonFunctionMethods.enable',
185+
'markTsCodeActions.enable',
186+
['markTsCodeFixes.character', ''],
187+
'removeCodeFixes.enable',
188+
'removeDefinitionFromReferences',
189+
'removeImportsFromReferences',
190+
'miscDefinitionImprovement',
191+
'improveJsxCompletions',
192+
'objectLiteralCompletions.moreVariants',
193+
'codeActions.extractTypeInferName',
194+
]

typescript/src/codeActions/decorateProxy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService,
2020
const program = languageService.getProgram()!
2121
const sourceFile = program.getSourceFile(fileName)!
2222
processApplicableRefactors(
23-
prior.find(r => r.description === 'Extract function'),
23+
prior.find(r => r.name === 'Extract Symbol' && r.actions.some(action => action.kind?.startsWith('refactor.extract.function')))?.actions,
2424
c,
2525
positionOrRange,
2626
sourceFile,

typescript/src/codeActions/functionExtractors.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { equals } from 'rambda'
21
import { GetConfig } from '../types'
32
import {
43
createDummySourceFile,
@@ -9,16 +8,16 @@ import {
98
} from '../utils'
109

1110
export const processApplicableRefactors = (
12-
refactor: ts.ApplicableRefactorInfo | undefined,
11+
refactorActions: ts.RefactorActionInfo[] | undefined,
1312
c: GetConfig,
1413
posOrRange: number | ts.TextRange,
1514
sourceFile: ts.SourceFile,
1615
) => {
17-
if (!refactor) return
18-
const functionExtractors = refactor?.actions.filter(({ notApplicableReason }) => !notApplicableReason)
16+
if (!refactorActions) return
17+
const functionExtractors = refactorActions.filter(({ notApplicableReason }) => !notApplicableReason)
1918
if (functionExtractors?.length) {
2019
const kind = functionExtractors[0]!.kind!
21-
const blockScopeRefactor = functionExtractors.find(e => e.description.startsWith('Extract to inner function in'))
20+
const blockScopeRefactor = functionExtractors.find(e => e.description.includes('inner function'))
2221
const addArrowCodeActions: ts.RefactorActionInfo[] = []
2322
if (blockScopeRefactor) {
2423
addArrowCodeActions.push({
@@ -28,9 +27,7 @@ export const processApplicableRefactors = (
2827
})
2928
}
3029
let addExtractToJsxRefactor = false
31-
const globalScopeRefactor = functionExtractors.find(e =>
32-
['Extract to function in global scope', 'Extract to function in module scope'].includes(e.description),
33-
)
30+
const globalScopeRefactor = functionExtractors.at(-1)
3431
if (globalScopeRefactor) {
3532
addArrowCodeActions.push({
3633
description: 'Extract to arrow function in global scope above',
@@ -42,16 +39,20 @@ export const processApplicableRefactors = (
4239
}
4340

4441
if (addExtractToJsxRefactor) {
45-
refactor.actions = refactor.actions.filter(action => !action.name.startsWith('function_scope'))
46-
refactor.actions.push({
42+
for (const refactorAction of refactorActions) {
43+
if (refactorAction.name.startsWith('function_scope')) {
44+
refactorAction.notApplicableReason = 'JSX Element Selected. Use Extract to JSX component'
45+
}
46+
}
47+
refactorActions.push({
4748
description: 'Extract to JSX component',
4849
kind: 'refactor.extract.jsx',
4950
name: `${globalScopeRefactor!.name}_jsx`,
5051
})
5152
return
5253
}
5354

54-
refactor.actions.push(...addArrowCodeActions)
55+
refactorActions.push(...addArrowCodeActions)
5556
}
5657
}
5758

typescript/src/completions/boostNameSuggestions.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,37 @@ export default (
1717
const fileText = sourceFile.getFullText()
1818
const fileTextBeforePos = fileText.slice(0, position)
1919
const beforeConstNodeOffset = fileTextBeforePos.match(/(?:const|let) ([\w\d]*)$/i)?.[1]
20+
const nodeWithStatements = node => {
21+
return node && 'statements' in node && Array.isArray(node.statements) ? node : undefined
22+
}
23+
const statementsNode = nodeWithStatements(node) || nodeWithStatements(node.parent)
24+
// Workaround for current locality bonus & TS 5.1
25+
if (statementsNode) {
26+
const statements = statementsNode.statements as any[]
27+
const prevNode =
28+
statementsNode === node
29+
? [...statements].reverse().find((statement: ts.Node) => statement.pos + statement.getLeadingTriviaWidth() < position)
30+
: statements[statements.indexOf(node) - 1]
31+
if (prevNode && ts.isVariableStatement(prevNode) && prevNode.declarationList.declarations.length === 1) {
32+
const { name } = prevNode.declarationList.declarations[0]!
33+
if (ts.isIdentifier(name)) {
34+
const kind: ts.ScriptElementKind =
35+
prevNode.declarationList.flags & ts.NodeFlags.Const ? ts.ScriptElementKind.constElement : ts.ScriptElementKind.letElement
36+
entries = boostOrAddSuggestions(entries, [
37+
{
38+
name: name.text,
39+
kind,
40+
},
41+
])
42+
}
43+
}
44+
}
2045
/** false - pick all identifiers after cursor
2146
* node - pick identifiers that within node */
2247
let filterBlock: undefined | false | ts.Node
2348
if (beforeConstNodeOffset !== undefined) {
2449
const node = findChildContainingPosition(ts, sourceFile, position - beforeConstNodeOffset.length - 2)
25-
if (!node || !ts.isVariableDeclarationList(node)) return
50+
if (!node || !ts.isVariableDeclarationList(node)) return entries
2651
filterBlock = false
2752
} else if (ts.isIdentifier(node) && node.parent?.parent) {
2853
// node > parent1 > parent2
@@ -44,7 +69,7 @@ export default (
4469
}
4570
}
4671

47-
if (filterBlock === undefined) return
72+
if (filterBlock === undefined) return entries
4873
const semanticDiagnostics = languageService.getSemanticDiagnostics(sourceFile.fileName)
4974

5075
const notFoundIdentifiers = semanticDiagnostics

typescript/src/completionsAtPosition.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import prepareTextForEmmet from './specialCommands/prepareTextForEmmet'
1515
import switchCaseExcludeCovered from './completions/switchCaseExcludeCovered'
1616
import additionalTypesSuggestions from './completions/additionalTypesSuggestions'
1717
import boostKeywordSuggestions from './completions/boostKeywordSuggestions'
18-
import boostTextSuggestions from './completions/boostNameSuggestions'
18+
import boostNameSuggestions from './completions/boostNameSuggestions'
1919
import keywordsSpace from './completions/keywordsSpace'
2020
import jsdocDefault from './completions/jsdocDefault'
2121
import defaultHelpers from './completions/defaultHelpers'
@@ -143,7 +143,7 @@ export const getCompletionsAtPosition = (
143143
}
144144

145145
if (leftNode) {
146-
const newEntries = boostTextSuggestions(prior?.entries ?? [], position, sourceFile, leftNode, languageService)
146+
const newEntries = boostNameSuggestions(prior?.entries ?? [], position, sourceFile, leftNode, languageService)
147147
if (newEntries?.length && ensurePrior() && prior) prior.entries = newEntries
148148
}
149149

typescript/src/definitions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService,
108108
}
109109
}
110110
}
111-
return
111+
return prior
112112
}
113113

114114
if (__WEB__) {

typescript/src/documentHighlights.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,10 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService,
55
proxy.getDocumentHighlights = (fileName, position, filesToSearch) => {
66
const prior = languageService.getDocumentHighlights(fileName, position, filesToSearch)
77
if (!prior) return
8-
if (prior.length !== 1) return prior
8+
if (prior.length !== 1 || c('disableUselessHighlighting') === 'disable') return prior
99
const node = findChildContainingPosition(ts, languageService.getProgram()!.getSourceFile(fileName)!, position)
1010
if (!node) return prior
11-
if (
12-
c('disableUselessHighlighting') !== 'disable' &&
13-
ts.isStringLiteralLike(node) &&
14-
(c('disableUselessHighlighting') === 'inAllStrings' || ts.isJsxAttribute(node.parent))
15-
) {
11+
if (ts.isStringLiteralLike(node) && (c('disableUselessHighlighting') === 'inAllStrings' || ts.isJsxAttribute(node.parent))) {
1612
return
1713
}
1814
return prior

0 commit comments

Comments
 (0)