@nitra/cursor 1.8.143 → 1.8.144
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/mdc/vue.mdc +2 -1
- package/package.json +1 -1
- package/scripts/check-vue.mjs +116 -12
package/mdc/vue.mdc
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Vue
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.3'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Vue 3 Composition API — правила для .cursorrules
|
|
@@ -111,6 +111,7 @@ const additionalInstructions = `
|
|
|
111
111
|
- Якість коду: **ESLint** + **eslint-plugin-vue**; форматування — **oxfmt**, див. `text.mdc`.
|
|
112
112
|
- Збірка та dev-сервер — **Vite**
|
|
113
113
|
- **Vue Devtools** для дебагу; продакшен-збірка — **`vite build`**, оптимізація асетів і кешування на рівні деплою / CDN.
|
|
114
|
+
- **esbuild заборонено:** у проєкті не має бути залежності `esbuild` і згадок `esbuild` у конфігах/коді. Якщо десь є налаштування або інструкції під `esbuild` — заміни на **rolldown**.
|
|
114
115
|
|
|
115
116
|
### CI/CD
|
|
116
117
|
|
package/package.json
CHANGED
package/scripts/check-vue.mjs
CHANGED
|
@@ -24,6 +24,98 @@ import { walkDir } from './utils/walkDir.mjs'
|
|
|
24
24
|
import { getMonorepoPackageRootDirs } from './utils/workspaces.mjs'
|
|
25
25
|
|
|
26
26
|
const MAJOR_VERSION_RE = /(\d+)/
|
|
27
|
+
const ESBUILD_RE = /\besbuild\b/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Визначає, чи можна сканувати файл як текст на згадки `esbuild`.
|
|
31
|
+
* @param {string} relPosix відносний шлях у posix-форматі
|
|
32
|
+
* @returns {boolean} true якщо файл варто перевірити
|
|
33
|
+
*/
|
|
34
|
+
function isEsbuildScanFile(relPosix) {
|
|
35
|
+
if (
|
|
36
|
+
relPosix.startsWith('node_modules/') ||
|
|
37
|
+
relPosix.startsWith('dist/') ||
|
|
38
|
+
relPosix.startsWith('build/') ||
|
|
39
|
+
relPosix.startsWith('coverage/') ||
|
|
40
|
+
relPosix.startsWith('.git/')
|
|
41
|
+
) {
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const lower = relPosix.toLowerCase()
|
|
46
|
+
if (
|
|
47
|
+
lower === 'bun.lock' ||
|
|
48
|
+
lower === 'bun.lockb' ||
|
|
49
|
+
lower === 'package-lock.json' ||
|
|
50
|
+
lower === 'yarn.lock' ||
|
|
51
|
+
lower === 'pnpm-lock.yaml'
|
|
52
|
+
) {
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
lower.endsWith('.js') ||
|
|
58
|
+
lower.endsWith('.mjs') ||
|
|
59
|
+
lower.endsWith('.cjs') ||
|
|
60
|
+
lower.endsWith('.ts') ||
|
|
61
|
+
lower.endsWith('.tsx') ||
|
|
62
|
+
lower.endsWith('.vue') ||
|
|
63
|
+
lower.endsWith('.json') ||
|
|
64
|
+
lower.endsWith('.jsonc') ||
|
|
65
|
+
lower.endsWith('.yaml') ||
|
|
66
|
+
lower.endsWith('.yml') ||
|
|
67
|
+
lower.endsWith('.md') ||
|
|
68
|
+
lower.endsWith('.mdc')
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Сканує дерево пакета на згадки `esbuild` і підказує заміну на `rolldown`.
|
|
74
|
+
* @param {string} rootDir відносний шлях до пакета
|
|
75
|
+
* @param {string} absPackageRoot абсолютний шлях до кореня пакета
|
|
76
|
+
* @param {string} prefix параметр prefix
|
|
77
|
+
* @param {(msg: string) => void} passFn callback при успішній перевірці
|
|
78
|
+
* @param {(msg: string) => void} fail callback при помилці
|
|
79
|
+
*/
|
|
80
|
+
async function checkEsbuildMentions(rootDir, absPackageRoot, prefix, passFn, fail) {
|
|
81
|
+
/** @type {{ rel: string; line: number; snippet: string }[]} */
|
|
82
|
+
const hits = []
|
|
83
|
+
|
|
84
|
+
await walkDir(absPackageRoot, absPath => {
|
|
85
|
+
const rel = relative(absPackageRoot, absPath).split('\\').join('/')
|
|
86
|
+
if (!isEsbuildScanFile(rel)) return
|
|
87
|
+
hits.push({ rel, line: 0, snippet: '' })
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// ми використали hits як буфер шляхів; зараз перетворимо на реальні співпадіння
|
|
91
|
+
/** @type {{ rel: string; line: number; snippet: string }[]} */
|
|
92
|
+
const matches = []
|
|
93
|
+
for (const { rel } of hits) {
|
|
94
|
+
const content = await readFile(join(absPackageRoot, rel), 'utf8')
|
|
95
|
+
if (!ESBUILD_RE.test(content)) continue
|
|
96
|
+
|
|
97
|
+
const lines = content.split('\n')
|
|
98
|
+
for (let i = 0; i < lines.length; i++) {
|
|
99
|
+
if (ESBUILD_RE.test(lines[i])) {
|
|
100
|
+
matches.push({ rel, line: i + 1, snippet: lines[i].trim() })
|
|
101
|
+
if (matches.length >= 30) break
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (matches.length >= 30) break
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (matches.length === 0) {
|
|
108
|
+
passFn(`${prefix}немає згадок 'esbuild' у джерелах пакета (очікується rolldown)`)
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for (const m of matches) {
|
|
113
|
+
fail(`${prefix}${m.rel}:${m.line} — знайдено 'esbuild'. Замінити на 'rolldown'. Фрагмент: ${m.snippet}`)
|
|
114
|
+
}
|
|
115
|
+
if (matches.length >= 30) {
|
|
116
|
+
fail(`${prefix}показано перші 30 збігів 'esbuild' (замінити на 'rolldown')`)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
27
119
|
|
|
28
120
|
/**
|
|
29
121
|
* Формує зрозумілий для людини підпис пакета для повідомлень перевірки.
|
|
@@ -107,6 +199,9 @@ async function checkViteConfig(rootDir, prefix, passFn, fail) {
|
|
|
107
199
|
return
|
|
108
200
|
}
|
|
109
201
|
const content = await readFile(join(rootDir, viteConfig), 'utf8')
|
|
202
|
+
if (ESBUILD_RE.test(content)) {
|
|
203
|
+
fail(`${prefix}${viteConfig} містить 'esbuild' — заміни на 'rolldown'`)
|
|
204
|
+
}
|
|
110
205
|
const checks = [
|
|
111
206
|
{ token: 'VueMacros', ok: `${viteConfig} використовує VueMacros`, err: `${viteConfig} не містить VueMacros` },
|
|
112
207
|
{ token: 'AutoImport', ok: `${viteConfig} використовує AutoImport`, err: `${viteConfig} не містить AutoImport` }
|
|
@@ -175,6 +270,10 @@ async function checkVuePackage(rootDir, fail, passFn) {
|
|
|
175
270
|
const devDeps = pkg.devDependencies || {}
|
|
176
271
|
const allDeps = { ...deps, ...devDeps }
|
|
177
272
|
|
|
273
|
+
if (allDeps.esbuild) {
|
|
274
|
+
fail(`${prefix}esbuild заборонено (знайдено: ${allDeps.esbuild}). Замінити на rolldown та прибрати esbuild.`)
|
|
275
|
+
}
|
|
276
|
+
|
|
178
277
|
checkRequiredDep(deps, 'vue', prefix, passFn, fail, 'vue відсутній в dependencies')
|
|
179
278
|
checkViteVersion(devDeps, prefix, passFn, fail)
|
|
180
279
|
checkRequiredDep(
|
|
@@ -205,6 +304,7 @@ async function checkVuePackage(rootDir, fail, passFn) {
|
|
|
205
304
|
|
|
206
305
|
await checkViteConfig(rootDir, prefix, passFn, fail)
|
|
207
306
|
await checkVueImportViolations(rootDir, join(process.cwd(), rootDir), prefix, passFn, fail)
|
|
307
|
+
await checkEsbuildMentions(rootDir, join(process.cwd(), rootDir), prefix, passFn, fail)
|
|
208
308
|
}
|
|
209
309
|
|
|
210
310
|
/**
|
|
@@ -215,17 +315,6 @@ export async function check() {
|
|
|
215
315
|
const reporter = createCheckReporter()
|
|
216
316
|
const { pass, fail } = reporter
|
|
217
317
|
|
|
218
|
-
if (existsSync('.vscode/extensions.json')) {
|
|
219
|
-
const ext = JSON.parse(await readFile('.vscode/extensions.json', 'utf8'))
|
|
220
|
-
if (ext.recommendations?.includes('Vue.volar')) {
|
|
221
|
-
pass('extensions.json містить Vue.volar')
|
|
222
|
-
} else {
|
|
223
|
-
fail('extensions.json не містить Vue.volar — додай до recommendations')
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
fail('.vscode/extensions.json не існує')
|
|
227
|
-
}
|
|
228
|
-
|
|
229
318
|
const roots = await getMonorepoPackageRootDirs()
|
|
230
319
|
/** @type {string[]} */
|
|
231
320
|
const vueRoots = []
|
|
@@ -237,8 +326,23 @@ export async function check() {
|
|
|
237
326
|
}
|
|
238
327
|
}
|
|
239
328
|
|
|
329
|
+
if (vueRoots.length > 0) {
|
|
330
|
+
if (existsSync('.vscode/extensions.json')) {
|
|
331
|
+
const ext = JSON.parse(await readFile('.vscode/extensions.json', 'utf8'))
|
|
332
|
+
if (ext.recommendations?.includes('Vue.volar')) {
|
|
333
|
+
pass('extensions.json містить Vue.volar')
|
|
334
|
+
} else {
|
|
335
|
+
fail('extensions.json не містить Vue.volar — додай до recommendations')
|
|
336
|
+
}
|
|
337
|
+
} else {
|
|
338
|
+
fail('.vscode/extensions.json не існує (для Vue-проєкту потрібна рекомендація Vue.volar)')
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
pass('Vue.volar: пропущено (у repo немає пакетів з vue у dependencies)')
|
|
342
|
+
}
|
|
343
|
+
|
|
240
344
|
if (vueRoots.length === 0) {
|
|
241
|
-
|
|
345
|
+
pass('vue не знайдено в dependencies жодного пакета (перевірка vue пропущена)')
|
|
242
346
|
return reporter.getExitCode()
|
|
243
347
|
}
|
|
244
348
|
|