@tsslint/typescript-plugin 0.0.1 → 0.0.3
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/index.js +77 -40
- package/lib/builtInPlugins.d.ts +1 -1
- package/lib/builtInPlugins.js +23 -43
- package/lib/watchConfig.d.ts +2 -13
- package/lib/watchConfig.js +71 -36
- package/package.json +5 -4
package/index.js
CHANGED
|
@@ -22,7 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
const watchConfig_1 = require("./lib/watchConfig");
|
|
26
25
|
const builtInPlugins_1 = require("./lib/builtInPlugins");
|
|
27
26
|
const path = __importStar(require("path"));
|
|
28
27
|
const languageServiceDecorators = new WeakMap();
|
|
@@ -47,20 +46,20 @@ const init = (modules) => {
|
|
|
47
46
|
function decorateLanguageService(ts, tsconfig, info) {
|
|
48
47
|
const getCompilerOptionsDiagnostics = info.languageService.getCompilerOptionsDiagnostics;
|
|
49
48
|
const getSyntacticDiagnostics = info.languageService.getSyntacticDiagnostics;
|
|
50
|
-
const
|
|
51
|
-
const getEditsForRefactor = info.languageService.getEditsForRefactor;
|
|
52
|
-
let compilerOptionsDiagnostics = [];
|
|
49
|
+
const getCodeFixesAtPosition = info.languageService.getCodeFixesAtPosition;
|
|
53
50
|
let configFile;
|
|
54
51
|
let configFileBuildContext;
|
|
52
|
+
let configFileDiagnostics = [];
|
|
55
53
|
let config;
|
|
56
54
|
let plugins = [];
|
|
57
55
|
info.languageService.getCompilerOptionsDiagnostics = () => {
|
|
58
|
-
return getCompilerOptionsDiagnostics().concat(
|
|
56
|
+
return getCompilerOptionsDiagnostics().concat(configFileDiagnostics);
|
|
59
57
|
};
|
|
60
58
|
info.languageService.getSyntacticDiagnostics = fileName => {
|
|
61
59
|
let errors = getSyntacticDiagnostics(fileName);
|
|
60
|
+
errors = errors.concat(configFileDiagnostics);
|
|
62
61
|
const sourceFile = info.languageService.getProgram()?.getSourceFile(fileName);
|
|
63
|
-
if (!sourceFile) {
|
|
62
|
+
if (!sourceFile || sourceFile.text.length > 20000) {
|
|
64
63
|
return errors;
|
|
65
64
|
}
|
|
66
65
|
const token = info.languageServiceHost.getCancellationToken?.();
|
|
@@ -78,63 +77,87 @@ function decorateLanguageService(ts, tsconfig, info) {
|
|
|
78
77
|
errors = errors.concat(pluginResult);
|
|
79
78
|
}
|
|
80
79
|
}
|
|
80
|
+
if (config?.debug) {
|
|
81
|
+
errors.push({
|
|
82
|
+
category: ts.DiagnosticCategory.Warning,
|
|
83
|
+
source: 'tsslint',
|
|
84
|
+
code: 'debug-info',
|
|
85
|
+
messageText: JSON.stringify({
|
|
86
|
+
rules: Object.keys(config?.rules ?? {}),
|
|
87
|
+
plugins: plugins.length,
|
|
88
|
+
configFile,
|
|
89
|
+
tsconfig,
|
|
90
|
+
}, null, 2),
|
|
91
|
+
file: sourceFile,
|
|
92
|
+
start: 0,
|
|
93
|
+
length: 0,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
81
96
|
return errors;
|
|
82
97
|
};
|
|
83
|
-
info.languageService.
|
|
84
|
-
let
|
|
85
|
-
const sourceFile = info.languageService.getProgram()?.getSourceFile(fileName);
|
|
86
|
-
if (!sourceFile) {
|
|
87
|
-
return refactors;
|
|
88
|
-
}
|
|
98
|
+
info.languageService.getCodeFixesAtPosition = (fileName, start, end, errorCodes, formatOptions, preferences) => {
|
|
99
|
+
let fixes = getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences);
|
|
89
100
|
const token = info.languageServiceHost.getCancellationToken?.();
|
|
90
101
|
for (const plugin of plugins) {
|
|
91
102
|
if (token?.isCancellationRequested()) {
|
|
92
103
|
break;
|
|
93
104
|
}
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
return refactors;
|
|
97
|
-
};
|
|
98
|
-
info.languageService.getEditsForRefactor = (fileName, formatOptions, positionOrRange, refactorName, actionName, ...rest) => {
|
|
99
|
-
const sourceFile = info.languageService.getProgram()?.getSourceFile(fileName);
|
|
100
|
-
if (!sourceFile) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
for (const plugin of plugins) {
|
|
104
|
-
const edits = plugin.fix?.(sourceFile, refactorName, actionName);
|
|
105
|
-
if (edits) {
|
|
106
|
-
return { edits };
|
|
107
|
-
}
|
|
105
|
+
fixes = fixes.concat(plugin.getFixes?.(fileName, start, end, errorCodes) ?? []);
|
|
108
106
|
}
|
|
109
|
-
return
|
|
107
|
+
return fixes;
|
|
110
108
|
};
|
|
111
109
|
return { update };
|
|
112
110
|
async function update(pluginConfig) {
|
|
113
|
-
|
|
114
|
-
const start = jsonConfigFile.text.indexOf(pluginConfig.configFile) - 1;
|
|
115
|
-
const length = pluginConfig.configFile.length + 2;
|
|
111
|
+
let configOptionSpan = { start: 0, length: 0 };
|
|
116
112
|
let newConfigFile;
|
|
113
|
+
let configImportPath;
|
|
117
114
|
let configResolveError;
|
|
115
|
+
const jsonConfigFile = ts.readJsonConfigFile(tsconfig, ts.sys.readFile);
|
|
118
116
|
try {
|
|
119
|
-
|
|
117
|
+
configImportPath = require.resolve('@tsslint/config', { paths: [path.dirname(tsconfig)] });
|
|
120
118
|
}
|
|
121
119
|
catch (err) {
|
|
122
120
|
configResolveError = err;
|
|
121
|
+
configFileDiagnostics = [{
|
|
122
|
+
category: ts.DiagnosticCategory.Error,
|
|
123
|
+
code: 0,
|
|
124
|
+
messageText: String(err),
|
|
125
|
+
file: jsonConfigFile,
|
|
126
|
+
start: 0,
|
|
127
|
+
length: 0,
|
|
128
|
+
}];
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const { findConfigFile, watchConfigFile } = require(configImportPath);
|
|
132
|
+
if (pluginConfig?.configFile) {
|
|
133
|
+
configOptionSpan = {
|
|
134
|
+
start: jsonConfigFile.text.indexOf(pluginConfig.configFile) - 1,
|
|
135
|
+
length: pluginConfig.configFile.length + 2,
|
|
136
|
+
};
|
|
137
|
+
try {
|
|
138
|
+
newConfigFile = require.resolve(pluginConfig.configFile, { paths: [path.dirname(tsconfig)] });
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
configResolveError = err;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
newConfigFile = findConfigFile(tsconfig);
|
|
123
146
|
}
|
|
124
147
|
if (newConfigFile !== configFile) {
|
|
125
148
|
configFile = newConfigFile;
|
|
126
149
|
config = undefined;
|
|
127
150
|
plugins = [];
|
|
128
151
|
configFileBuildContext?.dispose();
|
|
129
|
-
|
|
152
|
+
configFileDiagnostics = [];
|
|
130
153
|
if (configResolveError) {
|
|
131
|
-
|
|
154
|
+
configFileDiagnostics.push({
|
|
132
155
|
category: ts.DiagnosticCategory.Error,
|
|
133
156
|
code: 0,
|
|
134
157
|
messageText: String(configResolveError),
|
|
135
158
|
file: jsonConfigFile,
|
|
136
|
-
start: start,
|
|
137
|
-
length: length,
|
|
159
|
+
start: configOptionSpan.start,
|
|
160
|
+
length: configOptionSpan.length,
|
|
138
161
|
});
|
|
139
162
|
}
|
|
140
163
|
if (!configFile) {
|
|
@@ -147,20 +170,34 @@ function decorateLanguageService(ts, tsconfig, info) {
|
|
|
147
170
|
languageService: info.languageService,
|
|
148
171
|
typescript: ts,
|
|
149
172
|
};
|
|
150
|
-
configFileBuildContext = await (
|
|
173
|
+
configFileBuildContext = await watchConfigFile(configFile, async (_config, { errors, warnings }) => {
|
|
151
174
|
config = _config;
|
|
152
|
-
|
|
175
|
+
configFileDiagnostics = [
|
|
153
176
|
...errors.map(error => [error, ts.DiagnosticCategory.Error]),
|
|
154
177
|
...warnings.map(error => [error, ts.DiagnosticCategory.Warning]),
|
|
155
178
|
].map(([error, category]) => {
|
|
156
179
|
const diag = {
|
|
157
180
|
category,
|
|
181
|
+
source: 'tsslint',
|
|
158
182
|
code: 0,
|
|
159
|
-
messageText:
|
|
183
|
+
messageText: 'Failed to build config',
|
|
160
184
|
file: jsonConfigFile,
|
|
161
|
-
start: start,
|
|
162
|
-
length: length,
|
|
185
|
+
start: configOptionSpan.start,
|
|
186
|
+
length: configOptionSpan.length,
|
|
163
187
|
};
|
|
188
|
+
if (error.location) {
|
|
189
|
+
const fileName = path.resolve(error.location.file);
|
|
190
|
+
const fileText = ts.sys.readFile(error.location.file);
|
|
191
|
+
const sourceFile = ts.createSourceFile(fileName, fileText ?? '', ts.ScriptTarget.Latest, true);
|
|
192
|
+
diag.relatedInformation = [{
|
|
193
|
+
category,
|
|
194
|
+
code: error.id,
|
|
195
|
+
messageText: error.text,
|
|
196
|
+
file: sourceFile,
|
|
197
|
+
start: sourceFile.getPositionOfLineAndCharacter(error.location.line - 1, error.location.column),
|
|
198
|
+
length: error.location.lineText.length,
|
|
199
|
+
}];
|
|
200
|
+
}
|
|
164
201
|
return diag;
|
|
165
202
|
});
|
|
166
203
|
if (config) {
|
package/lib/builtInPlugins.d.ts
CHANGED
package/lib/builtInPlugins.js
CHANGED
|
@@ -31,6 +31,7 @@ exports.builtInPlugins = [
|
|
|
31
31
|
const ts = ctx.typescript;
|
|
32
32
|
const fileFixes = new Map();
|
|
33
33
|
const sourceFiles = new Map();
|
|
34
|
+
const configSourceFile = ts.createSourceFile(ctx.configFile, ts.sys.readFile(ctx.configFile) ?? '', ts.ScriptTarget.Latest, true);
|
|
34
35
|
return {
|
|
35
36
|
lint(sourceFile, rules) {
|
|
36
37
|
const rulesContext = {
|
|
@@ -87,27 +88,21 @@ exports.builtInPlugins = [
|
|
|
87
88
|
}
|
|
88
89
|
const stackFile = sourceFiles.get(fileName);
|
|
89
90
|
const pos = stackFile?.getPositionOfLineAndCharacter(stack.lineNumber - 1, stack.columnNumber - 1);
|
|
90
|
-
let reportNode;
|
|
91
|
-
stackFile.forEachChild(function visit(node) {
|
|
92
|
-
if (node.end < pos || reportNode) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
if (node.pos <= pos) {
|
|
96
|
-
if (node.getStart() === pos) {
|
|
97
|
-
reportNode = node;
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
node.forEachChild(visit);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
91
|
error.relatedInformation?.push({
|
|
105
92
|
category: ts.DiagnosticCategory.Message,
|
|
106
93
|
code: 0,
|
|
107
94
|
file: stackFile,
|
|
108
95
|
start: pos,
|
|
109
|
-
length:
|
|
110
|
-
messageText: '
|
|
96
|
+
length: 0,
|
|
97
|
+
messageText: 'Related rule file',
|
|
98
|
+
});
|
|
99
|
+
error.relatedInformation?.push({
|
|
100
|
+
category: ts.DiagnosticCategory.Message,
|
|
101
|
+
code: 0,
|
|
102
|
+
file: configSourceFile,
|
|
103
|
+
start: 0,
|
|
104
|
+
length: 0,
|
|
105
|
+
messageText: 'Related config file',
|
|
111
106
|
});
|
|
112
107
|
}
|
|
113
108
|
}
|
|
@@ -136,40 +131,25 @@ exports.builtInPlugins = [
|
|
|
136
131
|
};
|
|
137
132
|
}
|
|
138
133
|
},
|
|
139
|
-
getFixes(
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const fixes
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if ((start <= fix.start && end >= fix.end) ||
|
|
134
|
+
getFixes(fileName, start, end) {
|
|
135
|
+
const fixesMap = getFileFixes(fileName);
|
|
136
|
+
const result = [];
|
|
137
|
+
for (const [_errorCode, fixes] of fixesMap) {
|
|
138
|
+
for (let i = 0; i < fixes.length; i++) {
|
|
139
|
+
const fix = fixes[i];
|
|
140
|
+
if ((fix.start >= start && fix.start <= end) ||
|
|
141
|
+
(fix.end >= start && fix.end <= end) ||
|
|
148
142
|
(start >= fix.start && start <= fix.end) ||
|
|
149
143
|
(end >= fix.start && end <= fix.end)) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
name: 'tsslint/fix',
|
|
153
|
-
description: 'Fix ' + errorCode,
|
|
154
|
-
actions: [],
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
refactors[refactors.length - 1].actions.push({
|
|
158
|
-
name: errorCode + '-' + i,
|
|
144
|
+
result.push({
|
|
145
|
+
fixName: `tsslint: ${fix.title}`,
|
|
159
146
|
description: fix.title,
|
|
147
|
+
changes: fix.getEdits(),
|
|
160
148
|
});
|
|
161
149
|
}
|
|
162
150
|
}
|
|
163
151
|
}
|
|
164
|
-
return
|
|
165
|
-
},
|
|
166
|
-
fix(sourceFile, refactorName, actionName) {
|
|
167
|
-
if (refactorName === 'tsslint/fix') {
|
|
168
|
-
const errorCode = actionName.substring(0, actionName.lastIndexOf('-'));
|
|
169
|
-
const fixIndex = actionName.substring(actionName.lastIndexOf('-') + 1);
|
|
170
|
-
const fix = getFileFixes(sourceFile.fileName).get(errorCode)[Number(fixIndex)];
|
|
171
|
-
return fix.getEdits();
|
|
172
|
-
}
|
|
152
|
+
return result;
|
|
173
153
|
},
|
|
174
154
|
};
|
|
175
155
|
function getFileFixes(fileName) {
|
package/lib/watchConfig.d.ts
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
import type { Config } from '@tsslint/config';
|
|
2
|
-
import
|
|
3
|
-
export declare function watchConfig(tsConfigPath: string, onBuild: (config: Config | undefined, result:
|
|
4
|
-
entryPoints: string[];
|
|
5
|
-
bundle: true;
|
|
6
|
-
sourcemap: true;
|
|
7
|
-
outfile: string;
|
|
8
|
-
format: "cjs";
|
|
9
|
-
platform: "node";
|
|
10
|
-
plugins: {
|
|
11
|
-
name: string;
|
|
12
|
-
setup(build: esbuild.PluginBuild): void;
|
|
13
|
-
}[];
|
|
14
|
-
}>>;
|
|
2
|
+
import rollup = require('rollup');
|
|
3
|
+
export declare function watchConfig(tsConfigPath: string, onBuild: (config: Config | undefined, result: Error | undefined) => void): Promise<rollup.RollupBuild>;
|
|
15
4
|
//# sourceMappingURL=watchConfig.d.ts.map
|
package/lib/watchConfig.js
CHANGED
|
@@ -1,53 +1,88 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.watchConfig = void 0;
|
|
4
|
-
const
|
|
4
|
+
const rollup = require("rollup");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
async function watchConfig(tsConfigPath, onBuild) {
|
|
7
|
-
const outDir = path.resolve(
|
|
7
|
+
const outDir = path.resolve(__dirname, '..', '..', '.tsslint');
|
|
8
8
|
const outFileName = btoa(path.relative(outDir, tsConfigPath)) + '.cjs';
|
|
9
9
|
const outFile = path.join(outDir, outFileName);
|
|
10
|
-
const ctx = await esbuild.context({
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
// const ctx = await esbuild.context({
|
|
11
|
+
// entryPoints: [tsConfigPath],
|
|
12
|
+
// bundle: true,
|
|
13
|
+
// sourcemap: true,
|
|
14
|
+
// outfile: outFile,
|
|
15
|
+
// format: 'cjs',
|
|
16
|
+
// platform: 'node',
|
|
17
|
+
// plugins: [{
|
|
18
|
+
// name: 'tsslint',
|
|
19
|
+
// setup(build) {
|
|
20
|
+
// build.onResolve({ filter: /.*/ }, args => {
|
|
21
|
+
// if (!args.path.endsWith('.ts')) {
|
|
22
|
+
// try {
|
|
23
|
+
// const jsPath = require.resolve(args.path, { paths: [args.resolveDir] });
|
|
24
|
+
// return {
|
|
25
|
+
// path: jsPath,
|
|
26
|
+
// external: true,
|
|
27
|
+
// };
|
|
28
|
+
// } catch { }
|
|
29
|
+
// }
|
|
30
|
+
// return {};
|
|
31
|
+
// });
|
|
32
|
+
// build.onEnd(result => {
|
|
33
|
+
// let config: Config | undefined;
|
|
34
|
+
// if (!result.errors.length) {
|
|
35
|
+
// try {
|
|
36
|
+
// config = require(outFile).default;
|
|
37
|
+
// delete require.cache[outFile!];
|
|
38
|
+
// } catch (e) {
|
|
39
|
+
// result.errors.push({ text: String(e) } as any);
|
|
40
|
+
// }
|
|
41
|
+
// }
|
|
42
|
+
// onBuild(config, result);
|
|
43
|
+
// });
|
|
44
|
+
// },
|
|
45
|
+
// }],
|
|
46
|
+
// });
|
|
47
|
+
const bundle = await rollup.rollup({
|
|
48
|
+
input: tsConfigPath,
|
|
49
|
+
output: {
|
|
50
|
+
file: outFile,
|
|
51
|
+
format: 'cjs',
|
|
52
|
+
sourcemap: true,
|
|
53
|
+
},
|
|
54
|
+
watch: {},
|
|
55
|
+
external: ['typescript'],
|
|
17
56
|
plugins: [{
|
|
18
57
|
name: 'tsslint',
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
catch { }
|
|
58
|
+
resolveId(id, importer) {
|
|
59
|
+
if (!id.endsWith('.ts') && importer) {
|
|
60
|
+
try {
|
|
61
|
+
const jsPath = require.resolve(id, { paths: [path.dirname(importer)] });
|
|
62
|
+
return {
|
|
63
|
+
id: jsPath,
|
|
64
|
+
external: true,
|
|
65
|
+
};
|
|
30
66
|
}
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
67
|
+
catch { }
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
buildEnd(error) {
|
|
71
|
+
let config;
|
|
72
|
+
if (!error) {
|
|
73
|
+
try {
|
|
74
|
+
config = require(outFile).default;
|
|
75
|
+
delete require.cache[outFile];
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
error = { message: String(e) };
|
|
43
79
|
}
|
|
44
|
-
|
|
45
|
-
|
|
80
|
+
}
|
|
81
|
+
onBuild(config, error);
|
|
46
82
|
},
|
|
47
83
|
}],
|
|
48
84
|
});
|
|
49
|
-
|
|
50
|
-
return ctx;
|
|
85
|
+
return bundle;
|
|
51
86
|
}
|
|
52
87
|
exports.watchConfig = watchConfig;
|
|
53
88
|
//# sourceMappingURL=watchConfig.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsslint/typescript-plugin",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"**/*.js",
|
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
"directory": "packages/typescript-plugin"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@tsslint/config": "0.0.1",
|
|
16
15
|
"error-stack-parser": "^2.1.4",
|
|
17
|
-
"esbuild": "^0.19.9",
|
|
18
16
|
"source-map-support": "^0.5.19"
|
|
19
17
|
},
|
|
20
|
-
"
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@tsslint/config": "0.0.3"
|
|
20
|
+
},
|
|
21
|
+
"gitHead": "13557d614907865f38ad32fd3582c9f198fb9ffa"
|
|
21
22
|
}
|