@nitra/cursor 1.8.93 → 1.8.94

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/README.md CHANGED
@@ -16,7 +16,7 @@
16
16
  {
17
17
  "$schema": "https://unpkg.com/@nitra/cursor/schemas/n-cursor.json",
18
18
  "rules": ["npm-module", "text"],
19
- "skills": ["fix"]
19
+ "skills": ["fix", "lint"]
20
20
  }
21
21
  ```
22
22
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.8.93",
3
+ "version": "1.8.94",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -543,7 +543,7 @@ export function kustomizationHasAbieDeploymentNodeSelectorPatch(raw, mode) {
543
543
  * Чи YAML відносно кореня належить до **`${pkgRel}/k8s/**`** поза піддеревами **`ua/`** та **`ru/`** (base-шар abie).
544
544
  * @param {string} relFromRoot відносний шлях від кореня
545
545
  * @param {string} pkgRelFromRoot каталог пакета відносно кореня (без завершального слеша після імені пакета)
546
- * @returns {boolean}
546
+ * @returns {boolean} `true`, якщо шлях належить до base-шару abie
547
547
  */
548
548
  export function isK8sYamlInAbiePackageExcludingUaRuOverlays(relFromRoot, pkgRelFromRoot) {
549
549
  const normRel = relFromRoot.replaceAll('\\', '/')
@@ -560,7 +560,7 @@ export function isK8sYamlInAbiePackageExcludingUaRuOverlays(relFromRoot, pkgRelF
560
560
  * З HTTPRoute-документа рахує **`backendRefs`** до **`auth-run-hl`** / **`filelint-hl`** і порушення **`namespace: dev`**.
561
561
  * @param {unknown} obj корінь YAML
562
562
  * @param {string} rel відносний шлях (повідомлення)
563
- * @returns {{ refCount: number, errors: string[] }}
563
+ * @returns {{ refCount: number, errors: string[] }} кількість посилань і список порушень
564
564
  */
565
565
  function httpRouteDocSharedCrossNsBackendStats(obj, rel) {
566
566
  /** @type {string[]} */
@@ -582,26 +582,22 @@ function httpRouteDocSharedCrossNsBackendStats(obj, rel) {
582
582
  }
583
583
  let refCount = 0
584
584
  for (const rule of rules) {
585
- if (rule === null || typeof rule !== 'object' || Array.isArray(rule)) {
586
- continue
587
- }
588
- const brs = /** @type {Record<string, unknown>} */ (rule).backendRefs
589
- if (!Array.isArray(brs)) {
590
- continue
591
- }
592
- for (const br of brs) {
593
- if (br === null || typeof br !== 'object' || Array.isArray(br)) {
594
- continue
595
- }
596
- const brRec = /** @type {Record<string, unknown>} */ (br)
597
- const name = brRec.name
598
- if (typeof name !== 'string' || !ABIE_SHARED_CROSS_NS_BACKEND_SET.has(name)) {
599
- continue
600
- }
601
- refCount++
602
- const ns = brRec.namespace
603
- if (typeof ns !== 'string' || ns !== 'dev') {
604
- errors.push(`${rel}: HTTPRoute backendRefs до ${name} має містити namespace: dev (abie.mdc)`)
585
+ if (rule !== null && typeof rule === 'object' && !Array.isArray(rule)) {
586
+ const brs = /** @type {Record<string, unknown>} */ (rule).backendRefs
587
+ if (Array.isArray(brs)) {
588
+ for (const br of brs) {
589
+ if (br !== null && typeof br === 'object' && !Array.isArray(br)) {
590
+ const brRec = /** @type {Record<string, unknown>} */ (br)
591
+ const name = brRec.name
592
+ if (typeof name === 'string' && ABIE_SHARED_CROSS_NS_BACKEND_SET.has(name)) {
593
+ refCount++
594
+ const ns = brRec.namespace
595
+ if (typeof ns !== 'string' || ns !== 'dev') {
596
+ errors.push(`${rel}: HTTPRoute backendRefs до ${name} має містити namespace: dev (abie.mdc)`)
597
+ }
598
+ }
599
+ }
600
+ }
605
601
  }
606
602
  }
607
603
  }
@@ -613,7 +609,7 @@ function httpRouteDocSharedCrossNsBackendStats(obj, rel) {
613
609
  * @param {string} root корінь репозиторію
614
610
  * @param {string} pkgAbs абсолютний шлях до каталогу пакета
615
611
  * @param {string[]} yamlFilesAbs усі **yaml** під **k8s** (як **findK8sYamlFiles**)
616
- * @returns {Promise<{ refCount: number, baseErrors: string[] }>}
612
+ * @returns {Promise<{ refCount: number, baseErrors: string[] }>} кількість посилань і базові помилки
617
613
  */
618
614
  export async function analyzeAbieSharedBackendRefsInPackageK8s(root, pkgAbs, yamlFilesAbs) {
619
615
  const pkgRel = relative(root, pkgAbs).replaceAll('\\', '/') || pkgAbs
@@ -622,34 +618,36 @@ export async function analyzeAbieSharedBackendRefsInPackageK8s(root, pkgAbs, yam
622
618
  const baseErrors = []
623
619
  for (const abs of yamlFilesAbs) {
624
620
  const rel = relative(root, abs).replaceAll('\\', '/') || abs
625
- if (!isK8sYamlInAbiePackageExcludingUaRuOverlays(rel, pkgRel)) {
626
- continue
627
- }
628
- let raw
629
- try {
630
- raw = await readFile(abs, 'utf8')
631
- } catch {
632
- continue
633
- }
634
- const body = stripBom(raw)
635
- const lines = body.split(/\r?\n/u)
636
- const first = lines[0] ?? ''
637
- const rest = MODELINE_RE.test(first.trim()) ? lines.slice(1).join('\n') : body
638
- /** @type {import('yaml').Document[]} */
639
- let docs
640
- try {
641
- docs = parseAllDocuments(rest)
642
- } catch {
643
- continue
644
- }
645
- for (const doc of docs) {
646
- if (doc.errors.length > 0) {
647
- continue
621
+ if (isK8sYamlInAbiePackageExcludingUaRuOverlays(rel, pkgRel)) {
622
+ let raw
623
+ try {
624
+ raw = await readFile(abs, 'utf8')
625
+ } catch {
626
+ raw = undefined
627
+ }
628
+ if (raw !== undefined) {
629
+ const body = stripBom(raw)
630
+ const lines = body.split(/\r?\n/u)
631
+ const first = lines[0] ?? ''
632
+ const rest = MODELINE_RE.test(first.trim()) ? lines.slice(1).join('\n') : body
633
+ /** @type {import('yaml').Document[] | undefined} */
634
+ let docs
635
+ try {
636
+ docs = parseAllDocuments(rest)
637
+ } catch {
638
+ docs = undefined
639
+ }
640
+ if (docs !== undefined) {
641
+ for (const doc of docs) {
642
+ if (doc.errors.length === 0) {
643
+ const obj = doc.toJSON()
644
+ const st = httpRouteDocSharedCrossNsBackendStats(obj, rel)
645
+ refCount += st.refCount
646
+ baseErrors.push(...st.errors)
647
+ }
648
+ }
649
+ }
648
650
  }
649
- const obj = doc.toJSON()
650
- const st = httpRouteDocSharedCrossNsBackendStats(obj, rel)
651
- refCount += st.refCount
652
- baseErrors.push(...st.errors)
653
651
  }
654
652
  }
655
653
  return { refCount, baseErrors }
@@ -659,7 +657,7 @@ export async function analyzeAbieSharedBackendRefsInPackageK8s(root, pkgAbs, yam
659
657
  * Рахує операції JSON6902 з **`path`**: **`/spec/rules/…/backendRefs/…/namespace`** та **`value`** overlay.
660
658
  * @param {string} combined сукупний текст patch **HTTPRoute**
661
659
  * @param {'ua' | 'ru'} mode overlay
662
- * @returns {number}
660
+ * @returns {number} кількість знайдених патчів namespace
663
661
  */
664
662
  function countAbieHttpRouteBackendRefNamespacePatchesInCombined(combined, mode) {
665
663
  const re =
@@ -1073,8 +1071,8 @@ async function ensureUaRuAbieHttpRoutePatches(root, yamlFilesAbs, fail, passFn)
1073
1071
  /** @type {Map<string, Promise<{ refCount: number, baseErrors: string[] }>>} */
1074
1072
  const sharedBackendAnalysisByPkg = new Map()
1075
1073
  /**
1076
- * @param {string} pkgAbs
1077
- * @returns {Promise<{ refCount: number, baseErrors: string[] }>}
1074
+ * @param {string} pkgAbs абсолютний шлях до каталогу пакета
1075
+ * @returns {Promise<{ refCount: number, baseErrors: string[] }>} кількість посилань і базові помилки
1078
1076
  */
1079
1077
  const getSharedBackendAnalysis = pkgAbs => {
1080
1078
  let p = sharedBackendAnalysisByPkg.get(pkgAbs)
@@ -1152,7 +1152,6 @@ export function serviceSvcHlYamlHeadlessViolation(manifest) {
1152
1152
  *
1153
1153
  * Застосовується лише для **`apiVersion: networking.gke.io/v1`** і **`targetRef.kind: Service`** (або без **`kind`**).
1154
1154
  * Інші **`targetRef.kind`** скрипт не оцінює.
1155
- *
1156
1155
  * @param {unknown} manifest корінь YAML-документа
1157
1156
  * @returns {string | null} текст порушення або null
1158
1157
  */
@@ -1182,7 +1181,6 @@ export function healthCheckPolicyTargetRefHeadlessServiceViolation(manifest) {
1182
1181
  * Чи об’єкт схожий на **backendRef** до **Kubernetes Service** у Gateway API.
1183
1182
  *
1184
1183
  * Вимагає числовий **`port`**, щоб не плутати з **`HTTPHeaderMatch`** тощо (там теж є **`name`**, але без **`port`**).
1185
- *
1186
1184
  * @param {unknown} obj вузол у дереві **`spec`**
1187
1185
  * @returns {boolean} true, якщо враховуємо поле **`name`** як посилання на Service
1188
1186
  */
@@ -33,7 +33,7 @@ const EMIT_TYPES_CONFIG = 'npm/tsconfig.emit-types.json'
33
33
 
34
34
  /**
35
35
  * Чи є під `npm/src` хоча б один `.js` (рекурсивно).
36
- * @returns {Promise<boolean>}
36
+ * @returns {Promise<boolean>} `true`, якщо знайдено хоча б один `.js`
37
37
  */
38
38
  async function npmSrcTreeHasJsFile() {
39
39
  const root = 'npm/src'
@@ -51,7 +51,7 @@ async function npmSrcTreeHasJsFile() {
51
51
 
52
52
  /**
53
53
  * Знаходить текстовий вміст конфігурації hk для перевірки npm-module.
54
- * @returns {Promise<{ path: string, text: string } | null>}
54
+ * @returns {Promise<{ path: string, text: string } | null>} знайдений файл або `null`
55
55
  */
56
56
  async function readHkConfig() {
57
57
  const candidates = ['hk.pkl', '.config/hk.pkl']
@@ -66,8 +66,8 @@ async function readHkConfig() {
66
66
 
67
67
  /**
68
68
  * Підрядки для hk при layout з каталогом `npm/src` і glob `src` + `.js` у команді (див. npm-module.mdc).
69
- * @param {string} hkText
70
- * @returns {string[]}
69
+ * @param {string} hkText текст конфігурації hk
70
+ * @returns {string[]} відсутні фрагменти
71
71
  */
72
72
  function missingHkSrcLayoutFragments(hkText) {
73
73
  const need = [
@@ -85,8 +85,8 @@ function missingHkSrcLayoutFragments(hkText) {
85
85
 
86
86
  /**
87
87
  * Підрядки для hk при layout з `tsconfig.emit-types.json` (див. npm-module.mdc).
88
- * @param {string} hkText
89
- * @returns {string[]}
88
+ * @param {string} hkText текст конфігурації hk
89
+ * @returns {string[]} відсутні фрагменти
90
90
  */
91
91
  function missingHkEmitTypesConfigFragments(hkText) {
92
92
  const need = ['["pre-commit"]', 'bunx -p typescript tsc', 'tsconfig.emit-types.json']
@@ -95,7 +95,7 @@ function missingHkEmitTypesConfigFragments(hkText) {
95
95
 
96
96
  /**
97
97
  * Перевіряє `npm/tsconfig.emit-types.json` на мінімальний набір опцій для `emitDeclarationOnly` у `types/`.
98
- * @param {unknown} parsed
98
+ * @param {unknown} parsed результат `JSON.parse` конфігурації
99
99
  * @returns {string[]} повідомлення про помилки (порожній — OK)
100
100
  */
101
101
  function emitTypesConfigIssues(parsed) {
@@ -128,8 +128,8 @@ function emitTypesConfigIssues(parsed) {
128
128
 
129
129
  /**
130
130
  * Шлях на дискі до файлу з поля `types` у `npm/package.json` (значення на кшталт `./types/bin/x.d.ts`).
131
- * @param {string} typesField
132
- * @returns {string | null}
131
+ * @param {string} typesField значення поля `types` з `package.json`
132
+ * @returns {string | null} абсолютний шлях або `null`
133
133
  */
134
134
  function npmTypesFileFromPackageField(typesField) {
135
135
  if (typeof typesField !== 'string' || !typesField.startsWith('./types/')) {
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: n-lint
3
+ description: >-
4
+ Запустити кореневий bun run lint, виправити порушення й підтвердити чистий вихід
5
+ ---
6
+
7
+ # n-lint — лінт проєкту через кореневий скрипт
8
+
9
+ ## Мета
10
+
11
+ Один раз узгоджено прогнати весь ланцюжок **`lint`** з кореневого **`package.json`**, усунути помилки (авто- та вручну) і переконатися, що **`bun run lint`** завершується з кодом **`0`**.
12
+
13
+ ## Передумови
14
+
15
+ - Поточна робоча директорія — **корінь репозиторію**, де є **`package.json`** зі скриптом **`lint`**.
16
+ - Залежності встановлені (**`bun i`**) — якщо після правок змінювався **`package.json`** / lockfile, знову виконай **`bun i`** перед наступним запуском лінту.
17
+
18
+ ## Workflow
19
+
20
+ 1. **Запуск** — виконай повний лінт:
21
+
22
+ ```bash
23
+ bun run lint
24
+ ```
25
+
26
+ 2. **Якщо exit code не 0** — проаналізуй вивід (останній упавший крок у ланцюжку **`lint`** часто видно з stderr / логів):
27
+ - Де скрипт уже робить **auto-fix** (**`--fix`**, **`markdownlint-cli2 --fix`**, **`oxfmt`** тощо) — перезапусти **`bun run lint`** після змін файлів.
28
+ - Де auto-fix **немає** (наприклад, **jscpd**, **cspell**, **zizmor**, перевірки без прапорця fix) — виправ код, конфіги або винятки **узгоджено з** `.cursor/rules/` (не розширюй ignore лише щоб приховати проблему без причини).
29
+
30
+ 3. **Цикл** — повторюй кроки 1–2, доки **`bun run lint`** не завершиться успішно. Після суттєвих правок за потреби ще раз **`bun run lint`**, щоб переконатися, що не зламав наступний крок у скрипті **`lint`**.
31
+
32
+ 4. **Верифікація** — фінальна перевірка (обов’язково з кодом **0**):
33
+
34
+ ```bash
35
+ bun run lint
36
+ ```
37
+
38
+ 5. **Результат** — коротко опиши, що саме виправлено; якщо щось блокує нульовий exit code — залиш чітке пояснення й наступні кроки для людини.
39
+
40
+ ## Примітка
41
+
42
+ Цей скіл **не** замінює **`npx @nitra/cursor check`**: **`lint`** перевіряє лінтери/формат у **`package.json`**, а **`check`** — програмні правила пакета **`@nitra/cursor`**. За потреби запускай обидва.
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ export {}