mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-03 00:30:52 +03:00
fix(skills): чтение входного JSON — кодировка из BOM, эхо только для inline-значения (#80)
Этажом ниже разбора, на чтении файла, жил тот же класс дефектов в худшей форме. Файл в cp1251 с кириллицей: PS1 `Get-Content -Encoding UTF8` менял имя на 12 символов U+FFFD, JSON после этого разбирался УСПЕШНО, и навык создавал объект с именем из «замен» — молча. Py-порт на том же файле падал traceback-ом. Файл в UTF-16 давал ту же пару: traceback против ложного «JSON must have 'type' field». Новая семья read_json_file / Read-JsonInputFile: кодировка берётся из BOM (UTF-8, UTF-16 LE/BE), без BOM — строгий UTF-8, при провале сообщение называет файл и байт. Кодовую страницу не подбираем: угаданное имя уехало бы в метаданные так же молча. Эхо полученного значения печатается теперь только для inline-входа. Для файла оно показывало первые 60 символов первой строки независимо от того, что ошибка на 120-й, и спорило с позицией от парсера. Заодно уравнен пустой вход: PS 5.1 на пустой строке отдаёт $null, а не ошибку, и навык уходил дальше с $null, тогда как py-порт падал. Раннеру добавлен ключ inputEncoding (utf-16le / utf-16be / cp1251) — иначе кейс про кодировку не выразить, writeFileSync пишет только UTF-8. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0770889e47
commit
229e66b907
@@ -1,4 +1,4 @@
|
||||
# subsystem-compile v1.27 — Create 1C subsystem from JSON definition
|
||||
# subsystem-compile v1.28 — Create 1C subsystem from JSON definition
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[string]$DefinitionFile,
|
||||
@@ -13,22 +13,55 @@ $ErrorActionPreference = "Stop"
|
||||
# --- Разбор пользовательского JSON ---
|
||||
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||
# для полиморфного входа: у файла подсказка была бы наполнителем. -Inline печатает ещё и то,
|
||||
# что доехало: у файла такого вопроса нет — путь назван, позицию дал парсер, файл на диске.
|
||||
# Возврат через -NoEnumerate: без него одноэлементный
|
||||
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected, [switch]$Inline) {
|
||||
try {
|
||||
# PS 5.1 на пустой строке отдаёт $null, а не ошибку — навык уходил дальше с $null,
|
||||
# тогда как py-порт падал. Проверяем сами, чтобы порты вели себя одинаково.
|
||||
if ([string]::IsNullOrWhiteSpace($text)) { throw 'input is empty' }
|
||||
$parsed = $text | ConvertFrom-Json
|
||||
} catch {
|
||||
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||
$got = ($text -replace '\s+', ' ').Trim()
|
||||
$label = 'got'
|
||||
if ($got.Length -gt 60) { $label = 'got (first 60 chars, whitespace collapsed)'; $got = $got.Substring(0, 60) }
|
||||
[Console]::Error.WriteLine("[ERROR] ${what}, ${label}: ${got} ($($_.Exception.Message))")
|
||||
if ($Inline) {
|
||||
$got = ($text -replace '\s+', ' ').Trim()
|
||||
$label = 'got'
|
||||
if (-not $got) { $got = '(empty)' }
|
||||
elseif ($got.Length -gt 60) { $label = 'got (first 60 chars)'; $got = $got.Substring(0, 60) }
|
||||
$what = "${what}, ${label}: ${got}"
|
||||
}
|
||||
[Console]::Error.WriteLine("[ERROR] ${what} ($($_.Exception.Message))")
|
||||
exit 1
|
||||
}
|
||||
Write-Output -NoEnumerate $parsed
|
||||
}
|
||||
|
||||
# --- Чтение входного JSON-файла ---
|
||||
# Кодировку берём из BOM — это объявление самого файла, а не догадка. Без BOM ждём строгий UTF-8:
|
||||
# Get-Content -Encoding UTF8 на файле в cp1251 тихо меняет кириллицу на U+FFFD, JSON после этого
|
||||
# разбирается успешно, и в конфигурацию уезжает имя из «замен». Кодовую страницу не подбираем:
|
||||
# угаданное имя уйдёт в метаданные так же молча.
|
||||
function Read-JsonInputFile([string]$path) {
|
||||
$bytes = [System.IO.File]::ReadAllBytes($path)
|
||||
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
|
||||
return [System.Text.Encoding]::UTF8.GetString($bytes, 3, $bytes.Length - 3)
|
||||
}
|
||||
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) {
|
||||
return [System.Text.Encoding]::Unicode.GetString($bytes, 2, $bytes.Length - 2)
|
||||
}
|
||||
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFE -and $bytes[1] -eq 0xFF) {
|
||||
return [System.Text.Encoding]::BigEndianUnicode.GetString($bytes, 2, $bytes.Length - 2)
|
||||
}
|
||||
try {
|
||||
return (New-Object System.Text.UTF8Encoding($false, $true)).GetString($bytes)
|
||||
} catch {
|
||||
$detail = if ($_.Exception.InnerException) { $_.Exception.InnerException.Message } else { $_.Exception.Message }
|
||||
[Console]::Error.WriteLine("[ERROR] ${path} is not valid UTF-8: ${detail} - save the file as UTF-8, or add a BOM if it is UTF-16")
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
# --- 1. Load JSON ---
|
||||
@@ -49,14 +82,16 @@ if ($DefinitionFile) {
|
||||
Write-Error "Definition file not found: $DefinitionFile"
|
||||
exit 1
|
||||
}
|
||||
$json = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
||||
$json = Read-JsonInputFile $DefinitionFile
|
||||
$jsonSource = $DefinitionFile
|
||||
$jsonInline = $false
|
||||
} else {
|
||||
$json = $Value
|
||||
$jsonSource = "-Value"
|
||||
$jsonInline = $true
|
||||
}
|
||||
|
||||
$def = ConvertFrom-JsonInput $json $jsonSource
|
||||
$def = ConvertFrom-JsonInput $json $jsonSource -Inline:$jsonInline
|
||||
|
||||
if (-not $def.name) {
|
||||
Write-Error "JSON must have 'name' field"
|
||||
|
||||
Reference in New Issue
Block a user