@nitra/cursor 1.0.12 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,21 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * @nitra/cursor CLI
4
+ * nitra-cursor CLI завантаження правил
5
5
  *
6
- * Завантажує cursor-правила з npm-пакету @nitra/cursor у локальний репозиторій.
6
+ * Завантажує cursor-правила з npm-пакету nitra-cursor у локальний репозиторій.
7
7
  *
8
8
  * Використання:
9
9
  * npx @nitra/cursor
10
10
  *
11
- * Перед запуском у цільовому репо потрібно створити файл nitra-cursor.json
12
- * зі списком правил для завантаження.
11
+ * Якщо у корені репозиторію немає nitra-cursor.json, він створюється автоматично
12
+ * з усіма правилами з каталогу mdc пакету (їх можна відредагувати після створення).
13
13
  */
14
14
 
15
- import { readFile, writeFile, mkdir } from 'node:fs/promises'
16
15
  import { existsSync } from 'node:fs'
17
- import { join, basename } from 'node:path'
16
+ import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises'
17
+ import { basename, dirname, join } from 'node:path'
18
18
  import { cwd } from 'node:process'
19
+ import { fileURLToPath } from 'node:url'
19
20
 
20
21
  const PACKAGE_NAME = '@nitra/cursor'
21
22
  const UNPKG_BASE = 'https://unpkg.com'
@@ -23,10 +24,36 @@ const CONFIG_FILE = 'nitra-cursor.json'
23
24
  const RULES_DIR = '.cursor/rules'
24
25
  const RULE_PREFIX = 'nitra-'
25
26
 
27
+ const binDir = dirname(fileURLToPath(import.meta.url))
28
+ const BUNDLED_MDC_DIR = join(binDir, '..', 'mdc')
29
+
30
+ /**
31
+ * Імена правил (без .mdc) з каталогу mdc поточної інсталяції пакету
32
+ * @returns {Promise<string[]>} відсортовані імена файлів правил без суфікса .mdc
33
+ */
34
+ async function discoverBundledRuleNames() {
35
+ if (!existsSync(BUNDLED_MDC_DIR)) {
36
+ throw new Error(
37
+ `Не знайдено каталог правил пакету.\n` +
38
+ `Очікуваний шлях: ${BUNDLED_MDC_DIR}\n` +
39
+ `Перевстановіть ${PACKAGE_NAME} або створіть ${CONFIG_FILE} вручну.`
40
+ )
41
+ }
42
+ const names = await readdir(BUNDLED_MDC_DIR)
43
+ const rules = names
44
+ .filter(n => n.endsWith('.mdc'))
45
+ .map(n => n.slice(0, -'.mdc'.length))
46
+ .sort((a, b) => a.localeCompare(b))
47
+ if (rules.length === 0) {
48
+ throw new Error(`У каталозі mdc пакету немає файлів .mdc. Створіть ${CONFIG_FILE} вручну.`)
49
+ }
50
+ return rules
51
+ }
52
+
26
53
  /**
27
54
  * Завантажує текст з URL
28
- * @param {string} url
29
- * @returns {Promise<string>}
55
+ * @param {string} url адреса HTTP(S)
56
+ * @returns {Promise<string>} тіло відповіді як UTF-8 текст
30
57
  */
31
58
  async function fetchText(url) {
32
59
  const response = await fetch(url)
@@ -38,17 +65,18 @@ async function fetchText(url) {
38
65
 
39
66
  /**
40
67
  * Зчитує конфіг nitra-cursor.json з поточної директорії
41
- * @returns {Promise<{rules: string[], version?: string}>}
68
+ * @returns {Promise<{rules: string[], version?: string}>} об'єкт з масивом rules і опційно version; при відсутності файлу створює дефолтний конфіг
42
69
  */
43
70
  async function readConfig() {
44
71
  const configPath = join(cwd(), CONFIG_FILE)
45
72
  if (!existsSync(configPath)) {
46
- throw new Error(
47
- `Файл конфігурації не знайдено: ${CONFIG_FILE}\n` +
48
- `Створіть файл ${CONFIG_FILE} у корені репозиторію.\n` +
49
- `Приклад:\n` +
50
- `{\n "rules": ["js-format", "npm-module", "spell"]\n}`
73
+ const rules = await discoverBundledRuleNames()
74
+ const defaultConfig = { rules }
75
+ await writeFile(configPath, `${JSON.stringify(defaultConfig, null, 2)}\n`, 'utf8')
76
+ console.log(
77
+ `📝 Створено ${CONFIG_FILE} з усіма правилами з пакету (${rules.length}). ` + `За потреби відредагуйте список.\n`
51
78
  )
79
+ return defaultConfig
52
80
  }
53
81
  const raw = await readFile(configPath, 'utf8')
54
82
  let config
@@ -65,9 +93,9 @@ async function readConfig() {
65
93
 
66
94
  /**
67
95
  * Повертає URL для завантаження правила з unpkg
68
- * @param {string} ruleName ім'я без розширення, наприклад "js-format"
69
- * @param {string} [version] версія пакету (необов'язково, за замовчуванням "latest")
70
- * @returns {string}
96
+ * @param {string} ruleName - ім'я без розширення, наприклад "js-format"
97
+ * @param {string} [version] - версія пакету (необов'язково, за замовчуванням "latest")
98
+ * @returns {string} повний URL файлу правила на unpkg
71
99
  */
72
100
  function buildUrl(ruleName, version) {
73
101
  const name = ruleName.endsWith('.mdc') ? ruleName : `${ruleName}.mdc`
@@ -79,63 +107,59 @@ function buildUrl(ruleName, version) {
79
107
  * Витягує чисте ім'я файлу правила (без шляху, але зберігає .mdc)
80
108
  * "npm/mdc/js-format.mdc" → "js-format.mdc"
81
109
  * "js-format" → "js-format.mdc"
82
- * @param {string} ruleName
83
- * @returns {string}
110
+ * @param {string} ruleName шлях або базове ім'я, з суфіксом .mdc або без
111
+ * @returns {string} лише ім'я файлу з суфіксом .mdc
84
112
  */
85
113
  function normalizeRuleName(ruleName) {
86
114
  const name = ruleName.endsWith('.mdc') ? ruleName : `${ruleName}.mdc`
87
115
  return basename(name)
88
116
  }
89
117
 
90
- async function main() {
91
- console.log(`\n🔧 @nitra/cursor — завантаження cursor-правил\n`)
118
+ console.log(`\n🔧 @nitra/cursor — завантаження cursor-правил\n`)
92
119
 
93
- // 1. Зчитуємо конфіг
94
- let config
95
- try {
96
- config = await readConfig()
97
- } catch (err) {
98
- console.error(`❌ ${err.message}`)
99
- process.exit(1)
100
- }
120
+ // 1. Зчитуємо конфіг
121
+ let config
122
+ try {
123
+ config = await readConfig()
124
+ } catch (error) {
125
+ console.error(`❌ ${error.message}`)
126
+ process.exit(1)
127
+ }
101
128
 
102
- const { rules, version } = config
103
- if (version) {
104
- console.log(`📦 Версія пакету: ${version}`)
105
- }
106
- console.log(`📋 Правил до завантаження: ${rules.length}`)
107
-
108
- // 2. Створюємо директорію .cursor/rules якщо не існує
109
- const rulesDir = join(cwd(), RULES_DIR)
110
- await mkdir(rulesDir, { recursive: true })
111
-
112
- // 3. Завантажуємо та зберігаємо кожне правило
113
- let successCount = 0
114
- let failCount = 0
115
-
116
- for (const rule of rules) {
117
- const url = buildUrl(rule, version)
118
- const fileName = `${RULE_PREFIX}${normalizeRuleName(rule)}`
119
- const destPath = join(rulesDir, fileName)
120
-
121
- try {
122
- process.stdout.write(` ⬇ ${rule} → ${RULES_DIR}/${fileName} ... `)
123
- const content = await fetchText(url)
124
- await writeFile(destPath, content, 'utf8')
125
- console.log(`✅`)
126
- successCount++
127
- } catch (err) {
128
- console.log(`❌`)
129
- console.error(` Помилка: ${err.message}`)
130
- failCount++
131
- }
132
- }
129
+ const { rules, version } = config
130
+ if (version) {
131
+ console.log(`📦 Версія пакету: ${version}`)
132
+ }
133
+ console.log(`📋 Правил до завантаження: ${rules.length}`)
133
134
 
134
- // 4. Підсумок
135
- console.log(`\n✨ Готово: ${successCount} завантажено, ${failCount} з помилками\n`)
136
- if (failCount > 0) {
137
- process.exit(1)
135
+ // 2. Створюємо директорію .cursor/rules якщо не існує
136
+ const rulesDir = join(cwd(), RULES_DIR)
137
+ await mkdir(rulesDir, { recursive: true })
138
+
139
+ // 3. Завантажуємо та зберігаємо кожне правило
140
+ let successCount = 0
141
+ let failCount = 0
142
+
143
+ for (const rule of rules) {
144
+ const url = buildUrl(rule, version)
145
+ const fileName = `${RULE_PREFIX}${normalizeRuleName(rule)}`
146
+ const destPath = join(rulesDir, fileName)
147
+
148
+ try {
149
+ process.stdout.write(` ⬇ ${rule} → ${RULES_DIR}/${fileName} ... `)
150
+ const content = await fetchText(url)
151
+ await writeFile(destPath, content, 'utf8')
152
+ console.log(`✅`)
153
+ successCount++
154
+ } catch (error) {
155
+ console.log(`❌`)
156
+ console.error(` Помилка: ${error.message}`)
157
+ failCount++
138
158
  }
139
159
  }
140
160
 
141
- main()
161
+ // 4. Підсумок
162
+ console.log(`\n✨ Готово: ${successCount} завантажено, ${failCount} з помилками\n`)
163
+ if (failCount > 0) {
164
+ process.exit(1)
165
+ }
package/mdc/js-format.mdc CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  description: Правила форматів JavaScript ecosystem
3
3
  alwaysApply: true
4
- version: '1.1'
4
+ version: '1.2'
5
5
  ---
6
6
 
7
7
  В корені проекту є файл з правилами форматування для oxfmt:
@@ -94,4 +94,6 @@ version: '1.1'
94
94
  }
95
95
  ```
96
96
 
97
- Також потрібно прибрати якщо є в проекті модул @nitra/prettier-config та prettier та всі виклики prettier і налаштування для нього.
97
+ Також потрібно прибрати якщо є в проекті модул @nitra/prettier-config та prettier та всі виклики prettier і налаштування для нього.
98
+
99
+ Завжди пиши JSDoc до функцій та методів.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.0.12",
3
+ "version": "1.1.0",
4
4
  "description": "CLI для завантаження cursor-правил Nitra у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",