Skip to content

Commit f927cdf

Browse files
committed
master- | Adds syntactic error
1 parent 5ee93ef commit f927cdf

15 files changed

+164
-296
lines changed

README.md

-46
This file was deleted.

input.ldjson

-6
This file was deleted.

package.json

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
{
22
"name": "scoped-typescript-plugin",
3-
"version": "1.1.1",
4-
"description": "TypeScript Scoped plugin",
5-
"main": "dist/src/index.js",
3+
"version": "1.0.12",
4+
"main": "dist/index.js",
5+
"files": ["dist"],
6+
"private": true,
67
"scripts": {
7-
"build": "tsc",
8-
"test": "TSS_LOG='-file tsserver.log -level verbose' node node_modules/typescript/bin/tsserver < input.ldjson"
8+
"build": "tsc"
99
},
10+
"author": "Sebastián Gurin",
1011
"license": "MIT",
1112
"devDependencies": {
12-
"vscode-languageserver-types": "^3.16.0",
13-
"typescript": "^4.2.3",
14-
"prettier": "^2.2.1"
13+
"typescript": "^4.2.3"
1514
}
1615
}

src/configuration.ts

-53
This file was deleted.

src/index.ts

+152-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,153 @@
1-
import * as ts from 'typescript/lib/tsserverlibrary';
2-
import { Plugin } from './plugin';
1+
import * as ts_module from 'typescript/lib/tsserverlibrary';
32

4-
export = (mod: { typescript: typeof ts }) => new Plugin(mod.typescript);
3+
function init(modules: { typescript: typeof ts_module }) {
4+
const ts = modules.typescript;
5+
6+
function create(info: ts_module.server.PluginCreateInfo) {
7+
8+
// Get a list of things to remove from the completion list from the config object.
9+
// If nothing was specified, we'll just remove 'caller'
10+
const whatToRemove: string[] = info.config.remove || ['caller'];
11+
12+
// Diagnostic logging. Use something like `export TSS_LOG="-logToFile true -file `pwd`/tsserver.log -level verbose" to log to a file
13+
info.project.projectService.logger.info('I\'m getting set up now! Check the log for this message.');
14+
15+
// Set up decorator
16+
const proxy: ts.LanguageService = Object.create(null);
17+
for (let k of Object.keys(info.languageService) as Array<keyof ts.LanguageService>) {
18+
const x = info.languageService[k];
19+
// @ts-ignore
20+
proxy[k] = (...args: Array<{}>) => x!.apply(info.languageService, args);
21+
}
22+
23+
// We will be overriding the methods we need from this proxy object, in our case getCompletionsAtPosition, getApplicableRefactors and getEditsForRefactor
24+
25+
// Here starts our first behavior: remove some words from the autocompletion list. The words are defined in the user's tsconfig.json file, for example:
26+
// ```ts
27+
// "plugins": [{
28+
// "name": "sample-ts-plugin1",
29+
// "remove": ["caller", "callee", "getDay"]
30+
// }]
31+
// ```
32+
proxy.getCompletionsAtPosition = (fileName, position) => {
33+
const prior = info.languageService.getCompletionsAtPosition(fileName, position, undefined);
34+
const oldLength = prior.entries.length;
35+
prior.entries = prior.entries.filter(e => whatToRemove.indexOf(e.name) < 0);
36+
37+
// Sample logging for diagnostic purposes
38+
if (oldLength !== prior.entries.length) {
39+
info.project.projectService.logger.info(`dupa - Removed ${oldLength - prior.entries.length} entries from the completion list`);
40+
}
41+
// return the prior completions without the ones that matched words that user configured in its tsconfig.json
42+
return prior;
43+
};
44+
45+
proxy.getSyntacticDiagnostics = (fileName) => {
46+
info.project.projectService.logger.info('dupa ' + JSON.stringify(fileName));
47+
const file = info.languageService.getProgram().getSourceFile(fileName);
48+
49+
return [{
50+
messageText: 'dupasz...',
51+
start: 0,
52+
length: 10,
53+
file,
54+
category: ts_module.DiagnosticCategory.Error,
55+
code: 999,
56+
},
57+
];
58+
};
59+
60+
61+
// Here starts our second behavior: a refactor that will always be suggested no matter where is the cursor and does nothing
62+
// overriding getApplicableRefactors we add our refactor metadata only if the user has the cursor on the place we desire, in our case a class or interface declaration identifier
63+
proxy.getApplicableRefactors = (fileName, positionOrRange): ts_module.ApplicableRefactorInfo[] => {
64+
const refactors = info.languageService.getApplicableRefactors(fileName, positionOrRange, undefined) || [];
65+
const sourceFile = info.languageService.getProgram().getSourceFile(fileName);
66+
if (!sourceFile) {
67+
return refactors;
68+
}
69+
// Here we define the refactor metadata, the most important part is its actions name, 'useless-rename' which weill be used later when we define the "refactor edit" for implementing that action
70+
const refactorInfo: ts_module.ApplicableRefactorInfo = {
71+
name: 'useless-rename-info',
72+
description: 'useless rename desc',
73+
actions: [{ name: 'useless-rename', description: 'Useless Rename' }],
74+
};
75+
const nodeAtCursor = findChildContainingPosition(sourceFile, positionOrRangeToNumber(positionOrRange));
76+
if (nodeAtCursor &&
77+
nodeAtCursor.kind === ts.SyntaxKind.Identifier &&
78+
nodeAtCursor.parent &&
79+
// this refactor will appear when user has cursor over a class or interface declaration name
80+
[ts.SyntaxKind.InterfaceDeclaration, ts.SyntaxKind.ClassDeclaration].includes(nodeAtCursor.parent.kind)
81+
) {
82+
// if so, we add our refactor definition to the current refactor list and return it
83+
refactors.push(refactorInfo);
84+
}
85+
return refactors;
86+
};
87+
88+
proxy.getEditsForRefactor = (fileName, formatOptions, positionOrRange, refactorName, actionName, preferences) => {
89+
const refactors = info.languageService.getEditsForRefactor(fileName, formatOptions, positionOrRange, refactorName, actionName, preferences);
90+
// did the user select our refactor suggestion ?
91+
if (actionName !== 'useless-rename') {
92+
// in case we can't find what we want we return this array, but we could return also undefined or empty array
93+
return refactors;
94+
}
95+
const sourceFile = info.languageService.getProgram().getSourceFile(fileName);
96+
if (!sourceFile) {
97+
return refactors;
98+
}
99+
const nodeAtCursor = findChildContainingPosition(sourceFile, positionOrRangeToNumber(positionOrRange));
100+
if ((nodeAtCursor !== undefined && nodeAtCursor.kind === ts.SyntaxKind.Identifier)) {
101+
// we prefix the word Beautiful to te current identifier name
102+
const renameTo = 'Beautiful' + (nodeAtCursor as ts.Identifier).escapedText;
103+
const range = positionOrRangeToRange(positionOrRange);
104+
return {
105+
edits: [{
106+
fileName,
107+
// Notice how the change is represented as an action object (not a function but a command)
108+
textChanges: [{
109+
span: { start: range.pos, length: range.end - range.pos }, // the segment of code that will be replaced
110+
newText: renameTo,
111+
}],
112+
}],
113+
renameFilename: undefined,
114+
renameLocation: undefined,
115+
};
116+
} else {
117+
return refactors;
118+
}
119+
};
120+
return proxy;
121+
}
122+
123+
// Helper functions used in this tutorial
124+
125+
/**normalize the parameter so we are sure is of type Range */
126+
function positionOrRangeToRange(positionOrRange: number | ts_module.TextRange): ts_module.TextRange {
127+
return typeof positionOrRange === 'number'
128+
? { pos: positionOrRange, end: positionOrRange }
129+
: positionOrRange;
130+
}
131+
132+
/**normalize the parameter so we are sure is of type number */
133+
function positionOrRangeToNumber(positionOrRange: number | ts_module.TextRange): number {
134+
return typeof positionOrRange === 'number' ?
135+
positionOrRange :
136+
(positionOrRange as ts_module.TextRange).pos;
137+
}
138+
139+
/** from given position we find the child node that contains it */
140+
function findChildContainingPosition(sourceFile: ts.SourceFile, position: number): ts.Node | undefined {
141+
function find(node: ts.Node): ts.Node | undefined {
142+
if (position >= node.getStart() && position < node.getEnd()) {
143+
return ts.forEachChild(node, find) || node;
144+
}
145+
}
146+
147+
return find(sourceFile);
148+
}
149+
150+
return { create };
151+
}
152+
153+
export = init

src/logger.ts

-9
This file was deleted.

src/plugin.ts

-73
This file was deleted.

test-project/.DS_Store

-6 KB
Binary file not shown.

test-project/package.json

-7
This file was deleted.

test-project/src/index.ts

-7
This file was deleted.

0 commit comments

Comments
 (0)