@nitra/cursor 1.13.15 → 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.
- package/CHANGELOG.md +69 -0
- package/package.json +1 -1
- package/rules/abie/abie.mdc +1 -4
- package/rules/abie/policy/clean_merged_ignore_branches/clean_merged_ignore_branches.rego +21 -40
- package/rules/abie/policy/clean_merged_ignore_branches/template/clean-merged-branch.yml.snippet.yml +9 -0
- package/rules/docker/docker.mdc +2 -50
- package/rules/docker/policy/lint_docker_yml/lint_docker_yml.rego +33 -47
- package/rules/docker/policy/lint_docker_yml/template/lint-docker.yml.snippet.yml +41 -0
- package/rules/docker/policy/package_json/package_json.rego +11 -28
- package/rules/docker/policy/package_json/template/package.json.snippet.json +1 -0
- package/rules/image-avif/policy/package_json/package_json.rego +21 -35
- package/rules/image-avif/policy/package_json/template/package.json.deny.json +5 -0
- package/rules/image-compress/image-compress.mdc +2 -8
- package/rules/image-compress/policy/package_json/package_json.rego +24 -65
- package/rules/image-compress/policy/package_json/template/package.json.contains.json +5 -0
- package/rules/image-compress/policy/package_json/template/package.json.deny.json +8 -0
- package/rules/js-bun-db/policy/package_json/package_json.rego +8 -21
- package/rules/js-bun-db/policy/package_json/template/package.json.deny.json +7 -0
- package/rules/js-bun-redis/policy/package_json/package_json.rego +8 -30
- package/rules/js-bun-redis/policy/package_json/template/package.json.deny.json +12 -0
- package/rules/js-lint/policy/jscpd/jscpd.rego +29 -23
- package/rules/js-lint/policy/jscpd/template/.jscpd.json.snippet.json +6 -0
- package/rules/js-lint/policy/lint_js_yml/lint_js_yml.rego +39 -47
- package/rules/js-lint/policy/lint_js_yml/template/lint-js.yml.snippet.yml +44 -0
- package/rules/js-lint/policy/package_json/package_json.rego +22 -42
- package/rules/js-lint/policy/package_json/template/package.json.snippet.json +6 -0
- package/rules/js-lint/policy/vscode_extensions/template/extensions.json.snippet.json +7 -0
- package/rules/js-lint/policy/vscode_extensions/vscode_extensions.rego +4 -17
- package/rules/js-run/policy/configmap/configmap.rego +11 -35
- package/rules/js-run/policy/configmap/template/configmap.yaml.contains.yml +4 -0
- package/rules/js-run/policy/jsconfig/jsconfig.rego +39 -46
- package/rules/js-run/policy/jsconfig/template/jsconfig.json.snippet.json +10 -0
- package/rules/js-run/policy/package_json/package_json.rego +10 -21
- package/rules/js-run/policy/package_json/template/package.json.deny.json +10 -0
- package/rules/php/php.mdc +2 -56
- package/rules/php/policy/lint_php_yml/lint_php_yml.rego +15 -13
- package/rules/php/policy/lint_php_yml/template/lint-php.yml.snippet.yml +47 -0
- package/rules/php/policy/package_json/package_json.rego +9 -12
- package/rules/php/policy/package_json/template/package.json.contains.json +5 -0
- package/rules/style-lint/policy/lint_style_yml/lint_style_yml.rego +14 -16
- package/rules/style-lint/policy/lint_style_yml/template/lint-style.yml.snippet.yml +39 -0
- package/rules/style-lint/policy/package_json/package_json.rego +22 -30
- package/rules/style-lint/policy/package_json/template/package.json.contains.json +5 -0
- package/rules/style-lint/policy/package_json/template/package.json.snippet.json +5 -0
- package/rules/style-lint/policy/vscode_extensions/template/extensions.json.snippet.json +1 -0
- package/rules/style-lint/policy/vscode_extensions/vscode_extensions.rego +5 -15
- package/rules/style-lint/policy/vscode_settings/template/settings.json.snippet.json +5 -0
- package/rules/style-lint/policy/vscode_settings/vscode_settings.rego +7 -16
- package/rules/text/policy/cspell/cspell.rego +39 -59
- package/rules/text/policy/cspell/template/.cspell.json.contains.json +3 -0
- package/rules/text/policy/cspell/template/.cspell.json.deny.json +5 -0
- package/rules/text/policy/cspell/template/.cspell.json.snippet.json +12 -0
- package/rules/text/policy/markdownlint/markdownlint.rego +37 -50
- package/rules/text/policy/markdownlint/template/.markdownlint-cli2.jsonc.snippet.jsonc +11 -0
- package/rules/text/policy/oxfmtrc/oxfmtrc.rego +23 -58
- package/rules/text/policy/oxfmtrc/template/.oxfmtrc.json.snippet.json +12 -0
- package/rules/text/policy/package_json/package_json.rego +14 -52
- package/rules/text/policy/package_json/template/package.json.deny.json +15 -0
- package/rules/text/policy/vscode_extensions/template/extensions.json.snippet.json +7 -0
- package/rules/text/policy/vscode_extensions/vscode_extensions.rego +4 -28
- package/rules/text/policy/vscode_settings/template/settings.json.snippet.json +9 -0
- package/rules/text/policy/vscode_settings/vscode_settings.rego +20 -42
|
@@ -1,25 +1,12 @@
|
|
|
1
1
|
# Перевірка `.vscode/extensions.json` для js-lint (js-lint.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
# Канон задає мінімум — додаткові рекомендації від інших правил дозволені.
|
|
5
|
-
#
|
|
6
|
-
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
7
|
-
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
8
|
-
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
9
4
|
package js_lint.vscode_extensions
|
|
10
5
|
|
|
11
6
|
import rego.v1
|
|
12
7
|
|
|
13
|
-
required_extensions := {
|
|
14
|
-
"dbaeumer.vscode-eslint",
|
|
15
|
-
"github.vscode-github-actions",
|
|
16
|
-
"oxc.oxc-vscode",
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
recommendations_set := {r | some r in object.get(input, "recommendations", [])}
|
|
20
|
-
|
|
21
8
|
deny contains msg if {
|
|
22
|
-
some
|
|
23
|
-
not
|
|
24
|
-
msg := sprintf(".vscode/extensions.json: recommendations має містити %q (js-lint.mdc)", [
|
|
9
|
+
some rec in data.template.snippet.recommendations
|
|
10
|
+
not rec in {r | some r in object.get(input, "recommendations", [])}
|
|
11
|
+
msg := sprintf(".vscode/extensions.json: recommendations має містити %q (js-lint.mdc)", [rec])
|
|
25
12
|
}
|
|
@@ -1,45 +1,21 @@
|
|
|
1
|
-
#
|
|
2
|
-
# (js-run.mdc) — `OTEL_RESOURCE_ATTRIBUTES` має містити `service.name=` і
|
|
3
|
-
# `service.namespace=`.
|
|
1
|
+
# Перевірка ConfigMap (js-run.mdc).
|
|
4
2
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
# Відповідність імені ConfigMap імені Deployment (cross-file) — у JS і `check-k8s.mjs`.
|
|
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": { "contains": ... } }
|
|
4
|
+
# Структура --data сформована з template/configmap.yaml.contains.yml.
|
|
5
|
+
# Контекст: kind=ConfigMap; OTEL_RESOURCE_ATTRIBUTES має містити кожен substring
|
|
6
|
+
# зі snippet (`service.name=`, `service.namespace=`).
|
|
14
7
|
package js_run.configmap
|
|
15
8
|
|
|
16
9
|
import rego.v1
|
|
17
10
|
|
|
18
|
-
# Шаблони повідомлень — через `concat` для regal style/line-length.
|
|
19
|
-
otel_service_name_template := concat(" ", [
|
|
20
|
-
"ConfigMap %q: OTEL_RESOURCE_ATTRIBUTES має містити",
|
|
21
|
-
"`service.name=` (js-run.mdc)",
|
|
22
|
-
])
|
|
23
|
-
|
|
24
|
-
otel_service_namespace_template := concat(" ", [
|
|
25
|
-
"ConfigMap %q: OTEL_RESOURCE_ATTRIBUTES має містити",
|
|
26
|
-
"`service.namespace=` (js-run.mdc)",
|
|
27
|
-
])
|
|
28
|
-
|
|
29
|
-
deny contains msg if {
|
|
30
|
-
input.kind == "ConfigMap"
|
|
31
|
-
otel := object.get(object.get(input, "data", {}), "OTEL_RESOURCE_ATTRIBUTES", "")
|
|
32
|
-
otel != ""
|
|
33
|
-
not contains(otel, "service.name=")
|
|
34
|
-
msg := sprintf(otel_service_name_template, [cm_name])
|
|
35
|
-
}
|
|
36
|
-
|
|
37
11
|
deny contains msg if {
|
|
38
12
|
input.kind == "ConfigMap"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
13
|
+
some field, needles in data.template.contains.data
|
|
14
|
+
actual := object.get(object.get(input, "data", {}), field, "")
|
|
15
|
+
actual != ""
|
|
16
|
+
some needle in needles
|
|
17
|
+
not contains(actual, needle)
|
|
18
|
+
msg := sprintf("ConfigMap %q: %s має містити %q (js-run.mdc)", [cm_name, field, needle])
|
|
43
19
|
}
|
|
44
20
|
|
|
45
21
|
cm_name := object.get(object.get(input, "metadata", {}), "name", "?")
|
|
@@ -1,66 +1,59 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Перевірка `jsconfig.json` (js-run.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# Перевіряє: `compilerOptions.{lib, module, moduleResolution, target, checkJs}` і
|
|
8
|
-
# `include` мають канонічні значення (js-run.mdc).
|
|
9
|
-
#
|
|
10
|
-
# FS-перевірка (наявність каталогу `src/` у пакеті, наявність самого `jsconfig.json`)
|
|
11
|
-
# і вибір файлу-кандидата — у JS.
|
|
12
|
-
#
|
|
13
|
-
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
14
|
-
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
15
|
-
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
+
# Структура --data сформована з template/jsconfig.json.snippet.yml.
|
|
5
|
+
# Walker: для кожного leaf у template's snippet порівнюємо input[path].
|
|
6
|
+
# Для масивів — equality (не subset-of, бо в jsconfig потрібен точний набір).
|
|
16
7
|
package js_run.jsconfig
|
|
17
8
|
|
|
18
9
|
import rego.v1
|
|
19
10
|
|
|
20
|
-
#
|
|
21
|
-
|
|
11
|
+
# Generic 2-level walker: section → key → expected (для compilerOptions).
|
|
22
12
|
deny contains msg if {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
some section, expected_inner in data.template.snippet
|
|
14
|
+
is_object(expected_inner)
|
|
15
|
+
inner := object.get(input, section, {})
|
|
16
|
+
is_object(inner)
|
|
17
|
+
some leaf_key, expected_value in expected_inner
|
|
18
|
+
actual := object.get(inner, leaf_key, null)
|
|
19
|
+
not values_match(actual, expected_value)
|
|
20
|
+
msg := sprintf("jsconfig.json: %s.%s має бути %v (js-run.mdc)", [section, leaf_key, expected_value])
|
|
26
21
|
}
|
|
27
22
|
|
|
23
|
+
# Section відсутня або не обʼєкт.
|
|
28
24
|
deny contains msg if {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
some section, expected_inner in data.template.snippet
|
|
26
|
+
is_object(expected_inner)
|
|
27
|
+
raw := object.get(input, section, null)
|
|
28
|
+
not is_object(raw)
|
|
29
|
+
msg := sprintf("jsconfig.json: відсутній обʼєкт %s (js-run.mdc)", [section])
|
|
33
30
|
}
|
|
34
31
|
|
|
32
|
+
# Top-level масив (наприклад include) — порівнюємо як множину.
|
|
35
33
|
deny contains msg if {
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
some field, expected_array in data.template.snippet
|
|
35
|
+
is_array(expected_array)
|
|
36
|
+
actual := object.get(input, field, null)
|
|
37
|
+
not is_array(actual)
|
|
38
|
+
msg := sprintf("jsconfig.json: %s має бути масив %v (js-run.mdc)", [field, expected_array])
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
deny contains msg if {
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
some field, expected_array in data.template.snippet
|
|
43
|
+
is_array(expected_array)
|
|
44
|
+
is_array(object.get(input, field, null))
|
|
45
|
+
{x | some x in input[field]} != {x | some x in expected_array}
|
|
46
|
+
msg := sprintf("jsconfig.json: %s має бути %v (js-run.mdc)", [field, expected_array])
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
# Helper: leaf-level value match, з підтримкою масивів як множин.
|
|
50
|
+
values_match(actual, expected) if {
|
|
51
|
+
not is_array(expected)
|
|
52
|
+
actual == expected
|
|
48
53
|
}
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
# ── deny: include ──────────────────────────────────────────────────────────
|
|
56
|
-
|
|
57
|
-
deny contains msg if {
|
|
58
|
-
not is_array(object.get(input, "include", null))
|
|
59
|
-
msg := "jsconfig.json: include має бути [\"src/**/*\"] (js-run.mdc)"
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
deny contains msg if {
|
|
63
|
-
is_array(input.include)
|
|
64
|
-
{p | some p in input.include} != {"src/**/*"}
|
|
65
|
-
msg := "jsconfig.json: include має бути [\"src/**/*\"] (js-run.mdc)"
|
|
55
|
+
values_match(actual, expected) if {
|
|
56
|
+
is_array(expected)
|
|
57
|
+
is_array(actual)
|
|
58
|
+
{x | some x in actual} == {x | some x in expected}
|
|
66
59
|
}
|
|
@@ -1,31 +1,20 @@
|
|
|
1
|
-
#
|
|
2
|
-
# (js-run.mdc) — заборона `bunyan` / `@nitra/bunyan`.
|
|
1
|
+
# Перевірка `package.json` (js-run.mdc).
|
|
3
2
|
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# AST-скан коду на імпорти `bunyan` / `process.env` без `checkEnv`,
|
|
9
|
-
# `new Promise(resolve => setTimeout(resolve, ...))`, обмеження `#conn/*`-аліасів —
|
|
10
|
-
# у JS (потребує парсингу `.js` / `.ts` через oxc-parser).
|
|
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).
|
|
3
|
+
# Канон надходить через --data: { "template": { "deny": ... } }
|
|
4
|
+
# Структура --data сформована з template/package.json.deny.json.
|
|
5
|
+
# AST-скан коду (`bunyan`/`process.env`/`#conn/*`) — у JS.
|
|
15
6
|
package js_run.package_json
|
|
16
7
|
|
|
17
8
|
import rego.v1
|
|
18
9
|
|
|
19
|
-
forbidden_packages := {"bunyan", "@nitra/bunyan"}
|
|
20
|
-
|
|
21
10
|
deny contains msg if {
|
|
22
|
-
some
|
|
23
|
-
|
|
24
|
-
msg := sprintf("dependencies
|
|
11
|
+
some pkg, reason in data.template.deny.dependencies
|
|
12
|
+
pkg in object.keys(object.get(input, "dependencies", {}))
|
|
13
|
+
msg := sprintf("dependencies.%s — %s", [pkg, reason])
|
|
25
14
|
}
|
|
26
15
|
|
|
27
16
|
deny contains msg if {
|
|
28
|
-
some
|
|
29
|
-
|
|
30
|
-
msg := sprintf("devDependencies
|
|
17
|
+
some pkg, reason in data.template.deny.devDependencies
|
|
18
|
+
pkg in object.keys(object.get(input, "devDependencies", {}))
|
|
19
|
+
msg := sprintf("devDependencies.%s — %s", [pkg, reason])
|
|
31
20
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"bunyan": "використовуй стандартні логери (js-run.mdc)",
|
|
4
|
+
"@nitra/bunyan": "використовуй стандартні логери (js-run.mdc)"
|
|
5
|
+
},
|
|
6
|
+
"devDependencies": {
|
|
7
|
+
"bunyan": "використовуй стандартні логери (js-run.mdc)",
|
|
8
|
+
"@nitra/bunyan": "використовуй стандартні логери (js-run.mdc)"
|
|
9
|
+
}
|
|
10
|
+
}
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
1
|
+
# Перевірка `lint-php.yml` (php.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
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
|
-
|
|
25
|
-
|
|
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
|
-
#
|
|
1
|
+
# Перевірка `package.json` (php.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
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
|
-
|
|
18
|
-
|
|
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
|
}
|
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Перевірка `lint-style.yml` (style-lint.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
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`
|
|
1
|
+
# Порт перевірок `package.json` (style-lint.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
3
|
+
# Канон надходить через --data: { "template": { "contains": ..., "snippet": ... } }
|
|
4
|
+
# Структура --data сформована з template/package.json.{contains,snippet}.json.
|
|
5
|
+
# FS-альтернативи (`.stylelintrc.*` файли) + `.stylelintignore` — у JS.
|
|
5
6
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
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:
|
|
13
|
+
# ── deny: substring requirements у scripts (contains) ────────────────────
|
|
18
14
|
|
|
19
15
|
deny contains msg if {
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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 @@
|
|
|
1
|
+
{ "recommendations": ["stylelint.vscode-stylelint"] }
|