@ithinkdt/lint 4.0.0-6 → 4.0.0-700

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.
@@ -1,9 +1,14 @@
1
1
  import path from 'node:path'
2
+ import { cwd } from 'node:process'
3
+
2
4
  import ts from 'typescript'
5
+
3
6
  import { transformExtraFile } from './transform.js'
4
7
 
5
8
  export class TSServiceManager {
6
- tsServices = new Map()
9
+ constructor() {
10
+ this.tsServices = new Map()
11
+ }
7
12
 
8
13
  getProgram(code, options) {
9
14
  const tsconfigPath = options.project
@@ -15,8 +20,8 @@ export class TSServiceManager {
15
20
  this.tsServices.set(tsconfigPath, serviceList)
16
21
  }
17
22
 
18
- let service = serviceList.find((service) =>
19
- extraFileExtensions.every((ext) => service.extraFileExtensions.includes(ext)),
23
+ let service = serviceList.find(service =>
24
+ extraFileExtensions.every(ext => service.extraFileExtensions.includes(ext)),
20
25
  )
21
26
  if (!service) {
22
27
  service = new TSService(tsconfigPath, extraFileExtensions)
@@ -28,58 +33,18 @@ export class TSServiceManager {
28
33
  }
29
34
 
30
35
  export class TSService {
31
- watch
32
-
33
- patchedHostSet = new WeakSet()
34
-
35
- tsconfigPath
36
-
37
- extraFileExtensions
38
-
39
- currTarget = {
40
- code: '',
41
- filePath: '',
42
- dirMap: new Map(),
43
- }
44
-
45
- fileWatchCallbacks = new Map()
46
-
47
36
  constructor(tsconfigPath, extraFileExtensions) {
37
+ this.patchedHostSet = new WeakSet()
48
38
  this.tsconfigPath = tsconfigPath
49
39
  this.extraFileExtensions = extraFileExtensions
50
- this.watch = this.createWatch(tsconfigPath, extraFileExtensions)
51
- }
52
-
53
- getProgram(code, filePath) {
54
- const normalized = normalizeFileName(filePath)
55
- const lastTarget = this.currTarget
56
-
57
- const dirMap = new Map()
58
- let childPath = normalized
59
- for (const dirName of iterateDirs(normalized)) {
60
- dirMap.set(dirName, { path: childPath, name: path.basename(childPath) })
61
- childPath = dirName
62
- }
63
40
  this.currTarget = {
64
- code,
65
- filePath: normalized,
66
- dirMap,
41
+ code: '',
42
+ filePath: '',
43
+ sourceFile: undefined,
44
+ dirMap: new Map(),
67
45
  }
68
- for (const { filePath: targetPath } of [this.currTarget, lastTarget]) {
69
- if (!targetPath) continue
70
- if (!ts.sys.fileExists(targetPath)) {
71
- // Signal a directory change to request a re-scan of the directory
72
- // because it targets a file that does not actually exist.
73
- this.fileWatchCallbacks.get(normalizeFileName(this.tsconfigPath))?.update()
74
- }
75
- this.fileWatchCallbacks.get(normalizeFileName(targetPath))?.update()
76
- }
77
-
78
- const program = this.watch.getProgram().getProgram()
79
- // sets parent pointers in source files
80
- program.getTypeChecker()
81
-
82
- return program
46
+ this.fileWatchCallbacks = new Map()
47
+ this.watch = this.createWatch(tsconfigPath, extraFileExtensions)
83
48
  }
84
49
 
85
50
  createWatch(tsconfigPath, extraFileExtensions) {
@@ -92,28 +57,28 @@ export class TSService {
92
57
 
93
58
  const getTargetSourceFile = (fileName, languageVersionOrOptions) => {
94
59
  if (
95
- this.currTarget.filePath === normalizeFileName(fileName) &&
96
- isExtra(fileName, extraFileExtensions)
60
+ this.currTarget.filePath === normalizeFileName(fileName)
61
+ && isExtra(fileName, extraFileExtensions)
97
62
  ) {
98
- // Parse the target file as TSX.
99
- return (this.currTarget.sourceFile ??= ts.createSourceFile(
100
- this.currTarget.filePath,
101
- this.currTarget.code,
102
- languageVersionOrOptions,
103
- true,
104
- ts.ScriptKind.TSX,
105
- ))
63
+ return (
64
+ this.currTarget.sourceFile
65
+ ?? ts.createSourceFile(
66
+ this.currTarget.filePath,
67
+ this.currTarget.code,
68
+ languageVersionOrOptions,
69
+ true,
70
+ ts.ScriptKind.TSX,
71
+ )
72
+ )
106
73
  }
107
- return
74
+ return null
108
75
  }
109
76
 
110
77
  const original = {
111
78
  getSourceFile: host.getSourceFile,
112
79
  getSourceFileByPath: host.getSourceFileByPath,
113
80
  }
114
-
115
81
  host.getSourceFile = (fileName, languageVersionOrOptions, ...args) => {
116
- // Always call the original function, because it calls the file watcher.
117
82
  const originalSourceFile = original.getSourceFile.call(
118
83
  host,
119
84
  fileName,
@@ -123,7 +88,6 @@ export class TSService {
123
88
  return getTargetSourceFile(fileName, languageVersionOrOptions) ?? originalSourceFile
124
89
  }
125
90
  host.getSourceFileByPath = (fileName, path, languageVersionOrOptions, ...args) => {
126
- // Always call the original function, because it calls the file watcher.
127
91
  const originalSourceFile = original.getSourceFileByPath.call(
128
92
  host,
129
93
  fileName,
@@ -149,10 +113,6 @@ export class TSService {
149
113
  {
150
114
  noEmit: true,
151
115
  jsx: ts.JsxEmit.Preserve,
152
-
153
- // This option is required if `includes` only includes `*.vue` files.
154
- // However, the option is not in the documentation.
155
- // https://github.com/microsoft/TypeScript/issues/28447
156
116
  allowNonTsExtensions: true,
157
117
  },
158
118
  ts.sys,
@@ -160,11 +120,9 @@ export class TSService {
160
120
  (diagnostic) => {
161
121
  throw new Error(formatDiagnostics([diagnostic]))
162
122
  },
163
- () => {
164
- // Not reported in reportWatchStatus.
165
- },
123
+ () => {},
166
124
  undefined,
167
- extraFileExtensions.map((extension) => ({
125
+ extraFileExtensions.map(extension => ({
168
126
  extension,
169
127
  isMixedContent: true,
170
128
  scriptKind: ts.ScriptKind.Deferred,
@@ -180,28 +138,25 @@ export class TSService {
180
138
  watchCompilerHost.getDirectories = (dirName, ...args) => {
181
139
  const result = distinctArray(
182
140
  ...original.getDirectories.call(watchCompilerHost, dirName, ...args),
183
- // Include the path to the target file if the target file does not actually exist.
184
141
  this.currTarget.dirMap.get(normalizeFileName(dirName))?.name,
185
142
  )
186
143
  return result
187
144
  }
188
145
  watchCompilerHost.directoryExists = (dirName, ...args) => {
189
146
  return (
190
- original.directoryExists.call(watchCompilerHost, dirName, ...args) ||
191
- // Include the path to the target file if the target file does not actually exist.
192
- this.currTarget.dirMap.has(normalizeFileName(dirName))
147
+ original.directoryExists.call(watchCompilerHost, dirName, ...args)
148
+ || this.currTarget.dirMap.has(normalizeFileName(dirName))
193
149
  )
194
150
  }
195
151
  watchCompilerHost.readDirectory = (dirName, ...args) => {
196
152
  let results = original.readDirectory.call(watchCompilerHost, dirName, ...args)
197
153
 
198
- // Include the target file if the target file does not actually exist.
199
154
  const file = this.currTarget.dirMap.get(normalizeFileName(dirName))
200
155
  if (file) {
201
156
  if (file.path === this.currTarget.filePath) {
202
157
  results.push(file.path)
203
158
  } else {
204
- results = results.filter((f) => file.path !== f && file.name !== f)
159
+ results = results.filter(f => file.path !== f && file.name !== f)
205
160
  }
206
161
  }
207
162
 
@@ -209,11 +164,10 @@ export class TSService {
209
164
  }
210
165
  watchCompilerHost.readFile = (fileName, ...args) => {
211
166
  const realFileName = getRealFileNameIfExist(fileName)
212
- if (realFileName == undefined) {
167
+ if (realFileName == null) {
213
168
  return
214
169
  }
215
170
  if (this.currTarget.filePath === realFileName) {
216
- // It is the file currently being parsed.
217
171
  return transformExtraFile(this.currTarget.code, {
218
172
  filePath: realFileName,
219
173
  current: true,
@@ -229,20 +183,16 @@ export class TSService {
229
183
  current: false,
230
184
  })
231
185
  }
232
- // Modify it so that it can be determined that the virtual file actually exists.
233
186
  watchCompilerHost.fileExists = (fileName) => {
234
- return getRealFileNameIfExist(fileName) != undefined
187
+ return getRealFileNameIfExist(fileName) != null
235
188
  }
236
189
 
237
190
  const getRealFileNameIfExist = (fileName) => {
238
191
  const normalizedFileName = normalizeFileName(fileName)
239
- // Even if it is actually a file, if it is specified as a directory to the target file,
240
- // it is assumed that it does not exist as a file.
241
192
  if (this.currTarget.dirMap.has(normalizedFileName)) {
242
- return
193
+ return null
243
194
  }
244
195
  if (this.currTarget.filePath === normalizedFileName) {
245
- // It is the file currently being parsed.
246
196
  return normalizedFileName
247
197
  }
248
198
  const exists = original.fileExists.call(watchCompilerHost, normalizedFileName)
@@ -253,18 +203,16 @@ export class TSService {
253
203
  const real = normalizedFileName.slice(0, -4)
254
204
  for (const dts of toExtraDtsFileNames(real, extraFileExtensions)) {
255
205
  if (original.fileExists.call(watchCompilerHost, dts)) {
256
- // If the d.ts file exists, respect it and consider the virtual file not to exist.
257
- return
206
+ return null
258
207
  }
259
208
  }
260
209
  if (original.fileExists.call(watchCompilerHost, real)) {
261
210
  return real
262
211
  }
263
212
  }
264
- return
213
+ return null
265
214
  }
266
215
 
267
- // It keeps a callback to mark the parsed file as changed so that it can be re-parsed.
268
216
  watchCompilerHost.watchFile = (fileName, callback) => {
269
217
  const normalized = normalizeFileName(fileName)
270
218
  this.fileWatchCallbacks.set(normalized, {
@@ -277,23 +225,16 @@ export class TSService {
277
225
  },
278
226
  }
279
227
  }
280
- // Use watchCompilerHost but don't actually watch the files and directories.
281
228
  watchCompilerHost.watchDirectory = () => {
282
229
  return {
283
- close: () => {
284
- // noop
285
- },
230
+ close: () => {},
286
231
  }
287
232
  }
288
233
 
289
- /**
290
- * It heavily references typescript-eslint.
291
- * @see https://github.com/typescript-eslint/typescript-eslint/blob/84e316be33dac5302bd0367c4d1960bef40c484d/packages/typescript-estree/src/create-program/createWatchProgram.ts#L297-L309
292
- */
293
234
  watchCompilerHost.afterProgramCreate = (program) => {
294
235
  const originalDiagnostics = program.getConfigFileParsingDiagnostics()
295
236
  const configFileDiagnostics = originalDiagnostics.filter(
296
- (diag) => diag.category === ts.DiagnosticCategory.Error && diag.code !== 18_003,
237
+ diag => diag.category === ts.DiagnosticCategory.Error && diag.code !== 18_003,
297
238
  )
298
239
  if (configFileDiagnostics.length > 0) {
299
240
  throw new Error(formatDiagnostics(configFileDiagnostics))
@@ -303,33 +244,60 @@ export class TSService {
303
244
  const watch = ts.createWatchProgram(watchCompilerHost)
304
245
  return watch
305
246
  }
247
+
248
+ getProgram(code, filePath) {
249
+ const normalized = normalizeFileName(filePath)
250
+ const lastTarget = this.currTarget
251
+
252
+ const dirMap = new Map()
253
+ let childPath = normalized
254
+ for (const dirName of iterateDirs(normalized)) {
255
+ dirMap.set(dirName, { path: childPath, name: path.basename(childPath) })
256
+ childPath = dirName
257
+ }
258
+ this.currTarget = {
259
+ code,
260
+ filePath: normalized,
261
+ dirMap,
262
+ }
263
+ for (const { filePath: targetPath } of [this.currTarget, lastTarget]) {
264
+ if (!targetPath) continue
265
+ if (!ts.sys.fileExists(targetPath)) {
266
+ this.fileWatchCallbacks.get(normalizeFileName(this.tsconfigPath))?.update()
267
+ }
268
+ this.fileWatchCallbacks.get(normalizeFileName(targetPath))?.update()
269
+ }
270
+
271
+ const program = this.watch.getProgram().getProgram()
272
+ program.getTypeChecker()
273
+
274
+ return program
275
+ }
276
+
277
+ watch = null
306
278
  }
307
279
 
308
- /** If the given filename has extra extensions, returns the d.ts filename. */
309
280
  function toExtraDtsFileNames(fileName, extraFileExtensions) {
310
281
  const ext = getExtIfExtra(fileName, extraFileExtensions)
311
- if (ext != undefined) {
282
+ if (ext != null) {
312
283
  return [`${fileName}.d.ts`, `${fileName.slice(0, -ext.length)}.d${ext}.ts`]
313
284
  }
314
285
  return []
315
286
  }
316
287
 
317
- /** Checks the given filename has extra extension or not. */
318
288
  function isExtra(fileName, extraFileExtensions) {
319
- return getExtIfExtra(fileName, extraFileExtensions) != undefined
289
+ return getExtIfExtra(fileName, extraFileExtensions) != null
320
290
  }
321
291
 
322
- /** Gets the file extension if the given file is an extra extension file. */
323
292
  function getExtIfExtra(fileName, extraFileExtensions) {
324
293
  for (const extraFileExtension of extraFileExtensions) {
325
294
  if (fileName.endsWith(extraFileExtension)) {
326
295
  return extraFileExtension
327
296
  }
328
297
  }
329
- return
298
+ return null
330
299
  }
331
300
 
332
- /** Checks the given filename is virtual file tsx or not. */
333
301
  function isVirtualTSX(fileName, extraFileExtensions) {
334
302
  for (const extraFileExtension of extraFileExtensions) {
335
303
  if (fileName.endsWith(`${extraFileExtension}.tsx`)) {
@@ -341,8 +309,8 @@ function isVirtualTSX(fileName, extraFileExtensions) {
341
309
 
342
310
  function formatDiagnostics(diagnostics) {
343
311
  return ts.formatDiagnostics(diagnostics, {
344
- getCanonicalFileName: (f) => f,
345
- getCurrentDirectory: () => process.cwd(),
312
+ getCanonicalFileName: f => f,
313
+ getCurrentDirectory: () => cwd(),
346
314
  getNewLine: () => '\n',
347
315
  })
348
316
  }
@@ -353,13 +321,13 @@ function normalizeFileName(fileName) {
353
321
  normalized = normalized.slice(0, -1)
354
322
  }
355
323
  if (ts.sys.useCaseSensitiveFileNames) {
356
- return toAbsolutePath(normalized)
324
+ return toAbsolutePath(normalized, null)
357
325
  }
358
- return toAbsolutePath(normalized.toLowerCase())
326
+ return toAbsolutePath(normalized.toLowerCase(), null)
359
327
  }
360
328
 
361
329
  function toAbsolutePath(filePath, baseDir) {
362
- return path.isAbsolute(filePath) ? filePath : path.join(baseDir || process.cwd(), filePath)
330
+ return path.isAbsolute(filePath) ? filePath : path.join(baseDir || cwd(), filePath)
363
331
  }
364
332
 
365
333
  function* iterateDirs(filePath) {
@@ -372,7 +340,7 @@ function* iterateDirs(filePath) {
372
340
  }
373
341
 
374
342
  function distinctArray(...list) {
375
- return [...new Set(ts.sys.useCaseSensitiveFileNames ? list : list.map((s) => s?.toLowerCase()))].filter(
376
- (s) => s != undefined,
343
+ return [...new Set(ts.sys.useCaseSensitiveFileNames ? list : list.map(s => s?.toLowerCase()))].filter(
344
+ s => s != null,
377
345
  )
378
346
  }
@@ -1,7 +1,10 @@
1
1
  import path from 'node:path'
2
- import ts from 'typescript'
2
+ import { cwd } from 'node:process'
3
+
3
4
  import { globbySync } from 'globby'
4
5
  import isGlob from 'is-glob'
6
+ import ts from 'typescript'
7
+
5
8
  /**
6
9
  * Normalizes, sanitizes, resolves and filters the provided project paths
7
10
  */
@@ -9,7 +12,7 @@ export function resolveProjectList(options) {
9
12
  const sanitizedProjects = []
10
13
 
11
14
  // Normalize and sanitize the project paths
12
- if (options.project) {
15
+ if (options.project != null) {
13
16
  for (const project of options.project) {
14
17
  if (typeof project === 'string') {
15
18
  sanitizedProjects.push(project)
@@ -22,15 +25,18 @@ export function resolveProjectList(options) {
22
25
  }
23
26
 
24
27
  const projectFolderIgnoreList = []
28
+
25
29
  for (const folder of options.projectFolderIgnoreList ?? ['**/node_modules/**']) {
26
30
  if (typeof folder === 'string') {
27
- projectFolderIgnoreList.push(folder.startsWith('!') ? folder : `!${folder}`)
31
+ projectFolderIgnoreList.push(folder)
28
32
  }
29
33
  }
34
+ // prefix with a ! for not match glob
35
+ projectFolderIgnoreList.map(folder => (folder.startsWith('!') ? folder : `!${folder}`))
30
36
 
31
37
  // Transform glob patterns into paths
32
- const nonGlobProjects = sanitizedProjects.filter((project) => !isGlob(project))
33
- const globProjects = sanitizedProjects.filter((project) => isGlob(project))
38
+ const nonGlobProjects = sanitizedProjects.filter(project => !isGlob(project))
39
+ const globProjects = sanitizedProjects.filter(project => isGlob(project))
34
40
 
35
41
  const uniqueCanonicalProjectPaths = new Set(
36
42
  [
@@ -38,9 +44,9 @@ export function resolveProjectList(options) {
38
44
  ...(globProjects.length === 0
39
45
  ? []
40
46
  : globbySync([...globProjects, ...projectFolderIgnoreList], {
41
- cwd: options.tsconfigRootDir,
42
- })),
43
- ].map((project) => getCanonicalFileName(ensureAbsolutePath(project, options.tsconfigRootDir))),
47
+ cwd: options.tsconfigRootDir,
48
+ })),
49
+ ].map(project => _getCanonicalFileName(_ensureAbsolutePath(project, options.tsconfigRootDir))),
44
50
  )
45
51
 
46
52
  return [...uniqueCanonicalProjectPaths]
@@ -48,9 +54,9 @@ export function resolveProjectList(options) {
48
54
 
49
55
  // typescript doesn't provide a ts.sys implementation for browser environments
50
56
  const useCaseSensitiveFileNames = ts.sys === undefined ? true : ts.sys.useCaseSensitiveFileNames
51
- const correctPathCasing = useCaseSensitiveFileNames ? (filePath) => filePath : (filePath) => filePath.toLowerCase()
57
+ const correctPathCasing = useCaseSensitiveFileNames ? filePath => filePath : filePath => filePath.toLowerCase()
52
58
 
53
- function getCanonicalFileName(filePath) {
59
+ function _getCanonicalFileName(filePath) {
54
60
  let normalized = path.normalize(filePath)
55
61
  if (normalized.endsWith(path.sep)) {
56
62
  normalized = normalized.slice(0, -1)
@@ -58,6 +64,6 @@ function getCanonicalFileName(filePath) {
58
64
  return correctPathCasing(normalized)
59
65
  }
60
66
 
61
- function ensureAbsolutePath(p, tsconfigRootDir) {
62
- return path.isAbsolute(p) ? p : path.join(tsconfigRootDir || process.cwd(), p)
67
+ function _ensureAbsolutePath(p, tsconfigRootDir) {
68
+ return path.isAbsolute(p) ? p : path.join(tsconfigRootDir || cwd(), p)
63
69
  }
@@ -1,54 +0,0 @@
1
- import html from 'prettier/plugins/html'
2
-
3
- let flag = 0
4
- function replaceDoc(doc, attrs, parent, i) {
5
- if (Array.isArray(doc)) {
6
- for (let i = 0; i < doc.length; i++) {
7
- replaceDoc(doc[i], attrs, doc, i)
8
- }
9
- } else if (typeof doc === 'object' && (doc.type === 'group' || doc.type === 'indent')) {
10
- for (let i = 0; i < doc.contents.length; i++) {
11
- replaceDoc(doc.contents[i], attrs, doc.contents, i)
12
- }
13
- } else if (parent && typeof doc === 'string') {
14
- if (flag === 2) {
15
- parent[i] = `(${doc})`
16
- flag = 0
17
- } else if (flag === 0 && attrs.has(doc)) {
18
- flag = 1
19
- } else if (flag === 1 && doc === '="') {
20
- flag = 2
21
- } else {
22
- flag = 0
23
- }
24
- }
25
- }
26
-
27
- export default {
28
- ...html,
29
- printers: {
30
- ...html.printers,
31
- html: {
32
- ...html.printers.html,
33
- print(path, ops, print) {
34
- const res = html.printers.html.print(path, ops, print)
35
- if (path.node.type == 'element') {
36
- const attrs = path.node.attrs.filter((attr) => {
37
- return (
38
- attr.value &&
39
- (attr.name[0] === ':' || (attr.name[0] === 'v' && attr.name[1] === '-')) &&
40
- attr.value[0] === '(' &&
41
- attr.value.at(-1) === ')'
42
- )
43
- })
44
-
45
- if (attrs.length > 0) {
46
- flag = 0
47
- replaceDoc(res, new Set(attrs.map((attr) => attr.name)))
48
- }
49
- }
50
- return res
51
- },
52
- },
53
- },
54
- }
package/src/prettier.d.ts DELETED
@@ -1,4 +0,0 @@
1
- import { Config } from 'prettier'
2
-
3
- declare const config: Config
4
- export default config
package/src/prettier.js DELETED
@@ -1,15 +0,0 @@
1
- import path from 'node:path'
2
- /**
3
- * @type {import('prettier').Config}
4
- */
5
- export const config = {
6
- semi: false,
7
- tabWidth: 4,
8
- printWidth: 120,
9
- singleQuote: true,
10
- endOfLine: 'lf',
11
- vueIndentScriptAndStyle: false,
12
- plugins: [path.resolve(import.meta.dirname, './prettier-fix-vue.js')],
13
- }
14
-
15
- export default config
package/tsconfig.json DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "exclude": ["node_modules", "dist"],
3
- "compilerOptions": {
4
- "baseUrl": ".",
5
- "noImplicitOverride": true,
6
- "target": "ESNext",
7
- "module": "NodeNext",
8
- "moduleResolution": "NodeNext",
9
- "resolveJsonModule": true,
10
- "lib": ["ESNext"],
11
- "esModuleInterop": true,
12
- "strictNullChecks": true
13
- }
14
- }