@nitra/cursor 1.8.145 → 1.8.147
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/bin/n-cursor.js +1 -0
- package/bin/rename-yaml-extensions.mjs +0 -1
- package/mdc/js-lint.mdc +6 -4
- package/mdc/k8s.mdc +2 -2
- package/mdc/vue.mdc +3 -3
- package/package.json +3 -3
- package/scripts/auto-rules.mjs +46 -29
- package/scripts/check-ga.mjs +27 -15
- package/scripts/check-js-bun-db.mjs +3 -3
- package/scripts/check-js-lint.mjs +110 -27
- package/scripts/check-js-mssql.mjs +155 -96
- package/scripts/check-k8s.mjs +161 -32
- package/scripts/check-nginx-default-tpl.mjs +1 -1
- package/scripts/check-vue.mjs +82 -45
- package/scripts/cli-entry.mjs +2 -5
- package/scripts/upgrade-nitra-cursor-and-install.mjs +1 -1
- package/scripts/utils/bun-sql-scan.mjs +1 -1
- package/scripts/utils/mssql-pool-scan.mjs +65 -52
- package/scripts/utils/oxlint-canonical-skeleton.json +27 -0
- package/scripts/utils/oxlint-canonical.json +387 -0
- package/scripts/utils/oxlint-rules.tsv +359 -0
- package/scripts/utils/rebuild-oxlint-canonical.mjs +29 -0
package/scripts/check-vue.mjs
CHANGED
|
@@ -69,6 +69,42 @@ function isEsbuildScanFile(relPosix) {
|
|
|
69
69
|
)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Збирає `esbuild`-матчі по рядках одного файлу, поки буфер не досягне ліміту.
|
|
74
|
+
* @param {string} rel relative path
|
|
75
|
+
* @param {string} content вміст файлу
|
|
76
|
+
* @param {{ rel: string; line: number; snippet: string }[]} matches буфер для збору матчів
|
|
77
|
+
* @param {number} maxMatches максимум елементів у буфері
|
|
78
|
+
*/
|
|
79
|
+
function appendEsbuildLineMatches(rel, content, matches, maxMatches) {
|
|
80
|
+
const lines = content.split('\n')
|
|
81
|
+
for (const [i, line] of lines.entries()) {
|
|
82
|
+
if (matches.length >= maxMatches) return
|
|
83
|
+
if (ESBUILD_RE.test(line)) {
|
|
84
|
+
matches.push({ rel, line: i + 1, snippet: line.trim() })
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Перебирає вибрані файли пакета і збирає до `maxMatches` згадок `esbuild`.
|
|
91
|
+
* @param {string} absPackageRoot абсолютний шлях до кореня пакета
|
|
92
|
+
* @param {{ rel: string }[]} files перелік відносних шляхів
|
|
93
|
+
* @param {number} maxMatches максимум знайдених матчів
|
|
94
|
+
* @returns {Promise<{ rel: string; line: number; snippet: string }[]>} зібрані матчі
|
|
95
|
+
*/
|
|
96
|
+
async function collectEsbuildMatchesInFiles(absPackageRoot, files, maxMatches) {
|
|
97
|
+
/** @type {{ rel: string; line: number; snippet: string }[]} */
|
|
98
|
+
const matches = []
|
|
99
|
+
for (const { rel } of files) {
|
|
100
|
+
if (matches.length >= maxMatches) break
|
|
101
|
+
const content = await readFile(join(absPackageRoot, rel), 'utf8')
|
|
102
|
+
if (!ESBUILD_RE.test(content)) continue
|
|
103
|
+
appendEsbuildLineMatches(rel, content, matches, maxMatches)
|
|
104
|
+
}
|
|
105
|
+
return matches
|
|
106
|
+
}
|
|
107
|
+
|
|
72
108
|
/**
|
|
73
109
|
* Сканує дерево пакета на згадки `esbuild` і підказує заміну на `rolldown`.
|
|
74
110
|
* @param {string} rootDir відносний шлях до пакета
|
|
@@ -78,31 +114,16 @@ function isEsbuildScanFile(relPosix) {
|
|
|
78
114
|
* @param {(msg: string) => void} fail callback при помилці
|
|
79
115
|
*/
|
|
80
116
|
async function checkEsbuildMentions(rootDir, absPackageRoot, prefix, passFn, fail) {
|
|
81
|
-
/** @type {{ rel: string
|
|
82
|
-
const
|
|
83
|
-
|
|
117
|
+
/** @type {{ rel: string }[]} */
|
|
118
|
+
const candidates = []
|
|
84
119
|
await walkDir(absPackageRoot, absPath => {
|
|
85
120
|
const rel = relative(absPackageRoot, absPath).split('\\').join('/')
|
|
86
121
|
if (!isEsbuildScanFile(rel)) return
|
|
87
|
-
|
|
122
|
+
candidates.push({ rel })
|
|
88
123
|
})
|
|
89
124
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const matches = []
|
|
93
|
-
for (const { rel } of hits) {
|
|
94
|
-
const content = await readFile(join(absPackageRoot, rel), 'utf8')
|
|
95
|
-
if (!ESBUILD_RE.test(content)) continue
|
|
96
|
-
|
|
97
|
-
const lines = content.split('\n')
|
|
98
|
-
for (let i = 0; i < lines.length; i++) {
|
|
99
|
-
if (ESBUILD_RE.test(lines[i])) {
|
|
100
|
-
matches.push({ rel, line: i + 1, snippet: lines[i].trim() })
|
|
101
|
-
if (matches.length >= 30) break
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (matches.length >= 30) break
|
|
105
|
-
}
|
|
125
|
+
const maxMatches = 30
|
|
126
|
+
const matches = await collectEsbuildMatchesInFiles(absPackageRoot, candidates, maxMatches)
|
|
106
127
|
|
|
107
128
|
if (matches.length === 0) {
|
|
108
129
|
passFn(`${prefix}немає згадок 'esbuild' у джерелах пакета (очікується rolldown)`)
|
|
@@ -112,8 +133,8 @@ async function checkEsbuildMentions(rootDir, absPackageRoot, prefix, passFn, fai
|
|
|
112
133
|
for (const m of matches) {
|
|
113
134
|
fail(`${prefix}${m.rel}:${m.line} — знайдено 'esbuild'. Замінити на 'rolldown'. Фрагмент: ${m.snippet}`)
|
|
114
135
|
}
|
|
115
|
-
if (matches.length >=
|
|
116
|
-
fail(`${prefix}показано перші
|
|
136
|
+
if (matches.length >= maxMatches) {
|
|
137
|
+
fail(`${prefix}показано перші ${maxMatches} збігів 'esbuild' (замінити на 'rolldown')`)
|
|
117
138
|
}
|
|
118
139
|
}
|
|
119
140
|
|
|
@@ -308,44 +329,60 @@ async function checkVuePackage(rootDir, fail, passFn) {
|
|
|
308
329
|
}
|
|
309
330
|
|
|
310
331
|
/**
|
|
311
|
-
*
|
|
312
|
-
* @
|
|
332
|
+
* Збирає корені пакетів, у яких у `dependencies` є `vue`.
|
|
333
|
+
* @param {string[]} roots усі корені пакетів monorepo
|
|
334
|
+
* @returns {Promise<string[]>} перелік пакетів з vue у dependencies
|
|
313
335
|
*/
|
|
314
|
-
|
|
315
|
-
const reporter = createCheckReporter()
|
|
316
|
-
const { pass, fail } = reporter
|
|
317
|
-
|
|
318
|
-
const roots = await getMonorepoPackageRootDirs()
|
|
336
|
+
async function collectVueRoots(roots) {
|
|
319
337
|
/** @type {string[]} */
|
|
320
338
|
const vueRoots = []
|
|
321
339
|
for (const r of roots) {
|
|
322
340
|
const p = join(r, 'package.json')
|
|
323
|
-
if (existsSync(p))
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
341
|
+
if (!existsSync(p)) continue
|
|
342
|
+
const pkg = JSON.parse(await readFile(p, 'utf8'))
|
|
343
|
+
if (pkg.dependencies?.vue) vueRoots.push(r)
|
|
327
344
|
}
|
|
345
|
+
return vueRoots
|
|
346
|
+
}
|
|
328
347
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
348
|
+
/**
|
|
349
|
+
* Перевіряє наявність рекомендації `Vue.volar` у `.vscode/extensions.json`.
|
|
350
|
+
* @param {(msg: string) => void} pass pass callback
|
|
351
|
+
* @param {(msg: string) => void} fail fail callback
|
|
352
|
+
* @returns {Promise<void>}
|
|
353
|
+
*/
|
|
354
|
+
async function checkVueVolarRecommendation(pass, fail) {
|
|
355
|
+
if (!existsSync('.vscode/extensions.json')) {
|
|
356
|
+
fail('.vscode/extensions.json не існує (для Vue-проєкту потрібна рекомендація Vue.volar)')
|
|
357
|
+
return
|
|
358
|
+
}
|
|
359
|
+
const ext = JSON.parse(await readFile('.vscode/extensions.json', 'utf8'))
|
|
360
|
+
if (ext.recommendations?.includes('Vue.volar')) {
|
|
361
|
+
pass('extensions.json містить Vue.volar')
|
|
340
362
|
} else {
|
|
341
|
-
|
|
363
|
+
fail('extensions.json не містить Vue.volar — додай до recommendations')
|
|
342
364
|
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Перевіряє відповідність проєкту правилам vue.mdc (корінь і всі workspace-пакети з `vue` у dependencies).
|
|
369
|
+
* @returns {Promise<number>} 0 — все OK, 1 — є проблеми
|
|
370
|
+
*/
|
|
371
|
+
export async function check() {
|
|
372
|
+
const reporter = createCheckReporter()
|
|
373
|
+
const { pass, fail } = reporter
|
|
374
|
+
|
|
375
|
+
const roots = await getMonorepoPackageRootDirs()
|
|
376
|
+
const vueRoots = await collectVueRoots(roots)
|
|
343
377
|
|
|
344
378
|
if (vueRoots.length === 0) {
|
|
379
|
+
pass('Vue.volar: пропущено (у repo немає пакетів з vue у dependencies)')
|
|
345
380
|
pass('vue не знайдено в dependencies жодного пакета (перевірка vue пропущена)')
|
|
346
381
|
return reporter.getExitCode()
|
|
347
382
|
}
|
|
348
383
|
|
|
384
|
+
await checkVueVolarRecommendation(pass, fail)
|
|
385
|
+
|
|
349
386
|
for (const r of vueRoots) {
|
|
350
387
|
await checkVuePackage(r, fail, pass)
|
|
351
388
|
}
|
package/scripts/cli-entry.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Визначення, чи виконується поточний ESM-модуль як точка входу CLI, а не як import у тестах чи інших модулях.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Порівняння `import.meta.url` з `process.argv[1]` після `resolve`, щоб `bun path/to/script.mjs`
|
|
5
|
+
* і `node path/to/script.mjs` коректно вважалися прямим запуском.
|
|
6
6
|
*/
|
|
7
7
|
import { resolve } from 'node:path'
|
|
8
8
|
import { fileURLToPath } from 'node:url'
|
|
@@ -12,9 +12,6 @@ import { fileURLToPath } from 'node:url'
|
|
|
12
12
|
* @returns {boolean} `true`, якщо файл запущено напряму; інакше `false`.
|
|
13
13
|
*/
|
|
14
14
|
export function isRunAsCli() {
|
|
15
|
-
if (import.meta.main === true) {
|
|
16
|
-
return true
|
|
17
|
-
}
|
|
18
15
|
try {
|
|
19
16
|
const entry = process.argv[1]
|
|
20
17
|
if (!entry) {
|
|
@@ -108,7 +108,7 @@ async function runBunInstall(projectRoot) {
|
|
|
108
108
|
} catch (error) {
|
|
109
109
|
const exitCode = typeof error?.code === 'number' ? error.code : null
|
|
110
110
|
if (exitCode !== null && exitCode !== 0) {
|
|
111
|
-
throw new Error(`bun i завершився з кодом ${exitCode}
|
|
111
|
+
throw new Error(`bun i завершився з кодом ${exitCode}`, { cause: error })
|
|
112
112
|
}
|
|
113
113
|
throw error
|
|
114
114
|
}
|
|
@@ -278,7 +278,7 @@ export function findUnsafeBunSqlDynamicSqlListInText(content, virtualPath = 'sca
|
|
|
278
278
|
* Скан по сирому тексту — без AST, щоб бути дешевим: викликається на кожному
|
|
279
279
|
* JS/TS-файлі при зборі ознак для авто-детекту правил.
|
|
280
280
|
* @param {string} content вміст файлу
|
|
281
|
-
* @returns {boolean}
|
|
281
|
+
* @returns {boolean} true, якщо є імпорт sql або SQL з модуля bun
|
|
282
282
|
*/
|
|
283
283
|
export function textHasBunSqlImport(content) {
|
|
284
284
|
return BUN_SQL_IMPORT_RE.test(content)
|
|
@@ -307,7 +307,6 @@ export function findSharedMssqlRequestInText(content, virtualPath = 'scan.ts') {
|
|
|
307
307
|
*
|
|
308
308
|
* Цей патерн небезпечний навіть якщо зовні використовується tagged template, бо в запит
|
|
309
309
|
* потрапляє “готовий шматок SQL”, а не параметризовані значення.
|
|
310
|
-
*
|
|
311
310
|
* @param {string} content вихідний код
|
|
312
311
|
* @param {string} [virtualPath] шлях для вибору `lang`
|
|
313
312
|
* @returns {{ line: number, snippet: string }[]} список порушень
|
|
@@ -371,6 +370,24 @@ function isLiteralNumericArrayExpression(node) {
|
|
|
371
370
|
})
|
|
372
371
|
}
|
|
373
372
|
|
|
373
|
+
/**
|
|
374
|
+
* Чи це безпосередній виклик числового парсера (parseInt/parseFloat/Number/BigInt)
|
|
375
|
+
* або обʼєктний доступ до них (наприклад `Number.parseInt(...)`).
|
|
376
|
+
* @param {Record<string, unknown>} node AST CallExpression
|
|
377
|
+
* @returns {boolean} true, якщо callee — числовий парсер
|
|
378
|
+
*/
|
|
379
|
+
function isNumericParseCallExpression(node) {
|
|
380
|
+
if (node.type !== 'CallExpression') return false
|
|
381
|
+
const callee = node.callee
|
|
382
|
+
if (!callee) return false
|
|
383
|
+
if (callee.type === 'Identifier' && NUMERIC_PARSE_FN_NAMES.has(callee.name)) return true
|
|
384
|
+
if (callee.type === 'MemberExpression' && !callee.computed) {
|
|
385
|
+
const prop = callee.property
|
|
386
|
+
return !!prop && prop.type === 'Identifier' && NUMERIC_PARSE_FN_NAMES.has(prop.name)
|
|
387
|
+
}
|
|
388
|
+
return false
|
|
389
|
+
}
|
|
390
|
+
|
|
374
391
|
/**
|
|
375
392
|
* Чи містить піддерево виклик числового парсера (parseInt/parseFloat/Number/BigInt)
|
|
376
393
|
* або унарний `+` (приведення до Number). Це сигнал, що значення гарантовано числове
|
|
@@ -380,20 +397,9 @@ function isLiteralNumericArrayExpression(node) {
|
|
|
380
397
|
*/
|
|
381
398
|
function subtreeHasNumericParseCall(node) {
|
|
382
399
|
if (!node || typeof node !== 'object') return false
|
|
383
|
-
if (Array.isArray(node)) return node.some(subtreeHasNumericParseCall)
|
|
400
|
+
if (Array.isArray(node)) return node.some(item => subtreeHasNumericParseCall(item))
|
|
384
401
|
|
|
385
|
-
if (node
|
|
386
|
-
const callee = node.callee
|
|
387
|
-
if (callee && callee.type === 'Identifier' && NUMERIC_PARSE_FN_NAMES.has(callee.name)) {
|
|
388
|
-
return true
|
|
389
|
-
}
|
|
390
|
-
if (callee && callee.type === 'MemberExpression' && !callee.computed) {
|
|
391
|
-
const prop = callee.property
|
|
392
|
-
if (prop && prop.type === 'Identifier' && NUMERIC_PARSE_FN_NAMES.has(prop.name)) {
|
|
393
|
-
return true
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
402
|
+
if (isNumericParseCallExpression(node)) return true
|
|
397
403
|
if (node.type === 'UnaryExpression' && node.operator === '+') return true
|
|
398
404
|
|
|
399
405
|
for (const key of Object.keys(node)) {
|
|
@@ -426,7 +432,6 @@ function collectVariableDeclarators(programNode) {
|
|
|
426
432
|
*
|
|
427
433
|
* Якщо для Identifier немає видимого init (наприклад параметр функції чи import),
|
|
428
434
|
* вираз вважається не парсованим — потрібен явний парсер на місці підстановки.
|
|
429
|
-
*
|
|
430
435
|
* @param {unknown} expr вираз з template.expressions
|
|
431
436
|
* @param {Array<Record<string, unknown>>} declarators VariableDeclarator-и файлу
|
|
432
437
|
* @param {Set<string>} [seen] іменa Identifier-ів, що вже трасуються (анти-цикл)
|
|
@@ -461,19 +466,52 @@ function isInListExpressionParsed(expr, declarators, seen = new Set()) {
|
|
|
461
466
|
}
|
|
462
467
|
|
|
463
468
|
/**
|
|
464
|
-
*
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
469
|
+
* Сирий текст quasi-елемента TemplateLiteral на позиції перед expressions[i].
|
|
470
|
+
* @param {unknown} q quasi-елемент TemplateLiteral
|
|
471
|
+
* @returns {string} `q.value.raw` або порожній рядок, якщо структура не підходить
|
|
472
|
+
*/
|
|
473
|
+
function quasiRawText(q) {
|
|
474
|
+
return q && typeof q === 'object' && q.value && typeof q.value === 'object' && typeof q.value.raw === 'string'
|
|
475
|
+
? q.value.raw
|
|
476
|
+
: ''
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Збирає порушення для одного TemplateLiteral вузла: знаходить expressions, що
|
|
481
|
+
* стоять одразу після `IN (` без числового парсера значень.
|
|
482
|
+
* @param {Record<string, unknown>} node TemplateLiteral
|
|
483
|
+
* @param {string} content вихідний код
|
|
484
|
+
* @param {Array<Record<string, unknown>>} declarators VariableDeclarator-и для трасування
|
|
485
|
+
* @param {{ line: number, snippet: string }[]} out буфер результатів
|
|
486
|
+
*/
|
|
487
|
+
function collectInListUnparsedFromTemplate(node, content, declarators, out) {
|
|
488
|
+
if (node.type !== 'TemplateLiteral') return
|
|
489
|
+
const quasis = node.quasis
|
|
490
|
+
const expressions = node.expressions
|
|
491
|
+
if (!Array.isArray(quasis) || !Array.isArray(expressions) || expressions.length === 0) return
|
|
492
|
+
|
|
493
|
+
for (const [i, expr] of expressions.entries()) {
|
|
494
|
+
if (!IN_PLACEHOLDER_END_RE.test(quasiRawText(quasis[i]))) continue
|
|
495
|
+
if (!expr || typeof expr !== 'object') continue
|
|
496
|
+
if (isJoinCall(expr)) continue
|
|
497
|
+
if (isInListExpressionParsed(expr, declarators)) continue
|
|
498
|
+
|
|
499
|
+
const startOffset = typeof expr.start === 'number' ? expr.start : node.start
|
|
500
|
+
out.push({
|
|
501
|
+
line: offsetToLine(content, startOffset),
|
|
502
|
+
snippet: normalizeSnippet(content.slice(node.start, node.end))
|
|
503
|
+
})
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Знаходить підстановки IN (вираз) у TemplateLiteral, де вираз не пройшов числовий парсер.
|
|
474
509
|
*
|
|
510
|
+
* Навіть у безпечному tagged template pool.request().query краще явно парсити значення (parseInt,
|
|
511
|
+
* Number, BigInt, parseFloat) та фільтрувати NaN. Див. також findUnsafeMssqlDynamicSqlListInText для
|
|
512
|
+
* випадків arr.join у списках.
|
|
475
513
|
* @param {string} content вихідний код
|
|
476
|
-
* @param {string} [virtualPath] шлях для вибору
|
|
514
|
+
* @param {string} [virtualPath] шлях для вибору мови парсера (lang)
|
|
477
515
|
* @returns {{ line: number, snippet: string }[]} список порушень
|
|
478
516
|
*/
|
|
479
517
|
export function findUnsafeMssqlInListUnparsedInText(content, virtualPath = 'scan.ts') {
|
|
@@ -490,32 +528,7 @@ export function findUnsafeMssqlInListUnparsedInText(content, virtualPath = 'scan
|
|
|
490
528
|
|
|
491
529
|
/** @type {{ line: number, snippet: string }[]} */
|
|
492
530
|
const out = []
|
|
493
|
-
walkAstWithAncestors(result.program, [], node =>
|
|
494
|
-
if (node.type !== 'TemplateLiteral') return
|
|
495
|
-
const quasis = node.quasis
|
|
496
|
-
const expressions = node.expressions
|
|
497
|
-
if (!Array.isArray(quasis) || !Array.isArray(expressions) || expressions.length === 0) return
|
|
498
|
-
|
|
499
|
-
for (let i = 0; i < expressions.length; i++) {
|
|
500
|
-
const q = quasis[i]
|
|
501
|
-
const rawText =
|
|
502
|
-
q && typeof q === 'object' && q.value && typeof q.value === 'object' && typeof q.value.raw === 'string'
|
|
503
|
-
? q.value.raw
|
|
504
|
-
: ''
|
|
505
|
-
if (!IN_PLACEHOLDER_END_RE.test(rawText)) continue
|
|
506
|
-
|
|
507
|
-
const expr = expressions[i]
|
|
508
|
-
if (!expr || typeof expr !== 'object') continue
|
|
509
|
-
if (isJoinCall(expr)) continue
|
|
510
|
-
if (isInListExpressionParsed(expr, declarators)) continue
|
|
511
|
-
|
|
512
|
-
const startOffset = typeof expr.start === 'number' ? expr.start : node.start
|
|
513
|
-
out.push({
|
|
514
|
-
line: offsetToLine(content, startOffset),
|
|
515
|
-
snippet: normalizeSnippet(content.slice(node.start, node.end))
|
|
516
|
-
})
|
|
517
|
-
}
|
|
518
|
-
})
|
|
531
|
+
walkAstWithAncestors(result.program, [], node => collectInListUnparsedFromTemplate(node, content, declarators, out))
|
|
519
532
|
|
|
520
533
|
return out
|
|
521
534
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
3
|
+
"plugins": ["unicorn", "oxc", "import", "jsdoc", "promise", "node"],
|
|
4
|
+
"jsPlugins": ["@e18e/eslint-plugin"],
|
|
5
|
+
"categories": {},
|
|
6
|
+
"rules": {},
|
|
7
|
+
"settings": {
|
|
8
|
+
"next": {
|
|
9
|
+
"rootDir": []
|
|
10
|
+
},
|
|
11
|
+
"jsdoc": {
|
|
12
|
+
"ignorePrivate": false,
|
|
13
|
+
"ignoreInternal": false,
|
|
14
|
+
"ignoreReplacesDocs": true,
|
|
15
|
+
"overrideReplacesDocs": true,
|
|
16
|
+
"augmentsExtendsReplacesDocs": false,
|
|
17
|
+
"implementsReplacesDocs": false,
|
|
18
|
+
"exemptDestructuredRootsFromChecks": false,
|
|
19
|
+
"tagNamePreference": {}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"env": {
|
|
23
|
+
"builtin": true
|
|
24
|
+
},
|
|
25
|
+
"globals": {},
|
|
26
|
+
"ignorePatterns": []
|
|
27
|
+
}
|