@7n/rules 1.8.3 → 1.8.4
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 +7 -0
- package/package.json +1 -1
- package/rules/text/run-v8r/docs/main.md +8 -5
- package/rules/text/run-v8r/main.mjs +58 -28
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.8.4] - 2026-07-17
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- text/run-v8r: включати причину провалу v8r (stdout+stderr, без noise) у violation-повідомлення замість голого коду виходу
|
|
8
|
+
- k8s/manifests: форматування tests/check-schema.test.mjs (oxfmt)
|
|
9
|
+
|
|
3
10
|
## [1.8.3] - 2026-07-17
|
|
4
11
|
|
|
5
12
|
### Changed
|
package/package.json
CHANGED
|
@@ -3,7 +3,8 @@ type: JS Module
|
|
|
3
3
|
title: main.mjs
|
|
4
4
|
resource: npm/rules/text/run-v8r/main.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 5c8aab7b
|
|
7
|
+
model: manual
|
|
7
8
|
---
|
|
8
9
|
|
|
9
10
|
## Огляд
|
|
@@ -20,18 +21,20 @@ docgen:
|
|
|
20
21
|
- `V8R_CACHE_TTL_SECONDS` — TTL HTTP-кешу v8r (доба замість дефолтних 600 с): fallback-фетчі schemastore не повторюються на кожен прогін.
|
|
21
22
|
- `resolveCustomCatalogSchemas()` — читає джерельний каталог, повертає масив схем у форматі v8r `customCatalog.schemas` (ключ `location`, локальні шляхи — абсолютні).
|
|
22
23
|
- `writeResolvedV8rConfig()` — записує `{ cacheTtl, customCatalog: { schemas } }` у `RESOLVED_V8R_CONFIG_PATH` (побічний ефект: файлова операція запису, поза rollback-механізмом лінт-пайплайна).
|
|
23
|
-
- `runV8rWithGlobs(globs?)` — послідовно запускає `v8r` для кожного glob-у з `V8R_CONFIG_FILE`, вказаним на резольвнутий конфіг; при
|
|
24
|
-
- `runV8rWithFiles(files)` — delta-режим: один запуск `v8r` по конкретних існуючих шляхах (код 98 неможливий), порожній список — одразу 0
|
|
24
|
+
- `runV8rWithGlobs(globs?)` — послідовно запускає `v8r` для кожного glob-у з `V8R_CONFIG_FILE`, вказаним на резольвнутий конфіг; повертає `{ code, detail }` (не голий код): при `code` 0/98 вивід приховано, `detail` порожній; інакше `detail` друкується й повертається код першого невдалого прогону.
|
|
25
|
+
- `runV8rWithFiles(files)` — delta-режим: один запуск `v8r` по конкретних існуючих шляхах (код 98 неможливий), порожній список — одразу `{ code: 0, detail: '' }`.
|
|
26
|
+
- `extractFailureLines(combinedText)` — фільтрує `ℹ`-шум і bunx install-вивід з об'єднаного `stdout+stderr` одного запуску `v8r`, лишаючи предметну деталь (`✖ …`-заголовки, ajv-причини). Обидва потоки об'єднуються навмисно: `v8r` непослідовно розкидає деталь між ними залежно від типу помилки (schema violation — причина в stdout, заголовок у stderr; "не знайдено схему" — усе в stderr).
|
|
25
27
|
- `warnAboutRemoteSchemaFallback(stderrText)` — парсить stderr `v8r` і на кожен файл, чию схему знайдено мережевим fallback-ом (schemastore, не customCatalog), друкує в stdout пораду додати схему в каталог.
|
|
26
28
|
- `stripBunNodeShimDirs(pathValue)` — прибирає з PATH shim-теки `bun-node-*`, які `bun run --bun` додає з підміненим `node`: дочірній `v8r` (node-shebang) інакше виконувався б під bun і падав на непідтримуваному `node:sea`. Дочірній процес `v8r` завжди отримує очищений PATH.
|
|
27
|
-
- `lint(ctx)` — detector `text/run-v8r`: `ctx.files` → delta по відфільтрованих розширеннях, без `ctx.files` → full за `DEFAULT_V8R_GLOBS`.
|
|
29
|
+
- `lint(ctx)` — detector `text/run-v8r`: `ctx.files` → delta по відфільтрованих розширеннях, без `ctx.files` → full за `DEFAULT_V8R_GLOBS`. Порушення несе `detail` (якщо є) у тексті `fail()`-повідомлення — без нього LLM fix-worker бачив лише "щось не пройшло" й незмінно провалював усі rung-и драбини (не мав інформації, що саме виправляти).
|
|
28
30
|
|
|
29
31
|
## Публічний API
|
|
30
32
|
|
|
31
33
|
- `DEFAULT_V8R_GLOBS`, `V8R_CATALOG_PATH`, `RESOLVED_V8R_CONFIG_PATH`, `V8R_CACHE_TTL_SECONDS` — константи.
|
|
32
34
|
- `resolveCustomCatalogSchemas()` — обчислені схеми customCatalog.
|
|
33
35
|
- `writeResolvedV8rConfig()` — матеріалізація тимчасового конфігу, повертає його шлях.
|
|
34
|
-
- `runV8rWithGlobs(globs?)`, `runV8rWithFiles(files)` — точки входу перевірки (full/delta)
|
|
36
|
+
- `runV8rWithGlobs(globs?)`, `runV8rWithFiles(files)` — точки входу перевірки (full/delta), повертають `{ code, detail }`.
|
|
37
|
+
- `extractFailureLines(combinedText)` — фільтр noise-рядків для деталі провалу.
|
|
35
38
|
- `warnAboutRemoteSchemaFallback(stderrText)` — попередження про мережевий fallback схем.
|
|
36
39
|
- `stripBunNodeShimDirs(pathValue)` — PATH без shim-тек `bun-node-*` (для дочірнього v8r).
|
|
37
40
|
- `lint(ctx)` — інтеграція в lint-пайплайн.
|
|
@@ -114,17 +114,28 @@ export function writeResolvedV8rConfig() {
|
|
|
114
114
|
|
|
115
115
|
const PROCESSING_LINE_RE = /^ℹ Processing (.+)$/u
|
|
116
116
|
const FOUND_REMOTE_SCHEMA_RE = /^ℹ Found schema in (https?:\/\/\S+)/u
|
|
117
|
-
const
|
|
117
|
+
const NOISE_LINE_RE = /^(?:ℹ .*|Resolving dependencies|Resolved, downloaded and extracted.*|Saved lockfile)$/u
|
|
118
118
|
|
|
119
119
|
/**
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
120
|
+
* Прибирає v8r/bunx noise-рядки (весь `ℹ`-статус: Loaded config file, Patterns and relative
|
|
121
|
+
* paths, Pre-warming the cache, Processing <file>, Found schema in …, Validating …; і службовий
|
|
122
|
+
* вивід bunx-встановлення Resolving/Resolved/Saved lockfile) з об'єднаного stdout+stderr одного
|
|
123
|
+
* запуску —
|
|
124
|
+
* лишає предметну деталь (`✖ …`-заголовки й ajv-причини на кшталт "must NOT have additional
|
|
125
|
+
* properties…"). Обидва потоки об'єднуються НАВМИСНО: v8r непослідовно розкидає ці рядки між
|
|
126
|
+
* stdout/stderr залежно від типу помилки — при порушенні схеми ajv-причина йде у stdout, а
|
|
127
|
+
* `✖ … is invalid`-заголовок у stderr; при "не знайдено схему" все йде у stderr, stdout
|
|
128
|
+
* порожній. Фільтр лише за stdout (як раніше) на другому випадку повертав би зовсім порожню
|
|
129
|
+
* деталь — і LLM fix-worker (як і non-verbose CLI-підсумок) не бачив би жодної причини провалу.
|
|
130
|
+
* @param {string} combinedText stdout + '\n' + stderr одного запуску v8r
|
|
131
|
+
* @returns {string} відфільтровані непорожні рядки, join('\n') (порожній рядок, якщо деталі нема)
|
|
125
132
|
*/
|
|
126
|
-
export function extractFailureLines(
|
|
127
|
-
return
|
|
133
|
+
export function extractFailureLines(combinedText) {
|
|
134
|
+
return combinedText
|
|
135
|
+
.split('\n')
|
|
136
|
+
.map(line => line.trim())
|
|
137
|
+
.filter(line => line.length > 0 && !NOISE_LINE_RE.test(line))
|
|
138
|
+
.join('\n')
|
|
128
139
|
}
|
|
129
140
|
|
|
130
141
|
/**
|
|
@@ -168,11 +179,16 @@ export function stripBunNodeShimDirs(pathValue) {
|
|
|
168
179
|
|
|
169
180
|
/**
|
|
170
181
|
* Один виклик `bun x v8r <targets...>` з підготовленим `customCatalog`-конфігом.
|
|
182
|
+
* `detail` (рядки `✖ …`) обчислюється завжди, незалежно від `verbose` — потрібен викликачу
|
|
183
|
+
* (`lint()`) для вбудовування у violation-повідомлення, яке бачить LLM fix-worker: без нього
|
|
184
|
+
* fix-ladder отримує лише "щось не пройшло" й не має шансів вгадати, що саме (спостережено —
|
|
185
|
+
* усі 4 rung-и незмінно падають у timeout на v8r-порушеннях).
|
|
171
186
|
* @param {string[]} targets glob-и або конкретні шляхи файлів
|
|
172
187
|
* @param {string} configPath шлях до `V8R_CONFIG_FILE`
|
|
173
188
|
* @param {boolean} [verbose] друкувати повний raw stdout/stderr v8r при помилці; інакше — лише
|
|
174
189
|
* рядки `✖ …` без `ℹ`-шуму (Pre-warming the cache, Processing <file>, Found schema in …)
|
|
175
|
-
* @returns {{ exitError: true } | { exitError: false, code: number }} помилка
|
|
190
|
+
* @returns {{ exitError: true } | { exitError: false, code: number, detail: string }} помилка
|
|
191
|
+
* spawn або код v8r (0/98 — трактує викликач) + деталь `✖ …`-рядків
|
|
176
192
|
*/
|
|
177
193
|
function runOneV8rInvocation(targets, configPath, verbose = false) {
|
|
178
194
|
const bunPath = resolveCmd('bun') ?? process.execPath
|
|
@@ -192,16 +208,17 @@ function runOneV8rInvocation(targets, configPath, verbose = false) {
|
|
|
192
208
|
warnAboutRemoteSchemaFallback(result.stderr ?? '')
|
|
193
209
|
|
|
194
210
|
const exitCode = result.status ?? 1
|
|
211
|
+
let detail = ''
|
|
195
212
|
if (exitCode !== 0 && exitCode !== 98) {
|
|
213
|
+
detail = extractFailureLines(`${result.stdout ?? ''}\n${result.stderr ?? ''}`)
|
|
196
214
|
if (verbose) {
|
|
197
215
|
if (result.stdout?.length) process.stdout.write(result.stdout)
|
|
198
216
|
if (result.stderr?.length) process.stderr.write(result.stderr)
|
|
199
|
-
} else {
|
|
200
|
-
|
|
201
|
-
if (failureLines.length) process.stdout.write(`${failureLines}\n`)
|
|
217
|
+
} else if (detail.length) {
|
|
218
|
+
process.stdout.write(`${detail}\n`)
|
|
202
219
|
}
|
|
203
220
|
}
|
|
204
|
-
return { exitError: false, code: exitCode }
|
|
221
|
+
return { exitError: false, code: exitCode, detail }
|
|
205
222
|
}
|
|
206
223
|
|
|
207
224
|
/**
|
|
@@ -210,24 +227,25 @@ function runOneV8rInvocation(targets, configPath, verbose = false) {
|
|
|
210
227
|
* glob не знаходить файлів, і тоді решта розширень не перевіряються в тому ж виклику.
|
|
211
228
|
* @param {string[]} [globs] патерни; за замовчуванням DEFAULT_V8R_GLOBS
|
|
212
229
|
* @param {boolean} [verbose] друкувати повний raw вивід v8r при помилці (див. runOneV8rInvocation)
|
|
213
|
-
* @returns {number} 0 — OK, 1 — помилка spawn, 2 — немає
|
|
230
|
+
* @returns {{ code: number, detail: string }} `code`: 0 — OK, 1 — помилка spawn, 2 — немає
|
|
231
|
+
* каталогу схем, інше — код v8r; `detail` — рядки `✖ …` (порожньо, якщо `code` не про валідацію)
|
|
214
232
|
*/
|
|
215
233
|
export function runV8rWithGlobs(globs = DEFAULT_V8R_GLOBS, verbose = false) {
|
|
216
234
|
if (!existsSync(V8R_CATALOG_PATH)) {
|
|
217
235
|
process.stderr.write(
|
|
218
236
|
`run-v8r: не знайдено каталог схем за шляхом ${V8R_CATALOG_PATH} (очікується npm/schemas/v8r-catalog.json у пакеті)\n`
|
|
219
237
|
)
|
|
220
|
-
return 2
|
|
238
|
+
return { code: 2, detail: '' }
|
|
221
239
|
}
|
|
222
240
|
|
|
223
241
|
const configPath = writeResolvedV8rConfig()
|
|
224
242
|
|
|
225
243
|
for (const pattern of globs) {
|
|
226
244
|
const r = runOneV8rInvocation([pattern], configPath, verbose)
|
|
227
|
-
if (r.exitError) return 1
|
|
228
|
-
if (r.code !== 0 && r.code !== 98) return r.code
|
|
245
|
+
if (r.exitError) return { code: 1, detail: '' }
|
|
246
|
+
if (r.code !== 0 && r.code !== 98) return { code: r.code, detail: r.detail }
|
|
229
247
|
}
|
|
230
|
-
return 0
|
|
248
|
+
return { code: 0, detail: '' }
|
|
231
249
|
}
|
|
232
250
|
|
|
233
251
|
/**
|
|
@@ -235,21 +253,33 @@ export function runV8rWithGlobs(globs = DEFAULT_V8R_GLOBS, verbose = false) {
|
|
|
235
253
|
* бо кожен переданий шлях уже існує (не glob), тож код 98 "порожній glob" тут не виникає.
|
|
236
254
|
* @param {string[]} files абсолютні або відносні до cwd v8r-процесу шляхи файлів
|
|
237
255
|
* @param {boolean} [verbose] друкувати повний raw вивід v8r при помилці (див. runOneV8rInvocation)
|
|
238
|
-
* @returns {number} 0 — OK, 1 — помилка spawn, 2 — немає
|
|
256
|
+
* @returns {{ code: number, detail: string }} `code`: 0 — OK, 1 — помилка spawn, 2 — немає
|
|
257
|
+
* каталогу схем, інше — код v8r; `detail` — рядки `✖ …` (порожньо, якщо `code` не про валідацію)
|
|
239
258
|
*/
|
|
240
259
|
export function runV8rWithFiles(files, verbose = false) {
|
|
241
|
-
if (files.length === 0) return 0
|
|
260
|
+
if (files.length === 0) return { code: 0, detail: '' }
|
|
242
261
|
if (!existsSync(V8R_CATALOG_PATH)) {
|
|
243
262
|
process.stderr.write(
|
|
244
263
|
`run-v8r: не знайдено каталог схем за шляхом ${V8R_CATALOG_PATH} (очікується npm/schemas/v8r-catalog.json у пакеті)\n`
|
|
245
264
|
)
|
|
246
|
-
return 2
|
|
265
|
+
return { code: 2, detail: '' }
|
|
247
266
|
}
|
|
248
267
|
|
|
249
268
|
const configPath = writeResolvedV8rConfig()
|
|
250
269
|
const r = runOneV8rInvocation(files, configPath, verbose)
|
|
251
|
-
if (r.exitError) return 1
|
|
252
|
-
return r.code === 98 ? 0 : r.code
|
|
270
|
+
if (r.exitError) return { code: 1, detail: '' }
|
|
271
|
+
return { code: r.code === 98 ? 0 : r.code, detail: r.detail }
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Будує violation-повідомлення з опційною деталлю `✖ …`-рядків v8r — без неї LLM fix-worker
|
|
276
|
+
* бачить лише "щось не пройшло" й не має інформації, який файл/поле саме порушує схему.
|
|
277
|
+
* @param {string} detail рядки `✖ …` з `runV8rWithGlobs`/`runV8rWithFiles` (може бути порожнім)
|
|
278
|
+
* @returns {string} повне повідомлення для `fail()`
|
|
279
|
+
*/
|
|
280
|
+
function v8rFailMessage(detail) {
|
|
281
|
+
const base = 'v8r schema-валідація json/yaml/toml не пройшла (text.mdc)'
|
|
282
|
+
return detail ? `${base}:\n${detail}` : base
|
|
253
283
|
}
|
|
254
284
|
|
|
255
285
|
/**
|
|
@@ -264,19 +294,19 @@ export function lint(ctx) {
|
|
|
264
294
|
const verbose = ctx.verbose === true
|
|
265
295
|
|
|
266
296
|
if (ctx.files === undefined) {
|
|
267
|
-
const code = runV8rWithGlobs(DEFAULT_V8R_GLOBS, verbose)
|
|
268
|
-
if (code !== 0) fail(
|
|
297
|
+
const { code, detail } = runV8rWithGlobs(DEFAULT_V8R_GLOBS, verbose)
|
|
298
|
+
if (code !== 0) fail(v8rFailMessage(detail), 'v8r')
|
|
269
299
|
return reporter.result()
|
|
270
300
|
}
|
|
271
301
|
|
|
272
302
|
const files = ctx.files.filter(f => V8R_EXT_RE.test(f))
|
|
273
303
|
if (files.length === 0) return reporter.result()
|
|
274
|
-
const code = runV8rWithFiles(files, verbose)
|
|
275
|
-
if (code !== 0) fail(
|
|
304
|
+
const { code, detail } = runV8rWithFiles(files, verbose)
|
|
305
|
+
if (code !== 0) fail(v8rFailMessage(detail), 'v8r')
|
|
276
306
|
return reporter.result()
|
|
277
307
|
}
|
|
278
308
|
|
|
279
309
|
if (isRunAsCli(import.meta.url)) {
|
|
280
310
|
const globs = process.argv.length > 2 ? process.argv.slice(2) : DEFAULT_V8R_GLOBS
|
|
281
|
-
process.exitCode = runV8rWithGlobs(globs)
|
|
311
|
+
process.exitCode = runV8rWithGlobs(globs).code
|
|
282
312
|
}
|