@7n/rules-lang-js 0.4.1 → 0.6.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 +12 -0
- package/package.json +1 -1
- package/rules/js-run/runtime/concern.json +1 -0
- package/rules/style/admin_table/admin_table.mdc +88 -0
- package/rules/style/admin_table/concern.json +7 -0
- package/rules/style/admin_table/docs/index.md +9 -0
- package/rules/style/admin_table/docs/main.md +14 -0
- package/rules/style/admin_table/main.mjs +46 -0
- package/rules/style/colors/colors.mdc +21 -0
- package/rules/style/colors/concern.json +3 -0
- package/rules/style/docs/index.md +11 -0
- package/rules/style/gap/concern.json +7 -0
- package/rules/style/gap/docs/index.md +9 -0
- package/rules/style/gap/docs/main.md +15 -0
- package/rules/style/gap/gap.mdc +22 -0
- package/rules/style/gap/main.mjs +51 -0
- package/rules/style/lint/concern.json +7 -0
- package/rules/style/lint/docs/fix-lint.md +29 -0
- package/rules/style/lint/docs/index.md +11 -0
- package/rules/style/lint/docs/main.md +29 -0
- package/rules/style/lint/fix-lint.mjs +66 -0
- package/rules/style/lint/main.mjs +68 -0
- package/rules/style/main.json +1 -0
- package/rules/style/main.mdc +12 -0
- package/rules/style/package_json/concern.json +9 -0
- package/rules/style/package_json/docs/fix-package_json.md +26 -0
- package/rules/style/package_json/docs/index.md +9 -0
- package/rules/style/package_json/fix-package_json.mjs +3 -0
- package/rules/style/package_json/package_json.mdc +18 -0
- package/rules/style/package_json/package_json.rego +31 -0
- package/rules/style/package_json/template/package.json.snippet.json +5 -0
- package/rules/style/quasar/concern.json +3 -0
- package/rules/style/quasar/quasar.mdc +7 -0
- package/rules/style/quasar_fixes/concern.json +7 -0
- package/rules/style/quasar_fixes/docs/index.md +9 -0
- package/rules/style/quasar_fixes/docs/main.md +16 -0
- package/rules/style/quasar_fixes/main.mjs +57 -0
- package/rules/style/quasar_fixes/quasar_fixes.mdc +32 -0
- package/rules/style/tooling/concern.json +14 -0
- package/rules/style/tooling/docs/fix-tooling.md +29 -0
- package/rules/style/tooling/docs/index.md +12 -0
- package/rules/style/tooling/docs/main.md +34 -0
- package/rules/style/tooling/fix-tooling.mjs +58 -0
- package/rules/style/tooling/main.mjs +73 -0
- package/rules/style/tooling/tooling.mdc +85 -0
- package/rules/style/vscode_extensions/concern.json +9 -0
- package/rules/style/vscode_extensions/docs/fix-vscode_extensions.md +24 -0
- package/rules/style/vscode_extensions/docs/index.md +11 -0
- package/rules/style/vscode_extensions/fix-vscode_extensions.mjs +1 -0
- package/rules/style/vscode_extensions/template/extensions.json.snippet.json +1 -0
- package/rules/style/vscode_extensions/vscode_extensions.mdc +13 -0
- package/rules/style/vscode_extensions/vscode_extensions.rego +13 -0
- package/rules/style/vscode_settings/concern.json +9 -0
- package/rules/style/vscode_settings/docs/fix-vscode_settings.md +26 -0
- package/rules/style/vscode_settings/docs/index.md +9 -0
- package/rules/style/vscode_settings/fix-vscode_settings.mjs +5 -0
- package/rules/style/vscode_settings/template/settings.json.snippet.json +5 -0
- package/rules/style/vscode_settings/vscode_settings.mdc +19 -0
- package/rules/style/vscode_settings/vscode_settings.rego +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0] - 2026-07-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- правило style з ядра (stylelint-детектор css/scss/vue, тулінг-канон, quasar/admin-table/colors/gap-концерни) — фронтенд-сімʼя правил тепер повністю у плагіні
|
|
8
|
+
|
|
9
|
+
## [0.5.0] - 2026-07-19
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- skipLocalTier для js-run/runtime: local-tier емпірично 0/14 успіхів (llm-trace.jsonl), cloud-tier — 3/6; ladder одразу стартує з cloud-min (ADR 260718-0754)
|
|
14
|
+
|
|
3
15
|
## [0.4.1] - 2026-07-19
|
|
4
16
|
|
|
5
17
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@7n/rules-lang-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Плагін @7n/rules: JS/npm/bun-екосистема — lint-правила (js/bun/vue/js-run/npm-module/db), taze-провайдер (package.json, bunx taze) і doc-files-екстрактори (oxc AST)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"javascript",
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
## Адмінські таблиці — n-admin-table
|
|
2
|
+
|
|
3
|
+
Для таблиць, що мають займати всю висоту сторінки (або блоку), додавай клас `n-admin-table` і атрибути `hide-no-data`, `dense`, `flat`. Таблиця автоматично розтягнеться на весь доступний простір. У блоках меншої висоти — задай їм явний `height`.
|
|
4
|
+
|
|
5
|
+
```vue
|
|
6
|
+
<!-- ТАБЛИЦЯ -->
|
|
7
|
+
<q-table class="n-admin-table" hide-no-data flat dense />
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Якщо клас `.n-admin-table` не визначено в `app.scss` — додай:
|
|
11
|
+
|
|
12
|
+
```scss
|
|
13
|
+
// ADMIN TABLE
|
|
14
|
+
.n-admin-table {
|
|
15
|
+
height: calc(100vh - 106px);
|
|
16
|
+
|
|
17
|
+
thead {
|
|
18
|
+
position: sticky;
|
|
19
|
+
z-index: 3;
|
|
20
|
+
top: 0;
|
|
21
|
+
|
|
22
|
+
tr th {
|
|
23
|
+
background-color: $grey-3;
|
|
24
|
+
height: 36px !important;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// tbody td {
|
|
29
|
+
// font-size: 14px;
|
|
30
|
+
// }
|
|
31
|
+
|
|
32
|
+
tbody tr:last-child td {
|
|
33
|
+
border-bottom: 1px solid rgb(0 0 0 / 12%) !important;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
th:first-child,
|
|
37
|
+
td:first-child,
|
|
38
|
+
th:last-child,
|
|
39
|
+
td:last-child {
|
|
40
|
+
width: 1px;
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.q-table__bottom {
|
|
45
|
+
background-color: $grey-3;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.q-table__progress th {
|
|
49
|
+
height: 1px !important;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.text-wrap {
|
|
53
|
+
max-width: 250px;
|
|
54
|
+
white-space: normal;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// sticky columns
|
|
58
|
+
td.sticky-left {
|
|
59
|
+
position: sticky;
|
|
60
|
+
left: 0;
|
|
61
|
+
z-index: 2;
|
|
62
|
+
background-color: white;
|
|
63
|
+
box-shadow: 2px 0 5px #0002;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
td.sticky-right {
|
|
67
|
+
position: sticky;
|
|
68
|
+
right: 0;
|
|
69
|
+
z-index: 2;
|
|
70
|
+
background-color: white;
|
|
71
|
+
box-shadow: -2px 0 5px #0002;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
th.sticky-left {
|
|
75
|
+
position: sticky;
|
|
76
|
+
left: 0;
|
|
77
|
+
z-index: 3;
|
|
78
|
+
box-shadow: 2px 0 5px #0002;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
th.sticky-right {
|
|
82
|
+
position: sticky;
|
|
83
|
+
right: 0;
|
|
84
|
+
z-index: 3;
|
|
85
|
+
box-shadow: -2px 0 5px #0002;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: main.mjs
|
|
4
|
+
resource: plugins/lang-js/rules/style/admin_table/main.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: 267496d1
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Огляд
|
|
10
|
+
|
|
11
|
+
Детектор concern-а `admin_table` (read-only, whole-repo): якщо десь у `.vue`-файлі
|
|
12
|
+
використано клас `n-admin-table`, він має бути визначений хоч в одному `.scss`/`.css`/`.vue`
|
|
13
|
+
файлі проєкту, інакше — порушення `missing-admin-table-style`. Потребує whole-repo
|
|
14
|
+
сканування (usage і definition можуть бути в різних файлах), тому не залежить від `ctx.files`.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** @see ./docs/main.md */
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
|
|
4
|
+
import { createViolationReporter } from '@7n/rules/scripts/lib/lint-surface/violation-reporter.mjs'
|
|
5
|
+
import { walkDir } from '@7n/rules/scripts/utils/walkDir.mjs'
|
|
6
|
+
|
|
7
|
+
const RELEVANT_RE = /\.(?:vue|scss|css)$/u
|
|
8
|
+
const USAGE_RE = /\bn-admin-table\b/u
|
|
9
|
+
const DEFINITION_RE = /\.n-admin-table\b/u
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Detector style/admin_table (read-only, whole-repo): якщо десь у `.vue` використано
|
|
13
|
+
* клас `n-admin-table`, він має бути визначений хоч в одному `.scss`/`.css`/`.vue`
|
|
14
|
+
* (guide: `admin_table.mdc`). Для усунення false positives — крос-файлова перевірка,
|
|
15
|
+
* тож потребує whole-repo сканування незалежно від `ctx.files`.
|
|
16
|
+
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону (cwd)
|
|
17
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат зі зібраними violations
|
|
18
|
+
*/
|
|
19
|
+
export async function lint(ctx) {
|
|
20
|
+
const reporter = createViolationReporter(ctx)
|
|
21
|
+
const { fail } = reporter
|
|
22
|
+
const cwd = ctx.cwd
|
|
23
|
+
|
|
24
|
+
/** @type {string[]} */
|
|
25
|
+
const files = []
|
|
26
|
+
await walkDir(cwd, f => {
|
|
27
|
+
if (RELEVANT_RE.test(f)) files.push(f)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
let used = false
|
|
31
|
+
let defined = false
|
|
32
|
+
for (const file of files) {
|
|
33
|
+
const content = await readFile(file, 'utf8')
|
|
34
|
+
if (!used && file.endsWith('.vue') && USAGE_RE.test(content)) used = true
|
|
35
|
+
if (!defined && DEFINITION_RE.test(content)) defined = true
|
|
36
|
+
if (used && defined) break
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (used && !defined) {
|
|
40
|
+
fail(
|
|
41
|
+
'Клас `.n-admin-table` використовується у `.vue`, але не визначений у жодному `.scss`/`.css` (guide: style/admin_table.mdc) — додай фікс до app.scss',
|
|
42
|
+
'missing-admin-table-style'
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
return reporter.result()
|
|
46
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
## Кольори: quasar-variables.scss і app.scss
|
|
2
|
+
|
|
3
|
+
Основні кольори визначай виключно через стандартні Quasar-змінні: `$primary`, `$secondary`, `$accent`, `$positive`, `$negative`, `$warning`.
|
|
4
|
+
|
|
5
|
+
Якщо потрібен додатковий колір — визнач його в `quasar-variables.scss`, і **обов'язково** додай до `app.scss` відповідні `.text-*` / `.bg-*` класи:
|
|
6
|
+
|
|
7
|
+
```scss
|
|
8
|
+
/* quasar-variables.scss */
|
|
9
|
+
$white-a1: color.adjust(white, $alpha: -0.85);
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```scss
|
|
13
|
+
/* app.scss */
|
|
14
|
+
.text-white-a1 {
|
|
15
|
+
color: $white-a1 !important;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.bg-white-a1 {
|
|
19
|
+
background-color: $white-a1 !important;
|
|
20
|
+
}
|
|
21
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: main.mjs
|
|
4
|
+
resource: plugins/lang-js/rules/style/gap/main.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: 23cd7951
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Огляд
|
|
10
|
+
|
|
11
|
+
Детектор concern-а `gap` (read-only, whole-repo): кожен суфікс утиліти
|
|
12
|
+
`.n-gap-{xs,sm,md,lg}`, використаний у `.vue`-файлі, має бути визначений хоч в одному
|
|
13
|
+
`.scss`/`.css`/`.vue` файлі проєкту — інакше порушення `missing-gap-style` для цього
|
|
14
|
+
суфіксу. Суфікси відстежуються незалежно один від одного, тож часткове покриття все одно
|
|
15
|
+
виявляє відсутній. Whole-repo сканування, не залежить від `ctx.files`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## Gap між flex/grid-елементами — .n-gap-*
|
|
2
|
+
|
|
3
|
+
Для відступів між плаваючими елементами (flex, grid) використовуй класи `.n-gap-*` замість `q-gutter-*`. Якщо класів немає в `app.scss` — додай:
|
|
4
|
+
|
|
5
|
+
```scss
|
|
6
|
+
// GAP
|
|
7
|
+
.n-gap-xs {
|
|
8
|
+
gap: 4px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.n-gap-sm {
|
|
12
|
+
gap: 8px;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.n-gap-md {
|
|
16
|
+
gap: 16px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.n-gap-lg {
|
|
20
|
+
gap: 24px;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** @see ./docs/main.md */
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
|
|
4
|
+
import { createViolationReporter } from '@7n/rules/scripts/lib/lint-surface/violation-reporter.mjs'
|
|
5
|
+
import { walkDir } from '@7n/rules/scripts/utils/walkDir.mjs'
|
|
6
|
+
|
|
7
|
+
const RELEVANT_RE = /\.(?:vue|scss|css)$/u
|
|
8
|
+
const USAGE_RE = /\bn-gap-(xs|sm|md|lg)\b/gu
|
|
9
|
+
const DEFINITION_RE = /\.n-gap-(xs|sm|md|lg)\b/gu
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Detector style/gap (read-only, whole-repo): кожен суфікс `.n-gap-{xs,sm,md,lg}`,
|
|
13
|
+
* використаний у `.vue`, має бути визначений хоч в одному `.scss`/`.css`/`.vue`
|
|
14
|
+
* (guide: `gap.mdc`). Крос-файлова перевірка usage↔definition — потребує whole-repo
|
|
15
|
+
* сканування незалежно від `ctx.files`.
|
|
16
|
+
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону (cwd)
|
|
17
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат зі зібраними violations
|
|
18
|
+
*/
|
|
19
|
+
export async function lint(ctx) {
|
|
20
|
+
const reporter = createViolationReporter(ctx)
|
|
21
|
+
const { fail } = reporter
|
|
22
|
+
const cwd = ctx.cwd
|
|
23
|
+
|
|
24
|
+
/** @type {string[]} */
|
|
25
|
+
const files = []
|
|
26
|
+
await walkDir(cwd, f => {
|
|
27
|
+
if (RELEVANT_RE.test(f)) files.push(f)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
/** @type {Set<string>} */
|
|
31
|
+
const used = new Set()
|
|
32
|
+
/** @type {Set<string>} */
|
|
33
|
+
const defined = new Set()
|
|
34
|
+
for (const file of files) {
|
|
35
|
+
const content = await readFile(file, 'utf8')
|
|
36
|
+
if (file.endsWith('.vue')) {
|
|
37
|
+
for (const m of content.matchAll(USAGE_RE)) used.add(m[1])
|
|
38
|
+
}
|
|
39
|
+
for (const m of content.matchAll(DEFINITION_RE)) defined.add(m[1])
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const suffix of used) {
|
|
43
|
+
if (!defined.has(suffix)) {
|
|
44
|
+
fail(
|
|
45
|
+
`Клас \`.n-gap-${suffix}\` використовується у \`.vue\`, але не визначений у жодному \`.scss\`/\`.css\` (guide: style/gap.mdc) — додай клас до app.scss`,
|
|
46
|
+
'missing-gap-style'
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return reporter.result()
|
|
51
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: fix-lint.mjs
|
|
4
|
+
resource: plugins/lang-js/rules/style/lint/fix-lint.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: a63dc24c
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Огляд
|
|
10
|
+
|
|
11
|
+
T0-autofix для `style/lint`: детермінований прогін `stylelint --fix` по css/scss/vue-файлах.
|
|
12
|
+
Виправляє авто-fixable правила stylelint; решта лишається детектору на re-check, далі — LLM-ладдеру.
|
|
13
|
+
Запис незворотний (поза rollback).
|
|
14
|
+
|
|
15
|
+
## Поведінка
|
|
16
|
+
|
|
17
|
+
- Перелічує цільові файли: у дельта-режимі — зі списку змінених (лише css/scss/vue); у повному —
|
|
18
|
+
tracked css/scss/vue через git.
|
|
19
|
+
- Застосовує `stylelint --fix` на них; до списку змінених потрапляють лише файли з фактичною зміною.
|
|
20
|
+
|
|
21
|
+
## Публічний API
|
|
22
|
+
|
|
23
|
+
- `patterns` — масив T0-патернів; єдиний `style-stylelint-fix` спрацьовує на агрегованому
|
|
24
|
+
порушенні детектора (`stylelint-violation`).
|
|
25
|
+
|
|
26
|
+
## Гарантії поведінки
|
|
27
|
+
|
|
28
|
+
- Відсутній stylelint → no-op (без змін).
|
|
29
|
+
- Записуються лише фактично змінені файли; кожен реєструється через `recordWrite`.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: main.mjs
|
|
4
|
+
resource: plugins/lang-js/rules/style/lint/main.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: c9a94f80
|
|
7
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
+
score: 100
|
|
9
|
+
issues: judge:inaccurate:0.99
|
|
10
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
Файл відповідає за вибірку стильових файлів у проекті, що реалізується через функцію `filterStyleFiles`. Він також забезпечує валідацію якості коду в цих файлах шляхом виконання перевірок, що реалізується функцією `lint`.
|
|
16
|
+
|
|
17
|
+
## Поведінка
|
|
18
|
+
|
|
19
|
+
filterStyleFiles відбирає з наданого списку шляхів лише ті, які мають розширення CSS, SCSS або Vue.
|
|
20
|
+
lint виконує форматування та перевірку стильових файлів у проекті, застосовуючи автоматичне виправлення, якщо це не режим лише для читання.
|
|
21
|
+
|
|
22
|
+
## Публічний API
|
|
23
|
+
|
|
24
|
+
filterStyleFiles — Відбирає файли стилів для подальшої обробки.
|
|
25
|
+
lint — Перевіряє стилі у файлах (CSS/SCSS/Vue) окремо для кожного або для всього проєкту.
|
|
26
|
+
|
|
27
|
+
## Гарантії поведінки
|
|
28
|
+
|
|
29
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** @see ./docs/fix-lint.md */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* T0-autofix для `style/lint` — детермінований прогін `stylelint --fix` по css/scss/vue.
|
|
5
|
+
* Детектор емітить агрегований `stylelint-violation` без переліку файлів, тож фіксер
|
|
6
|
+
* самостійно перелічує цільові файли (ctx.files у дельті або tracked css/scss/vue у повному
|
|
7
|
+
* режимі), форматує їх і повертає лише фактично змінені. Запис permanent. Відсутній
|
|
8
|
+
* stylelint → no-op.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'node:fs'
|
|
11
|
+
import { resolve } from 'node:path'
|
|
12
|
+
|
|
13
|
+
import { filterStyleFiles, resolveStylelint } from './main.mjs'
|
|
14
|
+
import { spawnAsync } from '@7n/rules/scripts/utils/spawn-async.mjs'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Вміст файлу або null, якщо не читається.
|
|
18
|
+
* @param {string} abs абсолютний шлях
|
|
19
|
+
* @returns {string|null} вміст або null
|
|
20
|
+
*/
|
|
21
|
+
function readOrNull(abs) {
|
|
22
|
+
try {
|
|
23
|
+
return readFileSync(abs, 'utf8')
|
|
24
|
+
} catch {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Перелік цільових style-файлів: у дельті — з ctx.files; у повному режимі — tracked
|
|
31
|
+
* css/scss/vue через `git ls-files`.
|
|
32
|
+
* @param {string} cwd корінь
|
|
33
|
+
* @param {string[]|undefined} ctxFiles файли з контексту (дельта) або undefined (повний режим)
|
|
34
|
+
* @returns {Promise<string[]>} posix-relative шляхи
|
|
35
|
+
*/
|
|
36
|
+
async function listStyleFiles(cwd, ctxFiles) {
|
|
37
|
+
if (ctxFiles !== undefined) return filterStyleFiles(ctxFiles)
|
|
38
|
+
const r = await spawnAsync('git', ['ls-files', '-z', '--', '*.css', '*.scss', '*.vue'], { cwd })
|
|
39
|
+
if (r.exitCode !== 0) return []
|
|
40
|
+
return (r.stdout ?? '').split('\0').filter(Boolean)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** @type {import('../../../scripts/lib/lint-surface/types.mjs').T0Pattern[]} */
|
|
44
|
+
export const patterns = [
|
|
45
|
+
{
|
|
46
|
+
id: 'style-stylelint-fix',
|
|
47
|
+
standalone: true, // §8 Phase 2: apply бере ctx.files (не violations), stylelint --fix сам ре-аналізує
|
|
48
|
+
test: violations => violations.some(v => v.reason === 'stylelint-violation'),
|
|
49
|
+
apply: async (violations, ctx) => {
|
|
50
|
+
const stylelint = resolveStylelint(ctx.cwd)
|
|
51
|
+
if (!stylelint) return { touchedFiles: [] }
|
|
52
|
+
const files = await listStyleFiles(ctx.cwd, ctx.files)
|
|
53
|
+
if (files.length === 0) return { touchedFiles: [] }
|
|
54
|
+
|
|
55
|
+
const abs = files.map(f => resolve(ctx.cwd, f))
|
|
56
|
+
const before = new Map(abs.map(a => [a, readOrNull(a)]))
|
|
57
|
+
await spawnAsync(stylelint, ['--fix', ...files], { cwd: ctx.cwd })
|
|
58
|
+
|
|
59
|
+
const touchedFiles = abs.filter(a => readOrNull(a) !== before.get(a))
|
|
60
|
+
for (const a of touchedFiles) ctx.recordWrite?.(a)
|
|
61
|
+
return touchedFiles.length > 0
|
|
62
|
+
? { touchedFiles, message: `stylelint --fix: ${touchedFiles.length} файл(ів)` }
|
|
63
|
+
: { touchedFiles: [] }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lint-поверхня style: read-only detector (stylelint без --fix) для css/scss/vue.
|
|
3
|
+
* Per-file (ctx.files) або весь проєкт (ctx.files === undefined). Якщо stylelint
|
|
4
|
+
* недоступний — крок пропускається (без npx-автовстановлення).
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync } from 'node:fs'
|
|
7
|
+
import { join } from 'node:path'
|
|
8
|
+
|
|
9
|
+
import { createViolationReporter } from '@7n/rules/scripts/lib/lint-surface/violation-reporter.mjs'
|
|
10
|
+
import { resolveCmd } from '@7n/rules/scripts/utils/resolve-cmd.mjs'
|
|
11
|
+
import { spawnAsync } from '@7n/rules/scripts/utils/spawn-async.mjs'
|
|
12
|
+
|
|
13
|
+
const STYLE_EXT_RE = /\.(?:css|scss|vue)$/u
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {string[]} files список шляхів
|
|
17
|
+
* @returns {string[]} лише css/scss/vue
|
|
18
|
+
*/
|
|
19
|
+
export function filterStyleFiles(files) {
|
|
20
|
+
return files.filter(f => STYLE_EXT_RE.test(f))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Резолвить бінарник stylelint: спершу локальний node_modules/.bin, потім PATH.
|
|
25
|
+
* @param {string} cwd корінь
|
|
26
|
+
* @returns {string | null} абсолютний шлях або null
|
|
27
|
+
*/
|
|
28
|
+
export function resolveStylelint(cwd) {
|
|
29
|
+
const local = join(cwd, 'node_modules', '.bin', 'stylelint')
|
|
30
|
+
if (existsSync(local)) return local
|
|
31
|
+
return resolveCmd('stylelint')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Detector style/lint (read-only).
|
|
36
|
+
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону (cwd, files)
|
|
37
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат зі зібраними violations
|
|
38
|
+
*/
|
|
39
|
+
export async function lint(ctx) {
|
|
40
|
+
const reporter = createViolationReporter(ctx)
|
|
41
|
+
const { fail } = reporter
|
|
42
|
+
const cwd = ctx.cwd
|
|
43
|
+
const files = ctx.files
|
|
44
|
+
|
|
45
|
+
/** @type {string[]} */
|
|
46
|
+
const targets = []
|
|
47
|
+
if (files === undefined) {
|
|
48
|
+
targets.push('**/*.{css,scss,vue}')
|
|
49
|
+
} else {
|
|
50
|
+
const style = filterStyleFiles(files)
|
|
51
|
+
if (style.length === 0) return reporter.result()
|
|
52
|
+
targets.push(...style)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const stylelint = resolveStylelint(cwd)
|
|
56
|
+
if (!stylelint) {
|
|
57
|
+
// stylelint недоступний → крок пропущено (без автовстановлення)
|
|
58
|
+
return reporter.result()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const r = await spawnAsync(stylelint, targets, { cwd, shell: false })
|
|
62
|
+
if (r.exitCode !== 0) {
|
|
63
|
+
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
|
|
64
|
+
const outSuffix = out ? `\n${out}` : ''
|
|
65
|
+
fail(`lint-style: stylelint — порушення (код ${r.exitCode ?? 1}, style.mdc)${outSuffix}`, 'stylelint-violation')
|
|
66
|
+
}
|
|
67
|
+
return reporter.result()
|
|
68
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "auto": { "glob": ["**/*.css", "**/*.vue"] } }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Правила стилів CSS та SCSS
|
|
3
|
+
version: '1.5'
|
|
4
|
+
globs: "**/*.{css,scss,vue}"
|
|
5
|
+
alwaysApply: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Правило **style** для Vue-проєктів: Quasar як стильова система, SCSS-конвенції кольорів і відступів, фікси компонентів, stylelint через `@nitra/stylelint-config`.
|
|
9
|
+
|
|
10
|
+
- [settings.json.snippet.json](./vscode_settings/template/settings.json.snippet.json)
|
|
11
|
+
- [extensions.json.snippet.json](./vscode_extensions/template/extensions.json.snippet.json)
|
|
12
|
+
- [package.json.snippet.json](./package_json/template/package.json.snippet.json)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: fix-package_json.mjs
|
|
4
|
+
resource: plugins/lang-js/rules/style/package_json/fix-package_json.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: f364c0e4
|
|
7
|
+
model: openai-codex/gpt-5.5
|
|
8
|
+
score: 100
|
|
9
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Огляд
|
|
13
|
+
|
|
14
|
+
Надає `patterns` для визначення очікуваних перевірок, що спираються на `package.json`. Використовується як read-only опис вимог до конфігурації пакета, без самостійних змін файлової системи.
|
|
15
|
+
|
|
16
|
+
## Поведінка
|
|
17
|
+
|
|
18
|
+
1. `patterns` визначає правило виправлення для `package.json`.
|
|
19
|
+
|
|
20
|
+
2. `patterns` забезпечує приведення `package.json` до проєктного шаблону стилю.
|
|
21
|
+
|
|
22
|
+
3. `patterns` не змінює файлову систему самостійно, а лише описує доступний сценарій автоматичного виправлення для зовнішнього механізму перевірок.
|
|
23
|
+
|
|
24
|
+
## Гарантії поведінки
|
|
25
|
+
|
|
26
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: Directory Index
|
|
3
|
+
title: npm/rules/style/package_json
|
|
4
|
+
resource: plugins/lang-js/rules/style/package_json/
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
| Файл | Тип |
|
|
8
|
+
| ------------------------------------------- | --------- |
|
|
9
|
+
| [fix-package_json.mjs](fix-package_json.md) | JS Module |
|