@nitra/cursor 1.13.89 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/package.json +1 -1
- package/rules/abie/abie.mdc +8 -8
- package/rules/abie/js/{applies/check.mjs → applies.mjs} +2 -2
- package/rules/abie/js/{env_dns/check.mjs → env_dns.mjs} +3 -3
- package/rules/abie/js/{firebase_hosting/check.mjs → firebase_hosting.mjs} +1 -1
- package/rules/abie/js/{hc_pairing/check.mjs → hc_pairing.mjs} +4 -4
- package/rules/abie/js/{ua_http_route/check.mjs → ua_http_route.mjs} +6 -6
- package/rules/abie/js/{ua_node_selector/check.mjs → ua_node_selector.mjs} +5 -5
- package/rules/abie/policy/base_deployment_preem/base_deployment_preem.rego +2 -2
- package/rules/abie/policy/health_check_policy/health_check_policy.rego +2 -2
- package/rules/abie/policy/http_route_base/http_route_base.rego +1 -1
- package/rules/abie/utils/enabled.mjs +1 -1
- package/rules/abie/utils/k8s-tree.mjs +1 -1
- package/rules/adr/js/{hooks/check.mjs → hooks.mjs} +1 -1
- package/rules/bun/js/{layout/check.mjs → layout.mjs} +1 -1
- package/rules/capacitor/js/{platforms/check.mjs → platforms.mjs} +1 -1
- package/rules/changelog/changelog.mdc +1 -1
- package/rules/changelog/js/{consistency/check.mjs → consistency.mjs} +2 -2
- package/rules/changelog/{js/consistency → utils}/package-manifest.mjs +1 -1
- package/rules/docker/js/{lint/check.mjs → lint.mjs} +5 -5
- package/rules/docker/lint/lint.mjs +1 -1
- package/rules/docker/{js/lint → utils}/docker-hadolint.mjs +1 -1
- package/rules/feedback/feedback.mdc +1 -1
- package/rules/ga/js/{workflows/check.mjs → workflows.mjs} +5 -5
- package/rules/ga/lint/lint.mjs +1 -1
- package/rules/graphql/js/{tooling/check.mjs → tooling.mjs} +5 -5
- package/rules/hasura/js/{internal_urls/check.mjs → internal_urls.mjs} +4 -4
- package/rules/hasura/policy/svc_hl/svc_hl.rego +1 -1
- package/rules/image-avif/js/{avif_generation/check.mjs → avif_generation.mjs} +5 -5
- package/rules/image-compress/js/{package_setup/check.mjs → package_setup.mjs} +1 -1
- package/rules/js-bun-db/js/{safety/check.mjs → safety.mjs} +5 -5
- package/rules/js-bun-db/{js/safety → utils}/bun-sql-scan.mjs +1 -1
- package/rules/js-bun-redis/js/{imports/check.mjs → imports.mjs} +4 -4
- package/rules/js-bun-redis/policy/package_json/package_json.rego +1 -1
- package/rules/js-lint/js/{tooling/check.mjs → tooling.mjs} +8 -4
- package/rules/js-lint/js-lint.mdc +11 -1
- package/rules/js-lint/{js/tooling → utils}/rebuild-oxlint-canonical.mjs +2 -2
- package/rules/js-mssql/js/{deps/check.mjs → deps.mjs} +5 -5
- package/rules/js-mssql/{js/deps → utils}/mssql-pool-scan.mjs +1 -1
- package/rules/js-run/js/{runtime/check.mjs → runtime.mjs} +10 -10
- package/rules/js-run/{js/runtime → utils}/bunyan-imports.mjs +1 -1
- package/rules/js-run/{js/runtime → utils}/check-env-scan.mjs +1 -1
- package/rules/js-run/{js/runtime → utils}/conn-file-rules.mjs +1 -1
- package/rules/js-run/{js/runtime → utils}/conn-imports-scan.mjs +1 -1
- package/rules/js-run/{js/runtime → utils}/promise-settimeout-scan.mjs +1 -1
- package/rules/k8s/js/{manifests/check.mjs → manifests.mjs} +4 -4
- package/rules/k8s/k8s.mdc +1 -1
- package/rules/nginx-default-tpl/js/{template/check.mjs → template.mjs} +5 -5
- package/rules/npm-module/js/{package_structure/check.mjs → package_structure.mjs} +4 -4
- package/rules/php/js/{tooling/check.mjs → tooling.mjs} +1 -1
- package/rules/rego/js/{applies/check.mjs → applies.mjs} +3 -3
- package/rules/rust/auto.md +1 -0
- package/rules/rust/fix.mjs +19 -0
- package/rules/rust/js/applies.mjs +31 -0
- package/rules/rust/policy/lint_rust_yml/lint_rust_yml.rego +55 -0
- package/rules/rust/policy/lint_rust_yml/target.json +5 -0
- package/rules/rust/policy/lint_rust_yml/template/lint-rust.yml.snippet.yml +44 -0
- package/rules/rust/policy/package_json/package_json.rego +18 -0
- package/rules/rust/policy/package_json/target.json +5 -0
- package/rules/rust/policy/package_json/template/package.json.contains.json +9 -0
- package/rules/rust/policy/vscode_extensions/target.json +5 -0
- package/rules/rust/policy/vscode_extensions/template/extensions.json.snippet.json +1 -0
- package/rules/rust/policy/vscode_extensions/vscode_extensions.rego +15 -0
- package/rules/rust/rust.mdc +27 -0
- package/rules/rust/utils/has-cargo-toml.mjs +39 -0
- package/rules/security/js/{sample_secret/check.mjs → sample_secret.mjs} +2 -2
- package/rules/security/js/{trufflehog/check.mjs → trufflehog.mjs} +3 -3
- package/rules/security/security.mdc +2 -2
- package/rules/style-lint/js/{tooling/check.mjs → tooling.mjs} +1 -1
- package/rules/tauri/js/{tooling/check.mjs → tooling.mjs} +3 -5
- package/rules/tauri/policy/vscode_extensions/vscode_extensions.rego +9 -11
- package/rules/tauri/tauri.mdc +5 -5
- package/rules/test/js/{location/check.mjs → location.mjs} +3 -3
- package/rules/text/js/{formatting/check.mjs → formatting.mjs} +2 -2
- package/rules/vue/js/{packages/check.mjs → packages.mjs} +5 -5
- package/scripts/auto-rules.mjs +12 -3
- package/scripts/sync-claude-config.mjs +1 -1
- package/scripts/utils/discover-checkable-rules.mjs +20 -27
- package/scripts/utils/inline-template-links.mjs +1 -1
- package/scripts/utils/run-rule.mjs +18 -23
- /package/rules/adr/js/{hooks/template → templates/hooks}/.gitignore.snippet +0 -0
- /package/rules/docker/{js/lint → utils}/docker-mirror.mjs +0 -0
- /package/rules/graphql/{js/tooling → utils}/graphql-gql-scan.mjs +0 -0
- /package/rules/js-lint/js/{tooling → data/tooling}/knip-canonical.json +0 -0
- /package/rules/js-lint/js/{tooling → data/tooling}/oxlint-canonical-skeleton.json +0 -0
- /package/rules/js-lint/js/{tooling → data/tooling}/oxlint-canonical.json +0 -0
- /package/rules/js-lint/js/{tooling → data/tooling}/oxlint-rules.tsv +0 -0
- /package/rules/k8s/js/{kubescape_exceptions/template → templates/kubescape_exceptions}/.kubescape-exceptions.json.snippet.json +0 -0
- /package/rules/security/js/{trufflehog/template → templates/trufflehog}/.trufflehog-exclude.snippet.txt +0 -0
- /package/rules/vue/{js/packages → utils}/vue-forbidden-imports.mjs +0 -0
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
import { existsSync, statSync } from 'node:fs'
|
|
19
19
|
import { readFile } from 'node:fs/promises'
|
|
20
20
|
|
|
21
|
-
import { createCheckReporter } from '
|
|
22
|
-
import { runConftestBatch } from '
|
|
21
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
22
|
+
import { runConftestBatch } from '../../../scripts/utils/run-conftest-batch.mjs'
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Чи є префікс `@tauri-apps/` у ключах `dependencies` або `devDependencies`.
|
|
@@ -70,9 +70,7 @@ export async function check() {
|
|
|
70
70
|
|
|
71
71
|
const extPath = '.vscode/extensions.json'
|
|
72
72
|
if (!existsSync(extPath)) {
|
|
73
|
-
fail(
|
|
74
|
-
`${extPath} не існує — створи з recommendations "tauri-apps.tauri-vscode" і "rust-lang.rust-analyzer" (tauri.mdc)`
|
|
75
|
-
)
|
|
73
|
+
fail(`${extPath} не існує — створи з recommendations "tauri-apps.tauri-vscode" (tauri.mdc)`)
|
|
76
74
|
return reporter.getExitCode()
|
|
77
75
|
}
|
|
78
76
|
const violations = runConftestBatch({
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
# Перевірка `.vscode/extensions.json` для tauri (tauri.mdc).
|
|
2
2
|
#
|
|
3
|
-
# Викликається з `rules/tauri/
|
|
4
|
-
# як JS виявив маркер Tauri-проєкту (`src-tauri/` каталог,
|
|
5
|
-
# у будь-якому пакеті, або залежність `@tauri-apps/*`).
|
|
6
|
-
# (не auto-discoverable через `n-cursor fix`) —
|
|
3
|
+
# Викликається з `rules/tauri/js/tooling.mjs` через `runConftestBatch` лише
|
|
4
|
+
# ПІСЛЯ того, як JS виявив маркер Tauri-проєкту (`src-tauri/` каталог,
|
|
5
|
+
# `tauri.conf.json` у будь-якому пакеті, або залежність `@tauri-apps/*`).
|
|
6
|
+
# Без `target.json` поруч (не auto-discoverable через `n-cursor fix`) — це
|
|
7
|
+
# conditional правило.
|
|
7
8
|
#
|
|
8
|
-
# Canonical (tauri.mdc): `recommendations` має містити
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
9
|
+
# Canonical (tauri.mdc): `recommendations` має містити `tauri-apps.tauri-vscode`.
|
|
10
|
+
# `rust-lang.rust-analyzer` і `tamasfe.even-better-toml` — вимагаються правилом
|
|
11
|
+
# `rust` (rust.mdc), бо Tauri-проєкт завжди має `src-tauri/Cargo.toml`.
|
|
13
12
|
package tauri.vscode_extensions
|
|
14
13
|
|
|
15
14
|
import rego.v1
|
|
16
15
|
|
|
17
|
-
required_extensions := {"tauri-apps.tauri-vscode"
|
|
16
|
+
required_extensions := {"tauri-apps.tauri-vscode"}
|
|
18
17
|
|
|
19
18
|
missing_extension_template := ".vscode/extensions.json: recommendations має містити %q (tauri.mdc)"
|
|
20
19
|
|
|
21
|
-
# Множина усіх записів `recommendations` (поза deny — performance/non-loop-expression).
|
|
22
20
|
recommendations_set := {r | some r in object.get(input, "recommendations", [])}
|
|
23
21
|
|
|
24
22
|
deny contains msg if {
|
package/rules/tauri/tauri.mdc
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
description: Tauri
|
|
3
3
|
globs: "**/src-tauri/**,**/tauri.conf.json"
|
|
4
4
|
alwaysApply: false
|
|
5
|
-
version: '1.
|
|
5
|
+
version: '1.2'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
в файлі .vscode/extensions.json є налаштування для Vue:
|
|
8
|
+
У `.vscode/extensions.json` `recommendations` має містити `tauri-apps.tauri-vscode`:
|
|
10
9
|
|
|
11
10
|
```json title=".vscode/extensions.json"
|
|
12
11
|
{
|
|
13
|
-
"recommendations": ["tauri-apps.tauri-vscode"
|
|
14
|
-
"rust-lang.rust-analyzer"]
|
|
12
|
+
"recommendations": ["tauri-apps.tauri-vscode"]
|
|
15
13
|
}
|
|
16
14
|
```
|
|
15
|
+
|
|
16
|
+
Розширені Rust-вимоги (`rust-lang.rust-analyzer`, `tamasfe.even-better-toml`, скрипт `lint-rust`, CI `lint-rust.yml`) — у правилі **`rust`** (`n-rust.mdc`). Tauri-проєкт завжди має `src-tauri/Cargo.toml`, тому `rust` активується автоматично разом з `tauri`.
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { basename, dirname, relative } from 'node:path'
|
|
11
11
|
|
|
12
|
-
import { createCheckReporter } from '
|
|
13
|
-
import { loadCursorIgnorePaths } from '
|
|
14
|
-
import { walkDir } from '
|
|
12
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
13
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
14
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
15
15
|
|
|
16
16
|
const TESTS_DIR_NAME = 'tests'
|
|
17
17
|
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
import { existsSync } from 'node:fs'
|
|
33
33
|
import { readFile } from 'node:fs/promises'
|
|
34
34
|
|
|
35
|
-
import { createCheckReporter } from '
|
|
36
|
-
import { anyRunStepIncludes, parseWorkflowYaml } from '
|
|
35
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
36
|
+
import { anyRunStepIncludes, parseWorkflowYaml } from '../../../scripts/utils/gha-workflow.mjs'
|
|
37
37
|
|
|
38
38
|
/** Заголовок абзацу про апостроф у text.mdc / n-text.mdc. */
|
|
39
39
|
const UK_APOSTROPHE_HEADING = '**Український апостроф:**'
|
|
@@ -25,16 +25,16 @@ import { existsSync } from 'node:fs'
|
|
|
25
25
|
import { readFile } from 'node:fs/promises'
|
|
26
26
|
import { join, relative } from 'node:path'
|
|
27
27
|
|
|
28
|
-
import { createCheckReporter } from '
|
|
28
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
29
29
|
import {
|
|
30
30
|
findForbiddenNodeImportsInVueFile,
|
|
31
31
|
findForbiddenVueImportsInSourceFile,
|
|
32
32
|
isVueImportScanSourceFile,
|
|
33
33
|
shouldSkipFileForVueImportScan
|
|
34
|
-
} from '
|
|
35
|
-
import { loadCursorIgnorePaths } from '
|
|
36
|
-
import { walkDir } from '
|
|
37
|
-
import { getMonorepoPackageRootDirs } from '
|
|
34
|
+
} from '../utils/vue-forbidden-imports.mjs'
|
|
35
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
36
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
37
|
+
import { getMonorepoPackageRootDirs } from '../../../scripts/utils/workspaces.mjs'
|
|
38
38
|
|
|
39
39
|
const ESBUILD_RE = /\besbuild\b/
|
|
40
40
|
|
package/scripts/auto-rules.mjs
CHANGED
|
@@ -16,13 +16,13 @@ import { existsSync } from 'node:fs'
|
|
|
16
16
|
import { readdir, readFile } from 'node:fs/promises'
|
|
17
17
|
import { basename, join, relative } from 'node:path'
|
|
18
18
|
|
|
19
|
-
import { textHasBunSqlImport } from '../rules/js-bun-db/
|
|
19
|
+
import { textHasBunSqlImport } from '../rules/js-bun-db/utils/bun-sql-scan.mjs'
|
|
20
20
|
import {
|
|
21
21
|
isGqlScanSourceFile,
|
|
22
22
|
shouldSkipFileForGqlScan,
|
|
23
23
|
sourceFileHasGqlTaggedTemplate
|
|
24
|
-
} from '../rules/graphql/
|
|
25
|
-
import { contentForVueImportScan } from '../rules/vue/
|
|
24
|
+
} from '../rules/graphql/utils/graphql-gql-scan.mjs'
|
|
25
|
+
import { contentForVueImportScan } from '../rules/vue/utils/vue-forbidden-imports.mjs'
|
|
26
26
|
|
|
27
27
|
/** Порядок автододавання правил відповідно до `rules/<rule>/auto.md`. */
|
|
28
28
|
export const AUTO_RULE_ORDER = Object.freeze([
|
|
@@ -48,6 +48,7 @@ export const AUTO_RULE_ORDER = Object.freeze([
|
|
|
48
48
|
'npm-module',
|
|
49
49
|
'php',
|
|
50
50
|
'rego',
|
|
51
|
+
'rust',
|
|
51
52
|
'security',
|
|
52
53
|
'style-lint',
|
|
53
54
|
'text',
|
|
@@ -291,6 +292,7 @@ function updateDirFacts(dirName, facts) {
|
|
|
291
292
|
* @param {string} relPath шлях відносно кореня
|
|
292
293
|
* @param {{
|
|
293
294
|
* hasCapacitorConfig: boolean,
|
|
295
|
+
* hasCargoToml: boolean,
|
|
294
296
|
* hasDockerfile: boolean,
|
|
295
297
|
* hasJsLikeSource: boolean,
|
|
296
298
|
* hasNginxDefaultTplFile: boolean,
|
|
@@ -304,6 +306,9 @@ function updateFileFacts(fileName, relPath, facts) {
|
|
|
304
306
|
if (fileName === 'capacitor.config.json') {
|
|
305
307
|
facts.hasCapacitorConfig = true
|
|
306
308
|
}
|
|
309
|
+
if (fileName === 'Cargo.toml') {
|
|
310
|
+
facts.hasCargoToml = true
|
|
311
|
+
}
|
|
307
312
|
if (fileName === 'Dockerfile' || fileName.startsWith('Dockerfile.')) {
|
|
308
313
|
facts.hasDockerfile = true
|
|
309
314
|
}
|
|
@@ -407,6 +412,7 @@ async function updateHasuraFactFromFile(absPath, fileName, facts) {
|
|
|
407
412
|
* @param {{
|
|
408
413
|
* hasBunSqlImport: boolean,
|
|
409
414
|
* hasCapacitorConfig: boolean,
|
|
415
|
+
* hasCargoToml: boolean,
|
|
410
416
|
* hasDockerfile: boolean,
|
|
411
417
|
* hasGqlTaggedTemplates: boolean,
|
|
412
418
|
* hasHasuraConfig: boolean,
|
|
@@ -493,6 +499,7 @@ export function isMonorepoPackage(packageJson) {
|
|
|
493
499
|
* @param {string} root абсолютний шлях кореня репозиторію
|
|
494
500
|
* @returns {Promise<{
|
|
495
501
|
* hasCapacitorConfig: boolean,
|
|
502
|
+
* hasCargoToml: boolean,
|
|
496
503
|
* hasDockerfile: boolean,
|
|
497
504
|
* hasGaWorkflowsDir: boolean,
|
|
498
505
|
* hasBunSqlImport: boolean,
|
|
@@ -511,6 +518,7 @@ export async function collectAutoRuleFacts(root) {
|
|
|
511
518
|
const facts = {
|
|
512
519
|
hasBunSqlImport: false,
|
|
513
520
|
hasCapacitorConfig: false,
|
|
521
|
+
hasCargoToml: false,
|
|
514
522
|
hasDockerfile: false,
|
|
515
523
|
hasGaWorkflowsDir: existsSync(join(root, '.github', 'workflows')),
|
|
516
524
|
hasGqlTaggedTemplates: false,
|
|
@@ -656,6 +664,7 @@ export async function detectAutoRules({
|
|
|
656
664
|
{ enabled: npmDirExists, id: 'npm-module' },
|
|
657
665
|
{ enabled: composerJsonExists, id: 'php' },
|
|
658
666
|
{ enabled: facts.hasRegoFile, id: 'rego' },
|
|
667
|
+
{ enabled: facts.hasCargoToml, id: 'rust' },
|
|
659
668
|
{ enabled: facts.hasVueOrCssSource, id: 'style-lint' }
|
|
660
669
|
]
|
|
661
670
|
for (const item of autoRuleChecks) {
|
|
@@ -57,7 +57,7 @@ const ADR_HOOK_SCRIPT_NAME = 'capture-decisions.sh'
|
|
|
57
57
|
const ADR_NORMALIZE_HOOK_SCRIPT_NAME = 'normalize-decisions.sh'
|
|
58
58
|
const TEMPLATE_DIR_NAME = '.claude-template'
|
|
59
59
|
/** Відносний шлях до канонічного фрагмента `.gitignore` для ADR Stop-hook'ів у tarball пакета. */
|
|
60
|
-
export const ADR_GITIGNORE_SNIPPET_REL = 'rules/adr/js/hooks
|
|
60
|
+
export const ADR_GITIGNORE_SNIPPET_REL = 'rules/adr/js/templates/hooks/.gitignore.snippet'
|
|
61
61
|
const GITIGNORE_FILE = '.gitignore'
|
|
62
62
|
const EOL_RE = /\r?\n/u
|
|
63
63
|
|
|
@@ -1,29 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Discovery rules для CLI `
|
|
3
|
-
* - JS concerns: `rules/<id>/js/<concern
|
|
2
|
+
* Discovery rules для CLI `fix`. Шукає правила, для яких є щось «прогонне»:
|
|
3
|
+
* - JS concerns: `rules/<id>/js/<concern>.mjs` — один файл = один concern.
|
|
4
4
|
* - Policy concerns: `rules/<id>/policy/<concern>/target.json` — пара з `<concern>.rego`.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* Файли `*.test.mjs` фільтруються regex (`^check(?:-.+)?\.mjs$`).
|
|
6
|
+
* Файли з префіксом `_` (зокрема каталог `_lib/`) і `*.test.mjs` пропускаються — це хелпери й тести.
|
|
8
7
|
*
|
|
9
8
|
* Намеренно НЕ парсимо `target.json` тут (це робить runner). Discovery — швидкий скан структури:
|
|
10
9
|
* шляхи + назви, без I/O вмісту.
|
|
11
10
|
*
|
|
12
|
-
* Історичний контекст: convention пройшла еволюцію
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* Історичний контекст: convention пройшла еволюцію
|
|
12
|
+
* `js/<concern>/check.mjs` (1.13.80–1.13.89)
|
|
13
|
+
* → `js/<concern>.mjs` (1.13.90+, flat: концерн = файл, не каталог)
|
|
14
|
+
* Helpers, tests, templates і data винесені в окремі топ-level папки правила (`js/_lib/`,
|
|
15
|
+
* `tests/`, `templates/`, `data/`).
|
|
15
16
|
*/
|
|
16
17
|
import { existsSync } from 'node:fs'
|
|
17
18
|
import { readdir } from 'node:fs/promises'
|
|
18
19
|
import { join } from 'node:path'
|
|
19
20
|
|
|
20
|
-
const CHECK_FILENAME_RE = /^check(?:-.+)?\.mjs$/u
|
|
21
|
-
const TEST_SUFFIX = '.test.mjs'
|
|
22
|
-
|
|
23
21
|
/**
|
|
24
22
|
* @typedef {object} JsConcern
|
|
25
|
-
* @property {string} name імʼя концерну (
|
|
26
|
-
* @property {string[]} files імена `check*.mjs` у концерні (відсортовані алфавітно)
|
|
23
|
+
* @property {string} name імʼя концерну (= basename файла `js/<name>.mjs` без розширення)
|
|
27
24
|
*/
|
|
28
25
|
|
|
29
26
|
/**
|
|
@@ -39,30 +36,26 @@ const TEST_SUFFIX = '.test.mjs'
|
|
|
39
36
|
*/
|
|
40
37
|
|
|
41
38
|
/**
|
|
42
|
-
* Перелічує JS-концерни одного правила:
|
|
39
|
+
* Перелічує JS-концерни одного правила: файли `js/<name>.mjs` (один файл — один concern).
|
|
43
40
|
*
|
|
44
|
-
*
|
|
41
|
+
* Файли з префіксом `_` (наприклад каталог `_lib/`) і `*.test.mjs` пропускаються.
|
|
45
42
|
* @param {string} jsDir абсолютний шлях `rules/<id>/js/`
|
|
46
43
|
* @returns {Promise<JsConcern[]>} концерни в алфавітному порядку
|
|
47
44
|
*/
|
|
48
45
|
async function listJsConcerns(jsDir) {
|
|
49
46
|
if (!existsSync(jsDir)) return []
|
|
50
|
-
const
|
|
51
|
-
|
|
47
|
+
const entries = await readdir(jsDir, { withFileTypes: true })
|
|
52
48
|
/** @type {JsConcern[]} */
|
|
53
49
|
const concerns = []
|
|
54
|
-
for (const entry of
|
|
55
|
-
if (!entry.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
concerns.push({ name: entry.name, files })
|
|
63
|
-
}
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
if (!entry.isFile()) continue
|
|
52
|
+
if (!entry.name.endsWith('.mjs')) continue
|
|
53
|
+
if (entry.name.endsWith('.test.mjs')) continue
|
|
54
|
+
if (entry.name.startsWith('_')) continue
|
|
55
|
+
if (entry.name.startsWith('.')) continue
|
|
56
|
+
const name = entry.name.slice(0, -'.mjs'.length)
|
|
57
|
+
concerns.push({ name })
|
|
64
58
|
}
|
|
65
|
-
|
|
66
59
|
return concerns.toSorted((a, b) => a.name.localeCompare(b.name))
|
|
67
60
|
}
|
|
68
61
|
|
|
@@ -3,7 +3,7 @@ import { readFile } from 'node:fs/promises'
|
|
|
3
3
|
import { basename, extname, join } from 'node:path'
|
|
4
4
|
|
|
5
5
|
const MD_LINK_RE = /\[([^\]]{1,200})\]\((\.\/[^)]{1,500})\)/g
|
|
6
|
-
const TEMPLATE_SEGMENT_RE = /\/
|
|
6
|
+
const TEMPLATE_SEGMENT_RE = /\/templates?\//
|
|
7
7
|
/** Статичні regexp-літерали `^(.+)\.<slot>\.<ext>$` — без `RegExp(variable)`. */
|
|
8
8
|
const SLOT_SUFFIX_RES = [/^(.+)\.snippet\.[^.]+$/, /^(.+)\.deny\.[^.]+$/, /^(.+)\.contains\.[^.]+$/]
|
|
9
9
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Оркестратор одного правила під CLI `
|
|
2
|
+
* Оркестратор одного правила під CLI `fix`.
|
|
3
3
|
*
|
|
4
4
|
* Послідовність (concerns у межах правила — алфавітно):
|
|
5
|
-
* 1. **applies-гейт** з `js/applies
|
|
5
|
+
* 1. **applies-гейт** з `js/applies.mjs`. Якщо модуль експортує `applies()` і вона повертає
|
|
6
6
|
* false — друкуємо `✅ правило не застосовне` і завершуємо без подальших викликів.
|
|
7
|
-
* 2. **JS-концерни** — кожен
|
|
7
|
+
* 2. **JS-концерни** — кожен файл `js/<concern>.mjs`. Concern `applies` теж може мати
|
|
8
8
|
* `check()` для друку контексту (його `applies()` уже відпрацював на кроці 1, він не повторюється).
|
|
9
9
|
* 3. **Policy-концерни** — кожен `policy/<concern>/target.json` через `runConftestBatch`.
|
|
10
10
|
* Резолвер `resolveTargetFiles` ділить cache (`walkCache`) між концернами.
|
|
@@ -24,32 +24,29 @@ import { resolveConcernTemplateData } from './template.mjs'
|
|
|
24
24
|
const APPLIES_CONCERN_NAME = 'applies'
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Обчислює абсолютний шлях до
|
|
28
|
-
*
|
|
29
|
-
* (1.11.10–1.13.79) — щоб не плутати з кореневим `fix.mjs` entry-point'ом.
|
|
27
|
+
* Обчислює абсолютний шлях до файла-концерну: `rules/<id>/js/<concern>.mjs`.
|
|
28
|
+
* Flat-convention з 1.14.0 — концерн = файл, не каталог.
|
|
30
29
|
* @param {string} bundledRulesDir абсолютний `rules/`
|
|
31
30
|
* @param {string} ruleId id правила
|
|
32
31
|
* @param {import('./discover-checkable-rules.mjs').JsConcern} concern опис концерну
|
|
33
|
-
* @param {string} fileName імʼя файла з `concern.files`
|
|
34
32
|
* @returns {string} абсолютний шлях
|
|
35
33
|
*/
|
|
36
|
-
function resolveJsCheckPath(bundledRulesDir, ruleId, concern
|
|
37
|
-
return join(bundledRulesDir, ruleId, 'js', concern.name
|
|
34
|
+
function resolveJsCheckPath(bundledRulesDir, ruleId, concern) {
|
|
35
|
+
return join(bundledRulesDir, ruleId, 'js', `${concern.name}.mjs`)
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
/**
|
|
41
|
-
* Спробувати викликати applies() гейт з `js/applies
|
|
42
|
-
* Гейт активний лише за наявності концерну з імʼям `applies` і експортом-функцією `applies
|
|
43
|
-
* першому check-файлі (алфавіт).
|
|
39
|
+
* Спробувати викликати applies() гейт з `js/applies.mjs` правила.
|
|
40
|
+
* Гейт активний лише за наявності концерну з імʼям `applies` і експортом-функцією `applies`.
|
|
44
41
|
* @param {string} bundledRulesDir абсолютний `rules/`
|
|
45
42
|
* @param {import('./discover-checkable-rules.mjs').CheckableRule} rule опис правила
|
|
46
43
|
* @returns {Promise<boolean>} `true` — правило застосовне (або гейту немає); `false` — пропустити
|
|
47
44
|
*/
|
|
48
45
|
async function evaluateAppliesGate(bundledRulesDir, rule) {
|
|
49
46
|
const concern = rule.jsConcerns.find(c => c.name === APPLIES_CONCERN_NAME)
|
|
50
|
-
if (!concern
|
|
51
|
-
const path = resolveJsCheckPath(bundledRulesDir, rule.id, concern
|
|
52
|
-
// eslint-disable-next-line no-unsanitized/method -- path
|
|
47
|
+
if (!concern) return true
|
|
48
|
+
const path = resolveJsCheckPath(bundledRulesDir, rule.id, concern)
|
|
49
|
+
// eslint-disable-next-line no-unsanitized/method -- path з discovered concern, файл з whitelist'у readdir
|
|
53
50
|
const mod = await import(path)
|
|
54
51
|
if (typeof mod.applies !== 'function') return true
|
|
55
52
|
return Boolean(await mod.applies())
|
|
@@ -116,14 +113,12 @@ export async function runRule(rule, bundledRulesDir, walkCache) {
|
|
|
116
113
|
let totalCode = 0
|
|
117
114
|
|
|
118
115
|
for (const concern of rule.jsConcerns) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (code !== 0) totalCode = 1
|
|
126
|
-
}
|
|
116
|
+
const path = resolveJsCheckPath(bundledRulesDir, rule.id, concern)
|
|
117
|
+
// eslint-disable-next-line no-unsanitized/method -- path з discovered concern, файл з whitelist'у readdir
|
|
118
|
+
const mod = await import(path)
|
|
119
|
+
if (typeof mod.check === 'function') {
|
|
120
|
+
const code = await mod.check()
|
|
121
|
+
if (code !== 0) totalCode = 1
|
|
127
122
|
}
|
|
128
123
|
}
|
|
129
124
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|