@nitra/cursor 1.13.89 → 1.14.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 +27 -0
- package/package.json +1 -1
- package/rules/abie/abie.mdc +8 -8
- package/rules/abie/js/{applies/check.mjs → applies.mjs} +2 -2
- package/rules/abie/js/{env_dns/check.mjs → env_dns.mjs} +3 -3
- package/rules/abie/js/{firebase_hosting/check.mjs → firebase_hosting.mjs} +1 -1
- package/rules/abie/js/{hc_pairing/check.mjs → hc_pairing.mjs} +4 -4
- package/rules/abie/js/{ua_http_route/check.mjs → ua_http_route.mjs} +6 -6
- package/rules/abie/js/{ua_node_selector/check.mjs → ua_node_selector.mjs} +5 -5
- package/rules/abie/policy/base_deployment_preem/base_deployment_preem.rego +2 -2
- package/rules/abie/policy/health_check_policy/health_check_policy.rego +2 -2
- package/rules/abie/policy/http_route_base/http_route_base.rego +1 -1
- package/rules/abie/utils/enabled.mjs +1 -1
- package/rules/abie/utils/k8s-tree.mjs +1 -1
- package/rules/adr/js/{hooks/check.mjs → hooks.mjs} +1 -1
- package/rules/bun/js/{layout/check.mjs → layout.mjs} +1 -1
- package/rules/capacitor/js/{platforms/check.mjs → platforms.mjs} +1 -1
- package/rules/changelog/changelog.mdc +1 -1
- package/rules/changelog/js/{consistency/check.mjs → consistency.mjs} +2 -2
- package/rules/changelog/{js/consistency → utils}/package-manifest.mjs +1 -1
- package/rules/docker/js/{lint/check.mjs → lint.mjs} +5 -5
- package/rules/docker/lint/lint.mjs +1 -1
- package/rules/docker/{js/lint → utils}/docker-hadolint.mjs +1 -1
- package/rules/feedback/feedback.mdc +1 -1
- package/rules/ga/js/{workflows/check.mjs → workflows.mjs} +5 -5
- package/rules/ga/lint/lint.mjs +1 -1
- package/rules/graphql/js/{tooling/check.mjs → tooling.mjs} +5 -5
- package/rules/hasura/js/{internal_urls/check.mjs → internal_urls.mjs} +4 -4
- package/rules/hasura/policy/svc_hl/svc_hl.rego +1 -1
- package/rules/image-avif/js/{avif_generation/check.mjs → avif_generation.mjs} +5 -5
- package/rules/image-compress/js/{package_setup/check.mjs → package_setup.mjs} +1 -1
- package/rules/js-bun-db/js/{safety/check.mjs → safety.mjs} +5 -5
- package/rules/js-bun-db/{js/safety → utils}/bun-sql-scan.mjs +1 -1
- package/rules/js-bun-redis/js/{imports/check.mjs → imports.mjs} +4 -4
- package/rules/js-bun-redis/policy/package_json/package_json.rego +1 -1
- package/rules/js-lint/js/{tooling/check.mjs → tooling.mjs} +8 -4
- package/rules/js-lint/js-lint.mdc +11 -1
- package/rules/js-lint/{js/tooling → utils}/rebuild-oxlint-canonical.mjs +2 -2
- package/rules/js-mssql/js/{deps/check.mjs → deps.mjs} +5 -5
- package/rules/js-mssql/{js/deps → utils}/mssql-pool-scan.mjs +1 -1
- package/rules/js-run/js/{runtime/check.mjs → runtime.mjs} +10 -10
- package/rules/js-run/{js/runtime → utils}/bunyan-imports.mjs +1 -1
- package/rules/js-run/{js/runtime → utils}/check-env-scan.mjs +1 -1
- package/rules/js-run/{js/runtime → utils}/conn-file-rules.mjs +1 -1
- package/rules/js-run/{js/runtime → utils}/conn-imports-scan.mjs +1 -1
- package/rules/js-run/{js/runtime → utils}/promise-settimeout-scan.mjs +1 -1
- package/rules/k8s/js/{manifests/check.mjs → manifests.mjs} +4 -4
- package/rules/k8s/k8s.mdc +1 -1
- package/rules/nginx-default-tpl/js/{template/check.mjs → template.mjs} +5 -5
- package/rules/npm-module/js/{package_structure/check.mjs → package_structure.mjs} +4 -4
- package/rules/php/js/{tooling/check.mjs → tooling.mjs} +1 -1
- package/rules/rego/js/{applies/check.mjs → applies.mjs} +3 -3
- package/rules/security/js/{sample_secret/check.mjs → sample_secret.mjs} +2 -2
- package/rules/security/js/{trufflehog/check.mjs → trufflehog.mjs} +3 -3
- package/rules/security/security.mdc +2 -2
- package/rules/style-lint/js/{tooling/check.mjs → tooling.mjs} +1 -1
- package/rules/tauri/js/{tooling/check.mjs → tooling.mjs} +2 -2
- package/rules/test/js/{location/check.mjs → location.mjs} +3 -3
- package/rules/text/js/{formatting/check.mjs → formatting.mjs} +2 -2
- package/rules/vue/js/{packages/check.mjs → packages.mjs} +5 -5
- package/scripts/auto-rules.mjs +3 -3
- package/scripts/sync-claude-config.mjs +1 -1
- package/scripts/utils/discover-checkable-rules.mjs +20 -27
- package/scripts/utils/inline-template-links.mjs +1 -1
- package/scripts/utils/run-rule.mjs +18 -23
- /package/rules/adr/js/{hooks/template → templates/hooks}/.gitignore.snippet +0 -0
- /package/rules/docker/{js/lint → utils}/docker-mirror.mjs +0 -0
- /package/rules/graphql/{js/tooling → utils}/graphql-gql-scan.mjs +0 -0
- /package/rules/js-lint/js/{tooling → data/tooling}/knip-canonical.json +0 -0
- /package/rules/js-lint/js/{tooling → data/tooling}/oxlint-canonical-skeleton.json +0 -0
- /package/rules/js-lint/js/{tooling → data/tooling}/oxlint-canonical.json +0 -0
- /package/rules/js-lint/js/{tooling → data/tooling}/oxlint-rules.tsv +0 -0
- /package/rules/k8s/js/{kubescape_exceptions/template → templates/kubescape_exceptions}/.kubescape-exceptions.json.snippet.json +0 -0
- /package/rules/security/js/{trufflehog/template → templates/trufflehog}/.trufflehog-exclude.snippet.txt +0 -0
- /package/rules/vue/{js/packages → utils}/vue-forbidden-imports.mjs +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,33 @@
|
|
|
4
4
|
|
|
5
5
|
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
|
|
6
6
|
|
|
7
|
+
## [1.14.0] - 2026-05-24
|
|
8
|
+
|
|
9
|
+
### Changed (BREAKING)
|
|
10
|
+
|
|
11
|
+
- **Flat концерн-лейаут:** кожен JS-концерн правила тепер один файл `npm/rules/<rule>/js/<concern>.mjs` замість вкладеного `js/<concern>/check.mjs`. Tests — у `js/tests/<concern>.test.mjs` (single) або `js/tests/<concern>/<name>.test.mjs` (multi+fixtures). Templates — у `js/templates/<concern>/`. Data (json/tsv) — у `js/data/<concern>/`. Helpers (cross-concern і concern-private) — у `<rule>/utils/<helper>.mjs` peer до `js/` (existing convention з `abie/utils/`).
|
|
12
|
+
- **`JsConcern.files` removed:** один файл на concern, поле більше не потрібне. `runRule` обчислює шлях як `<rule>/js/<concern.name>.mjs`; `resolveJsCheckPath` тепер `(bundledRulesDir, ruleId, concern)` без `fileName`.
|
|
13
|
+
- **`CHECK_FILENAME_RE` і `TEST_SUFFIX` removed:** discovery більше не використовує regex `check-*.mjs` — `listJsConcerns` фільтрує `*.mjs` без `.test.mjs` (підкаталоги скіпаються через `!isFile()`).
|
|
14
|
+
- **`scripts/sync-claude-config.mjs::ADR_GITIGNORE_SNIPPET_REL`** змінено: `rules/adr/js/hooks/template/.gitignore.snippet` → `rules/adr/js/templates/hooks/.gitignore.snippet`.
|
|
15
|
+
- **`scripts/utils/inline-template-links.mjs::TEMPLATE_SEGMENT_RE`** розширено з `/\/template\//` до `/\/templates?\//` — підтримує і `js/templates/` (нова конвенція), і `policy/<concern>/template/` (існуюча).
|
|
16
|
+
|
|
17
|
+
### Breaking (для зовнішніх інтеграторів)
|
|
18
|
+
|
|
19
|
+
- Каталог `npm/rules/<rule>/js/<concern>/check.mjs` тепер `npm/rules/<rule>/js/<concern>.mjs`. Tests → `js/tests/`, templates → `js/templates/`, data → `js/data/` (усе всередині `js/`); helpers → `<rule>/utils/<helper>.mjs` (peer до `js/`, як `abie/utils/`). Імпорти helpers з concern-файлів: `from '../utils/<helper>.mjs'`. Міграційний скрипт у git-історії — комміт `refactor(rules): flat layout js/<concern>.mjs (міграційний move)`.
|
|
20
|
+
|
|
21
|
+
### Notes
|
|
22
|
+
|
|
23
|
+
- Convention для helper-імен: namespace-префікс (`<rule>-` або `<concern>-`) робить колізії у плоскому `utils/` неможливими (як уже робить abie: `k8s-tree`, `kustomization-patches`; docker: `docker-mirror`; vue: `vue-forbidden-imports`).
|
|
24
|
+
- Шпаргалка імпорт-шляхів у `.cursor/rules/scripts.mdc` (1.10 → 1.11).
|
|
25
|
+
- `.cursor/rules/conftest.mdc` — алгоритм Rego-first переписаний під flat-layout.
|
|
26
|
+
- Канонічні `security.mdc` і `k8s.mdc` markdown-лінки на template-файли оновлені (`./js/templates/<concern>/`).
|
|
27
|
+
|
|
28
|
+
## [1.13.90] - 2026-05-24
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- **`js-lint` 1.23 → 1.24 — конвенція `utils/` vs `lib/`:** додано секцію «Структура спільних модулів». `utils/` — низькорівневі generic helpers без домену (могли б жити окремим npm-пакетом); `lib/` — внутрішні модулі з доменним state/конфігом/side effects. Канонічні назви лише ці дві — не `shared/`, не `common/`. Дзеркало `.cursor/rules/n-js-lint.mdc` оновлено.
|
|
33
|
+
|
|
7
34
|
## [1.13.89] - 2026-05-23
|
|
8
35
|
|
|
9
36
|
### Changed
|
package/package.json
CHANGED
package/rules/abie/abie.mdc
CHANGED
|
@@ -133,7 +133,7 @@ KVCMS_URL=http://kvcms-hl.ua-apruv.svc.abie-ua.internal:8080
|
|
|
133
133
|
|
|
134
134
|
`<namespace>` (наприклад `dev-apruv` / `ua-apruv`) — `metadata.name` цільового namespace після kustomize-overlay для відповідного середовища; `<service>` — `metadata.name` headless Service (`-hl`) того сервісу, до якого йде URL.
|
|
135
135
|
|
|
136
|
-
**Перевірка `js/env_dns
|
|
136
|
+
**Перевірка `js/env_dns.mjs`** сканує всі `*.env` файли, basename яких збігається з `dev.env` / `ua.env` (з провідною крапкою чи без), знаходить **усі** internal URL (`http://<svc>.<ns>.svc.<dns>` — як для Hasura-ендпоінта, так і для KVCMS чи будь-якого іншого) і вимагає, щоб для кожного:
|
|
137
137
|
|
|
138
138
|
- DNS-суфікс відповідав env: `abie-dev.internal` / `abie-ua.internal`;
|
|
139
139
|
- namespace починався з `dev-` / `ua-` відповідно.
|
|
@@ -160,7 +160,7 @@ bun add -d @nitra/abie-docs
|
|
|
160
160
|
|
|
161
161
|
## Швидкий gate через conftest (Rego)
|
|
162
162
|
|
|
163
|
-
Підмножину пер-документних правил продубльовано як rego-полісі у **`npm/rules/abie/policy/`** (запускається через **`bun run lint-rego`** для `*_test.rego` юніт-тестів і через **`npx @nitra/cursor fix abie`** для прогону по реальних YAML — деталі в **conftest.mdc** / **n-rego.mdc**). JS у **`js/<concern
|
|
163
|
+
Підмножину пер-документних правил продубльовано як rego-полісі у **`npm/rules/abie/policy/`** (запускається через **`bun run lint-rego`** для `*_test.rego` юніт-тестів і через **`npx @nitra/cursor fix abie`** для прогону по реальних YAML — деталі в **conftest.mdc** / **n-rego.mdc**). JS у **`js/<concern>.mjs`** authoritative — rego тільки швидкий gate для одиничного маніфеста (зокрема через IDE-розширення `tsandall.opa`).
|
|
164
164
|
|
|
165
165
|
Пакети (директорія в **`npm/policy/abie/`** → namespace → що перевіряє):
|
|
166
166
|
|
|
@@ -170,12 +170,12 @@ bun add -d @nitra/abie-docs
|
|
|
170
170
|
- **`clean_merged_ignore_branches/`** → `abie.clean_merged_ignore_branches` — у workflow `.github/workflows/clean-merged-branch.yml` крок з `uses: phpdocker-io/github-actions-delete-abandoned-branches` має `with.ignore_branches`, що містить токени `dev,ua` (case-insensitive). **Цільові файли:** `.github/workflows/clean-merged-branch.yml`.
|
|
171
171
|
- **`package_json_docs/`** → `abie.package_json_docs` — у кореневому `package.json` `devDependencies` має містити `@nitra/abie-docs` (presence-only, версію не фіксуємо). **Цільові файли:** `package.json`.
|
|
172
172
|
|
|
173
|
-
Cross-file / FS-логіка лишається у JS-частинах (`js/<concern
|
|
173
|
+
Cross-file / FS-логіка лишається у JS-частинах (`js/<concern>.mjs`) — Rego не читає файлову систему й не робить cross-document резолюцію:
|
|
174
174
|
|
|
175
|
-
- парність HCP↔Deployment у каталозі та modeline `hc.yaml` — `js/hc_pairing
|
|
176
|
-
- валідація ua-overlay JSON6902 patches на HTTPRoute + аналіз cross-namespace `backendRefs` у пакетах — `js/ua_http_route
|
|
177
|
-
- ua-overlay JSON6902 patch на `Deployment.nodeSelector` (`preem: false`) — `js/ua_node_selector
|
|
178
|
-
- env→cluster DNS (`*.dev.env` / `*.ua.env`) — `js/env_dns
|
|
179
|
-
- скан артефактів Firebase Hosting у підкаталогах першого рівня — `js/firebase_hosting
|
|
175
|
+
- парність HCP↔Deployment у каталозі та modeline `hc.yaml` — `js/hc_pairing.mjs`;
|
|
176
|
+
- валідація ua-overlay JSON6902 patches на HTTPRoute + аналіз cross-namespace `backendRefs` у пакетах — `js/ua_http_route.mjs`;
|
|
177
|
+
- ua-overlay JSON6902 patch на `Deployment.nodeSelector` (`preem: false`) — `js/ua_node_selector.mjs`;
|
|
178
|
+
- env→cluster DNS (`*.dev.env` / `*.ua.env`) — `js/env_dns.mjs`;
|
|
179
|
+
- скан артефактів Firebase Hosting у підкаталогах першого рівня — `js/firebase_hosting.mjs`.
|
|
180
180
|
|
|
181
181
|
Точна звірка `targetRef.name` HealthCheckPolicy з суфіксом `-hl` обчислюється з `hcp.metadata.name` і живе у Rego (`abie.health_check_policy`); за конвенцією `hcp.metadata.name` дорівнює `<deployment.name>`, тому окремий cross-file lookup до маніфесту Deployment не потрібен.
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* Якщо повертає `false` — CLI пропускає всі концерни (JS і policy) цього правила.
|
|
4
4
|
* `check()` друкує тільки context-pass; решта концернів роблять справжню роботу.
|
|
5
5
|
*/
|
|
6
|
-
import { createCheckReporter } from '
|
|
6
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
7
7
|
|
|
8
|
-
import { isAbieRuleEnabled } from '
|
|
8
|
+
import { isAbieRuleEnabled } from '../utils/enabled.mjs'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @returns {Promise<boolean>} `true` — правило застосовне; `false` — пропустити
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
import { readFile } from 'node:fs/promises'
|
|
10
10
|
import { basename, relative } from 'node:path'
|
|
11
11
|
|
|
12
|
-
import { createCheckReporter } from '
|
|
13
|
-
import { loadCursorIgnorePaths } from '
|
|
12
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
13
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
14
14
|
|
|
15
|
-
import { abieEnvNameFromBasename, collectAbieEnvFiles, validateAbieEnvInternalUrls } from '
|
|
15
|
+
import { abieEnvNameFromBasename, collectAbieEnvFiles, validateAbieEnvInternalUrls } from '../utils/env-dns.mjs'
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* @returns {Promise<number>} результат
|
|
@@ -7,7 +7,7 @@ import { existsSync } from 'node:fs'
|
|
|
7
7
|
import { readdir } from 'node:fs/promises'
|
|
8
8
|
import { join } from 'node:path'
|
|
9
9
|
|
|
10
|
-
import { createCheckReporter } from '
|
|
10
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
11
11
|
|
|
12
12
|
const SKIP_TOP_DIR_NAMES = new Set(['.git', 'node_modules'])
|
|
13
13
|
|
|
@@ -10,11 +10,11 @@ import { existsSync } from 'node:fs'
|
|
|
10
10
|
import { readFile } from 'node:fs/promises'
|
|
11
11
|
import { relative } from 'node:path'
|
|
12
12
|
|
|
13
|
-
import { createCheckReporter } from '
|
|
14
|
-
import { loadCursorIgnorePaths } from '
|
|
13
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
14
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
15
15
|
|
|
16
|
-
import { validateAbieHcModeline } from '
|
|
17
|
-
import { collectDeploymentDirs, findK8sYamlFiles } from '
|
|
16
|
+
import { validateAbieHcModeline } from '../utils/hc-yaml.mjs'
|
|
17
|
+
import { collectDeploymentDirs, findK8sYamlFiles } from '../utils/k8s-tree.mjs'
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* @returns {Promise<number>} результат
|
|
@@ -10,20 +10,20 @@
|
|
|
10
10
|
import { readFile } from 'node:fs/promises'
|
|
11
11
|
import { relative } from 'node:path'
|
|
12
12
|
|
|
13
|
-
import { createCheckReporter } from '
|
|
14
|
-
import { loadCursorIgnorePaths } from '
|
|
13
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
14
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
15
15
|
|
|
16
|
-
import { analyzeAbieSharedBackendRefsInPackageK8s } from '
|
|
17
|
-
import { findK8sYamlFiles } from '
|
|
16
|
+
import { analyzeAbieSharedBackendRefsInPackageK8s } from '../utils/http-route.mjs'
|
|
17
|
+
import { findK8sYamlFiles } from '../utils/k8s-tree.mjs'
|
|
18
18
|
import {
|
|
19
19
|
getCombinedNginxRunPatchTextFromKustomization,
|
|
20
20
|
validateAbieNginxRunHttpRoutePatches
|
|
21
|
-
} from '
|
|
21
|
+
} from '../utils/kustomization-patches.mjs'
|
|
22
22
|
import {
|
|
23
23
|
abiePackageDirFromK8sOverlay,
|
|
24
24
|
abieOverlayRequiresHttpRouteByVite,
|
|
25
25
|
isUaKustomizationPath
|
|
26
|
-
} from '
|
|
26
|
+
} from '../utils/overlay-paths.mjs'
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* @returns {Promise<number>} результат
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
import { readFile } from 'node:fs/promises'
|
|
9
9
|
import { relative } from 'node:path'
|
|
10
10
|
|
|
11
|
-
import { createCheckReporter } from '
|
|
12
|
-
import { loadCursorIgnorePaths } from '
|
|
11
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
12
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
13
13
|
|
|
14
|
-
import { collectDeploymentDirs, findK8sYamlFiles } from '
|
|
15
|
-
import { kustomizationHasAbieDeploymentNodeSelectorPatch } from '
|
|
16
|
-
import { abieOverlayK8sTreeHasDeployment, isUaKustomizationPath } from '
|
|
14
|
+
import { collectDeploymentDirs, findK8sYamlFiles } from '../utils/k8s-tree.mjs'
|
|
15
|
+
import { kustomizationHasAbieDeploymentNodeSelectorPatch } from '../utils/kustomization-patches.mjs'
|
|
16
|
+
import { abieOverlayK8sTreeHasDeployment, isUaKustomizationPath } from '../utils/overlay-paths.mjs'
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* @returns {Promise<number>} результат
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# `spec.template.spec.nodeSelector.preem` зі значенням, що вважається істинним
|
|
3
3
|
# (boolean `true` або рядок `"true"` без урахування регістру). Overlay ua далі
|
|
4
4
|
# підміняє селектор JSON6902-патчем на `preem: false`
|
|
5
|
-
# (див. `js/ua_node_selector
|
|
5
|
+
# (див. `js/ua_node_selector.mjs`).
|
|
6
6
|
#
|
|
7
7
|
# Запуск (локально, лише для одного base-YAML з Deployment):
|
|
8
8
|
# conftest test path/to/k8s/base/deployment.yaml \
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
#
|
|
12
12
|
# Cross-file gating: шлях `…/k8s/.../base/…` фільтрується через
|
|
13
13
|
# `policy/base_deployment_preem/target.json` (glob). Rule-level applies-гейт —
|
|
14
|
-
# `js/applies
|
|
14
|
+
# `js/applies.mjs` (поле `rules` у `.n-cursor.json`).
|
|
15
15
|
#
|
|
16
16
|
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
17
17
|
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
#
|
|
19
19
|
# Cross-file gating: glob по `hc.yaml` у k8s-дереві — у
|
|
20
20
|
# `policy/health_check_policy/target.json`. FS-парність HCP↔Deployment та
|
|
21
|
-
# modeline `hc.yaml` — `js/hc_pairing
|
|
22
|
-
# `js/applies
|
|
21
|
+
# modeline `hc.yaml` — `js/hc_pairing.mjs`. Rule-level applies-гейт —
|
|
22
|
+
# `js/applies.mjs`.
|
|
23
23
|
#
|
|
24
24
|
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
25
25
|
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
#
|
|
9
9
|
# Cross-file gating (саме шлях `…/k8s/.../base/...` визначає, чи застосовувати
|
|
10
10
|
# правило) задає glob у `policy/http_route_base/target.json`. Тут — лише
|
|
11
|
-
# валідація вмісту `spec.hostnames`. Rule-level applies-гейт — `js/applies
|
|
11
|
+
# валідація вмісту `spec.hostnames`. Rule-level applies-гейт — `js/applies.mjs`.
|
|
12
12
|
#
|
|
13
13
|
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
14
14
|
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Rule-level applies-гейт abie: чи `.n-cursor.json:rules` містить `abie`.
|
|
3
|
-
* Використовується `js/applies
|
|
3
|
+
* Використовується `js/applies.mjs` як `applies()`-експорт — якщо false,
|
|
4
4
|
* CLI пропускає всі концерни правила (включно з policy).
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync } from 'node:fs'
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { dirname, relative } from 'node:path'
|
|
10
10
|
|
|
11
|
-
import { pathHasK8sSegment } from '../../k8s/js/manifests
|
|
11
|
+
import { pathHasK8sSegment } from '../../k8s/js/manifests.mjs'
|
|
12
12
|
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
13
13
|
import { isDeploymentDoc, readAndParseYamlDocs } from './yaml.mjs'
|
|
14
14
|
|
|
@@ -24,7 +24,7 @@ import { delimiter, dirname, join } from 'node:path'
|
|
|
24
24
|
import { env } from 'node:process'
|
|
25
25
|
import { fileURLToPath } from 'node:url'
|
|
26
26
|
|
|
27
|
-
import { createCheckReporter } from '
|
|
27
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
28
28
|
|
|
29
29
|
/** Один hook-артефакт: bash-скрипт + його лог-файл, які перевіряємо однотипно. */
|
|
30
30
|
const HOOK_ARTIFACTS = /** @type {const} */ ([
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
import { existsSync } from 'node:fs'
|
|
21
21
|
import { readFile } from 'node:fs/promises'
|
|
22
22
|
|
|
23
|
-
import { createCheckReporter } from '
|
|
23
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
24
24
|
|
|
25
25
|
/** Розділювач токенів у `scripts.lint` (послідовність пробільних символів). */
|
|
26
26
|
const WHITESPACE_RE = /\s+/u
|
|
@@ -25,7 +25,7 @@ import { existsSync } from 'node:fs'
|
|
|
25
25
|
import { readdir, readFile } from 'node:fs/promises'
|
|
26
26
|
import { join, relative } from 'node:path'
|
|
27
27
|
|
|
28
|
-
import { createCheckReporter } from '
|
|
28
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
29
29
|
|
|
30
30
|
/** Мінімальна допустима мажорна версія Capacitor (capacitor.mdc) */
|
|
31
31
|
const MIN_CAPACITOR_MAJOR = 8
|
|
@@ -43,7 +43,7 @@ alwaysApply: true
|
|
|
43
43
|
|
|
44
44
|
**Вимагають bump + нову секцію CHANGELOG** — усі інші зміни в каталозі workspace (код, rego, правила, скіли, конфіги, тести тощо). Виняток `.cursor/` / `.claude/` **не** поширюється на джерело правил у репо `@nitra/cursor` — воно лежить під `npm/`, тож зміни в ньому далі вимагають bump.
|
|
45
45
|
|
|
46
|
-
Перевірка програмна (`changelog/js/consistency
|
|
46
|
+
Перевірка програмна (`changelog/js/consistency.mjs`).
|
|
47
47
|
|
|
48
48
|
## Дві моделі бази порівняння
|
|
49
49
|
|
|
@@ -22,13 +22,13 @@ import { readFile } from 'node:fs/promises'
|
|
|
22
22
|
import { join } from 'node:path'
|
|
23
23
|
import { promisify } from 'node:util'
|
|
24
24
|
|
|
25
|
-
import { createCheckReporter } from '
|
|
25
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
26
26
|
import {
|
|
27
27
|
getMonorepoProjectRootDirs,
|
|
28
28
|
manifestFilePath,
|
|
29
29
|
parsePyprojectFields,
|
|
30
30
|
readPackageManifest
|
|
31
|
-
} from '
|
|
31
|
+
} from '../utils/package-manifest.mjs'
|
|
32
32
|
|
|
33
33
|
const execFileAsync = promisify(execFile)
|
|
34
34
|
|
|
@@ -8,7 +8,7 @@ import { dirname, join, relative } from 'node:path'
|
|
|
8
8
|
|
|
9
9
|
import { parse as parseToml } from 'smol-toml'
|
|
10
10
|
|
|
11
|
-
import { getMonorepoPackageRootDirs, isIgnoredWorkspaceRoot } from '
|
|
11
|
+
import { getMonorepoPackageRootDirs, isIgnoredWorkspaceRoot } from '../../../scripts/utils/workspaces.mjs'
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @typedef {'npm' | 'python'} PackageKind
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
import { readFile } from 'node:fs/promises'
|
|
31
31
|
import { basename } from 'node:path'
|
|
32
32
|
|
|
33
|
-
import { getMirrorGcrHint, getFromImageToken } from '
|
|
34
|
-
import { lintDockerfileWithHadolint, posixRel } from '
|
|
35
|
-
import { createCheckReporter } from '
|
|
36
|
-
import { loadCursorIgnorePaths } from '
|
|
37
|
-
import { walkDir } from '
|
|
33
|
+
import { getMirrorGcrHint, getFromImageToken } from '../utils/docker-mirror.mjs'
|
|
34
|
+
import { lintDockerfileWithHadolint, posixRel } from '../utils/docker-hadolint.mjs'
|
|
35
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
36
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
37
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
38
38
|
|
|
39
39
|
const NEWLINE_RE = /\r?\n/
|
|
40
40
|
const BUN_INSTALL_RE = /\bbun\s+(?:install|i)\b/iu
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { basename } from 'node:path'
|
|
14
14
|
|
|
15
15
|
import { isRunAsCli } from '../../../scripts/cli-entry.mjs'
|
|
16
|
-
import { lintDockerfileWithHadolint, posixRel } from '../
|
|
16
|
+
import { lintDockerfileWithHadolint, posixRel } from '../utils/docker-hadolint.mjs'
|
|
17
17
|
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
18
18
|
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
19
19
|
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { spawnSync } from 'node:child_process'
|
|
9
9
|
import { relative, sep } from 'node:path'
|
|
10
10
|
|
|
11
|
-
import { resolveCmd } from '
|
|
11
|
+
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
12
12
|
|
|
13
13
|
/** Тег образу для резервного запуску (узгоджуй з docker.mdc). */
|
|
14
14
|
export const HADOLINT_IMAGE = 'hadolint/hadolint:v2.12.0'
|
|
@@ -17,7 +17,7 @@ version: '1.0'
|
|
|
17
17
|
**Тертя** — усе, що ускладнило роботу скілу й стосується самого пакета `@nitra/cursor`, а не коду користувацького проєкту:
|
|
18
18
|
|
|
19
19
|
- неоднозначна чи неповна інструкція в `SKILL.md` або `.mdc`;
|
|
20
|
-
- правило вимагає поведінку, яку можна перевірити програмно, але програмної перевірки (`rules/<id>/js/<concern
|
|
20
|
+
- правило вимагає поведінку, яку можна перевірити програмно, але програмної перевірки (`rules/<id>/js/<concern>.mjs` або `rules/<id>/policy/<concern>/*.rego`) для неї немає;
|
|
21
21
|
- хибне спрацювання перевірки (false positive);
|
|
22
22
|
- порушення, яке правило вимагає виправляти вручну, хоча реальний автофікс можливий;
|
|
23
23
|
- повторюваний патерн, який варто закодувати в правило чи скіл.
|
|
@@ -20,11 +20,11 @@ import { execFileSync } from 'node:child_process'
|
|
|
20
20
|
import { basename, dirname, join } from 'node:path'
|
|
21
21
|
import { fileURLToPath } from 'node:url'
|
|
22
22
|
|
|
23
|
-
import { createCheckReporter } from '
|
|
24
|
-
import { eventPathsIncludeExact, parseWorkflowYaml } from '
|
|
25
|
-
import { resolveCmd } from '
|
|
26
|
-
import { runConftestBatch } from '
|
|
27
|
-
import { loadTemplate } from '
|
|
23
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
24
|
+
import { eventPathsIncludeExact, parseWorkflowYaml } from '../../../scripts/utils/gha-workflow.mjs'
|
|
25
|
+
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
26
|
+
import { runConftestBatch } from '../../../scripts/utils/run-conftest-batch.mjs'
|
|
27
|
+
import { loadTemplate } from '../../../scripts/utils/template.mjs'
|
|
28
28
|
|
|
29
29
|
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
30
30
|
const GA_POLICY_DIR = join(HERE, '..', '..', 'policy')
|
package/rules/ga/lint/lint.mjs
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
*/
|
|
30
30
|
import { platform } from 'node:process'
|
|
31
31
|
|
|
32
|
-
import { check as checkGa } from '../js/workflows
|
|
32
|
+
import { check as checkGa } from '../js/workflows.mjs'
|
|
33
33
|
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
34
34
|
import { runLintStep } from '../../../scripts/utils/run-lint-step.mjs'
|
|
35
35
|
import { runStandardLint } from '../../../scripts/utils/run-standard-lint.mjs'
|
|
@@ -10,15 +10,15 @@ import { existsSync } from 'node:fs'
|
|
|
10
10
|
import { readFile } from 'node:fs/promises'
|
|
11
11
|
import { relative } from 'node:path'
|
|
12
12
|
|
|
13
|
-
import { createCheckReporter } from '
|
|
13
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
14
14
|
import {
|
|
15
15
|
isGqlScanSourceFile,
|
|
16
16
|
shouldSkipFileForGqlScan,
|
|
17
17
|
sourceFileHasGqlTaggedTemplate
|
|
18
|
-
} from '
|
|
19
|
-
import { loadCursorIgnorePaths } from '
|
|
20
|
-
import { runConftestBatch } from '
|
|
21
|
-
import { walkDir } from '
|
|
18
|
+
} from '../utils/graphql-gql-scan.mjs'
|
|
19
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
20
|
+
import { runConftestBatch } from '../../../scripts/utils/run-conftest-batch.mjs'
|
|
21
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
22
22
|
|
|
23
23
|
/** Очікуваний файл GraphQL Config у корені (graphql.mdc). */
|
|
24
24
|
export const GRAPHQL_RC_FILENAME = '.graphqlrc.yml'
|
|
@@ -28,10 +28,10 @@ import { basename, join, relative } from 'node:path'
|
|
|
28
28
|
|
|
29
29
|
import { parseAllDocuments } from 'yaml'
|
|
30
30
|
|
|
31
|
-
import { getRepositoryUrl } from '
|
|
32
|
-
import { createCheckReporter } from '
|
|
33
|
-
import { loadCursorIgnorePaths } from '
|
|
34
|
-
import { walkDir } from '
|
|
31
|
+
import { getRepositoryUrl } from '../../../scripts/auto-rules.mjs'
|
|
32
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
33
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
34
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
35
35
|
|
|
36
36
|
const NITRA_REPOSITORY_URL_MARKER = 'https://github.com/nitra/'
|
|
37
37
|
const ABIE_REPOSITORY_URL_MARKER = 'https://github.com/abinbevefes/'
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# conftest test hasura/k8s/base/svc-hl.yaml -p npm/rules/hasura/policy/svc_hl \
|
|
9
9
|
# --namespace hasura.svc_hl
|
|
10
10
|
#
|
|
11
|
-
# Cross-file (`HASURA_GRAPHQL_ENDPOINT` ↔ YAML) — `js/internal_urls
|
|
11
|
+
# Cross-file (`HASURA_GRAPHQL_ENDPOINT` ↔ YAML) — `js/internal_urls.mjs`.
|
|
12
12
|
package hasura.svc_hl
|
|
13
13
|
|
|
14
14
|
import rego.v1
|
|
@@ -30,11 +30,11 @@ import { join, relative } from 'node:path'
|
|
|
30
30
|
import { spawnSync } from 'node:child_process'
|
|
31
31
|
import { env } from 'node:process'
|
|
32
32
|
|
|
33
|
-
import { createCheckReporter } from '
|
|
34
|
-
import { loadCursorIgnorePaths } from '
|
|
35
|
-
import { resolveCmd } from '
|
|
36
|
-
import { walkDir } from '
|
|
37
|
-
import { getMonorepoPackageRootDirs } from '
|
|
33
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
34
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
35
|
+
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
36
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
37
|
+
import { getMonorepoPackageRootDirs } from '../../../scripts/utils/workspaces.mjs'
|
|
38
38
|
|
|
39
39
|
/** Імʼя CLI-пакета, який генерує AVIF. */
|
|
40
40
|
const MINIFY_PACKAGE_NAME = '@nitra/minify-image'
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import { existsSync } from 'node:fs'
|
|
20
20
|
import { readFile } from 'node:fs/promises'
|
|
21
21
|
|
|
22
|
-
import { createCheckReporter } from '
|
|
22
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
23
23
|
|
|
24
24
|
/** Імʼя committed-кешу (sha1 + originalSize + size) у `@nitra/minify-image` ≥ 3.2.0. */
|
|
25
25
|
const HASH_CACHE_FILENAME = '.n-minify-image.tsv'
|
|
@@ -33,7 +33,7 @@ import { existsSync } from 'node:fs'
|
|
|
33
33
|
import { readFile } from 'node:fs/promises'
|
|
34
34
|
import { join, relative } from 'node:path'
|
|
35
35
|
|
|
36
|
-
import { createCheckReporter } from '
|
|
36
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
37
37
|
import {
|
|
38
38
|
findBunSqlPerRequestConnectionInText,
|
|
39
39
|
findBunSqlPgLeftoverCallInText,
|
|
@@ -48,10 +48,10 @@ import {
|
|
|
48
48
|
isBunSqlScanSourceFile,
|
|
49
49
|
textHasBunSqlImport,
|
|
50
50
|
textHasPgLibImport
|
|
51
|
-
} from '
|
|
52
|
-
import { findAllPackageJsonPaths } from '
|
|
53
|
-
import { loadCursorIgnorePaths } from '
|
|
54
|
-
import { walkDir } from '
|
|
51
|
+
} from '../utils/bun-sql-scan.mjs'
|
|
52
|
+
import { findAllPackageJsonPaths } from '../../../scripts/utils/find-package-json-paths.mjs'
|
|
53
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
54
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
55
55
|
|
|
56
56
|
// Дешеві pre-filter regex'и для AST-сканера LISTEN/NOTIFY: уникаємо парсингу
|
|
57
57
|
// файлів, у яких ніяких сигналів немає. Винесено в модульний скоуп, щоб не
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
parseProgramOrNull,
|
|
28
28
|
templateQuasisText,
|
|
29
29
|
walkAstWithAncestors
|
|
30
|
-
} from '
|
|
30
|
+
} from '../../../scripts/utils/ast-scan-utils.mjs'
|
|
31
31
|
|
|
32
32
|
const SOURCE_FILE_RE = /\.([cm]?[jt]sx?)$/u
|
|
33
33
|
const BUN_SQL_IMPORT_RE = /\bimport\s*\{[\s\S]*?\b(sql|SQL)\b[\s\S]*?\}\s*from\s*["']bun["']/u
|
|
@@ -14,14 +14,14 @@ import { existsSync } from 'node:fs'
|
|
|
14
14
|
import { readFile } from 'node:fs/promises'
|
|
15
15
|
import { join, relative } from 'node:path'
|
|
16
16
|
|
|
17
|
-
import { createCheckReporter } from '
|
|
18
|
-
import { loadCursorIgnorePaths } from '
|
|
17
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
18
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
19
19
|
import {
|
|
20
20
|
findRedisImportsInText,
|
|
21
21
|
isRedisScanSourceFile,
|
|
22
22
|
shouldSkipFileForRedisScan
|
|
23
|
-
} from '
|
|
24
|
-
import { walkDir } from '
|
|
23
|
+
} from '../../../scripts/utils/redis-imports.mjs'
|
|
24
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Збирає абсолютні шляхи JS/TS джерел у репозиторії для скану заборонених redis-імпортів.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Канон надходить через --data: { "template": { "deny": ... } }
|
|
4
4
|
# Структура --data сформована з template/package.json.deny.json.
|
|
5
5
|
# AST-скан коду (`import`/`require`/dynamic `import()` тих самих пакетів)
|
|
6
|
-
# лишається у `js-bun-redis/js/imports
|
|
6
|
+
# лишається у `js-bun-redis/js/imports.mjs`.
|
|
7
7
|
package js_bun_redis.package_json
|
|
8
8
|
|
|
9
9
|
import rego.v1
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Перевіряє лінт JavaScript за правилом js-lint.mdc.
|
|
3
3
|
*
|
|
4
4
|
* Flat ESLint з getConfig і ignore для auto-imports,
|
|
5
|
-
* `.oxlintrc.json` має збігатися з каноном oxlint у пакеті (`npm/rules/js-lint/js/tooling/oxlint-canonical.json`):
|
|
5
|
+
* `.oxlintrc.json` має збігатися з каноном oxlint у пакеті (`npm/rules/js-lint/js/data/tooling/oxlint-canonical.json`):
|
|
6
6
|
* plugins, jsPlugins, categories, усі правила з канону (додаткові записи в `rules` дозволені), settings, env,
|
|
7
7
|
* globals, ignorePatterns. Також перевіряє workspace `package.json` на `type: "module"`
|
|
8
8
|
* і `engines`, workflow-дубль у `lint.yml`, `knip.json` autofill і застарілі `.eslintrc*`.
|
|
@@ -15,17 +15,21 @@ import { copyFile, readFile } from 'node:fs/promises'
|
|
|
15
15
|
import { dirname, join } from 'node:path'
|
|
16
16
|
import { fileURLToPath } from 'node:url'
|
|
17
17
|
|
|
18
|
-
import { createCheckReporter } from '
|
|
18
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
19
19
|
|
|
20
20
|
/** Шлях до канонічного oxlint JSON у цьому пакеті (для перевірки та тестів). */
|
|
21
21
|
export const OXLINT_CANONICAL_JSON_PATH = join(
|
|
22
22
|
dirname(fileURLToPath(import.meta.url)),
|
|
23
|
+
'data',
|
|
24
|
+
'tooling',
|
|
23
25
|
'oxlint-canonical.json'
|
|
24
26
|
)
|
|
25
27
|
|
|
26
28
|
/** Шлях до канонічного knip JSON у цьому пакеті — копіюється у корінь проєкту-споживача, якщо відсутній. */
|
|
27
29
|
export const KNIP_CANONICAL_JSON_PATH = join(
|
|
28
30
|
dirname(fileURLToPath(import.meta.url)),
|
|
31
|
+
'data',
|
|
32
|
+
'tooling',
|
|
29
33
|
'knip-canonical.json'
|
|
30
34
|
)
|
|
31
35
|
|
|
@@ -154,7 +158,7 @@ export function verifyOxlintRcAgainstCanonical(cfg, canonical) {
|
|
|
154
158
|
|
|
155
159
|
if (!deepEqualOxlintCanonical(actual, expected)) {
|
|
156
160
|
failures.push(
|
|
157
|
-
`.oxlintrc.json: поле "${key}" має збігатися з каноном пакета @nitra/cursor (npm/rules/js-lint/js/tooling/oxlint-canonical.json)`
|
|
161
|
+
`.oxlintrc.json: поле "${key}" має збігатися з каноном пакета @nitra/cursor (npm/rules/js-lint/js/data/tooling/oxlint-canonical.json)`
|
|
158
162
|
)
|
|
159
163
|
}
|
|
160
164
|
}
|
|
@@ -384,7 +388,7 @@ async function checkKnipConfig(passFn, failFn) {
|
|
|
384
388
|
return
|
|
385
389
|
}
|
|
386
390
|
await copyFile(KNIP_CANONICAL_JSON_PATH, 'knip.json')
|
|
387
|
-
passFn('knip.json створено з канонічного npm/rules/js-lint/js/tooling/knip-canonical.json (js-lint.mdc)')
|
|
391
|
+
passFn('knip.json створено з канонічного npm/rules/js-lint/js/data/tooling/knip-canonical.json (js-lint.mdc)')
|
|
388
392
|
}
|
|
389
393
|
|
|
390
394
|
/**
|