@7n/rules 1.27.0 → 1.28.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/CHANGELOG.md +6 -0
- package/package.json +1 -5
- package/scripts/auto-rules.mjs +2 -3
- package/scripts/docs/auto-rules.md +1 -1
- package/scripts/lib/docs/glob-to-regex.md +31 -0
- package/scripts/lib/docs/index.md +2 -0
- package/scripts/lib/docs/js-source-signals.md +32 -0
- package/scripts/lib/glob-to-regex.mjs +79 -0
- package/scripts/lib/js-source-signals.mjs +50 -0
- package/scripts/utils/ast-scan-utils.mjs +2 -2
- package/scripts/utils/docs/ast-scan-utils.md +1 -1
- package/rules/bun/bunfig/bunfig.mdc +0 -17
- package/rules/bun/bunfig/bunfig.rego +0 -29
- package/rules/bun/bunfig/concern.json +0 -9
- package/rules/bun/bunfig/template/bunfig.toml.snippet.toml +0 -2
- package/rules/bun/docs/index.md +0 -11
- package/rules/bun/layout/concern.json +0 -16
- package/rules/bun/layout/docs/fix-layout.md +0 -29
- package/rules/bun/layout/docs/main.md +0 -34
- package/rules/bun/layout/fix-layout.mjs +0 -63
- package/rules/bun/layout/layout.mdc +0 -60
- package/rules/bun/layout/main.mjs +0 -53
- package/rules/bun/licensee/concern.json +0 -7
- package/rules/bun/licensee/docs/fix-licensee.md +0 -27
- package/rules/bun/licensee/docs/index.md +0 -12
- package/rules/bun/licensee/docs/main.md +0 -30
- package/rules/bun/licensee/fix-licensee.mjs +0 -31
- package/rules/bun/licensee/main.mjs +0 -68
- package/rules/bun/lint-surface/concern.json +0 -3
- package/rules/bun/lint-surface/lint-surface.mdc +0 -13
- package/rules/bun/main.json +0 -1
- package/rules/bun/main.mdc +0 -11
- package/rules/bun/package_json/concern.json +0 -9
- package/rules/bun/package_json/docs/fix-package_json.md +0 -28
- package/rules/bun/package_json/docs/index.md +0 -9
- package/rules/bun/package_json/fix-package_json.mjs +0 -311
- package/rules/bun/package_json/package_json.mdc +0 -14
- package/rules/bun/package_json/package_json.rego +0 -64
- package/rules/bun/package_json/template/package.json.deny.json +0 -4
- package/rules/js/check/check.mdc +0 -26
- package/rules/js/check/concern.json +0 -19
- package/rules/js/check/docs/eslint-config.md +0 -56
- package/rules/js/check/docs/fix-check.md +0 -48
- package/rules/js/check/docs/index.md +0 -13
- package/rules/js/check/docs/main.md +0 -48
- package/rules/js/check/eslint-config.mjs +0 -262
- package/rules/js/check/fix-check.mjs +0 -82
- package/rules/js/check/main.mjs +0 -310
- package/rules/js/dep-policy/concern.json +0 -4
- package/rules/js/dep-policy/dep-policy.mdc +0 -36
- package/rules/js/dep-policy/docs/main.md +0 -35
- package/rules/js/dep-policy/main.mjs +0 -99
- package/rules/js/docs/index.md +0 -11
- package/rules/js/eslint/concern.json +0 -8
- package/rules/js/eslint/docs/fix-eslint.md +0 -50
- package/rules/js/eslint/docs/fix-worker.md +0 -31
- package/rules/js/eslint/docs/index.md +0 -11
- package/rules/js/eslint/docs/main.md +0 -35
- package/rules/js/eslint/fix-eslint.mjs +0 -160
- package/rules/js/eslint/fix-worker.mjs +0 -139
- package/rules/js/eslint/main.mjs +0 -115
- package/rules/js/file-extensions/concern.json +0 -3
- package/rules/js/file-extensions/file-extensions.mdc +0 -12
- package/rules/js/jscpd_config/concern.json +0 -11
- package/rules/js/jscpd_config/docs/fix-jscpd_config.md +0 -26
- package/rules/js/jscpd_config/docs/index.md +0 -9
- package/rules/js/jscpd_config/fix-jscpd_config.mjs +0 -3
- package/rules/js/jscpd_config/jscpd_config.mdc +0 -42
- package/rules/js/jscpd_config/jscpd_config.rego +0 -44
- package/rules/js/jscpd_config/template/.jscpd.json.snippet.json +0 -7
- package/rules/js/jscpd_duplicates/concern.json +0 -7
- package/rules/js/jscpd_duplicates/docs/main.md +0 -29
- package/rules/js/jscpd_duplicates/main.mjs +0 -69
- package/rules/js/knip/concern.json +0 -7
- package/rules/js/knip/docs/main.md +0 -32
- package/rules/js/knip/knip.mdc +0 -15
- package/rules/js/knip/main.mjs +0 -68
- package/rules/js/lint-findings/concern.json +0 -3
- package/rules/js/lint-findings/docs/main.md +0 -41
- package/rules/js/lint-findings/main.mjs +0 -125
- package/rules/js/main.json +0 -1
- package/rules/js/main.mdc +0 -18
- package/rules/js/package_json/concern.json +0 -9
- package/rules/js/package_json/docs/fix-package_json.md +0 -26
- package/rules/js/package_json/docs/index.md +0 -9
- package/rules/js/package_json/fix-package_json.mjs +0 -3
- package/rules/js/package_json/package_json.mdc +0 -15
- package/rules/js/package_json/package_json.rego +0 -142
- package/rules/js/package_json/template/package.json.snippet.json +0 -6
- package/rules/js/tooling/concern.json +0 -3
- package/rules/js/tooling/data/tooling/knip-canonical.json +0 -30
- package/rules/js/tooling/data/tooling/oxlint-canonical.json +0 -400
- package/rules/js/tooling/docs/main.md +0 -53
- package/rules/js/tooling/main.mjs +0 -183
- package/rules/js/utils_imports/concern.json +0 -4
- package/rules/js/utils_imports/docs/main.md +0 -50
- package/rules/js/utils_imports/main.mjs +0 -185
- package/rules/js/utils_imports/utils_imports.mdc +0 -15
- package/rules/js/vscode_extensions/concern.json +0 -11
- package/rules/js/vscode_extensions/docs/fix-vscode_extensions.md +0 -25
- package/rules/js/vscode_extensions/docs/index.md +0 -11
- package/rules/js/vscode_extensions/fix-vscode_extensions.mjs +0 -1
- package/rules/js/vscode_extensions/template/extensions.json.snippet.json +0 -6
- package/rules/js/vscode_extensions/vscode_extensions.mdc +0 -11
- package/rules/js/vscode_extensions/vscode_extensions.rego +0 -12
- package/rules/js-bun-db/connection/concern.json +0 -3
- package/rules/js-bun-db/connection/connection.mdc +0 -42
- package/rules/js-bun-db/docs/index.md +0 -11
- package/rules/js-bun-db/lib/bun-sql-scan.mjs +0 -1055
- package/rules/js-bun-db/lib/docs/bun-sql-scan.md +0 -63
- package/rules/js-bun-db/lib/docs/index.md +0 -11
- package/rules/js-bun-db/main.json +0 -1
- package/rules/js-bun-db/main.mdc +0 -8
- package/rules/js-bun-db/package_json/concern.json +0 -9
- package/rules/js-bun-db/package_json/package_json.mdc +0 -31
- package/rules/js-bun-db/package_json/package_json.rego +0 -15
- package/rules/js-bun-db/package_json/template/package.json.deny.json +0 -6
- package/rules/js-bun-db/pg_format_identifiers/concern.json +0 -3
- package/rules/js-bun-db/pg_format_identifiers/pg_format_identifiers.mdc +0 -104
- package/rules/js-bun-db/safety/concern.json +0 -4
- package/rules/js-bun-db/safety/docs/main.md +0 -34
- package/rules/js-bun-db/safety/main.mjs +0 -430
- package/rules/js-bun-db/safety/safety.mdc +0 -458
- package/rules/js-bun-redis/docs/index.md +0 -11
- package/rules/js-bun-redis/imports/concern.json +0 -4
- package/rules/js-bun-redis/imports/docs/main.md +0 -36
- package/rules/js-bun-redis/imports/imports.mdc +0 -47
- package/rules/js-bun-redis/imports/main.mjs +0 -88
- package/rules/js-bun-redis/lib/docs/index.md +0 -11
- package/rules/js-bun-redis/lib/docs/redis-imports.md +0 -227
- package/rules/js-bun-redis/lib/redis-imports.mjs +0 -130
- package/rules/js-bun-redis/main.json +0 -1
- package/rules/js-bun-redis/main.mdc +0 -8
- package/rules/js-bun-redis/package_json/concern.json +0 -9
- package/rules/js-bun-redis/package_json/package_json.mdc +0 -11
- package/rules/js-bun-redis/package_json/package_json.rego +0 -15
- package/rules/js-bun-redis/package_json/template/package.json.deny.json +0 -12
- package/rules/js-mssql/deps/concern.json +0 -4
- package/rules/js-mssql/deps/docs/main.md +0 -33
- package/rules/js-mssql/deps/main.mjs +0 -297
- package/rules/js-mssql/docs/index.md +0 -11
- package/rules/js-mssql/lib/docs/index.md +0 -11
- package/rules/js-mssql/lib/docs/mssql-pool-scan.md +0 -380
- package/rules/js-mssql/lib/mssql-pool-scan.mjs +0 -610
- package/rules/js-mssql/main.json +0 -1
- package/rules/js-mssql/main.mdc +0 -144
- package/rules/js-mssql/mssql-tvp/concern.json +0 -3
- package/rules/js-mssql/mssql-tvp/mssql-tvp.mdc +0 -77
- package/rules/js-mssql/package_json/concern.json +0 -9
- package/rules/js-mssql/package_json/package_json.mdc +0 -9
- package/rules/js-mssql/package_json/package_json.rego +0 -57
- package/rules/js-run/configmap/concern.json +0 -9
- package/rules/js-run/configmap/configmap.mdc +0 -37
- package/rules/js-run/configmap/configmap.rego +0 -21
- package/rules/js-run/configmap/template/configmap.yaml.contains.yml +0 -4
- package/rules/js-run/docs/index.md +0 -11
- package/rules/js-run/jsconfig/concern.json +0 -9
- package/rules/js-run/jsconfig/docs/fix-jsconfig.md +0 -29
- package/rules/js-run/jsconfig/docs/index.md +0 -9
- package/rules/js-run/jsconfig/fix-jsconfig.mjs +0 -119
- package/rules/js-run/jsconfig/jsconfig.mdc +0 -48
- package/rules/js-run/jsconfig/jsconfig.rego +0 -59
- package/rules/js-run/jsconfig/template/jsconfig.json.snippet.json +0 -10
- package/rules/js-run/lib/bunyan-imports.mjs +0 -98
- package/rules/js-run/lib/check-env-scan.mjs +0 -338
- package/rules/js-run/lib/conn-file-rules.mjs +0 -214
- package/rules/js-run/lib/conn-imports-scan.mjs +0 -154
- package/rules/js-run/lib/docs/bunyan-imports.md +0 -121
- package/rules/js-run/lib/docs/check-env-scan.md +0 -438
- package/rules/js-run/lib/docs/conn-file-rules.md +0 -304
- package/rules/js-run/lib/docs/conn-imports-scan.md +0 -208
- package/rules/js-run/lib/docs/index.md +0 -16
- package/rules/js-run/lib/docs/promise-settimeout-scan.md +0 -334
- package/rules/js-run/lib/docs/temporal-scan.md +0 -29
- package/rules/js-run/lib/promise-settimeout-scan.mjs +0 -128
- package/rules/js-run/lib/temporal-scan.mjs +0 -52
- package/rules/js-run/main.json +0 -1
- package/rules/js-run/main.mdc +0 -16
- package/rules/js-run/package_json/concern.json +0 -9
- package/rules/js-run/package_json/package_json.mdc +0 -44
- package/rules/js-run/package_json/package_json.rego +0 -37
- package/rules/js-run/package_json/template/package.json.deny.json +0 -22
- package/rules/js-run/project-structure/concern.json +0 -3
- package/rules/js-run/project-structure/project-structure.mdc +0 -11
- package/rules/js-run/runtime/concern.json +0 -12
- package/rules/js-run/runtime/docs/fix-runtime.md +0 -27
- package/rules/js-run/runtime/docs/main.md +0 -35
- package/rules/js-run/runtime/fix-runtime.mjs +0 -46
- package/rules/js-run/runtime/main.mjs +0 -494
- package/rules/js-run/runtime/runtime.mdc +0 -184
- package/rules/js-run/scope/concern.json +0 -3
- package/rules/js-run/scope/scope.mdc +0 -11
- package/rules/npm-module/docs/index.md +0 -11
- package/rules/npm-module/emit_types_config/concern.json +0 -9
- package/rules/npm-module/emit_types_config/docs/fix-emit_types_config.md +0 -25
- package/rules/npm-module/emit_types_config/docs/index.md +0 -9
- package/rules/npm-module/emit_types_config/emit_types_config.mdc +0 -43
- package/rules/npm-module/emit_types_config/emit_types_config.rego +0 -28
- package/rules/npm-module/emit_types_config/fix-emit_types_config.mjs +0 -5
- package/rules/npm-module/emit_types_config/template/tsconfig.emit-types.json.snippet.json +0 -9
- package/rules/npm-module/header_doc_pointer/concern.json +0 -5
- package/rules/npm-module/header_doc_pointer/docs/main.md +0 -40
- package/rules/npm-module/header_doc_pointer/header_doc_pointer.mdc +0 -18
- package/rules/npm-module/header_doc_pointer/main.mjs +0 -131
- package/rules/npm-module/main.json +0 -1
- package/rules/npm-module/main.mdc +0 -36
- package/rules/npm-module/npm_package_json/concern.json +0 -9
- package/rules/npm-module/npm_package_json/docs/fix-npm_package_json.md +0 -27
- package/rules/npm-module/npm_package_json/docs/index.md +0 -9
- package/rules/npm-module/npm_package_json/fix-npm_package_json.mjs +0 -5
- package/rules/npm-module/npm_package_json/npm_package_json.mdc +0 -57
- package/rules/npm-module/npm_package_json/npm_package_json.rego +0 -73
- package/rules/npm-module/npm_package_json/template/package.json.snippet.json +0 -1
- package/rules/npm-module/package_structure/concern.json +0 -5
- package/rules/npm-module/package_structure/docs/main.md +0 -37
- package/rules/npm-module/package_structure/main.mjs +0 -515
- package/rules/npm-module/package_structure/package_structure.mdc +0 -63
- package/rules/npm-module/root_package_json/concern.json +0 -9
- package/rules/npm-module/root_package_json/docs/fix-root_package_json.md +0 -26
- package/rules/npm-module/root_package_json/docs/index.md +0 -9
- package/rules/npm-module/root_package_json/fix-root_package_json.mjs +0 -5
- package/rules/npm-module/root_package_json/root_package_json.mdc +0 -41
- package/rules/npm-module/root_package_json/root_package_json.rego +0 -28
- package/rules/npm-module/root_package_json/template/package.json.snippet.json +0 -1
- package/rules/npm-module/rule_meta/concern.json +0 -8
- package/rules/npm-module/rule_meta/docs/main.md +0 -35
- package/rules/npm-module/rule_meta/main.mjs +0 -119
- package/rules/npm-module/rule_meta/rule_meta.mdc +0 -11
- package/rules/npm-module/skill_meta/concern.json +0 -5
- package/rules/npm-module/skill_meta/docs/main.md +0 -149
- package/rules/npm-module/skill_meta/main.mjs +0 -91
- package/rules/npm-module/skill_meta/skill_meta.mdc +0 -11
- package/rules/tool-surface/docs/index.md +0 -11
- package/rules/tool-surface/main.json +0 -6
- package/rules/tool-surface/main.mdc +0 -72
- package/rules/vue/composition-api/composition-api.mdc +0 -82
- package/rules/vue/composition-api/concern.json +0 -3
- package/rules/vue/docs/index.md +0 -11
- package/rules/vue/lib/docs/index.md +0 -11
- package/rules/vue/lib/docs/vue-forbidden-imports.md +0 -265
- package/rules/vue/lib/vue-forbidden-imports.mjs +0 -264
- package/rules/vue/main.json +0 -1
- package/rules/vue/main.mdc +0 -18
- package/rules/vue/nheader-layout/concern.json +0 -3
- package/rules/vue/nheader-layout/nheader-layout.mdc +0 -171
- package/rules/vue/package_json/concern.json +0 -9
- package/rules/vue/package_json/package_json.mdc +0 -30
- package/rules/vue/package_json/package_json.rego +0 -140
- package/rules/vue/packages/concern.json +0 -6
- package/rules/vue/packages/docs/index.md +0 -11
- package/rules/vue/packages/docs/main.md +0 -35
- package/rules/vue/packages/main.mjs +0 -575
- package/rules/vue/packages/packages.mdc +0 -56
- package/rules/vue/quasar-ui/concern.json +0 -3
- package/rules/vue/quasar-ui/quasar-ui.mdc +0 -32
- package/rules/vue/structure/concern.json +0 -3
- package/rules/vue/structure/structure.mdc +0 -101
- package/rules/vue/testing/concern.json +0 -3
- package/rules/vue/testing/testing.mdc +0 -40
- package/rules/vue/tfm-translations/concern.json +0 -7
- package/rules/vue/tfm-translations/docs/main.md +0 -29
- package/rules/vue/tfm-translations/main.mjs +0 -55
- package/rules/vue/tfm-translations/tfm-translations.mdc +0 -32
- package/rules/vue/vite-config/concern.json +0 -3
- package/rules/vue/vite-config/vite-config.mdc +0 -153
- package/rules/vue/vite-env/concern.json +0 -3
- package/rules/vue/vite-env/vite-env.mdc +0 -61
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lint-поверхня js/jscpd_duplicates: read-only detector дублікатів коду (`jscpd`).
|
|
3
|
-
* Кожен клон → одне порушення (anchored на `firstFile`), із посиланням на `secondFile`
|
|
4
|
-
* у `data`. JSON-звіт пишеться у системний tmp (поза репо) — дерево не мутується.
|
|
5
|
-
*/
|
|
6
|
-
import { mkdtempSync, readFileSync, rmSync } from 'node:fs'
|
|
7
|
-
import { tmpdir } from 'node:os'
|
|
8
|
-
import { join } from 'node:path'
|
|
9
|
-
|
|
10
|
-
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @typedef {{ name: string, start: number, end: number }} JscpdFileRef
|
|
14
|
-
* @typedef {{ firstFile: JscpdFileRef, secondFile: JscpdFileRef, lines: number, format: string }} JscpdClone
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Один клон → LintViolation.
|
|
19
|
-
* @param {JscpdClone} clone дубльований фрагмент
|
|
20
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintViolation} нормалізоване порушення
|
|
21
|
-
*/
|
|
22
|
-
function cloneToViolation(clone) {
|
|
23
|
-
const a = clone.firstFile
|
|
24
|
-
const b = clone.secondFile
|
|
25
|
-
const aLoc = `${a.name}:${a.start}-${a.end}`
|
|
26
|
-
const bLoc = `${b.name}:${b.start}-${b.end}`
|
|
27
|
-
return /** @type {import('../../../scripts/lib/lint-surface/types.mjs').LintViolation} */ ({
|
|
28
|
-
reason: 'duplicate-clone',
|
|
29
|
-
message: `jscpd: дубльований фрагмент (${clone.lines} рядків, ${clone.format}) ${aLoc} ↔ ${bLoc}`,
|
|
30
|
-
file: a.name,
|
|
31
|
-
data: {
|
|
32
|
-
line: a.start,
|
|
33
|
-
lines: clone.lines,
|
|
34
|
-
format: clone.format,
|
|
35
|
-
first: { file: a.name, start: a.start, end: a.end },
|
|
36
|
-
second: { file: b.name, start: b.start, end: b.end }
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Detector js/jscpd_duplicates: дублікати коду через `jscpd` (read-only). Async (не блокує
|
|
43
|
-
* event loop) — детектор може виконуватись у parallel lane `detectAll()` (ADR 260716-1354).
|
|
44
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту
|
|
45
|
-
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} перелік порушень
|
|
46
|
-
*/
|
|
47
|
-
export async function lint(ctx) {
|
|
48
|
-
const cwd = ctx.cwd
|
|
49
|
-
const outDir = mkdtempSync(join(tmpdir(), 'jscpd-'))
|
|
50
|
-
try {
|
|
51
|
-
const r = await spawnAsync('bunx', ['jscpd', '.', '--reporters', 'json', '--output', outDir, '--silent'], { cwd })
|
|
52
|
-
let report
|
|
53
|
-
try {
|
|
54
|
-
report = JSON.parse(readFileSync(join(outDir, 'jscpd-report.json'), 'utf8'))
|
|
55
|
-
} catch {
|
|
56
|
-
// jscpd не зміг сформувати звіт (інструмент відсутній / краш) — пропускаємо
|
|
57
|
-
const detail = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 500)
|
|
58
|
-
const suffix = detail ? `: ${detail}` : ''
|
|
59
|
-
return {
|
|
60
|
-
violations: [],
|
|
61
|
-
diagnostics: [{ level: 'warn', message: `jscpd: не вдалося прочитати JSON-звіт${suffix}` }]
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
const clones = Array.isArray(report.duplicates) ? report.duplicates : []
|
|
65
|
-
return { violations: clones.map(clone => cloneToViolation(clone)) }
|
|
66
|
-
} finally {
|
|
67
|
-
rmSync(outDir, { recursive: true, force: true })
|
|
68
|
-
}
|
|
69
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/js/knip/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: e44b88a8
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
score: 100
|
|
9
|
-
issues: judge:inaccurate:0.98
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
Аналізує проєкт на предмет невикористаних залежностей та експортів. Виконує операцію лише для читання, не змінюючи файлову систему чи базу даних. Публічна функція `lint` надає звіт про виявлені проблеми, який визначається за кодом виходу.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
1. Викликається функція `lint`.
|
|
20
|
-
2. Система аналізує проект на предмет невикористаних залежностей та експортів.
|
|
21
|
-
3. На основі збору виявлених проблем, система генерує звіт.
|
|
22
|
-
4. Якщо знайдено хоча б одну проблему, функція повертає значення 1; інакше — 0.
|
|
23
|
-
|
|
24
|
-
## Публічний API
|
|
25
|
-
|
|
26
|
-
Я розумію завдання. Мені потрібно перетворити технічний опис на лаконічну, поведінкову документацію українською мовою у форматі маркерів, дотримуючись усіх зазначених обмежень.
|
|
27
|
-
|
|
28
|
-
Будь ласка, надайте список, який потрібно переписати.
|
|
29
|
-
|
|
30
|
-
## Гарантії поведінки
|
|
31
|
-
|
|
32
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
package/rules/js/knip/knip.mdc
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
## `knip.json` — аналіз невикористаних залежностей та експортів
|
|
2
|
-
|
|
3
|
-
Залежнісний аналіз (knip — невикористані залежності/експорти, `knip.json` канон) крос-файловий; запускається як частина `npx @7n/rules lint js`.
|
|
4
|
-
|
|
5
|
-
У корені проєкту має бути **`knip.json`**, який стартує з канонічного baseline з пакета `@7n/rules` — файл [`knip-canonical.json`](../tooling/data/tooling/knip-canonical.json). Канон покриває типові false-positives для наших правил:
|
|
6
|
-
|
|
7
|
-
- `entry` зі CLI-конфігами (eslint, stylelint, oxlint, jscpd, markdownlint-cli2, `commitlint`);
|
|
8
|
-
- `project` для `**/*.{js,mjs,cjs,jsx,ts,tsx,mts,cts}`;
|
|
9
|
-
- `ignore` для `**/__fixtures__/**`;
|
|
10
|
-
- `ignoreDependencies` для пакетів, посилання на які є лише в не-JS-конфігах (`@nitra/cspell-dict`, `/@cspell\/dict-.+/`, `graphql`);
|
|
11
|
-
- `ignoreBinaries` для CLI, які канон вимагає викликати через `npx`/`bunx` і яких заборонено додавати в `devDependencies` (`actionlint`, `cspell`, `eslint`, `git-ai`, `jscpd`, `markdownlint-cli2`, `oxfmt`, `oxlint`, `shellcheck`, `uvx`, `v8r`, `zizmor`).
|
|
12
|
-
|
|
13
|
-
Якщо `knip.json` відсутній — `npx @7n/rules lint js` (концерн `js/check`) копіює канон у корінь проєкту як side effect детектора, ще до фази LLM-фіксів. Після створення модифікуй файл під свій проєкт як завгодно: перевіряємо лише наявність, зміст подальших змін не валідується.
|
|
14
|
-
|
|
15
|
-
Пакет `knip` окремо в `devDependencies` не додавай — `bunx knip` тягне його ad-hoc, як oxlint/eslint/jscpd.
|
package/rules/js/knip/main.mjs
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lint-поверхня js/knip: read-only detector невикористаних залежностей/експортів/файлів.
|
|
3
|
-
* Кожен knip-issue → одне порушення (reason = тип issue, file/line де доступні). Жодних
|
|
4
|
-
* мутацій (knip запускається без `--fix`) і жодного друку звіту — рендерить runner.
|
|
5
|
-
*/
|
|
6
|
-
import { createRequire } from 'node:module'
|
|
7
|
-
import { dirname, join, relative } from 'node:path'
|
|
8
|
-
import { pathToFileURL } from 'node:url'
|
|
9
|
-
|
|
10
|
-
import { main as knipMain } from 'knip'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Один knip-issue → LintViolation.
|
|
14
|
-
* @param {{ type: string, filePath?: string, symbol?: string, symbolType?: string, line?: number, col?: number, severity?: string }} issue knip-issue
|
|
15
|
-
* @param {string} cwd робочий каталог
|
|
16
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintViolation} нормалізоване порушення
|
|
17
|
-
*/
|
|
18
|
-
function issueToViolation(issue, cwd) {
|
|
19
|
-
const abs = issue.filePath
|
|
20
|
-
const file = abs ? relative(cwd, abs).split('\\').join('/') : undefined
|
|
21
|
-
const lineSuffix = issue.line ? `:${issue.line}` : ''
|
|
22
|
-
const where = file ? `${file}${lineSuffix}` : '<unknown>'
|
|
23
|
-
const symbolType = issue.symbolType ? ` (${issue.symbolType})` : ''
|
|
24
|
-
const sym = issue.symbol ? ` \`${issue.symbol}\`${symbolType}` : ''
|
|
25
|
-
/** @type {Partial<import('../../../scripts/lib/lint-surface/types.mjs').LintViolation>} */
|
|
26
|
-
const v = {
|
|
27
|
-
reason: issue.type || 'knip-issue',
|
|
28
|
-
message: `knip: ${issue.type}${sym} — ${where}`,
|
|
29
|
-
severity: issue.severity === 'warn' ? 'warn' : 'error',
|
|
30
|
-
data: { line: issue.line, col: issue.col, symbol: issue.symbol, type: issue.type }
|
|
31
|
-
}
|
|
32
|
-
if (file) v.file = file
|
|
33
|
-
return v
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Detector js/knip: невикористані deps/exports/files через programmatic API knip (read-only).
|
|
38
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту
|
|
39
|
-
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} перелік порушень
|
|
40
|
-
*/
|
|
41
|
-
export async function lint(ctx) {
|
|
42
|
-
const cwd = ctx.cwd
|
|
43
|
-
|
|
44
|
-
// knip-package не експортує внутрішні util-и через "exports" — резолвимо dist-каталог
|
|
45
|
-
// від головного entry і імпортуємо `create-options` за абсолютним file:// URL.
|
|
46
|
-
const require = createRequire(import.meta.url)
|
|
47
|
-
const distDir = dirname(require.resolve('knip'))
|
|
48
|
-
// eslint-disable-next-line no-unsanitized/method -- URL from resolved package path, not user input
|
|
49
|
-
const { createOptions } = await import(pathToFileURL(join(distDir, 'util/create-options.js')).href)
|
|
50
|
-
|
|
51
|
-
// knip вмикає власний прогрес-репортер ("Analyzing workspace …") автоматично в TTY,
|
|
52
|
-
// незалежно від наших verbose-прапорців — глушимо його поза `--verbose`, щоб не
|
|
53
|
-
// засмічувати вивід `lint --full`.
|
|
54
|
-
const options = await createOptions({ cwd, isDisableConfigHints: true, isShowProgress: ctx.verbose === true })
|
|
55
|
-
const results = await knipMain(options)
|
|
56
|
-
|
|
57
|
-
/** @type {import('../../../scripts/lib/lint-surface/types.mjs').LintViolation[]} */
|
|
58
|
-
const violations = []
|
|
59
|
-
// results.issues: { <type>: { <file>: { <key>: Issue } } }
|
|
60
|
-
for (const byFile of Object.values(results.issues)) {
|
|
61
|
-
for (const byKey of Object.values(byFile)) {
|
|
62
|
-
for (const issue of Object.values(byKey)) {
|
|
63
|
-
violations.push(issueToViolation(/** @type {Parameters<typeof issueToViolation>[0]} */ (issue), cwd))
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return { violations }
|
|
68
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/js/lint-findings/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: cb60407d
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
tier: local-min
|
|
9
|
-
score: 100
|
|
10
|
-
issues: judge:inaccurate:0.98
|
|
11
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Огляд
|
|
15
|
-
|
|
16
|
-
Ось оновлений текст секції «overview» відповідно до ваших вимог:
|
|
17
|
-
|
|
18
|
-
Ця система надає можливості для аналізу логіки та виявлення помилок на основі результатів відмінних лінтерів. Доступні функції включають `parseOxlint` та `parseEslint` для парсингу результатів. Далі, `eslintResultsToFindings` перетворює ці результати у стандартизовані знахідки, які потім класифікуються за допомогою `classifyFindings`. Фінальне представлення цих знахідок здійснюється функцією `renderFindings`. Усі операції є read-only та не взаємодіють з файловою системою чи базою даних. Система працює з принципом fail-safe, тобто перехоплює можливі помилки і, замість викидання винятку, повертає порожнє значення, наприклад, `null`.
|
|
19
|
-
|
|
20
|
-
## Поведінка
|
|
21
|
-
|
|
22
|
-
Поведінка:
|
|
23
|
-
parseOxlint: Парсить вивід `oxlint` у форматі JSON, повертаючи список знайдених порушень або `null` у разі непарсибельного JSON.
|
|
24
|
-
parseEslint: Парсить вивід `eslint` у форматі JSON, повертаючи список знайдених порушень або `null` у разі непарсибельного JSON.
|
|
25
|
-
eslintResultsToFindings: Конвертує результати, отримані з API `eslint.lintFiles`, у нормалізований список знайдених порушень.
|
|
26
|
-
classifyFindings: Класифікує знайдені порушення на "внесено цією зміною" або "борг файлу" на основі інформації про додані рядки у файлі.
|
|
27
|
-
renderFindings: Форматує класифіковані порушення у текстовий звіт, розділяючи внесені та існуючі проблеми.
|
|
28
|
-
|
|
29
|
-
## Публічний API
|
|
30
|
-
|
|
31
|
-
parseOxlint — отримує результат парсингу Oxlint, повертаючи `null`, якщо вивід інструмента не може бути інтерпретований як JSON.
|
|
32
|
-
parseEslint — отримує результат парсингу Eslint, повертаючи `null`, якщо вивід інструмента не може бути інтерпретований як JSON.
|
|
33
|
-
eslintResultsToFindings — перетворює детальні звіти з ESLint у стандартизований формат знахідок.
|
|
34
|
-
classifyFindings — розрізняє знахідки, які виникли через додані рядки, від тих, що були присутні до змін.
|
|
35
|
-
renderFindings — створює зведений звіт, відображаючи нові знахідки (🆕 introduced) та існуючий технічний борг (🗄 pre-existing).
|
|
36
|
-
|
|
37
|
-
## Гарантії поведінки
|
|
38
|
-
|
|
39
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
40
|
-
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
41
|
-
- За певних помилок повертає порожнє значення (напр. `null`) замість винятку.
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/** @see ./docs/lint-findings.md */
|
|
2
|
-
import { isAbsolute, relative } from 'node:path'
|
|
3
|
-
|
|
4
|
-
import { isIntroducedLine } from '../../../scripts/lib/diff-added-lines.mjs'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @param {string} jsonText вивід `oxlint --format=json`
|
|
8
|
-
* @returns {{ file: string, line: number, rule: string, message: string, tool: string }[] | null} findings,
|
|
9
|
-
* або `null` якщо json непарсабельний (краш/обрізаний вивід інструмента — НЕ «чисто»)
|
|
10
|
-
*/
|
|
11
|
-
export function parseOxlint(jsonText) {
|
|
12
|
-
let data
|
|
13
|
-
try {
|
|
14
|
-
data = JSON.parse(jsonText)
|
|
15
|
-
} catch {
|
|
16
|
-
return null
|
|
17
|
-
}
|
|
18
|
-
const diags = Array.isArray(data?.diagnostics) ? data.diagnostics : []
|
|
19
|
-
return diags
|
|
20
|
-
.filter(d => d?.filename)
|
|
21
|
-
.map(d => ({
|
|
22
|
-
file: d.filename,
|
|
23
|
-
line: d.labels?.[0]?.span?.line ?? 0,
|
|
24
|
-
rule: d.code ?? '',
|
|
25
|
-
message: d.message ?? '',
|
|
26
|
-
tool: 'oxlint'
|
|
27
|
-
}))
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @param {string} jsonText вивід `eslint --format=json`
|
|
32
|
-
* @returns {{ file: string, line: number, rule: string, message: string, tool: string }[] | null} findings,
|
|
33
|
-
* або `null` якщо json непарсабельний (краш/обрізаний вивід інструмента — НЕ «чисто»)
|
|
34
|
-
*/
|
|
35
|
-
export function parseEslint(jsonText) {
|
|
36
|
-
let data
|
|
37
|
-
try {
|
|
38
|
-
data = JSON.parse(jsonText)
|
|
39
|
-
} catch {
|
|
40
|
-
return null
|
|
41
|
-
}
|
|
42
|
-
const results = Array.isArray(data) ? data : []
|
|
43
|
-
const out = []
|
|
44
|
-
for (const r of results) {
|
|
45
|
-
for (const m of r?.messages ?? []) {
|
|
46
|
-
out.push({
|
|
47
|
-
file: r.filePath,
|
|
48
|
-
line: m.line ?? 0,
|
|
49
|
-
rule: m.ruleId ?? '(syntax)',
|
|
50
|
-
message: m.message ?? '',
|
|
51
|
-
tool: 'eslint'
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return out.filter(f => f.file)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Конвертує результати ESLint programmatic API у нормалізовані findings.
|
|
60
|
-
* @param {import('eslint').ESLint.LintResult[]} results результати `eslint.lintFiles()`
|
|
61
|
-
* @returns {{ file: string, line: number, rule: string, message: string, tool: string }[]} findings
|
|
62
|
-
*/
|
|
63
|
-
export function eslintResultsToFindings(results) {
|
|
64
|
-
const out = []
|
|
65
|
-
for (const r of results) {
|
|
66
|
-
for (const m of r.messages) {
|
|
67
|
-
out.push({
|
|
68
|
-
file: r.filePath,
|
|
69
|
-
line: m.line ?? 0,
|
|
70
|
-
rule: m.ruleId ?? '(syntax)',
|
|
71
|
-
message: m.message ?? '',
|
|
72
|
-
tool: 'eslint'
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return out.filter(f => f.file)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Розділяє findings на introduced / pre-existing за доданими рядками.
|
|
81
|
-
* @param {{ file: string, line: number }[]} findings нормалізовані findings
|
|
82
|
-
* @param {Map<string, Set<number> | string>} addedLines з `addedLinesByFile`
|
|
83
|
-
* @param {string} [cwd] корінь (для нормалізації абсолютних шляхів у relative)
|
|
84
|
-
* @returns {{ introduced: object[], preExisting: object[] }} класифікація
|
|
85
|
-
*/
|
|
86
|
-
export function classifyFindings(findings, addedLines, cwd = process.cwd()) {
|
|
87
|
-
const introduced = []
|
|
88
|
-
const preExisting = []
|
|
89
|
-
for (const f of findings) {
|
|
90
|
-
const rel = isAbsolute(f.file) ? relative(cwd, f.file) : f.file
|
|
91
|
-
if (isIntroducedLine(addedLines, rel, f.line)) introduced.push(f)
|
|
92
|
-
else preExisting.push(f)
|
|
93
|
-
}
|
|
94
|
-
return { introduced, preExisting }
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Рядок одного finding: `<rel>:<line> <rule> <message>`.
|
|
99
|
-
* @param {{ file: string, line: number, rule: string, message: string }} f finding
|
|
100
|
-
* @param {string} cwd корінь
|
|
101
|
-
* @returns {string} рядок
|
|
102
|
-
*/
|
|
103
|
-
function formatFinding(f, cwd) {
|
|
104
|
-
const rel = isAbsolute(f.file) ? relative(cwd, f.file) : f.file
|
|
105
|
-
return ` ${rel}:${f.line} ${f.rule} ${f.message}`
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Згрупований звіт: 🆕 introduced (виправ) + 🗄 pre-existing (борг файлу).
|
|
110
|
-
* @param {{ introduced: object[], preExisting: object[] }} classified результат `classifyFindings`
|
|
111
|
-
* @param {string} [cwd] корінь
|
|
112
|
-
* @returns {string} текст звіту
|
|
113
|
-
*/
|
|
114
|
-
export function renderFindings({ introduced, preExisting }, cwd = process.cwd()) {
|
|
115
|
-
const lines = []
|
|
116
|
-
if (introduced.length > 0) {
|
|
117
|
-
lines.push(` 🆕 introduced (${introduced.length}) — внесено цією зміною, виправ:`)
|
|
118
|
-
for (const f of introduced) lines.push(formatFinding(f, cwd))
|
|
119
|
-
}
|
|
120
|
-
if (preExisting.length > 0) {
|
|
121
|
-
lines.push(` 🗄 pre-existing (${preExisting.length}) — борг файлу, не з цієї зміни:`)
|
|
122
|
-
for (const f of preExisting) lines.push(formatFinding(f, cwd))
|
|
123
|
-
}
|
|
124
|
-
return lines.join('\n')
|
|
125
|
-
}
|
package/rules/js/main.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{ "auto": { "glob": ["**/*.mjs", "**/*.cjs", "**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] } }
|
package/rules/js/main.mdc
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Перевірка JavaScript коду
|
|
3
|
-
globs: "**/{.oxlintrc.json,eslint.config.js,.jscpd.json,knip.json,package.json},**/*.{js,mjs,cjs,jsx,ts,tsx}"
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
version: '1.31'
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
**oxlint**, **ESLint**, **jscpd**, **knip**. Запуск — **`n-rules lint js`** (локально; у CI — `--no-fix`, без **`--fix`** для oxlint/eslint). Без **prettier** і **@nitra/prettier-config**.
|
|
9
|
-
|
|
10
|
-
`eslint.config.js` — flat config з `getConfig` (`@nitra/eslint-config`). Аргументи `node: [...]`/`vue: [...]` мають відповідати воркспейс-типам репо (`workspaces` root `package.json`; vue-воркспейс = Vue-залежність у deps або `.vue` файли) — інакше `.vue` файли не парсяться. Відсутній конфіг створюється (scaffold), наявний — зазнає хірургічного merge (fix не перезаписує файл цілком).
|
|
11
|
-
|
|
12
|
-
## Швидкий gate через conftest
|
|
13
|
-
|
|
14
|
-
Rego-пакети — запускаються `npx @7n/rules lint js` або `conftest`:
|
|
15
|
-
|
|
16
|
-
- [.jscpd.json.snippet.json](./jscpd_config/template/.jscpd.json.snippet.json)
|
|
17
|
-
- [extensions.json.snippet.json](./vscode_extensions/template/extensions.json.snippet.json)
|
|
18
|
-
- [package.json.snippet.json](./package_json/template/package.json.snippet.json)
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: fix-package_json.mjs
|
|
4
|
-
resource: npm/rules/js/package_json/fix-package_json.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 048fe1b5
|
|
7
|
-
model: openai-codex/gpt-5.4-mini
|
|
8
|
-
tier: cloud-min
|
|
9
|
-
score: 100
|
|
10
|
-
issues: judge:inaccurate:0.98
|
|
11
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Огляд
|
|
15
|
-
|
|
16
|
-
`patterns` забезпечує перевірку й звірку `package.json` з очікуваним шаблоном цього проєкту. Модуль читає `package.json` як основний конфіг, на який спирається код, і використовується для оцінки відповідності структури та вмісту файла вимогам проєкту. Робота read-only: змін у файловій системі чи базі даних не вносить.
|
|
17
|
-
|
|
18
|
-
## Поведінка
|
|
19
|
-
|
|
20
|
-
1. `patterns` надає набір правил, які приводять `package.json` до очікуваного шаблону для цього проєкту.
|
|
21
|
-
2. Кожне правило орієнтується на конфігурацію `package.json` і застосовується до нього як до цільового файлу.
|
|
22
|
-
3. `patterns` використовується як публічна точка входу для перевірки й вирівнювання структури `package.json` без змін у файловій системі чи базі даних.
|
|
23
|
-
|
|
24
|
-
## Гарантії поведінки
|
|
25
|
-
|
|
26
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
## Rego-gate `package.json`
|
|
2
|
-
|
|
3
|
-
Rego-пакет: `js_lint.package_json`
|
|
4
|
-
|
|
5
|
-
Цільовий файл: `package.json` (корінь і workspace-пакети).
|
|
6
|
-
|
|
7
|
-
Що перевіряється:
|
|
8
|
-
|
|
9
|
-
- `"type"` — точна відповідність `"module"` (з канон-snippet)
|
|
10
|
-
- `scripts.lint-js` — нормалізована точна відповідність (collapse whitespace)
|
|
11
|
-
- `engines.node` — semver-парсинг: major >= 24 (inverse, без template)
|
|
12
|
-
- `engines.bun` — semver-парсинг: >= 1.3 (inverse, без template)
|
|
13
|
-
- `devDependencies["@nitra/eslint-config"]` — наявність ключа + semver >= порогу зі snippet (`^3.10.0`); `workspace:*` завжди проходить
|
|
14
|
-
|
|
15
|
-
Канон-snippet: [package.json.snippet.json](./template/package.json.snippet.json)
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# Перевірка `package.json` (js.mdc).
|
|
2
|
-
#
|
|
3
|
-
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
-
# Структура --data сформована з template/package.json.snippet.json
|
|
5
|
-
# (canonical `type` + `scripts.lint-js` + `devDependencies.@nitra/eslint-config` як мін-поріг).
|
|
6
|
-
#
|
|
7
|
-
# Мінімальна версія `@nitra/eslint-config` — ЄДИНЕ джерело в snippet
|
|
8
|
-
# (`devDependencies.@nitra/eslint-config`); rego лише парсить поріг і робить semver-порівняння.
|
|
9
|
-
#
|
|
10
|
-
# Логіка, що ЛИШАЄТЬСЯ у rego (inverse, без template-значення):
|
|
11
|
-
# - `engines.node` >= 24, `engines.bun` >= 1.3 (semver range parsing).
|
|
12
|
-
package js.package_json
|
|
13
|
-
|
|
14
|
-
import rego.v1
|
|
15
|
-
|
|
16
|
-
# ── deny: top-level scalar leafs (type) ─────────────────────────────────
|
|
17
|
-
|
|
18
|
-
banned_fastify_pkg := "@nitra/as-integrations-fastify"
|
|
19
|
-
|
|
20
|
-
deny contains msg if {
|
|
21
|
-
some key, expected_value in data.template.snippet
|
|
22
|
-
not is_object(expected_value)
|
|
23
|
-
actual := object.get(input, key, null)
|
|
24
|
-
actual != expected_value
|
|
25
|
-
msg := sprintf("package.json: \"%s\" має бути %q (js.mdc)", [key, expected_value])
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
# ── deny: scripts (nested) — exact match із normalize ──────────────────
|
|
29
|
-
|
|
30
|
-
deny contains msg if {
|
|
31
|
-
some script_name, expected in data.template.snippet.scripts
|
|
32
|
-
actual := object.get(object.get(input, "scripts", {}), script_name, "")
|
|
33
|
-
normalize_script(actual) != expected
|
|
34
|
-
msg := sprintf("package.json: scripts.%s має бути %q (js.mdc)", [script_name, expected])
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
# ── deny: engines.node >= 24 (inverse, у rego) ──────────────────────────
|
|
38
|
-
|
|
39
|
-
deny contains msg if {
|
|
40
|
-
engines := object.get(input, "engines", {})
|
|
41
|
-
not engines_node_meets(object.get(engines, "node", ""))
|
|
42
|
-
msg := "package.json: engines.node має бути >= 24 (js.mdc)"
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
deny contains msg if {
|
|
46
|
-
engines := object.get(input, "engines", {})
|
|
47
|
-
not engines_bun_meets(object.get(engines, "bun", ""))
|
|
48
|
-
msg := "package.json: engines.bun має бути >= 1.3 (js.mdc)"
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
# ── deny: @nitra/eslint-config >= snippet-поріг ─────────────────────────
|
|
52
|
-
|
|
53
|
-
deny contains msg if {
|
|
54
|
-
dev := object.get(input, "devDependencies", {})
|
|
55
|
-
not "@nitra/eslint-config" in object.keys(dev)
|
|
56
|
-
msg := "package.json: відсутній @nitra/eslint-config у devDependencies (js.mdc)"
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
deny contains msg if {
|
|
60
|
-
range := object.get(object.get(input, "devDependencies", {}), "@nitra/eslint-config", "")
|
|
61
|
-
range != ""
|
|
62
|
-
not eslint_config_meets_min(range)
|
|
63
|
-
msg := sprintf("package.json: @nitra/eslint-config має бути >= %s (зараз %q) (js.mdc)", [eslint_min_display, range])
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
# ── deny: @nitra/as-integrations-fastify заборонений (dep-policy.mdc) ───
|
|
67
|
-
|
|
68
|
-
deny contains msg if {
|
|
69
|
-
deps := object.get(input, "dependencies", {})
|
|
70
|
-
banned_fastify_pkg in object.keys(deps)
|
|
71
|
-
msg := sprintf("package.json: dependencies.%s заборонений — використовуй @as-integrations/fastify (js.mdc dep-policy)", [banned_fastify_pkg])
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
deny contains msg if {
|
|
75
|
-
deps := object.get(input, "peerDependencies", {})
|
|
76
|
-
banned_fastify_pkg in object.keys(deps)
|
|
77
|
-
msg := sprintf("package.json: peerDependencies.%s заборонений — використовуй @as-integrations/fastify (js.mdc dep-policy)", [banned_fastify_pkg])
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
# ── helpers ──────────────────────────────────────────────────────────────
|
|
81
|
-
|
|
82
|
-
# Канонічний мін-поріг `@nitra/eslint-config` із snippet (напр. "^3.10.0").
|
|
83
|
-
eslint_min_range := object.get(object.get(data.template.snippet, "devDependencies", {}), "@nitra/eslint-config", "")
|
|
84
|
-
|
|
85
|
-
# Поріг для повідомлення без діапазонних префіксів (напр. "3.10.0").
|
|
86
|
-
eslint_min_display := trim_left(eslint_min_range, "^~>=v ")
|
|
87
|
-
|
|
88
|
-
normalize_script(s) := regex.replace(trim_space(s), `\s+`, " ")
|
|
89
|
-
|
|
90
|
-
engines_node_meets(spec) if {
|
|
91
|
-
major := first_major(spec)
|
|
92
|
-
major >= 24
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
engines_bun_meets(spec) if {
|
|
96
|
-
parts := split_to_numbers(spec)
|
|
97
|
-
count(parts) >= 2
|
|
98
|
-
parts[0] > 1
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
engines_bun_meets(spec) if {
|
|
102
|
-
parts := split_to_numbers(spec)
|
|
103
|
-
count(parts) >= 2
|
|
104
|
-
parts[0] == 1
|
|
105
|
-
parts[1] >= 3
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
eslint_config_meets_min(range) if startswith(trim_space(range), "workspace:")
|
|
109
|
-
|
|
110
|
-
eslint_config_meets_min(range) if {
|
|
111
|
-
actual := split_to_numbers(range)
|
|
112
|
-
count(actual) >= 3
|
|
113
|
-
min_parts := split_to_numbers(eslint_min_range)
|
|
114
|
-
count(min_parts) >= 3
|
|
115
|
-
semver_gte(actual, min_parts)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
# actual >= min_parts за major.minor.patch (лексикографічно).
|
|
119
|
-
semver_gte(a, b) if a[0] > b[0]
|
|
120
|
-
|
|
121
|
-
semver_gte(a, b) if {
|
|
122
|
-
a[0] == b[0]
|
|
123
|
-
a[1] > b[1]
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
semver_gte(a, b) if {
|
|
127
|
-
a[0] == b[0]
|
|
128
|
-
a[1] == b[1]
|
|
129
|
-
a[2] >= b[2]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
first_major(spec) := major if {
|
|
133
|
-
parts := split_to_numbers(spec)
|
|
134
|
-
count(parts) >= 1
|
|
135
|
-
major := parts[0]
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
split_to_numbers(spec) := nums if {
|
|
139
|
-
tokens := regex.split(`\D+`, spec)
|
|
140
|
-
non_empty := [t | some t in tokens; t != ""]
|
|
141
|
-
nums := [n | some t in non_empty; n := to_number(t)]
|
|
142
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://unpkg.com/knip@5/schema.json",
|
|
3
|
-
"entry": [
|
|
4
|
-
".pi/extensions/**/*.ts",
|
|
5
|
-
"eslint.config.{js,mjs,cjs}",
|
|
6
|
-
"stylelint.config.{js,cjs,mjs}",
|
|
7
|
-
"oxlint.config.{js,mjs}",
|
|
8
|
-
"jscpd.config.{js,mjs}",
|
|
9
|
-
"markdownlint-cli2.config.{js,mjs,cjs,jsonc}",
|
|
10
|
-
".markdownlint-cli2.{jsonc,cjs,mjs}",
|
|
11
|
-
"commitlint.config.{js,cjs,mjs}"
|
|
12
|
-
],
|
|
13
|
-
"project": ["**/*.{js,mjs,cjs,jsx,ts,tsx,mts,cts}"],
|
|
14
|
-
"ignore": ["**/__fixtures__/**"],
|
|
15
|
-
"ignoreDependencies": ["@nitra/cspell-dict", "/@cspell\\/dict-.+/", "graphql"],
|
|
16
|
-
"ignoreBinaries": [
|
|
17
|
-
"actionlint",
|
|
18
|
-
"cspell",
|
|
19
|
-
"eslint",
|
|
20
|
-
"git-ai",
|
|
21
|
-
"jscpd",
|
|
22
|
-
"markdownlint-cli2",
|
|
23
|
-
"oxfmt",
|
|
24
|
-
"oxlint",
|
|
25
|
-
"shellcheck",
|
|
26
|
-
"uvx",
|
|
27
|
-
"v8r",
|
|
28
|
-
"zizmor"
|
|
29
|
-
]
|
|
30
|
-
}
|