@7n/rules-lang-js 0.3.1 → 0.4.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.
- package/CHANGELOG.md +6 -0
- package/package.json +14 -4
- package/rules/bun/bunfig/bunfig.mdc +17 -0
- package/rules/bun/bunfig/bunfig.rego +29 -0
- package/rules/bun/bunfig/concern.json +9 -0
- package/rules/bun/bunfig/template/bunfig.toml.snippet.toml +2 -0
- package/rules/bun/docs/index.md +11 -0
- package/rules/bun/layout/concern.json +16 -0
- package/rules/bun/layout/docs/fix-layout.md +29 -0
- package/rules/bun/layout/docs/main.md +34 -0
- package/rules/bun/layout/fix-layout.mjs +63 -0
- package/rules/bun/layout/layout.mdc +60 -0
- package/rules/bun/layout/main.mjs +53 -0
- package/rules/bun/licensee/concern.json +7 -0
- package/rules/bun/licensee/docs/fix-licensee.md +27 -0
- package/rules/bun/licensee/docs/index.md +12 -0
- package/rules/bun/licensee/docs/main.md +30 -0
- package/rules/bun/licensee/fix-licensee.mjs +31 -0
- package/rules/bun/licensee/main.mjs +68 -0
- package/rules/bun/lint-surface/concern.json +3 -0
- package/rules/bun/lint-surface/lint-surface.mdc +13 -0
- package/rules/bun/main.json +1 -0
- package/rules/bun/main.mdc +11 -0
- package/rules/bun/package_json/concern.json +9 -0
- package/rules/bun/package_json/docs/fix-package_json.md +28 -0
- package/rules/bun/package_json/docs/index.md +9 -0
- package/rules/bun/package_json/fix-package_json.mjs +311 -0
- package/rules/bun/package_json/package_json.mdc +14 -0
- package/rules/bun/package_json/package_json.rego +64 -0
- package/rules/bun/package_json/template/package.json.deny.json +4 -0
- package/rules/js/check/check.mdc +26 -0
- package/rules/js/check/concern.json +19 -0
- package/rules/js/check/docs/eslint-config.md +56 -0
- package/rules/js/check/docs/fix-check.md +48 -0
- package/rules/js/check/docs/index.md +13 -0
- package/rules/js/check/docs/main.md +48 -0
- package/rules/js/check/eslint-config.mjs +262 -0
- package/rules/js/check/fix-check.mjs +82 -0
- package/rules/js/check/main.mjs +310 -0
- package/rules/js/dep-policy/concern.json +4 -0
- package/rules/js/dep-policy/dep-policy.mdc +36 -0
- package/rules/js/dep-policy/docs/main.md +35 -0
- package/rules/js/dep-policy/main.mjs +99 -0
- package/rules/js/docs/index.md +11 -0
- package/rules/js/eslint/concern.json +8 -0
- package/rules/js/eslint/docs/fix-eslint.md +50 -0
- package/rules/js/eslint/docs/fix-worker.md +31 -0
- package/rules/js/eslint/docs/index.md +11 -0
- package/rules/js/eslint/docs/main.md +35 -0
- package/rules/js/eslint/fix-eslint.mjs +160 -0
- package/rules/js/eslint/fix-worker.mjs +139 -0
- package/rules/js/eslint/main.mjs +115 -0
- package/rules/js/file-extensions/concern.json +3 -0
- package/rules/js/file-extensions/file-extensions.mdc +12 -0
- package/rules/js/jscpd_config/concern.json +11 -0
- package/rules/js/jscpd_config/docs/fix-jscpd_config.md +25 -0
- package/rules/js/jscpd_config/docs/index.md +9 -0
- package/rules/js/jscpd_config/fix-jscpd_config.mjs +3 -0
- package/rules/js/jscpd_config/jscpd_config.mdc +42 -0
- package/rules/js/jscpd_config/jscpd_config.rego +44 -0
- package/rules/js/jscpd_config/template/.jscpd.json.snippet.json +7 -0
- package/rules/js/jscpd_duplicates/concern.json +7 -0
- package/rules/js/jscpd_duplicates/docs/main.md +29 -0
- package/rules/js/jscpd_duplicates/main.mjs +69 -0
- package/rules/js/knip/concern.json +7 -0
- package/rules/js/knip/docs/main.md +32 -0
- package/rules/js/knip/knip.mdc +15 -0
- package/rules/js/knip/main.mjs +68 -0
- package/rules/js/lint-findings/concern.json +3 -0
- package/rules/js/lint-findings/docs/main.md +40 -0
- package/rules/js/lint-findings/main.mjs +125 -0
- package/rules/js/main.json +1 -0
- package/rules/js/main.mdc +18 -0
- package/rules/js/package_json/concern.json +9 -0
- package/rules/js/package_json/docs/fix-package_json.md +25 -0
- package/rules/js/package_json/docs/index.md +9 -0
- package/rules/js/package_json/fix-package_json.mjs +3 -0
- package/rules/js/package_json/package_json.mdc +15 -0
- package/rules/js/package_json/package_json.rego +142 -0
- package/rules/js/package_json/template/package.json.snippet.json +6 -0
- package/rules/js/tooling/concern.json +3 -0
- package/rules/js/tooling/data/tooling/knip-canonical.json +30 -0
- package/rules/js/tooling/data/tooling/oxlint-canonical.json +400 -0
- package/rules/js/tooling/docs/main.md +53 -0
- package/rules/js/tooling/main.mjs +183 -0
- package/rules/js/utils_imports/concern.json +4 -0
- package/rules/js/utils_imports/docs/main.md +50 -0
- package/rules/js/utils_imports/main.mjs +185 -0
- package/rules/js/utils_imports/utils_imports.mdc +15 -0
- package/rules/js/vscode_extensions/concern.json +11 -0
- package/rules/js/vscode_extensions/docs/fix-vscode_extensions.md +24 -0
- package/rules/js/vscode_extensions/docs/index.md +11 -0
- package/rules/js/vscode_extensions/fix-vscode_extensions.mjs +1 -0
- package/rules/js/vscode_extensions/template/extensions.json.snippet.json +6 -0
- package/rules/js/vscode_extensions/vscode_extensions.mdc +11 -0
- package/rules/js/vscode_extensions/vscode_extensions.rego +12 -0
- package/rules/js-bun-db/connection/concern.json +3 -0
- package/rules/js-bun-db/connection/connection.mdc +42 -0
- package/rules/js-bun-db/docs/index.md +11 -0
- package/rules/js-bun-db/lib/bun-sql-scan.mjs +1047 -0
- package/rules/js-bun-db/lib/docs/bun-sql-scan.md +63 -0
- package/rules/js-bun-db/lib/docs/index.md +11 -0
- package/rules/js-bun-db/main.json +1 -0
- package/rules/js-bun-db/main.mdc +8 -0
- package/rules/js-bun-db/package_json/concern.json +9 -0
- package/rules/js-bun-db/package_json/package_json.mdc +31 -0
- package/rules/js-bun-db/package_json/package_json.rego +15 -0
- package/rules/js-bun-db/package_json/template/package.json.deny.json +6 -0
- package/rules/js-bun-db/pg_format_identifiers/concern.json +3 -0
- package/rules/js-bun-db/pg_format_identifiers/pg_format_identifiers.mdc +104 -0
- package/rules/js-bun-db/safety/concern.json +4 -0
- package/rules/js-bun-db/safety/docs/main.md +34 -0
- package/rules/js-bun-db/safety/main.mjs +430 -0
- package/rules/js-bun-db/safety/safety.mdc +458 -0
- package/rules/js-bun-redis/docs/index.md +11 -0
- package/rules/js-bun-redis/imports/concern.json +4 -0
- package/rules/js-bun-redis/imports/docs/main.md +36 -0
- package/rules/js-bun-redis/imports/imports.mdc +47 -0
- package/rules/js-bun-redis/imports/main.mjs +88 -0
- package/rules/js-bun-redis/lib/docs/index.md +11 -0
- package/rules/js-bun-redis/lib/docs/redis-imports.md +227 -0
- package/rules/js-bun-redis/lib/redis-imports.mjs +130 -0
- package/rules/js-bun-redis/main.json +1 -0
- package/rules/js-bun-redis/main.mdc +8 -0
- package/rules/js-bun-redis/package_json/concern.json +9 -0
- package/rules/js-bun-redis/package_json/package_json.mdc +11 -0
- package/rules/js-bun-redis/package_json/package_json.rego +15 -0
- package/rules/js-bun-redis/package_json/template/package.json.deny.json +12 -0
- package/rules/js-mssql/deps/concern.json +4 -0
- package/rules/js-mssql/deps/docs/main.md +33 -0
- package/rules/js-mssql/deps/main.mjs +297 -0
- package/rules/js-mssql/docs/index.md +11 -0
- package/rules/js-mssql/lib/docs/index.md +11 -0
- package/rules/js-mssql/lib/docs/mssql-pool-scan.md +380 -0
- package/rules/js-mssql/lib/mssql-pool-scan.mjs +610 -0
- package/rules/js-mssql/main.json +1 -0
- package/rules/js-mssql/main.mdc +144 -0
- package/rules/js-mssql/mssql-tvp/concern.json +3 -0
- package/rules/js-mssql/mssql-tvp/mssql-tvp.mdc +77 -0
- package/rules/js-mssql/package_json/concern.json +9 -0
- package/rules/js-mssql/package_json/package_json.mdc +9 -0
- package/rules/js-mssql/package_json/package_json.rego +57 -0
- package/rules/js-run/configmap/concern.json +9 -0
- package/rules/js-run/configmap/configmap.mdc +37 -0
- package/rules/js-run/configmap/configmap.rego +21 -0
- package/rules/js-run/configmap/template/configmap.yaml.contains.yml +4 -0
- package/rules/js-run/docs/index.md +11 -0
- package/rules/js-run/jsconfig/concern.json +9 -0
- package/rules/js-run/jsconfig/docs/fix-jsconfig.md +28 -0
- package/rules/js-run/jsconfig/docs/index.md +9 -0
- package/rules/js-run/jsconfig/fix-jsconfig.mjs +119 -0
- package/rules/js-run/jsconfig/jsconfig.mdc +48 -0
- package/rules/js-run/jsconfig/jsconfig.rego +59 -0
- package/rules/js-run/jsconfig/template/jsconfig.json.snippet.json +10 -0
- package/rules/js-run/lib/bunyan-imports.mjs +98 -0
- package/rules/js-run/lib/check-env-scan.mjs +338 -0
- package/rules/js-run/lib/conn-file-rules.mjs +214 -0
- package/rules/js-run/lib/conn-imports-scan.mjs +154 -0
- package/rules/js-run/lib/docs/bunyan-imports.md +121 -0
- package/rules/js-run/lib/docs/check-env-scan.md +438 -0
- package/rules/js-run/lib/docs/conn-file-rules.md +304 -0
- package/rules/js-run/lib/docs/conn-imports-scan.md +208 -0
- package/rules/js-run/lib/docs/index.md +16 -0
- package/rules/js-run/lib/docs/promise-settimeout-scan.md +334 -0
- package/rules/js-run/lib/docs/temporal-scan.md +29 -0
- package/rules/js-run/lib/promise-settimeout-scan.mjs +128 -0
- package/rules/js-run/lib/temporal-scan.mjs +52 -0
- package/rules/js-run/main.json +1 -0
- package/rules/js-run/main.mdc +16 -0
- package/rules/js-run/package_json/concern.json +9 -0
- package/rules/js-run/package_json/package_json.mdc +44 -0
- package/rules/js-run/package_json/package_json.rego +37 -0
- package/rules/js-run/package_json/template/package.json.deny.json +22 -0
- package/rules/js-run/project-structure/concern.json +3 -0
- package/rules/js-run/project-structure/project-structure.mdc +11 -0
- package/rules/js-run/runtime/concern.json +12 -0
- package/rules/js-run/runtime/docs/fix-runtime.md +27 -0
- package/rules/js-run/runtime/docs/main.md +35 -0
- package/rules/js-run/runtime/fix-runtime.mjs +46 -0
- package/rules/js-run/runtime/main.mjs +496 -0
- package/rules/js-run/runtime/runtime.mdc +184 -0
- package/rules/js-run/scope/concern.json +3 -0
- package/rules/js-run/scope/scope.mdc +11 -0
- package/rules/npm-module/docs/index.md +11 -0
- package/rules/npm-module/emit_types_config/concern.json +9 -0
- package/rules/npm-module/emit_types_config/docs/fix-emit_types_config.md +25 -0
- package/rules/npm-module/emit_types_config/docs/index.md +9 -0
- package/rules/npm-module/emit_types_config/emit_types_config.mdc +43 -0
- package/rules/npm-module/emit_types_config/emit_types_config.rego +28 -0
- package/rules/npm-module/emit_types_config/fix-emit_types_config.mjs +5 -0
- package/rules/npm-module/emit_types_config/template/tsconfig.emit-types.json.snippet.json +9 -0
- package/rules/npm-module/header_doc_pointer/concern.json +5 -0
- package/rules/npm-module/header_doc_pointer/docs/main.md +40 -0
- package/rules/npm-module/header_doc_pointer/header_doc_pointer.mdc +18 -0
- package/rules/npm-module/header_doc_pointer/main.mjs +131 -0
- package/rules/npm-module/main.json +1 -0
- package/rules/npm-module/main.mdc +36 -0
- package/rules/npm-module/npm_package_json/concern.json +9 -0
- package/rules/npm-module/npm_package_json/docs/fix-npm_package_json.md +26 -0
- package/rules/npm-module/npm_package_json/docs/index.md +9 -0
- package/rules/npm-module/npm_package_json/fix-npm_package_json.mjs +5 -0
- package/rules/npm-module/npm_package_json/npm_package_json.mdc +57 -0
- package/rules/npm-module/npm_package_json/npm_package_json.rego +73 -0
- package/rules/npm-module/npm_package_json/template/package.json.snippet.json +1 -0
- package/rules/npm-module/package_structure/concern.json +5 -0
- package/rules/npm-module/package_structure/docs/main.md +37 -0
- package/rules/npm-module/package_structure/main.mjs +448 -0
- package/rules/npm-module/package_structure/package_structure.mdc +63 -0
- package/rules/npm-module/root_package_json/concern.json +9 -0
- package/rules/npm-module/root_package_json/docs/fix-root_package_json.md +25 -0
- package/rules/npm-module/root_package_json/docs/index.md +9 -0
- package/rules/npm-module/root_package_json/fix-root_package_json.mjs +5 -0
- package/rules/npm-module/root_package_json/root_package_json.mdc +41 -0
- package/rules/npm-module/root_package_json/root_package_json.rego +28 -0
- package/rules/npm-module/root_package_json/template/package.json.snippet.json +1 -0
- package/rules/npm-module/rule_meta/concern.json +8 -0
- package/rules/npm-module/rule_meta/docs/main.md +35 -0
- package/rules/npm-module/rule_meta/main.mjs +119 -0
- package/rules/npm-module/rule_meta/rule_meta.mdc +11 -0
- package/rules/npm-module/skill_meta/concern.json +5 -0
- package/rules/npm-module/skill_meta/docs/main.md +149 -0
- package/rules/npm-module/skill_meta/main.mjs +91 -0
- package/rules/npm-module/skill_meta/skill_meta.mdc +11 -0
- package/rules/tool-surface/docs/index.md +11 -0
- package/rules/tool-surface/main.json +6 -0
- package/rules/tool-surface/main.mdc +72 -0
- package/rules/vue/composition-api/composition-api.mdc +82 -0
- package/rules/vue/composition-api/concern.json +3 -0
- package/rules/vue/docs/index.md +11 -0
- package/rules/vue/lib/docs/index.md +11 -0
- package/rules/vue/lib/docs/vue-forbidden-imports.md +265 -0
- package/rules/vue/lib/vue-forbidden-imports.mjs +240 -0
- package/rules/vue/main.json +1 -0
- package/rules/vue/main.mdc +18 -0
- package/rules/vue/nheader-layout/concern.json +3 -0
- package/rules/vue/nheader-layout/nheader-layout.mdc +171 -0
- package/rules/vue/package_json/concern.json +9 -0
- package/rules/vue/package_json/package_json.mdc +30 -0
- package/rules/vue/package_json/package_json.rego +140 -0
- package/rules/vue/packages/concern.json +6 -0
- package/rules/vue/packages/docs/index.md +11 -0
- package/rules/vue/packages/docs/main.md +35 -0
- package/rules/vue/packages/main.mjs +575 -0
- package/rules/vue/packages/packages.mdc +56 -0
- package/rules/vue/quasar-ui/concern.json +3 -0
- package/rules/vue/quasar-ui/quasar-ui.mdc +32 -0
- package/rules/vue/structure/concern.json +3 -0
- package/rules/vue/structure/structure.mdc +101 -0
- package/rules/vue/testing/concern.json +3 -0
- package/rules/vue/testing/testing.mdc +40 -0
- package/rules/vue/tfm-translations/concern.json +7 -0
- package/rules/vue/tfm-translations/docs/main.md +29 -0
- package/rules/vue/tfm-translations/main.mjs +55 -0
- package/rules/vue/tfm-translations/tfm-translations.mdc +32 -0
- package/rules/vue/vite-config/concern.json +3 -0
- package/rules/vue/vite-config/vite-config.mdc +153 -0
- package/rules/vue/vite-env/concern.json +3 -0
- package/rules/vue/vite-env/vite-env.mdc +61 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
## Структура папок
|
|
2
|
+
|
|
3
|
+
```javascript
|
|
4
|
+
const folderStructure = `
|
|
5
|
+
src/
|
|
6
|
+
components/
|
|
7
|
+
composables/
|
|
8
|
+
views/
|
|
9
|
+
router/
|
|
10
|
+
store/
|
|
11
|
+
assets/
|
|
12
|
+
public/
|
|
13
|
+
App.vue
|
|
14
|
+
main.mjs
|
|
15
|
+
`
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Найменування файлів
|
|
19
|
+
|
|
20
|
+
- **SFC:** імена файлів компонентів у **PascalCase** починаючи з букви N(`NMyWidget.vue`).
|
|
21
|
+
- **Інші JS-модулі:** узгоджено **kebab-case** (`date-utils.mjs`).
|
|
22
|
+
|
|
23
|
+
### Модулі та архітектура
|
|
24
|
+
|
|
25
|
+
- **ES modules** (`import`/`export`), один модуль — одна відповідальність, уникай **circular dependencies**.
|
|
26
|
+
- **Composition** замість успадкування; логіку для повторного використання винось у **composables** (замість зайвих HOC, де це доречно).
|
|
27
|
+
|
|
28
|
+
### Code splitting
|
|
29
|
+
|
|
30
|
+
- **Route-based:** lazy-імпорти в маршрутах (`() => import('...')`) і async components.
|
|
31
|
+
|
|
32
|
+
## Додаткові вказівки
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
const additionalInstructions = `
|
|
36
|
+
1. Використовуй JavaScript
|
|
37
|
+
2. Коректно оголошуй props, emits, defineModel
|
|
38
|
+
3. За потреби використовуй компонент Teleport у Vue 3
|
|
39
|
+
4. Застосовуй Suspense для async components
|
|
40
|
+
5. Реалізуй належний error handling
|
|
41
|
+
6. Дотримуйся Vue 3 style guide і naming conventions
|
|
42
|
+
7. Використовуй Vite для швидкої розробки та збірки
|
|
43
|
+
`
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Детальні вказівки
|
|
47
|
+
|
|
48
|
+
1. **Vue router**: Завжди використовуй Vue router для маршрутизації в проекті версії 5 та його file-based routing.
|
|
49
|
+
2. **Компонент Teleport**: Використовуй Teleport у Vue 3, коли потрібно рендерити поза поточною ієрархією DOM.
|
|
50
|
+
3. **Suspense для async components**: Застосовуй Suspense для асинхронних компонентів і кращого UX.
|
|
51
|
+
4. **Error handling**: Реалізуй глобальний error handling механізмами Vue 3, щоб коректно перехоплювати та обробляти помилки.
|
|
52
|
+
5. **Style guide і naming**: Дотримуйся офіційного Vue 3 style guide і naming conventions для узгодженості кодової бази.
|
|
53
|
+
6. **Vue macros**: Використовуй Vue macros для більш ефективного розробки компонентів.
|
|
54
|
+
7. **Vue Reactivity Transform**: Використовуй Vue Reactivity Transform для змінних в компонентах.
|
|
55
|
+
|
|
56
|
+
## Коментарі в `<template>`
|
|
57
|
+
|
|
58
|
+
Додавай коментарі в `<template>` відповідно до логічного призначення блоку. Коментарі допомагають швидко орієнтуватися в розмітці.
|
|
59
|
+
|
|
60
|
+
```vue
|
|
61
|
+
<template>
|
|
62
|
+
<q-page>
|
|
63
|
+
<!-- ФІЛЬТРИ В ШАПЦІ -->
|
|
64
|
+
<teleport v-if="mounted" to="#header-filters">...</teleport>
|
|
65
|
+
|
|
66
|
+
<!-- ТАБЛИЦЯ -->
|
|
67
|
+
<q-table ... />
|
|
68
|
+
|
|
69
|
+
<!-- ДІАЛОГ РЕДАГУВАННЯ -->
|
|
70
|
+
<n-dialog v-model="editDialog">...</n-dialog>
|
|
71
|
+
</q-page>
|
|
72
|
+
</template>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Pinia store для стану сторінки
|
|
76
|
+
|
|
77
|
+
Зберігай у Pinia store:
|
|
78
|
+
|
|
79
|
+
- вибрані значення фільтрів
|
|
80
|
+
- вибрані для відображення колонки (`NTableColumns`)
|
|
81
|
+
- кількість записів на сторінці (pagination)
|
|
82
|
+
|
|
83
|
+
Називай store за назвою сторінки або компонента — `customerPageStore`, `routePageStore` тощо. На сторінці звертайся до нього через змінну `pageStore`.
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
// store/customerPage.mjs
|
|
87
|
+
export const useCustomerPageStore = defineStore('customerPage', {
|
|
88
|
+
state: () => ({
|
|
89
|
+
filterName: '',
|
|
90
|
+
filterStatus: [],
|
|
91
|
+
columns: [],
|
|
92
|
+
rowsPerPage: 20
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```vue
|
|
98
|
+
<script setup>
|
|
99
|
+
const pageStore = useCustomerPageStore()
|
|
100
|
+
</script>
|
|
101
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
## Тестування Vue-компонентів
|
|
2
|
+
|
|
3
|
+
### Unit + Component / DOM
|
|
4
|
+
|
|
5
|
+
**Vitest** (`vitest`) + **Vue Test Utils** з **happy-dom** як DOM-середовищем. Це канон, узгоджений з `test.mdc` (Stryker з vitest-runner + `perTest`-аналіз покриття). `vitest.config.mjs` повторно використовує `vite.config.js` через `mergeConfig` і перемикає `environment` на `'happy-dom'`:
|
|
6
|
+
|
|
7
|
+
```js title="vitest.config.mjs"
|
|
8
|
+
import { defineConfig, mergeConfig } from 'vitest/config'
|
|
9
|
+
import viteConfig from './vite.config.js'
|
|
10
|
+
|
|
11
|
+
export default mergeConfig(viteConfig, defineConfig({
|
|
12
|
+
test: {
|
|
13
|
+
include: ['**/*.test.{js,mjs}', 'tests/**/*.test.{js,mjs}'],
|
|
14
|
+
environment: 'happy-dom',
|
|
15
|
+
coverage: { provider: 'v8', reporter: ['lcov', 'text-summary'] }
|
|
16
|
+
}
|
|
17
|
+
}))
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`jsdom` не використовуй — happy-dom швидший і достатній для типових Vue-компонентних тестів.
|
|
21
|
+
|
|
22
|
+
У `package.json#scripts` тримай `"test": "vitest run"`; vitest devDeps (`vitest`, `@vitest/coverage-v8`, `@stryker-mutator/vitest-runner`) — у кореневому `devDependencies` (npm-module rule забороняє devDeps у published workspace-у).
|
|
23
|
+
|
|
24
|
+
### Чому цей файл — docs-only
|
|
25
|
+
|
|
26
|
+
Вимога `scripts.test === "vitest run"` і `environment: 'happy-dom'` у `vitest.config` стосується Vue-пакетів, які **вже мають** компонентні тести. Не кожен workspace-пакет з `vue` у `dependencies` зобов'язаний мати компонентні тести на цьому етапі (наприклад, sandbox/demo-пакет для ручного прогону Vite-конфігурації без жодного `*.test.*` файлу) — механічна перевірка `scripts.test`/`vitest.config` для **усіх** таких пакетів дає хибні спрацювання там, де тестів свідомо ще немає. Тому концерн лишається docs-only.
|
|
27
|
+
|
|
28
|
+
Суміжні вимоги вже перевіряються іншими concern-ами: кореневий `devDependencies` з `vitest`/`@vitest/coverage-v8`/`@stryker-mutator/vitest-runner` — концерн `packages` (`checkRootVitestDevDeps`); заборона `jsdom`/`vitest` у самому Vue-пакеті — Rego-концерн `package_json`.
|
|
29
|
+
|
|
30
|
+
### E2E
|
|
31
|
+
|
|
32
|
+
**Playwright** — змістовні сценарії користувацьких потоків.
|
|
33
|
+
|
|
34
|
+
Проекту повинен бути покритий тестами E2E за допомогою Playwright.
|
|
35
|
+
|
|
36
|
+
Вимога E2E-покриття Playwright не перевіряється механічно (немає детермінованого способу оцінити «повноту» покриття користувацьких сценаріїв) — залишається на розсуд ревʼю.
|
|
37
|
+
|
|
38
|
+
### CI/CD
|
|
39
|
+
|
|
40
|
+
У pipeline: **install**, **lint**, **test**, **vite build**; артефакти з продакшен-режиму.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: main.mjs
|
|
4
|
+
resource: plugins/lang-js/rules/vue/tfm-translations/main.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: 84fe5390
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Огляд
|
|
10
|
+
|
|
11
|
+
Модуль перевіряє конвенцію `@nitra/tfm` з `vue.mdc` (розділ tfm-translations): якщо `.vue`-файл іменовано імпортує `tf` з `@nitra/tfm`, у тому ж файлі має бути оголошена функція `getTr`, що повертає обʼєкт перекладів.
|
|
12
|
+
|
|
13
|
+
## Поведінка
|
|
14
|
+
|
|
15
|
+
Per-file lint по змінених `.vue`-файлах (`ctx.files`). Для кожного файлу:
|
|
16
|
+
|
|
17
|
+
- шукає іменований імпорт з `@nitra/tfm`, у списку якого є специфікатор `tf` (з опційним `as <alias>`);
|
|
18
|
+
- якщо такий імпорт знайдено — перевіряє наявність у файлі оголошення `getTr` (`function getTr(...)` або `const/let getTr = ...`); відсутність — порушення.
|
|
19
|
+
|
|
20
|
+
Файли без імпорту `tf` з `@nitra/tfm` (включно з імпортом лише інших експортів модуля, напр. `lang`) не перевіряються. Без `ctx.files` (delta відсутня) перевірка нічого не робить.
|
|
21
|
+
|
|
22
|
+
## Публічний API
|
|
23
|
+
|
|
24
|
+
`lint(ctx)` — detector-функція lint-поверхні: приймає контекст лінту (`cwd`, `files`), повертає список порушень.
|
|
25
|
+
|
|
26
|
+
## Гарантії поведінки
|
|
27
|
+
|
|
28
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
29
|
+
- Перевіряє лише файли з розширенням `.vue`; інші файли зі списку `ctx.files` ігноруються.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** @see ./docs/main.md */
|
|
2
|
+
import { createViolationReporter } from '@7n/rules/scripts/lib/lint-surface/violation-reporter.mjs'
|
|
3
|
+
|
|
4
|
+
/** Іменований імпорт з `@nitra/tfm` — захоплює список імен усередині `{ ... }`. */
|
|
5
|
+
const TFM_IMPORT_RE = /import\s*\{([^}]*)\}\s*from\s*['"]@nitra\/tfm['"]/
|
|
6
|
+
|
|
7
|
+
/** Один запис іменованого імпорту `tf` (з опційним `as <alias>`). */
|
|
8
|
+
const TF_SPECIFIER_RE = /^tf(?:\s+as\s+\w+)?$/
|
|
9
|
+
|
|
10
|
+
/** Оголошення функції `getTr` — `function getTr(...)` або `const/let getTr = (...)`. */
|
|
11
|
+
const GET_TR_DECL_RE = /(?:function\s+getTr\s*\(|(?:const|let|var)\s+getTr\s*=)/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Чи імпортує вміст файлу `tf` (можливо з `as <alias>`) саме з `@nitra/tfm`.
|
|
15
|
+
* @param {string} content вихідний текст файлу
|
|
16
|
+
* @returns {boolean} `true`, якщо знайдено іменований імпорт `tf` з `@nitra/tfm`
|
|
17
|
+
*/
|
|
18
|
+
function importsTfFromTfm(content) {
|
|
19
|
+
const m = TFM_IMPORT_RE.exec(content)
|
|
20
|
+
if (!m) return false
|
|
21
|
+
return m[1].split(',').some(entry => TF_SPECIFIER_RE.test(entry.trim()))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Detector concern-а `tfm-translations`: якщо `.vue`-файл імпортує `tf` з `@nitra/tfm`,
|
|
26
|
+
* у цьому ж файлі має бути оголошена функція `getTr()` з перекладами (vue.mdc tfm-translations).
|
|
27
|
+
* @param {import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту (`ctx.files` — delta-файли).
|
|
28
|
+
* @returns {Promise<import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintResult>} результат з порушеннями.
|
|
29
|
+
*/
|
|
30
|
+
export async function lint(ctx) {
|
|
31
|
+
const reporter = createViolationReporter(ctx)
|
|
32
|
+
const { fail } = reporter
|
|
33
|
+
|
|
34
|
+
if (ctx.files === undefined || ctx.files.length === 0) return reporter.result()
|
|
35
|
+
|
|
36
|
+
const { readFile } = await import('node:fs/promises')
|
|
37
|
+
const { join } = await import('node:path')
|
|
38
|
+
const { existsSync } = await import('node:fs')
|
|
39
|
+
|
|
40
|
+
for (const file of ctx.files) {
|
|
41
|
+
if (!file.endsWith('.vue')) continue
|
|
42
|
+
const absPath = join(ctx.cwd, file)
|
|
43
|
+
if (!existsSync(absPath)) continue
|
|
44
|
+
const content = await readFile(absPath, 'utf8')
|
|
45
|
+
if (!importsTfFromTfm(content)) continue
|
|
46
|
+
if (GET_TR_DECL_RE.test(content)) continue
|
|
47
|
+
fail(
|
|
48
|
+
`${file}: імпортує 'tf' з '@nitra/tfm', але не оголошує функцію getTr() з перекладами ` +
|
|
49
|
+
`(vue.mdc tfm-translations)`,
|
|
50
|
+
{ file }
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return reporter.result()
|
|
55
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
## @nitra/tfm — переклади
|
|
2
|
+
|
|
3
|
+
Використовуй `@nitra/tfm` для всіх текстів. Переклади для всіх мов проекту оголошуй наприкінці `<script setup>` у функції `getTr()`. Змінна `lang` із `@nitra/tfm` — для визначення або зміни поточної мови застосунку.
|
|
4
|
+
|
|
5
|
+
```vue
|
|
6
|
+
<template>
|
|
7
|
+
{{ lang }}
|
|
8
|
+
{{ t`Анкеты` }}
|
|
9
|
+
{{ subtitle }}
|
|
10
|
+
</template>
|
|
11
|
+
<script setup>
|
|
12
|
+
import { lang, tf as tfm } from '@nitra/tfm'
|
|
13
|
+
const t = tfm.bind({ tr: getTr() })
|
|
14
|
+
const subtitle = $computed(() => t`Анкеты`)
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* LOCALIZATION
|
|
18
|
+
* @returns {object} translations
|
|
19
|
+
*/
|
|
20
|
+
function getTr() {
|
|
21
|
+
return {
|
|
22
|
+
Анкеты: { en: 'Surveys', ro: 'Sondaje', tr: 'Anketler' }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
</script>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Перевірка
|
|
29
|
+
|
|
30
|
+
Якщо `.vue`-файл іменовано імпортує `tf` (з опційним `as <alias>`) саме з `@nitra/tfm`, у тому ж файлі має бути оголошена функція `getTr` (`function getTr(...)` або `const/let getTr = ...`). Файли, які не імпортують `tf` з `@nitra/tfm`, не перевіряються.
|
|
31
|
+
|
|
32
|
+
Це лише синтаксична перевірка структури (наявність `getTr` поряд з імпортом `tf`) — вона **не** оцінює повноту чи коректність самих перекладів (усі мови проекту, актуальність рядків тощо), це залишається на розсуд ревʼю.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
## Vite-конфігурація: VueMacros, AutoImport, Layouts
|
|
2
|
+
|
|
3
|
+
Потрібно використовувати **Vite версії 8.1 та вище** для frontend проекту на Vue.
|
|
4
|
+
|
|
5
|
+
Потрібно використовувати **`unplugin-auto-import`** для автоматичного імпортування компонентів, composables, utils та інших функцій і прибирати з файлів усередині Vite проектів відповідні ручні імпорти, зокрема рядки виду `import { … } from 'vue'` — API Vue (`ref`, `computed`, `watch` тощо) мають підставлятися через auto-import, а не дублюватися явним імпортом з модуля `vue`.
|
|
6
|
+
|
|
7
|
+
**Виняток — бібліотеки компонентів (`vue` у `peerDependencies`).** Увесь стек auto-import застосовується лише коли `vue` підключено як звичайну `dependencies`. Якщо ж пакет оголошує `vue` у `peerDependencies` — це проєкт-бібліотека компонентів: його джерела споживаються Vite-додатками і **не** проходять через `unplugin-auto-import` споживача. Тому до таких пакетів **не** застосовуються: заборона явних `import { ref, computed, … } from 'vue'` (вони обовʼязкові), вимога `'vue'` у `AutoImport.imports`, а також вимоги наявності `VueMacros` / `AutoImport` у `vite.config`. Решта перевірок (заборона `esbuild`, `process.env.npm_lifecycle_event` тощо) лишаються. Тригер винятку — `isVueComponentLibraryPkg` у `npm/rules/vue/packages/main.mjs`.
|
|
8
|
+
|
|
9
|
+
Потрібно використовувати **`vite-plugin-vue-layouts-next`** для автоматичного імпортування layout компонентів.
|
|
10
|
+
|
|
11
|
+
### Це вже перевіряється автоматично
|
|
12
|
+
|
|
13
|
+
Увесь зміст цього файлу — вже реалізовані, а не лише документовані, перевірки:
|
|
14
|
+
|
|
15
|
+
- **Обов'язкові залежності** (`vite` мажор ≥ 8 і мінор ≥ 1, `@vitejs/plugin-vue`, `vue-macros`, `unplugin-auto-import`, `vite-plugin-vue-layouts-next`) і **заборона** `esbuild`/`vitest`/`jsdom` у `package.json` — Rego-пакет `vue.package_json` (`npm/rules/vue/package_json/package_json.rego`, концерн `package_json`).
|
|
16
|
+
- **`vite.config.{js,ts,mjs}`**: наявність `VueMacros`, `AutoImport` (і `'vue'` у його `imports`, якщо застосовний), `css: { transformer: 'lightningcss' }`, заборона `esbuild`, заборона `process.env.npm_lifecycle_event` (Bun-сумісність) — JS-концерн `packages` (`npm/rules/vue/packages/main.mjs`, функція `checkViteConfig`).
|
|
17
|
+
- **`.vscode/extensions.json`** з рекомендацією `Vue.volar` — той самий концерн `packages` (`checkVueVolarRecommendation`).
|
|
18
|
+
|
|
19
|
+
Цей concern (`vite-config`) залишається **docs-only** — він не додає нової перевірки, а лише зберігає розгорнутий еталонний приклад `vite.config.js`/`package.json` і пояснення для людини; фактичний gate — вище.
|
|
20
|
+
|
|
21
|
+
### Еталонний `vite.config.js`
|
|
22
|
+
|
|
23
|
+
```javascript title="vite.config.js"
|
|
24
|
+
import Vue from '@vitejs/plugin-vue'
|
|
25
|
+
import VueMacros from 'vue-macros/vite'
|
|
26
|
+
import { defineConfig } from 'vite'
|
|
27
|
+
import AutoImport from 'unplugin-auto-import/vite'
|
|
28
|
+
import Layouts from 'vite-plugin-vue-layouts-next'
|
|
29
|
+
|
|
30
|
+
export default defineConfig({
|
|
31
|
+
plugins: [
|
|
32
|
+
AutoImport({
|
|
33
|
+
imports: [
|
|
34
|
+
// presets
|
|
35
|
+
'vue',
|
|
36
|
+
'vue-router',
|
|
37
|
+
'quasar',
|
|
38
|
+
'pinia',
|
|
39
|
+
// custom
|
|
40
|
+
{
|
|
41
|
+
'@nitra/vite-boot/apollo': [
|
|
42
|
+
// named imports
|
|
43
|
+
'gql',
|
|
44
|
+
'useQuery',
|
|
45
|
+
'useMutation',
|
|
46
|
+
'useSubscription'
|
|
47
|
+
],
|
|
48
|
+
'@nitra/consola': [
|
|
49
|
+
// named imports
|
|
50
|
+
'createLogger' // import { createLogger } from '@nitra/consola'
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}),
|
|
55
|
+
VueMacros({
|
|
56
|
+
plugins: {
|
|
57
|
+
vue: Vue()
|
|
58
|
+
}
|
|
59
|
+
}),
|
|
60
|
+
Layouts()
|
|
61
|
+
]
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### `npm_lifecycle_event` (Bun-сумісність)
|
|
66
|
+
|
|
67
|
+
У більшості проектів у файлі `vite.config.js` є конструкція виду:
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
switch (process.env.npm_lifecycle_event) {
|
|
71
|
+
case 'start-remote-tr': {
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Вона перестала працювати з новим Bun. Тепер її треба обрамити у функцію і передавати `mode`:
|
|
75
|
+
|
|
76
|
+
```javascript title="vite.config.js"
|
|
77
|
+
function getProxy(mode) {
|
|
78
|
+
const proxy = {}
|
|
79
|
+
|
|
80
|
+
switch (mode) {
|
|
81
|
+
case 'remote-tr': {
|
|
82
|
+
proxy['^/auth/.*'] = 'https://tr.efes.cloud'
|
|
83
|
+
proxy['/file-link/'] = 'https://tr.efes.cloud'
|
|
84
|
+
break
|
|
85
|
+
}
|
|
86
|
+
default: {
|
|
87
|
+
proxy['^/auth/.*'] = 'https://dev.efes.cloud'
|
|
88
|
+
proxy['/file-link/'] = 'https://dev.efes.cloud'
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return proxy
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```javascript title="vite.config.js"
|
|
96
|
+
export default defineConfig(({ mode, command }) => {
|
|
97
|
+
// ...
|
|
98
|
+
server: {
|
|
99
|
+
proxy: getProxy(mode)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### CSS-трансформер: lightningcss (обов'язково)
|
|
105
|
+
|
|
106
|
+
У `vite.config` має бути `css: { transformer: 'lightningcss' }`:
|
|
107
|
+
|
|
108
|
+
```javascript title="vite.config.js"
|
|
109
|
+
export default defineConfig({
|
|
110
|
+
css: {
|
|
111
|
+
transformer: 'lightningcss'
|
|
112
|
+
},
|
|
113
|
+
// ...
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Lightningcss ~18% швидше за sass-трансформер на типовому Vue+Quasar-проєкті. Потрібний `lightningcss` у `devDependencies`.
|
|
118
|
+
|
|
119
|
+
**Виняток:** бібліотеки компонентів (`vue` у `peerDependencies`) від цієї вимоги звільнені — вони не збираються напряму.
|
|
120
|
+
|
|
121
|
+
### esbuild заборонено
|
|
122
|
+
|
|
123
|
+
У проєкті не має бути залежності `esbuild` і згадок `esbuild` у конфігах/коді. Якщо десь є налаштування або інструкції під `esbuild` — заміни на **rolldown**.
|
|
124
|
+
|
|
125
|
+
### Еталонний `package.json`
|
|
126
|
+
|
|
127
|
+
мінімальний повний `package.json` для Vite + Vue + `vue-macros` (версії підлаштуй під проєкт):
|
|
128
|
+
|
|
129
|
+
```json title="package.json"
|
|
130
|
+
{
|
|
131
|
+
"name": "my-vue-app",
|
|
132
|
+
"private": true,
|
|
133
|
+
"type": "module",
|
|
134
|
+
"dependencies": {
|
|
135
|
+
"vue": "^3.6.12"
|
|
136
|
+
},
|
|
137
|
+
"devDependencies": {
|
|
138
|
+
"vite": "^8.1.0",
|
|
139
|
+
"@vitejs/plugin-vue": "^6.0.0",
|
|
140
|
+
"vue-macros": "^3.1.2"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### VS Code розширення
|
|
146
|
+
|
|
147
|
+
У файлі `.vscode/extensions.json` потрібна рекомендація для Vue:
|
|
148
|
+
|
|
149
|
+
```json title=".vscode/extensions.json"
|
|
150
|
+
{
|
|
151
|
+
"recommendations": ["Vue.volar"]
|
|
152
|
+
}
|
|
153
|
+
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
## Vite client types (Volar, імпорти асетів)
|
|
2
|
+
|
|
3
|
+
Без типів **Vite** редактор (Volar / TypeScript) не знає, що імпорт статичного файлу (`import url from './hero.avif'`, `*.png`, `*.svg` тощо) відповідає модулю з `string` URL. Тоді у `.vue` з'являється помилка на кшталт **Cannot find module '…' or its corresponding type declarations**.
|
|
4
|
+
|
|
5
|
+
У **кожному** workspace-пакеті з **Vue + Vite** обов'язково:
|
|
6
|
+
|
|
7
|
+
1. **`src/vite-env.d.ts`** — рівно з посиланням на клієнтські типи Vite (одного рядка достатньо):
|
|
8
|
+
|
|
9
|
+
```ts title="src/vite-env.d.ts"
|
|
10
|
+
/// <reference types="vite/client" />
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Так підтягуються декларації з `vite/client.d.ts` (`declare module '*.avif'`, `*.png`, …).
|
|
14
|
+
|
|
15
|
+
2. **Корінь пакета:** **`jsconfig.json`** із **`include`**, що охоплює `src` (наприклад `"include": ["src/**/*"]`), щоб мова служби бачила `vite-env.d.ts` і SFC.
|
|
16
|
+
|
|
17
|
+
Мінімальний приклад для JS-пакета:
|
|
18
|
+
|
|
19
|
+
```json title="jsconfig.json"
|
|
20
|
+
{
|
|
21
|
+
"compilerOptions": {
|
|
22
|
+
"target": "ESNext",
|
|
23
|
+
"module": "ESNext",
|
|
24
|
+
"moduleResolution": "bundler",
|
|
25
|
+
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
26
|
+
"jsx": "preserve",
|
|
27
|
+
"strict": true,
|
|
28
|
+
"noEmit": true,
|
|
29
|
+
"skipLibCheck": true,
|
|
30
|
+
"resolveJsonModule": true,
|
|
31
|
+
"isolatedModules": true,
|
|
32
|
+
"allowJs": true
|
|
33
|
+
},
|
|
34
|
+
"include": ["src/**/*"]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Не** звужуй без потреби **`compilerOptions.types`** до `["vite/client"]`: це може відрізати інші пакети з `@types` і зламати інші підказки. Достатньо `/// <reference types="vite/client" />` у `vite-env.d.ts` і коректного `include`.
|
|
39
|
+
|
|
40
|
+
### Ця частина вже перевіряється автоматично
|
|
41
|
+
|
|
42
|
+
Наявність `src/vite-env.d.ts` з коректним `/// <reference types="vite/client" />` і наявність `jsconfig.json` у корені пакета — вже реалізований JS-концерн `packages` (`npm/rules/vue/packages/main.mjs`, функція `checkViteClientEnvAndEditorConfig`). Цей concern (`vite-env`) не дублює перевірку — лишається docs-only довідкою з еталонним прикладом.
|
|
43
|
+
|
|
44
|
+
## Статичні файли — BASE_URL
|
|
45
|
+
|
|
46
|
+
Для підключення статичних файлів не використовуй відносні шляхи. Завжди будуй URL через `import.meta.env.BASE_URL`:
|
|
47
|
+
|
|
48
|
+
```vue
|
|
49
|
+
<!-- Погано -->
|
|
50
|
+
<img src="/logo.png" />
|
|
51
|
+
<img src="./assets/logo.png" />
|
|
52
|
+
|
|
53
|
+
<!-- Добре -->
|
|
54
|
+
<img :src="baseUrl + 'logo.png'" />
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const baseUrl = import.meta.env.BASE_URL
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Ця вимога **не** перевіряється механічно: рядок-специфікатор `src` може легітимно вказувати на зовнішній URL, дата-URI чи інший валідний шлях, і однозначно відрізнити «статичний асет проекту» від інших випадків без хибних спрацювань неможливо — залишається на розсуд ревʼю.
|