@tsslint/typescript-plugin 0.0.0

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.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import type * as ts from 'typescript/lib/tsserverlibrary.js';
2
+ declare const init: ts.server.PluginModuleFactory;
3
+ export = init;
4
+ //# sourceMappingURL=index.d.ts.map
package/index.js ADDED
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ const watchConfig_1 = require("./lib/watchConfig");
26
+ const builtInPlugins_1 = require("./lib/builtInPlugins");
27
+ const path = __importStar(require("path"));
28
+ const init = (modules) => {
29
+ const { typescript: ts } = modules;
30
+ const pluginModule = {
31
+ create(info) {
32
+ const tsconfig = info.project.projectKind === ts.server.ProjectKind.Configured
33
+ ? info.project.getProjectName()
34
+ : undefined;
35
+ if (!tsconfig) {
36
+ return info.languageService;
37
+ }
38
+ if (!info.config.configFile) {
39
+ return info.languageService;
40
+ }
41
+ let configFile;
42
+ try {
43
+ configFile = path.resolve(tsconfig, '..', info.config.configFile);
44
+ }
45
+ catch (err) {
46
+ // TODO: show error in tsconfig.json
47
+ }
48
+ if (!configFile) {
49
+ return info.languageService;
50
+ }
51
+ let config;
52
+ let plugins = [];
53
+ const languageServiceHost = info.languageServiceHost;
54
+ const languageService = info.languageService;
55
+ const projectContext = {
56
+ configFile,
57
+ tsconfig,
58
+ languageServiceHost,
59
+ languageService,
60
+ typescript: ts,
61
+ };
62
+ decorateLanguageService();
63
+ (0, watchConfig_1.watchConfig)(configFile, async (_config, result) => {
64
+ config = _config;
65
+ if (config) {
66
+ plugins = await Promise.all([
67
+ ...builtInPlugins_1.builtInPlugins,
68
+ ...config.plugins ?? []
69
+ ].map(plugin => plugin(projectContext, result)));
70
+ for (const plugin of plugins) {
71
+ if (plugin.resolveRules) {
72
+ config.rules = plugin.resolveRules(config.rules ?? {});
73
+ }
74
+ }
75
+ }
76
+ info.project.refreshDiagnostics();
77
+ });
78
+ return languageService;
79
+ function decorateLanguageService() {
80
+ const getSyntacticDiagnostics = languageService.getSyntacticDiagnostics;
81
+ const getApplicableRefactors = languageService.getApplicableRefactors;
82
+ const getEditsForRefactor = languageService.getEditsForRefactor;
83
+ languageService.getSyntacticDiagnostics = fileName => {
84
+ let errors = getSyntacticDiagnostics(fileName);
85
+ const sourceFile = languageService.getProgram()?.getSourceFile(fileName);
86
+ if (!sourceFile) {
87
+ return errors;
88
+ }
89
+ const token = languageServiceHost.getCancellationToken?.();
90
+ for (const plugin of plugins) {
91
+ if (token?.isCancellationRequested()) {
92
+ break;
93
+ }
94
+ if (plugin.lint) {
95
+ let pluginResult = plugin.lint?.(sourceFile, config?.rules ?? {});
96
+ for (const plugin of plugins) {
97
+ if (plugin.resolveResult) {
98
+ pluginResult = plugin.resolveResult(pluginResult);
99
+ }
100
+ }
101
+ errors = errors.concat(pluginResult);
102
+ }
103
+ }
104
+ return errors;
105
+ };
106
+ languageService.getApplicableRefactors = (fileName, positionOrRange, ...rest) => {
107
+ let refactors = getApplicableRefactors(fileName, positionOrRange, ...rest);
108
+ const sourceFile = languageService.getProgram()?.getSourceFile(fileName);
109
+ if (!sourceFile) {
110
+ return refactors;
111
+ }
112
+ const token = languageServiceHost.getCancellationToken?.();
113
+ for (const plugin of plugins) {
114
+ if (token?.isCancellationRequested()) {
115
+ break;
116
+ }
117
+ refactors = refactors.concat(plugin.getFixes?.(sourceFile, positionOrRange) ?? []);
118
+ }
119
+ return refactors;
120
+ };
121
+ languageService.getEditsForRefactor = (fileName, formatOptions, positionOrRange, refactorName, actionName, ...rest) => {
122
+ const sourceFile = languageService.getProgram()?.getSourceFile(fileName);
123
+ if (!sourceFile) {
124
+ return;
125
+ }
126
+ for (const plugin of plugins) {
127
+ const edits = plugin.fix?.(sourceFile, refactorName, actionName);
128
+ if (edits) {
129
+ return { edits };
130
+ }
131
+ }
132
+ return getEditsForRefactor(fileName, formatOptions, positionOrRange, refactorName, actionName, ...rest);
133
+ };
134
+ }
135
+ },
136
+ };
137
+ return pluginModule;
138
+ };
139
+ module.exports = init;
140
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,3 @@
1
+ import { Plugin } from '@tsslint/config';
2
+ export declare const builtInPlugins: Plugin[];
3
+ //# sourceMappingURL=builtInPlugins.d.ts.map
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.builtInPlugins = void 0;
27
+ const ErrorStackParser = __importStar(require("error-stack-parser"));
28
+ exports.builtInPlugins = [
29
+ (ctx, { warnings, errors }) => {
30
+ const ts = ctx.typescript;
31
+ return {
32
+ lint(sourceFile) {
33
+ if (sourceFile.fileName !== ctx.configFile) {
34
+ return [];
35
+ }
36
+ return [
37
+ ...errors.map(error => [error, ts.DiagnosticCategory.Error]),
38
+ ...warnings.map(error => [error, ts.DiagnosticCategory.Warning]),
39
+ ].map(([error, category]) => {
40
+ const diag = {
41
+ category,
42
+ source: 'tsslint-esbuild',
43
+ code: error.id,
44
+ messageText: JSON.stringify(error, null, 2),
45
+ file: sourceFile,
46
+ start: 0,
47
+ length: 0,
48
+ };
49
+ // TODO: parse error.notes for relatedInformation
50
+ return diag;
51
+ });
52
+ },
53
+ };
54
+ },
55
+ ctx => {
56
+ const ts = ctx.typescript;
57
+ const fileFixes = new Map();
58
+ const sourceFiles = new Map();
59
+ return {
60
+ lint(sourceFile, rules) {
61
+ const rulesContext = {
62
+ ...ctx,
63
+ sourceFile,
64
+ reportError,
65
+ reportWarning,
66
+ reportSuggestion,
67
+ };
68
+ const token = ctx.languageServiceHost.getCancellationToken?.();
69
+ const result = [];
70
+ const fixes = getFileFixes(sourceFile.fileName);
71
+ fixes.clear();
72
+ let currentRuleId;
73
+ for (const [id, rule] of Object.entries(rules)) {
74
+ if (token?.isCancellationRequested()) {
75
+ break;
76
+ }
77
+ currentRuleId = id;
78
+ rule(rulesContext);
79
+ }
80
+ return result;
81
+ function reportError(message, start, end) {
82
+ return report(ts.DiagnosticCategory.Error, message, start, end);
83
+ }
84
+ function reportWarning(message, start, end) {
85
+ return report(ts.DiagnosticCategory.Warning, message, start, end);
86
+ }
87
+ function reportSuggestion(message, start, end) {
88
+ return report(ts.DiagnosticCategory.Suggestion, message, start, end);
89
+ }
90
+ function report(category, message, start, end) {
91
+ const error = {
92
+ category,
93
+ code: currentRuleId,
94
+ messageText: message,
95
+ file: sourceFile,
96
+ start,
97
+ length: end - start,
98
+ source: 'tsslint',
99
+ relatedInformation: [],
100
+ };
101
+ const stacks = ErrorStackParser.parse(new Error());
102
+ if (stacks.length >= 3) {
103
+ const stack = stacks[2];
104
+ if (stack.fileName && stack.lineNumber !== undefined && stack.columnNumber !== undefined) {
105
+ let fileName = stack.fileName.replace(/\\/g, '/');
106
+ if (fileName.startsWith('file://')) {
107
+ fileName = fileName.substring('file://'.length);
108
+ }
109
+ if (!sourceFiles.has(fileName)) {
110
+ sourceFiles.set(fileName, ts.createSourceFile(fileName, ctx.languageServiceHost.readFile(fileName), ts.ScriptTarget.Latest, true));
111
+ }
112
+ const stackFile = sourceFiles.get(fileName);
113
+ const pos = stackFile?.getPositionOfLineAndCharacter(stack.lineNumber - 1, stack.columnNumber - 1);
114
+ let reportNode;
115
+ stackFile.forEachChild(function visit(node) {
116
+ if (node.end < pos || reportNode) {
117
+ return;
118
+ }
119
+ if (node.pos <= pos) {
120
+ if (node.getStart() === pos) {
121
+ reportNode = node;
122
+ }
123
+ else {
124
+ node.forEachChild(visit);
125
+ }
126
+ }
127
+ });
128
+ error.relatedInformation?.push({
129
+ category: ts.DiagnosticCategory.Message,
130
+ code: 0,
131
+ file: stackFile,
132
+ start: pos,
133
+ length: reportNode?.end ? reportNode.end - pos : 0,
134
+ messageText: '👈 Reporter',
135
+ });
136
+ }
137
+ }
138
+ result.push(error);
139
+ return {
140
+ withDeprecated() {
141
+ error.reportsDeprecated = true;
142
+ return this;
143
+ },
144
+ withUnnecessary() {
145
+ error.reportsUnnecessary = true;
146
+ return this;
147
+ },
148
+ withFix(title, getEdits) {
149
+ if (!fixes.has(currentRuleId)) {
150
+ fixes.set(currentRuleId, []);
151
+ }
152
+ fixes.get(currentRuleId).push(({
153
+ title,
154
+ start,
155
+ end,
156
+ getEdits,
157
+ }));
158
+ return this;
159
+ },
160
+ };
161
+ }
162
+ },
163
+ getFixes(sourceFile, positionOrRange) {
164
+ const start = typeof positionOrRange === 'number' ? positionOrRange : positionOrRange.pos;
165
+ const end = typeof positionOrRange === 'number' ? positionOrRange : positionOrRange.end;
166
+ const fixes = getFileFixes(sourceFile.fileName);
167
+ const refactors = [];
168
+ for (const [errorCode, _fixes] of fixes) {
169
+ for (let i = 0; i < _fixes.length; i++) {
170
+ const fix = _fixes[i];
171
+ if ((start <= fix.start && end >= fix.end) ||
172
+ (start >= fix.start && start <= fix.end) ||
173
+ (end >= fix.start && end <= fix.end)) {
174
+ if (refactors[refactors.length - 1]?.name !== 'tsslint/fix') {
175
+ refactors.push({
176
+ name: 'tsslint/fix',
177
+ description: 'Fix ' + errorCode,
178
+ actions: [],
179
+ });
180
+ }
181
+ refactors[refactors.length - 1].actions.push({
182
+ name: errorCode + '-' + i,
183
+ description: fix.title,
184
+ });
185
+ }
186
+ }
187
+ }
188
+ return refactors;
189
+ },
190
+ fix(sourceFile, refactorName, actionName) {
191
+ if (refactorName === 'tsslint/fix') {
192
+ const errorCode = actionName.substring(0, actionName.lastIndexOf('-'));
193
+ const fixIndex = actionName.substring(actionName.lastIndexOf('-') + 1);
194
+ const fix = getFileFixes(sourceFile.fileName).get(errorCode)[Number(fixIndex)];
195
+ return fix.getEdits();
196
+ }
197
+ },
198
+ };
199
+ function getFileFixes(fileName) {
200
+ if (!fileFixes.has(fileName)) {
201
+ fileFixes.set(fileName, new Map());
202
+ }
203
+ return fileFixes.get(fileName);
204
+ }
205
+ },
206
+ ];
207
+ //# sourceMappingURL=builtInPlugins.js.map
@@ -0,0 +1,14 @@
1
+ import type { Config } from '@tsslint/config';
2
+ import esbuild = require('esbuild');
3
+ export declare function watchConfig(tsConfigPath: string, onBuild: (config: Config | undefined, result: esbuild.BuildResult) => void): Promise<esbuild.BuildContext<{
4
+ entryPoints: string[];
5
+ bundle: true;
6
+ outfile: string;
7
+ format: "cjs";
8
+ platform: "node";
9
+ plugins: {
10
+ name: string;
11
+ setup(build: esbuild.PluginBuild): void;
12
+ }[];
13
+ }>>;
14
+ //# sourceMappingURL=watchConfig.d.ts.map
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.watchConfig = void 0;
4
+ const esbuild = require("esbuild");
5
+ const path = require("path");
6
+ async function watchConfig(tsConfigPath, onBuild) {
7
+ const outDir = path.resolve(path.dirname(require.resolve('@tsslint/typescript-plugin/package.json')), '..', '.tsslint');
8
+ const outFileName = path
9
+ .relative(outDir, tsConfigPath)
10
+ .replace(/\.\./g, '__up')
11
+ .replace(/\//g, '__slash')
12
+ + '.cjs';
13
+ const outFile = path.join(outDir, outFileName);
14
+ const ctx = await esbuild.context({
15
+ entryPoints: [tsConfigPath],
16
+ bundle: true,
17
+ outfile: outFile,
18
+ format: 'cjs',
19
+ platform: 'node',
20
+ plugins: [{
21
+ name: 'tsslint',
22
+ setup(build) {
23
+ build.onResolve({ filter: /.*/ }, args => {
24
+ if (!args.path.endsWith('.ts')) {
25
+ try {
26
+ const jsPath = require.resolve(args.path, { paths: [args.resolveDir] });
27
+ return {
28
+ path: jsPath,
29
+ external: true,
30
+ };
31
+ }
32
+ catch { }
33
+ }
34
+ return {};
35
+ });
36
+ build.onEnd(result => {
37
+ let config;
38
+ if (!result.errors.length) {
39
+ try {
40
+ config = require(outFile).default;
41
+ delete require.cache[outFile];
42
+ }
43
+ catch (e) {
44
+ result.errors.push({ text: String(e) });
45
+ }
46
+ }
47
+ onBuild(config, result);
48
+ });
49
+ },
50
+ }],
51
+ });
52
+ await ctx.watch();
53
+ return ctx;
54
+ }
55
+ exports.watchConfig = watchConfig;
56
+ //# sourceMappingURL=watchConfig.js.map
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@tsslint/typescript-plugin",
3
+ "version": "0.0.0",
4
+ "license": "MIT",
5
+ "files": [
6
+ "**/*.js",
7
+ "**/*.d.ts"
8
+ ],
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/johnsoncodehk/tsslint.git",
12
+ "directory": "packages/typescript-plugin"
13
+ },
14
+ "dependencies": {
15
+ "@tsslint/config": "0.0.0",
16
+ "error-stack-parser": "^2.1.4",
17
+ "esbuild": "^0.19.9"
18
+ }
19
+ }