@nitra/cursor 1.5.5 → 1.6.5
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 +8 -2
- package/bin/n-cursor.js +28 -4
- package/mdc/bun.mdc +2 -2
- package/mdc/ga.mdc +18 -41
- package/mdc/js-lint.mdc +11 -19
- package/mdc/npm-module.mdc +4 -16
- package/mdc/text.mdc +16 -37
- package/package.json +1 -1
- package/schemas/n-cursor.json +4 -0
- package/scripts/check-bun.mjs +6 -0
- package/scripts/check-ga.mjs +84 -0
- package/scripts/check-js-format.mjs +5 -0
- package/scripts/check-js-lint.mjs +35 -1
- package/scripts/check-js-pino.mjs +8 -6
- package/scripts/check-nginx-default-tpl.mjs +6 -0
- package/scripts/check-npm-module.mjs +28 -0
- package/scripts/check-style-lint.mjs +6 -0
- package/scripts/check-text.mjs +8 -2
- package/scripts/check-vue.mjs +7 -3
- package/scripts/utils/pass.mjs +3 -1
- package/scripts/utils/workspaces.mjs +6 -0
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
```json
|
|
16
16
|
{
|
|
17
|
+
"$schema": "https://unpkg.com/@nitra/cursor/schemas/n-cursor.json",
|
|
17
18
|
"rules": ["js-format", "npm-module", "text"]
|
|
18
19
|
}
|
|
19
20
|
```
|
|
@@ -30,6 +31,7 @@
|
|
|
30
31
|
|
|
31
32
|
```json
|
|
32
33
|
{
|
|
34
|
+
"$schema": "https://unpkg.com/@nitra/cursor/schemas/n-cursor.json",
|
|
33
35
|
"version": "2.5.0",
|
|
34
36
|
"rules": ["js-format", "text"]
|
|
35
37
|
}
|
|
@@ -39,11 +41,15 @@
|
|
|
39
41
|
|
|
40
42
|
```bash
|
|
41
43
|
npx @nitra/cursor
|
|
44
|
+
npx @nitra/cursor check
|
|
45
|
+
npx @nitra/cursor check bun ga
|
|
42
46
|
```
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
Команда `check` запускає programmatic перевірки з каталогу `scripts/` пакету. Якщо в корені репозиторію вже є `.n-cursor.json`, перед перевірками виконується зчитування конфігу — зокрема додається або виправляється поле `$schema`, якщо воно відсутнє або не збігається з очікуваним URL.
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
CLI автоматично (команда завантаження правил без підкоманди `check`):
|
|
51
|
+
|
|
52
|
+
1. Знайде або створить `.n-cursor.json` у поточній директорії (із полем `$schema` на JSON Schema пакету; якщо файл уже є без коректного `$schema`, поле буде додано або оновлено при зчитуванні конфігу)
|
|
47
53
|
2. Створить директорію `.cursor/rules/`, якщо її ще немає
|
|
48
54
|
3. Завантажить кожне з перелічених у конфігу правило з unpkg.com і збереже файли з префіксом `n-`
|
|
49
55
|
4. Після оновлення файлів на диску згенерує в корені проєкту **`AGENTS.md`**: повний вміст береться з шаблону пакету `AGENTS.template.md`, а список правил у шаблоні формується з **усіх наявних файлів `*.mdc`** у `.cursor/rules/` (відсортовано за ім’ям)
|
package/bin/n-cursor.js
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Використання:
|
|
7
7
|
* `npx \@nitra/cursor` — завантажити cursor-правила
|
|
8
|
-
* `npx \@nitra/cursor check` — перевірити правила, перелічені в AGENTS.md (якщо є check-*.mjs)
|
|
8
|
+
* `npx \@nitra/cursor check` — перевірити правила, перелічені в AGENTS.md (якщо є check-*.mjs);
|
|
9
|
+
* якщо в корені вже є `.n-cursor.json`, спочатку зчитується конфіг і за потреби дописується `$schema`
|
|
9
10
|
* `npx \@nitra/cursor check bun` — перевірити лише вказані правила (ігнорує AGENTS.md)
|
|
10
11
|
*
|
|
11
12
|
* Якщо у корені репозиторію немає .n-cursor.json, спочатку перейменовується за наявності nitra-cursor.json;
|
|
12
13
|
* у `.cursor/rules` файли `nitra-*.mdc` перейменовуються на `n-*.mdc`; інакше конфіг створюється автоматично
|
|
13
|
-
* з усіма правилами з каталогу mdc пакету (їх можна відредагувати після створення).
|
|
14
|
+
* з усіма правилами з каталогу mdc пакету (їх можна відредагувати після створення). У файлі завжди має бути
|
|
15
|
+
* поле `$schema` з посиланням на JSON Schema пакету; при зчитуванні конфігу воно додається або виправляється на диску, якщо відсутнє або некоректне.
|
|
14
16
|
*
|
|
15
17
|
* Файл AGENTS.md у корені: щоразу повністю перезаписується змістом з AGENTS.template.md
|
|
16
18
|
* пакету; список правил у шаблоні будується з файлів *.mdc у .cursor/rules поточного проєкту.
|
|
@@ -33,6 +35,8 @@ import { fileURLToPath } from 'node:url'
|
|
|
33
35
|
const PACKAGE_NAME = '@nitra/cursor'
|
|
34
36
|
const UNPKG_BASE = 'https://unpkg.com'
|
|
35
37
|
const CONFIG_FILE = '.n-cursor.json'
|
|
38
|
+
/** URL JSON Schema для `.n-cursor.json` (поле `$schema` у файлі конфігурації) */
|
|
39
|
+
const CONFIG_SCHEMA_URL = `${UNPKG_BASE}/${PACKAGE_NAME}/schemas/n-cursor.json`
|
|
36
40
|
const AGENTS_FILE = 'AGENTS.md'
|
|
37
41
|
const AGENTS_TEMPLATE_FILE = 'AGENTS.template.md'
|
|
38
42
|
const RULES_DIR = '.cursor/rules'
|
|
@@ -144,7 +148,7 @@ async function migrateLegacyConfigIfNeeded() {
|
|
|
144
148
|
|
|
145
149
|
/**
|
|
146
150
|
* Зчитує конфіг .n-cursor.json з поточної директорії
|
|
147
|
-
* @returns {Promise<{rules: string[], skills: string[], version?: string}
|
|
151
|
+
* @returns {Promise<{ $schema: string, rules: string[], skills: string[], version?: string } & Record<string, unknown>>} rules, skills (id без префікса n-), опційно version; при відсутності файлу створює дефолтний конфіг
|
|
148
152
|
*/
|
|
149
153
|
async function readConfig() {
|
|
150
154
|
await migrateLegacyConfigIfNeeded()
|
|
@@ -152,7 +156,7 @@ async function readConfig() {
|
|
|
152
156
|
if (!existsSync(configPath)) {
|
|
153
157
|
const rules = await discoverBundledRuleNames()
|
|
154
158
|
const skills = await discoverBundledSkillNames()
|
|
155
|
-
const defaultConfig = { rules, skills }
|
|
159
|
+
const defaultConfig = { $schema: CONFIG_SCHEMA_URL, rules, skills }
|
|
156
160
|
await writeFile(configPath, `${JSON.stringify(defaultConfig, null, 2)}\n`, 'utf8')
|
|
157
161
|
console.log(
|
|
158
162
|
`📝 Створено ${CONFIG_FILE} з усіма правилами (${rules.length}) і skills (${skills.length}) з пакету. За потреби відредагуйте списки.\n`
|
|
@@ -175,6 +179,15 @@ async function readConfig() {
|
|
|
175
179
|
}
|
|
176
180
|
config.skills = await discoverBundledSkillNames()
|
|
177
181
|
}
|
|
182
|
+
|
|
183
|
+
if (config.$schema !== CONFIG_SCHEMA_URL) {
|
|
184
|
+
const { $schema: _omit, ...rest } = config
|
|
185
|
+
const normalized = { $schema: CONFIG_SCHEMA_URL, ...rest }
|
|
186
|
+
await writeFile(configPath, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8')
|
|
187
|
+
console.log(`📝 Оновлено поле $schema у ${CONFIG_FILE}\n`)
|
|
188
|
+
return normalized
|
|
189
|
+
}
|
|
190
|
+
|
|
178
191
|
return config
|
|
179
192
|
}
|
|
180
193
|
|
|
@@ -546,6 +559,17 @@ async function runChecks(requestedRules) {
|
|
|
546
559
|
throw new Error('No check scripts found')
|
|
547
560
|
}
|
|
548
561
|
|
|
562
|
+
const root = cwd()
|
|
563
|
+
const legacyConfigPath = join(root, 'nitra-cursor.json')
|
|
564
|
+
if (existsSync(join(root, CONFIG_FILE)) || existsSync(legacyConfigPath)) {
|
|
565
|
+
try {
|
|
566
|
+
await readConfig()
|
|
567
|
+
} catch (error) {
|
|
568
|
+
console.error(`❌ ${error.message}`)
|
|
569
|
+
throw error
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
549
573
|
let rulesToCheck
|
|
550
574
|
if (requestedRules.length > 0) {
|
|
551
575
|
rulesToCheck = requestedRules
|
package/mdc/bun.mdc
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Bun як єдиний package manager у монорепо
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.2'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
Проект використовує тільки Bun для керування залежностями та запуску скриптів.
|
|
@@ -50,7 +50,7 @@ Lockfile у репозиторії: `bun.lock`.
|
|
|
50
50
|
|
|
51
51
|
Якщо в package.json є поля `packageManager`, то прибрати їх, також прибрати всі директорії та файли для yarn
|
|
52
52
|
|
|
53
|
-
Якщо в проекті використовується npx, то не
|
|
53
|
+
Якщо в проекті використовується npx, то не замінювати його на bunx, а використовувати npx.
|
|
54
54
|
Коли зміна відбувається в Dockerfile, то використовувати
|
|
55
55
|
|
|
56
56
|
```dockerfile
|
package/mdc/ga.mdc
CHANGED
|
@@ -1,30 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Правила форматів для .github/workflows
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.2'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Всі файли в директорії .github/workflows повинні мати розширення тільки yml
|
|
10
|
-
|
|
11
|
-
Якщо є .github/workflows/apply-k8s.yml, то в ньому обов'язково повинно бути вказано що критерій для запуску це:
|
|
12
|
-
|
|
13
|
-
```yaml
|
|
14
|
-
on:
|
|
15
|
-
push:
|
|
16
|
-
paths:
|
|
17
|
-
- '**/k8s/*.yaml'
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Якщо є .github/workflows/apply-nats-consumer.yml, то в ньому обов'язково повинно бути вказано що критерій для запуску це:
|
|
21
|
-
|
|
22
|
-
```yaml
|
|
23
|
-
on:
|
|
24
|
-
push:
|
|
25
|
-
paths:
|
|
26
|
-
- '**/consumer.yaml'
|
|
27
|
-
```
|
|
7
|
+
У `.github/workflows/` лише **`.yml`**. Мають бути **`clean-ga-workflows.yml`**, **`clean-merged-branch.yml`**, **`lint-ga.yml`**. Якщо є **`apply-k8s.yml`** / **`apply-nats-consumer.yml`** — paths у тригері як у фрагментах.
|
|
28
8
|
|
|
29
9
|
Повинен бути файл .github/workflows/clean-ga-workflows.yml, зі змістом:
|
|
30
10
|
|
|
@@ -53,7 +33,6 @@ jobs:
|
|
|
53
33
|
save_min_runs_number: 0
|
|
54
34
|
|
|
55
35
|
```
|
|
56
|
-
|
|
57
36
|
Повинен бути файл .github/workflows/clean-merged-branch.yml, зі змістом:
|
|
58
37
|
|
|
59
38
|
```yaml
|
|
@@ -89,8 +68,7 @@ jobs:
|
|
|
89
68
|
echo "Deleted branches: ${DELETED_BRANCHES}"
|
|
90
69
|
```
|
|
91
70
|
|
|
92
|
-
|
|
93
|
-
|
|
71
|
+
Інші гілки в `ignore_branches` — допустимо.
|
|
94
72
|
Повинен бути файл .github/workflows/lint-ga.yml, зі змістом:
|
|
95
73
|
|
|
96
74
|
```yaml
|
|
@@ -145,25 +123,13 @@ jobs:
|
|
|
145
123
|
run: bun run lint-ga
|
|
146
124
|
```
|
|
147
125
|
|
|
148
|
-
в файлі .vscode/extensions.json є налаштування для GitHub Actions:
|
|
149
|
-
|
|
150
126
|
```json title=".vscode/extensions.json"
|
|
151
127
|
{
|
|
152
128
|
"recommendations": ["github.vscode-github-actions"]
|
|
153
129
|
}
|
|
154
130
|
```
|
|
155
131
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Статична перевірка синтаксису та виразів GitHub Actions: [actionlint](https://github.com/rhysd/actionlint).
|
|
159
|
-
|
|
160
|
-
У кореневому `package.json` у скрипті `lint-ga` викликай **actionlint** через **`bunx node-actionlint`** (пакет [node-actionlint](https://www.npmjs.com/package/node-actionlint) постає бінарник actionlint для Node-екосистеми).
|
|
161
|
-
|
|
162
|
-
## zizmor
|
|
163
|
-
|
|
164
|
-
Статичний аналіз безпеки для GitHub Actions: [zizmor documentation](https://docs.zizmor.sh).
|
|
165
|
-
|
|
166
|
-
У кореневому `package.json` має бути скрипт:
|
|
132
|
+
**Лінт:** [actionlint](https://github.com/rhysd/actionlint) через [node-actionlint](https://www.npmjs.com/package/node-actionlint); [zizmor](https://docs.zizmor.sh) — `uvx`, офлайн. Скрипт у корені:
|
|
167
133
|
|
|
168
134
|
```json title="package.json"
|
|
169
135
|
"scripts": {
|
|
@@ -171,11 +137,22 @@ jobs:
|
|
|
171
137
|
}
|
|
172
138
|
```
|
|
173
139
|
|
|
174
|
-
|
|
140
|
+
**`.github/zizmor.yml`:** для [unpinned-uses](https://docs.zizmor.sh/audits/#unpinned-uses) — політика **`ref-pin`**, якщо в `uses:` семантичні теги. За потреби вимкни [template-injection](https://docs.zizmor.sh/audits/#template-injection):
|
|
141
|
+
|
|
142
|
+
```yaml title=".github/zizmor.yml"
|
|
143
|
+
# https://docs.zizmor.sh/configuration/
|
|
144
|
+
rules:
|
|
145
|
+
unpinned-uses:
|
|
146
|
+
config:
|
|
147
|
+
policies:
|
|
148
|
+
'*': ref-pin
|
|
149
|
+
template-injection:
|
|
150
|
+
disable: true
|
|
151
|
+
```
|
|
175
152
|
|
|
176
|
-
|
|
153
|
+
**MegaLinter:** не використовувати; прибрати workflow, конфіги (`.mega-linter.yml`, `.megalinter.yaml`, `.mega-linter.yaml`), залежності та згадки в CI / pre-commit / документації.
|
|
177
154
|
|
|
178
155
|
## Перевірка
|
|
179
156
|
|
|
180
|
-
- `bun run lint-ga`
|
|
157
|
+
- `bun run lint-ga`
|
|
181
158
|
- `npx @nitra/cursor check ga`
|
package/mdc/js-lint.mdc
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Перевірка JavaScript коду
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.7'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
У файлі `.vscode/extensions.json` мають бути рекомендації розширень:
|
|
7
|
+
**oxlint**, **ESLint**, **jscpd**. У скрипті **`lint-js`:** `oxlint` (без `bunx`), **`bunx eslint`**, **`bunx jscpd`**; у CI — `bunx oxlint` / `bunx eslint` / `bunx jscpd`. Без **prettier** і **@nitra/prettier-config**. Достатньо **`@nitra/eslint-config`** у devDependencies; пакети oxlint/eslint/jscpd не додавай без потреби монорепо.
|
|
10
8
|
|
|
11
9
|
```json title=".vscode/extensions.json"
|
|
12
10
|
{
|
|
@@ -18,19 +16,19 @@ version: '1.5'
|
|
|
18
16
|
}
|
|
19
17
|
```
|
|
20
18
|
|
|
21
|
-
У кореневому `package.json` додай скрипт і залежності:
|
|
22
|
-
|
|
23
19
|
```json title="package.json"
|
|
20
|
+
{
|
|
24
21
|
"scripts": {
|
|
25
22
|
"lint-js": "oxlint --fix && bunx eslint --fix . && bunx jscpd ."
|
|
26
23
|
},
|
|
27
24
|
"devDependencies": {
|
|
28
25
|
"@nitra/eslint-config": "^3.4.0"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=24"
|
|
29
29
|
}
|
|
30
|
+
}
|
|
30
31
|
```
|
|
31
|
-
|
|
32
|
-
У `devDependencies` достатньо `@nitra/eslint-config` (залежності ESLint підтягуються разом із ним). **oxlint**, **eslint** та **jscpd** у скриптах викликай через `bunx`; окремо не додавай пакети `oxlint` / `eslint` / `jscpd`, якщо цього не вимагає ваш монорепо.
|
|
33
|
-
|
|
34
32
|
У корені проєкту має бути `.jscpd.json`. Мінімум: увімкнути облік `.gitignore`, ненульовий код виходу при знаходженні клонів, консольний звіт. За потреби додай `ignore` (дзеркальні каталоги, шаблони) та `minLines`, щоб відсікти дрібні збіги:
|
|
35
33
|
|
|
36
34
|
```json title=".jscpd.json"
|
|
@@ -54,9 +52,9 @@ version: '1.5'
|
|
|
54
52
|
|
|
55
53
|
Але обов'язково перед рефакторингом перевір чи є тести на блоки які підлягають зміні, а саме Bun.test для js та playwright для vue. Якщо є, то перевір чи вони покривають блоки які підлягають зміні. Якщо не покривають або тестів немає — спочатку створи їх, перевір що вони покривають і відпрацьовують коректно, а потім роби рефакторинг і ще раз запускай тести, але якщо тести не відпрацьовують коректно після рефакторингу, то не роби рефакторинг.
|
|
56
54
|
|
|
57
|
-
Додай workflow
|
|
55
|
+
Додай workflow:
|
|
58
56
|
|
|
59
|
-
```yaml
|
|
57
|
+
```yaml title=".github/workflows/lint-js.yml"
|
|
60
58
|
name: Lint JS
|
|
61
59
|
|
|
62
60
|
on:
|
|
@@ -114,9 +112,7 @@ jobs:
|
|
|
114
112
|
bunx jscpd .
|
|
115
113
|
```
|
|
116
114
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
У корені проєкту має бути `eslint.config.js` із розподілом директорій за типом коду:
|
|
115
|
+
Один workflow на лінт JS; зайвий `lint.yml` з тими самими кроками — прибери.
|
|
120
116
|
|
|
121
117
|
```javascript title="eslint.config.js"
|
|
122
118
|
import { getConfig } from '@nitra/eslint-config'
|
|
@@ -129,7 +125,6 @@ export default [
|
|
|
129
125
|
```
|
|
130
126
|
|
|
131
127
|
У монорепо пакети з Vite (frontend) вкажи в секції `vue`, решту — у секції `node` у виклику `getConfig`.
|
|
132
|
-
|
|
133
128
|
## Додаткові js правила
|
|
134
129
|
|
|
135
130
|
Завжди додавай до package.json що підтримується 24+ версія node:
|
|
@@ -139,10 +134,7 @@ export default [
|
|
|
139
134
|
"node": ">=24"
|
|
140
135
|
}
|
|
141
136
|
```
|
|
142
|
-
|
|
143
|
-
Завжди код повинен використовувати синтаксис 24+ версії node
|
|
144
|
-
|
|
145
|
-
Завжди повинен використовуватися top level await
|
|
137
|
+
**Код:** синтаксис Node **24+**, **top level await**.
|
|
146
138
|
|
|
147
139
|
## Перевірка
|
|
148
140
|
|
package/mdc/npm-module.mdc
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Оформлення репозиторію для npm модуля
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.2'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Bun monorepo: workspace **`npm/`**, кореневий **`package.json`**, **`.github/workflows/`**; опційно **`demo/`**.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## npm publish
|
|
10
10
|
|
|
11
|
-
- .
|
|
12
|
-
- demo/ - опціонально демо проект
|
|
13
|
-
- npm/ - файли для npm модуля
|
|
14
|
-
- package.json
|
|
15
|
-
|
|
16
|
-
## npm publish (GitHub Actions)
|
|
17
|
-
|
|
18
|
-
У `.github/workflows/` має бути workflow `npm-publish.yml`, який публікує пакет з `npm/package.json` на npm при push у `main`, коли змінюється дерево `npm/**`.
|
|
19
|
-
|
|
20
|
-
Приклад вмісту:
|
|
11
|
+
**`npm-publish.yml`:** push у **`main`**, **`paths: npm/**`**, **`JS-DevTools/npm-publish@v4`**, **`with.package: npm/package.json`**, **`permissions.id-token: write`** (OIDC на npm).
|
|
21
12
|
|
|
22
13
|
```yaml title=".github/workflows/npm-publish.yml"
|
|
23
14
|
name: npm-publish
|
|
@@ -56,9 +47,6 @@ jobs:
|
|
|
56
47
|
package: npm/package.json
|
|
57
48
|
```
|
|
58
49
|
|
|
59
|
-
- `id-token: write` потрібен для **trusted publishing** (OIDC) на npm, якщо пакет налаштований у npm без класичного токена в секретах.
|
|
60
|
-
- Шлях `package: npm/package.json` узгоджений зі структурою monorepo (`npm/` — каталог модуля).
|
|
61
|
-
|
|
62
50
|
## Перевірка
|
|
63
51
|
|
|
64
52
|
`npx @nitra/cursor check npm-module`
|
package/mdc/text.mdc
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Обробка та перевірка текстових файлів (cspell, markdownlint-cli2, v8r, CI)
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.16'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## Розширення Cursor / VS Code
|
|
10
|
-
|
|
11
|
-
У файлі `.vscode/extensions.json` **додай** `DavidAnson.vscode-markdownlint` у масив `recommendations` (разом із записами з інших правил, зокрема js-lint / js-format):
|
|
7
|
+
**cspell**, **markdownlint-cli2**, **[v8r](https://chris48s.github.io/v8r/)** ([Schema Store](https://www.schemastore.org/)), розширення **DavidAnson.vscode-markdownlint**, workflow **`lint-text`**.
|
|
12
8
|
|
|
13
9
|
```json title=".vscode/extensions.json"
|
|
14
10
|
{
|
|
@@ -21,34 +17,20 @@ version: '1.13'
|
|
|
21
17
|
}
|
|
22
18
|
```
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
У кореневому `package.json` один скрипт **lint-text** має послідовно викликати **cspell**, **markdownlint-cli2** і **v8r** (і решту блоків з розділів нижче в одному файлі):
|
|
20
|
+
**`package.json`:** скрипт **`lint-text`** і devDependencies **`@nitra/cspell-dict`**, **`markdownlint-cli2`**. Для української додай **`@cspell/dict-uk-ua`**. **`v8r`** лише через **`bunx`**, не в devDependencies. Окремий пакет **`markdownlint`** не потрібний.
|
|
27
21
|
|
|
28
22
|
```json title="package.json"
|
|
23
|
+
{
|
|
29
24
|
"scripts": {
|
|
30
25
|
"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
26
|
},
|
|
32
27
|
"devDependencies": {
|
|
33
|
-
"
|
|
28
|
+
"@nitra/cspell-dict": "^1.0.185"
|
|
34
29
|
}
|
|
30
|
+
}
|
|
35
31
|
```
|
|
36
32
|
|
|
37
|
-
**
|
|
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` не створюй завчасно** — файл потрібен **лише коли** `bunx v8r` падає на JSON/YAML без схеми в каталозі (тоді додай у ignore відповідні glob’и).
|
|
46
|
-
|
|
47
|
-
Пакет **`v8r` у `devDependencies` не додавай** — у скрипті достатньо **`bunx v8r`**.
|
|
48
|
-
|
|
49
|
-
## Конфігурація markdownlint-cli2
|
|
50
|
-
|
|
51
|
-
У корені проєкту має бути **`.markdownlint-cli2.jsonc`** (документація: [DavidAnson/markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2)):
|
|
33
|
+
**v8r:** чотири виклики `(bunx v8r "<glob>" || [ $? -eq 98 ])` — exit **98**, якщо glob порожній. **`.v8rignore`** лише коли немає схеми. Враховує `.gitignore`.
|
|
52
34
|
|
|
53
35
|
```json title=".markdownlint-cli2.jsonc"
|
|
54
36
|
{
|
|
@@ -63,19 +45,14 @@ version: '1.13'
|
|
|
63
45
|
}
|
|
64
46
|
```
|
|
65
47
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
За потреби увімкни окремі правила (наприклад `MD013` з `line_length: 120`), щоб узгодити довжину рядків з `.oxfmtrc.json`.
|
|
69
|
-
|
|
70
|
-
`MD041` вимкнено навмисно: файли `.mdc` (Cursor rules) мають YAML frontmatter, після якого перший абзац часто не є заголовком H1.
|
|
48
|
+
**MD041** off навмисно (`.mdc` з frontmatter). Деталі — [markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2).
|
|
71
49
|
|
|
72
50
|
## Cspell
|
|
73
51
|
|
|
74
52
|
У корені проєкту має бути `.cspell.json` і залежності для cspell у кореневому `package.json` (зазвичай `devDependencies`).
|
|
75
53
|
|
|
76
54
|
Додай workflow `.github/workflows/lint-text.yml`:
|
|
77
|
-
|
|
78
|
-
```yaml
|
|
55
|
+
```yaml title=".github/workflows/lint-text.yml"
|
|
79
56
|
name: Lint Text
|
|
80
57
|
|
|
81
58
|
on:
|
|
@@ -144,11 +121,11 @@ jobs:
|
|
|
144
121
|
run: bun run lint-text
|
|
145
122
|
```
|
|
146
123
|
|
|
147
|
-
|
|
124
|
+
Не дублюй окремий workflow з тими самими кроками cspell/markdownlint.
|
|
148
125
|
|
|
149
|
-
|
|
126
|
+
**`.cspell.json`**, `version: "0.2"`, **`language`**, **`import`** з `@nitra/cspell-dict`, **`ignorePaths`**, **`words`** лише для назв/термінів, коли не виправити текстом.
|
|
150
127
|
|
|
151
|
-
|
|
128
|
+
Базово (англійська + українська + корпоративний словник):
|
|
152
129
|
|
|
153
130
|
```json title=".cspell.json"
|
|
154
131
|
{
|
|
@@ -167,14 +144,14 @@ jobs:
|
|
|
167
144
|
},
|
|
168
145
|
"devDependencies": {
|
|
169
146
|
"@nitra/cspell-dict": "^1.0.185",
|
|
170
|
-
"
|
|
147
|
+
"@cspell/dict-uk-ua": "^4.0.6"
|
|
171
148
|
}
|
|
172
149
|
}
|
|
173
150
|
```
|
|
174
151
|
|
|
175
152
|
## Проєкт з українською мовою
|
|
176
153
|
|
|
177
|
-
Якщо в репозиторії є українська документація, коментарі або рядки в коді — потрібен **окремий словник** `@cspell/dict-
|
|
154
|
+
Якщо в репозиторії є українська документація, коментарі або рядки в коді — потрібен **окремий словник** `@cspell/dict-ru_ru`, інакше cspell не перевірятиме російський правопис коректно.
|
|
178
155
|
|
|
179
156
|
**1. Залежності** — додай пакет словника поруч із `@nitra/cspell-dict`:
|
|
180
157
|
|
|
@@ -186,6 +163,7 @@ jobs:
|
|
|
186
163
|
"devDependencies": {
|
|
187
164
|
"@nitra/cspell-dict": "^1.0.185",
|
|
188
165
|
"@cspell/dict-uk-ua": "^4.0.6",
|
|
166
|
+
"@cspell/dict-ru_ru": "^2.3.2",
|
|
189
167
|
"markdownlint-cli2": "^0.22.0"
|
|
190
168
|
}
|
|
191
169
|
}
|
|
@@ -224,6 +202,7 @@ jobs:
|
|
|
224
202
|
|
|
225
203
|
Для іншої мови встанови відповідний пакет `@cspell/dict-*`, додай його `cspell-ext.json` у `import` і код мови в `language`. Огляд словників: [streetsidesoftware/cspell-dicts](https://github.com/streetsidesoftware/cspell-dicts).
|
|
226
204
|
|
|
205
|
+
|
|
227
206
|
## Перевірка
|
|
228
207
|
|
|
229
208
|
`npx @nitra/cursor check text`
|
package/package.json
CHANGED
package/schemas/n-cursor.json
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": true,
|
|
8
8
|
"properties": {
|
|
9
|
+
"$schema": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Посилання на JSON Schema для автодоповнення та валідації в IDE; має збігатися з $id цієї схеми (рекомендовано завжди вказувати)."
|
|
12
|
+
},
|
|
9
13
|
"rules": {
|
|
10
14
|
"type": "array",
|
|
11
15
|
"description": "Ідентифікатори правил без префікса n- (відповідають файлам n-<id>.mdc).",
|
package/scripts/check-bun.mjs
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Перевіряє відповідність репозиторію правилам Bun (n-bun.mdc).
|
|
3
|
+
*
|
|
4
|
+
* Очікує наявність `bun.lock`, забороняє lockfile та артефакти yarn/pnpm, директорію `.yarn`
|
|
5
|
+
* і поле `packageManager` у кореневому `package.json`.
|
|
6
|
+
*/
|
|
1
7
|
import { existsSync } from 'node:fs'
|
|
2
8
|
import { readFile } from 'node:fs/promises'
|
|
3
9
|
|
package/scripts/check-ga.mjs
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Перевіряє GitHub Actions за правилом ga.mdc.
|
|
3
|
+
*
|
|
4
|
+
* Workflows лише з розширенням `.yml`, наявність clean/lint workflow, конфіг zizmor з ref-pin,
|
|
5
|
+
* відсутність MegaLinter, коректний скрипт `lint-ga` у `package.json` і виклик у `lint-ga.yml`.
|
|
6
|
+
*/
|
|
1
7
|
import { existsSync } from 'node:fs'
|
|
2
8
|
import { readdir, readFile } from 'node:fs/promises'
|
|
9
|
+
import { join } from 'node:path'
|
|
3
10
|
|
|
4
11
|
import { pass } from './utils/pass.mjs'
|
|
5
12
|
|
|
13
|
+
/** Шаблони наявності MegaLinter у вмісті workflow */
|
|
14
|
+
const MEGALINTER_USE_PATTERNS = [/oxsecurity\/megalinter-action/i, /megalinter\/megalinter/i]
|
|
15
|
+
|
|
16
|
+
/** Типові конфіги MegaLinter у корені репо */
|
|
17
|
+
const MEGALINTER_CONFIG_NAMES = ['.mega-linter.yml', '.megalinter.yaml', '.mega-linter.yaml']
|
|
18
|
+
|
|
6
19
|
/**
|
|
7
20
|
* Перевіряє відповідність проєкту правилам ga.mdc
|
|
8
21
|
* @returns {Promise<number>} 0 — все OK, 1 — є проблеми
|
|
@@ -67,5 +80,76 @@ export async function check() {
|
|
|
67
80
|
fail('.vscode/extensions.json не існує')
|
|
68
81
|
}
|
|
69
82
|
|
|
83
|
+
const ymlWorkflows = files.filter(f => f.endsWith('.yml'))
|
|
84
|
+
let foundMegalinter = false
|
|
85
|
+
for (const f of ymlWorkflows) {
|
|
86
|
+
const content = await readFile(join(wfDir, f), 'utf8')
|
|
87
|
+
if (MEGALINTER_USE_PATTERNS.some(re => re.test(content))) {
|
|
88
|
+
foundMegalinter = true
|
|
89
|
+
fail(`MegaLinter у workflow ${wfDir}/${f} — видали інтеграцію (ga.mdc: MegaLinter)`)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
for (const name of MEGALINTER_CONFIG_NAMES) {
|
|
94
|
+
if (existsSync(name)) {
|
|
95
|
+
foundMegalinter = true
|
|
96
|
+
fail(`Файл ${name} — видали конфіг MegaLinter (ga.mdc: MegaLinter)`)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!foundMegalinter) {
|
|
101
|
+
pass('Залишків MegaLinter не виявлено')
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const zizmorPath = '.github/zizmor.yml'
|
|
105
|
+
if (existsSync(zizmorPath)) {
|
|
106
|
+
const z = await readFile(zizmorPath, 'utf8')
|
|
107
|
+
pass(`${zizmorPath} існує`)
|
|
108
|
+
if (z.includes('ref-pin')) {
|
|
109
|
+
pass(`${zizmorPath} містить політику ref-pin (zizmor)`)
|
|
110
|
+
} else {
|
|
111
|
+
fail(`${zizmorPath}: додай policies ref-pin для unpinned-uses (ga.mdc)`)
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
fail(`Відсутній ${zizmorPath} — потрібен для zizmor (ga.mdc)`)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (existsSync('package.json')) {
|
|
118
|
+
const pkg = JSON.parse(await readFile('package.json', 'utf8'))
|
|
119
|
+
const lg = pkg.scripts?.['lint-ga']
|
|
120
|
+
if (typeof lg === 'string') {
|
|
121
|
+
pass('package.json містить lint-ga')
|
|
122
|
+
if (lg.includes('node-actionlint')) {
|
|
123
|
+
pass('lint-ga викликає node-actionlint')
|
|
124
|
+
} else {
|
|
125
|
+
fail('lint-ga має містити bunx node-actionlint (ga.mdc)')
|
|
126
|
+
}
|
|
127
|
+
if (lg.includes('zizmor') && lg.includes('--offline')) {
|
|
128
|
+
pass('lint-ga викликає zizmor з --offline')
|
|
129
|
+
} else {
|
|
130
|
+
fail('lint-ga має містити zizmor і --offline (ga.mdc)')
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
fail('package.json: додай скрипт "lint-ga" (ga.mdc)')
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
fail('package.json не існує — потрібен lint-ga у scripts')
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const lintGaWf = join(wfDir, 'lint-ga.yml')
|
|
140
|
+
if (existsSync(lintGaWf)) {
|
|
141
|
+
const lgContent = await readFile(lintGaWf, 'utf8')
|
|
142
|
+
if (lgContent.includes('bun run lint-ga')) {
|
|
143
|
+
pass('lint-ga.yml викликає bun run lint-ga')
|
|
144
|
+
} else {
|
|
145
|
+
fail('lint-ga.yml: крок має містити bun run lint-ga')
|
|
146
|
+
}
|
|
147
|
+
if (lgContent.includes('astral-sh/setup-uv')) {
|
|
148
|
+
pass('lint-ga.yml містить astral-sh/setup-uv')
|
|
149
|
+
} else {
|
|
150
|
+
fail('lint-ga.yml: додай astral-sh/setup-uv для uvx zizmor (ga.mdc)')
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
70
154
|
return exitCode
|
|
71
155
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Перевіряє лінт JavaScript за правилом js-lint.mdc.
|
|
3
|
+
*
|
|
4
|
+
* Flat ESLint, скрипт `lint-js` (oxlint, eslint, jscpd), `engines.node`, без prettier,
|
|
5
|
+
* наявність `.jscpd.json` і workflow `lint-js.yml`.
|
|
6
|
+
*/
|
|
1
7
|
import { existsSync } from 'node:fs'
|
|
2
8
|
import { readFile } from 'node:fs/promises'
|
|
3
9
|
|
|
@@ -27,15 +33,43 @@ export async function check() {
|
|
|
27
33
|
|
|
28
34
|
if (pkg.scripts?.['lint-js']) {
|
|
29
35
|
pass('package.json містить скрипт lint-js')
|
|
30
|
-
|
|
36
|
+
const lintJs = String(pkg.scripts['lint-js'])
|
|
37
|
+
if (lintJs.includes('jscpd')) {
|
|
31
38
|
pass('lint-js містить jscpd')
|
|
32
39
|
} else {
|
|
33
40
|
fail('lint-js має викликати jscpd — додай "&& bunx jscpd ." у кінець скрипта')
|
|
34
41
|
}
|
|
42
|
+
if (lintJs.includes('bunx eslint')) {
|
|
43
|
+
pass('lint-js викликає bunx eslint')
|
|
44
|
+
} else {
|
|
45
|
+
fail('lint-js має містити bunx eslint (n-js-lint.mdc)')
|
|
46
|
+
}
|
|
47
|
+
if (lintJs.includes('bunx jscpd')) {
|
|
48
|
+
pass('lint-js викликає bunx jscpd')
|
|
49
|
+
} else {
|
|
50
|
+
fail('lint-js має містити bunx jscpd (n-js-lint.mdc)')
|
|
51
|
+
}
|
|
52
|
+
if (lintJs.includes('oxlint')) {
|
|
53
|
+
pass('lint-js містить oxlint')
|
|
54
|
+
} else {
|
|
55
|
+
fail('lint-js має містити oxlint (n-js-lint.mdc)')
|
|
56
|
+
}
|
|
35
57
|
} else {
|
|
36
58
|
fail('package.json не містить скрипт "lint-js" — додай: "oxlint --fix && bunx eslint --fix . && bunx jscpd ."')
|
|
37
59
|
}
|
|
38
60
|
|
|
61
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
62
|
+
if (allDeps.prettier) {
|
|
63
|
+
fail('package.json: видали залежність prettier (oxfmt замість prettier, n-js-lint.mdc)')
|
|
64
|
+
} else {
|
|
65
|
+
pass('package.json не містить prettier')
|
|
66
|
+
}
|
|
67
|
+
if (allDeps['@nitra/prettier-config']) {
|
|
68
|
+
fail('package.json: видали @nitra/prettier-config (n-js-lint.mdc)')
|
|
69
|
+
} else {
|
|
70
|
+
pass('package.json не містить @nitra/prettier-config')
|
|
71
|
+
}
|
|
72
|
+
|
|
39
73
|
if (pkg.devDependencies?.['@nitra/eslint-config']) {
|
|
40
74
|
pass('@nitra/eslint-config є в devDependencies')
|
|
41
75
|
} else {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Для кожного workspace-пакета перевіряє правило js-pino.mdc.
|
|
3
|
+
*
|
|
4
|
+
* Заборона bunyan на користь pino та наявність `OTEL_RESOURCE_ATTRIBUTES` у `k8s/base/configmap.yaml`,
|
|
5
|
+
* якщо такий файл існує.
|
|
6
|
+
*/
|
|
1
7
|
import { existsSync } from 'node:fs'
|
|
2
8
|
import { readFile } from 'node:fs/promises'
|
|
3
9
|
import { join } from 'node:path'
|
|
@@ -34,9 +40,7 @@ async function checkWorkspacePackage(rootDir, fail) {
|
|
|
34
40
|
if (content.includes('service.name=') && content.includes('service.namespace=')) {
|
|
35
41
|
pass(`${label}OTEL_RESOURCE_ATTRIBUTES містить service.name та service.namespace`)
|
|
36
42
|
} else {
|
|
37
|
-
fail(
|
|
38
|
-
`${label}OTEL_RESOURCE_ATTRIBUTES має містити service.name=<name>,service.namespace=<namespace>`
|
|
39
|
-
)
|
|
43
|
+
fail(`${label}OTEL_RESOURCE_ATTRIBUTES має містити service.name=<name>,service.namespace=<namespace>`)
|
|
40
44
|
}
|
|
41
45
|
} else {
|
|
42
46
|
fail(`${label}k8s/base/configmap.yaml не містить OTEL_RESOURCE_ATTRIBUTES`)
|
|
@@ -59,9 +63,7 @@ export async function check() {
|
|
|
59
63
|
const workspaceRoots = roots.filter(r => r !== '.')
|
|
60
64
|
|
|
61
65
|
if (workspaceRoots.length === 0) {
|
|
62
|
-
pass(
|
|
63
|
-
'js-pino: немає workspace-пакетів у кореневому package.json — перевірку залежностей і k8s у пакетах пропущено'
|
|
64
|
-
)
|
|
66
|
+
pass('js-pino: немає workspace-пакетів у кореневому package.json — перевірку залежностей і k8s у пакетах пропущено')
|
|
65
67
|
return exitCode
|
|
66
68
|
}
|
|
67
69
|
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Перевіряє шаблон nginx за правилом nginx-default-tpl.mdc.
|
|
3
|
+
*
|
|
4
|
+
* Правильна назва файлу, `listen 8080`, `/healthz`, `gzip_static`, без `proxy_pass` у шаблоні,
|
|
5
|
+
* рекомендації VSCode для nginx.
|
|
6
|
+
*/
|
|
1
7
|
import { existsSync } from 'node:fs'
|
|
2
8
|
import { readFile } from 'node:fs/promises'
|
|
3
9
|
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Перевіряє структуру npm-модуля в монорепо за правилом npm-module.mdc.
|
|
3
|
+
*
|
|
4
|
+
* Workspace `npm/`, `npm/package.json`, workflow `npm-publish.yml` з OIDC і шляхом до пакета.
|
|
5
|
+
*/
|
|
1
6
|
import { existsSync } from 'node:fs'
|
|
2
7
|
import { readFile, stat } from 'node:fs/promises'
|
|
3
8
|
|
|
@@ -53,5 +58,28 @@ export async function check() {
|
|
|
53
58
|
fail('.github/workflows/ не існує')
|
|
54
59
|
}
|
|
55
60
|
|
|
61
|
+
const publishWf = '.github/workflows/npm-publish.yml'
|
|
62
|
+
if (existsSync(publishWf)) {
|
|
63
|
+
pass(`${publishWf} існує`)
|
|
64
|
+
const pub = await readFile(publishWf, 'utf8')
|
|
65
|
+
const need = [
|
|
66
|
+
{ sub: 'npm/**', msg: `${publishWf}: у on.push.paths має бути npm/**` },
|
|
67
|
+
{ sub: 'branches:', msg: `${publishWf}: очікується on.push.branches` },
|
|
68
|
+
{ sub: 'main', msg: `${publishWf}: очікується branch main` },
|
|
69
|
+
{ sub: 'id-token: write', msg: `${publishWf}: permissions має містити id-token: write (OIDC)` },
|
|
70
|
+
{ sub: 'JS-DevTools/npm-publish', msg: `${publishWf}: очікується uses: JS-DevTools/npm-publish` },
|
|
71
|
+
{ sub: 'package: npm/package.json', msg: `${publishWf}: with.package має бути npm/package.json` }
|
|
72
|
+
]
|
|
73
|
+
for (const { sub, msg } of need) {
|
|
74
|
+
if (pub.includes(sub)) {
|
|
75
|
+
pass(`${publishWf} містить «${sub}»`)
|
|
76
|
+
} else {
|
|
77
|
+
fail(msg)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
fail(`Відсутній ${publishWf} (npm-module.mdc: npm publish)`)
|
|
82
|
+
}
|
|
83
|
+
|
|
56
84
|
return exitCode
|
|
57
85
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Перевіряє CSS/SCSS лінт за правилом style-lint.mdc.
|
|
3
|
+
*
|
|
4
|
+
* `@nitra/stylelint-config`, скрипт `lint-style`, `.stylelintignore`, workflow `lint-style.yml`,
|
|
5
|
+
* VSCode stylelint і вимкнена вбудована CSS-валідація.
|
|
6
|
+
*/
|
|
1
7
|
import { existsSync } from 'node:fs'
|
|
2
8
|
import { readFile } from 'node:fs/promises'
|
|
3
9
|
|
package/scripts/check-text.mjs
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Перевіряє текстовий стек за правилом text.mdc.
|
|
3
|
+
*
|
|
4
|
+
* cspell, markdownlint-cli2, скрипт `lint-text` з чотирма викликами v8r, workflow `lint-text.yml`,
|
|
5
|
+
* розширення VSCode для markdownlint.
|
|
6
|
+
*/
|
|
1
7
|
import { existsSync } from 'node:fs'
|
|
2
8
|
import { readFile } from 'node:fs/promises'
|
|
3
9
|
|
|
@@ -90,7 +96,7 @@ export async function check() {
|
|
|
90
96
|
if (devDeps['markdownlint-cli2']) {
|
|
91
97
|
pass('markdownlint-cli2 є в devDependencies')
|
|
92
98
|
} else {
|
|
93
|
-
fail('markdownlint-cli2 відсутній — bun add -d markdownlint-cli2')
|
|
99
|
+
fail('markdownlint-cli2 відсутній — bun add -d markdownlint-cli2 (n-text.mdc)')
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
const lintText = pkg.scripts?.['lint-text']
|
|
@@ -99,7 +105,7 @@ export async function check() {
|
|
|
99
105
|
if (
|
|
100
106
|
typeof lintText === 'string' &&
|
|
101
107
|
lintText.includes('cspell') &&
|
|
102
|
-
lintText.includes('markdownlint-cli2') &&
|
|
108
|
+
lintText.includes('bunx markdownlint-cli2') &&
|
|
103
109
|
lintText.includes('**/*.mdc') &&
|
|
104
110
|
v8rCalls >= 4 &&
|
|
105
111
|
eq98Hints >= 4 &&
|
package/scripts/check-vue.mjs
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Знаходить пакети з `vue` у dependencies і перевіряє їх за правилом vue.mdc.
|
|
3
|
+
*
|
|
4
|
+
* Версії Vite та плагінів, vue-macros, auto-import, layouts, вміст `vite.config`;
|
|
5
|
+
* у репозиторії — рекомендацію розширення Vue.volar.
|
|
6
|
+
*/
|
|
1
7
|
import { existsSync } from 'node:fs'
|
|
2
8
|
import { readFile } from 'node:fs/promises'
|
|
3
9
|
import { join } from 'node:path'
|
|
@@ -125,9 +131,7 @@ export async function check() {
|
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
if (vueRoots.length === 0) {
|
|
128
|
-
fail(
|
|
129
|
-
'vue не знайдено в dependencies жодного пакета (корінь репо та каталоги з кореневого workspaces)'
|
|
130
|
-
)
|
|
134
|
+
fail('vue не знайдено в dependencies жодного пакета (корінь репо та каталоги з кореневого workspaces)')
|
|
131
135
|
return exitCode
|
|
132
136
|
}
|
|
133
137
|
|
package/scripts/utils/pass.mjs
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Допоміжний модуль для скриптів перевірки монорепо.
|
|
3
|
+
*
|
|
4
|
+
* Зчитує кореневий `package.json` і повертає список каталогів-пакетів (корінь `.` плюс шляхи
|
|
5
|
+
* з `workspaces`, з урахуванням glob).
|
|
6
|
+
*/
|
|
1
7
|
import { existsSync } from 'node:fs'
|
|
2
8
|
import { glob, readFile } from 'node:fs/promises'
|
|
3
9
|
import { dirname, join, relative } from 'node:path'
|