@nitra/cursor 1.4.1 → 1.5.1

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
@@ -14,7 +14,7 @@
14
14
 
15
15
  ```json
16
16
  {
17
- "rules": ["js-format", "npm-module", "spell"]
17
+ "rules": ["js-format", "npm-module", "text"]
18
18
  }
19
19
  ```
20
20
 
@@ -24,14 +24,14 @@
24
24
  | ------------ | ------------------------------------------------- |
25
25
  | `js-format` | Правила форматування JavaScript ecosystem (oxfmt) |
26
26
  | `npm-module` | Структура репозиторію для npm-модуля (bun mono) |
27
- | `spell` | Перевірка правопису через cspell |
27
+ | `text` | Текстові файли: cspell, CI |
28
28
 
29
29
  Щоб завантажити правила конкретної версії пакету, додайте поле `version`:
30
30
 
31
31
  ```json
32
32
  {
33
33
  "version": "2.5.0",
34
- "rules": ["js-format", "spell"]
34
+ "rules": ["js-format", "text"]
35
35
  }
36
36
  ```
37
37
 
@@ -56,7 +56,7 @@ CLI автоматично:
56
56
  📋 Правил до завантаження: 3
57
57
  ⬇ js-format → .cursor/rules/n-js-format.mdc ... ✅
58
58
  ⬇ npm-module → .cursor/rules/n-npm-module.mdc ... ✅
59
- spell → .cursor/rules/n-spell.mdc ... ✅
59
+ text → .cursor/rules/n-text.mdc ... ✅
60
60
  📝 Оновлено AGENTS.md з AGENTS.template.md
61
61
 
62
62
  ✨ Готово: 3 завантажено, 0 з помилками
@@ -70,7 +70,7 @@ npm/
70
70
  ├── mdc/ # cursor-правила
71
71
  │ ├── js-format.mdc
72
72
  │ ├── npm-module.mdc
73
- │ └── spell.mdc
73
+ │ └── text.mdc
74
74
  └── bin/
75
75
  └── n-cursor.js # CLI-скрипт
76
76
  ```
@@ -96,7 +96,7 @@ npm/
96
96
  {{/services}}
97
97
  ```
98
98
 
99
- Під час запуску CLI тіло між `{{#services}}` і `{{/services}}` повторюється для кожного `*.mdc` у `.cursor/rules/`; у `{{name}}` підставляється вже готовий markdown-рядок (наприклад `- .cursor/rules/n-spell.mdc`).
99
+ Під час запуску CLI тіло між `{{#services}}` і `{{/services}}` повторюється для кожного `*.mdc` у `.cursor/rules/`; у `{{name}}` підставляється вже готовий markdown-рядок (наприклад `- .cursor/rules/n-text.mdc`).
100
100
 
101
101
  3. Після змін у шаблоні перевірте локально: у тестовому репозиторії з `.n-cursor.json` виконайте `npx`/`bunx` на зібраному пакеті або `node npm/bin/n-cursor.js` з кореня того репозиторію і переконайтеся, що **`AGENTS.md`** виглядає як очікується.
102
102
 
package/bin/n-cursor.js CHANGED
@@ -107,20 +107,19 @@ async function migrateLegacyManagedRuleFilenames(rulesDir) {
107
107
  }
108
108
  const names = await readdir(rulesDir)
109
109
  for (const name of names) {
110
- if (!name.endsWith('.mdc') || !name.startsWith('nitra-')) {
111
- continue
112
- }
113
- const rest = name.slice('nitra-'.length)
114
- const newName = `${RULE_PREFIX}${rest}`
115
- const from = join(rulesDir, name)
116
- const to = join(rulesDir, newName)
117
- if (existsSync(to)) {
118
- await unlink(from)
119
- console.log(`📝 Видалено застарілий ${RULES_DIR}/${name} (вже є ${newName})\n`)
120
- continue
110
+ if (name.endsWith('.mdc') && name.startsWith('nitra-')) {
111
+ const rest = name.slice('nitra-'.length)
112
+ const newName = `${RULE_PREFIX}${rest}`
113
+ const from = join(rulesDir, name)
114
+ const to = join(rulesDir, newName)
115
+ if (existsSync(to)) {
116
+ await unlink(from)
117
+ console.log(`📝 Видалено застарілий ${RULES_DIR}/${name} (вже є ${newName})\n`)
118
+ } else {
119
+ await rename(from, to)
120
+ console.log(`📝 Перейменовано ${RULES_DIR}/${name} → ${RULES_DIR}/${newName}\n`)
121
+ }
121
122
  }
122
- await rename(from, to)
123
- console.log(`📝 Перейменовано ${RULES_DIR}/${name} → ${RULES_DIR}/${newName}\n`)
124
123
  }
125
124
  }
126
125
 
@@ -168,7 +167,7 @@ async function readConfig() {
168
167
  throw new Error(`Невірний JSON у файлі ${CONFIG_FILE}`)
169
168
  }
170
169
  if (!Array.isArray(config.rules) || config.rules.length === 0) {
171
- throw new Error(`У ${CONFIG_FILE} має бути непоророжній масив "rules"`)
170
+ throw new Error(`У ${CONFIG_FILE} має бути непорожній масив "rules"`)
172
171
  }
173
172
  if (!Array.isArray(config.skills)) {
174
173
  if ('skills' in config) {
@@ -204,7 +203,7 @@ function normalizeRuleName(ruleName) {
204
203
  }
205
204
 
206
205
  /**
207
- * Нормалізує id skill з конфігу до форми без префікса n- (як «fix-cursor»)
206
+ * Нормалізує id skill з конфігу до форми без префікса n- (як «fix»)
208
207
  * @param {string} skillName елемент масиву skills або ім'я каталогу
209
208
  * @returns {string} id без префікса n-
210
209
  */
@@ -216,13 +215,28 @@ function normalizeSkillId(skillName) {
216
215
  return s
217
216
  }
218
217
 
218
+ /** Legacy id у `.n-cursor.json` → поточний bundled id (каталог `n-<id>` у пакеті) */
219
+ const LEGACY_SKILL_ID_MAP = {
220
+ 'fix-cursor': 'fix'
221
+ }
222
+
223
+ /**
224
+ * Поточний id skill для шляхів у пакеті та `.cursor/skills`
225
+ * @param {string} skillName елемент масиву skills або ім'я каталогу
226
+ * @returns {string} canonical id без префікса n-
227
+ */
228
+ function canonicalSkillId(skillName) {
229
+ const id = normalizeSkillId(skillName)
230
+ return LEGACY_SKILL_ID_MAP[id] ?? id
231
+ }
232
+
219
233
  /**
220
234
  * Ім'я керованого каталогу skill у .cursor/skills (префікс n-)
221
235
  * @param {string} skillId id без префікса
222
- * @returns {string} наприклад n-fix-cursor
236
+ * @returns {string} наприклад n-fix
223
237
  */
224
238
  function managedSkillDirName(skillId) {
225
- return `${RULE_PREFIX}${normalizeSkillId(skillId)}`
239
+ return `${RULE_PREFIX}${canonicalSkillId(skillId)}`
226
240
  }
227
241
 
228
242
  /**
@@ -429,12 +443,13 @@ async function syncSkills(configSkills) {
429
443
  let fail = 0
430
444
 
431
445
  for (const skillId of configSkills) {
446
+ const id = canonicalSkillId(skillId)
432
447
  const dirName = managedSkillDirName(skillId)
433
448
  const srcDir = join(BUNDLED_SKILLS_DIR, dirName)
434
449
  const destDir = join(skillsRoot, dirName)
435
450
 
436
451
  if (existsSync(srcDir)) {
437
- process.stdout.write(` ⬇ ${skillId} → ${SKILLS_DIR}/${dirName} ... `)
452
+ process.stdout.write(` ⬇ ${id} → ${SKILLS_DIR}/${dirName} ... `)
438
453
  try {
439
454
  await mkdir(destDir, { recursive: true })
440
455
  const files = await readdir(srcDir)
@@ -450,7 +465,7 @@ async function syncSkills(configSkills) {
450
465
  fail++
451
466
  }
452
467
  } else {
453
- process.stdout.write(` ⬇ ${skillId} → ${SKILLS_DIR}/${dirName} ... `)
468
+ process.stdout.write(` ⬇ ${id} → ${SKILLS_DIR}/${dirName} ... `)
454
469
  console.log(`❌`)
455
470
  console.error(` Немає каталогу в пакеті: ${dirName}`)
456
471
  fail++
package/mdc/bun.mdc CHANGED
@@ -12,9 +12,11 @@ version: '1.1'
12
12
  - Якщо новий виклик CLI додається з нуля і в цьому репозиторії прийнято лише Bun — можна `bunx <tool>`.
13
13
 
14
14
  Заборонено використовувати як менеджер пакетів / lockfile:
15
+
15
16
  - `npm install`, `yarn`, `pnpm` (і відповідні lockfile, крім `bun.lock`)
16
17
 
17
18
  Дозволені команди:
19
+
18
20
  - `bun i`
19
21
  - `bun run <script>`
20
22
  - `bun add <pkg>`
@@ -23,7 +25,6 @@ version: '1.1'
23
25
  - `bunx <tool>`
24
26
  - `npx <tool>`
25
27
 
26
-
27
28
  - Для встановлення залежностей використовуй `bun i`.
28
29
  - Для запуску скриптів використовуй `bun run <script>`.
29
30
  - Для додавання залежностей:
@@ -32,6 +33,7 @@ version: '1.1'
32
33
  - Для одноразових CLI-команд використовуй `bunx <tool>`.
33
34
 
34
35
  Заборонено використовувати:
36
+
35
37
  - `npm`
36
38
  - `yarn`
37
39
  - `pnpm`
@@ -41,20 +43,24 @@ Lockfile у репозиторії: `bun.lock`.
41
43
  Видалити якщо вони є. Видалити .yarn та .yarnrc.yml якщо вони є.
42
44
 
43
45
  Для Bun monorepo:
46
+
44
47
  - Встановлювати залежності у відповідному пакеті, а не в корені без потреби.
45
48
  - Якщо залежність потрібна лише одному пакету, додавати її в директорії цього пакета.
46
49
  - У CI та локально запускати скрипти через `bun run`.
47
50
 
48
- Якщо в package.json є поля `packageManager`, то прибрати їх, також прибрати всі директорії та файлидля yarn
51
+ Якщо в package.json є поля `packageManager`, то прибрати їх, також прибрати всі директорії та файли для yarn
49
52
 
50
53
  Якщо в проекті використовується npx, то не заміняти його на bunx, а використовувати npx.
51
54
  Коли зміна відбувається в Dockerfile, то використовувати
55
+
52
56
  ```dockerfile
53
57
  FROM oven/bun:alpine AS build-env
54
58
  ```
59
+
55
60
  замість образу node
56
61
 
57
62
  В Github actions bun повинен налаштований так:
63
+
58
64
  ```yaml
59
65
  - uses: oven-sh/setup-bun@v2
60
66
 
package/mdc/js-pino.mdc CHANGED
@@ -14,4 +14,4 @@ Configmap повинен бути з тією самою назвою, що і d
14
14
 
15
15
  ## Перевірка
16
16
 
17
- `npx @nitra/cursor check js-pino`
17
+ `npx @nitra/cursor check js-pino`
@@ -8,7 +8,7 @@ version: '1.1'
8
8
 
9
9
  - **Джерело правил:** перед тим як писати або суттєво змінювати **`.css`**, **`.scss`** або стилі в **`.vue`**, переглянь у корені проєкту (і в релевантних пакетах монорепо, якщо є) поле **`stylelint`** у **`package.json`** (зокрема `extends`), наявні **`.stylelintrc.*`**, **`stylelint.config.*`** та **`.stylelintignore`**. Не покладайся на «типові» правила stylelint з пам’яті — дотримуйся **проєктного** **`@nitra/stylelint-config`** і будь-яких локальних доповнень у репозиторії.
10
10
  - **Форматування** узгоджуй з **`n-js-format.mdc`** (oxfmt / `.oxfmtrc.json` для css, scss тощо), щоб форматер і stylelint не суперечили один одному.
11
- - **Після змін:** запускай **`bun run lint-style`** (або `bunx stylelint` з тими ж glob-ами та прапорцями, що в скрипті та CI) і виправляй усе, що лишилось після auto-fix. Якщо в репозиторії є **`n-lint`** / навичка n-lint — можна пройтись повним набором `lint-*` з `package.json`.
11
+ - **Після змін:** запускай **`bun run lint-style`** (або `bunx stylelint` з тими ж glob-ами та прапорцями, що в скрипті та CI) і виправляй усе, що лишилось після auto-fix. За потреби пройдись повним набором `lint-*` з `package.json` (див. навичку **`n-fix`**).
12
12
  - **Не розширюй винятки:** не додавай зайві **`stylelint-disable`** / вузькі придушення правил без потреби; краще змінити стилі під правила проєкту.
13
13
 
14
14
  В файлі .vscode/extensions.json є налаштування для офіційного плагіну:
package/mdc/text.mdc ADDED
@@ -0,0 +1,218 @@
1
+ ---
2
+ description: Обробка та перевірка текстових файлів (cspell, markdownlint-cli2, v8r, CI)
3
+ alwaysApply: true
4
+ version: '1.10'
5
+ ---
6
+
7
+ Правило описує роботу з **текстовими файлами** в репозиторії: перевірка правопису через **cspell**, стиль **Markdown** через **markdownlint-cli2**, валідація **JSON/YAML/TOML** через **[v8r](https://chris48s.github.io/v8r/)** ([Schema Store](https://www.schemastore.org/)), розширення **DavidAnson.vscode-markdownlint** у Cursor/VS Code та інтеграція в CI.
8
+
9
+ ## Розширення Cursor / VS Code
10
+
11
+ У файлі `.vscode/extensions.json` **додай** `DavidAnson.vscode-markdownlint` у масив `recommendations` (разом із записами з інших правил, зокрема js-lint / js-format):
12
+
13
+ ```json title=".vscode/extensions.json"
14
+ {
15
+ "recommendations": [
16
+ "dbaeumer.vscode-eslint",
17
+ "github.vscode-github-actions",
18
+ "oxc.oxc-vscode",
19
+ "DavidAnson.vscode-markdownlint"
20
+ ]
21
+ }
22
+ ```
23
+
24
+ ## Скрипти та залежності в package.json
25
+
26
+ У кореневому `package.json` один скрипт **lint-text** має послідовно викликати **cspell**, **markdownlint-cli2** і **v8r** (і решту блоків з розділів нижче в одному файлі):
27
+
28
+ ```json title="package.json"
29
+ "scripts": {
30
+ "lint-text": "npx cspell . && bunx markdownlint-cli2 --fix \"**/*.md\" \"**/*.mdc\" && (bunx v8r \"**/*.json\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.yml\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.yaml\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.toml\" || [ $? -eq 98 ])"
31
+ },
32
+ "devDependencies": {
33
+ "markdownlint-cli2": "^0.22.0"
34
+ }
35
+ ```
36
+
37
+ **markdownlint-cli2** і **v8r** у скрипті викликай через `bunx`. Окремо не додавай пакет `markdownlint`, якщо достатньо `markdownlint-cli2`. Маски `**/*.md` і `**/*.mdc` охоплюють Markdown і правила Cursor (`.mdc`); виключення з `.gitignore` для markdownlint задаються в `.markdownlint-cli2.jsonc` (`gitignore: true`). За потреби можна додати окремий скрипт `lint-md` лише для markdownlint — CI все одно має викликати повний `bun run lint-text`.
38
+
39
+ ## v8r
40
+
41
+ [v8r](https://chris48s.github.io/v8r/) — CLI-валідатор: за іменем файлу знаходить схему в [Schema Store](https://www.schemastore.org/) і перевіряє вміст. У `lint-text` — чотири послідовні виклики з масками `**/*.json`, `**/*.yml`, `**/*.yaml`, `**/*.toml`, кожен у вигляді `(bunx v8r "<glob>" || [ $? -eq 98 ])`.
42
+
43
+ **Код 98:** якщо для glob **немає жодного файлу**, v8r дає **98**. Це стосується не лише TOML: репозиторій без `.yml`/`.yaml` зламає **один** спільний виклик `v8r` уже на `**/*.yml`. Окремі виклики з дозволом лише **98** покривають і такі репозиторії.
44
+
45
+ За замовчуванням v8r враховує **`.gitignore`** і **`.v8rignore`**. Якщо для файлу немає схеми в каталозі, запуск завершиться з помилкою — додай такі шляхи в **`.v8rignore`**.
46
+
47
+ ## Конфігурація markdownlint-cli2
48
+
49
+ У корені проєкту має бути **`.markdownlint-cli2.jsonc`** (документація: [DavidAnson/markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2)):
50
+
51
+ ```json title=".markdownlint-cli2.jsonc"
52
+ {
53
+ "gitignore": true,
54
+ "config": {
55
+ "default": true,
56
+ "MD013": false,
57
+ "MD029": false,
58
+ "MD040": false,
59
+ "MD041": false
60
+ }
61
+ }
62
+ ```
63
+
64
+ `gitignore: true` змушує markdownlint-cli2 пропускати шляхи з `.gitignore` (у тому числі `node_modules`, якщо воно там є). Додатковий glob `"#node_modules"` у скрипті не потрібен. За потреби додай власні шляхи через `ignores` у цьому ж файлі.
65
+
66
+ За потреби увімкни окремі правила (наприклад `MD013` з `line_length: 120`), щоб узгодити довжину рядків з `.oxfmtrc.json`.
67
+
68
+ `MD041` вимкнено навмисно: файли `.mdc` (Cursor rules) мають YAML frontmatter, після якого перший абзац часто не є заголовком H1.
69
+
70
+ ## Cspell
71
+
72
+ У корені проєкту має бути `.cspell.json` і залежності для cspell у кореневому `package.json` (зазвичай `devDependencies`).
73
+
74
+ Додай workflow `.github/workflows/lint-text.yml`:
75
+
76
+ ```yaml
77
+ name: Lint Text
78
+
79
+ on:
80
+ push:
81
+ branches:
82
+ - dev
83
+ paths:
84
+ - '.cspell.json'
85
+ - '.gitignore'
86
+ - '.markdownlint-cli2.jsonc'
87
+ - '.v8rignore'
88
+ - '**/*.js'
89
+ - '**/*.ts'
90
+ - '**/*.vue'
91
+ - '**/*.html'
92
+ - '**/*.css'
93
+ - '**/*.scss'
94
+ - '**/*.less'
95
+ - '**/*.json'
96
+ - '**/*.jsonc'
97
+ - '**/*.yaml'
98
+ - '**/*.yml'
99
+ - '**/*.toml'
100
+ - '**/*.xml'
101
+ - '**/*.md'
102
+ - '**/*.mdc'
103
+ - '**/*.mdс'
104
+ - '**/*.txt'
105
+ - '**/*.go'
106
+ - '**/*.py'
107
+ - '**/*.php'
108
+
109
+ pull_request:
110
+ branches:
111
+ - dev
112
+
113
+ concurrency:
114
+ group: ${{ github.ref }}-${{ github.workflow }}
115
+ cancel-in-progress: true
116
+
117
+ jobs:
118
+ text:
119
+ runs-on: ubuntu-latest
120
+ steps:
121
+ - uses: actions/checkout@v4
122
+
123
+ - uses: oven-sh/setup-bun@v2
124
+
125
+ - name: Cache Bun dependencies
126
+ uses: actions/cache@v4
127
+ with:
128
+ path: |
129
+ ~/.bun/install/cache
130
+ node_modules
131
+ key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
132
+ restore-keys: |
133
+ ${{ runner.os }}-bun-
134
+
135
+ - name: Install dependencies
136
+ run: bun install --frozen-lockfile
137
+
138
+ - name: Lint text
139
+ run: bun run lint-text
140
+ ```
141
+
142
+ **Без дублювання CI:** якщо в `.github/workflows` уже є workflow з тими самими кроками `cspell` або `markdownlint-cli2`, видали зайвий — перевірки тексту та Markdown мають виконуватися в одному місці.
143
+
144
+ ## Базовий варіант cspell (без окремого словника української)
145
+
146
+ Якщо текст переважно англійською та достатньо корпоративного словника (@nitra/cspell-dict; у полі `language` cspell лишається тег `nitra`):
147
+
148
+ ```json title=".cspell.json"
149
+ {
150
+ "version": "0.2",
151
+ "language": "nitra",
152
+ "ignorePaths": ["**/node_modules/**", "**/vscode-extension/**", "**/.git/**", ".vscode", "report"],
153
+ "import": ["@nitra/cspell-dict/cspell-ext.json"],
154
+ "words": []
155
+ }
156
+ ```
157
+
158
+ ```json title="package.json"
159
+ {
160
+ "scripts": {
161
+ "lint-text": "npx cspell . && bunx markdownlint-cli2 --fix \"**/*.md\" \"**/*.mdc\" && (bunx v8r \"**/*.json\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.yml\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.yaml\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.toml\" || [ $? -eq 98 ])"
162
+ },
163
+ "devDependencies": {
164
+ "@nitra/cspell-dict": "^1.0.185",
165
+ "markdownlint-cli2": "^0.22.0"
166
+ }
167
+ }
168
+ ```
169
+
170
+ ## Проєкт з українською мовою
171
+
172
+ Якщо в репозиторії є українська документація, коментарі або рядки в коді — потрібен **окремий словник** `@cspell/dict-uk-ua`, інакше cspell не перевірятиме український правопис коректно.
173
+
174
+ **1. Залежності** — додай пакет словника поруч із `@nitra/cspell-dict`:
175
+
176
+ ```json title="package.json"
177
+ {
178
+ "scripts": {
179
+ "lint-text": "npx cspell . && bunx markdownlint-cli2 --fix \"**/*.md\" \"**/*.mdc\" && (bunx v8r \"**/*.json\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.yml\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.yaml\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.toml\" || [ $? -eq 98 ])"
180
+ },
181
+ "devDependencies": {
182
+ "@nitra/cspell-dict": "^1.0.185",
183
+ "@cspell/dict-uk-ua": "^4.0.6",
184
+ "markdownlint-cli2": "^0.22.0"
185
+ }
186
+ }
187
+ ```
188
+
189
+ Встановлення: `bun add -d @cspell/dict-uk-ua` (або `npm i -D @cspell/dict-uk-ua`).
190
+
191
+ **2. `.cspell.json`** — у полі `language` має бути `uk` (разом з іншими мовами через кому), у `import` — підключення розширення українського словника:
192
+
193
+ ```json title=".cspell.json"
194
+ {
195
+ "version": "0.2",
196
+ "language": "en,uk,nitra",
197
+ "ignorePaths": ["**/node_modules/**", "**/vscode-extension/**", "**/.git/**", ".vscode", "report"],
198
+ "import": [
199
+ "@nitra/cspell-dict/cspell-ext.json",
200
+ "@cspell/dict-uk-ua/cspell-ext.json"
201
+ ],
202
+ "words": []
203
+ }
204
+ ```
205
+
206
+ Підлаштуй `language` під проєкт (наприклад додай `ru-ru`, якщо потрібна перевірка російською). Порядок у `import` може впливати на пріоритет словників — тримай корпоративний `@nitra/cspell-dict` там, де зручно для ваших правил.
207
+
208
+ ## Локальні виключення
209
+
210
+ У секції `words` у `.cspell.json` додають власні терміни, імена та скорочення, яких немає в словниках.
211
+
212
+ ## Інші мови
213
+
214
+ Для іншої мови встанови відповідний пакет `@cspell/dict-*`, додай його `cspell-ext.json` у `import` і код мови в `language`. Огляд словників: [streetsidesoftware/cspell-dicts](https://github.com/streetsidesoftware/cspell-dicts).
215
+
216
+ ## Перевірка
217
+
218
+ `npx @nitra/cursor check text`
package/mdc/vue.mdc CHANGED
@@ -4,8 +4,6 @@ alwaysApply: true
4
4
  version: '1.2'
5
5
  ---
6
6
 
7
- # Vue 3 (Composition API)
8
-
9
7
  # Vue 3 Composition API — правила для .cursorrules
10
8
 
11
9
  ## Найкращі практики Vue 3 Composition API
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.4.1",
3
+ "version": "1.5.1",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -1,13 +1,14 @@
1
1
  import { existsSync } from 'node:fs'
2
2
  import { readFile } from 'node:fs/promises'
3
3
 
4
+ import { pass } from './utils/pass.mjs'
5
+
4
6
  /**
5
7
  * Перевіряє відповідність проєкту правилам bun.mdc
6
8
  * @returns {Promise<number>} 0 — все OK, 1 — є проблеми
7
9
  */
8
10
  export async function check() {
9
11
  let exitCode = 0
10
- const pass = msg => console.log(` ✅ ${msg}`)
11
12
  const fail = msg => {
12
13
  console.log(` ❌ ${msg}`)
13
14
  exitCode = 1
@@ -15,17 +16,31 @@ export async function check() {
15
16
 
16
17
  const forbidden = ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', '.yarnrc.yml']
17
18
  for (const f of forbidden) {
18
- existsSync(f) ? fail(`Знайдено заборонений файл: ${f} — видали його`) : pass(`Немає ${f}`)
19
+ if (existsSync(f)) {
20
+ fail(`Знайдено заборонений файл: ${f} — видали його`)
21
+ } else {
22
+ pass(`Немає ${f}`)
23
+ }
19
24
  }
20
25
 
21
- existsSync('.yarn') ? fail('Знайдено директорію .yarn — видали її') : pass('Немає .yarn/')
22
- existsSync('bun.lock') ? pass('bun.lock є') : fail('Відсутній bun.lock запусти bun i')
26
+ if (existsSync('.yarn')) {
27
+ fail('Знайдено директорію .yarnвидали її')
28
+ } else {
29
+ pass('Немає .yarn/')
30
+ }
31
+ if (existsSync('bun.lock')) {
32
+ pass('bun.lock є')
33
+ } else {
34
+ fail('Відсутній bun.lock — запусти bun i')
35
+ }
23
36
 
24
37
  if (existsSync('package.json')) {
25
38
  const pkg = JSON.parse(await readFile('package.json', 'utf8'))
26
- pkg.packageManager
27
- ? fail(`package.json містить поле packageManager: "${pkg.packageManager}" — видали його`)
28
- : pass('package.json не містить packageManager')
39
+ if (pkg.packageManager) {
40
+ fail(`package.json містить поле packageManager: "${pkg.packageManager}" — видали його`)
41
+ } else {
42
+ pass('package.json не містить packageManager')
43
+ }
29
44
  }
30
45
 
31
46
  return exitCode
@@ -1,13 +1,14 @@
1
1
  import { existsSync } from 'node:fs'
2
2
  import { readdir, readFile } from 'node:fs/promises'
3
3
 
4
+ import { pass } from './utils/pass.mjs'
5
+
4
6
  /**
5
7
  * Перевіряє відповідність проєкту правилам ga.mdc
6
8
  * @returns {Promise<number>} 0 — все OK, 1 — є проблеми
7
9
  */
8
10
  export async function check() {
9
11
  let exitCode = 0
10
- const pass = msg => console.log(` ✅ ${msg}`)
11
12
  const fail = msg => {
12
13
  console.log(` ❌ ${msg}`)
13
14
  exitCode = 1
@@ -30,28 +31,38 @@ export async function check() {
30
31
  }
31
32
 
32
33
  for (const f of ['clean-ga-workflows.yml', 'clean-merged-branch.yml']) {
33
- files.includes(f) ? pass(`${f} існує`) : fail(`Відсутній ${wfDir}/${f}`)
34
+ if (files.includes(f)) {
35
+ pass(`${f} існує`)
36
+ } else {
37
+ fail(`Відсутній ${wfDir}/${f}`)
38
+ }
34
39
  }
35
40
 
36
41
  if (files.includes('apply-k8s.yml')) {
37
42
  const content = await readFile(`${wfDir}/apply-k8s.yml`, 'utf8')
38
- content.includes('**/k8s/*.yaml')
39
- ? pass('apply-k8s.yml має правильний paths trigger')
40
- : fail('apply-k8s.yml не містить paths: **/k8s/*.yaml')
43
+ if (content.includes('**/k8s/*.yaml')) {
44
+ pass('apply-k8s.yml має правильний paths trigger')
45
+ } else {
46
+ fail('apply-k8s.yml не містить paths: **/k8s/*.yaml')
47
+ }
41
48
  }
42
49
 
43
50
  if (files.includes('apply-nats-consumer.yml')) {
44
51
  const content = await readFile(`${wfDir}/apply-nats-consumer.yml`, 'utf8')
45
- content.includes('**/consumer.yaml')
46
- ? pass('apply-nats-consumer.yml має правильний paths trigger')
47
- : fail('apply-nats-consumer.yml не містить paths: **/consumer.yaml')
52
+ if (content.includes('**/consumer.yaml')) {
53
+ pass('apply-nats-consumer.yml має правильний paths trigger')
54
+ } else {
55
+ fail('apply-nats-consumer.yml не містить paths: **/consumer.yaml')
56
+ }
48
57
  }
49
58
 
50
59
  if (existsSync('.vscode/extensions.json')) {
51
60
  const ext = JSON.parse(await readFile('.vscode/extensions.json', 'utf8'))
52
- ext.recommendations?.includes('github.vscode-github-actions')
53
- ? pass('extensions.json містить github.vscode-github-actions')
54
- : fail('extensions.json не містить github.vscode-github-actions')
61
+ if (ext.recommendations?.includes('github.vscode-github-actions')) {
62
+ pass('extensions.json містить github.vscode-github-actions')
63
+ } else {
64
+ fail('extensions.json не містить github.vscode-github-actions')
65
+ }
55
66
  } else {
56
67
  fail('.vscode/extensions.json не існує')
57
68
  }
@@ -1,29 +1,39 @@
1
1
  import { existsSync } from 'node:fs'
2
2
  import { readFile } from 'node:fs/promises'
3
3
 
4
+ import { pass } from './utils/pass.mjs'
5
+
4
6
  /**
5
7
  * Перевіряє відповідність проєкту правилам js-format.mdc
6
8
  * @returns {Promise<number>} 0 — все OK, 1 — є проблеми
7
9
  */
8
10
  export async function check() {
9
11
  let exitCode = 0
10
- const pass = msg => console.log(` ✅ ${msg}`)
11
12
  const fail = msg => {
12
13
  console.log(` ❌ ${msg}`)
13
14
  exitCode = 1
14
15
  }
15
16
 
16
17
  const expectedKeys = [
17
- 'arrowParens', 'printWidth', 'bracketSpacing', 'bracketSameLine',
18
- 'semi', 'singleQuote', 'tabWidth', 'trailingComma', 'useTabs'
18
+ 'arrowParens',
19
+ 'printWidth',
20
+ 'bracketSpacing',
21
+ 'bracketSameLine',
22
+ 'semi',
23
+ 'singleQuote',
24
+ 'tabWidth',
25
+ 'trailingComma',
26
+ 'useTabs'
19
27
  ]
20
28
 
21
29
  if (existsSync('.oxfmtrc.json')) {
22
30
  const cfg = JSON.parse(await readFile('.oxfmtrc.json', 'utf8'))
23
31
  const missing = expectedKeys.filter(k => !(k in cfg))
24
- missing.length === 0
25
- ? pass('.oxfmtrc.json містить всі обовʼязкові ключі')
26
- : fail(`.oxfmtrc.json відсутні ключі: ${missing.join(', ')}`)
32
+ if (missing.length === 0) {
33
+ pass('.oxfmtrc.json містить всі обовʼязкові ключі')
34
+ } else {
35
+ fail(`.oxfmtrc.json відсутні ключі: ${missing.join(', ')}`)
36
+ }
27
37
 
28
38
  if (cfg.semi !== false) fail('.oxfmtrc.json: semi має бути false')
29
39
  if (cfg.singleQuote !== true) fail('.oxfmtrc.json: singleQuote має бути true')
@@ -36,18 +46,22 @@ export async function check() {
36
46
 
37
47
  if (existsSync('.vscode/extensions.json')) {
38
48
  const ext = JSON.parse(await readFile('.vscode/extensions.json', 'utf8'))
39
- ext.recommendations?.includes('oxc.oxc-vscode')
40
- ? pass('extensions.json містить oxc.oxc-vscode')
41
- : fail('extensions.json не містить oxc.oxc-vscode')
49
+ if (ext.recommendations?.includes('oxc.oxc-vscode')) {
50
+ pass('extensions.json містить oxc.oxc-vscode')
51
+ } else {
52
+ fail('extensions.json не містить oxc.oxc-vscode')
53
+ }
42
54
  } else {
43
55
  fail('.vscode/extensions.json не існує')
44
56
  }
45
57
 
46
58
  if (existsSync('.vscode/settings.json')) {
47
59
  const settings = JSON.parse(await readFile('.vscode/settings.json', 'utf8'))
48
- settings['editor.formatOnSave'] === true
49
- ? pass('settings.json: editor.formatOnSave увімкнено')
50
- : fail('settings.json: editor.formatOnSave має бути true')
60
+ if (settings['editor.formatOnSave'] === true) {
61
+ pass('settings.json: editor.formatOnSave увімкнено')
62
+ } else {
63
+ fail('settings.json: editor.formatOnSave має бути true')
64
+ }
51
65
 
52
66
  const fmtTypes = ['javascript', 'typescript', 'json', 'vue', 'css', 'html']
53
67
  for (const t of fmtTypes) {