@tsslint/cli 1.4.0 → 1.4.1

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 CHANGED
@@ -8,6 +8,7 @@ const worker = require("./lib/worker.js");
8
8
  const glob = require("glob");
9
9
  const fs = require("fs");
10
10
  const os = require("os");
11
+ const languagePlugins = require("./lib/languagePlugins.js");
11
12
  const _reset = '\x1b[0m';
12
13
  const purple = (s) => '\x1b[35m' + s + _reset;
13
14
  const darkGray = (s) => '\x1b[90m' + s + _reset;
@@ -24,39 +25,45 @@ if (process.argv.includes('--threads')) {
24
25
  }
25
26
  threads = Math.min(os.availableParallelism(), Number(threadsArg));
26
27
  }
27
- (async () => {
28
- class Project {
29
- constructor(tsconfigOption) {
30
- this.workers = [];
31
- this.fileNames = [];
32
- this.options = {};
33
- this.currentFileIndex = 0;
34
- this.cache = {};
35
- try {
36
- this.tsconfig = require.resolve(tsconfigOption, { paths: [process.cwd()] });
37
- }
38
- catch {
39
- console.error(lightRed(`No such file: ${tsconfigOption}`));
40
- process.exit(1);
41
- }
42
- this.configFile = ts.findConfigFile(path.dirname(this.tsconfig), ts.sys.fileExists, 'tsslint.config.ts');
43
- if (!this.configFile) {
44
- log(`${purple('[project]')} ${path.relative(process.cwd(), this.tsconfig)} ${darkGray('(No tsslint.config.ts found)')}`);
45
- return;
46
- }
47
- const commonLine = parseCommonLine(this.tsconfig);
48
- this.fileNames = commonLine.fileNames;
49
- this.options = commonLine.options;
50
- if (!this.fileNames.length) {
51
- log(`${purple('[project]')} ${path.relative(process.cwd(), this.tsconfig)} ${darkGray('(No included files)')}`);
52
- return;
53
- }
54
- log(`${purple('[project]')} ${path.relative(process.cwd(), this.tsconfig)} ${darkGray(`(${this.fileNames.length})`)}`);
55
- if (!process.argv.includes('--force')) {
56
- this.cache = cache.loadCache(this.tsconfig, this.configFile, ts.sys.createHash);
57
- }
28
+ class Project {
29
+ constructor(tsconfigOption, languages) {
30
+ this.languages = languages;
31
+ this.workers = [];
32
+ this.fileNames = [];
33
+ this.options = {};
34
+ this.currentFileIndex = 0;
35
+ this.cache = {};
36
+ try {
37
+ this.tsconfig = require.resolve(tsconfigOption, { paths: [process.cwd()] });
58
38
  }
39
+ catch {
40
+ console.error(lightRed(`No such file: ${tsconfigOption}`));
41
+ process.exit(1);
42
+ }
43
+ }
44
+ async init(
45
+ // @ts-expect-error
46
+ clack) {
47
+ this.configFile = ts.findConfigFile(path.dirname(this.tsconfig), ts.sys.fileExists, 'tsslint.config.ts');
48
+ if (!this.configFile) {
49
+ clack.log.error(`${purple('[project]')} ${path.relative(process.cwd(), this.tsconfig)} ${darkGray('(No tsslint.config.ts found)')}`);
50
+ return this;
51
+ }
52
+ const commonLine = await parseCommonLine(this.tsconfig, this.languages);
53
+ this.fileNames = commonLine.fileNames;
54
+ this.options = commonLine.options;
55
+ if (!this.fileNames.length) {
56
+ clack.log.warn(`${purple('[project]')} ${path.relative(process.cwd(), this.tsconfig)} ${darkGray('(No included files)')}`);
57
+ return this;
58
+ }
59
+ clack.log.info(`${purple('[project]')} ${path.relative(process.cwd(), this.tsconfig)} ${darkGray(`(${this.fileNames.length})`)}`);
60
+ if (!process.argv.includes('--force')) {
61
+ this.cache = cache.loadCache(this.tsconfig, this.configFile, ts.sys.createHash);
62
+ }
63
+ return this;
59
64
  }
65
+ }
66
+ (async () => {
60
67
  const builtConfigs = new Map();
61
68
  const clack = await import('@clack/prompts');
62
69
  const processFiles = new Set();
@@ -71,45 +78,164 @@ if (process.argv.includes('--threads')) {
71
78
  let errors = 0;
72
79
  let warnings = 0;
73
80
  let cached = 0;
74
- spinner.start();
75
- if (process.argv.includes('--project')) {
76
- const projectIndex = process.argv.indexOf('--project');
77
- let tsconfig = process.argv[projectIndex + 1];
78
- if (!tsconfig || tsconfig.startsWith('-')) {
79
- console.error(lightRed(`Missing argument for --project.`));
81
+ const tsconfigAndLanguages = new Map();
82
+ if (!process.argv.includes('--project')
83
+ && !process.argv.includes('--projects')
84
+ && !process.argv.includes('--vue-project')
85
+ && !process.argv.includes('--vue-projects')
86
+ && !process.argv.includes('--mdx-project')
87
+ && !process.argv.includes('--mdx-projects')
88
+ && !process.argv.includes('--astro-project')
89
+ && !process.argv.includes('--astro-projects')) {
90
+ const languages = await clack.multiselect({
91
+ required: false,
92
+ message: 'Select frameworks (optional)',
93
+ options: [{
94
+ label: 'Vue',
95
+ value: 'vue',
96
+ }, {
97
+ label: 'MDX',
98
+ value: 'mdx',
99
+ }, {
100
+ label: 'Astro',
101
+ value: 'astro',
102
+ }],
103
+ });
104
+ if (clack.isCancel(languages)) {
80
105
  process.exit(1);
81
106
  }
82
- if (!tsconfig.startsWith('.')) {
83
- tsconfig = `./${tsconfig}`;
107
+ const tsconfigOptions = glob.sync('**/{tsconfig.json,jsconfig.json}');
108
+ let options = await Promise.all(tsconfigOptions.map(async (tsconfigOption) => {
109
+ const tsconfig = require.resolve(tsconfigOption.startsWith('.') ? tsconfigOption : `./${tsconfigOption}`, { paths: [process.cwd()] });
110
+ try {
111
+ const commonLine = await parseCommonLine(tsconfig, languages);
112
+ return {
113
+ label: path.relative(process.cwd(), tsconfig) + ` (${commonLine.fileNames.length})`,
114
+ value: tsconfigOption,
115
+ };
116
+ }
117
+ catch {
118
+ return undefined;
119
+ }
120
+ }));
121
+ options = options.filter(option => !!option);
122
+ if (!options.length) {
123
+ clack.log.error(lightRed('No projects found.'));
124
+ process.exit(1);
84
125
  }
85
- projects.push(new Project(tsconfig));
86
- }
87
- else if (process.argv.includes('--projects')) {
88
- const projectsIndex = process.argv.indexOf('--projects');
89
- let foundArg = false;
90
- for (let i = projectsIndex + 1; i < process.argv.length; i++) {
91
- if (process.argv[i].startsWith('-')) {
92
- break;
126
+ const selectedTsconfigs = await clack.multiselect({
127
+ message: 'Select one or multiple projects',
128
+ // @ts-expect-error
129
+ options,
130
+ });
131
+ if (clack.isCancel(selectedTsconfigs)) {
132
+ process.exit(1);
133
+ }
134
+ let command = 'tsslint';
135
+ if (!languages.length) {
136
+ if (selectedTsconfigs.length === 1) {
137
+ command += ' --project ' + selectedTsconfigs[0];
93
138
  }
94
- foundArg = true;
95
- const searchGlob = process.argv[i];
96
- const tsconfigs = glob.sync(searchGlob);
97
- for (let tsconfig of tsconfigs) {
98
- if (!tsconfig.startsWith('.')) {
99
- tsconfig = `./${tsconfig}`;
139
+ else {
140
+ command += ' --projects ' + selectedTsconfigs.join(' ');
141
+ }
142
+ }
143
+ else {
144
+ for (const language of languages) {
145
+ if (selectedTsconfigs.length === 1) {
146
+ command += ` --${language}-project ` + selectedTsconfigs[0];
147
+ }
148
+ else {
149
+ command += ` --${language}-projects ` + selectedTsconfigs.join(' ');
100
150
  }
101
- projects.push(new Project(tsconfig));
102
151
  }
103
152
  }
104
- if (!foundArg) {
105
- console.error(lightRed(`Missing argument for --projects.`));
106
- process.exit(1);
153
+ clack.log.info(`Running: ${purple(command)}`);
154
+ for (let tsconfig of selectedTsconfigs) {
155
+ if (!tsconfig.startsWith('.')) {
156
+ tsconfig = `./${tsconfig}`;
157
+ }
158
+ tsconfigAndLanguages.set(tsconfig, languages);
107
159
  }
108
160
  }
109
161
  else {
110
- const tsconfig = await askTSConfig();
111
- projects.push(new Project(tsconfig));
162
+ const options = [
163
+ {
164
+ projectFlag: '--project',
165
+ projectsFlag: '--projects',
166
+ language: undefined,
167
+ },
168
+ {
169
+ projectFlag: '--vue-project',
170
+ projectsFlag: '--vue-projects',
171
+ language: 'vue',
172
+ },
173
+ {
174
+ projectFlag: '--mdx-project',
175
+ projectsFlag: '--mdx-projects',
176
+ language: 'mdx',
177
+ },
178
+ {
179
+ projectFlag: '--astro-project',
180
+ projectsFlag: '--astro-projects',
181
+ language: 'astro',
182
+ },
183
+ ];
184
+ for (const { projectFlag, projectsFlag, language } of options) {
185
+ if (process.argv.includes(projectFlag)) {
186
+ const projectIndex = process.argv.indexOf(projectFlag);
187
+ let tsconfig = process.argv[projectIndex + 1];
188
+ if (!tsconfig || tsconfig.startsWith('-')) {
189
+ clack.log.error(lightRed(`Missing argument for ${projectFlag}.`));
190
+ process.exit(1);
191
+ }
192
+ if (!tsconfig.startsWith('.')) {
193
+ tsconfig = `./${tsconfig}`;
194
+ }
195
+ if (!tsconfigAndLanguages.has(tsconfig)) {
196
+ tsconfigAndLanguages.set(tsconfig, []);
197
+ }
198
+ if (language) {
199
+ tsconfigAndLanguages.get(tsconfig).push(language);
200
+ }
201
+ }
202
+ if (process.argv.includes(projectsFlag)) {
203
+ const projectsIndex = process.argv.indexOf(projectsFlag);
204
+ let foundArg = false;
205
+ for (let i = projectsIndex + 1; i < process.argv.length; i++) {
206
+ if (process.argv[i].startsWith('-')) {
207
+ break;
208
+ }
209
+ foundArg = true;
210
+ const searchGlob = process.argv[i];
211
+ const tsconfigs = glob.sync(searchGlob);
212
+ if (!tsconfigs.length) {
213
+ clack.log.error(lightRed(`No projects found for ${projectsFlag} ${searchGlob}.`));
214
+ process.exit(1);
215
+ }
216
+ for (let tsconfig of tsconfigs) {
217
+ if (!tsconfig.startsWith('.')) {
218
+ tsconfig = `./${tsconfig}`;
219
+ }
220
+ if (!tsconfigAndLanguages.has(tsconfig)) {
221
+ tsconfigAndLanguages.set(tsconfig, []);
222
+ }
223
+ if (language) {
224
+ tsconfigAndLanguages.get(tsconfig).push(language);
225
+ }
226
+ }
227
+ }
228
+ if (!foundArg) {
229
+ clack.log.error(lightRed(`Missing argument for ${projectsFlag}.`));
230
+ process.exit(1);
231
+ }
232
+ }
233
+ }
112
234
  }
235
+ for (const [tsconfig, languages] of tsconfigAndLanguages) {
236
+ projects.push(await new Project(tsconfig, languages).init(clack));
237
+ }
238
+ spinner.start();
113
239
  projects = projects.filter(project => !!project.configFile);
114
240
  projects = projects.filter(project => !!project.fileNames.length);
115
241
  for (const project of projects) {
@@ -168,7 +294,7 @@ if (process.argv.includes('--threads')) {
168
294
  })[0];
169
295
  }
170
296
  project.workers.push(linterWorker);
171
- const setupSuccess = await linterWorker.setup(project.tsconfig, project.configFile, project.builtConfig, project.fileNames, project.options);
297
+ const setupSuccess = await linterWorker.setup(project.tsconfig, project.languages, project.configFile, project.builtConfig, project.fileNames, project.options);
172
298
  if (!setupSuccess) {
173
299
  projects = projects.filter(p => p !== project);
174
300
  startWorker(linterWorker);
@@ -207,7 +333,7 @@ if (process.argv.includes('--threads')) {
207
333
  diagnostics = await linterWorker.lint(fileName, fileCache);
208
334
  }
209
335
  if (diagnostics.length) {
210
- hasFix ||= await linterWorker.hasCodeFixes(fileName);
336
+ hasFix ||= Object.values(fileCache[1]).some(fixes => fixes > 0) || await linterWorker.hasCodeFixes(fileName);
211
337
  for (const diagnostic of diagnostics) {
212
338
  if (diagnostic.category === ts.DiagnosticCategory.Suggestion) {
213
339
  continue;
@@ -249,31 +375,6 @@ if (process.argv.includes('--threads')) {
249
375
  }
250
376
  return await builtConfigs.get(configFile);
251
377
  }
252
- async function askTSConfig() {
253
- const presetConfig = ts.findConfigFile(process.cwd(), ts.sys.fileExists);
254
- let shortTsconfig = presetConfig ? path.relative(process.cwd(), presetConfig) : undefined;
255
- if (!shortTsconfig?.startsWith('.')) {
256
- shortTsconfig = `./${shortTsconfig}`;
257
- }
258
- return await clack.text({
259
- message: 'Select the project. (Use --project or --projects to skip this prompt.)',
260
- placeholder: shortTsconfig ? `${shortTsconfig} (${parseCommonLine(presetConfig).fileNames.length} files)` : 'No tsconfig.json/jsconfig.json found, please enter the path to the tsconfig.json/jsconfig.json file.',
261
- defaultValue: shortTsconfig,
262
- validate(value) {
263
- value ||= shortTsconfig;
264
- try {
265
- require.resolve(value, { paths: [process.cwd()] });
266
- }
267
- catch {
268
- return 'No such file.';
269
- }
270
- },
271
- });
272
- }
273
- function parseCommonLine(tsconfig) {
274
- const jsonConfigFile = ts.readJsonConfigFile(tsconfig, ts.sys.readFile);
275
- return ts.parseJsonSourceFileConfigFileContent(jsonConfigFile, ts.sys, path.dirname(tsconfig), {}, tsconfig);
276
- }
277
378
  function addProcessFile(fileName) {
278
379
  processFiles.add(fileName);
279
380
  updateSpinner();
@@ -297,4 +398,10 @@ if (process.argv.includes('--threads')) {
297
398
  spinner.start();
298
399
  }
299
400
  })();
401
+ async function parseCommonLine(tsconfig, languages) {
402
+ const jsonConfigFile = ts.readJsonConfigFile(tsconfig, ts.sys.readFile);
403
+ const plugins = await languagePlugins.load(tsconfig, languages);
404
+ const extraFileExtensions = plugins.flatMap(plugin => plugin.typescript?.extraFileExtensions ?? []).flat();
405
+ return ts.parseJsonSourceFileConfigFileContent(jsonConfigFile, ts.sys, path.dirname(tsconfig), {}, tsconfig, undefined, extraFileExtensions);
406
+ }
300
407
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,2 @@
1
+ import { LanguagePlugin } from '@volar/language-core';
2
+ export declare function load(tsconfig: string, languages: string[]): Promise<LanguagePlugin<string, import("@volar/language-core").VirtualCode>[]>;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.load = load;
4
+ const path = require("path");
5
+ const ts = require("typescript");
6
+ const cache = new Map();
7
+ async function load(tsconfig, languages) {
8
+ if (cache.has(tsconfig)) {
9
+ return cache.get(tsconfig);
10
+ }
11
+ const plugins = [];
12
+ if (languages.includes('vue')) {
13
+ let vue;
14
+ let vueTscPkgPath;
15
+ if (findPackageJson('@vue/language-core')) {
16
+ vue = require('@vue/language-core');
17
+ }
18
+ else if (vueTscPkgPath = findPackageJson('vue-tsc')) {
19
+ const vueTscPath = path.dirname(vueTscPkgPath);
20
+ vue = require(require.resolve('@vue/language-core', { paths: [vueTscPath] }));
21
+ }
22
+ else {
23
+ const pkg = ts.findConfigFile(path.dirname(tsconfig), ts.sys.fileExists, 'package.json');
24
+ if (pkg) {
25
+ throw new Error('Please install @vue/language-core or vue-tsc to ' + path.relative(process.cwd(), pkg));
26
+ }
27
+ else {
28
+ throw new Error('Please install @vue/language-core or vue-tsc for ' + path.relative(process.cwd(), tsconfig));
29
+ }
30
+ }
31
+ const commonLine = vue.createParsedCommandLine(ts, ts.sys, tsconfig);
32
+ const vueLanguagePlugin = vue.createVueLanguagePlugin(ts, commonLine.options, commonLine.vueOptions, fileName => fileName);
33
+ plugins.push(vueLanguagePlugin);
34
+ }
35
+ if (languages.includes('mdx')) {
36
+ let mdx;
37
+ try {
38
+ mdx = await import(require.resolve('@mdx-js/language-service', { paths: [path.dirname(tsconfig)] }));
39
+ }
40
+ catch {
41
+ const pkg = ts.findConfigFile(path.dirname(tsconfig), ts.sys.fileExists, 'package.json');
42
+ if (pkg) {
43
+ throw new Error('Please install @mdx-js/language-service to ' + path.relative(process.cwd(), pkg));
44
+ }
45
+ else {
46
+ throw new Error('Please install @mdx-js/language-service for ' + path.relative(process.cwd(), tsconfig));
47
+ }
48
+ }
49
+ const mdxLanguagePlugin = mdx.createMdxLanguagePlugin();
50
+ plugins.push(mdxLanguagePlugin);
51
+ }
52
+ if (languages.includes('astro')) {
53
+ let astro;
54
+ try {
55
+ astro = require(require.resolve('@astrojs/ts-plugin/dist/language.js', { paths: [path.dirname(tsconfig)] }));
56
+ }
57
+ catch (err) {
58
+ const pkg = ts.findConfigFile(path.dirname(tsconfig), ts.sys.fileExists, 'package.json');
59
+ if (pkg) {
60
+ throw new Error('Please install @astrojs/ts-plugin to ' + path.relative(process.cwd(), pkg));
61
+ }
62
+ else {
63
+ throw new Error('Please install @astrojs/ts-plugin for ' + path.relative(process.cwd(), tsconfig));
64
+ }
65
+ }
66
+ const astroLanguagePlugin = astro.getLanguagePlugin();
67
+ plugins.push(astroLanguagePlugin);
68
+ }
69
+ cache.set(tsconfig, plugins);
70
+ return plugins;
71
+ function findPackageJson(pkgName) {
72
+ try {
73
+ return require.resolve(`${pkgName}/package.json`, { paths: [path.dirname(tsconfig)] });
74
+ }
75
+ catch { }
76
+ }
77
+ }
78
+ //# sourceMappingURL=languagePlugins.js.map
package/lib/worker.d.ts CHANGED
@@ -1,20 +1,20 @@
1
1
  import ts = require('typescript');
2
2
  import core = require('@tsslint/core');
3
3
  export declare function createLocal(): {
4
- setup(tsconfig: string, configFile: string, builtConfig: string, _fileNames: string[], _options: ts.CompilerOptions): Promise<boolean>;
4
+ setup(tsconfig: string, languages: string[], configFile: string, builtConfig: string, _fileNames: string[], _options: ts.CompilerOptions): Promise<boolean>;
5
5
  lint(fileName: string, fileCache: core.FileLintCache): ts.DiagnosticWithLocation[];
6
6
  lintAndFix(fileName: string, fileCache: core.FileLintCache): ts.DiagnosticWithLocation[];
7
7
  hasCodeFixes(fileName: string): boolean;
8
- hasRules(fileName: string, minimatchCache: Record<string, boolean>): Promise<boolean>;
8
+ hasRules(fileName: string, minimatchCache: Record<string, boolean>): boolean;
9
9
  };
10
10
  export declare function create(): {
11
- setup(tsconfig: string, configFile: string, builtConfig: string, _fileNames: string[], _options: ts.CompilerOptions): Promise<boolean>;
11
+ setup(tsconfig: string, languages: string[], configFile: string, builtConfig: string, _fileNames: string[], _options: ts.CompilerOptions): Promise<boolean>;
12
12
  lint(fileName: string, fileCache: core.FileLintCache): Promise<ts.DiagnosticWithLocation[]>;
13
13
  lintAndFix(fileName: string, fileCache: core.FileLintCache): Promise<ts.DiagnosticWithLocation[]>;
14
14
  hasCodeFixes(fileName: string): Promise<boolean>;
15
15
  hasRules(fileName: string, minimatchCache: Record<string, boolean>): Promise<boolean>;
16
16
  };
17
- declare function setup(tsconfig: string, configFile: string, builtConfig: string, _fileNames: string[], _options: ts.CompilerOptions): Promise<boolean>;
17
+ declare function setup(tsconfig: string, languages: string[], configFile: string, builtConfig: string, _fileNames: string[], _options: ts.CompilerOptions): Promise<boolean>;
18
18
  declare function lintAndFix(fileName: string, fileCache: core.FileLintCache): readonly [ts.DiagnosticWithLocation[], core.FileLintCache];
19
19
  declare function lint(fileName: string, fileCache: core.FileLintCache): readonly [ts.DiagnosticWithLocation[], core.FileLintCache];
20
20
  declare function hasCodeFixes(fileName: string): boolean;
package/lib/worker.js CHANGED
@@ -7,14 +7,20 @@ const core = require("@tsslint/core");
7
7
  const url = require("url");
8
8
  const fs = require("fs");
9
9
  const worker_threads = require("worker_threads");
10
+ const languagePlugins = require("./languagePlugins.js");
11
+ const language_core_1 = require("@volar/language-core");
12
+ const typescript_1 = require("@volar/typescript");
13
+ const transform_1 = require("@volar/typescript/lib/node/transform");
10
14
  let projectVersion = 0;
11
15
  let typeRootsVersion = 0;
12
16
  let options = {};
13
17
  let fileNames = [];
18
+ let language;
14
19
  let linter;
20
+ let linterLanguageService;
15
21
  const snapshots = new Map();
16
22
  const versions = new Map();
17
- const languageServiceHost = {
23
+ const originalHost = {
18
24
  ...ts.sys,
19
25
  useCaseSensitiveFileNames() {
20
26
  return ts.sys.useCaseSensitiveFileNames;
@@ -44,7 +50,8 @@ const languageServiceHost = {
44
50
  return ts.getDefaultLibFilePath(options);
45
51
  },
46
52
  };
47
- const languageService = ts.createLanguageService(languageServiceHost);
53
+ const linterHost = { ...originalHost };
54
+ const originalService = ts.createLanguageService(linterHost);
48
55
  function createLocal() {
49
56
  return {
50
57
  setup(...args) {
@@ -59,7 +66,7 @@ function createLocal() {
59
66
  hasCodeFixes(...args) {
60
67
  return hasCodeFixes(...args);
61
68
  },
62
- async hasRules(...args) {
69
+ hasRules(...args) {
63
70
  return hasRules(...args)[0];
64
71
  },
65
72
  };
@@ -110,7 +117,7 @@ const handlers = {
110
117
  hasCodeFixes,
111
118
  hasRules,
112
119
  };
113
- async function setup(tsconfig, configFile, builtConfig, _fileNames, _options) {
120
+ async function setup(tsconfig, languages, configFile, builtConfig, _fileNames, _options) {
114
121
  const clack = await import('@clack/prompts');
115
122
  let config;
116
123
  try {
@@ -125,21 +132,50 @@ async function setup(tsconfig, configFile, builtConfig, _fileNames, _options) {
125
132
  }
126
133
  return false;
127
134
  }
135
+ for (let key in linterHost) {
136
+ if (!(key in originalHost)) {
137
+ // @ts-ignore
138
+ delete linterHost[key];
139
+ }
140
+ else {
141
+ // @ts-ignore
142
+ linterHost[key] = originalHost[key];
143
+ }
144
+ }
145
+ linterLanguageService = originalService;
146
+ language = undefined;
147
+ const plugins = await languagePlugins.load(tsconfig, languages);
148
+ if (plugins.length) {
149
+ const { getScriptSnapshot } = originalHost;
150
+ language = (0, language_core_1.createLanguage)([
151
+ ...plugins,
152
+ { getLanguageId: fileName => (0, typescript_1.resolveFileLanguageId)(fileName) },
153
+ ], new language_core_1.FileMap(ts.sys.useCaseSensitiveFileNames), fileName => {
154
+ const snapshot = getScriptSnapshot(fileName);
155
+ if (snapshot) {
156
+ language.scripts.set(fileName, snapshot);
157
+ }
158
+ });
159
+ (0, typescript_1.decorateLanguageServiceHost)(ts, language, linterHost);
160
+ const proxy = (0, typescript_1.createProxyLanguageService)(linterLanguageService);
161
+ proxy.initialize(language);
162
+ linterLanguageService = proxy.proxy;
163
+ }
128
164
  projectVersion++;
129
165
  typeRootsVersion++;
130
166
  fileNames = _fileNames;
131
167
  options = _options;
132
168
  linter = core.createLinter({
133
169
  configFile,
134
- languageService,
135
- languageServiceHost,
170
+ languageService: linterLanguageService,
171
+ languageServiceHost: linterHost,
136
172
  typescript: ts,
137
173
  tsconfig: ts.server.toNormalizedPath(tsconfig),
138
174
  }, config, 'cli', clack);
139
175
  return true;
140
176
  }
141
177
  function lintAndFix(fileName, fileCache) {
142
- let retry = 3;
178
+ let retry = 1;
143
179
  let shouldRetry = true;
144
180
  let newSnapshot;
145
181
  let diagnostics;
@@ -151,9 +187,15 @@ function lintAndFix(fileName, fileCache) {
151
187
  fileCache[3].length = 0;
152
188
  }
153
189
  diagnostics = linter.lint(fileName, fileCache);
154
- const fixes = linter
190
+ let fixes = linter
155
191
  .getCodeFixes(fileName, 0, Number.MAX_VALUE, diagnostics, fileCache[4])
156
192
  .filter(fix => fix.fixId === 'tsslint');
193
+ if (language) {
194
+ fixes = fixes.map(fix => {
195
+ fix.changes = (0, transform_1.transformFileTextChanges)(language, fix.changes, false, language_core_1.isCodeActionsEnabled);
196
+ return fix;
197
+ });
198
+ }
157
199
  const textChanges = core.combineCodeFixes(fileName, fixes);
158
200
  if (textChanges.length) {
159
201
  const oldSnapshot = snapshots.get(fileName);
@@ -174,8 +216,27 @@ function lintAndFix(fileName, fileCache) {
174
216
  if (shouldRetry) {
175
217
  diagnostics = linter.lint(fileName, fileCache);
176
218
  }
177
- return [
178
- diagnostics.map(diagnostic => ({
219
+ if (language) {
220
+ diagnostics = diagnostics
221
+ .map(d => (0, transform_1.transformDiagnostic)(language, d, originalService.getCurrentProgram(), false))
222
+ .filter(d => !!d);
223
+ diagnostics = diagnostics.map(diagnostic => ({
224
+ ...diagnostic,
225
+ file: {
226
+ fileName: diagnostic.file.fileName,
227
+ text: getFileText(diagnostic.file.fileName),
228
+ },
229
+ relatedInformation: diagnostic.relatedInformation?.map(info => ({
230
+ ...info,
231
+ file: info.file ? {
232
+ fileName: info.file.fileName,
233
+ text: getFileText(info.file.fileName),
234
+ } : undefined,
235
+ })),
236
+ }));
237
+ }
238
+ else {
239
+ diagnostics = diagnostics.map(diagnostic => ({
179
240
  ...diagnostic,
180
241
  file: {
181
242
  fileName: diagnostic.file.fileName,
@@ -188,13 +249,33 @@ function lintAndFix(fileName, fileCache) {
188
249
  text: info.file.text,
189
250
  } : undefined,
190
251
  })),
191
- })),
192
- fileCache,
193
- ];
252
+ }));
253
+ }
254
+ return [diagnostics, fileCache];
194
255
  }
195
256
  function lint(fileName, fileCache) {
196
- return [
197
- linter.lint(fileName, fileCache).map(diagnostic => ({
257
+ let diagnostics = linter.lint(fileName, fileCache);
258
+ if (language) {
259
+ diagnostics = diagnostics
260
+ .map(d => (0, transform_1.transformDiagnostic)(language, d, originalService.getCurrentProgram(), false))
261
+ .filter(d => !!d);
262
+ diagnostics = diagnostics.map(diagnostic => ({
263
+ ...diagnostic,
264
+ file: {
265
+ fileName: diagnostic.file.fileName,
266
+ text: getFileText(diagnostic.file.fileName),
267
+ },
268
+ relatedInformation: diagnostic.relatedInformation?.map(info => ({
269
+ ...info,
270
+ file: info.file ? {
271
+ fileName: info.file.fileName,
272
+ text: getFileText(info.file.fileName),
273
+ } : undefined,
274
+ })),
275
+ }));
276
+ }
277
+ else {
278
+ diagnostics = diagnostics.map(diagnostic => ({
198
279
  ...diagnostic,
199
280
  file: {
200
281
  fileName: diagnostic.file.fileName,
@@ -207,9 +288,12 @@ function lint(fileName, fileCache) {
207
288
  text: info.file.text,
208
289
  } : undefined,
209
290
  })),
210
- })),
211
- fileCache,
212
- ];
291
+ }));
292
+ }
293
+ return [diagnostics, fileCache];
294
+ }
295
+ function getFileText(fileName) {
296
+ return originalHost.getScriptSnapshot(fileName).getText(0, Number.MAX_VALUE);
213
297
  }
214
298
  function hasCodeFixes(fileName) {
215
299
  return linter.hasCodeFixes(fileName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsslint/cli",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "tsslint": "./bin/tsslint.js"
@@ -16,12 +16,17 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@clack/prompts": "^0.8.2",
19
- "@tsslint/config": "1.4.0",
20
- "@tsslint/core": "1.4.0",
19
+ "@tsslint/config": "1.4.1",
20
+ "@tsslint/core": "1.4.1",
21
+ "@volar/language-core": "~2.4.0",
22
+ "@volar/typescript": "~2.4.0",
21
23
  "glob": "^10.4.1"
22
24
  },
23
25
  "peerDependencies": {
24
26
  "typescript": "*"
25
27
  },
26
- "gitHead": "9a3f7ce55f079eaaedfb61af9b72d8ba736f0123"
28
+ "devDependencies": {
29
+ "@vue/language-core": "latest"
30
+ },
31
+ "gitHead": "54f42ec9414029a356fa19a762260f03392563fa"
27
32
  }