@nitra/cursor 3.22.0 → 3.23.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/.pi-template/extensions/n-cursor-adr/docs/index.md +181 -0
- package/AGENTS.template.md +4 -0
- package/CHANGELOG.md +37 -3
- package/bin/docs/n-cursor.md +636 -0
- package/bin/docs/rename-yaml-extensions.md +207 -0
- package/bin/n-cursor.js +30 -3
- package/package.json +1 -1
- package/rules/abie/docs/fix.md +18 -0
- package/rules/abie/js/docs/applies.md +26 -0
- package/rules/abie/js/docs/env_dns.md +32 -0
- package/rules/abie/js/docs/firebase_hosting.md +23 -0
- package/rules/abie/js/docs/hc_pairing.md +35 -0
- package/rules/abie/js/docs/ua_http_route.md +28 -0
- package/rules/abie/js/docs/ua_node_selector.md +28 -0
- package/rules/abie/lib/docs/enabled.md +29 -0
- package/rules/abie/lib/docs/env-dns.md +35 -0
- package/rules/abie/lib/docs/hc-yaml.md +33 -0
- package/rules/abie/lib/docs/http-route.md +44 -0
- package/rules/abie/lib/docs/k8s-tree.md +40 -0
- package/rules/abie/lib/docs/kustomization-patches.md +47 -0
- package/rules/abie/lib/docs/overlay-paths.md +38 -0
- package/rules/abie/lib/docs/yaml.md +29 -0
- package/rules/adr/docs/fix.md +148 -0
- package/rules/adr/js/docs/hooks.md +259 -0
- package/rules/bun/docs/fix.md +156 -0
- package/rules/bun/js/docs/layout.md +393 -0
- package/rules/capacitor/docs/fix.md +121 -0
- package/rules/capacitor/js/docs/platforms.md +295 -0
- package/rules/changelog/changelog.mdc +4 -2
- package/rules/changelog/docs/fix.md +174 -0
- package/rules/changelog/js/consistency.mjs +114 -13
- package/rules/changelog/js/docs/consistency.md +387 -0
- package/rules/changelog/lib/docs/package-manifest.md +210 -0
- package/rules/ci4/docs/fix.md +179 -0
- package/rules/ci4/js/docs/marksman_config.md +128 -0
- package/rules/docker/docker.mdc +8 -3
- package/rules/docker/docs/fix.md +171 -0
- package/rules/docker/js/docs/lint.md +258 -0
- package/rules/docker/lib/docs/docker-hadolint.md +184 -0
- package/rules/docker/lib/docs/docker-mirror.md +247 -0
- package/rules/docker/lib/docs/docker-native-addon.md +170 -0
- package/rules/docker/lib/docs/docker-nginx-user.md +219 -0
- package/rules/docker/lint/docs/lint.md +193 -0
- package/rules/efes/docs/fix.md +203 -0
- package/rules/feedback/docs/fix.md +140 -0
- package/rules/flow/docs/fix.md +152 -0
- package/rules/ga/docs/fix.md +158 -0
- package/rules/ga/js/docs/lint.md +100 -0
- package/rules/ga/js/docs/workflows.md +217 -0
- package/rules/ga/lint/docs/lint.md +209 -0
- package/rules/ga/policy/clean_merged_branch/clean_merged_branch.rego +11 -2
- package/rules/ga/policy/clean_merged_branch/template/clean-merged-branch.yml.snippet.yml +3 -4
- package/rules/graphql/docs/fix.md +126 -0
- package/rules/graphql/js/docs/tooling.md +264 -0
- package/rules/graphql/lib/docs/graphql-gql-scan.md +219 -0
- package/rules/hasura/docs/fix.md +120 -0
- package/rules/hasura/hasura.mdc +14 -0
- package/rules/hasura/js/docs/internal_urls.md +326 -0
- package/rules/image-avif/docs/fix.md +132 -0
- package/rules/image-avif/js/docs/avif_generation.md +241 -0
- package/rules/image-compress/docs/fix.md +150 -0
- package/rules/image-compress/js/docs/package_setup.md +191 -0
- package/rules/js-bun-db/docs/fix.md +148 -0
- package/rules/js-bun-db/js/docs/safety.md +231 -0
- package/rules/js-bun-db/js-bun-db.mdc +42 -13
- package/rules/js-bun-db/lib/docs/bun-sql-scan.md +347 -0
- package/rules/js-bun-redis/docs/fix.md +123 -0
- package/rules/js-bun-redis/js/docs/imports.md +176 -0
- package/rules/js-bun-redis/lib/docs/redis-imports.md +223 -0
- package/rules/js-lint/docs/fix.md +117 -0
- package/rules/js-lint/js/docs/lint.md +250 -0
- package/rules/js-lint/js/docs/tooling.md +348 -0
- package/rules/js-lint/js/docs/utils_imports.md +207 -0
- package/rules/js-lint-ci/docs/fix.md +154 -0
- package/rules/js-lint-ci/js/docs/lint.md +144 -0
- package/rules/js-mssql/docs/fix.md +128 -0
- package/rules/js-mssql/js/docs/deps.md +263 -0
- package/rules/js-mssql/lib/docs/mssql-pool-scan.md +367 -0
- package/rules/js-run/docs/fix.md +144 -0
- package/rules/js-run/js/docs/runtime.md +388 -0
- package/rules/js-run/lib/docs/bunyan-imports.md +117 -0
- package/rules/js-run/lib/docs/check-env-scan.md +433 -0
- package/rules/js-run/lib/docs/conn-file-rules.md +300 -0
- package/rules/js-run/lib/docs/conn-imports-scan.md +204 -0
- package/rules/js-run/lib/docs/promise-settimeout-scan.md +326 -0
- package/rules/k8s/docs/fix.md +129 -0
- package/rules/k8s/js/docs/manifests.md +344 -0
- package/rules/k8s/js/manifests.mjs +6 -2
- package/rules/k8s/k8s.mdc +4 -2
- package/rules/k8s/lint/docs/lint.md +411 -0
- package/rules/k8s/policy/network_policy/template/deployment.snippet.yaml +2 -0
- package/rules/k8s/policy/network_policy/template/stateful-set.snippet.yaml +2 -0
- package/rules/nginx-default-tpl/docs/fix.md +124 -0
- package/rules/nginx-default-tpl/js/docs/template.md +378 -0
- package/rules/npm-module/docs/fix.md +98 -0
- package/rules/npm-module/js/docs/package_structure.md +274 -0
- package/rules/npm-module/js/docs/rule_meta.md +137 -0
- package/rules/npm-module/js/docs/skill_meta.md +190 -0
- package/rules/php/docs/fix.md +107 -0
- package/rules/php/js/docs/tooling.md +152 -0
- package/rules/php/lint/docs/lint.md +215 -0
- package/rules/python/docs/fix.md +163 -0
- package/rules/python/js/docs/applies.md +108 -0
- package/rules/python/js/docs/tooling.md +153 -0
- package/rules/python/lint/docs/lint.md +322 -0
- package/rules/rego/docs/fix.md +121 -0
- package/rules/rego/js/docs/applies.md +174 -0
- package/rules/rego/js/docs/lint.md +118 -0
- package/rules/rego/lint/docs/lint.md +204 -0
- package/rules/release/docs/change.md +185 -0
- package/rules/release/docs/fix.md +119 -0
- package/rules/release/docs/release.md +222 -0
- package/rules/release/lib/docs/aggregate.md +246 -0
- package/rules/release/lib/docs/change-file.md +200 -0
- package/rules/release/lib/docs/fallback.md +203 -0
- package/rules/rust/docs/fix.md +129 -0
- package/rules/rust/js/docs/applies.md +140 -0
- package/rules/rust/lib/docs/has-cargo-toml.md +130 -0
- package/rules/security/docs/fix.md +86 -0
- package/rules/security/js/docs/lint.md +171 -0
- package/rules/security/js/docs/sample_secret.md +190 -0
- package/rules/security/js/docs/trufflehog.md +137 -0
- package/rules/security/js/lint.mjs +9 -1
- package/rules/style-lint/docs/fix.md +155 -0
- package/rules/style-lint/js/docs/lint.md +184 -0
- package/rules/style-lint/js/docs/tooling.md +194 -0
- package/rules/tauri/docs/fix.md +158 -0
- package/rules/tauri/js/docs/cargo_mutants_config.md +168 -0
- package/rules/tauri/js/docs/tooling.md +228 -0
- package/rules/test/coverage/coverage.mjs +15 -3
- package/rules/test/docs/fix.md +132 -0
- package/rules/test/js/data/stryker_config/docs/stryker-vue-macros-ignorer.md +138 -0
- package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +134 -0
- package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +160 -0
- package/rules/test/js/data/vitest_config/docs/vitest.config.baseline.md +195 -0
- package/rules/test/js/docs/cargo_mutants_config.md +173 -0
- package/rules/test/js/docs/location.md +136 -0
- package/rules/test/js/docs/no-process-chdir.md +160 -0
- package/rules/test/js/docs/no-relative-fs-path.md +271 -0
- package/rules/test/js/docs/stryker_config.md +152 -0
- package/rules/test/js/docs/vitest-config-pool-forks.md +174 -0
- package/rules/text/docs/fix.md +118 -0
- package/rules/text/js/docs/forbidden-prettier.md +143 -0
- package/rules/text/js/docs/formatting.md +256 -0
- package/rules/text/js/docs/lint.md +122 -0
- package/rules/text/lint/docs/lint.md +220 -0
- package/rules/text/lint/docs/run-dotenv-linter.md +157 -0
- package/rules/text/lint/docs/run-shellcheck.md +212 -0
- package/rules/text/lint/docs/run-v8r.md +197 -0
- package/rules/vue/docs/fix.md +127 -0
- package/rules/vue/js/docs/packages.md +335 -0
- package/rules/vue/lib/docs/vue-forbidden-imports.md +261 -0
- package/rules/worktree/docs/fix.md +161 -0
- package/schemas/rule-meta.json +5 -1
- package/scripts/auto-rules.mjs +7 -4
- package/scripts/coverage-classify/docs/apply.md +202 -0
- package/scripts/coverage-classify/docs/cache.md +203 -0
- package/scripts/coverage-classify/docs/index.md +218 -0
- package/scripts/coverage-classify/docs/prompt.md +132 -0
- package/scripts/coverage-classify/docs/verdict-schema.md +169 -0
- package/scripts/coverage-fix-extract.mjs +122 -0
- package/scripts/coverage-fix.mjs +1 -1
- package/scripts/dispatcher/docs/graph.md +346 -0
- package/scripts/dispatcher/docs/index.md +236 -0
- package/scripts/dispatcher/docs/trace.md +296 -0
- package/scripts/dispatcher/index.mjs +1 -1
- package/scripts/dispatcher/lib/active.mjs +4 -8
- package/scripts/dispatcher/lib/commands.mjs +7 -11
- package/scripts/dispatcher/lib/docs/active.md +348 -0
- package/scripts/dispatcher/lib/docs/artifact.md +232 -0
- package/scripts/dispatcher/lib/docs/budget.md +167 -0
- package/scripts/dispatcher/lib/docs/capability.md +196 -0
- package/scripts/dispatcher/lib/docs/commands.md +210 -0
- package/scripts/dispatcher/lib/docs/events.md +182 -0
- package/scripts/dispatcher/lib/docs/executor.md +190 -0
- package/scripts/dispatcher/lib/docs/flow-lock.md +161 -0
- package/scripts/dispatcher/lib/docs/flow-resolve.md +267 -0
- package/scripts/dispatcher/lib/docs/gate.md +231 -0
- package/scripts/dispatcher/lib/docs/level.md +335 -0
- package/scripts/dispatcher/lib/docs/plan-panel.md +181 -0
- package/scripts/dispatcher/lib/docs/plan.md +200 -0
- package/scripts/dispatcher/lib/docs/planner.md +269 -0
- package/scripts/dispatcher/lib/docs/review.md +255 -0
- package/scripts/dispatcher/lib/docs/reviewer.md +240 -0
- package/scripts/dispatcher/lib/docs/snapshot.md +247 -0
- package/scripts/dispatcher/lib/docs/spec.md +203 -0
- package/scripts/dispatcher/lib/docs/state-store.md +303 -0
- package/scripts/dispatcher/lib/docs/subagent-runner.md +173 -0
- package/scripts/dispatcher/lib/executor.mjs +6 -1
- package/scripts/dispatcher/lib/flow-resolve.mjs +3 -1
- package/scripts/dispatcher/lib/level.mjs +29 -3
- package/scripts/dispatcher/lib/review.mjs +1 -1
- package/scripts/dispatcher/lib/subagent-runner.mjs +5 -3
- package/scripts/docs/auto-rules.md +376 -0
- package/scripts/docs/auto-skills.md +173 -0
- package/scripts/docs/build-agents-commands.md +183 -0
- package/scripts/docs/cli-entry.md +153 -0
- package/scripts/docs/coverage-fix.md +177 -0
- package/scripts/docs/ensure-nitra-cursor-dev-dependencies.md +189 -0
- package/scripts/lib/changed-files.mjs +4 -1
- package/scripts/lib/docs/changed-files.md +149 -0
- package/scripts/lib/docs/check-mdc-template-refs.md +222 -0
- package/scripts/lib/docs/check-reporter.md +175 -0
- package/scripts/lib/docs/discover-check-rules-from-cursor.md +157 -0
- package/scripts/lib/docs/discover-checkable-rules.md +165 -0
- package/scripts/lib/docs/ensure-tool.md +254 -0
- package/scripts/lib/docs/generated-markdown.md +275 -0
- package/scripts/lib/docs/gha-workflow.md +326 -0
- package/scripts/lib/docs/inline-template-links.md +303 -0
- package/scripts/lib/docs/list-rule-ids.md +156 -0
- package/scripts/lib/docs/load-cursor-config.md +147 -0
- package/scripts/lib/docs/mirror-parity.md +167 -0
- package/scripts/lib/worktree.mjs +26 -0
- package/scripts/worktree-cli.mjs +12 -2
- package/skills/coverage-fix/SKILL.md +34 -45
- package/skills/docgen/SKILL.md +44 -23
- package/skills/docgen/bench/etalon/firebase_hosting.md +19 -0
- package/skills/docgen/bench/etalon/k8s-tree.md +24 -0
- package/skills/docgen/bench/etalon/overlay-paths.md +24 -0
- package/skills/docgen/js/docgen-ignore.mjs +54 -0
- package/skills/docgen/js/docgen-scan.mjs +37 -21
- package/skills/llm-patch/SKILL.md +23 -2
- package/skills/start-check/SKILL.md +26 -53
- package/skills/start-check/js/check.mjs +211 -0
- package/skills/taze/SKILL.md +9 -3
- package/skills/taze/js/diff.mjs +154 -0
- package/types/bin/n-cursor.d.ts +1 -1
- package/skills/fix-tests/SKILL.md +0 -119
- package/skills/fix-tests/meta.json +0 -1
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# `runtime.mjs` — JS-runtime перевірки правила `js-run.mdc`
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Модуль `npm/rules/js-run/js/runtime.mjs` — це **виконавча частина** правила `js-run.mdc`
|
|
6
|
+
для монорепо-перевірки командою `npx @nitra/cursor check`. Він обходить усі workspace-пакети
|
|
7
|
+
(виключаючи кореневий `.`) і для кожного пакета валідує дотримання набору JS-/інфраструктурних
|
|
8
|
+
конвенцій, які складно або неможливо виразити лише через Rego-політики per-document.
|
|
9
|
+
|
|
10
|
+
Покрите цим модулем:
|
|
11
|
+
|
|
12
|
+
- **Заборона `@nitra/bunyan` / `bunyan` в імпортах коду** — статичні `import`, CommonJS
|
|
13
|
+
`require`, динамічний `import()`; знаходиться через AST-парсер (`oxc-parser`, делегується
|
|
14
|
+
в `../lib/bunyan-imports.mjs`).
|
|
15
|
+
- **`OTEL_RESOURCE_ATTRIBUTES` у `k8s/base/configmap.yaml`** — наявність файлу (структуру
|
|
16
|
+
валідує Rego через `npx @nitra/cursor fix`, namespace `js_run.configmap`).
|
|
17
|
+
- **Внутрішні аліаси `#conn/*`** — імпорти `bun#SQL`, `mssql`, `@nitra/graphql-request#GraphQLClient`
|
|
18
|
+
дозволені лише в каталозі `src/conn/` (або в каталозі, заданому `package.json#imports['#conn/*']`).
|
|
19
|
+
- **Нейминг і експорти у `#conn/`** — `ql-<id>` / `(pg|mysql|mssql)-(read|write)[-<id>]`;
|
|
20
|
+
`export default` заборонений; іменований експорт має дорівнювати camelCase від basename файла;
|
|
21
|
+
`index.*` пропускається як reexport-барель.
|
|
22
|
+
- **`process.env` / `CheckEnv`** — пряме `process.env.X` заборонене; обов'язкові змінні —
|
|
23
|
+
через `env` з `@nitra/check-env` + `checkEnv(['X', …])` у тому ж файлі (або коментар
|
|
24
|
+
`// @nitra/cursor ignore-next-line checkEnv`); опційні — через `env` з `node:process`.
|
|
25
|
+
- **Паузи через `setTimeout`** — `new Promise(r => setTimeout(r, ms))` має бути замінений на
|
|
26
|
+
`await setTimeout(ms)` з `node:timers/promises`.
|
|
27
|
+
- **`jsconfig.json` у backend-пакеті з `src/`** — наявність файла (структуру `NodeNext` і
|
|
28
|
+
`include: src/**/*` валідує Rego `js_run.jsconfig` через `runConftestBatch`).
|
|
29
|
+
|
|
30
|
+
Per-document валідація `package.json` (заборона `@nitra/bunyan`/`bunyan` у залежностях,
|
|
31
|
+
правила для `node` у `scripts`) делегована окремому rego-пакету `js_run.package_json` у
|
|
32
|
+
`npm/rules/js-run/policy/package_json/`; цей JS-файл — про крос-файлові й AST-перевірки.
|
|
33
|
+
|
|
34
|
+
Frontend-пакети (з `vite` у `devDependencies`) повністю пропускаються — для них
|
|
35
|
+
актуальний інший контекст (браузерний бандл без `node:process`); bunyan-залежність
|
|
36
|
+
такого пакета все одно перевіряється Rego-частиною.
|
|
37
|
+
|
|
38
|
+
## Експорти / API
|
|
39
|
+
|
|
40
|
+
| Експорт | Тип | Призначення |
|
|
41
|
+
| ------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
42
|
+
| `check(cwd?)` | `async function` | Єдина публічна точка входу. Запускає перевірку всіх workspace-пакетів. Повертає `0` (все OK) або `1` (є порушення). |
|
|
43
|
+
|
|
44
|
+
Усі інші функції модуля — внутрішні (без `export`) і використовуються лише з `check`.
|
|
45
|
+
|
|
46
|
+
## Функції
|
|
47
|
+
|
|
48
|
+
### `check(cwd = process.cwd())` _(export)_
|
|
49
|
+
|
|
50
|
+
- **Сигнатура:** `async function check(cwd?: string): Promise<number>`
|
|
51
|
+
- **Параметри:**
|
|
52
|
+
- `cwd` _(string, опційний)_ — абсолютний корінь репозиторію; за замовчуванням
|
|
53
|
+
`process.cwd()`.
|
|
54
|
+
- **Повертає:** `Promise<number>` — exit-код від `createCheckReporter().getExitCode()`
|
|
55
|
+
(0 — успіх, 1 — є хоча б одне `fail(...)`).
|
|
56
|
+
- **Side effects:**
|
|
57
|
+
- читає `package.json` коренева/workspace-пакетів через `getMonorepoPackageRootDirs`;
|
|
58
|
+
- читає `.cursorignore` / конфіг через `loadCursorIgnorePaths`;
|
|
59
|
+
- читає файли пакетів (`fs/promises`), синхронні `existsSync` / `statSync`;
|
|
60
|
+
- друкує повідомлення `pass(...)` / `fail(...)` через репортер;
|
|
61
|
+
- запускає `conftest` через `runConftestBatch` (зовнішній процес) для перевірки `jsconfig.json`.
|
|
62
|
+
- **Алгоритм:**
|
|
63
|
+
1. Створює репортер `createCheckReporter()`.
|
|
64
|
+
2. Бере список усіх коренів пакетів і відфільтровує кореневий `.`.
|
|
65
|
+
3. Якщо workspace-пакетів немає — викликає `pass(...)` з відповідним повідомленням
|
|
66
|
+
і повертає exit-код.
|
|
67
|
+
4. Завантажує перелік `ignorePaths` (повністю виключені з обходу).
|
|
68
|
+
5. По черзі викликає `checkWorkspacePackage(r, ignorePaths, fail, pass, cwd)` для кожного `r`.
|
|
69
|
+
6. Повертає `reporter.getExitCode()`.
|
|
70
|
+
|
|
71
|
+
### `checkWorkspacePackage(rootDir, ignorePaths, fail, passFn, cwd)`
|
|
72
|
+
|
|
73
|
+
- **Сигнатура:**
|
|
74
|
+
`async function checkWorkspacePackage(rootDir: string, ignorePaths: string[], fail: (msg: string) => void, passFn: (msg: string) => void, cwd: string): Promise<void>`
|
|
75
|
+
- **Параметри:**
|
|
76
|
+
- `rootDir` — відносний шлях workspace-пакета (не `'.'`).
|
|
77
|
+
- `ignorePaths` — абсолютні шляхи каталогів, виключені з обходу.
|
|
78
|
+
- `fail` — callback реєстрації порушення.
|
|
79
|
+
- `passFn` — callback повідомлення про успішну під-перевірку.
|
|
80
|
+
- `cwd` — корінь репозиторію.
|
|
81
|
+
- **Повертає:** `Promise<void>`.
|
|
82
|
+
- **Side effects:** читає `package.json` пакета; запускає всі під-перевірки нижче;
|
|
83
|
+
для frontend-пакета (vite у `devDependencies`) повертається одразу після `passFn`.
|
|
84
|
+
- **Алгоритм:**
|
|
85
|
+
1. Формує `label = '[<rootDir>] '` і `absPackageRoot`.
|
|
86
|
+
2. Завантажує `pkgJson = loadPackageJson(rootDir, cwd)`.
|
|
87
|
+
3. Якщо `packageJsonHasViteDevDependency(pkgJson)` — `passFn(...)` і вихід.
|
|
88
|
+
4. `checkBackendJsconfigWhenSrcPresent(...)` — gate на `jsconfig.json`.
|
|
89
|
+
5. `checkBunyanImports(...)` → якщо `0` порушень, друкує позитивне повідомлення.
|
|
90
|
+
6. `collectSourceFiles(...)` — спільний список JS/TS-файлів для подальших сканів.
|
|
91
|
+
7. `checkConnImports(...)` → позитивне повідомлення з резолвленим `connDir`.
|
|
92
|
+
8. `checkConnFileNamingAndExports(...)` → позитивне повідомлення про канон у `connDir/`.
|
|
93
|
+
9. `checkProcessEnvUsage(...)` → позитивне повідомлення про `process.env`/`checkEnv`.
|
|
94
|
+
10. `checkPromiseSetTimeoutPause(...)` → позитивне повідомлення про `setTimeout`-паузи.
|
|
95
|
+
11. `checkOtelConfigmap(...)` — лише наявність `k8s/base/configmap.yaml`.
|
|
96
|
+
|
|
97
|
+
### `backendPackageHasSrcDir(absPackageRoot)`
|
|
98
|
+
|
|
99
|
+
- **Сигнатура:** `function backendPackageHasSrcDir(absPackageRoot: string): boolean`
|
|
100
|
+
- **Параметри:** `absPackageRoot` — абсолютний корінь пакета.
|
|
101
|
+
- **Повертає:** `true`, якщо `<absPackageRoot>/src` існує і це каталог.
|
|
102
|
+
- **Side effects:** синхронний `statSync`; помилки ловить і повертає `false`.
|
|
103
|
+
|
|
104
|
+
### `checkBackendJsconfigWhenSrcPresent(rootDir, absPackageRoot, label, fail, passFn, cwd)`
|
|
105
|
+
|
|
106
|
+
- **Сигнатура:**
|
|
107
|
+
`function checkBackendJsconfigWhenSrcPresent(rootDir: string, absPackageRoot: string, label: string, fail: (msg: string) => void, passFn: (msg: string) => void, cwd: string): void`
|
|
108
|
+
- **Параметри:** як у `checkWorkspacePackage`.
|
|
109
|
+
- **Повертає:** `void`.
|
|
110
|
+
- **Side effects:** `existsSync` для `jsconfig.json`; виклик `runConftestBatch` (зовнішній
|
|
111
|
+
процес `conftest`); виклик `fail`/`passFn`.
|
|
112
|
+
- **Алгоритм:**
|
|
113
|
+
1. Якщо `src/` відсутній — повернутися (gate перевірки).
|
|
114
|
+
2. Якщо `jsconfig.json` відсутній — `fail(...)` із повідомленням про канонічний файл і вихід.
|
|
115
|
+
3. Викликає `runConftestBatch({ policyDirRel: 'js-run/jsconfig', namespace: 'js_run.jsconfig', files: [jcPath] })`.
|
|
116
|
+
4. Якщо порушень немає — `passFn(...)`; інакше — `fail(...)` для кожного.
|
|
117
|
+
|
|
118
|
+
### `relPosix(absPackageRoot, absPath)`
|
|
119
|
+
|
|
120
|
+
- **Сигнатура:** `function relPosix(absPackageRoot: string, absPath: string): string`
|
|
121
|
+
- **Параметри:** корінь пакета й абсолютний шлях до файлу.
|
|
122
|
+
- **Повертає:** відносний шлях у posix-форматі (`/`), отриманий заміною `\\` → `/` у результаті
|
|
123
|
+
`node:path#relative`.
|
|
124
|
+
- **Side effects:** немає (чиста функція).
|
|
125
|
+
|
|
126
|
+
### `checkBunyanImports(absPackageRoot, ignorePaths, label, fail)`
|
|
127
|
+
|
|
128
|
+
- **Сигнатура:**
|
|
129
|
+
`async function checkBunyanImports(absPackageRoot: string, ignorePaths: string[], label: string, fail: (msg: string) => void): Promise<number>`
|
|
130
|
+
- **Повертає:** кількість знайдених порушень.
|
|
131
|
+
- **Side effects:** `walkDir` (читання каталогу), `readFile` для кожного source-файла, виклик `fail`.
|
|
132
|
+
- **Алгоритм:**
|
|
133
|
+
1. Збирає `sourcePaths` обходом `walkDir`, фільтр: `!shouldSkipFileForBunyanScan(rel) && isBunyanScanSourceFile(rel)`.
|
|
134
|
+
2. Для кожного — читає вміст і викликає `findBunyanImportsInText(content, rel)`.
|
|
135
|
+
3. Для кожного `v` друкує повідомлення з номером рядка, ім'ям модуля й snippet'ом і
|
|
136
|
+
інкрементує лічильник.
|
|
137
|
+
|
|
138
|
+
### `collectSourceFiles(absPackageRoot, ignorePaths)`
|
|
139
|
+
|
|
140
|
+
- **Сигнатура:**
|
|
141
|
+
`async function collectSourceFiles(absPackageRoot: string, ignorePaths: string[]): Promise<string[]>`
|
|
142
|
+
- **Повертає:** масив абсолютних шляхів до файлів-кандидатів на скан (фільтр
|
|
143
|
+
`isCheckEnvScanSourceFile`).
|
|
144
|
+
- **Side effects:** `walkDir`. Зверніть увагу: фільтр базується саме на правилах
|
|
145
|
+
`check-env-scan`, але отриманий список потім перевикористовується для інших сканів
|
|
146
|
+
(`conn-imports`, `conn-file-rules`, `process-env`, `promise-settimeout`), кожен з яких
|
|
147
|
+
має свій додатковий внутрішній фільтр (`isConnImportsScanSourceFile` тощо).
|
|
148
|
+
|
|
149
|
+
### `checkConnImports(absPackageRoot, sourcePaths, pkgJson, label, fail)`
|
|
150
|
+
|
|
151
|
+
- **Сигнатура:**
|
|
152
|
+
`async function checkConnImports(absPackageRoot: string, sourcePaths: string[], pkgJson: unknown, label: string, fail: (msg: string) => void): Promise<number>`
|
|
153
|
+
- **Повертає:** кількість порушень.
|
|
154
|
+
- **Side effects:** `readFile`, `fail`.
|
|
155
|
+
- **Алгоритм:**
|
|
156
|
+
1. `connDir = resolveConnDirFromPackageJson(pkgJson)`.
|
|
157
|
+
2. Для кожного файла зі `sourcePaths`:
|
|
158
|
+
- пропускає, якщо не source-file для conn-imports-scan;
|
|
159
|
+
- пропускає, якщо файл вже всередині `connDir/`;
|
|
160
|
+
- читає вміст, викликає `findConnFactoryImportsInText(content, rel)` і друкує
|
|
161
|
+
повідомлення `fail(...)` із форматуванням `{ <specifier> } from '<module>'` або
|
|
162
|
+
`'<module>'` (коли `specifier === '*'`).
|
|
163
|
+
|
|
164
|
+
### `checkConnFileNamingAndExports(absPackageRoot, sourcePaths, pkgJson, label, fail)`
|
|
165
|
+
|
|
166
|
+
- **Сигнатура:**
|
|
167
|
+
`async function checkConnFileNamingAndExports(absPackageRoot: string, sourcePaths: string[], pkgJson: unknown, label: string, fail: (msg: string) => void): Promise<number>`
|
|
168
|
+
- **Повертає:** кількість порушень.
|
|
169
|
+
- **Side effects:** `readFile`, `fail`.
|
|
170
|
+
- **Алгоритм:** для кожного файла, який `isConnFileToCheck(rel, connDir)`, читає вміст і
|
|
171
|
+
для кожного `v` з `findConnFileRuleViolations(content, rel)` друкує повідомлення з
|
|
172
|
+
`formatConnFileViolation(v, label, rel, connDir)`.
|
|
173
|
+
|
|
174
|
+
### `isConnFileToCheck(rel, connDir)`
|
|
175
|
+
|
|
176
|
+
- **Сигнатура:** `function isConnFileToCheck(rel: string, connDir: string): boolean`
|
|
177
|
+
- **Повертає:** `true`, коли файл:
|
|
178
|
+
- лежить всередині `connDir/` (`isInsideConnDir`);
|
|
179
|
+
- має розширення JS/TS, що відповідає `isConnFileRulesSourceFile`;
|
|
180
|
+
- basename **не** починається з `index.` (бо це reexport-барель).
|
|
181
|
+
|
|
182
|
+
### `formatConnFileViolation(v, label, rel, connDir)`
|
|
183
|
+
|
|
184
|
+
- **Сигнатура:**
|
|
185
|
+
`function formatConnFileViolation(v: { kind: 'name'|'default-export'|'export-name', expectedName?: string, foundNames?: string[] }, label: string, rel: string, connDir: string): string`
|
|
186
|
+
- **Повертає:** готовий текст повідомлення для `fail(...)`.
|
|
187
|
+
- **Поведінка за `kind`:**
|
|
188
|
+
- `'name'` — повідомлення про канон імен (`ql-<id>`, `pg-/mysql-/mssql-{read|write}[-<id>]`,
|
|
189
|
+
kebab-case `[a-z0-9-]`).
|
|
190
|
+
- `'default-export'` — заборонений `export default` у `connDir/`.
|
|
191
|
+
- інше (`'export-name'`) — очікувано `export const <expectedName>`; знайдені імена
|
|
192
|
+
показуються через кому, якщо `foundNames` непорожній, інакше тире.
|
|
193
|
+
|
|
194
|
+
### `checkProcessEnvUsage(absPackageRoot, sourcePaths, label, fail)`
|
|
195
|
+
|
|
196
|
+
- **Сигнатура:**
|
|
197
|
+
`async function checkProcessEnvUsage(absPackageRoot: string, sourcePaths: string[], label: string, fail: (msg: string) => void): Promise<number>`
|
|
198
|
+
- **Повертає:** кількість порушень.
|
|
199
|
+
- **Side effects:** `readFile`, `fail`.
|
|
200
|
+
- **Алгоритм:** для кожного файла читає вміст і викликає `findUncheckedProcessEnvInText`.
|
|
201
|
+
Залежно від `v.kind` формує різне повідомлення:
|
|
202
|
+
- `'process-env'` — пряме `process.env.X`: підказує замінити на `env` з
|
|
203
|
+
`@nitra/check-env` + `checkEnv(['X'])` або з `node:process` (опційно).
|
|
204
|
+
- інакше — `env.X` з `@nitra/check-env`, не закритий `checkEnv(['X'])` (або
|
|
205
|
+
`// @nitra/cursor ignore-next-line checkEnv`).
|
|
206
|
+
|
|
207
|
+
### `checkPromiseSetTimeoutPause(absPackageRoot, sourcePaths, label, fail)`
|
|
208
|
+
|
|
209
|
+
- **Сигнатура:**
|
|
210
|
+
`async function checkPromiseSetTimeoutPause(absPackageRoot: string, sourcePaths: string[], label: string, fail: (msg: string) => void): Promise<number>`
|
|
211
|
+
- **Повертає:** кількість порушень.
|
|
212
|
+
- **Side effects:** `readFile`, `fail`.
|
|
213
|
+
- **Алгоритм:** фільтрує файли через `isPromiseSetTimeoutScanSourceFile`, для решти
|
|
214
|
+
читає вміст і викликає `findPromiseSetTimeoutInText` — порушення друкуються з
|
|
215
|
+
підказкою «`await setTimeout(ms)` з `node:timers/promises`».
|
|
216
|
+
|
|
217
|
+
### `packageJsonHasViteDevDependency(pkgJson)`
|
|
218
|
+
|
|
219
|
+
- **Сигнатура:** `function packageJsonHasViteDevDependency(pkgJson: unknown): boolean`
|
|
220
|
+
- **Повертає:** `true`, якщо `pkgJson.devDependencies` — об'єкт і має ключ `'vite'`.
|
|
221
|
+
- **Side effects:** немає.
|
|
222
|
+
- **Семантика:** ідентично `packageJsonLacksViteDevDependency` з `auto-rules.mjs`, але
|
|
223
|
+
приймає вже розпарсений об'єкт (без I/O).
|
|
224
|
+
|
|
225
|
+
### `loadPackageJson(rootDir, cwd)`
|
|
226
|
+
|
|
227
|
+
- **Сигнатура:** `async function loadPackageJson(rootDir: string, cwd: string): Promise<unknown>`
|
|
228
|
+
- **Повертає:** розпарсений `package.json` пакета або `null`, якщо файла немає.
|
|
229
|
+
- **Side effects:** `existsSync`, `readFile`, `JSON.parse`.
|
|
230
|
+
- **Примітка:** заборону `@nitra/bunyan` / `bunyan` у `dependencies` / `devDependencies`
|
|
231
|
+
перенесено в Rego-пакет `npm/policy/js_run/package_json/`; тут залишилась лише AST-перевірка
|
|
232
|
+
імпортів.
|
|
233
|
+
|
|
234
|
+
### `checkOtelConfigmap(rootDir, passFn, cwd)`
|
|
235
|
+
|
|
236
|
+
- **Сигнатура:**
|
|
237
|
+
`function checkOtelConfigmap(rootDir: string, passFn: (msg: string) => void, cwd: string): void`
|
|
238
|
+
- **Повертає:** `void`.
|
|
239
|
+
- **Side effects:** `existsSync`, `passFn`.
|
|
240
|
+
- **Алгоритм:** якщо `<rootDir>/k8s/base/configmap.yaml` існує — друкує повідомлення про
|
|
241
|
+
факт наявності й нагадує, що структуру (OTEL-атрибути) перевіряє Rego через
|
|
242
|
+
`npx @nitra/cursor fix` → `js_run.configmap`.
|
|
243
|
+
|
|
244
|
+
## Залежності
|
|
245
|
+
|
|
246
|
+
### Node.js стандартна бібліотека
|
|
247
|
+
|
|
248
|
+
- `node:fs` — `existsSync`, `statSync` (синхронні перевірки наявності каталогу / файла).
|
|
249
|
+
- `node:fs/promises` — `readFile` (читання текстових файлів).
|
|
250
|
+
- `node:path` — `join`, `relative` (формування шляхів; `relPosix` додатково нормалізує).
|
|
251
|
+
|
|
252
|
+
### Локальні модулі (`../lib/`)
|
|
253
|
+
|
|
254
|
+
- `../lib/bunyan-imports.mjs` — `findBunyanImportsInText`, `isBunyanScanSourceFile`,
|
|
255
|
+
`shouldSkipFileForBunyanScan`.
|
|
256
|
+
- `../lib/check-env-scan.mjs` — `findUncheckedProcessEnvInText`, `isCheckEnvScanSourceFile`.
|
|
257
|
+
- `../lib/conn-file-rules.mjs` — `findConnFileRuleViolations`, `isConnFileRulesSourceFile`.
|
|
258
|
+
- `../lib/conn-imports-scan.mjs` — `findConnFactoryImportsInText`, `isConnImportsScanSourceFile`,
|
|
259
|
+
`isInsideConnDir`, `resolveConnDirFromPackageJson`.
|
|
260
|
+
- `../lib/promise-settimeout-scan.mjs` — `findPromiseSetTimeoutInText`,
|
|
261
|
+
`isPromiseSetTimeoutScanSourceFile`.
|
|
262
|
+
|
|
263
|
+
### Скрипти каркасу (`../../../scripts/`)
|
|
264
|
+
|
|
265
|
+
- `scripts/lib/check-reporter.mjs` — `createCheckReporter` (репортер `pass`/`fail` +
|
|
266
|
+
`getExitCode`).
|
|
267
|
+
- `scripts/lib/run-conftest-batch.mjs` — `runConftestBatch` (запуск `conftest` на наборі
|
|
268
|
+
файлів, повертає `violations[]`).
|
|
269
|
+
- `scripts/lib/load-cursor-config.mjs` — `loadCursorIgnorePaths` (читання списку шляхів
|
|
270
|
+
для виключення з обходу).
|
|
271
|
+
- `scripts/utils/walkDir.mjs` — `walkDir` (рекурсивний обхід каталогу з callback'ом і
|
|
272
|
+
списком ігнорувань).
|
|
273
|
+
- `scripts/lib/workspaces.mjs` — `getMonorepoPackageRootDirs` (перелік коренів
|
|
274
|
+
workspace-пакетів монорепо).
|
|
275
|
+
|
|
276
|
+
### Зовнішні залежності (через посередників)
|
|
277
|
+
|
|
278
|
+
- `conftest` — викликається з `runConftestBatch`; виконує Rego-політики, наприклад
|
|
279
|
+
`js_run.jsconfig` із `npm/rules/js-run/policy/jsconfig/`.
|
|
280
|
+
- `oxc-parser` — використовується в `bunyan-imports.mjs` для AST-сканування імпортів
|
|
281
|
+
(через залежність, не імпортується прямо тут).
|
|
282
|
+
|
|
283
|
+
## Потік виконання / Використання
|
|
284
|
+
|
|
285
|
+
### Точка входу
|
|
286
|
+
|
|
287
|
+
Модуль експортує лише `check(cwd?)`, яку викликає диспетчер правил (`@nitra/cursor check`)
|
|
288
|
+
для правила `js-run`. Очікуваний контракт — повернути exit-код для агрегації по всіх правилах.
|
|
289
|
+
|
|
290
|
+
### Високорівневий потік
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
check(cwd)
|
|
294
|
+
└─ createCheckReporter()
|
|
295
|
+
└─ getMonorepoPackageRootDirs(cwd) → roots
|
|
296
|
+
└─ workspaceRoots = roots.filter(r => r !== '.')
|
|
297
|
+
└─ [if empty] pass('немає workspace-пакетів') → return exitCode
|
|
298
|
+
└─ loadCursorIgnorePaths(cwd) → ignorePaths
|
|
299
|
+
└─ for each r ∈ workspaceRoots:
|
|
300
|
+
checkWorkspacePackage(r, ignorePaths, fail, pass, cwd)
|
|
301
|
+
├─ loadPackageJson(r, cwd)
|
|
302
|
+
├─ [if vite-frontend] passFn → return
|
|
303
|
+
├─ checkBackendJsconfigWhenSrcPresent(...)
|
|
304
|
+
│ ├─ backendPackageHasSrcDir → gate
|
|
305
|
+
│ ├─ [no jsconfig] fail
|
|
306
|
+
│ └─ runConftestBatch (Rego: js_run.jsconfig)
|
|
307
|
+
├─ checkBunyanImports(...)
|
|
308
|
+
│ ├─ walkDir → sourcePaths (фільтр bunyan-scan)
|
|
309
|
+
│ └─ for each → findBunyanImportsInText
|
|
310
|
+
├─ collectSourceFiles(...) → sourcePaths (фільтр check-env)
|
|
311
|
+
├─ checkConnImports(...)
|
|
312
|
+
│ └─ resolveConnDirFromPackageJson + findConnFactoryImportsInText
|
|
313
|
+
├─ checkConnFileNamingAndExports(...)
|
|
314
|
+
│ ├─ isConnFileToCheck
|
|
315
|
+
│ └─ findConnFileRuleViolations → formatConnFileViolation
|
|
316
|
+
├─ checkProcessEnvUsage(...)
|
|
317
|
+
│ └─ findUncheckedProcessEnvInText
|
|
318
|
+
├─ checkPromiseSetTimeoutPause(...)
|
|
319
|
+
│ └─ findPromiseSetTimeoutInText
|
|
320
|
+
└─ checkOtelConfigmap(...) [лише існування k8s/base/configmap.yaml]
|
|
321
|
+
└─ return reporter.getExitCode()
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Логіка пропусків (gate'и)
|
|
325
|
+
|
|
326
|
+
- **Кореневий `.`** workspace відфільтровується одразу.
|
|
327
|
+
- **Frontend (vite у `devDependencies`)** — увесь `js-run` пропускається на рівні
|
|
328
|
+
workspace.
|
|
329
|
+
- **`jsconfig.json`** — перевіряється лише там, де є `src/` каталог.
|
|
330
|
+
- **Conn-сканування** — імпорти `bun#SQL` / `mssql` / `@nitra/graphql-request#GraphQLClient`
|
|
331
|
+
перевіряються тільки **поза** каталогом `connDir` (а нейминг/експорти — тільки
|
|
332
|
+
всередині нього, окрім `index.*`).
|
|
333
|
+
- **Bunyan-сканування** — додатково керується `shouldSkipFileForBunyanScan` для специфічних
|
|
334
|
+
шляхів і `isBunyanScanSourceFile` для розширень.
|
|
335
|
+
- **`k8s/base/configmap.yaml`** — лише наявність; OTEL-атрибути перевіряє Rego.
|
|
336
|
+
|
|
337
|
+
### Як модуль інтегрується із суміжними частинами правила
|
|
338
|
+
|
|
339
|
+
- **AST-частина**: бере на себе крос-файлову й AST-логіку, яку складно виразити в Rego.
|
|
340
|
+
- **Per-document Rego**: `js_run.package_json` (bunyan/scripts.node), `js_run.configmap`
|
|
341
|
+
(OTEL), `js_run.jsconfig` (canonical `compilerOptions`/`include`).
|
|
342
|
+
- **JS-оркестрація Rego через `runConftestBatch`**: модуль викликає `conftest` лише там, де
|
|
343
|
+
попередній gate (наявність `src/` + наявність `jsconfig.json`) дозволяє це робити —
|
|
344
|
+
_Plan B_: Rego-authoritative, JS оркеструє per-package gate.
|
|
345
|
+
|
|
346
|
+
### Приклад використання
|
|
347
|
+
|
|
348
|
+
```js
|
|
349
|
+
import { check } from './runtime.mjs'
|
|
350
|
+
|
|
351
|
+
const exitCode = await check(process.cwd())
|
|
352
|
+
process.exit(exitCode)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Поведінкові інваріанти
|
|
356
|
+
|
|
357
|
+
- Будь-який `fail(...)` → exit-code 1.
|
|
358
|
+
- Відсутність помилок у під-перевірці → відповідне інформаційне `pass(...)`.
|
|
359
|
+
- Frontend-пакет (vite) ніколи не отримує жодного `fail` від цього модуля.
|
|
360
|
+
- Кореневий пакет монорепо ніколи не перевіряється цим модулем.
|
|
361
|
+
|
|
362
|
+
## Rebuild Test
|
|
363
|
+
|
|
364
|
+
Документ написано на основі повного читання вихідного файла `runtime.mjs` (446 рядків).
|
|
365
|
+
Якщо повністю відновлювати модуль за цим описом, відтворюються:
|
|
366
|
+
|
|
367
|
+
- Єдиний експорт `check(cwd?)` та його контракт із `createCheckReporter`.
|
|
368
|
+
- Список workspace-фільтрації (`r !== '.'`) та early-return при порожньому списку.
|
|
369
|
+
- Виклик `loadCursorIgnorePaths` й передача `ignorePaths` в усі скани.
|
|
370
|
+
- Послідовність дев'яти кроків у `checkWorkspacePackage` із саме такими повідомленнями
|
|
371
|
+
для `passFn` / `fail`.
|
|
372
|
+
- Gate `vite у devDependencies` → пропуск усього `js-run` для frontend-пакета.
|
|
373
|
+
- Gate `src/` для `jsconfig.json` та делегування структури до Rego `js_run.jsconfig`
|
|
374
|
+
через `runConftestBatch({ policyDirRel: 'js-run/jsconfig', namespace: 'js_run.jsconfig',
|
|
375
|
+
files: [jcPath] })`.
|
|
376
|
+
- Дев'ять допоміжних функцій (`backendPackageHasSrcDir`, `relPosix`, `checkBunyanImports`,
|
|
377
|
+
`collectSourceFiles`, `checkConnImports`, `checkConnFileNamingAndExports`,
|
|
378
|
+
`isConnFileToCheck`, `formatConnFileViolation`, `checkProcessEnvUsage`,
|
|
379
|
+
`checkPromiseSetTimeoutPause`, `packageJsonHasViteDevDependency`, `loadPackageJson`,
|
|
380
|
+
`checkOtelConfigmap`, `checkBackendJsconfigWhenSrcPresent`) із зазначеними сигнатурами,
|
|
381
|
+
параметрами й side effects.
|
|
382
|
+
- Перелік модулів-залежностей (`../lib/*`, `../../../scripts/lib/*`,
|
|
383
|
+
`../../../scripts/utils/walkDir.mjs`) і стандартних модулів Node.js (`node:fs`,
|
|
384
|
+
`node:fs/promises`, `node:path`).
|
|
385
|
+
- Інваріант, що `collectSourceFiles` використовує фільтр `isCheckEnvScanSourceFile`,
|
|
386
|
+
а інші скани мають свої внутрішні фільтри (`isConnImportsScanSourceFile`,
|
|
387
|
+
`isPromiseSetTimeoutScanSourceFile`).
|
|
388
|
+
- Формат повідомлень `fail(...)` із префіксом `[<pkg>] ` та номером рядка `${rel}:${v.line}`.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# `bunyan-imports.mjs`
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Модуль `bunyan-imports.mjs` — це AST-сканер, який знаходить у вихідних файлах JavaScript / TypeScript заборонені імпорти й виклики модулів `@nitra/bunyan` та застарілого `bunyan`. Згідно з правилом `js-run.mdc` уся логіка структурованого логування у проєкті переведена на `@nitra/pino`, тому будь-яке згадування `bunyan`/`@nitra/bunyan` має бути замінене на `@nitra/pino`.
|
|
6
|
+
|
|
7
|
+
Ключові властивості:
|
|
8
|
+
|
|
9
|
+
- Семантика береться з **oxc-parser** (`module.staticImports`) — без regex по тілу файлу; це робить сканер стійким до коментарів, рядкових літералів та форматувань.
|
|
10
|
+
- На додачу до статичних `import`-ів сканер обходить AST програми і ловить:
|
|
11
|
+
- `require('@nitra/bunyan')` / `require('bunyan')` — для CommonJS;
|
|
12
|
+
- динамічний `import('@nitra/bunyan')` / `import('bunyan')` — для випадків асинхронного підключення в межах одного файлу.
|
|
13
|
+
- Сканер не вимагає, щоб файл компілювався: при синтаксичних помилках парсера повертається **порожній** результат — спершу слід полагодити синтаксис, потім перезапустити перевірку.
|
|
14
|
+
- Декларації типів (`*.d.ts`) виключені з обходу через окремий хелпер.
|
|
15
|
+
|
|
16
|
+
Файл є частиною бібліотеки правила `js-run` й використовується чек-скриптами цього правила для сигналізації про порушення.
|
|
17
|
+
|
|
18
|
+
## Експорти / API
|
|
19
|
+
|
|
20
|
+
Модуль експортує три іменовані функції:
|
|
21
|
+
|
|
22
|
+
| Експорт | Призначення |
|
|
23
|
+
| ------------------------------------------------ | ----------------------------------------------------------- |
|
|
24
|
+
| `findBunyanImportsInText(content, virtualPath?)` | Основний AST-сканер тексту файлу — повертає масив порушень. |
|
|
25
|
+
| `isBunyanScanSourceFile(relativePath)` | Фільтр за розширенням файлу (JS/TS-сім'я). |
|
|
26
|
+
| `shouldSkipFileForBunyanScan(relativePosix)` | Виключення декларацій типів (`*.d.ts`). |
|
|
27
|
+
|
|
28
|
+
Внутрішні (не експортовані) константи:
|
|
29
|
+
|
|
30
|
+
- `SOURCE_FILE_RE` — `/\.([cm]?[jt]sx?)$/u` — регулярний вираз для розширень `.js`, `.cjs`, `.mjs`, `.jsx`, `.ts`, `.cts`, `.mts`, `.tsx`.
|
|
31
|
+
- `FORBIDDEN_MODULES` — `Set` з двох імен модулів: `'@nitra/bunyan'` і `'bunyan'`.
|
|
32
|
+
|
|
33
|
+
## Функції
|
|
34
|
+
|
|
35
|
+
### `findBunyanImportsInText(content, virtualPath = 'scan.ts')`
|
|
36
|
+
|
|
37
|
+
Основний сканер. Парсить переданий текст як модуль JS/TS і збирає всі місця, де згадуються заборонені модулі через статичний `import`, `require(...)` або динамічний `import(...)`.
|
|
38
|
+
|
|
39
|
+
- Сигнатура: `findBunyanImportsInText(content: string, virtualPath?: string) => { line: number, snippet: string, module: string }[]`
|
|
40
|
+
- Параметри:
|
|
41
|
+
- `content` (`string`) — повний вихідний код, який треба перевірити.
|
|
42
|
+
- `virtualPath` (`string`, опційно, за замовчуванням `'scan.ts'`) — віртуальний шлях, який передається в парсер; використовується тільки для вибору `lang` (TS/JS/JSX/TSX) через `langFromPath(...)`. Реальний файл на диску не читається.
|
|
43
|
+
- Повертає: масив об'єктів-порушень. Кожен елемент:
|
|
44
|
+
- `line` — номер рядка (1-індекс) місця початку конструкції (`offsetToLine`).
|
|
45
|
+
- `snippet` — нормалізований текстовий зріз `content.slice(start, end)` через `normalizeSnippet` (стискання пробілів/обрізання).
|
|
46
|
+
- `module` — рядок самого імпортованого імені (`'@nitra/bunyan'` або `'bunyan'`).
|
|
47
|
+
- Порядок результату: спершу всі статичні `import`-и в порядку їх появи в `module.staticImports`, далі — `require`/`import(...)` у порядку обходу AST через `walkAstWithAncestors`.
|
|
48
|
+
- Side effects: відсутні. Функція суто функціональна: жодних I/O, мутацій вхідних параметрів чи логів. Виняткова поведінка `parseSync` поглинається `try/catch`, помилки парсера в `result.errors` трактуються як «нічого не знайдено» — повертається `[]`.
|
|
49
|
+
- Граничні випадки:
|
|
50
|
+
- `virtualPath` falsy (порожній рядок, `undefined`) — використовується запасне значення `'scan.ts'`.
|
|
51
|
+
- Якщо `parseSync` кинув виняток або у `result.errors` є записи — повертається `[]`.
|
|
52
|
+
- Якщо `result.module` відсутній (наприклад, скрипт CJS), цикл по `module.staticImports` пропускається через `?? []`, AST-обхід усе одно виконується.
|
|
53
|
+
- Для `require`/динамічного `import` модулі з не-літеральним аргументом (`require(name)`) хелпери з `ast-scan-utils` повернуть `null` і вузол буде проігноровано.
|
|
54
|
+
|
|
55
|
+
### `isBunyanScanSourceFile(relativePath)`
|
|
56
|
+
|
|
57
|
+
Швидкий фільтр за розширенням — чи має сенс взагалі парсити цей файл.
|
|
58
|
+
|
|
59
|
+
- Сигнатура: `isBunyanScanSourceFile(relativePath: string) => boolean`
|
|
60
|
+
- Параметри:
|
|
61
|
+
- `relativePath` (`string`) — відносний шлях до файлу (формат розділювача не важливий, перевіряється тільки суфікс).
|
|
62
|
+
- Повертає: `true`, якщо розширення входить у JS/TS-сім'ю (`.js`, `.cjs`, `.mjs`, `.jsx`, `.ts`, `.cts`, `.mts`, `.tsx`); інакше `false`.
|
|
63
|
+
- Side effects: відсутні; чиста перевірка регулярним виразом `SOURCE_FILE_RE`.
|
|
64
|
+
|
|
65
|
+
### `shouldSkipFileForBunyanScan(relativePosix)`
|
|
66
|
+
|
|
67
|
+
Виключення для декларацій типів TypeScript.
|
|
68
|
+
|
|
69
|
+
- Сигнатура: `shouldSkipFileForBunyanScan(relativePosix: string) => boolean`
|
|
70
|
+
- Параметри:
|
|
71
|
+
- `relativePosix` (`string`) — шлях у posix-форматі (з `/`).
|
|
72
|
+
- Повертає: `true`, якщо шлях завершується на `.d.ts` — такий файл містить лише типи й не повинен сканеритися; інакше `false`.
|
|
73
|
+
- Side effects: відсутні.
|
|
74
|
+
- Примітка: цей хелпер логічно йде паралельно до `isBunyanScanSourceFile`. Файл `*.d.ts` теж задовольнить `SOURCE_FILE_RE`, тож обхідник пакета має застосовувати **обидва** хелпери: спочатку відсіяти за розширенням, потім додатково пропустити `.d.ts`.
|
|
75
|
+
|
|
76
|
+
## Залежності
|
|
77
|
+
|
|
78
|
+
Зовнішні (`node_modules`):
|
|
79
|
+
|
|
80
|
+
- `oxc-parser` — парсер JS/TS, експортує `parseSync`. Сканер користується вузлами `module.staticImports` (метадані статичних `import`-декларацій) та повним AST програми (`result.program`).
|
|
81
|
+
|
|
82
|
+
Внутрішні (відносний імпорт з `../../../scripts/utils/ast-scan-utils.mjs`):
|
|
83
|
+
|
|
84
|
+
- `dynamicImportModule(node)` — повертає рядок-аргумент динамічного `import('...')` або `null`.
|
|
85
|
+
- `langFromPath(path)` — визначає `lang` (`'ts'`, `'tsx'`, `'js'`, `'jsx'`, …) за розширенням шляху для `parseSync`.
|
|
86
|
+
- `normalizeSnippet(text)` — нормалізує сирий шматок коду перед збереженням у результат (типово стискає пробіли / обрізає).
|
|
87
|
+
- `offsetToLine(content, offset)` — перетворює числовий offset у тексті на 1-індексований номер рядка.
|
|
88
|
+
- `requireCallModule(node)` — повертає рядок-аргумент виклику `require('...')` або `null`.
|
|
89
|
+
- `walkAstWithAncestors(program, ancestors, visitor)` — обхід AST з accumulator-предків (тут передається порожній масив; колбек дивиться лише на поточний `node`).
|
|
90
|
+
|
|
91
|
+
Очікувані виклики (хто використовує цей модуль): чек-скрипти правила `js-run` (наприклад, `npm/rules/js-run/check-*.mjs`), які отримують вміст файлів пакета й передають їх у `findBunyanImportsInText`, після чого формують повідомлення про порушення з `line` / `snippet` / `module`. Обхідник файлів пакета використовує `isBunyanScanSourceFile` для фільтра кандидатів і `shouldSkipFileForBunyanScan` для виключень.
|
|
92
|
+
|
|
93
|
+
## Потік виконання / Використання
|
|
94
|
+
|
|
95
|
+
Типовий сценарій інтеграції в чек-правила:
|
|
96
|
+
|
|
97
|
+
1. Обхідник перебирає всі файли пакета та конвертує шляхи у posix-формат.
|
|
98
|
+
2. Для кожного `relativePosix` викликається `isBunyanScanSourceFile(relativePosix)`. Якщо `false` — файл пропускається.
|
|
99
|
+
3. Якщо `shouldSkipFileForBunyanScan(relativePosix)` повертає `true` (тобто `*.d.ts`) — файл також пропускається.
|
|
100
|
+
4. Інакше файл читається з диска (зовнішнім кодом), а його вміст подається у `findBunyanImportsInText(content, relativePosix)`.
|
|
101
|
+
5. Усередині `findBunyanImportsInText`:
|
|
102
|
+
1. Обчислюється `lang` через `langFromPath(virtualPath)`.
|
|
103
|
+
2. Викликається `parseSync(virtualPath, content, { lang, sourceType: 'module' })` всередині `try/catch`.
|
|
104
|
+
3. Якщо парсер кинув виняток або в `result.errors` є записи — повертається `[]`.
|
|
105
|
+
4. Інакше перебираються `result.module?.staticImports ?? []`; для кожного `import`, де `moduleRequest.value` входить у `FORBIDDEN_MODULES`, до результату додається запис `{ line, snippet, module }`.
|
|
106
|
+
5. Далі `walkAstWithAncestors(result.program, [], visitor)` проходить по AST. У відвідувача:
|
|
107
|
+
- `requireCallModule(node)` повертає не-`null` для `require('...')` — якщо модуль заборонений, додаємо запис; інакше пропускаємо.
|
|
108
|
+
- `dynamicImportModule(node)` — те саме для динамічного `import('...')`.
|
|
109
|
+
6. Викликач отримує плаский масив порушень і формує звіт (наприклад, друкує `path:line` та `snippet`).
|
|
110
|
+
|
|
111
|
+
Гарантії та особливості:
|
|
112
|
+
|
|
113
|
+
- Чисто синхронний прохід — жодного I/O всередині модуля.
|
|
114
|
+
- Якщо файл містить синтаксичні помилки, результат `[]` означає **не «все добре»**, а «парсер не зрозумів файл» — це усвідомлене дизайн-рішення: спершу виправити синтаксис, потім перезапустити перевірку.
|
|
115
|
+
- Регулярка `SOURCE_FILE_RE` не покриває нестандартні розширення (наприклад, `.vue`, `.svelte`). Якщо для них потрібен власний пайплайн (з вилученням `<script>` блоку), його треба будувати окремо.
|
|
116
|
+
- Між списком `module.staticImports` і обходом AST вузли `import` не дублюються: статичні `import`-декларації обходяться лише через `module.staticImports`, а у візиторі перевіряються тільки `require` та динамічний `import(...)`.
|
|
117
|
+
- Перелік заборонених модулів суворо обмежений `FORBIDDEN_MODULES` (рівність рядків). Підшляхи на кшталт `@nitra/bunyan/foo` не вловлюються — це навмисна вузька семантика правила.
|