@nitra/cursor 1.13.14 → 1.13.25

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/package.json +1 -1
  3. package/rules/abie/abie.mdc +1 -4
  4. package/rules/abie/policy/clean_merged_ignore_branches/clean_merged_ignore_branches.rego +21 -40
  5. package/rules/abie/policy/clean_merged_ignore_branches/template/clean-merged-branch.yml.snippet.yml +9 -0
  6. package/rules/docker/docker.mdc +2 -50
  7. package/rules/docker/policy/lint_docker_yml/lint_docker_yml.rego +33 -47
  8. package/rules/docker/policy/lint_docker_yml/template/lint-docker.yml.snippet.yml +41 -0
  9. package/rules/docker/policy/package_json/package_json.rego +11 -28
  10. package/rules/docker/policy/package_json/template/package.json.snippet.json +1 -0
  11. package/rules/image-avif/policy/package_json/package_json.rego +21 -35
  12. package/rules/image-avif/policy/package_json/template/package.json.deny.json +5 -0
  13. package/rules/image-compress/image-compress.mdc +2 -8
  14. package/rules/image-compress/policy/package_json/package_json.rego +24 -65
  15. package/rules/image-compress/policy/package_json/template/package.json.contains.json +5 -0
  16. package/rules/image-compress/policy/package_json/template/package.json.deny.json +8 -0
  17. package/rules/js-bun-db/policy/package_json/package_json.rego +8 -21
  18. package/rules/js-bun-db/policy/package_json/template/package.json.deny.json +7 -0
  19. package/rules/js-bun-redis/policy/package_json/package_json.rego +8 -30
  20. package/rules/js-bun-redis/policy/package_json/template/package.json.deny.json +12 -0
  21. package/rules/js-lint/policy/jscpd/jscpd.rego +29 -23
  22. package/rules/js-lint/policy/jscpd/template/.jscpd.json.snippet.json +6 -0
  23. package/rules/js-lint/policy/lint_js_yml/lint_js_yml.rego +39 -47
  24. package/rules/js-lint/policy/lint_js_yml/template/lint-js.yml.snippet.yml +44 -0
  25. package/rules/js-lint/policy/package_json/package_json.rego +22 -42
  26. package/rules/js-lint/policy/package_json/template/package.json.snippet.json +6 -0
  27. package/rules/js-lint/policy/vscode_extensions/template/extensions.json.snippet.json +7 -0
  28. package/rules/js-lint/policy/vscode_extensions/vscode_extensions.rego +4 -17
  29. package/rules/js-run/policy/configmap/configmap.rego +11 -35
  30. package/rules/js-run/policy/configmap/template/configmap.yaml.contains.yml +4 -0
  31. package/rules/js-run/policy/jsconfig/jsconfig.rego +39 -46
  32. package/rules/js-run/policy/jsconfig/template/jsconfig.json.snippet.json +10 -0
  33. package/rules/js-run/policy/package_json/package_json.rego +10 -21
  34. package/rules/js-run/policy/package_json/template/package.json.deny.json +10 -0
  35. package/rules/npm-module/npm-module.mdc +7 -36
  36. package/rules/npm-module/policy/emit_types_config/emit_types_config.rego +18 -27
  37. package/rules/npm-module/policy/emit_types_config/template/tsconfig.emit-types.json.snippet.json +9 -0
  38. package/rules/npm-module/policy/npm_package_json/npm_package_json.rego +20 -30
  39. package/rules/npm-module/policy/npm_package_json/template/package.json.snippet.json +1 -0
  40. package/rules/npm-module/policy/npm_publish_yml/npm_publish_yml.rego +46 -38
  41. package/rules/npm-module/policy/npm_publish_yml/template/npm-publish.yml.snippet.yml +34 -0
  42. package/rules/npm-module/policy/root_package_json/root_package_json.rego +17 -17
  43. package/rules/npm-module/policy/root_package_json/template/package.json.snippet.json +1 -0
  44. package/rules/php/php.mdc +2 -56
  45. package/rules/php/policy/lint_php_yml/lint_php_yml.rego +15 -13
  46. package/rules/php/policy/lint_php_yml/template/lint-php.yml.snippet.yml +47 -0
  47. package/rules/php/policy/package_json/package_json.rego +9 -12
  48. package/rules/php/policy/package_json/template/package.json.contains.json +5 -0
  49. package/rules/style-lint/policy/lint_style_yml/lint_style_yml.rego +14 -16
  50. package/rules/style-lint/policy/lint_style_yml/template/lint-style.yml.snippet.yml +39 -0
  51. package/rules/style-lint/policy/package_json/package_json.rego +22 -30
  52. package/rules/style-lint/policy/package_json/template/package.json.contains.json +5 -0
  53. package/rules/style-lint/policy/package_json/template/package.json.snippet.json +5 -0
  54. package/rules/style-lint/policy/vscode_extensions/template/extensions.json.snippet.json +1 -0
  55. package/rules/style-lint/policy/vscode_extensions/vscode_extensions.rego +5 -15
  56. package/rules/style-lint/policy/vscode_settings/template/settings.json.snippet.json +5 -0
  57. package/rules/style-lint/policy/vscode_settings/vscode_settings.rego +7 -16
  58. package/rules/text/policy/cspell/cspell.rego +39 -59
  59. package/rules/text/policy/cspell/template/.cspell.json.contains.json +3 -0
  60. package/rules/text/policy/cspell/template/.cspell.json.deny.json +5 -0
  61. package/rules/text/policy/cspell/template/.cspell.json.snippet.json +12 -0
  62. package/rules/text/policy/markdownlint/markdownlint.rego +37 -50
  63. package/rules/text/policy/markdownlint/template/.markdownlint-cli2.jsonc.snippet.jsonc +11 -0
  64. package/rules/text/policy/oxfmtrc/oxfmtrc.rego +23 -58
  65. package/rules/text/policy/oxfmtrc/template/.oxfmtrc.json.snippet.json +12 -0
  66. package/rules/text/policy/package_json/package_json.rego +14 -52
  67. package/rules/text/policy/package_json/template/package.json.deny.json +15 -0
  68. package/rules/text/policy/vscode_extensions/template/extensions.json.snippet.json +7 -0
  69. package/rules/text/policy/vscode_extensions/vscode_extensions.rego +4 -28
  70. package/rules/text/policy/vscode_settings/template/settings.json.snippet.json +9 -0
  71. package/rules/text/policy/vscode_settings/vscode_settings.rego +20 -42
@@ -1,28 +1,28 @@
1
- # Порт перевірки кореневого `package.json` з `npm/scripts/check-npm-module.mjs`
2
- # (npm-module.mdc) — масив `workspaces` має містити "npm".
3
- #
4
- # Запуск (локально):
5
- # conftest test package.json -p npm/policy/npm_module \
6
- # --namespace npm_module.root_package_json
1
+ # Перевірка кореневого `package.json` для npm-module (npm-module.mdc).
7
2
  #
3
+ # Канон надходить через --data: { "template": { "snippet": ... } }
4
+ # Структура --data сформована з template/package.json.snippet.json.
5
+ # Snippet-array subset-of: кожне значення з template-масиву має бути у input-масиві.
8
6
  # Решта кореневих `package.json`-перевірок (заборонені поля, devDeps лише @nitra/*)
9
- # — у `bun.package_json`. FS-перевірки (наявність каталогу `npm/`,
10
- # `npm/package.json`) — у JS.
11
- #
12
- # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
13
- # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
14
- # (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
7
+ # — у `bun.package_json`. FS-перевірки (наявність каталогу `npm/`, `npm/package.json`)
8
+ # — у JS.
15
9
  package npm_module.root_package_json
16
10
 
17
11
  import rego.v1
18
12
 
13
+ # Поле має бути масивом — інакше окрема deny.
19
14
  deny contains msg if {
20
- not is_array(object.get(input, "workspaces", null))
21
- msg := "package.json: масив workspaces відсутній — має містити \"npm\" (npm-module.mdc)"
15
+ some field in object.keys(data.template.snippet)
16
+ not is_array(object.get(input, field, null))
17
+ msg := sprintf("package.json: масив %s відсутній або не масив (npm-module.mdc)", [field])
22
18
  }
23
19
 
20
+ # Subset-of: кожне значення з template має бути в input-масиві.
24
21
  deny contains msg if {
25
- is_array(input.workspaces)
26
- not "npm" in {w | some w in input.workspaces}
27
- msg := "package.json: workspaces має містити \"npm\" (npm-module.mdc)"
22
+ some field, expected_values in data.template.snippet
23
+ is_array(object.get(input, field, null))
24
+ actual_set := {v | some v in input[field]}
25
+ some required in expected_values
26
+ not required in actual_set
27
+ msg := sprintf("package.json: %s має містити %q (npm-module.mdc)", [field, required])
28
28
  }
package/rules/php/php.mdc CHANGED
@@ -65,13 +65,7 @@ composer audit
65
65
 
66
66
  `composer`-інструмененти не мають єдиного CLI, який сам обходить репозиторій, тому `lint-php` зручно делегувати у JS-скрипт-обгортку (як `lint-docker`, `lint-k8s`).
67
67
 
68
- ```json title="package.json"
69
- {
70
- "scripts": {
71
- "lint-php": "bun ./npm/scripts/run-php.mjs"
72
- }
73
- }
74
- ```
68
+ - Канон `package.json#scripts.lint-php` (substring requirement): [package.json.contains.json](./policy/package_json/template/package.json.contains.json)
75
69
 
76
70
  Скрипт `run-php.mjs`:
77
71
 
@@ -82,52 +76,4 @@ composer audit
82
76
 
83
77
  ## CI: `.github/workflows/lint-php.yml`
84
78
 
85
- ```yaml title=".github/workflows/lint-php.yml"
86
- name: Lint PHP
87
-
88
- on:
89
- push:
90
- branches:
91
- - dev
92
- - main
93
- paths:
94
- - '**/*.php'
95
- - 'composer.json'
96
- - 'composer.lock'
97
- - 'phpstan.neon'
98
- - 'phpstan.neon.dist'
99
- - 'psalm.xml'
100
- - '.github/workflows/lint-php.yml'
101
-
102
- pull_request:
103
- branches:
104
- - dev
105
- - main
106
-
107
- concurrency:
108
- group: ${{ github.ref }}-${{ github.workflow }}
109
- cancel-in-progress: true
110
-
111
- jobs:
112
- php:
113
- runs-on: ubuntu-latest
114
- permissions:
115
- contents: read
116
- steps:
117
- - uses: actions/checkout@v6
118
- with:
119
- persist-credentials: false
120
-
121
- - uses: ./.github/actions/setup-bun-deps
122
-
123
- - name: Install PHP
124
- uses: shivammathur/setup-php@v2
125
- with:
126
- php-version: '8.5'
127
-
128
- - name: Install Composer dependencies
129
- run: composer install --no-interaction --no-progress --prefer-dist
130
-
131
- - name: Lint PHP
132
- run: bun run lint-php
133
- ```
79
+ - Канон: [lint-php.yml.snippet.yml](./policy/lint_php_yml/template/lint-php.yml.snippet.yml)
@@ -1,19 +1,20 @@
1
- # Порт перевірки `lint-php.yml` з `npm/scripts/check-php.mjs` (php.mdc).
1
+ # Перевірка `lint-php.yml` (php.mdc).
2
2
  #
3
- # Запуск (локально):
4
- # conftest test .github/workflows/lint-php.yml -p npm/policy/php \
5
- # --namespace php.lint_php_yml
6
- #
7
- # Перевіряє: хоча б один крок `run` містить `bun run lint-php`. Універсальні
8
- # workflow-перевірки — у `ga.workflow_common`.
9
- #
10
- # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
11
- # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
12
- # (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
3
+ # Канон надходить через --data: { "template": { "snippet": ... } }
4
+ # Структура --data сформована з template/lint-php.yml.snippet.yml.
5
+ # Маркер `run:` (bun run lint-php) збирається з template's php-job steps.
6
+ # Універсальні workflow-перевірки — у `ga.workflow_common`.
13
7
  package php.lint_php_yml
14
8
 
15
9
  import rego.v1
16
10
 
11
+ # Очікуваний `run:` маркер — конкатенація всіх run-блоків з template.
12
+ expected_run_blob := concat("\n", [r |
13
+ some step in data.template.snippet.jobs.php.steps
14
+ r := object.get(step, "run", "")
15
+ r != ""
16
+ ])
17
+
17
18
  all_run_text := concat("\n", [run_text |
18
19
  some job in object.get(input, "jobs", {})
19
20
  some step in object.get(job, "steps", [])
@@ -21,8 +22,9 @@ all_run_text := concat("\n", [run_text |
21
22
  ])
22
23
 
23
24
  deny contains msg if {
24
- not contains(all_run_text, "bun run lint-php")
25
- msg := "lint-php.yml: жоден крок run не містить `bun run lint-php` (php.mdc)"
25
+ expected_run_blob != ""
26
+ not contains(all_run_text, expected_run_blob)
27
+ msg := sprintf("lint-php.yml: жоден крок run не містить %q (php.mdc)", [expected_run_blob])
26
28
  }
27
29
 
28
30
  step_run_to_text(step) := step.run if is_string(step.run)
@@ -0,0 +1,47 @@
1
+ name: Lint PHP
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - dev
7
+ - main
8
+ paths:
9
+ - '**/*.php'
10
+ - 'composer.json'
11
+ - 'composer.lock'
12
+ - 'phpstan.neon'
13
+ - 'phpstan.neon.dist'
14
+ - 'psalm.xml'
15
+ - '.github/workflows/lint-php.yml'
16
+
17
+ pull_request:
18
+ branches:
19
+ - dev
20
+ - main
21
+
22
+ concurrency:
23
+ group: ${{ github.ref }}-${{ github.workflow }}
24
+ cancel-in-progress: true
25
+
26
+ jobs:
27
+ php:
28
+ runs-on: ubuntu-latest
29
+ permissions:
30
+ contents: read
31
+ steps:
32
+ - uses: actions/checkout@v6
33
+ with:
34
+ persist-credentials: false
35
+
36
+ - uses: ./.github/actions/setup-bun-deps
37
+
38
+ - name: Install PHP
39
+ uses: shivammathur/setup-php@v2
40
+ with:
41
+ php-version: '8.5'
42
+
43
+ - name: Install Composer dependencies
44
+ run: composer install --no-interaction --no-progress --prefer-dist
45
+
46
+ - name: Lint PHP
47
+ run: bun run lint-php
@@ -1,19 +1,16 @@
1
- # Порт перевірки `package.json` з `npm/scripts/check-php.mjs` (php.mdc).
1
+ # Перевірка `package.json` (php.mdc).
2
2
  #
3
- # Запуск (локально):
4
- # conftest test package.json -p npm/policy/php --namespace php.package_json
5
- #
6
- # Перевіряє: наявність скрипта `lint-php`. FS-перевірки (`composer.json`, наявність
7
- # `package.json` як такого) — у JS.
8
- #
9
- # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
10
- # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
11
- # (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
3
+ # Канон надходить через --data: { "template": { "contains": ... } }
4
+ # Структура --data сформована з template/package.json.contains.json.
5
+ # FS-перевірки (`composer.json`, наявність `package.json` як такого) — у JS.
12
6
  package php.package_json
13
7
 
14
8
  import rego.v1
15
9
 
16
10
  deny contains msg if {
17
- not object.get(object.get(input, "scripts", {}), "lint-php", false)
18
- msg := "package.json: додай скрипт \"lint-php\" (php.mdc)"
11
+ some script_name, needles in data.template.contains.scripts
12
+ actual := object.get(object.get(input, "scripts", {}), script_name, "")
13
+ some needle in needles
14
+ not contains(actual, needle)
15
+ msg := sprintf("package.json: scripts.%s має містити %q (php.mdc)", [script_name, needle])
19
16
  }
@@ -0,0 +1,5 @@
1
+ {
2
+ "scripts": {
3
+ "lint-php": ["bun"]
4
+ }
5
+ }
@@ -1,21 +1,19 @@
1
- # Порт перевірки `lint-style.yml` з `npm/scripts/check-style-lint.mjs` (style-lint.mdc).
1
+ # Перевірка `lint-style.yml` (style-lint.mdc).
2
2
  #
3
- # Запуск (локально):
4
- # conftest test .github/workflows/lint-style.yml -p npm/policy/style_lint \
5
- # --namespace style_lint.lint_style_yml
6
- #
7
- # Перевіряє: хоча б один крок `run` містить `npx stylelint` (саме через npx, не
8
- # `bun run lint-style`). Універсальні workflow-перевірки (concurrency, заборонені
9
- # setup-bun/cache/install) — у `ga.workflow_common`.
10
- #
11
- # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
12
- # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
13
- # (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
3
+ # Канон надходить через --data: { "template": { "snippet": ... } }
4
+ # Структура --data сформована з template/lint-style.yml.snippet.yml.
5
+ # Маркер `run:` (npx stylelint substring) збирається з template's stylelint-job steps.
6
+ # Універсальні workflow-перевірки — у `ga.workflow_common`.
14
7
  package style_lint.lint_style_yml
15
8
 
16
9
  import rego.v1
17
10
 
18
- # Усі тексти `run:` зі steps усіх jobs, склеєні в один blob — для substring-перевірки.
11
+ expected_run_blob := concat("\n", [r |
12
+ some step in data.template.snippet.jobs.stylelint.steps
13
+ r := object.get(step, "run", "")
14
+ r != ""
15
+ ])
16
+
19
17
  all_run_text := concat("\n", [run_text |
20
18
  some job in object.get(input, "jobs", {})
21
19
  some step in object.get(job, "steps", [])
@@ -23,11 +21,11 @@ all_run_text := concat("\n", [run_text |
23
21
  ])
24
22
 
25
23
  deny contains msg if {
26
- not contains(all_run_text, "npx stylelint")
27
- msg := "lint-style.yml: жоден крок run не містить `npx stylelint` (style-lint.mdc)"
24
+ expected_run_blob != ""
25
+ not contains(all_run_text, expected_run_blob)
26
+ msg := sprintf("lint-style.yml: жоден крок run не містить %q (style-lint.mdc)", [expected_run_blob])
28
27
  }
29
28
 
30
- # Текст `run:` як один рядок: підтримує string і array форми (YAML).
31
29
  step_run_to_text(step) := step.run if is_string(step.run)
32
30
 
33
31
  else := concat("\n", [s | some s in step.run]) if is_array(step.run)
@@ -0,0 +1,39 @@
1
+ name: StyleLint
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - dev
7
+ - main
8
+ paths:
9
+ - '**/*.css'
10
+ - '**/*.scss'
11
+ - '**/*.vue'
12
+
13
+ pull_request:
14
+ branches:
15
+ - dev
16
+ - main
17
+ paths:
18
+ - '**/*.css'
19
+ - '**/*.scss'
20
+ - '**/*.vue'
21
+
22
+ concurrency:
23
+ group: ${{ github.ref }}-${{ github.workflow }}
24
+ cancel-in-progress: true
25
+
26
+ jobs:
27
+ stylelint:
28
+ runs-on: ubuntu-latest
29
+ permissions:
30
+ contents: read
31
+ steps:
32
+ - uses: actions/checkout@v6
33
+ with:
34
+ persist-credentials: false
35
+
36
+ - uses: ./.github/actions/setup-bun-deps
37
+
38
+ - name: StyleLint
39
+ run: npx stylelint '**/*.{css,scss,vue}' --fix
@@ -1,49 +1,41 @@
1
- # Порт перевірок `package.json` з `npm/scripts/check-style-lint.mjs` (style-lint.mdc).
1
+ # Порт перевірок `package.json` (style-lint.mdc).
2
2
  #
3
- # Запуск (локально):
4
- # conftest test package.json -p npm/policy/style_lint --namespace style_lint.package_json
3
+ # Канон надходить через --data: { "template": { "contains": ..., "snippet": ... } }
4
+ # Структура --data сформована з template/package.json.{contains,snippet}.json.
5
+ # FS-альтернативи (`.stylelintrc.*` файли) + `.stylelintignore` — у JS.
5
6
  #
6
- # Перевіряє: наявність скрипта `lint-style` з `npx stylelint`, `@nitra/stylelint-config`
7
- # у `devDependencies`, поле `stylelint.extends == "@nitra/stylelint-config"`. FS-частина
8
- # (зовнішні `.stylelintrc.*` як альтернатива полю; `.stylelintignore`) лишається у JS.
9
- #
10
- # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
11
- # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
12
- # (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
7
+ # Логіка, що ЛИШАЄТЬСЯ у rego (inverse не виноситься у template):
8
+ # - `@nitra/stylelint-config` має бути у devDependencies (presence-check).
13
9
  package style_lint.package_json
14
10
 
15
11
  import rego.v1
16
12
 
17
- # ── deny: lint-style скрипт ───────────────────────────────────────────────
13
+ # ── deny: substring requirements у scripts (contains) ────────────────────
18
14
 
19
15
  deny contains msg if {
20
- not object.get(object.get(input, "scripts", {}), "lint-style", false)
21
- msg := "package.json не містить скрипт \"lint-style\" (style-lint.mdc)"
16
+ some script_name, needles in data.template.contains.scripts
17
+ actual := object.get(object.get(input, "scripts", {}), script_name, "")
18
+ some needle in needles
19
+ not contains(actual, needle)
20
+ msg := sprintf("package.json: scripts.%s має містити %q (style-lint.mdc)", [script_name, needle])
22
21
  }
23
22
 
23
+ # ── deny: 2-level snippet walker (для stylelint.extends, якщо поле є) ────
24
+
24
25
  deny contains msg if {
25
- lint_style := object.get(object.get(input, "scripts", {}), "lint-style", "")
26
- lint_style != ""
27
- not contains(lint_style, "npx stylelint")
28
- msg := sprintf("lint-style має викликати stylelint через npx (зараз: %q) (style-lint.mdc)", [lint_style])
26
+ some section, expected_inner in data.template.snippet
27
+ cfg := object.get(input, section, null)
28
+ is_object(cfg)
29
+ some leaf_key, expected_value in expected_inner
30
+ actual := object.get(cfg, leaf_key, null)
31
+ actual != expected_value
32
+ msg := sprintf("package.json: %s.%s має бути %q (style-lint.mdc)", [section, leaf_key, expected_value])
29
33
  }
30
34
 
31
- # ── deny: @nitra/stylelint-config у devDependencies ───────────────────────
35
+ # ── deny: @nitra/stylelint-config у devDependencies (inverse) ────────────
32
36
 
33
37
  deny contains msg if {
34
38
  dev := object.get(input, "devDependencies", {})
35
39
  not "@nitra/stylelint-config" in object.keys(dev)
36
40
  msg := "@nitra/stylelint-config відсутній — bun add -d @nitra/stylelint-config (style-lint.mdc)"
37
41
  }
38
-
39
- # ── deny: поле stylelint.extends = "@nitra/stylelint-config" ──────────────
40
- #
41
- # JS-перевірка дозволяє альтернативу: окремий файл `.stylelintrc.*`. Цю частину
42
- # перевіряємо в JS (FS-вибірка); тут — лише структурна валідація поля, якщо воно є.
43
-
44
- deny contains msg if {
45
- cfg := object.get(input, "stylelint", null)
46
- is_object(cfg)
47
- object.get(cfg, "extends", null) != "@nitra/stylelint-config"
48
- msg := "package.json: stylelint.extends має бути \"@nitra/stylelint-config\" (style-lint.mdc)"
49
- }
@@ -0,0 +1,5 @@
1
+ {
2
+ "scripts": {
3
+ "lint-style": ["npx stylelint"]
4
+ }
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "stylelint": {
3
+ "extends": "@nitra/stylelint-config"
4
+ }
5
+ }
@@ -0,0 +1 @@
1
+ { "recommendations": ["stylelint.vscode-stylelint"] }
@@ -1,23 +1,13 @@
1
1
  # Перевірка `.vscode/extensions.json` для style-lint (style-lint.mdc).
2
2
  #
3
- # Запуск (локально):
4
- # conftest test .vscode/extensions.json -p npm/policy/style_lint/vscode_extensions \
5
- # --namespace style_lint.vscode_extensions
6
- #
7
- # Canonical (style-lint.mdc):
8
- # { "recommendations": ["stylelint.vscode-stylelint"] }
9
- #
10
- # Канон задає мінімум — `recommendations` має МІСТИТИ `stylelint.vscode-stylelint`;
11
- # додаткові записи (від інших правил — markdownlint, oxc тощо) дозволені.
12
- #
13
- # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
14
- # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`.
3
+ # Канон надходить через --data: { "template": { "snippet": ... } }
4
+ # Структура --data сформована з template/extensions.json.snippet.json.
15
5
  package style_lint.vscode_extensions
16
6
 
17
7
  import rego.v1
18
8
 
19
9
  deny contains msg if {
20
- recs := object.get(input, "recommendations", [])
21
- not "stylelint.vscode-stylelint" in {r | some r in recs}
22
- msg := ".vscode/extensions.json: recommendations має містити \"stylelint.vscode-stylelint\" (style-lint.mdc)"
10
+ some rec in data.template.snippet.recommendations
11
+ not rec in {r | some r in object.get(input, "recommendations", [])}
12
+ msg := sprintf(".vscode/extensions.json: recommendations має містити %q (style-lint.mdc)", [rec])
23
13
  }
@@ -0,0 +1,5 @@
1
+ {
2
+ "css.validate": false,
3
+ "less.validate": false,
4
+ "scss.validate": false
5
+ }
@@ -1,24 +1,15 @@
1
1
  # Перевірка `.vscode/settings.json` для style-lint (style-lint.mdc).
2
2
  #
3
- # Запуск (локально):
4
- # conftest test .vscode/settings.json -p npm/policy/style_lint/vscode_settings \
5
- # --namespace style_lint.vscode_settings
6
- #
7
- # Canonical (style-lint.mdc): вимкнути вбудовану валідацію CSS/SCSS/Less, щоб
8
- # stylelint був єдиним джерелом діагностики.
9
- # { "css.validate": false, "less.validate": false, "scss.validate": false }
10
- #
11
- # `editor.codeActionsOnSave` у каноні є, але це smell-test — навмисно не deny,
12
- # щоб не падати на пакетах, які мають свій codeActionsOnSave-конфіг.
13
- #
14
- # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
15
- # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`.
3
+ # Канон надходить через --data: { "template": { "snippet": ... } }
4
+ # Структура --data сформована з template/settings.json.snippet.json.
5
+ # Top-level літеральні keys — leaf-by-leaf walker.
16
6
  package style_lint.vscode_settings
17
7
 
18
8
  import rego.v1
19
9
 
20
10
  deny contains msg if {
21
- some key in {"css.validate", "less.validate", "scss.validate"}
22
- object.get(input, key, null) != false
23
- msg := sprintf(".vscode/settings.json: \"%s\" має бути false (style-lint.mdc)", [key])
11
+ some key, expected_value in data.template.snippet
12
+ actual := object.get(input, key, null)
13
+ actual != expected_value
14
+ msg := sprintf(".vscode/settings.json: \"%s\" має бути %v (style-lint.mdc)", [key, expected_value])
24
15
  }
@@ -1,91 +1,71 @@
1
- # Порт перевірок `.cspell.json` з `npm/scripts/check-text.mjs` (text.mdc).
1
+ # Перевірка `.cspell.json` (text.mdc).
2
2
  #
3
- # Запуск (локально):
4
- # conftest test .cspell.json -p npm/policy/text --namespace text.cspell
3
+ # Канон надходить через --data: { "template": { "snippet": ..., "contains": ..., "deny": ... } }
4
+ # Структура --data сформована з template/.cspell.json.{snippet,contains,deny}.json.
5
5
  #
6
- # Перевіряє: `version: "0.2"`, наявність `language`, імпорт `@nitra/cspell-dict`,
7
- # відсутність прямих імпортів `@cspell/dict-*`, обовʼязкові glob-и в `ignorePaths`
8
- # (text.mdc).
9
- #
10
- # Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
11
- # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
12
- # (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
6
+ # Логіка, що ЛИШАЄТЬСЯ у rego (inverse — не виноситься у template):
7
+ # - `language` має бути присутнє (presence-only).
13
8
  package text.cspell
14
9
 
15
10
  import rego.v1
16
11
 
17
- # ── Очікувані значення ─────────────────────────────────────────────────────
12
+ # ── deny: top-level snippet leafs (version etc) ──────────────────────────
18
13
 
19
- # Канонічні `ignorePaths` з text.mdc — кожен має бути присутнім.
20
- required_ignore_paths := {
21
- "**/node_modules/**",
22
- "**/vscode-extension/**",
23
- "**/.git/**",
24
- ".vscode",
25
- "report",
26
- "*.svg",
27
- "**/k8s/**/*.yaml",
14
+ deny contains msg if {
15
+ some key, expected_value in data.template.snippet
16
+ not is_array(expected_value)
17
+ not is_object(expected_value)
18
+ actual := object.get(input, key, null)
19
+ actual != expected_value
20
+ msg := sprintf(".cspell.json: %s має бути %v (text.mdc)", [key, expected_value])
28
21
  }
29
22
 
30
- nitra_cspell_dict_marker := "@nitra/cspell-dict"
31
-
32
- legacy_dict_marker := "@cspell/dict-"
33
-
34
- # Шаблон повідомлення про заборонений імпорт `@cspell/dict-*` — через `concat`
35
- # для regal style/line-length.
36
- legacy_dict_import_template := concat(" ", [
37
- ".cspell.json не має імпортувати @cspell/dict-* —",
38
- "використовуй лише @nitra/cspell-dict (знайдено: %s) (text.mdc)",
39
- ])
40
-
41
- # ── deny: version / language ──────────────────────────────────────────────
23
+ # ── deny: ignorePaths subset-of ──────────────────────────────────────────
42
24
 
43
25
  deny contains msg if {
44
- object.get(input, "version", null) != "0.2"
45
- msg := ".cspell.json: version має бути \"0.2\" (text.mdc)"
26
+ some field, expected_values in data.template.snippet
27
+ is_array(expected_values)
28
+ is_array(object.get(input, field, null))
29
+ actual_set := {v | some v in input[field]}
30
+ some required in expected_values
31
+ not required in actual_set
32
+ msg := sprintf(".cspell.json %s: додай %q (text.mdc)", [field, required])
46
33
  }
47
34
 
35
+ # ── deny: language presence (inverse, in rego) ───────────────────────────
36
+
48
37
  deny contains msg if {
49
38
  not object.get(input, "language", false)
50
39
  msg := ".cspell.json: відсутнє поле language (text.mdc)"
51
40
  }
52
41
 
53
- # ── deny: imports ─────────────────────────────────────────────────────────
42
+ # ── deny: import substrings required (contains) ─────────────────────────
54
43
 
55
44
  deny contains msg if {
56
- imports := object.get(input, "import", [])
45
+ some field, needles in data.template.contains
46
+ imports := object.get(input, field, [])
57
47
  is_array(imports)
58
- not has_nitra_dict_import(imports)
59
- msg := ".cspell.json не імпортує @nitra/cspell-dict/cspell-ext.json (text.mdc)"
48
+ some needle in needles
49
+ not has_substring_in_array(imports, needle)
50
+ msg := sprintf(".cspell.json: %s має містити %q (text.mdc)", [field, needle])
60
51
  }
61
52
 
53
+ # ── deny: import substrings forbidden ────────────────────────────────────
54
+
62
55
  deny contains msg if {
56
+ some forbidden, reason in data.template.deny["import-substrings"]
63
57
  imports := object.get(input, "import", [])
64
58
  is_array(imports)
65
59
  some imp in imports
66
60
  is_string(imp)
67
- contains(imp, legacy_dict_marker)
68
- msg := sprintf(legacy_dict_import_template, [imp])
61
+ contains(imp, forbidden)
62
+ msg := sprintf(".cspell.json import містить заборонений %q — %s", [imp, reason])
69
63
  }
70
64
 
71
- # ── deny: ignorePaths ─────────────────────────────────────────────────────
65
+ # ── helpers ──────────────────────────────────────────────────────────────
72
66
 
73
- deny contains msg if {
74
- not is_array(object.get(input, "ignorePaths", null))
75
- msg := ".cspell.json: додай масив ignorePaths з канонічними glob-ами (text.mdc)"
76
- }
77
-
78
- deny contains msg if {
79
- is_array(input.ignorePaths)
80
- some path in required_ignore_paths
81
- not path in {p | some p in input.ignorePaths}
82
- msg := sprintf(".cspell.json ignorePaths: додай %q (text.mdc)", [path])
83
- }
84
-
85
- # ── helpers ────────────────────────────────────────────────────────────────
86
-
87
- has_nitra_dict_import(imports) if {
88
- some imp in imports
89
- is_string(imp)
90
- contains(imp, nitra_cspell_dict_marker)
67
+ has_substring_in_array(arr, needle) if {
68
+ some item in arr
69
+ is_string(item)
70
+ contains(item, needle)
91
71
  }
@@ -0,0 +1,3 @@
1
+ {
2
+ "import": ["@nitra/cspell-dict"]
3
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "import-substrings": {
3
+ "@cspell/dict-": "використовуй лише @nitra/cspell-dict (text.mdc)"
4
+ }
5
+ }