@nitra/cursor 1.5.0 → 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/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,6 +43,7 @@ Lockfile у репозиторії: `bun.lock`.
41
43
  Видалити якщо вони є. Видалити .yarn та .yarnrc.yml якщо вони є.
42
44
 
43
45
  Для Bun monorepo:
46
+
44
47
  - Встановлювати залежності у відповідному пакеті, а не в корені без потреби.
45
48
  - Якщо залежність потрібна лише одному пакету, додавати її в директорії цього пакета.
46
49
  - У CI та локально запускати скрипти через `bun run`.
@@ -49,12 +52,15 @@ Lockfile у репозиторії: `bun.lock`.
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`
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.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -0,0 +1,139 @@
1
+ import { existsSync } from 'node:fs'
2
+ import { readFile } from 'node:fs/promises'
3
+
4
+ import { pass } from './utils/pass.mjs'
5
+
6
+ /**
7
+ * Перевіряє відповідність проєкту правилам text.mdc (cspell, markdownlint-cli2, v8r)
8
+ * @returns {Promise<number>} 0 — все OK, 1 — є проблеми
9
+ */
10
+ export async function check() {
11
+ let exitCode = 0
12
+ const fail = msg => {
13
+ console.log(` ❌ ${msg}`)
14
+ exitCode = 1
15
+ }
16
+
17
+ if (existsSync('.vscode/extensions.json')) {
18
+ try {
19
+ const ext = JSON.parse(await readFile('.vscode/extensions.json', 'utf8'))
20
+ const rec = ext.recommendations
21
+ if (Array.isArray(rec) && rec.includes('DavidAnson.vscode-markdownlint')) {
22
+ pass('extensions.json містить DavidAnson.vscode-markdownlint')
23
+ } else {
24
+ fail('extensions.json: додай "DavidAnson.vscode-markdownlint" у recommendations (див. n-text.mdc)')
25
+ }
26
+ } catch {
27
+ fail('.vscode/extensions.json — невалідний JSON')
28
+ }
29
+ } else {
30
+ fail('.vscode/extensions.json не існує — створи з recommendations згідно n-text.mdc')
31
+ }
32
+
33
+ if (existsSync('.markdownlint-cli2.jsonc')) {
34
+ try {
35
+ const ml = JSON.parse(await readFile('.markdownlint-cli2.jsonc', 'utf8'))
36
+ pass('.markdownlint-cli2.jsonc існує і є валідним JSON')
37
+ if (ml.gitignore === true) {
38
+ pass('.markdownlint-cli2.jsonc: gitignore увімкнено')
39
+ } else {
40
+ fail('.markdownlint-cli2.jsonc: додай на верхньому рівні "gitignore": true (див. n-text.mdc)')
41
+ }
42
+ } catch {
43
+ fail('.markdownlint-cli2.jsonc — невалідний JSON; перевір синтаксис')
44
+ }
45
+ } else {
46
+ fail('.markdownlint-cli2.jsonc не існує — створи згідно n-text.mdc')
47
+ }
48
+
49
+ if (existsSync('.cspell.json')) {
50
+ const cfg = JSON.parse(await readFile('.cspell.json', 'utf8'))
51
+
52
+ if (cfg.version === '0.2') {
53
+ pass('.cspell.json version: 0.2')
54
+ } else {
55
+ fail('.cspell.json version має бути "0.2"')
56
+ }
57
+
58
+ if (cfg.language) {
59
+ pass(`.cspell.json language: "${cfg.language}"`)
60
+ } else {
61
+ fail('.cspell.json не містить поле language')
62
+ }
63
+
64
+ const imports = cfg.import || []
65
+ if (imports.some(i => i.includes('@nitra/cspell-dict'))) {
66
+ pass('.cspell.json імпортує @nitra/cspell-dict')
67
+ } else {
68
+ fail('.cspell.json не імпортує @nitra/cspell-dict/cspell-ext.json')
69
+ }
70
+
71
+ if (Array.isArray(cfg.ignorePaths)) {
72
+ pass('.cspell.json містить ignorePaths')
73
+ } else {
74
+ fail('.cspell.json не містить ignorePaths')
75
+ }
76
+ } else {
77
+ fail('.cspell.json не існує — створи його')
78
+ }
79
+
80
+ if (existsSync('package.json')) {
81
+ const pkg = JSON.parse(await readFile('package.json', 'utf8'))
82
+ const devDeps = pkg.devDependencies || {}
83
+
84
+ if (devDeps['@nitra/cspell-dict']) {
85
+ pass('@nitra/cspell-dict є в devDependencies')
86
+ } else {
87
+ fail('@nitra/cspell-dict відсутній — bun add -d @nitra/cspell-dict')
88
+ }
89
+
90
+ if (devDeps['markdownlint-cli2']) {
91
+ pass('markdownlint-cli2 є в devDependencies')
92
+ } else {
93
+ fail('markdownlint-cli2 відсутній — bun add -d markdownlint-cli2')
94
+ }
95
+
96
+ const lintText = pkg.scripts?.['lint-text']
97
+ const v8rCalls = typeof lintText === 'string' ? (lintText.match(/bunx v8r/g) || []).length : 0
98
+ const eq98Hints = typeof lintText === 'string' ? (lintText.match(/eq 98/g) || []).length : 0
99
+ if (
100
+ typeof lintText === 'string' &&
101
+ lintText.includes('cspell') &&
102
+ lintText.includes('markdownlint-cli2') &&
103
+ lintText.includes('**/*.mdc') &&
104
+ v8rCalls >= 4 &&
105
+ eq98Hints >= 4 &&
106
+ lintText.includes('**/*.json') &&
107
+ lintText.includes('**/*.yml') &&
108
+ lintText.includes('**/*.yaml') &&
109
+ lintText.includes('**/*.toml')
110
+ ) {
111
+ pass('package.json: lint-text — чотири виклики v8r з || [ $? -eq 98 ] для json/yml/yaml/toml')
112
+ } else {
113
+ fail(
114
+ 'package.json: lint-text — чотири (bunx v8r "<glob>" || [ $? -eq 98 ]) для **/*.json **/*.yml **/*.yaml **/*.toml (див. n-text.mdc)'
115
+ )
116
+ }
117
+
118
+ if (existsSync('.github/workflows/lint-text.yml')) {
119
+ const wf = await readFile('.github/workflows/lint-text.yml', 'utf8')
120
+ if (wf.includes('bun run lint-text')) {
121
+ pass('lint-text.yml викликає bun run lint-text')
122
+ } else {
123
+ fail('lint-text.yml має містити крок bun run lint-text')
124
+ }
125
+ } else {
126
+ fail('.github/workflows/lint-text.yml не існує — створи згідно n-text.mdc')
127
+ }
128
+
129
+ if (existsSync('.cspell.json')) {
130
+ const cfg = JSON.parse(await readFile('.cspell.json', 'utf8'))
131
+ const hasUkImport = (cfg.import || []).some(i => i.includes('@cspell/dict-uk-ua'))
132
+ if (hasUkImport && !devDeps['@cspell/dict-uk-ua']) {
133
+ fail('.cspell.json імпортує @cspell/dict-uk-ua, але пакет відсутній в devDependencies')
134
+ }
135
+ }
136
+ }
137
+
138
+ return exitCode
139
+ }
@@ -40,6 +40,7 @@ oxfmt .
40
40
 
41
41
  ```bash
42
42
  bun run lint-js
43
+ bun run lint-text
43
44
  bun run lint-style
44
45
  ```
45
46
 
@@ -47,11 +47,12 @@ Telegram підтримує моноширний шрифт через markdown-
47
47
  <1-2 речення — що отримали, яка вигода>
48
48
  ```
49
49
 
50
- #тег використовуються наступні:
51
- якщо публікація стосовно AI, то #ai
52
- якщо публікація стосовно npm модуля, то #npm
53
- якщо публікація стосовно розробки, то #dev
54
- якщо публікація стосовно інфраструктури, скриптів, налаштувань, ефективності коду чи безпеки то #sre
50
+ Теги (хештеги в кінці поста) — підбір за темою:
51
+
52
+ - якщо публікація стосовно AI, то `#ai`
53
+ - якщо публікація стосовно npm модуля, то `#npm`
54
+ - якщо публікація стосовно розробки, то `#dev`
55
+ - якщо публікація стосовно інфраструктури, скриптів, налаштувань, ефективності коду чи безпеки, то `#sre`
55
56
 
56
57
  ## Правила
57
58
 
@@ -68,6 +69,8 @@ Telegram підтримує моноширний шрифт через markdown-
68
69
 
69
70
  ````
70
71
  ```
72
+ #dev
73
+
71
74
  📌 Міграція з Prettier на oxfmt
72
75
 
73
76
  Проблема:
@@ -87,7 +90,5 @@ Prettier повільно форматував великі файли і
87
90
  Результат:
88
91
  Форматування працює миттєво при збереженні,
89
92
  зникли конфлікти між форматером і лінтером.
90
-
91
- #dx #tooling #oxfmt
92
93
  ```
93
94
  ````
package/mdc/spell.mdc DELETED
@@ -1,155 +0,0 @@
1
- ---
2
- description: Перевірка правопису в текстових файлах
3
- alwaysApply: true
4
- version: '1.3'
5
- ---
6
-
7
- У корені проєкту має бути `.cspell.json` і залежності для cspell у кореневому `package.json` (зазвичай `devDependencies`).
8
-
9
- У кореневому `package.json` додай скрипт CLI **cspell** (об’єднай з блоками з розділів нижче в одному файлі):
10
-
11
- ```json title="package.json"
12
- "scripts": {
13
- "lint-spell": "npx cspell ."
14
- }
15
- ```
16
-
17
- Додай workflow `.github/workflows/lint-spell.yml`:
18
-
19
- ```yaml
20
- name: Lint Spell
21
-
22
- on:
23
- push:
24
- branches:
25
- - dev
26
- paths:
27
- - '.cspell.json'
28
- - '**/*.js'
29
- - '**/*.ts'
30
- - '**/*.vue'
31
- - '**/*.html'
32
- - '**/*.css'
33
- - '**/*.scss'
34
- - '**/*.less'
35
- - '**/*.json'
36
- - '**/*.jsonc'
37
- - '**/*.yaml'
38
- - '**/*.yml'
39
- - '**/*.toml'
40
- - '**/*.xml'
41
- - '**/*.md'
42
- - '**/*.mdс'
43
- - '**/*.txt'
44
- - '**/*.go'
45
- - '**/*.py'
46
- - '**/*.php'
47
-
48
- pull_request:
49
- branches:
50
- - dev
51
-
52
- concurrency:
53
- group: ${{ github.ref }}-${{ github.workflow }}
54
- cancel-in-progress: true
55
-
56
- jobs:
57
- cspell:
58
- runs-on: ubuntu-latest
59
- steps:
60
- - uses: actions/checkout@v4
61
-
62
- - uses: oven-sh/setup-bun@v2
63
-
64
- - name: Cache Bun dependencies
65
- uses: actions/cache@v4
66
- with:
67
- path: |
68
- ~/.bun/install/cache
69
- node_modules
70
- key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
71
- restore-keys: |
72
- ${{ runner.os }}-bun-
73
-
74
- - name: Install dependencies
75
- run: bun install --frozen-lockfile
76
-
77
- - name: Cspell
78
- run: bun run lint-spell
79
- ```
80
-
81
- **Без дублювання CI:** якщо в `.github/workflows` уже є workflow з тими самими кроками `cspell`, видали зайвий — перевірка правопису має виконуватися в одному місці.
82
-
83
- ## Базовий варіант (без окремого словника української)
84
-
85
- Якщо текст переважно англійською та достатньо корпоративного словника (@nitra/cspell-dict; у полі `language` cspell лишається тег `nitra`):
86
-
87
- ```json title=".cspell.json"
88
- {
89
- "version": "0.2",
90
- "language": "nitra",
91
- "ignorePaths": ["**/node_modules/**", "**/vscode-extension/**", "**/.git/**", ".vscode", "report"],
92
- "import": ["@nitra/cspell-dict/cspell-ext.json"],
93
- "words": []
94
- }
95
- ```
96
-
97
- ```json title="package.json"
98
- {
99
- "scripts": {
100
- "lint-spell": "npx cspell ."
101
- },
102
- "devDependencies": {
103
- "@nitra/cspell-dict": "^1.0.185"
104
- }
105
- }
106
- ```
107
-
108
- ## Проєкт з українською мовою
109
-
110
- Якщо в репозиторії є українська документація, коментарі або рядки в коді — потрібен **окремий словник** `@cspell/dict-uk-ua`, інакше cspell не перевірятиме український правопис коректно.
111
-
112
- **1. Залежності** — додай пакет словника поруч із `@nitra/cspell-dict`:
113
-
114
- ```json title="package.json"
115
- {
116
- "scripts": {
117
- "lint-spell": "npx cspell ."
118
- },
119
- "devDependencies": {
120
- "@nitra/cspell-dict": "^1.0.185",
121
- "@cspell/dict-uk-ua": "^4.0.6"
122
- }
123
- }
124
- ```
125
-
126
- Встановлення: `bun add -d @cspell/dict-uk-ua` (або `npm i -D @cspell/dict-uk-ua`).
127
-
128
- **2. `.cspell.json`** — у полі `language` має бути `uk` (разом з іншими мовами через кому), у `import` — підключення розширення українського словника:
129
-
130
- ```json title=".cspell.json"
131
- {
132
- "version": "0.2",
133
- "language": "en,uk,nitra",
134
- "ignorePaths": ["**/node_modules/**", "**/vscode-extension/**", "**/.git/**", ".vscode", "report"],
135
- "import": [
136
- "@nitra/cspell-dict/cspell-ext.json",
137
- "@cspell/dict-uk-ua/cspell-ext.json"
138
- ],
139
- "words": []
140
- }
141
- ```
142
-
143
- Підлаштуй `language` під проєкт (наприклад додай `ru-ru`, якщо потрібна перевірка російською). Порядок у `import` може впливати на пріоритет словників — тримай корпоративний `@nitra/cspell-dict` там, де зручно для ваших правил.
144
-
145
- ## Локальні виключення
146
-
147
- У секції `words` у `.cspell.json` додають власні терміни, імена та скорочення, яких немає в словниках.
148
-
149
- ## Інші мови
150
-
151
- Для іншої мови встанови відповідний пакет `@cspell/dict-*`, додай його `cspell-ext.json` у `import` і код мови в `language`. Огляд словників: [streetsidesoftware/cspell-dicts](https://github.com/streetsidesoftware/cspell-dicts).
152
-
153
- ## Перевірка
154
-
155
- `npx @nitra/cursor check spell`
@@ -1,86 +0,0 @@
1
- import { existsSync } from 'node:fs'
2
- import { readFile } from 'node:fs/promises'
3
-
4
- import { pass } from './utils/pass.mjs'
5
-
6
- /**
7
- * Перевіряє відповідність проєкту правилам spell.mdc
8
- * @returns {Promise<number>} 0 — все OK, 1 — є проблеми
9
- */
10
- export async function check() {
11
- let exitCode = 0
12
- const fail = msg => {
13
- console.log(` ❌ ${msg}`)
14
- exitCode = 1
15
- }
16
-
17
- if (existsSync('.cspell.json')) {
18
- const cfg = JSON.parse(await readFile('.cspell.json', 'utf8'))
19
-
20
- if (cfg.version === '0.2') {
21
- pass('.cspell.json version: 0.2')
22
- } else {
23
- fail('.cspell.json version має бути "0.2"')
24
- }
25
-
26
- if (cfg.language) {
27
- pass(`.cspell.json language: "${cfg.language}"`)
28
- } else {
29
- fail('.cspell.json не містить поле language')
30
- }
31
-
32
- const imports = cfg.import || []
33
- if (imports.some(i => i.includes('@nitra/cspell-dict'))) {
34
- pass('.cspell.json імпортує @nitra/cspell-dict')
35
- } else {
36
- fail('.cspell.json не імпортує @nitra/cspell-dict/cspell-ext.json')
37
- }
38
-
39
- if (Array.isArray(cfg.ignorePaths)) {
40
- pass('.cspell.json містить ignorePaths')
41
- } else {
42
- fail('.cspell.json не містить ignorePaths')
43
- }
44
- } else {
45
- fail('.cspell.json не існує — створи його')
46
- }
47
-
48
- if (existsSync('package.json')) {
49
- const pkg = JSON.parse(await readFile('package.json', 'utf8'))
50
- const devDeps = pkg.devDependencies || {}
51
-
52
- if (devDeps['@nitra/cspell-dict']) {
53
- pass('@nitra/cspell-dict є в devDependencies')
54
- } else {
55
- fail('@nitra/cspell-dict відсутній — bun add -d @nitra/cspell-dict')
56
- }
57
-
58
- const lintSpell = pkg.scripts?.['lint-spell']
59
- if (typeof lintSpell === 'string' && lintSpell.includes('cspell')) {
60
- pass('package.json містить скрипт lint-spell з cspell')
61
- } else {
62
- fail('package.json не містить скрипт "lint-spell": "npx cspell ." (див. n-spell.mdc)')
63
- }
64
-
65
- if (existsSync('.github/workflows/lint-spell.yml')) {
66
- const wf = await readFile('.github/workflows/lint-spell.yml', 'utf8')
67
- if (wf.includes('lint-spell')) {
68
- pass('lint-spell.yml існує і викликає lint-spell')
69
- } else {
70
- fail('lint-spell.yml має містити виклик bun run lint-spell')
71
- }
72
- } else {
73
- fail('.github/workflows/lint-spell.yml не існує — створи згідно n-spell.mdc')
74
- }
75
-
76
- if (existsSync('.cspell.json')) {
77
- const cfg = JSON.parse(await readFile('.cspell.json', 'utf8'))
78
- const hasUkImport = (cfg.import || []).some(i => i.includes('@cspell/dict-uk-ua'))
79
- if (hasUkImport && !devDeps['@cspell/dict-uk-ua']) {
80
- fail('.cspell.json імпортує @cspell/dict-uk-ua, але пакет відсутній в devDependencies')
81
- }
82
- }
83
- }
84
-
85
- return exitCode
86
- }