@nitra/cursor 1.9.9 → 1.9.14
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 +50 -0
- package/mdc/js-lint.mdc +5 -11
- package/mdc/text.mdc +3 -0
- package/package.json +1 -1
- package/policy/bun/package_json/package_json_test.rego +109 -0
- package/policy/js_lint/package_json/package_json.rego +1 -1
- package/policy/js_lint/package_json/package_json_test.rego +130 -0
- package/policy/text/markdownlint/markdownlint.rego +49 -0
- package/policy/text/markdownlint/markdownlint_test.rego +98 -0
- package/scripts/check-bun.mjs +3 -11
- package/scripts/check-js-lint.mjs +21 -61
- package/scripts/utils/knip-canonical.json +29 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,56 @@
|
|
|
4
4
|
|
|
5
5
|
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
|
|
6
6
|
|
|
7
|
+
## [1.9.14] - 2026-05-13
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`text.markdownlint` rego — повний канон `.markdownlint-cli2.jsonc` тепер виноситься як deny:** раніше rego-полісі мала **рівно один** deny (`gitignore == true`), а решта канонічного блока з [text.mdc](mdc/text.mdc) (`config.default == true`, `MD013 == false`, `MD024.siblings_only == true`, `MD029 == false`, `MD040 == false`, `MD041 == false`) була показана як приклад, але не перевірялась. Додано 6 нових deny-правил, що покривають кожне поле канону; додаткові поля верхнього рівня (`ignores`) і додаткові MD-rules (`MD033` тощо) дозволені — канон задає мінімум. Шаблон повідомлень — через `concat` для regal style/line-length.
|
|
12
|
+
- **`npm/policy/text/markdownlint/markdownlint_test.rego` — 14 нових тестів:** happy path (канонічний `.markdownlint-cli2.jsonc`), дозволені розширення (`ignores`, `MD033`), порушення для `gitignore` (відсутній / `false`), `config.default` (відсутній / `false`), `MD013/029/040/041` (`true` або відсутній), `MD024` (не object / `siblings_only: false` / відсутній). `conftest verify` — **183/183 pass** (+14). `lint-conftest` на реальному `.markdownlint-cli2.jsonc` репо: 5/5 (раніше було 1/1 — додано 4 нові тестові кейси проти реального файлу).
|
|
13
|
+
|
|
14
|
+
## [1.9.13] - 2026-05-13
|
|
15
|
+
|
|
16
|
+
### Removed
|
|
17
|
+
|
|
18
|
+
- **`check-bun.mjs::isAllowedRootDevDependency` — видалено JS-копію, дубль rego:** функція експортувалася лише для тестів, у `check()` не викликалась; логіка «дозволено лише `@nitra/*` у кореневих `devDependencies`» давно живе у `npm/policy/bun/package_json/package_json.rego` (`not startswith(name, "@nitra/")`). Docstring помилково посилався на `check-text.mjs`, який цю функцію не імпортує. Тепер єдине джерело — rego; у `check-bun.mjs` додано коментар з посиланням на полісі.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **`npm/policy/bun/package_json/package_json_test.rego` — rego-тести для bun.package_json:** 12 нових `test_*`-кейсів через `json.patch`-фікстури — happy path (без `devDependencies`, з кількома `@nitra/*`), 4 негативні `devDependencies` (`@cspell/dict-uk-ua`, `@cspell/cspell-lib`, `lodash`, `@types/node`), mixed-devDeps з конкретним повідомленням про `lodash`, заборона `packageManager`, заборона кореневих `dependencies` (порожній обʼєкт теж), агрегований `lint`-скрипт (відсутній / не покриває `bun run` / без `&& oxfmt .`). Покривається `bun run lint-rego` (169/169 pass).
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- **`npm/tests/check-bun.test.mjs` — прибрано `describe('isAllowedRootDevDependency')`:** імпорт і блок тестів видалено; залишено інтеграційні `check-bun`-тести у тимчасових каталогах (FS / cross-file частина).
|
|
27
|
+
- **Аудит інших `check-*.mjs`**: пройдено всі 22 скрипти на наявність дубля з rego (export не викликається внутрішньо + наявне `npm/policy/<rule>/<name>/<name>.rego`). Знайдено лише цей кейс; `httpRouteMatchesNginxDefaultTpl` у `check-nginx-default-tpl.mjs` залишається — не має rego-counterpart і свідомо лишений для майбутнього використання згідно docstring. Інші експорти або викликаються у відповідному `check()` / приватних helper-ах, або не мають rego-копії.
|
|
28
|
+
|
|
29
|
+
## [1.9.12] - 2026-05-13
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
|
|
33
|
+
- **`check-js-lint.mjs` — видалено дубльовані JS-копії канону `lint-js`:** експорти `CANONICAL_LINT_JS`, `isCanonicalLintJs`, `normalizeLintJsScript`, `nitraEslintConfigMeetsMinVersion` і константу `WHITESPACE_RE` видалено. Ці функції експортувалися, але **не використовувалися** у `check()` — пер-документна перевірка кореневого `package.json` (канонічний `lint-js`, `@nitra/eslint-config ≥ 3.9.2`, `type: "module"`, `engines.{node,bun}`) давно мігровано до rego-полісі `npm/policy/js_lint/package_json/`. Залишені експорти створювали два джерела істини: при оновленні канону (`bunx knip --no-config-hints`) доводилось правити і `.rego`, і `.mjs`-константу, що відкриває дрифт. Тепер канон лише в rego, JS-копії немає. У `check-js-lint.mjs` додано коментар з посиланням на rego-полісі.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **`npm/policy/js_lint/package_json/package_json_test.rego` — rego-тести для канону `lint-js`:** перенесено покриття з JS-тестів (`normalizeLintJsScript`, `isCanonicalLintJs`, `nitraEslintConfigMeetsMinVersion`) у rego через `json.patch`-фікстури: 16 нових `test_*`-кейсів — happy path, неправильний порядок команд, відсутність `bunx knip`, відсутність `--no-config-hints`, `type` не `module`, `engines.node < 24`, `engines.bun < 1.3`, `@nitra/eslint-config` < 3.9.2, `workspace:*` дозволено. Покривається `bun run lint-rego` (`conftest verify`).
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- **`npm/tests/check-js-lint.test.mjs` — прибрано тести для видалених JS-копій:** видалено блоки `describe('normalizeLintJsScript / isCanonicalLintJs')` і `describe('nitraEslintConfigMeetsMinVersion')` разом з імпортами. Залишилися тести `verifyOxlintRcAgainstCanonical` (там JS усе ще authoritative — потрібен readFile + рекурсивне порівняння канон-блока).
|
|
42
|
+
|
|
43
|
+
## [1.9.11] - 2026-05-13
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- **`lint-js` — `bunx knip --no-config-hints` у каноні (js-lint.mdc `1.20 → 1.21`):** до канонічного `lint-js`-скрипта додано прапор `--no-config-hints`, щоб knip не друкував щоразу інформаційну секцію «Configuration hints» (`Remove from ignoreDependencies/ignoreBinaries`). Hints не впливають на exit code і часто стосуються свідомо доданих ignore (`graphql` як peer-залежність) — щоразу їх читати немає сенсу. Оновлено: `CANONICAL_LINT_JS` у `check-js-lint.mjs`, `canonical_lint_js` у `npm_module_unused.../js_lint.package_json.rego`, приклади `lint-js`-скрипта і CI-блока у `npm/mdc/js-lint.mdc` + дзеркало `.cursor/rules/n-js-lint.mdc`, реальний `package.json#scripts.lint-js` у корені, реальний `.github/workflows/lint-js.yml`. Rego-deny `lint-js.yml: у run немає bunx knip` ловиться через `contains` — новий рядок з прапором проходить як раніше.
|
|
48
|
+
|
|
49
|
+
## [1.9.10] - 2026-05-13
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
|
|
53
|
+
- **`npm/scripts/utils/knip-canonical.json` — канонічний baseline `knip.json` для проєктів-споживачів:** покриває типові false-positives `bunx knip` для наших правил — `entry` зі CLI-конфігами (eslint/stylelint/oxlint/jscpd/markdownlint-cli2/commitlint), `project` для `**/*.{js,mjs,cjs,jsx,ts,tsx,mts,cts}`, `ignore` для `**/__fixtures__/**`, `ignoreDependencies` (`@nitra/cspell-dict`, `/@cspell\/dict-.+/`), `ignoreBinaries` для CLI з канону `bunx`/`npx` (`actionlint`, `cspell`, `depcheck`, `eslint`, `git-ai`, `jscpd`, `markdownlint-cli2`, `oxfmt`, `oxlint`, `shellcheck`, `uvx`, `v8r`, `zizmor`). Структурно поряд з `oxlint-canonical.json` / `oxlint-canonical-skeleton.json` у `npm/scripts/utils/`.
|
|
54
|
+
- **`js-lint.mdc` — секція про канонічний `knip.json` (версія `1.19 → 1.20`):** правило тепер вимагає `knip.json` у корені проєкту як стартовий baseline з канонічного файлу пакета. Перевіряється **лише наявність** — зміст подальших модифікацій локально не валідується (`entry` / `project` / `ignore` / `ignoreDependencies` / `ignoreBinaries` дозволені будь-які). Дзеркало — `.cursor/rules/n-js-lint.mdc`. Прибрано згадку про обовʼязковий `ignoreDependencies: ["graphql"]` як зміст-вимогу (тепер це лише стартова рекомендація через канон).
|
|
55
|
+
- **`check-js-lint.mjs::checkKnipConfig` — auto-create з канону:** якщо `knip.json` відсутній у корені, чек копіює `KNIP_CANONICAL_JSON_PATH` у `knip.json` і повідомляє pass про створення. Раніше функція падала з fail на відсутність і додатково перевіряла `ignoreDependencies ∋ "graphql"` — обидві перевірки замінено на FS-existence + копію канону (side effect, описано у `js-lint.mdc`).
|
|
56
|
+
|
|
7
57
|
## [1.9.9] - 2026-05-13
|
|
8
58
|
|
|
9
59
|
### Changed
|
package/mdc/js-lint.mdc
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Перевірка JavaScript коду
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.21'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
**oxlint**, **ESLint**, **jscpd**, **knip**. У скрипті **`lint-js`** і в CI — **`bunx oxlint`**, **`bunx eslint`**, **`bunx jscpd`**, **`bunx knip`** (у CI без **`--fix`** для oxlint/eslint — див. приклад workflow нижче). Без **prettier** і **@nitra/prettier-config**. У **`devDependencies`** має бути **`@nitra/eslint-config` мінімум `^3.9.2`** (з **3.8.0** правило `no-restricted-syntax` забороняє `for...in`; з **3.9.2** у `getConfig` вбудовано ignore для **`**/adr/**`** — ADR-документи не валідуються ESLint, локально цей glob додавати не потрібно; також транзитивно йде **`@e18e/eslint-plugin`** для oxlint); пакет **`@e18e/eslint-plugin`** окремо не додавай. Пакети oxlint/eslint/jscpd/knip не додавай без потреби монорепо.
|
|
@@ -22,7 +22,7 @@ version: '1.19'
|
|
|
22
22
|
{
|
|
23
23
|
"type": "module",
|
|
24
24
|
"scripts": {
|
|
25
|
-
"lint-js": "bunx oxlint --fix && bunx eslint --fix . && bunx jscpd . && bunx knip"
|
|
25
|
+
"lint-js": "bunx oxlint --fix && bunx eslint --fix . && bunx jscpd . && bunx knip --no-config-hints"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@nitra/eslint-config": "^3.9.4"
|
|
@@ -65,15 +65,9 @@ version: '1.19'
|
|
|
65
65
|
|
|
66
66
|
Перевірку невикористаних залежностей і експортів виконує **knip** (заміна `depcheck`). Викликається у скрипті `lint-js` і в CI разом з oxlint/eslint/jscpd — окремий крок у CI не потрібен.
|
|
67
67
|
|
|
68
|
-
У корені проєкту має бути `knip.json`
|
|
68
|
+
У корені проєкту має бути **`knip.json`**, який стартує з канонічного baseline з пакета `@nitra/cursor` — файл [`npm/scripts/utils/knip-canonical.json`](../scripts/utils/knip-canonical.json). Він покриває типові false-positives для наших правил: `entry` зі CLI-конфігами (eslint, stylelint, oxlint, jscpd, markdownlint-cli2, `commitlint`), `project` для `**/*.{js,mjs,cjs,jsx,ts,tsx,mts,cts}`, `ignore` для `**/__fixtures__/**`, `ignoreDependencies` для пакетів, посилання на які є лише в не-JS-конфігах (`@nitra/cspell-dict`, `/@cspell\/dict-.+/`), і `ignoreBinaries` для CLI, які канон вимагає викликати через `npx`/`bunx` і яких заборонено додавати в `devDependencies` (`actionlint`, `cspell`, `depcheck`, `eslint`, `git-ai`, `jscpd`, `markdownlint-cli2`, `oxfmt`, `oxlint`, `shellcheck`, `uvx`, `v8r`, `zizmor`).
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
{
|
|
72
|
-
"ignoreDependencies": [
|
|
73
|
-
"graphql"
|
|
74
|
-
]
|
|
75
|
-
}
|
|
76
|
-
```
|
|
70
|
+
Якщо `knip.json` відсутній — `npx @nitra/cursor check js-lint` копіює канон у корінь проєкту (side effect). Після створення модифікуй файл під свій проєкт як завгодно: перевіряємо лише наявність, зміст подальших змін не валідується.
|
|
77
71
|
|
|
78
72
|
Пакет `knip` окремо в `devDependencies` не додавай — `bunx knip` тягне його ad-hoc, як oxlint/eslint/jscpd.
|
|
79
73
|
|
|
@@ -134,7 +128,7 @@ jobs:
|
|
|
134
128
|
bunx oxlint
|
|
135
129
|
bunx eslint .
|
|
136
130
|
bunx jscpd .
|
|
137
|
-
bunx knip
|
|
131
|
+
bunx knip --no-config-hints
|
|
138
132
|
```
|
|
139
133
|
|
|
140
134
|
Перед **`./.github/actions/setup-bun-deps`** — **`actions/checkout@v6`** (див. **ga.mdc**). Composite: Node 24, Bun, кеш, `bun install --frozen-lockfile`.
|
package/mdc/text.mdc
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Тести для `bun.package_json`. Запуск:
|
|
2
|
+
# conftest verify -p npm/policy/bun/package_json
|
|
3
|
+
package bun.package_json_test
|
|
4
|
+
|
|
5
|
+
import rego.v1
|
|
6
|
+
|
|
7
|
+
import data.bun.package_json
|
|
8
|
+
|
|
9
|
+
valid_pkg := {
|
|
10
|
+
"name": "n-cursor",
|
|
11
|
+
"devDependencies": {"@nitra/eslint-config": "^3.9.2"},
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
# ── happy path ────────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
test_allow_minimal if {
|
|
17
|
+
count(package_json.deny) == 0 with input as valid_pkg
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
test_allow_multiple_nitra_deps if {
|
|
21
|
+
pkg := json.patch(valid_pkg, [{
|
|
22
|
+
"op": "replace",
|
|
23
|
+
"path": "/devDependencies",
|
|
24
|
+
"value": {"@nitra/eslint-config": "^3.9.2", "@nitra/cspell-dict": "^2.0.0", "@nitra/stylelint-config": "^1.0.0"},
|
|
25
|
+
}])
|
|
26
|
+
count(package_json.deny) == 0 with input as pkg
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
test_allow_no_dev_dependencies if {
|
|
30
|
+
pkg := json.patch(valid_pkg, [{"op": "remove", "path": "/devDependencies"}])
|
|
31
|
+
count(package_json.deny) == 0 with input as pkg
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# ── deny: devDependencies лише @nitra/* ──────────────────────────────────
|
|
35
|
+
|
|
36
|
+
test_deny_non_nitra_devdep if {
|
|
37
|
+
cases := [
|
|
38
|
+
{"@cspell/dict-uk-ua": "^2.0.0"},
|
|
39
|
+
{"@cspell/cspell-lib": "^9.0.0"},
|
|
40
|
+
{"lodash": "*"},
|
|
41
|
+
{"@types/node": "^24.0.0"},
|
|
42
|
+
]
|
|
43
|
+
some bad in cases
|
|
44
|
+
pkg := json.patch(valid_pkg, [{"op": "replace", "path": "/devDependencies", "value": bad}])
|
|
45
|
+
count(package_json.deny) > 0 with input as pkg
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
test_deny_mixed_dev_deps_only_flags_non_nitra if {
|
|
49
|
+
pkg := json.patch(valid_pkg, [{
|
|
50
|
+
"op": "replace",
|
|
51
|
+
"path": "/devDependencies",
|
|
52
|
+
"value": {"@nitra/eslint-config": "^3.9.2", "lodash": "*"},
|
|
53
|
+
}])
|
|
54
|
+
some msg in package_json.deny with input as pkg
|
|
55
|
+
contains(msg, "lodash")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# ── deny: packageManager ─────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
test_deny_package_manager_field if {
|
|
61
|
+
pkg := json.patch(valid_pkg, [{"op": "add", "path": "/packageManager", "value": "pnpm@9.0.0"}])
|
|
62
|
+
count(package_json.deny) > 0 with input as pkg
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# ── deny: dependencies у кореневому ──────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
test_deny_root_dependencies_present if {
|
|
68
|
+
pkg := json.patch(valid_pkg, [{"op": "add", "path": "/dependencies", "value": {"lodash": "*"}}])
|
|
69
|
+
count(package_json.deny) > 0 with input as pkg
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
test_deny_empty_dependencies_object if {
|
|
73
|
+
pkg := json.patch(valid_pkg, [{"op": "add", "path": "/dependencies", "value": {}}])
|
|
74
|
+
count(package_json.deny) > 0 with input as pkg
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# ── deny: агрегований lint ───────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
test_deny_lint_prefixed_without_aggregate if {
|
|
80
|
+
pkg := json.patch(valid_pkg, [{"op": "add", "path": "/scripts", "value": {"lint-js": "echo"}}])
|
|
81
|
+
count(package_json.deny) > 0 with input as pkg
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
test_allow_lint_aggregate_calls_subscript_and_oxfmt if {
|
|
85
|
+
pkg := json.patch(valid_pkg, [{
|
|
86
|
+
"op": "add",
|
|
87
|
+
"path": "/scripts",
|
|
88
|
+
"value": {"lint-js": "echo", "lint": "bun run lint-js && oxfmt ."},
|
|
89
|
+
}])
|
|
90
|
+
count(package_json.deny) == 0 with input as pkg
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
test_deny_lint_aggregate_missing_oxfmt if {
|
|
94
|
+
pkg := json.patch(valid_pkg, [{
|
|
95
|
+
"op": "add",
|
|
96
|
+
"path": "/scripts",
|
|
97
|
+
"value": {"lint-js": "echo", "lint": "bun run lint-js"},
|
|
98
|
+
}])
|
|
99
|
+
count(package_json.deny) > 0 with input as pkg
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
test_deny_lint_aggregate_missing_subscript_via_bun_run if {
|
|
103
|
+
pkg := json.patch(valid_pkg, [{
|
|
104
|
+
"op": "add",
|
|
105
|
+
"path": "/scripts",
|
|
106
|
+
"value": {"lint-js": "echo", "lint-text": "echo", "lint": "bun run lint-js && oxfmt ."},
|
|
107
|
+
}])
|
|
108
|
+
count(package_json.deny) > 0 with input as pkg
|
|
109
|
+
}
|
|
@@ -17,7 +17,7 @@ package js_lint.package_json
|
|
|
17
17
|
|
|
18
18
|
import rego.v1
|
|
19
19
|
|
|
20
|
-
canonical_lint_js := "bunx oxlint --fix && bunx eslint --fix . && bunx jscpd . && bunx knip"
|
|
20
|
+
canonical_lint_js := "bunx oxlint --fix && bunx eslint --fix . && bunx jscpd . && bunx knip --no-config-hints"
|
|
21
21
|
|
|
22
22
|
# ── deny: `lint-js` скрипт ─────────────────────────────────────────────────
|
|
23
23
|
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Тести для `js_lint.package_json`. Запуск:
|
|
2
|
+
# conftest verify -p npm/policy/js_lint/package_json
|
|
3
|
+
package js_lint.package_json_test
|
|
4
|
+
|
|
5
|
+
import rego.v1
|
|
6
|
+
|
|
7
|
+
import data.js_lint.package_json
|
|
8
|
+
|
|
9
|
+
canonical_lint_js := "bunx oxlint --fix && bunx eslint --fix . && bunx jscpd . && bunx knip --no-config-hints"
|
|
10
|
+
|
|
11
|
+
valid_pkg := {
|
|
12
|
+
"type": "module",
|
|
13
|
+
"scripts": {"lint-js": canonical_lint_js},
|
|
14
|
+
"engines": {"node": ">=24", "bun": ">=1.3"},
|
|
15
|
+
"devDependencies": {"@nitra/eslint-config": "^3.9.2"},
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# ── happy path ────────────────────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
test_allow_canonical if {
|
|
21
|
+
count(package_json.deny) == 0 with input as valid_pkg
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
test_allow_workspace_eslint_config if {
|
|
25
|
+
pkg := json.patch(
|
|
26
|
+
valid_pkg,
|
|
27
|
+
[{"op": "replace", "path": "/devDependencies/@nitra~1eslint-config", "value": "workspace:*"}],
|
|
28
|
+
)
|
|
29
|
+
count(package_json.deny) == 0 with input as pkg
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# ── lint-js ───────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
test_deny_missing_lint_js if {
|
|
35
|
+
pkg := json.patch(valid_pkg, [{"op": "remove", "path": "/scripts/lint-js"}])
|
|
36
|
+
count(package_json.deny) > 0 with input as pkg
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
test_deny_lint_js_without_knip if {
|
|
40
|
+
pkg := json.patch(
|
|
41
|
+
valid_pkg,
|
|
42
|
+
[{"op": "replace", "path": "/scripts/lint-js", "value": "bunx oxlint --fix && bunx eslint --fix . && bunx jscpd ."}],
|
|
43
|
+
)
|
|
44
|
+
count(package_json.deny) > 0 with input as pkg
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
test_deny_lint_js_without_no_config_hints if {
|
|
48
|
+
without_flag := "bunx oxlint --fix && bunx eslint --fix . && bunx jscpd . && bunx knip"
|
|
49
|
+
pkg := json.patch(valid_pkg, [{"op": "replace", "path": "/scripts/lint-js", "value": without_flag}])
|
|
50
|
+
count(package_json.deny) > 0 with input as pkg
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
test_deny_lint_js_wrong_order if {
|
|
54
|
+
wrong_order := "bunx eslint --fix . && bunx oxlint --fix && bunx jscpd . && bunx knip --no-config-hints"
|
|
55
|
+
pkg := json.patch(valid_pkg, [{"op": "replace", "path": "/scripts/lint-js", "value": wrong_order}])
|
|
56
|
+
count(package_json.deny) > 0 with input as pkg
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
test_allow_lint_js_with_extra_whitespace if {
|
|
60
|
+
pkg := json.patch(
|
|
61
|
+
valid_pkg,
|
|
62
|
+
[{"op": "replace", "path": "/scripts/lint-js", "value": concat(" ", ["", canonical_lint_js, ""])}],
|
|
63
|
+
)
|
|
64
|
+
count(package_json.deny) == 0 with input as pkg
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# ── type: module ──────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
test_deny_type_not_module if {
|
|
70
|
+
pkg := json.patch(valid_pkg, [{"op": "replace", "path": "/type", "value": "commonjs"}])
|
|
71
|
+
count(package_json.deny) > 0 with input as pkg
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
test_deny_type_missing if {
|
|
75
|
+
pkg := json.patch(valid_pkg, [{"op": "remove", "path": "/type"}])
|
|
76
|
+
count(package_json.deny) > 0 with input as pkg
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# ── engines ──────────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
test_deny_node_below_24 if {
|
|
82
|
+
pkg := json.patch(valid_pkg, [{"op": "replace", "path": "/engines/node", "value": ">=22"}])
|
|
83
|
+
count(package_json.deny) > 0 with input as pkg
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
test_allow_node_above_24 if {
|
|
87
|
+
pkg := json.patch(valid_pkg, [{"op": "replace", "path": "/engines/node", "value": ">=25"}])
|
|
88
|
+
count(package_json.deny) == 0 with input as pkg
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
test_deny_bun_below_1_3 if {
|
|
92
|
+
pkg := json.patch(valid_pkg, [{"op": "replace", "path": "/engines/bun", "value": ">=1.2"}])
|
|
93
|
+
count(package_json.deny) > 0 with input as pkg
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
test_allow_bun_2_x if {
|
|
97
|
+
pkg := json.patch(valid_pkg, [{"op": "replace", "path": "/engines/bun", "value": "^2.0.0"}])
|
|
98
|
+
count(package_json.deny) == 0 with input as pkg
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# ── @nitra/eslint-config ─────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
test_deny_eslint_config_below_3_9_2 if {
|
|
104
|
+
cases := [
|
|
105
|
+
"^3.9.1",
|
|
106
|
+
"^3.8.0",
|
|
107
|
+
"^3.6.12",
|
|
108
|
+
"^3.4.3",
|
|
109
|
+
]
|
|
110
|
+
some bad in cases
|
|
111
|
+
pkg := json.patch(valid_pkg, [{"op": "replace", "path": "/devDependencies/@nitra~1eslint-config", "value": bad}])
|
|
112
|
+
count(package_json.deny) > 0 with input as pkg
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
test_allow_eslint_config_above_3_9_2 if {
|
|
116
|
+
cases := [
|
|
117
|
+
"^3.9.2",
|
|
118
|
+
"^3.9.10",
|
|
119
|
+
"^3.10.0",
|
|
120
|
+
"^4.0.0",
|
|
121
|
+
]
|
|
122
|
+
some good in cases
|
|
123
|
+
pkg := json.patch(valid_pkg, [{"op": "replace", "path": "/devDependencies/@nitra~1eslint-config", "value": good}])
|
|
124
|
+
count(package_json.deny) == 0 with input as pkg
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
test_deny_missing_eslint_config if {
|
|
128
|
+
pkg := json.patch(valid_pkg, [{"op": "remove", "path": "/devDependencies/@nitra~1eslint-config"}])
|
|
129
|
+
count(package_json.deny) > 0 with input as pkg
|
|
130
|
+
}
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
# У випадку справжнього JSONC з `//` коментарями цей крок мовчки ігноруватиметься
|
|
9
9
|
# (conftest skip). FS-перевірка (наявність файлу) живе у JS.
|
|
10
10
|
#
|
|
11
|
+
# Перевіряє канонічний baseline з text.mdc (мінімум — додаткові ключі дозволені):
|
|
12
|
+
# { "gitignore": true,
|
|
13
|
+
# "config": { "default": true, "MD013": false, "MD024": {"siblings_only": true},
|
|
14
|
+
# "MD029": false, "MD040": false, "MD041": false } }
|
|
15
|
+
# MD041 off навмисно — `.mdc` з frontmatter (див. text.mdc).
|
|
16
|
+
#
|
|
11
17
|
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
12
18
|
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
13
19
|
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
@@ -15,7 +21,50 @@ package text.markdownlint
|
|
|
15
21
|
|
|
16
22
|
import rego.v1
|
|
17
23
|
|
|
24
|
+
# ── Шаблони повідомлень ────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
config_rule_template := concat(" ", [
|
|
27
|
+
".markdownlint-cli2.jsonc: config.%s має бути %v",
|
|
28
|
+
"(зараз: %v) (text.mdc)",
|
|
29
|
+
])
|
|
30
|
+
|
|
31
|
+
# ── deny: gitignore ───────────────────────────────────────────────────────
|
|
32
|
+
|
|
18
33
|
deny contains msg if {
|
|
19
34
|
object.get(input, "gitignore", null) != true
|
|
20
35
|
msg := ".markdownlint-cli2.jsonc: додай на верхньому рівні \"gitignore\": true (text.mdc)"
|
|
21
36
|
}
|
|
37
|
+
|
|
38
|
+
# ── deny: config.default ──────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
deny contains msg if {
|
|
41
|
+
config := object.get(input, "config", {})
|
|
42
|
+
object.get(config, "default", null) != true
|
|
43
|
+
msg := sprintf(config_rule_template, ["default", true, object.get(config, "default", null)])
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# ── deny: MD013 / MD029 / MD040 / MD041 повинні бути `false` ──────────────
|
|
47
|
+
|
|
48
|
+
deny contains msg if {
|
|
49
|
+
config := object.get(input, "config", {})
|
|
50
|
+
some rule in {"MD013", "MD029", "MD040", "MD041"}
|
|
51
|
+
object.get(config, rule, null) != false
|
|
52
|
+
msg := sprintf(config_rule_template, [rule, false, object.get(config, rule, null)])
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# ── deny: MD024.siblings_only == true ─────────────────────────────────────
|
|
56
|
+
|
|
57
|
+
deny contains msg if {
|
|
58
|
+
config := object.get(input, "config", {})
|
|
59
|
+
md024 := object.get(config, "MD024", null)
|
|
60
|
+
not is_object(md024)
|
|
61
|
+
msg := sprintf(config_rule_template, ["MD024", "{\"siblings_only\": true}", md024])
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
deny contains msg if {
|
|
65
|
+
config := object.get(input, "config", {})
|
|
66
|
+
md024 := object.get(config, "MD024", {})
|
|
67
|
+
is_object(md024)
|
|
68
|
+
object.get(md024, "siblings_only", null) != true
|
|
69
|
+
msg := sprintf(config_rule_template, ["MD024.siblings_only", true, object.get(md024, "siblings_only", null)])
|
|
70
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Тести для `text.markdownlint`. Запуск:
|
|
2
|
+
# conftest verify -p npm/policy/text/markdownlint
|
|
3
|
+
package text.markdownlint_test
|
|
4
|
+
|
|
5
|
+
import rego.v1
|
|
6
|
+
|
|
7
|
+
import data.text.markdownlint
|
|
8
|
+
|
|
9
|
+
valid_cfg := {
|
|
10
|
+
"gitignore": true,
|
|
11
|
+
"config": {
|
|
12
|
+
"default": true,
|
|
13
|
+
"MD013": false,
|
|
14
|
+
"MD024": {"siblings_only": true},
|
|
15
|
+
"MD029": false,
|
|
16
|
+
"MD040": false,
|
|
17
|
+
"MD041": false,
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# ── happy path ────────────────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
test_allow_canonical if {
|
|
24
|
+
count(markdownlint.deny) == 0 with input as valid_cfg
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
test_allow_with_additional_top_level_keys if {
|
|
28
|
+
cfg := json.patch(valid_cfg, [{"op": "add", "path": "/ignores", "value": ["**/adr/**"]}])
|
|
29
|
+
count(markdownlint.deny) == 0 with input as cfg
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
test_allow_with_additional_md_rules if {
|
|
33
|
+
cfg := json.patch(valid_cfg, [{"op": "add", "path": "/config/MD033", "value": {"allowed_elements": ["a"]}}])
|
|
34
|
+
count(markdownlint.deny) == 0 with input as cfg
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# ── gitignore ─────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
test_deny_missing_gitignore if {
|
|
40
|
+
cfg := json.patch(valid_cfg, [{"op": "remove", "path": "/gitignore"}])
|
|
41
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
test_deny_gitignore_false if {
|
|
45
|
+
cfg := json.patch(valid_cfg, [{"op": "replace", "path": "/gitignore", "value": false}])
|
|
46
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# ── config.default ────────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
test_deny_default_false if {
|
|
52
|
+
cfg := json.patch(valid_cfg, [{"op": "replace", "path": "/config/default", "value": false}])
|
|
53
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
test_deny_default_missing if {
|
|
57
|
+
cfg := json.patch(valid_cfg, [{"op": "remove", "path": "/config/default"}])
|
|
58
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# ── MD013 / MD029 / MD040 / MD041 — повинні бути false ────────────────────
|
|
62
|
+
|
|
63
|
+
test_deny_md013_true if {
|
|
64
|
+
cfg := json.patch(valid_cfg, [{"op": "replace", "path": "/config/MD013", "value": true}])
|
|
65
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
test_deny_md029_missing if {
|
|
69
|
+
cfg := json.patch(valid_cfg, [{"op": "remove", "path": "/config/MD029"}])
|
|
70
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
test_deny_md040_true if {
|
|
74
|
+
cfg := json.patch(valid_cfg, [{"op": "replace", "path": "/config/MD040", "value": true}])
|
|
75
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
test_deny_md041_true if {
|
|
79
|
+
cfg := json.patch(valid_cfg, [{"op": "replace", "path": "/config/MD041", "value": true}])
|
|
80
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# ── MD024.siblings_only ──────────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
test_deny_md024_not_object if {
|
|
86
|
+
cfg := json.patch(valid_cfg, [{"op": "replace", "path": "/config/MD024", "value": false}])
|
|
87
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
test_deny_md024_siblings_only_false if {
|
|
91
|
+
cfg := json.patch(valid_cfg, [{"op": "replace", "path": "/config/MD024/siblings_only", "value": false}])
|
|
92
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
test_deny_md024_missing if {
|
|
96
|
+
cfg := json.patch(valid_cfg, [{"op": "remove", "path": "/config/MD024"}])
|
|
97
|
+
count(markdownlint.deny) > 0 with input as cfg
|
|
98
|
+
}
|
package/scripts/check-bun.mjs
CHANGED
|
@@ -20,17 +20,9 @@ import { readFile } from 'node:fs/promises'
|
|
|
20
20
|
|
|
21
21
|
import { createCheckReporter } from './utils/check-reporter.mjs'
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* Залишилася як експорт для `check-text.mjs` і тестів — `bun.package_json` Rego
|
|
27
|
-
* робить ту саму перевірку для check-runner-а.
|
|
28
|
-
* @param {string} name ключ з поля `devDependencies`
|
|
29
|
-
* @returns {boolean} true, якщо префікс дозволений
|
|
30
|
-
*/
|
|
31
|
-
export function isAllowedRootDevDependency(name) {
|
|
32
|
-
return name.startsWith('@nitra/')
|
|
33
|
-
}
|
|
23
|
+
// Перевірка `devDependencies` кореневого `package.json` (дозволено лише `@nitra/*`)
|
|
24
|
+
// — у rego (`npm/policy/bun/package_json/`). JS-копії `isAllowedRootDevDependency`
|
|
25
|
+
// видалено, щоб не було двох джерел істини.
|
|
34
26
|
|
|
35
27
|
/**
|
|
36
28
|
* Зчитує ідентифікатори правил з `.n-cursor.json` (поле `rules`).
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* `engines.bun` >= 1.3, `"type": "module"` у кореневому і всіх workspace `package.json`. Дубль перевірки JS у `lint.yml` — заборонено.
|
|
13
13
|
*/
|
|
14
14
|
import { existsSync } from 'node:fs'
|
|
15
|
-
import { readFile } from 'node:fs/promises'
|
|
15
|
+
import { copyFile, readFile } from 'node:fs/promises'
|
|
16
16
|
import { dirname, join } from 'node:path'
|
|
17
17
|
import { fileURLToPath } from 'node:url'
|
|
18
18
|
|
|
@@ -25,55 +25,18 @@ export const OXLINT_CANONICAL_JSON_PATH = join(
|
|
|
25
25
|
'oxlint-canonical.json'
|
|
26
26
|
)
|
|
27
27
|
|
|
28
|
-
/**
|
|
29
|
-
export const
|
|
28
|
+
/** Шлях до канонічного knip JSON у цьому пакеті — копіюється у корінь проєкту-споживача, якщо відсутній. */
|
|
29
|
+
export const KNIP_CANONICAL_JSON_PATH = join(dirname(fileURLToPath(import.meta.url)), 'utils', 'knip-canonical.json')
|
|
30
30
|
|
|
31
31
|
/** Мінімальні рекомендації розширень редактора з js-lint.mdc (eslint, oxlint, GA). */
|
|
32
32
|
export const REQUIRED_VSCODE_EXTENSIONS = ['dbaeumer.vscode-eslint', 'github.vscode-github-actions', 'oxc.oxc-vscode']
|
|
33
33
|
|
|
34
|
-
const WHITESPACE_RE = /\s+/gu
|
|
35
34
|
const NON_DIGITS_RE = /\D+/u
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
*/
|
|
42
|
-
export function normalizeLintJsScript(s) {
|
|
43
|
-
return String(s).trim().replaceAll(WHITESPACE_RE, ' ')
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Чи рядок `lint-js` збігається з каноном (`bunx oxlint`, `bunx eslint`, `bunx jscpd`).
|
|
48
|
-
* @param {string} script значення `scripts.lint-js` з package.json
|
|
49
|
-
* @returns {boolean} true, якщо рядок канонічний
|
|
50
|
-
*/
|
|
51
|
-
export function isCanonicalLintJs(script) {
|
|
52
|
-
return normalizeLintJsScript(script) === CANONICAL_LINT_JS
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Чи діапазон `@nitra/eslint-config` у `package.json` задовольняє мінімум `>= 3.9.2`
|
|
57
|
-
* (заборона `for...in` через `no-restricted-syntax` з 3.8.0 + вбудований ignore для ADR-каталогів
|
|
58
|
-
* у `getConfig` з 3.9.2 + транзитивний `@e18e/eslint-plugin` для oxlint).
|
|
59
|
-
* @param {unknown} versionSpec значення `devDependencies['@nitra/eslint-config']`
|
|
60
|
-
* @returns {boolean} true для `workspace:*` або першої semver у рядку >= 3.9.2
|
|
61
|
-
*/
|
|
62
|
-
export function nitraEslintConfigMeetsMinVersion(versionSpec) {
|
|
63
|
-
const s = String(versionSpec).trim()
|
|
64
|
-
if (s.startsWith('workspace:')) {
|
|
65
|
-
return true
|
|
66
|
-
}
|
|
67
|
-
const parts = s.split(NON_DIGITS_RE).filter(Boolean)
|
|
68
|
-
if (parts.length < 3) {
|
|
69
|
-
return false
|
|
70
|
-
}
|
|
71
|
-
const [major, minor, patch] = parts.slice(0, 3).map(Number)
|
|
72
|
-
if ([major, minor, patch].some(n => Number.isNaN(n))) {
|
|
73
|
-
return false
|
|
74
|
-
}
|
|
75
|
-
return major > 3 || (major === 3 && (minor > 9 || (minor === 9 && patch >= 2)))
|
|
76
|
-
}
|
|
36
|
+
// Канонічний рядок `lint-js`-скрипта і мінімальна версія `@nitra/eslint-config` —
|
|
37
|
+
// у rego (`npm/policy/js_lint/package_json/`). JS-копії (`CANONICAL_LINT_JS`,
|
|
38
|
+
// `isCanonicalLintJs`, `nitraEslintConfigMeetsMinVersion`) видалено, щоб не
|
|
39
|
+
// було двох джерел істини й ризику дрифту.
|
|
77
40
|
|
|
78
41
|
/**
|
|
79
42
|
* Рекурсивне порівняння фрагментів канону oxlint (масиви — порядок як у каноні; об’єкти — той самий набір ключів і вкладеність).
|
|
@@ -473,31 +436,28 @@ async function checkJscpdConfig(passFn, failFn) {
|
|
|
473
436
|
}
|
|
474
437
|
|
|
475
438
|
/**
|
|
476
|
-
* Перевіряє `knip.json
|
|
477
|
-
*
|
|
478
|
-
*
|
|
439
|
+
* Перевіряє наявність `knip.json` у корені проєкту. Якщо файл відсутній —
|
|
440
|
+
* копіює канонічний `knip-canonical.json` з пакета `@nitra/cursor` як стартовий
|
|
441
|
+
* baseline; зміст подальших модифікацій локально не валідується (`entry` /
|
|
442
|
+
* `project` / `ignore` / `ignoreDependencies` / `ignoreBinaries` дозволені
|
|
443
|
+
* будь-які; це side effect — описано у js-lint.mdc).
|
|
479
444
|
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
480
445
|
* @param {(msg: string) => void} failFn callback при помилці
|
|
481
446
|
*/
|
|
482
447
|
async function checkKnipConfig(passFn, failFn) {
|
|
483
|
-
if (
|
|
484
|
-
|
|
448
|
+
if (existsSync('knip.json')) {
|
|
449
|
+
passFn('knip.json існує')
|
|
485
450
|
return
|
|
486
451
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
452
|
+
if (!existsSync(KNIP_CANONICAL_JSON_PATH)) {
|
|
453
|
+
failFn(
|
|
454
|
+
`knip.json відсутній, і канонічний шаблон у пакеті не знайдено (${KNIP_CANONICAL_JSON_PATH}) — ` +
|
|
455
|
+
'перевстанови @nitra/cursor'
|
|
456
|
+
)
|
|
492
457
|
return
|
|
493
458
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
if (Array.isArray(ignoreDeps) && ignoreDeps.includes('graphql')) {
|
|
497
|
-
passFn('knip.json: ignoreDependencies містить "graphql"')
|
|
498
|
-
} else {
|
|
499
|
-
failFn('knip.json: ignoreDependencies має містити "graphql" (peer-залежність) (js-lint.mdc)')
|
|
500
|
-
}
|
|
459
|
+
await copyFile(KNIP_CANONICAL_JSON_PATH, 'knip.json')
|
|
460
|
+
passFn('knip.json створено з канонічного npm/scripts/utils/knip-canonical.json (js-lint.mdc)')
|
|
501
461
|
}
|
|
502
462
|
|
|
503
463
|
/**
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://unpkg.com/knip@5/schema.json",
|
|
3
|
+
"entry": [
|
|
4
|
+
"eslint.config.{js,mjs,cjs}",
|
|
5
|
+
"stylelint.config.{js,cjs,mjs}",
|
|
6
|
+
"oxlint.config.{js,mjs}",
|
|
7
|
+
"jscpd.config.{js,mjs}",
|
|
8
|
+
"markdownlint-cli2.config.{js,mjs,cjs,jsonc}",
|
|
9
|
+
".markdownlint-cli2.{jsonc,cjs,mjs}",
|
|
10
|
+
"commitlint.config.{js,cjs,mjs}"
|
|
11
|
+
],
|
|
12
|
+
"project": ["**/*.{js,mjs,cjs,jsx,ts,tsx,mts,cts}"],
|
|
13
|
+
"ignore": ["**/__fixtures__/**"],
|
|
14
|
+
"ignoreDependencies": ["@nitra/cspell-dict", "/@cspell\\/dict-.+/", "graphql"],
|
|
15
|
+
"ignoreBinaries": [
|
|
16
|
+
"actionlint",
|
|
17
|
+
"cspell",
|
|
18
|
+
"eslint",
|
|
19
|
+
"git-ai",
|
|
20
|
+
"jscpd",
|
|
21
|
+
"markdownlint-cli2",
|
|
22
|
+
"oxfmt",
|
|
23
|
+
"oxlint",
|
|
24
|
+
"shellcheck",
|
|
25
|
+
"uvx",
|
|
26
|
+
"v8r",
|
|
27
|
+
"zizmor"
|
|
28
|
+
]
|
|
29
|
+
}
|