@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,23 +1,13 @@
|
|
|
1
1
|
# Перевірка `.vscode/extensions.json` для style-lint (style-lint.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
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
|
-
|
|
21
|
-
not
|
|
22
|
-
msg := ".vscode/extensions.json: recommendations має містити
|
|
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
|
}
|
|
@@ -1,24 +1,15 @@
|
|
|
1
1
|
# Перевірка `.vscode/settings.json` для style-lint (style-lint.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
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
|
|
22
|
-
object.get(input, key, null)
|
|
23
|
-
|
|
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
|
-
#
|
|
1
|
+
# Перевірка `.cspell.json` (text.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ..., "contains": ..., "deny": ... } }
|
|
4
|
+
# Структура --data сформована з template/.cspell.json.{snippet,contains,deny}.json.
|
|
5
5
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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:
|
|
42
|
+
# ── deny: import substrings required (contains) ─────────────────────────
|
|
54
43
|
|
|
55
44
|
deny contains msg if {
|
|
56
|
-
|
|
45
|
+
some field, needles in data.template.contains
|
|
46
|
+
imports := object.get(input, field, [])
|
|
57
47
|
is_array(imports)
|
|
58
|
-
|
|
59
|
-
|
|
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,
|
|
68
|
-
msg := sprintf(
|
|
61
|
+
contains(imp, forbidden)
|
|
62
|
+
msg := sprintf(".cspell.json import містить заборонений %q — %s", [imp, reason])
|
|
69
63
|
}
|
|
70
64
|
|
|
71
|
-
# ──
|
|
65
|
+
# ── helpers ──────────────────────────────────────────────────────────────
|
|
72
66
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
}
|
|
@@ -1,70 +1,57 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Перевірка `.markdownlint-cli2.jsonc` (text.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# Конфтест парсить `.jsonc` як JSON лише якщо файл — валідний JSON (без коментарів).
|
|
8
|
-
# У випадку справжнього JSONC з `//` коментарями цей крок мовчки ігноруватиметься
|
|
9
|
-
# (conftest skip). FS-перевірка (наявність файлу) живе у JS.
|
|
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
|
-
#
|
|
17
|
-
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
18
|
-
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
19
|
-
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
+
# Структура --data сформована з template/.markdownlint-cli2.jsonc.snippet.jsonc.
|
|
5
|
+
# Walker: top-level leaf, потім вкладені обʼєкти (config.<rule>); також рекурсивний
|
|
6
|
+
# leaf-check для MD024.siblings_only.
|
|
20
7
|
package text.markdownlint
|
|
21
8
|
|
|
22
9
|
import rego.v1
|
|
23
10
|
|
|
24
|
-
# ──
|
|
25
|
-
|
|
26
|
-
config_rule_template := concat(" ", [
|
|
27
|
-
".markdownlint-cli2.jsonc: config.%s має бути %v",
|
|
28
|
-
"(зараз: %v) (text.mdc)",
|
|
29
|
-
])
|
|
30
|
-
|
|
31
|
-
# ── deny: gitignore ───────────────────────────────────────────────────────
|
|
11
|
+
# ── deny: top-level leafs ───────────────────────────────────────────────
|
|
32
12
|
|
|
33
13
|
deny contains msg if {
|
|
34
|
-
|
|
35
|
-
|
|
14
|
+
some key, expected_value in data.template.snippet
|
|
15
|
+
not is_object(expected_value)
|
|
16
|
+
actual := object.get(input, key, null)
|
|
17
|
+
actual != expected_value
|
|
18
|
+
msg := sprintf(".markdownlint-cli2.jsonc: %s має бути %v (text.mdc)", [key, expected_value])
|
|
36
19
|
}
|
|
37
20
|
|
|
38
|
-
# ── deny: config
|
|
21
|
+
# ── deny: 2-level leafs (config.<rule> = scalar) ────────────────────────
|
|
39
22
|
|
|
40
23
|
deny contains msg if {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
24
|
+
some section, expected_inner in data.template.snippet
|
|
25
|
+
is_object(expected_inner)
|
|
26
|
+
inner := object.get(input, section, {})
|
|
27
|
+
is_object(inner)
|
|
28
|
+
some leaf_key, expected_value in expected_inner
|
|
29
|
+
not is_object(expected_value)
|
|
30
|
+
actual := object.get(inner, leaf_key, null)
|
|
31
|
+
actual != expected_value
|
|
32
|
+
msg := sprintf(".markdownlint-cli2.jsonc: %s.%s має бути %v (text.mdc)", [section, leaf_key, expected_value])
|
|
44
33
|
}
|
|
45
34
|
|
|
46
|
-
# ── deny:
|
|
35
|
+
# ── deny: 3-level leafs (config.MD024.siblings_only) ────────────────────
|
|
47
36
|
|
|
48
37
|
deny contains msg if {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
some section, expected_inner in data.template.snippet
|
|
39
|
+
is_object(expected_inner)
|
|
40
|
+
some inner_key, expected_subinner in expected_inner
|
|
41
|
+
is_object(expected_subinner)
|
|
42
|
+
subinner := object.get(object.get(input, section, {}), inner_key, {})
|
|
43
|
+
is_object(subinner)
|
|
44
|
+
some leaf, expected in expected_subinner
|
|
45
|
+
actual := object.get(subinner, leaf, null)
|
|
46
|
+
actual != expected
|
|
47
|
+
msg := sprintf(".markdownlint-cli2.jsonc: %s.%s.%s має бути %v (text.mdc)", [section, inner_key, leaf, expected])
|
|
53
48
|
}
|
|
54
49
|
|
|
55
|
-
# ── deny:
|
|
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
|
-
}
|
|
50
|
+
# ── deny: vкладеного обʼєкта взагалі немає ──────────────────────────────
|
|
63
51
|
|
|
64
52
|
deny contains msg if {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
is_object(
|
|
68
|
-
|
|
69
|
-
msg := sprintf(config_rule_template, ["MD024.siblings_only", true, object.get(md024, "siblings_only", null)])
|
|
53
|
+
some section, expected_inner in data.template.snippet
|
|
54
|
+
is_object(expected_inner)
|
|
55
|
+
not is_object(object.get(input, section, null))
|
|
56
|
+
msg := sprintf(".markdownlint-cli2.jsonc: відсутній обʼєкт %s (text.mdc)", [section])
|
|
70
57
|
}
|
|
@@ -1,24 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Перевірка `.oxfmtrc.json` (text.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
+
# Структура --data сформована з template/.oxfmtrc.json.snippet.json.
|
|
5
|
+
# Generic walker: top-level scalar leaf-check + array subset-of (для ignorePatterns).
|
|
5
6
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# канонічними glob-ами (hasura/metadata, schema.graphql, auto-imports.d.ts).
|
|
9
|
-
#
|
|
10
|
-
# FS-перевірки (наявність самого `.oxfmtrc.json`, `.prettierrc.*` файлів) живуть
|
|
11
|
-
# у `check-text.mjs`. Тут — лише про вже завантажений input.
|
|
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).
|
|
7
|
+
# Логіка, що ЛИШАЄТЬСЯ у rego (inverse — не виноситься у template):
|
|
8
|
+
# - required_keys: ключі, що мають бути присутні (presence-only, без точного значення).
|
|
16
9
|
package text.oxfmtrc
|
|
17
10
|
|
|
18
11
|
import rego.v1
|
|
19
12
|
|
|
20
|
-
# ── Очікувані значення ─────────────────────────────────────────────────────
|
|
21
|
-
|
|
22
13
|
required_keys := [
|
|
23
14
|
"arrowParens",
|
|
24
15
|
"printWidth",
|
|
@@ -31,60 +22,34 @@ required_keys := [
|
|
|
31
22
|
"useTabs",
|
|
32
23
|
]
|
|
33
24
|
|
|
34
|
-
required_ignore_patterns := {
|
|
35
|
-
"**/hasura/metadata/**",
|
|
36
|
-
"**/schema.graphql",
|
|
37
|
-
"**/auto-imports.d.ts",
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
# ── deny: обовʼязкові ключі ────────────────────────────────────────────────
|
|
41
|
-
|
|
42
25
|
deny contains msg if {
|
|
43
26
|
some key in required_keys
|
|
44
27
|
not key in object.keys(input)
|
|
45
28
|
msg := sprintf(".oxfmtrc.json: відсутній обовʼязковий ключ %q (text.mdc)", [key])
|
|
46
29
|
}
|
|
47
30
|
|
|
48
|
-
# ── deny: канонічні значення ───────────────────────────────────────────────
|
|
49
|
-
#
|
|
50
|
-
# `object.get(…, sentinel)` робить значення визначеним — інакше при відсутньому
|
|
51
|
-
# ключі порівняння дало б `undefined`, не `true`, і правило мовчки не спрацювало б.
|
|
52
|
-
|
|
53
|
-
deny contains msg if {
|
|
54
|
-
object.get(input, "semi", null) != false
|
|
55
|
-
msg := ".oxfmtrc.json: semi має бути false (text.mdc)"
|
|
56
|
-
}
|
|
57
|
-
|
|
58
31
|
deny contains msg if {
|
|
59
|
-
|
|
60
|
-
|
|
32
|
+
some key, expected_value in data.template.snippet
|
|
33
|
+
not is_array(expected_value)
|
|
34
|
+
not is_object(expected_value)
|
|
35
|
+
actual := object.get(input, key, null)
|
|
36
|
+
actual != expected_value
|
|
37
|
+
msg := sprintf(".oxfmtrc.json: %s має бути %v (text.mdc)", [key, expected_value])
|
|
61
38
|
}
|
|
62
39
|
|
|
63
40
|
deny contains msg if {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
deny contains msg if {
|
|
69
|
-
object.get(input, "useTabs", null) != false
|
|
70
|
-
msg := ".oxfmtrc.json: useTabs має бути false (text.mdc)"
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
deny contains msg if {
|
|
74
|
-
object.get(input, "printWidth", null) != 120
|
|
75
|
-
msg := ".oxfmtrc.json: printWidth має бути 120 (text.mdc)"
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
# ── deny: ignorePatterns ───────────────────────────────────────────────────
|
|
79
|
-
|
|
80
|
-
deny contains msg if {
|
|
81
|
-
not is_array(object.get(input, "ignorePatterns", null))
|
|
82
|
-
msg := ".oxfmtrc.json: додай масив ignorePatterns з канонічними glob-ами (text.mdc)"
|
|
41
|
+
some field, expected_values in data.template.snippet
|
|
42
|
+
is_array(expected_values)
|
|
43
|
+
not is_array(object.get(input, field, null))
|
|
44
|
+
msg := sprintf(".oxfmtrc.json: додай масив %s з канонічними glob-ами (text.mdc)", [field])
|
|
83
45
|
}
|
|
84
46
|
|
|
85
47
|
deny contains msg if {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
48
|
+
some field, expected_values in data.template.snippet
|
|
49
|
+
is_array(expected_values)
|
|
50
|
+
is_array(object.get(input, field, null))
|
|
51
|
+
actual_set := {v | some v in input[field]}
|
|
52
|
+
some required in expected_values
|
|
53
|
+
not required in actual_set
|
|
54
|
+
msg := sprintf(".oxfmtrc.json %s: додай %q (text.mdc)", [field, required])
|
|
90
55
|
}
|
|
@@ -1,66 +1,34 @@
|
|
|
1
|
-
# Порт текст-специфічних перевірок `package.json`
|
|
1
|
+
# Порт текст-специфічних перевірок `package.json` (text.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
3
|
+
# Канон надходить через --data: { "template": { "deny": ... } }
|
|
4
|
+
# Структура --data сформована з template/package.json.deny.json:
|
|
5
|
+
# - `top-level`: top-level forbidden fields (e.g. `prettier`)
|
|
6
|
+
# - `dependencies` / `devDependencies`: forbidden packages.
|
|
5
7
|
#
|
|
6
|
-
#
|
|
7
|
-
# у
|
|
8
|
-
#
|
|
9
|
-
# Перевірка скрипта `lint-text` (cspell, run-shellcheck-text.mjs, markdownlint, v8r,
|
|
10
|
-
# обовʼязкові glob-и для v8r) — у JS-частині (`check-text.mjs`): занадто варіативна
|
|
11
|
-
# для декларативної політики (3 режими v8r з різними вимогами до глобів).
|
|
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).
|
|
8
|
+
# Логіка, що ЛИШАЄТЬСЯ у rego (inverse, не виноситься у template):
|
|
9
|
+
# - `@nitra/cspell-dict` ^2.0.0+ обовʼязковий у devDependencies (presence + semver range).
|
|
16
10
|
package text.package_json
|
|
17
11
|
|
|
18
12
|
import rego.v1
|
|
19
13
|
|
|
20
|
-
# ── Заборонені пакети у dependencies/devDependencies ──────────────────────
|
|
21
|
-
|
|
22
|
-
forbidden_packages := {
|
|
23
|
-
"prettier": "Prettier заборонено — використовуй oxfmt (text.mdc)",
|
|
24
|
-
"@nitra/prettier-config": "Prettier-конфіг заборонено — використовуй oxfmt (text.mdc)",
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
# ── deny: заборонене поле `prettier` у package.json ───────────────────────
|
|
28
|
-
|
|
29
14
|
deny contains msg if {
|
|
30
|
-
|
|
31
|
-
|
|
15
|
+
some field, reason in data.template.deny["top-level"]
|
|
16
|
+
object.get(input, field, null) != null
|
|
17
|
+
msg := sprintf("package.json містить поле %q — %s", [field, reason])
|
|
32
18
|
}
|
|
33
19
|
|
|
34
|
-
# ── deny: prettier у dependencies/devDependencies ─────────────────────────
|
|
35
|
-
|
|
36
20
|
deny contains msg if {
|
|
37
|
-
some pkg,
|
|
21
|
+
some pkg, reason in data.template.deny.dependencies
|
|
38
22
|
pkg in object.keys(object.get(input, "dependencies", {}))
|
|
39
|
-
msg := sprintf("package.json: dependencies містить %q — %s", [pkg,
|
|
23
|
+
msg := sprintf("package.json: dependencies містить %q — %s", [pkg, reason])
|
|
40
24
|
}
|
|
41
25
|
|
|
42
26
|
deny contains msg if {
|
|
43
|
-
some pkg,
|
|
27
|
+
some pkg, reason in data.template.deny.devDependencies
|
|
44
28
|
pkg in object.keys(object.get(input, "devDependencies", {}))
|
|
45
|
-
msg := sprintf("package.json: devDependencies містить %q — %s", [pkg,
|
|
29
|
+
msg := sprintf("package.json: devDependencies містить %q — %s", [pkg, reason])
|
|
46
30
|
}
|
|
47
31
|
|
|
48
|
-
# ── deny: markdownlint-cli2 не повинен бути у залежностях ─────────────────
|
|
49
|
-
#
|
|
50
|
-
# Канонічний виклик — `bunx markdownlint-cli2` у `lint-text`, без оголошення пакета.
|
|
51
|
-
|
|
52
|
-
deny contains msg if {
|
|
53
|
-
"markdownlint-cli2" in object.keys(object.get(input, "dependencies", {}))
|
|
54
|
-
msg := "package.json: dependencies містить markdownlint-cli2 — використовуй bunx у lint-text (text.mdc)"
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
deny contains msg if {
|
|
58
|
-
"markdownlint-cli2" in object.keys(object.get(input, "devDependencies", {}))
|
|
59
|
-
msg := "package.json: devDependencies містить markdownlint-cli2 — використовуй bunx у lint-text (text.mdc)"
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
# ── deny: @nitra/cspell-dict ^2.0.0+ обовʼязковий ─────────────────────────
|
|
63
|
-
|
|
64
32
|
deny contains msg if {
|
|
65
33
|
dev := object.get(input, "devDependencies", {})
|
|
66
34
|
not "@nitra/cspell-dict" in object.keys(dev)
|
|
@@ -74,13 +42,7 @@ deny contains msg if {
|
|
|
74
42
|
msg := sprintf("@nitra/cspell-dict має бути ^2.0.0 або новіший (зараз %q) (text.mdc)", [range])
|
|
75
43
|
}
|
|
76
44
|
|
|
77
|
-
# ── helpers ────────────────────────────────────────────────────────────────
|
|
78
|
-
|
|
79
|
-
# Чи мажорна версія cspell-dict ≥ 2. Підтримує `^2.0.0`, `~2.x`, `2.5.0`,
|
|
80
|
-
# `>=2.0.0`, `workspace:*` (тоді fallback false), із префіксом і без.
|
|
81
|
-
# Regex `^[\^~>=<]*\s*(\d+)` дістає першу цифру після опціональних range-операторів.
|
|
82
45
|
cspell_dict_major_at_least_2(range) if {
|
|
83
|
-
# `regex.find_n` повертає масив збігів; беремо перший і дивимось на перше число.
|
|
84
46
|
match := regex.find_n(`^[\^~>=<]*\s*(\d+)`, range, 1)
|
|
85
47
|
count(match) > 0
|
|
86
48
|
major := to_number(regex.replace(match[0], `^[\^~>=<]*\s*`, ""))
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"top-level": {
|
|
3
|
+
"prettier": "Prettier заборонено — використовуй oxfmt (text.mdc)"
|
|
4
|
+
},
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"prettier": "Prettier заборонено — використовуй oxfmt (text.mdc)",
|
|
7
|
+
"@nitra/prettier-config": "Prettier-конфіг заборонено — використовуй oxfmt (text.mdc)",
|
|
8
|
+
"markdownlint-cli2": "використовуй bunx у lint-text (text.mdc)"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"prettier": "Prettier заборонено — використовуй oxfmt (text.mdc)",
|
|
12
|
+
"@nitra/prettier-config": "Prettier-конфіг заборонено — використовуй oxfmt (text.mdc)",
|
|
13
|
+
"markdownlint-cli2": "використовуй bunx у lint-text (text.mdc)"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -1,36 +1,12 @@
|
|
|
1
1
|
# Перевірка `.vscode/extensions.json` для text (text.mdc).
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
# conftest test .vscode/extensions.json -p npm/policy/text/vscode_extensions \
|
|
5
|
-
# --namespace text.vscode_extensions
|
|
6
|
-
#
|
|
7
|
-
# Canonical (text.mdc): у `recommendations` мають бути три розширення
|
|
8
|
-
# - DavidAnson.vscode-markdownlint
|
|
9
|
-
# - oxc.oxc-vscode
|
|
10
|
-
# - timonwong.shellcheck
|
|
11
|
-
#
|
|
12
|
-
# Канон задає мінімум — додаткові записи (від інших правил) дозволені.
|
|
13
|
-
#
|
|
14
|
-
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
15
4
|
package text.vscode_extensions
|
|
16
5
|
|
|
17
6
|
import rego.v1
|
|
18
7
|
|
|
19
|
-
required_extensions := {
|
|
20
|
-
"DavidAnson.vscode-markdownlint",
|
|
21
|
-
"oxc.oxc-vscode",
|
|
22
|
-
"timonwong.shellcheck",
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
missing_extension_template := ".vscode/extensions.json: recommendations має містити %q (text.mdc)"
|
|
26
|
-
|
|
27
|
-
# Множина усіх записів `recommendations` (вираз поза deny — щоб regal не лаявся
|
|
28
|
-
# performance/non-loop-expression: інакше `object.get` виконувався б на кожній
|
|
29
|
-
# ітерації по `required_extensions`).
|
|
30
|
-
recommendations_set := {r | some r in object.get(input, "recommendations", [])}
|
|
31
|
-
|
|
32
8
|
deny contains msg if {
|
|
33
|
-
some
|
|
34
|
-
not
|
|
35
|
-
msg := sprintf(
|
|
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 (text.mdc)", [rec])
|
|
36
12
|
}
|