@7n/rules-lang-js 0.3.1 → 0.4.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 +14 -4
- package/rules/bun/bunfig/bunfig.mdc +17 -0
- package/rules/bun/bunfig/bunfig.rego +29 -0
- package/rules/bun/bunfig/concern.json +9 -0
- package/rules/bun/bunfig/template/bunfig.toml.snippet.toml +2 -0
- package/rules/bun/docs/index.md +11 -0
- package/rules/bun/layout/concern.json +16 -0
- package/rules/bun/layout/docs/fix-layout.md +29 -0
- package/rules/bun/layout/docs/main.md +34 -0
- package/rules/bun/layout/fix-layout.mjs +63 -0
- package/rules/bun/layout/layout.mdc +60 -0
- package/rules/bun/layout/main.mjs +53 -0
- package/rules/bun/licensee/concern.json +7 -0
- package/rules/bun/licensee/docs/fix-licensee.md +27 -0
- package/rules/bun/licensee/docs/index.md +12 -0
- package/rules/bun/licensee/docs/main.md +30 -0
- package/rules/bun/licensee/fix-licensee.mjs +31 -0
- package/rules/bun/licensee/main.mjs +68 -0
- package/rules/bun/lint-surface/concern.json +3 -0
- package/rules/bun/lint-surface/lint-surface.mdc +13 -0
- package/rules/bun/main.json +1 -0
- package/rules/bun/main.mdc +11 -0
- package/rules/bun/package_json/concern.json +9 -0
- package/rules/bun/package_json/docs/fix-package_json.md +28 -0
- package/rules/bun/package_json/docs/index.md +9 -0
- package/rules/bun/package_json/fix-package_json.mjs +311 -0
- package/rules/bun/package_json/package_json.mdc +14 -0
- package/rules/bun/package_json/package_json.rego +64 -0
- package/rules/bun/package_json/template/package.json.deny.json +4 -0
- package/rules/js/check/check.mdc +26 -0
- package/rules/js/check/concern.json +19 -0
- package/rules/js/check/docs/eslint-config.md +56 -0
- package/rules/js/check/docs/fix-check.md +48 -0
- package/rules/js/check/docs/index.md +13 -0
- package/rules/js/check/docs/main.md +48 -0
- package/rules/js/check/eslint-config.mjs +262 -0
- package/rules/js/check/fix-check.mjs +82 -0
- package/rules/js/check/main.mjs +310 -0
- package/rules/js/dep-policy/concern.json +4 -0
- package/rules/js/dep-policy/dep-policy.mdc +36 -0
- package/rules/js/dep-policy/docs/main.md +35 -0
- package/rules/js/dep-policy/main.mjs +99 -0
- package/rules/js/docs/index.md +11 -0
- package/rules/js/eslint/concern.json +8 -0
- package/rules/js/eslint/docs/fix-eslint.md +50 -0
- package/rules/js/eslint/docs/fix-worker.md +31 -0
- package/rules/js/eslint/docs/index.md +11 -0
- package/rules/js/eslint/docs/main.md +35 -0
- package/rules/js/eslint/fix-eslint.mjs +160 -0
- package/rules/js/eslint/fix-worker.mjs +139 -0
- package/rules/js/eslint/main.mjs +115 -0
- package/rules/js/file-extensions/concern.json +3 -0
- package/rules/js/file-extensions/file-extensions.mdc +12 -0
- package/rules/js/jscpd_config/concern.json +11 -0
- package/rules/js/jscpd_config/docs/fix-jscpd_config.md +25 -0
- package/rules/js/jscpd_config/docs/index.md +9 -0
- package/rules/js/jscpd_config/fix-jscpd_config.mjs +3 -0
- package/rules/js/jscpd_config/jscpd_config.mdc +42 -0
- package/rules/js/jscpd_config/jscpd_config.rego +44 -0
- package/rules/js/jscpd_config/template/.jscpd.json.snippet.json +7 -0
- package/rules/js/jscpd_duplicates/concern.json +7 -0
- package/rules/js/jscpd_duplicates/docs/main.md +29 -0
- package/rules/js/jscpd_duplicates/main.mjs +69 -0
- package/rules/js/knip/concern.json +7 -0
- package/rules/js/knip/docs/main.md +32 -0
- package/rules/js/knip/knip.mdc +15 -0
- package/rules/js/knip/main.mjs +68 -0
- package/rules/js/lint-findings/concern.json +3 -0
- package/rules/js/lint-findings/docs/main.md +40 -0
- package/rules/js/lint-findings/main.mjs +125 -0
- package/rules/js/main.json +1 -0
- package/rules/js/main.mdc +18 -0
- package/rules/js/package_json/concern.json +9 -0
- package/rules/js/package_json/docs/fix-package_json.md +25 -0
- package/rules/js/package_json/docs/index.md +9 -0
- package/rules/js/package_json/fix-package_json.mjs +3 -0
- package/rules/js/package_json/package_json.mdc +15 -0
- package/rules/js/package_json/package_json.rego +142 -0
- package/rules/js/package_json/template/package.json.snippet.json +6 -0
- package/rules/js/tooling/concern.json +3 -0
- package/rules/js/tooling/data/tooling/knip-canonical.json +30 -0
- package/rules/js/tooling/data/tooling/oxlint-canonical.json +400 -0
- package/rules/js/tooling/docs/main.md +53 -0
- package/rules/js/tooling/main.mjs +183 -0
- package/rules/js/utils_imports/concern.json +4 -0
- package/rules/js/utils_imports/docs/main.md +50 -0
- package/rules/js/utils_imports/main.mjs +185 -0
- package/rules/js/utils_imports/utils_imports.mdc +15 -0
- package/rules/js/vscode_extensions/concern.json +11 -0
- package/rules/js/vscode_extensions/docs/fix-vscode_extensions.md +24 -0
- package/rules/js/vscode_extensions/docs/index.md +11 -0
- package/rules/js/vscode_extensions/fix-vscode_extensions.mjs +1 -0
- package/rules/js/vscode_extensions/template/extensions.json.snippet.json +6 -0
- package/rules/js/vscode_extensions/vscode_extensions.mdc +11 -0
- package/rules/js/vscode_extensions/vscode_extensions.rego +12 -0
- package/rules/js-bun-db/connection/concern.json +3 -0
- package/rules/js-bun-db/connection/connection.mdc +42 -0
- package/rules/js-bun-db/docs/index.md +11 -0
- package/rules/js-bun-db/lib/bun-sql-scan.mjs +1047 -0
- package/rules/js-bun-db/lib/docs/bun-sql-scan.md +63 -0
- package/rules/js-bun-db/lib/docs/index.md +11 -0
- package/rules/js-bun-db/main.json +1 -0
- package/rules/js-bun-db/main.mdc +8 -0
- package/rules/js-bun-db/package_json/concern.json +9 -0
- package/rules/js-bun-db/package_json/package_json.mdc +31 -0
- package/rules/js-bun-db/package_json/package_json.rego +15 -0
- package/rules/js-bun-db/package_json/template/package.json.deny.json +6 -0
- package/rules/js-bun-db/pg_format_identifiers/concern.json +3 -0
- package/rules/js-bun-db/pg_format_identifiers/pg_format_identifiers.mdc +104 -0
- package/rules/js-bun-db/safety/concern.json +4 -0
- package/rules/js-bun-db/safety/docs/main.md +34 -0
- package/rules/js-bun-db/safety/main.mjs +430 -0
- package/rules/js-bun-db/safety/safety.mdc +458 -0
- package/rules/js-bun-redis/docs/index.md +11 -0
- package/rules/js-bun-redis/imports/concern.json +4 -0
- package/rules/js-bun-redis/imports/docs/main.md +36 -0
- package/rules/js-bun-redis/imports/imports.mdc +47 -0
- package/rules/js-bun-redis/imports/main.mjs +88 -0
- package/rules/js-bun-redis/lib/docs/index.md +11 -0
- package/rules/js-bun-redis/lib/docs/redis-imports.md +227 -0
- package/rules/js-bun-redis/lib/redis-imports.mjs +130 -0
- package/rules/js-bun-redis/main.json +1 -0
- package/rules/js-bun-redis/main.mdc +8 -0
- package/rules/js-bun-redis/package_json/concern.json +9 -0
- package/rules/js-bun-redis/package_json/package_json.mdc +11 -0
- package/rules/js-bun-redis/package_json/package_json.rego +15 -0
- package/rules/js-bun-redis/package_json/template/package.json.deny.json +12 -0
- package/rules/js-mssql/deps/concern.json +4 -0
- package/rules/js-mssql/deps/docs/main.md +33 -0
- package/rules/js-mssql/deps/main.mjs +297 -0
- package/rules/js-mssql/docs/index.md +11 -0
- package/rules/js-mssql/lib/docs/index.md +11 -0
- package/rules/js-mssql/lib/docs/mssql-pool-scan.md +380 -0
- package/rules/js-mssql/lib/mssql-pool-scan.mjs +610 -0
- package/rules/js-mssql/main.json +1 -0
- package/rules/js-mssql/main.mdc +144 -0
- package/rules/js-mssql/mssql-tvp/concern.json +3 -0
- package/rules/js-mssql/mssql-tvp/mssql-tvp.mdc +77 -0
- package/rules/js-mssql/package_json/concern.json +9 -0
- package/rules/js-mssql/package_json/package_json.mdc +9 -0
- package/rules/js-mssql/package_json/package_json.rego +57 -0
- package/rules/js-run/configmap/concern.json +9 -0
- package/rules/js-run/configmap/configmap.mdc +37 -0
- package/rules/js-run/configmap/configmap.rego +21 -0
- package/rules/js-run/configmap/template/configmap.yaml.contains.yml +4 -0
- package/rules/js-run/docs/index.md +11 -0
- package/rules/js-run/jsconfig/concern.json +9 -0
- package/rules/js-run/jsconfig/docs/fix-jsconfig.md +28 -0
- package/rules/js-run/jsconfig/docs/index.md +9 -0
- package/rules/js-run/jsconfig/fix-jsconfig.mjs +119 -0
- package/rules/js-run/jsconfig/jsconfig.mdc +48 -0
- package/rules/js-run/jsconfig/jsconfig.rego +59 -0
- package/rules/js-run/jsconfig/template/jsconfig.json.snippet.json +10 -0
- package/rules/js-run/lib/bunyan-imports.mjs +98 -0
- package/rules/js-run/lib/check-env-scan.mjs +338 -0
- package/rules/js-run/lib/conn-file-rules.mjs +214 -0
- package/rules/js-run/lib/conn-imports-scan.mjs +154 -0
- package/rules/js-run/lib/docs/bunyan-imports.md +121 -0
- package/rules/js-run/lib/docs/check-env-scan.md +438 -0
- package/rules/js-run/lib/docs/conn-file-rules.md +304 -0
- package/rules/js-run/lib/docs/conn-imports-scan.md +208 -0
- package/rules/js-run/lib/docs/index.md +16 -0
- package/rules/js-run/lib/docs/promise-settimeout-scan.md +334 -0
- package/rules/js-run/lib/docs/temporal-scan.md +29 -0
- package/rules/js-run/lib/promise-settimeout-scan.mjs +128 -0
- package/rules/js-run/lib/temporal-scan.mjs +52 -0
- package/rules/js-run/main.json +1 -0
- package/rules/js-run/main.mdc +16 -0
- package/rules/js-run/package_json/concern.json +9 -0
- package/rules/js-run/package_json/package_json.mdc +44 -0
- package/rules/js-run/package_json/package_json.rego +37 -0
- package/rules/js-run/package_json/template/package.json.deny.json +22 -0
- package/rules/js-run/project-structure/concern.json +3 -0
- package/rules/js-run/project-structure/project-structure.mdc +11 -0
- package/rules/js-run/runtime/concern.json +12 -0
- package/rules/js-run/runtime/docs/fix-runtime.md +27 -0
- package/rules/js-run/runtime/docs/main.md +35 -0
- package/rules/js-run/runtime/fix-runtime.mjs +46 -0
- package/rules/js-run/runtime/main.mjs +496 -0
- package/rules/js-run/runtime/runtime.mdc +184 -0
- package/rules/js-run/scope/concern.json +3 -0
- package/rules/js-run/scope/scope.mdc +11 -0
- package/rules/npm-module/docs/index.md +11 -0
- package/rules/npm-module/emit_types_config/concern.json +9 -0
- package/rules/npm-module/emit_types_config/docs/fix-emit_types_config.md +25 -0
- package/rules/npm-module/emit_types_config/docs/index.md +9 -0
- package/rules/npm-module/emit_types_config/emit_types_config.mdc +43 -0
- package/rules/npm-module/emit_types_config/emit_types_config.rego +28 -0
- package/rules/npm-module/emit_types_config/fix-emit_types_config.mjs +5 -0
- package/rules/npm-module/emit_types_config/template/tsconfig.emit-types.json.snippet.json +9 -0
- package/rules/npm-module/header_doc_pointer/concern.json +5 -0
- package/rules/npm-module/header_doc_pointer/docs/main.md +40 -0
- package/rules/npm-module/header_doc_pointer/header_doc_pointer.mdc +18 -0
- package/rules/npm-module/header_doc_pointer/main.mjs +131 -0
- package/rules/npm-module/main.json +1 -0
- package/rules/npm-module/main.mdc +36 -0
- package/rules/npm-module/npm_package_json/concern.json +9 -0
- package/rules/npm-module/npm_package_json/docs/fix-npm_package_json.md +26 -0
- package/rules/npm-module/npm_package_json/docs/index.md +9 -0
- package/rules/npm-module/npm_package_json/fix-npm_package_json.mjs +5 -0
- package/rules/npm-module/npm_package_json/npm_package_json.mdc +57 -0
- package/rules/npm-module/npm_package_json/npm_package_json.rego +73 -0
- package/rules/npm-module/npm_package_json/template/package.json.snippet.json +1 -0
- package/rules/npm-module/package_structure/concern.json +5 -0
- package/rules/npm-module/package_structure/docs/main.md +37 -0
- package/rules/npm-module/package_structure/main.mjs +448 -0
- package/rules/npm-module/package_structure/package_structure.mdc +63 -0
- package/rules/npm-module/root_package_json/concern.json +9 -0
- package/rules/npm-module/root_package_json/docs/fix-root_package_json.md +25 -0
- package/rules/npm-module/root_package_json/docs/index.md +9 -0
- package/rules/npm-module/root_package_json/fix-root_package_json.mjs +5 -0
- package/rules/npm-module/root_package_json/root_package_json.mdc +41 -0
- package/rules/npm-module/root_package_json/root_package_json.rego +28 -0
- package/rules/npm-module/root_package_json/template/package.json.snippet.json +1 -0
- package/rules/npm-module/rule_meta/concern.json +8 -0
- package/rules/npm-module/rule_meta/docs/main.md +35 -0
- package/rules/npm-module/rule_meta/main.mjs +119 -0
- package/rules/npm-module/rule_meta/rule_meta.mdc +11 -0
- package/rules/npm-module/skill_meta/concern.json +5 -0
- package/rules/npm-module/skill_meta/docs/main.md +149 -0
- package/rules/npm-module/skill_meta/main.mjs +91 -0
- package/rules/npm-module/skill_meta/skill_meta.mdc +11 -0
- package/rules/tool-surface/docs/index.md +11 -0
- package/rules/tool-surface/main.json +6 -0
- package/rules/tool-surface/main.mdc +72 -0
- package/rules/vue/composition-api/composition-api.mdc +82 -0
- package/rules/vue/composition-api/concern.json +3 -0
- package/rules/vue/docs/index.md +11 -0
- package/rules/vue/lib/docs/index.md +11 -0
- package/rules/vue/lib/docs/vue-forbidden-imports.md +265 -0
- package/rules/vue/lib/vue-forbidden-imports.mjs +240 -0
- package/rules/vue/main.json +1 -0
- package/rules/vue/main.mdc +18 -0
- package/rules/vue/nheader-layout/concern.json +3 -0
- package/rules/vue/nheader-layout/nheader-layout.mdc +171 -0
- package/rules/vue/package_json/concern.json +9 -0
- package/rules/vue/package_json/package_json.mdc +30 -0
- package/rules/vue/package_json/package_json.rego +140 -0
- package/rules/vue/packages/concern.json +6 -0
- package/rules/vue/packages/docs/index.md +11 -0
- package/rules/vue/packages/docs/main.md +35 -0
- package/rules/vue/packages/main.mjs +575 -0
- package/rules/vue/packages/packages.mdc +56 -0
- package/rules/vue/quasar-ui/concern.json +3 -0
- package/rules/vue/quasar-ui/quasar-ui.mdc +32 -0
- package/rules/vue/structure/concern.json +3 -0
- package/rules/vue/structure/structure.mdc +101 -0
- package/rules/vue/testing/concern.json +3 -0
- package/rules/vue/testing/testing.mdc +40 -0
- package/rules/vue/tfm-translations/concern.json +7 -0
- package/rules/vue/tfm-translations/docs/main.md +29 -0
- package/rules/vue/tfm-translations/main.mjs +55 -0
- package/rules/vue/tfm-translations/tfm-translations.mdc +32 -0
- package/rules/vue/vite-config/concern.json +3 -0
- package/rules/vue/vite-config/vite-config.mdc +153 -0
- package/rules/vue/vite-env/concern.json +3 -0
- package/rules/vue/vite-env/vite-env.mdc +61 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: main.mjs
|
|
4
|
+
resource: plugins/lang-js/rules/js/utils_imports/main.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: a705c81d
|
|
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
|
+
Огляд
|
|
16
|
+
Сканує всі каталоги `utils` у монорепозиторії, виявляючи джерела коду, уникаючи стандартних артефактів. Аналізує кожен рядковий імпорт, витягнутий із коду, порівнюючи його з шаблоном імпорту з батьківського каталогу. При виявленні невідповідностей фіксує помилки, вказуючи відносний шлях до файлу.
|
|
17
|
+
|
|
18
|
+
Поведінка
|
|
19
|
+
|
|
20
|
+
1. Ініціалізація перевірки відбувається через виклик функції `main`, яка працює в fail-safe режимі та перехоплює помилки, не викидаючи винятків назовні.
|
|
21
|
+
2. Робочий каталог системи слугує коренем репозиторію.
|
|
22
|
+
3. Конфігураційні шляхи, які мають бути виключені з перевірки (наприклад, `.git`, `node_modules`), завантажуються з файлу .n-rules.json.
|
|
23
|
+
4. Визначаються кореневі каталоги монорепозиторію.
|
|
24
|
+
5. Проводиться пошук усіх каталогів `utils` у всіх пакетах монорепозиторію, при цьому ігноруються каталоги, які є типовими артефактами (наприклад, `node_modules`, `.git`, `dist`, `coverage`, `.turbo`, `.next`, `__fixtures__`).
|
|
25
|
+
6. Для кожного знайденого каталогу `utils` збирається повний набір відповідних джерел коду, виходячи за межі підкаталогів `tests/` та `__fixtures__/`.
|
|
26
|
+
7. Вміст кожного зібраного джерела коду зчитується з файлів.
|
|
27
|
+
8. Використовується парсер для аналізу синтаксису з метою витягування всіх рядкових імпортів із коду.
|
|
28
|
+
9. Кожен витягнутий імпорт піддається перевірці на відповідність шаблону, що визначає імпорт з батьківського каталогу.
|
|
29
|
+
10. Якщо імпорт заборонений, фіксується помилка, яка вказує на відносний шлях до файлу, і реєструється обов'язковий маркер повідомлення (js.mdc).
|
|
30
|
+
11. Після завершення перевірки всіх файлів, якщо жодних порушень не знайдено, реєструється успішне завершення (js.mdc).
|
|
31
|
+
|
|
32
|
+
## Поведінка
|
|
33
|
+
|
|
34
|
+
1. Викликається функція `main` для ініціалізації перевірки.
|
|
35
|
+
2. Системний робочий каталог використовується для визначення кореня репозиторію.
|
|
36
|
+
3. Завантажуються конфігураційні шляхи, які ігнорують перевірку, з файлу .n-rules.json.
|
|
37
|
+
4. Знаходяться кореневі каталоги монорепозиторію.
|
|
38
|
+
5. Пошукаються всі каталоги з іменем `utils` у всіх пакетах монорепозиторію, при цьому пропускаються типові артефакти (наприклад, node_modules, .git, dist, coverage, .turbo, .next, **fixtures**).
|
|
39
|
+
6. Для кожного знайденого каталогу `utils` збираються всі відповідні джерела коду, виходячи за межі підкаталогів `tests/` та `__fixtures__/`.
|
|
40
|
+
7. Для кожного зібраного джерела коду зчитується вміст файлу.
|
|
41
|
+
8. Витягуються всі рядкові імпорти з коду, використовуючи парсер для аналізу синтаксису.
|
|
42
|
+
9. Кожен витягнутий імпорт перевіряється на відповідність шаблону, що вказує на імпорт з батьківського каталогу.
|
|
43
|
+
10. Якщо імпорт заборонений, фіксується помилка, яка вказує на відносний шлях до файлу.
|
|
44
|
+
11. Після перевірки усіх файлів, якщо порушень не знайдено, реєструється успішне завершення (js.mdc).
|
|
45
|
+
|
|
46
|
+
## Гарантії поведінки
|
|
47
|
+
|
|
48
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
49
|
+
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
50
|
+
- Свідомо пропускає шляхи: `.git`, `node_modules`.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/** @see ./docs/utils_imports.md */
|
|
2
|
+
import { readdir, readFile } from 'node:fs/promises'
|
|
3
|
+
import { join, relative, sep } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { parseSync } from 'oxc-parser'
|
|
6
|
+
|
|
7
|
+
import { createViolationReporter } from '@7n/rules/scripts/lib/lint-surface/violation-reporter.mjs'
|
|
8
|
+
import { loadCursorIgnorePaths } from '@7n/rules/scripts/lib/load-cursor-config.mjs'
|
|
9
|
+
import { getMonorepoPackageRootDirs } from '@7n/rules/scripts/lib/workspaces.mjs'
|
|
10
|
+
import {
|
|
11
|
+
dynamicImportModule,
|
|
12
|
+
langFromPath,
|
|
13
|
+
requireCallModule,
|
|
14
|
+
walkAstWithAncestors
|
|
15
|
+
} from '@7n/rules/scripts/utils/ast-scan-utils.mjs'
|
|
16
|
+
|
|
17
|
+
const JS_SOURCE_RE = /\.(?:[cm]?[jt]sx?)$/u
|
|
18
|
+
const TEST_FILE_RE = /\.test\.[cm]?[jt]sx?$/u
|
|
19
|
+
const PARENT_RELATIVE_RE = /^\.\.(?:\/|$)/u
|
|
20
|
+
const SKIP_DIR_NAMES = new Set(['node_modules', '.git', 'dist', 'coverage', '.turbo', '.next', '__fixtures__'])
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Чи каталог `dir` входить у список ignore (точний збіг або префікс).
|
|
24
|
+
* @param {string} dir абсолютний posix-шлях
|
|
25
|
+
* @param {string[]} ignorePaths абсолютні posix-шляхи з .n-rules.json
|
|
26
|
+
* @returns {boolean} true — пропускаємо
|
|
27
|
+
*/
|
|
28
|
+
function isIgnored(dir, ignorePaths) {
|
|
29
|
+
for (const p of ignorePaths) {
|
|
30
|
+
if (dir === p || dir.startsWith(`${p}/`)) return true
|
|
31
|
+
}
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Рекурсивно знаходить усі каталоги з ім'ям `utils` під `root` (пропускаючи типові артефакти).
|
|
37
|
+
* @param {string} root корінь
|
|
38
|
+
* @param {string[]} ignorePosix абс. posix-шляхи з ignore-конфігу
|
|
39
|
+
* @returns {Promise<string[]>} абсолютні шляхи знайдених `utils/`-каталогів
|
|
40
|
+
*/
|
|
41
|
+
async function findUtilsDirs(root, ignorePosix) {
|
|
42
|
+
const found = []
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} dir поточний каталог обходу
|
|
45
|
+
*/
|
|
46
|
+
async function walk(dir) {
|
|
47
|
+
let entries
|
|
48
|
+
try {
|
|
49
|
+
entries = await readdir(dir, { withFileTypes: true })
|
|
50
|
+
} catch {
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (!entry.isDirectory()) continue
|
|
55
|
+
if (SKIP_DIR_NAMES.has(entry.name)) continue
|
|
56
|
+
const full = join(dir, entry.name)
|
|
57
|
+
const posix = full.split(sep).join('/')
|
|
58
|
+
if (isIgnored(posix, ignorePosix)) continue
|
|
59
|
+
if (entry.name === 'utils') {
|
|
60
|
+
found.push(full)
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
await walk(full)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
await walk(root)
|
|
67
|
+
return found
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Збирає всі не-тестові `.[cm]?[jt]sx?` файли під `utilsDir` (включно з підкаталогами,
|
|
72
|
+
* крім `tests/` і `__fixtures__/`).
|
|
73
|
+
* @param {string} utilsDir абсолютний шлях `utils/`
|
|
74
|
+
* @returns {Promise<string[]>} абсолютні шляхи джерел
|
|
75
|
+
*/
|
|
76
|
+
async function collectUtilsSources(utilsDir) {
|
|
77
|
+
const out = []
|
|
78
|
+
/**
|
|
79
|
+
* @param {string} dir поточний каталог
|
|
80
|
+
*/
|
|
81
|
+
async function walk(dir) {
|
|
82
|
+
let entries
|
|
83
|
+
try {
|
|
84
|
+
entries = await readdir(dir, { withFileTypes: true })
|
|
85
|
+
} catch {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
const full = join(dir, entry.name)
|
|
90
|
+
if (entry.isDirectory()) {
|
|
91
|
+
if (entry.name === 'tests' || entry.name === '__fixtures__' || SKIP_DIR_NAMES.has(entry.name)) continue
|
|
92
|
+
await walk(full)
|
|
93
|
+
continue
|
|
94
|
+
}
|
|
95
|
+
if (entry.isFile() && JS_SOURCE_RE.test(entry.name) && !TEST_FILE_RE.test(entry.name)) {
|
|
96
|
+
out.push(full)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
await walk(utilsDir)
|
|
101
|
+
return out
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Витягає з джерела всі рядкові імпорт-source (статичні, динамічні, require). Помилки парсера
|
|
106
|
+
* не падають — спочатку треба полагодити синтаксис, потім перезапустити концерн.
|
|
107
|
+
* @param {string} source текст файлу
|
|
108
|
+
* @param {string} filePath шлях (для вибору мови)
|
|
109
|
+
* @returns {string[]} список source-рядків, як вони задані в коді
|
|
110
|
+
*/
|
|
111
|
+
function extractImportSources(source, filePath) {
|
|
112
|
+
/** @type {string[]} */
|
|
113
|
+
const sources = []
|
|
114
|
+
let parsed
|
|
115
|
+
try {
|
|
116
|
+
parsed = parseSync(filePath, source, { lang: langFromPath(filePath) })
|
|
117
|
+
} catch {
|
|
118
|
+
return sources
|
|
119
|
+
}
|
|
120
|
+
const staticImports = parsed?.module?.staticImports ?? []
|
|
121
|
+
for (const imp of staticImports) {
|
|
122
|
+
if (typeof imp?.moduleRequest?.value === 'string') {
|
|
123
|
+
sources.push(imp.moduleRequest.value)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const program = parsed?.program
|
|
127
|
+
if (program && typeof program === 'object') {
|
|
128
|
+
walkAstWithAncestors(program, [], node => {
|
|
129
|
+
const dyn = dynamicImportModule(node)
|
|
130
|
+
if (dyn !== null) sources.push(dyn)
|
|
131
|
+
const req = requireCallModule(node)
|
|
132
|
+
if (req !== null) sources.push(req)
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
return sources
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @param {import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту
|
|
140
|
+
* @returns {Promise<import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintResult>} результат лінту
|
|
141
|
+
*/
|
|
142
|
+
export async function lint(ctx) {
|
|
143
|
+
const reporter = createViolationReporter(ctx)
|
|
144
|
+
const root = ctx.cwd
|
|
145
|
+
const ignorePaths = await loadCursorIgnorePaths(root)
|
|
146
|
+
const ignorePosix = ignorePaths.map(p => p.split(sep).join('/'))
|
|
147
|
+
const packageRoots = await getMonorepoPackageRootDirs(root)
|
|
148
|
+
/** @type {Set<string>} */
|
|
149
|
+
const utilsDirSet = new Set()
|
|
150
|
+
for (const pkgRel of packageRoots) {
|
|
151
|
+
const pkgAbs = pkgRel === '.' ? root : join(root, pkgRel)
|
|
152
|
+
for (const utilsDir of await findUtilsDirs(pkgAbs, ignorePosix)) {
|
|
153
|
+
utilsDirSet.add(utilsDir)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (utilsDirSet.size === 0) {
|
|
157
|
+
reporter.pass('utils-каталогів немає — перевірку пропущено (js.mdc)')
|
|
158
|
+
return reporter.result()
|
|
159
|
+
}
|
|
160
|
+
let violations = 0
|
|
161
|
+
let checkedFiles = 0
|
|
162
|
+
for (const utilsDir of utilsDirSet) {
|
|
163
|
+
const sources = await collectUtilsSources(utilsDir)
|
|
164
|
+
for (const file of sources) {
|
|
165
|
+
checkedFiles += 1
|
|
166
|
+
const content = await readFile(file, 'utf8')
|
|
167
|
+
const imports = extractImportSources(content, file)
|
|
168
|
+
for (const src of imports) {
|
|
169
|
+
if (!PARENT_RELATIVE_RE.test(src)) {
|
|
170
|
+
continue
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const rel = relative(root, file)
|
|
174
|
+
reporter.fail(`${rel}: заборонений імпорт '${src}' — utils/-файли мають бути generic (js.mdc)`)
|
|
175
|
+
violations += 1
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (violations === 0) {
|
|
180
|
+
reporter.pass(
|
|
181
|
+
`utils-каталогів: ${utilsDirSet.size}, перевірено ${checkedFiles} файлів — domain-bound імпортів немає (js.mdc)`
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
return reporter.result()
|
|
185
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## Структура спільних модулів: `utils/` vs `lib/`
|
|
2
|
+
|
|
3
|
+
Коли спільні методи виносяться з кількох JS-файлів в окремий каталог — назву каталога обирай за призначенням модулів усередині.
|
|
4
|
+
|
|
5
|
+
- **`utils/`** — низькорівневі, чисті, generic helpers без бізнес-логіки і без залежностей від домену проєкту. Те, що могло б жити в окремому npm-пакеті. Приклади: `formatDate()`, `chunk(array, size)`, `retry(fn, opts)`, `deepMerge()`, `parseDuration('5m')`, `sleep(ms)`.
|
|
6
|
+
|
|
7
|
+
- **`lib/`** — внутрішні модулі / підсистеми проєкту, які знають про домен. Більші за `utils/`, часто з власним state, конфігом або side effects. Приклади: `lib/gmail-client.js`, `lib/circuit-breaker.js`, `lib/skill-loader.js`, `lib/safety/dry-run.js`.
|
|
8
|
+
|
|
9
|
+
Швидкий тест: якщо файл завтра можна опублікувати окремим npm-пакетом без переписування — це `utils/`; якщо він тримає domain-state, читає конфіг проєкту або викликає зовнішні сервіси/файли — це `lib/`. Не плутай із чужими каталогами на кшталт `shared/` чи `common/`: канонічні назви — лише `utils/` і `lib/`.
|
|
10
|
+
|
|
11
|
+
### Автоматична перевірка імпортів у `utils/`
|
|
12
|
+
|
|
13
|
+
`npx @7n/rules lint js` (концерн `utils_imports`) обходить кожен `utils/`-каталог у воркспейсах і падає, якщо знаходить relative-імпорт з `..` (вихід за межі каталогу) у будь-якому не-тестовому файлі. Це механічне втілення правила «utils не знає про домен»: тільки same-dir (`./X`), bare-пакети та `node:*` дозволені; cross-rule, конфіги проєкту чи sibling-utils — fail.
|
|
14
|
+
|
|
15
|
+
Якщо потрібна domain-залежність — перенеси файл у `lib/`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
|
|
3
|
+
"fixability": "config",
|
|
4
|
+
"policy": {
|
|
5
|
+
"files": {
|
|
6
|
+
"single": ".vscode/extensions.json",
|
|
7
|
+
"required": true
|
|
8
|
+
},
|
|
9
|
+
"missingMessage": ".vscode/extensions.json не існує — додай recommendations з js.mdc"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: fix-vscode_extensions.mjs
|
|
4
|
+
resource: plugins/lang-js/rules/js/vscode_extensions/fix-vscode_extensions.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: b6cffd44
|
|
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
|
+
Файл визначає шаблони, які використовуються для корекції компонентів VS Code. Він застосовує ці шаблони для забезпечення відповідності коду вимогам, визначеним у конфігураціях, а також для корекції помилок, описаних в [ANKOR_ISSUE_1] та [ANKOR_ISSUE_2].
|
|
16
|
+
|
|
17
|
+
## Поведінка
|
|
18
|
+
|
|
19
|
+
1. Ідентифікує шаблони, необхідні для корекції розширень VS Code.
|
|
20
|
+
2. Застосовує ці шаблони для приведення коду до відповідності стандартам.
|
|
21
|
+
|
|
22
|
+
## Гарантії поведінки
|
|
23
|
+
|
|
24
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Directory Index
|
|
3
|
+
title: npm/rules/js/vscode_extensions
|
|
4
|
+
resource: plugins/lang-js/rules/js/vscode_extensions/
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# npm/rules/js/vscode_extensions
|
|
8
|
+
|
|
9
|
+
| Файл | Тип |
|
|
10
|
+
| ----------------------------------------------------- | --------- |
|
|
11
|
+
| [fix-vscode_extensions.mjs](fix-vscode_extensions.md) | JS Module |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { patterns } from '@7n/rules/scripts/lib/fix/vscode-ext-add.mjs'
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Rego-gate `.vscode/extensions.json`
|
|
2
|
+
|
|
3
|
+
Rego-пакет: `js_lint.vscode_extensions`
|
|
4
|
+
|
|
5
|
+
Цільовий файл: `.vscode/extensions.json`.
|
|
6
|
+
|
|
7
|
+
Що перевіряється:
|
|
8
|
+
|
|
9
|
+
- `recommendations` — subset-of: масив має містити всі три канонічні розширення (`dbaeumer.vscode-eslint`, `github.vscode-github-actions`, `oxc.oxc-vscode`)
|
|
10
|
+
|
|
11
|
+
Канон-snippet: [extensions.json.snippet.json](./template/extensions.json.snippet.json)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Перевірка `.vscode/extensions.json` для js (js.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
+
package js.vscode_extensions
|
|
5
|
+
|
|
6
|
+
import rego.v1
|
|
7
|
+
|
|
8
|
+
deny contains msg if {
|
|
9
|
+
some rec in data.template.snippet.recommendations
|
|
10
|
+
not rec in {r | some r in object.get(input, "recommendations", [])}
|
|
11
|
+
msg := sprintf(".vscode/extensions.json: recommendations має містити %q (js.mdc)", [rec])
|
|
12
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
## Підключення (singleton + env)
|
|
2
|
+
|
|
3
|
+
Дефолтний експорт `sql` з `'bun'` сам читає змінні середовища (`DATABASE_URL`, `POSTGRES_URL`, `MYSQL_URL`, `PGHOST`/`PGUSER`/... та `MYSQL_HOST`/`MYSQL_USER`/...) і керує пулом — окремий `Pool` як у `pg` створювати не треба.
|
|
4
|
+
|
|
5
|
+
Для явного конфігу — `new SQL(...)` як **singleton** на рівні модуля, а не на кожен запит. Файл кладеться у `src/conn/db.mjs` і експортує іменовані константи `pgWrite` (основний запис) та `pgRead` (read-only replica), щоб glob `**/src/conn/**` у правилах покривав ці файли:
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
// src/conn/db.mjs
|
|
9
|
+
import { SQL } from 'bun'
|
|
10
|
+
|
|
11
|
+
export const pgWrite = new SQL({
|
|
12
|
+
url: process.env.DATABASE_URL,
|
|
13
|
+
max: 20,
|
|
14
|
+
idleTimeout: 30,
|
|
15
|
+
connectionTimeout: 10
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export const pgRead = new SQL({
|
|
19
|
+
url: process.env.PG_CONN_READ ?? process.env.DATABASE_URL,
|
|
20
|
+
max: 10,
|
|
21
|
+
idleTimeout: 30,
|
|
22
|
+
connectionTimeout: 10
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Connection string обирає адаптер автоматично:
|
|
27
|
+
|
|
28
|
+
- `postgres://...` / `postgresql://...` → PostgreSQL
|
|
29
|
+
- `mysql://...` / `mysql2://...` → MySQL/MariaDB
|
|
30
|
+
- `sqlite://...` / `file://...` / `:memory:` → SQLite
|
|
31
|
+
|
|
32
|
+
### Не створювати підключення на кожен запит
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
// ❌ нове підключення/інстанс на кожен виклик
|
|
36
|
+
function getUser(id) {
|
|
37
|
+
const pgWrite = new SQL(process.env.DATABASE_URL)
|
|
38
|
+
return pgWrite`SELECT * FROM users WHERE id = ${id}`
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`new SQL(...)` має створюватись **один раз** на рівні модуля. Bun сам тримає пул (`max`, `idleTimeout`, `maxLifetime`) — окремих `Pool`/`Client` як у `pg` не потрібно. Автоматична перевірка (`lib/bun-sql-scan.mjs`, `findBunSqlPerRequestConnectionInText`, підключена з `safety/main.mjs`) фейлить будь-який `new SQL(...)` усередині функції — це єдина частина цієї сторінки, яку лінтер справді перевіряє; сам singleton-паттерн (файл, іменування `pgWrite`/`pgRead`) — рекомендація без автоматичної перевірки.
|