@7n/rules 1.27.0 → 1.28.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/CHANGELOG.md +12 -0
- package/package.json +1 -5
- package/schemas/v8r-catalog.json +10 -1
- 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
package/rules/js/check/main.mjs
DELETED
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
/** @see ./docs/tooling.md */
|
|
2
|
-
import { existsSync } from 'node:fs'
|
|
3
|
-
import { copyFile, readFile } from 'node:fs/promises'
|
|
4
|
-
import { join } from 'node:path'
|
|
5
|
-
|
|
6
|
-
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
KNIP_CANONICAL_JSON_PATH,
|
|
10
|
-
OXLINT_CANONICAL_JSON_PATH,
|
|
11
|
-
OXLINTRC_DRIFT,
|
|
12
|
-
OXLINTRC_MISSING,
|
|
13
|
-
verifyOxlintRcAgainstCanonical
|
|
14
|
-
} from '../tooling/main.mjs'
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
AUTO_IMPORTS_IGNORE,
|
|
18
|
-
ESLINT_CONFIG_IGNORES,
|
|
19
|
-
ESLINT_CONFIG_MISSING,
|
|
20
|
-
ESLINT_CONFIG_VUE_WORKSPACE,
|
|
21
|
-
detectWorkspaceTypes,
|
|
22
|
-
parseVueList
|
|
23
|
-
} from './eslint-config.mjs'
|
|
24
|
-
|
|
25
|
-
const NON_DIGITS_RE = /\D+/u
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Перевіряє ESLint flat config файл.
|
|
29
|
-
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
30
|
-
* @param {(msg: string) => void} failFn callback при помилці
|
|
31
|
-
* @param {string} cwd корінь репозиторію
|
|
32
|
-
*/
|
|
33
|
-
async function checkEslintConfig(passFn, failFn, cwd) {
|
|
34
|
-
let eslintPath
|
|
35
|
-
if (existsSync(join(cwd, 'eslint.config.js'))) {
|
|
36
|
-
eslintPath = 'eslint.config.js'
|
|
37
|
-
passFn('eslint.config.js існує')
|
|
38
|
-
} else if (existsSync(join(cwd, 'eslint.config.mjs'))) {
|
|
39
|
-
eslintPath = 'eslint.config.mjs'
|
|
40
|
-
passFn('eslint.config.mjs існує')
|
|
41
|
-
} else {
|
|
42
|
-
failFn('Відсутній eslint.config.js або eslint.config.mjs — flat config з getConfig (js.mdc)', ESLINT_CONFIG_MISSING)
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
const eslintRaw = await readFile(join(cwd, eslintPath), 'utf8')
|
|
46
|
-
const checks = [
|
|
47
|
-
{
|
|
48
|
-
needle: 'getConfig',
|
|
49
|
-
ok: `${eslintPath}: містить getConfig`,
|
|
50
|
-
err: `${eslintPath}: потрібен виклик getConfig (js.mdc)`
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
needle: '@nitra/eslint-config',
|
|
54
|
-
ok: `${eslintPath}: імпорт @nitra/eslint-config`,
|
|
55
|
-
err: `${eslintPath}: імпортуй getConfig з @nitra/eslint-config`
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
needle: AUTO_IMPORTS_IGNORE,
|
|
59
|
-
ok: `${eslintPath}: ignores містить ${AUTO_IMPORTS_IGNORE}`,
|
|
60
|
-
err: `${eslintPath}: додай у ignores запис ${AUTO_IMPORTS_IGNORE} (js.mdc)`,
|
|
61
|
-
reason: ESLINT_CONFIG_IGNORES
|
|
62
|
-
}
|
|
63
|
-
]
|
|
64
|
-
for (const { needle, ok, err, reason } of checks) {
|
|
65
|
-
if (eslintRaw.includes(needle)) {
|
|
66
|
-
passFn(ok)
|
|
67
|
-
} else {
|
|
68
|
-
failFn(err, reason)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
await checkEslintWorkspaceTypes(eslintRaw, eslintPath, passFn, failFn, cwd)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Кожен vue-воркспейс (детекція: `workspaces` root package.json + vue-залежність
|
|
76
|
-
* або `.vue` файли) має бути у `vue: [...]` аргументах getConfig — інакше eslint
|
|
77
|
-
* не підключає vue-parser і всі `.vue` файли воркспейсу не парсяться. Ловить
|
|
78
|
-
* хибний scaffold типу `getConfig({ node: ['npm'] })` у vue-монорепо.
|
|
79
|
-
* @param {string} eslintRaw вміст eslint.config
|
|
80
|
-
* @param {string} eslintPath ім'я файлу конфігу для повідомлень
|
|
81
|
-
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
82
|
-
* @param {(msg: string, reason?: string) => void} failFn callback при помилці
|
|
83
|
-
* @param {string} cwd корінь репозиторію
|
|
84
|
-
*/
|
|
85
|
-
async function checkEslintWorkspaceTypes(eslintRaw, eslintPath, passFn, failFn, cwd) {
|
|
86
|
-
const types = await detectWorkspaceTypes(cwd)
|
|
87
|
-
if (types.vue.length === 0) return
|
|
88
|
-
const vueEntries = parseVueList(eslintRaw)
|
|
89
|
-
for (const ws of types.vue) {
|
|
90
|
-
if (vueEntries.includes(ws)) {
|
|
91
|
-
passFn(`${eslintPath}: vue-воркспейс '${ws}' у vue: [...]`)
|
|
92
|
-
} else {
|
|
93
|
-
failFn(
|
|
94
|
-
`${eslintPath}: воркспейс '${ws}' містить Vue-код, але відсутній у vue: [...] getConfig — ` +
|
|
95
|
-
'.vue файли не парсяться (js.mdc)',
|
|
96
|
-
ESLINT_CONFIG_VUE_WORKSPACE
|
|
97
|
-
)
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Перевірки `prettier` / `@nitra/prettier-config` у залежностях (text.mdc) і
|
|
103
|
-
// `@nitra/eslint-config ≥ 3.10.0` тепер у Rego: відповідно
|
|
104
|
-
// `npm/policy/text/package_json/` і `npm/policy/js_lint/package_json/`. Тут
|
|
105
|
-
// лишилася лише workspace-ітерація для `type: "module"` і engines, бо js_lint
|
|
106
|
-
// Rego запускається лише на кореневому `package.json`.
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Перевіряє, що package.json має `"type": "module"`.
|
|
110
|
-
* @param {string} label шлях або назва пакета для повідомлень
|
|
111
|
-
* @param {{ type?: string }} pkg parsed package.json
|
|
112
|
-
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
113
|
-
* @param {(msg: string) => void} failFn callback при помилці
|
|
114
|
-
*/
|
|
115
|
-
function checkPackageJsonTypeModule(label, pkg, passFn, failFn) {
|
|
116
|
-
if (pkg.type === 'module') {
|
|
117
|
-
passFn(`${label}: "type": "module"`)
|
|
118
|
-
} else {
|
|
119
|
-
failFn(`${label}: має містити "type": "module" (js.mdc)`)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* `"type": "module"`, `engines.node >= 24` і `engines.bun >= 1.3` у кожному workspace `package.json`.
|
|
125
|
-
* @param {unknown[]} workspaces поле workspaces з package.json
|
|
126
|
-
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
127
|
-
* @param {(msg: string) => void} failFn callback при помилці
|
|
128
|
-
* @param {string} cwd корінь репозиторію
|
|
129
|
-
*/
|
|
130
|
-
async function checkWorkspacePackages(workspaces, passFn, failFn, cwd) {
|
|
131
|
-
for (const ws of workspaces) {
|
|
132
|
-
const wsPkgRel = `${ws}/package.json`
|
|
133
|
-
const wsPkgAbs = join(cwd, wsPkgRel)
|
|
134
|
-
if (existsSync(wsPkgAbs)) {
|
|
135
|
-
const wsPkg = JSON.parse(await readFile(wsPkgAbs, 'utf8'))
|
|
136
|
-
checkPackageJsonTypeModule(wsPkgRel, wsPkg, passFn, failFn)
|
|
137
|
-
checkEnginesNode(wsPkgRel, wsPkg, passFn, failFn)
|
|
138
|
-
checkEnginesBun(wsPkgRel, wsPkg, passFn, failFn)
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* engines.node >= 24.
|
|
145
|
-
* @param {string} label шлях або назва пакета для повідомлень
|
|
146
|
-
* @param {{ engines?: { node?: string } }} pkg розпарсений package.json
|
|
147
|
-
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
148
|
-
* @param {(msg: string) => void} failFn callback при помилці
|
|
149
|
-
*/
|
|
150
|
-
function checkEnginesNode(label, pkg, passFn, failFn) {
|
|
151
|
-
const nodeEngine = pkg.engines?.node
|
|
152
|
-
if (nodeEngine) {
|
|
153
|
-
const firstNumeric = String(nodeEngine).split(NON_DIGITS_RE).find(Boolean)
|
|
154
|
-
if (firstNumeric && Number(firstNumeric) >= 24) {
|
|
155
|
-
passFn(`${label}: engines.node "${nodeEngine}"`)
|
|
156
|
-
} else {
|
|
157
|
-
failFn(`${label}: engines.node "${nodeEngine}" — має бути >=24`)
|
|
158
|
-
}
|
|
159
|
-
} else {
|
|
160
|
-
failFn(`${label} не містить engines.node — додай: "engines": { "node": ">=24" }`)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* engines.bun >= 1.3.
|
|
166
|
-
* @param {string} label шлях або назва пакета для повідомлень
|
|
167
|
-
* @param {{ engines?: { bun?: string } }} pkg розпарсений package.json
|
|
168
|
-
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
169
|
-
* @param {(msg: string) => void} failFn callback при помилці
|
|
170
|
-
*/
|
|
171
|
-
function checkEnginesBun(label, pkg, passFn, failFn) {
|
|
172
|
-
const bunEngine = pkg.engines?.bun
|
|
173
|
-
if (bunEngine) {
|
|
174
|
-
const [major, minor] = String(bunEngine).split(NON_DIGITS_RE).filter(Boolean).map(Number)
|
|
175
|
-
if (Number.isFinite(major) && Number.isFinite(minor) && (major > 1 || (major === 1 && minor >= 3))) {
|
|
176
|
-
passFn(`${label}: engines.bun "${bunEngine}"`)
|
|
177
|
-
} else {
|
|
178
|
-
failFn(`${label}: engines.bun "${bunEngine}" — має бути >=1.3`)
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
failFn(`${label} не містить engines.bun — додай: "engines": { "bun": ">=1.3" }`)
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Workspace-ітерація: для кожного workspace `package.json` перевіряємо
|
|
187
|
-
* `type: "module"` і `engines.{node,bun}`. Кореневий `package.json` ці поля
|
|
188
|
-
* валідує `npm/policy/js_lint/package_json/`; lint-js скрипт і `@nitra/eslint-config`
|
|
189
|
-
* — теж у Rego.
|
|
190
|
-
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
191
|
-
* @param {(msg: string) => void} failFn callback при помилці
|
|
192
|
-
* @param {string} cwd корінь репозиторію
|
|
193
|
-
*/
|
|
194
|
-
async function checkPackageJsonJsLint(passFn, failFn, cwd) {
|
|
195
|
-
const pkgPath = join(cwd, 'package.json')
|
|
196
|
-
if (!existsSync(pkgPath)) return
|
|
197
|
-
const pkg = JSON.parse(await readFile(pkgPath, 'utf8'))
|
|
198
|
-
const workspaces = Array.isArray(pkg.workspaces) ? pkg.workspaces : []
|
|
199
|
-
await checkWorkspacePackages(workspaces, passFn, failFn, cwd)
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Перевіряє .oxlintrc.json.
|
|
204
|
-
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
205
|
-
* @param {(msg: string) => void} failFn callback при помилці
|
|
206
|
-
* @param {string} cwd корінь репозиторію
|
|
207
|
-
*/
|
|
208
|
-
async function checkOxlintRc(passFn, failFn, cwd) {
|
|
209
|
-
const oxPath = join(cwd, '.oxlintrc.json')
|
|
210
|
-
if (!existsSync(oxPath)) {
|
|
211
|
-
failFn('.oxlintrc.json не існує — додай конфіг oxlint (js.mdc)', OXLINTRC_MISSING)
|
|
212
|
-
return
|
|
213
|
-
}
|
|
214
|
-
let oxCfg
|
|
215
|
-
try {
|
|
216
|
-
oxCfg = JSON.parse(await readFile(oxPath, 'utf8'))
|
|
217
|
-
} catch {
|
|
218
|
-
failFn('.oxlintrc.json не є валідним JSON')
|
|
219
|
-
return
|
|
220
|
-
}
|
|
221
|
-
passFn('.oxlintrc.json існує')
|
|
222
|
-
let canonical
|
|
223
|
-
try {
|
|
224
|
-
canonical = JSON.parse(await readFile(OXLINT_CANONICAL_JSON_PATH, 'utf8'))
|
|
225
|
-
} catch {
|
|
226
|
-
failFn('внутрішня помилка: не вдалося прочитати канон oxlint з пакета @7n/rules')
|
|
227
|
-
return
|
|
228
|
-
}
|
|
229
|
-
const oxV = verifyOxlintRcAgainstCanonical(oxCfg, canonical)
|
|
230
|
-
if (oxV.ok) {
|
|
231
|
-
passFn('.oxlintrc.json збігається з каноном oxlint (@7n/rules)')
|
|
232
|
-
} else {
|
|
233
|
-
for (const msg of oxV.failures) {
|
|
234
|
-
failFn(msg, OXLINTRC_DRIFT)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Cross-file перевірка: `lint.yml` (якщо існує) не дублює лінт JS-кроки з `lint-js.yml`.
|
|
241
|
-
* Existence і структуру `lint-js.yml` валідує mixin-концерн `js/lint_js_yml`
|
|
242
|
-
* плагіна `@7n/rules-ci-github` (провайдер-специфіка — поза ядром).
|
|
243
|
-
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
244
|
-
* @param {(msg: string) => void} failFn callback при помилці
|
|
245
|
-
* @param {string} cwd корінь репозиторію
|
|
246
|
-
*/
|
|
247
|
-
async function checkLintJsWorkflows(passFn, failFn, cwd) {
|
|
248
|
-
// Existence/структуру lint-js.yml вимагає провайдер-плагін @7n/rules-ci-github
|
|
249
|
-
// (mixin js/lint_js_yml, policy required) — ядро провайдер-агностичне і тут
|
|
250
|
-
// перевіряє лише крос-файловий дубляж, коли GitHub-workflow уже існують.
|
|
251
|
-
const lintYmlPath = join(cwd, '.github/workflows/lint.yml')
|
|
252
|
-
if (existsSync(lintYmlPath)) {
|
|
253
|
-
const lintYml = await readFile(lintYmlPath, 'utf8')
|
|
254
|
-
if (lintYml.includes('bunx oxlint') && lintYml.includes('bunx eslint') && lintYml.includes('jscpd')) {
|
|
255
|
-
failFn('.github/workflows/lint.yml дублює кроки lint-js.yml — залиш один workflow на лінт JS (js.mdc)')
|
|
256
|
-
} else {
|
|
257
|
-
passFn('.github/workflows/lint.yml не дублює oxlint/eslint/jscpd з lint-js.yml')
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Перевіряє наявність `knip.json` у корені проєкту. Якщо файл відсутній —
|
|
264
|
-
* копіює канонічний `knip-canonical.json` з пакета `@7n/rules` як стартовий
|
|
265
|
-
* baseline; зміст подальших модифікацій локально не валідується (`entry` /
|
|
266
|
-
* `project` / `ignore` / `ignoreDependencies` / `ignoreBinaries` дозволені
|
|
267
|
-
* будь-які; це side effect — описано у js.mdc).
|
|
268
|
-
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
269
|
-
* @param {(msg: string) => void} failFn callback при помилці
|
|
270
|
-
* @param {string} cwd корінь репозиторію
|
|
271
|
-
*/
|
|
272
|
-
async function checkKnipConfig(passFn, failFn, cwd) {
|
|
273
|
-
const knipPath = join(cwd, 'knip.json')
|
|
274
|
-
if (existsSync(knipPath)) {
|
|
275
|
-
passFn('knip.json існує')
|
|
276
|
-
return
|
|
277
|
-
}
|
|
278
|
-
if (!existsSync(KNIP_CANONICAL_JSON_PATH)) {
|
|
279
|
-
failFn(
|
|
280
|
-
`knip.json відсутній, і канонічний шаблон у пакеті не знайдено (${KNIP_CANONICAL_JSON_PATH}) — ` +
|
|
281
|
-
'перевстанови @7n/rules'
|
|
282
|
-
)
|
|
283
|
-
return
|
|
284
|
-
}
|
|
285
|
-
await copyFile(KNIP_CANONICAL_JSON_PATH, knipPath)
|
|
286
|
-
passFn('knip.json створено з канонічного npm/rules/js/tooling/data/tooling/knip-canonical.json (js.mdc)')
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Перевіряє відповідність проєкту правилам js.mdc
|
|
291
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту
|
|
292
|
-
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} перелік порушень
|
|
293
|
-
*/
|
|
294
|
-
export async function lint(ctx) {
|
|
295
|
-
const cwd = ctx.cwd
|
|
296
|
-
const reporter = createViolationReporter(ctx)
|
|
297
|
-
const { pass, fail } = reporter
|
|
298
|
-
|
|
299
|
-
await checkEslintConfig(pass, fail, cwd)
|
|
300
|
-
await checkPackageJsonJsLint(pass, fail, cwd)
|
|
301
|
-
await checkOxlintRc(pass, fail, cwd)
|
|
302
|
-
await checkLintJsWorkflows(pass, fail, cwd)
|
|
303
|
-
await checkKnipConfig(pass, fail, cwd)
|
|
304
|
-
|
|
305
|
-
for (const dup of ['.eslintrc', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yml']) {
|
|
306
|
-
if (existsSync(join(cwd, dup))) fail(`Знайдено застарілий конфіг ESLint: ${dup} — видали, використовуй flat config`)
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
return reporter.result()
|
|
310
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
## Залежнісна політика (що не додавати)
|
|
2
|
-
|
|
3
|
-
`@e18e/eslint-plugin` окремо не додавай — він уже в залежностях `@nitra/eslint-config` (з **3.8.0**), oxlint підвантажує його з `node_modules`. Пакети `oxlint`/`eslint`/`jscpd`/`knip` теж не додавай у `devDependencies` без потреби монорепо — `bunx` тягне їх ad-hoc.
|
|
4
|
-
|
|
5
|
-
### Заборона `ua-parser-js`
|
|
6
|
-
|
|
7
|
-
Пакет **`ua-parser-js`** заборонений починаючи з версії **2.x**, де ліцензія змінилась з MIT на **AGPL-3.0** — несумісну з комерційним використанням у закритому SaaS. Замінити на **`bowser`** (MIT, ~6 KB gzip):
|
|
8
|
-
|
|
9
|
-
```javascript title="❌ до"
|
|
10
|
-
import { UAParser } from 'ua-parser-js'
|
|
11
|
-
const parser = new UAParser(userAgent)
|
|
12
|
-
const result = parser.getResult()
|
|
13
|
-
const browserName = result.browser.name
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
```javascript title="✅ після"
|
|
17
|
-
import Bowser from 'bowser'
|
|
18
|
-
const browser = Bowser.getParser(userAgent)
|
|
19
|
-
const browserName = browser.getBrowserName()
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Bowser надає ті самі поля: `getBrowserName()`, `getOSName()`, `getPlatform().vendor`. Міграція займає кілька рядків; логіка не змінюється.
|
|
23
|
-
|
|
24
|
-
### Заборона `@nitra/as-integrations-fastify`
|
|
25
|
-
|
|
26
|
-
Пакет **`@nitra/as-integrations-fastify`** заборонений у **`dependencies`**, **`peerDependencies`** та в import-specifier-ах. Це чистий републіш upstream, застряглий на peer `@apollo/server: "^4.0.0"`, тож на Apollo 5 `bun install` дає `warn: incorrect peer dependency`. Заміна — upstream **`@as-integrations/fastify`** (**`^3.1.0`**): peer `@apollo/server: "^4.0.0 || ^5.0.0"` + `fastify: "^5.3.0"`.
|
|
27
|
-
|
|
28
|
-
Міграція — лише specifier у трьох місцях: залежність у `package.json`, `import`, та `vi.mock(...)` / `await import(...)` у тестах. **Код не міняється**, експорти ті самі: `default` → `fastifyApollo`, named → `fastifyApolloDrainPlugin`.
|
|
29
|
-
|
|
30
|
-
```javascript title="❌ до"
|
|
31
|
-
import fastifyApollo, { fastifyApolloDrainPlugin } from '@nitra/as-integrations-fastify'
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
```javascript title="✅ після"
|
|
35
|
-
import fastifyApollo, { fastifyApolloDrainPlugin } from '@as-integrations/fastify'
|
|
36
|
-
```
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/js/dep-policy/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 12ae4636
|
|
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
|
-
Файл сканує всі JS/TS-файли у поточному робочому каталозі, виключаючи конфігураційно визначені шляхи. Завдяки публічній функції main, він перевіряє відповідність усіх імпортів у коді політиці залежностей, визначеній у dep-policy.mdc. Ця **read-only** операція виявляє та фіксує будь-які імпорти, заборонені в dep-policy.mdc, надаючи підказки заміни з js.mdc. Механізм працює з fail-safe принципом, перехоплюючи помилки та не дозволяючи виняткам виходити назовні.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
Поведінка:
|
|
20
|
-
|
|
21
|
-
1. Виконується функція main.
|
|
22
|
-
2. Аналізуються всі JS/TS-файли у поточному робочому каталозі, виключаючи шляхи, визначені конфігурацією.
|
|
23
|
-
3. Для кожного файлу витягуються всі імпорти (статичні, динамічні та виклики require).
|
|
24
|
-
4. Знаходяться імпорти, які знаходяться у списку заборонених especifiers (dep-policy.mdc).
|
|
25
|
-
5. Якщо знайдений імпорт заборонений, реєструється помилка, яка вказує на шлях до файлу, заборонений імпорт та підказку про його заміну (js.mdc).
|
|
26
|
-
6. Після перевірки всіх файлів, якщо заборонених імпортів не знайдено, реєструється повідомлення про успішне завершення перевірки.
|
|
27
|
-
|
|
28
|
-
## Публічний API
|
|
29
|
-
|
|
30
|
-
main — перевіряє імпорти у файлах JavaScript та TypeScript на відповідність політиці залежностей.
|
|
31
|
-
|
|
32
|
-
## Гарантії поведінки
|
|
33
|
-
|
|
34
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
35
|
-
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/** @see ./docs/dep-policy.md */
|
|
2
|
-
import { readFile } from 'node:fs/promises'
|
|
3
|
-
import { relative } from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { parseSync } from 'oxc-parser'
|
|
6
|
-
|
|
7
|
-
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
8
|
-
import { loadCursorIgnorePaths } from '../../../scripts/lib/load-cursor-config.mjs'
|
|
9
|
-
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
10
|
-
import {
|
|
11
|
-
dynamicImportModule,
|
|
12
|
-
langFromPath,
|
|
13
|
-
requireCallModule,
|
|
14
|
-
walkAstWithAncestors
|
|
15
|
-
} from '../../../scripts/utils/ast-scan-utils.mjs'
|
|
16
|
-
|
|
17
|
-
const JS_SOURCE_RE = /\.(?:[cm]?[jt]sx?)$/u
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Пакети, заборонені як import-specifier у будь-якому JS/TS-файлі.
|
|
21
|
-
* Ключ — specifier, значення — підказка про заміну.
|
|
22
|
-
*/
|
|
23
|
-
const BANNED_SPECIFIERS = new Map([
|
|
24
|
-
['@nitra/as-integrations-fastify', 'використовуй @as-integrations/fastify'],
|
|
25
|
-
[
|
|
26
|
-
'ua-parser-js',
|
|
27
|
-
'замінити на bowser (MIT, ~6 KB) — npm i bowser. ua-parser-js v2 змінив ліцензію на AGPL-3.0, несумісну з комерційним використанням'
|
|
28
|
-
]
|
|
29
|
-
])
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Витягає з джерела всі import-specifier'и (static + dynamic + require).
|
|
33
|
-
* @param {string} source текст файлу
|
|
34
|
-
* @param {string} filePath шлях до файлу (для вибору мови OXC-парсера)
|
|
35
|
-
* @returns {string[]} список specifier'ів
|
|
36
|
-
*/
|
|
37
|
-
function extractImportSpecifiers(source, filePath) {
|
|
38
|
-
/** @type {string[]} */
|
|
39
|
-
const result = []
|
|
40
|
-
let parsed
|
|
41
|
-
try {
|
|
42
|
-
parsed = parseSync(filePath, source, { lang: langFromPath(filePath) })
|
|
43
|
-
} catch {
|
|
44
|
-
return result
|
|
45
|
-
}
|
|
46
|
-
for (const imp of parsed?.module?.staticImports ?? []) {
|
|
47
|
-
if (typeof imp?.moduleRequest?.value === 'string') result.push(imp.moduleRequest.value)
|
|
48
|
-
}
|
|
49
|
-
const program = parsed?.program
|
|
50
|
-
if (program && typeof program === 'object') {
|
|
51
|
-
walkAstWithAncestors(program, [], node => {
|
|
52
|
-
const dyn = dynamicImportModule(node)
|
|
53
|
-
if (dyn !== null) result.push(dyn)
|
|
54
|
-
const req = requireCallModule(node)
|
|
55
|
-
if (req !== null) result.push(req)
|
|
56
|
-
})
|
|
57
|
-
}
|
|
58
|
-
return result
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Сканує всі JS/TS-файли проєкту на заборонені import-specifier'и (dep-policy.mdc).
|
|
63
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту
|
|
64
|
-
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} Результат лінту з переліком порушень.
|
|
65
|
-
*/
|
|
66
|
-
export async function lint(ctx) {
|
|
67
|
-
const reporter = createViolationReporter(ctx)
|
|
68
|
-
const cwd = ctx.cwd
|
|
69
|
-
const ignorePaths = await loadCursorIgnorePaths(cwd)
|
|
70
|
-
|
|
71
|
-
const files = []
|
|
72
|
-
await walkDir(
|
|
73
|
-
cwd,
|
|
74
|
-
p => {
|
|
75
|
-
if (JS_SOURCE_RE.test(p)) files.push(p)
|
|
76
|
-
},
|
|
77
|
-
ignorePaths
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
let violations = 0
|
|
81
|
-
for (const absPath of files) {
|
|
82
|
-
const source = await readFile(absPath, 'utf8')
|
|
83
|
-
const specifiers = extractImportSpecifiers(source, absPath)
|
|
84
|
-
for (const spec of specifiers) {
|
|
85
|
-
const hint = BANNED_SPECIFIERS.get(spec)
|
|
86
|
-
if (hint !== undefined) {
|
|
87
|
-
const rel = relative(cwd, absPath)
|
|
88
|
-
reporter.fail(`${rel}: заборонений import '${spec}' — ${hint} (js.mdc dep-policy)`)
|
|
89
|
-
violations += 1
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (violations === 0) {
|
|
95
|
-
reporter.pass(`dep-policy: перевірено ${files.length} файлів — заборонених import-specifier'ів немає (js.mdc)`)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return reporter.result()
|
|
99
|
-
}
|
package/rules/js/docs/index.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: fix-eslint.mjs
|
|
4
|
-
resource: npm/rules/js/eslint/fix-eslint.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 31afb96e
|
|
7
|
-
model: manual
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Огляд
|
|
11
|
-
|
|
12
|
-
T0-autofix для `js/eslint`, два патерни в порядку застосування. `js-eslint-autofix`:
|
|
13
|
-
детермінований прогін лінтерів у fix-режимі (`oxlint --fix` + `eslint --fix`) по файлах, де
|
|
14
|
-
детектор знайшов порушення — виправляє лише авто-fixable правила. `js-eslint-mechanical-text-fix`:
|
|
15
|
-
для правил, які `--fix` НЕ покриває (suggestion-only у власній реалізації інструментів, перевірено
|
|
16
|
-
емпірично на реальних lint-прогонах), але заміна на позначеному `data.line` текстуально однозначна
|
|
17
|
-
й безпечна без AST-парсингу. Усе, що лишається непокритим — детектору на повторну перевірку, а
|
|
18
|
-
далі LLM-ладдеру. Запис незворотний (поза rollback).
|
|
19
|
-
|
|
20
|
-
## Поведінка
|
|
21
|
-
|
|
22
|
-
`js-eslint-autofix`:
|
|
23
|
-
- Збирає унікальні файли з порушень концерну, лишає лише js-сімейство (`.mjs/.cjs/.js/.jsx/.ts/.tsx/.vue`).
|
|
24
|
-
- Послідовно застосовує `oxlint --fix` (CLI) і `eslint --fix` (через API з `outputFixes`).
|
|
25
|
-
- До списку змінених потрапляють лише файли, чий вміст фактично змінився (порівняння до/після).
|
|
26
|
-
|
|
27
|
-
`js-eslint-mechanical-text-fix`:
|
|
28
|
-
- `MECHANICAL_TEXT_FIXES` — реєстр `{ reasons, replace }`: `reasons` покриває обидва формати
|
|
29
|
-
`violation.reason` (eslint `"plugin/rule"`, oxlint `"plugin(rule)"` — той самий rule різні тули
|
|
30
|
-
віддають по-різному); `replace(line)` — чиста функція рядка, `null` якщо шаблон не знайдено.
|
|
31
|
-
- Групує порушення за файлом, для кожного цільового `data.line` (1-indexed) застосовує
|
|
32
|
-
відповідну `replace`; рядок без очікуваного шаблону (файл змінився з моменту detect-у) —
|
|
33
|
-
пропускається без гадання.
|
|
34
|
-
- Наразі покриває `unicorn/prefer-number-is-safe-integer` (`Number.isInteger` → `Number.isSafeInteger`).
|
|
35
|
-
|
|
36
|
-
## Публічний API
|
|
37
|
-
|
|
38
|
-
- `patterns` — масив T0-патернів (`id` / `test` / `apply`), що його споживає центральний fix-pipeline:
|
|
39
|
-
`js-eslint-autofix` (лінтери в fix-режимі), `js-eslint-mechanical-text-fix` (текстові заміни для
|
|
40
|
-
suggestion-only правил).
|
|
41
|
-
|
|
42
|
-
## Гарантії поведінки
|
|
43
|
-
|
|
44
|
-
- `js-eslint-autofix`: якщо серед порушень немає js-файлів — лінтери не запускаються, змін немає.
|
|
45
|
-
- `js-eslint-mechanical-text-fix`: пише лише файли з реальною зміною рядка (шаблон збігся); не
|
|
46
|
-
чіпає рядки поза `MECHANICAL_TEXT_FIXES`-реєстром.
|
|
47
|
-
- Обидва патерни повертають лише фактично змінені файли; перед записом кожен реєструється через
|
|
48
|
-
`recordWrite`.
|
|
49
|
-
- Межа CI: модуль належить fix-фазі; у `--no-fix` (CI) не запускається — узгоджено із
|
|
50
|
-
забороною `oxlint --fix`/`eslint --fix` у CI.
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: fix-worker.mjs
|
|
4
|
-
resource: npm/rules/js/eslint/fix-worker.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 802ef1f3
|
|
7
|
-
model: manual
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Огляд
|
|
11
|
-
|
|
12
|
-
Custom fix-worker `js/eslint` (перекриває дефолтний `default-worker.mjs`): замість одного `runAgentFix`-виклику з усіма порушеннями з усіх файлів concern-а — окрема агентна сесія на кожен файл, ПАРАЛЕЛЬНО (обмежений пул, не більше `MAX_PARALLEL_FILES`). Мотивація й еволюція дизайну — `docs/adr/260718-0754-js-eslint-fix-worker-per-session-overhead.md`: послідовна версія стабільно впиралась у timeout на всіх 4 rung-ах драбини (local-min→cloud-avg); профайлінг реального прогону показав, що домінує кількість/довжина раундів моделі на файл, а не фіксовані bootstrap-витрати сесії — тож паралелізм (кілька файлів одночасно замість черги) дає пряме пришвидшення незалежно від причини.
|
|
13
|
-
|
|
14
|
-
## Поведінка
|
|
15
|
-
|
|
16
|
-
1. Групує вхідні `violations` за `file`; порушення без `file` ігноруються.
|
|
17
|
-
2. Дедлайн — `DEADLINE_FRACTION` (0.8) від `ctx.timeoutMs`; гейтить лише СТАРТ нового файлу з черги (не скасовує вже запущені).
|
|
18
|
-
3. `runPooled` — обмежений пул воркерів (`MAX_PARALLEL_FILES=4`): при `files.length ≤ MAX_PARALLEL_FILES` усі файли стартують майже одночасно й отримують практично весь бюджет незалежно один від одного; при більшій кількості черга природно звужує бюджет пізніших хвиль (`callTimeoutMs` рахується в момент старту файлу з черги, не наперед).
|
|
19
|
-
4. На кожен файл — окремий `runAgentFix` із `targetFiles: [file]` і власним `verify` (`verifyFile`): item-scoped canonical re-detect лише цього файлу, не всього concern-а — інакше evidence-гейт хибно вважав би файл незакритим через порушення в ІНШИХ файлах.
|
|
20
|
-
5. Один файл, що завершився з `error` АБО кинув виняток (try/catch у тілі воркера), не обриває пул — пропускається, решта файлів обробляються незалежно.
|
|
21
|
-
6. Повертає лише `touchedFiles` з успішних (`!error`) викликів; success rung-а все одно визначає whole-concern canonical re-detect runner-а (`runRung`), не цей worker.
|
|
22
|
-
|
|
23
|
-
## Публічний API
|
|
24
|
-
|
|
25
|
-
- `fixWorker(violations, ctx)` — контракт `FixWorkerFn`; резолвиться автоматично замість `default-worker.mjs`, бо лежить як `fix-worker.mjs` поруч із `main.mjs` concern-а.
|
|
26
|
-
|
|
27
|
-
## Гарантії поведінки
|
|
28
|
-
|
|
29
|
-
- Пише лише у файли з переданих `violations` (`targetFiles: [file]` на кожен виклик) — той самий semantic-collateral guard, що й у дефолтного worker-а.
|
|
30
|
-
- `recordWrite` (не durable) на кожен файл: rollback-контракт незмінний — якщо після worker-а в concern-і лишилось хоч одне порушення будь-де, `runRung` відкочує ВСІ правки цього rung-а, включно з уже полагодженими файлами.
|
|
31
|
-
- Конкурентні виклики `recordWrite` безпечні: central snapshot — синхронні Map-операції без `await` усередині, event loop не перериває їх посеред виконання.
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: Directory Index
|
|
3
|
-
title: npm/rules/js/eslint
|
|
4
|
-
resource: npm/rules/js/eslint/
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
| Файл | Тип |
|
|
8
|
-
| ------------------------------- | --------- |
|
|
9
|
-
| [fix-eslint.mjs](fix-eslint.md) | JS Module |
|
|
10
|
-
| [fix-worker.mjs](fix-worker.md) | JS Module |
|
|
11
|
-
| [main.mjs](main.md) | JS Module |
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/js/eslint/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: e831a6e8
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
score: 100
|
|
9
|
-
issues: judge:inaccurate:0.99
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
Цей файл надає публічний інтерфейс для валідації коду, використовуючи інструменти Oxlint та ESLint. Він дозволяє визначати набір JavaScript-файлів для аналізу через функцію `filterJsFiles` та виконувати сам процес лінтингу за допомогою функції `lint`. Компонент є read-only, оскільки не здійснює змін до файлової системи чи баз даних. У разі виявлення помилок, механізм забезпечує fail-safe режим, перехоплюючи їх та не викликаючи винятків назовні.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
Поведінка:
|
|
20
|
-
filterJsFiles фільтрує список вказаних файлів, залишаючи лише ті, що відповідають розширенням JavaScript.
|
|
21
|
-
lint запускає лінтинг для файлів. Якщо передаються файли, він аналізує їх на наявність порушень; якщо не передані, він виконує повний аналіз проекту.
|
|
22
|
-
|
|
23
|
-
## Публічний API
|
|
24
|
-
|
|
25
|
-
filterJsFiles — відбирає файли для подальшої обробки.
|
|
26
|
-
lint — проводить статичний аналіз коду (пофайлово або по всьому проєкту).
|
|
27
|
-
|
|
28
|
-
## Гарантії поведінки
|
|
29
|
-
|
|
30
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
31
|
-
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
32
|
-
|
|
33
|
-
**warnIgnored: false.** ESLint конструюється з `warnIgnored: false` — файли з delta-списку, що матчать ignore-патерни `eslint.config.js` (наприклад, синковані `.pi/extensions/**` чи згенеровані `npm/types/**`), не рахуються порушеннями.
|
|
34
|
-
|
|
35
|
-
**Worktree-чекаути ігноруються.** Обидва інструменти виключають `.worktrees/**` і `.claude/worktrees/**` (копії репо від сесійних git-worktree, яких споживацький конфіг зазвичай не виключає): ESLint — через global ignores у `overrideConfig`, oxlint — через `--ignore-pattern`. Діє і у full-режимі, і для явно переданих файлів.
|