mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-28 22:19:41 +03:00
fix(skills): внятная диагностика разбора JSON вместо стектрейса (#80)
Неверный входной JSON ронял скрипты необработанным исключением: PS1 отдавал дамп
ConvertFrom-Json с CategoryInfo, py-порт — traceback с внутренностями json/decoder.py.
Имя файла в сообщении не фигурировало, а для полиморфного -Value не было видно, какую
форму ждёт операция.
Общий хелпер ConvertFrom-JsonInput / parse_json_input в 12 навыках × 2 порта (24 места),
зарегистрирован семьёй в check-inline-drift.mjs — копии держит гард. Сообщение в одну
строку: ожидаемая форма, полученное значение, текст парсера в скобках.
Эхо полученного значения нужно потому, что съеденные оболочкой кавычки дают почти тот же
JSON ({group:X} вместо {"group":"X"}), и без него агент считает свой вызов верным. PS 5.1
печатает лишь огрызок и локализованно, Python — только номер колонки.
Возврат в PS1 через Write-Output -NoEnumerate: вынос разбора в функцию добавляет второй
анруллинг, и одноэлементный JSON-массив стал бы скаляром. Импорты внутри тела py-хелпера —
skd-decompile импортирует json локально как _json, а тело семьи обязано быть одинаковым.
В раннер добавлен inputRaw (запись входного файла дословно): через case.input битый JSON
невыразим, JSON.stringify всегда даёт валидный документ.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
53fc16d2f1
commit
a44a29a7d8
@@ -1,4 +1,4 @@
|
|||||||
# cf-edit v1.19 — Edit 1C configuration root (Configuration.xml)
|
# cf-edit v1.20 — Edit 1C configuration root (Configuration.xml)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)][Alias('Path')][string]$ConfigPath,
|
[Parameter(Mandatory)][Alias('Path')][string]$ConfigPath,
|
||||||
@@ -10,6 +10,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# --- Mode validation ---
|
# --- Mode validation ---
|
||||||
@@ -639,10 +658,7 @@ function Do-SetPanels($valArg) {
|
|||||||
# Accept string (JSON), PSCustomObject, or hashtable
|
# Accept string (JSON), PSCustomObject, or hashtable
|
||||||
$layout = $valArg
|
$layout = $valArg
|
||||||
if ($layout -is [string]) {
|
if ($layout -is [string]) {
|
||||||
try { $layout = $layout | ConvertFrom-Json } catch {
|
$layout = ConvertFrom-JsonInput $layout "-Value for operation 'set-panels'" "a JSON object with panel layout"
|
||||||
Write-Error "set-panels value must be valid JSON object, got: $valArg"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (-not $layout) {
|
if (-not $layout) {
|
||||||
Write-Error "set-panels value is empty"
|
Write-Error "set-panels value is empty"
|
||||||
@@ -826,9 +842,7 @@ $indent</Item>
|
|||||||
function Do-SetHomePage($valArg) {
|
function Do-SetHomePage($valArg) {
|
||||||
$layout = $valArg
|
$layout = $valArg
|
||||||
if ($layout -is [string]) {
|
if ($layout -is [string]) {
|
||||||
try { $layout = $layout | ConvertFrom-Json } catch {
|
$layout = ConvertFrom-JsonInput $layout "-Value for operation 'set-home-page'" "a JSON object with home page layout"
|
||||||
Write-Error "set-home-page value must be valid JSON object"; exit 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (-not $layout) { Write-Error "set-home-page value is empty"; exit 1 }
|
if (-not $layout) { Write-Error "set-home-page value is empty"; exit 1 }
|
||||||
|
|
||||||
@@ -943,7 +957,7 @@ if ($DefinitionFile) {
|
|||||||
$DefinitionFile = Join-Path (Get-Location).Path $DefinitionFile
|
$DefinitionFile = Join-Path (Get-Location).Path $DefinitionFile
|
||||||
}
|
}
|
||||||
$jsonText = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
$jsonText = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
||||||
$ops = $jsonText | ConvertFrom-Json
|
$ops = ConvertFrom-JsonInput $jsonText $DefinitionFile
|
||||||
if ($ops -is [System.Array]) {
|
if ($ops -is [System.Array]) {
|
||||||
foreach ($op in $ops) { $operations += $op }
|
foreach ($op in $ops) { $operations += $op }
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# cf-edit v1.19 — Edit 1C configuration root (Configuration.xml)
|
# cf-edit v1.20 — Edit 1C configuration root (Configuration.xml)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -14,6 +14,29 @@ from lxml import etree
|
|||||||
|
|
||||||
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
||||||
# регистр не различают, в argparse совпадение точное.
|
# регистр не различают, в argparse совпадение точное.
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class CIDict(dict):
|
class CIDict(dict):
|
||||||
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
||||||
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
||||||
@@ -821,11 +844,8 @@ def main():
|
|||||||
nonlocal modify_count
|
nonlocal modify_count
|
||||||
layout = value
|
layout = value
|
||||||
if isinstance(layout, str):
|
if isinstance(layout, str):
|
||||||
try:
|
layout = ci_json(parse_json_input(
|
||||||
layout = ci_json(json.loads(layout))
|
layout, "-Value for operation 'set-panels'", "a JSON object with panel layout"))
|
||||||
except json.JSONDecodeError:
|
|
||||||
print(f"set-panels value must be valid JSON object", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
if not isinstance(layout, dict) or not layout:
|
if not isinstance(layout, dict) or not layout:
|
||||||
print("set-panels value must be non-empty object", file=sys.stderr)
|
print("set-panels value must be non-empty object", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -976,11 +996,8 @@ def main():
|
|||||||
nonlocal modify_count
|
nonlocal modify_count
|
||||||
layout = value
|
layout = value
|
||||||
if isinstance(layout, str):
|
if isinstance(layout, str):
|
||||||
try:
|
layout = ci_json(parse_json_input(
|
||||||
layout = ci_json(json.loads(layout))
|
layout, "-Value for operation 'set-home-page'", "a JSON object with home page layout"))
|
||||||
except json.JSONDecodeError:
|
|
||||||
print("set-home-page value must be valid JSON object", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
if not isinstance(layout, dict) or not layout:
|
if not isinstance(layout, dict) or not layout:
|
||||||
print("set-home-page value must be non-empty object", file=sys.stderr)
|
print("set-home-page value must be non-empty object", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -1045,7 +1062,7 @@ def main():
|
|||||||
if not os.path.isabs(def_file):
|
if not os.path.isabs(def_file):
|
||||||
def_file = os.path.join(os.getcwd(), def_file)
|
def_file = os.path.join(os.getcwd(), def_file)
|
||||||
with open(def_file, "r", encoding="utf-8-sig") as fh:
|
with open(def_file, "r", encoding="utf-8-sig") as fh:
|
||||||
ops = ci_json(json.loads(fh.read()))
|
ops = ci_json(parse_json_input(fh.read(), def_file))
|
||||||
if isinstance(ops, list):
|
if isinstance(ops, list):
|
||||||
operations = ops
|
operations = ops
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# form-compile v1.192 — Compile 1C managed form from JSON or object metadata (гвард на группу additionalColumns без ключа columns)
|
# form-compile v1.193 — Compile 1C managed form from JSON or object metadata (гвард на группу additionalColumns без ключа columns)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[string]$JsonPath,
|
[string]$JsonPath,
|
||||||
@@ -14,6 +14,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# ═══════════════════════════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
@@ -300,7 +319,7 @@ function Load-Preset([string]$PresetName, [string]$ScriptDir) {
|
|||||||
$presetDir = Join-Path (Split-Path $ScriptDir -Parent) "presets"
|
$presetDir = Join-Path (Split-Path $ScriptDir -Parent) "presets"
|
||||||
$builtInPath = Join-Path $presetDir "$PresetName.json"
|
$builtInPath = Join-Path $presetDir "$PresetName.json"
|
||||||
if (Test-Path $builtInPath) {
|
if (Test-Path $builtInPath) {
|
||||||
$presetJson = Get-Content -Raw -Encoding UTF8 $builtInPath | ConvertFrom-Json
|
$presetJson = ConvertFrom-JsonInput (Get-Content -Raw -Encoding UTF8 $builtInPath) $builtInPath
|
||||||
# Convert PSCustomObject to hashtable recursively
|
# Convert PSCustomObject to hashtable recursively
|
||||||
$toHash = {
|
$toHash = {
|
||||||
param($obj)
|
param($obj)
|
||||||
@@ -327,7 +346,7 @@ function Load-Preset([string]$PresetName, [string]$ScriptDir) {
|
|||||||
while ($scanDir) {
|
while ($scanDir) {
|
||||||
$projPreset = Join-Path (Join-Path (Join-Path (Join-Path $scanDir "presets") "skills") "form") "$PresetName.json"
|
$projPreset = Join-Path (Join-Path (Join-Path (Join-Path $scanDir "presets") "skills") "form") "$PresetName.json"
|
||||||
if (Test-Path $projPreset) {
|
if (Test-Path $projPreset) {
|
||||||
$projJson = Get-Content -Raw -Encoding UTF8 $projPreset | ConvertFrom-Json
|
$projJson = ConvertFrom-JsonInput (Get-Content -Raw -Encoding UTF8 $projPreset) $projPreset
|
||||||
$projHash = & $toHash $projJson
|
$projHash = & $toHash $projJson
|
||||||
foreach ($k in @($projHash.Keys)) {
|
foreach ($k in @($projHash.Keys)) {
|
||||||
$defaults[$k] = & $deepMerge $defaults[$k] $projHash[$k]
|
$defaults[$k] = & $deepMerge $defaults[$k] $projHash[$k]
|
||||||
@@ -1656,7 +1675,7 @@ if ($FromObject) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$json = Get-Content -Raw -Encoding UTF8 $JsonPath
|
$json = Get-Content -Raw -Encoding UTF8 $JsonPath
|
||||||
$def = $json | ConvertFrom-Json
|
$def = ConvertFrom-JsonInput $json $JsonPath
|
||||||
}
|
}
|
||||||
|
|
||||||
# Базовая директория для @file-ссылок в query динсписка (зеркало skd-compile)
|
# Базовая директория для @file-ссылок в query динсписка (зеркало skd-compile)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# form-compile v1.192 — Compile 1C managed form from JSON or object metadata (гвард на группу additionalColumns без ключа columns)
|
# form-compile v1.193 — Compile 1C managed form from JSON or object metadata (гвард на группу additionalColumns без ключа columns)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
import argparse
|
import argparse
|
||||||
import copy
|
import copy
|
||||||
@@ -15,6 +15,29 @@ from lxml import etree
|
|||||||
|
|
||||||
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
||||||
# регистр не различают, в argparse совпадение точное.
|
# регистр не различают, в argparse совпадение точное.
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class CIDict(dict):
|
class CIDict(dict):
|
||||||
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
||||||
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
||||||
@@ -543,7 +566,7 @@ def load_preset(preset_name, script_dir, out_path_resolved):
|
|||||||
built_in_path = os.path.join(preset_dir, f'{preset_name}.json')
|
built_in_path = os.path.join(preset_dir, f'{preset_name}.json')
|
||||||
if os.path.isfile(built_in_path):
|
if os.path.isfile(built_in_path):
|
||||||
with open(built_in_path, 'r', encoding='utf-8-sig') as f:
|
with open(built_in_path, 'r', encoding='utf-8-sig') as f:
|
||||||
preset_data = ci_json(json.load(f))
|
preset_data = ci_json(parse_json_input(f.read(), built_in_path))
|
||||||
for k in list(preset_data.keys()):
|
for k in list(preset_data.keys()):
|
||||||
defaults[k] = _deep_merge(defaults.get(k), preset_data[k])
|
defaults[k] = _deep_merge(defaults.get(k), preset_data[k])
|
||||||
|
|
||||||
@@ -553,7 +576,7 @@ def load_preset(preset_name, script_dir, out_path_resolved):
|
|||||||
proj_preset = os.path.join(scan_dir, 'presets', 'skills', 'form', f'{preset_name}.json')
|
proj_preset = os.path.join(scan_dir, 'presets', 'skills', 'form', f'{preset_name}.json')
|
||||||
if os.path.isfile(proj_preset):
|
if os.path.isfile(proj_preset):
|
||||||
with open(proj_preset, 'r', encoding='utf-8-sig') as f:
|
with open(proj_preset, 'r', encoding='utf-8-sig') as f:
|
||||||
proj_data = json.load(f)
|
proj_data = parse_json_input(f.read(), proj_preset)
|
||||||
for k in list(proj_data.keys()):
|
for k in list(proj_data.keys()):
|
||||||
defaults[k] = _deep_merge(defaults.get(k), proj_data[k])
|
defaults[k] = _deep_merge(defaults.get(k), proj_data[k])
|
||||||
break
|
break
|
||||||
@@ -6456,7 +6479,7 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
with open(json_path, 'r', encoding='utf-8-sig') as f:
|
with open(json_path, 'r', encoding='utf-8-sig') as f:
|
||||||
defn = ci_json(json.load(f))
|
defn = ci_json(parse_json_input(f.read(), json_path))
|
||||||
global QUERY_BASE_DIR
|
global QUERY_BASE_DIR
|
||||||
QUERY_BASE_DIR = os.path.dirname(os.path.abspath(json_path))
|
QUERY_BASE_DIR = os.path.dirname(os.path.abspath(json_path))
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# form-edit v1.14 — Edit 1C managed form elements (+esc_xml/esc_xml_text: разное экранирование атрибута и текста)
|
# form-edit v1.15 — Edit 1C managed form elements (+esc_xml/esc_xml_text: разное экранирование атрибута и текста)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -10,6 +10,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# --- Support guard (Ext/ParentConfigurations.bin) ---
|
# --- Support guard (Ext/ParentConfigurations.bin) ---
|
||||||
@@ -175,7 +194,7 @@ $root = $xmlDoc.DocumentElement
|
|||||||
|
|
||||||
# === 2. Load JSON ===
|
# === 2. Load JSON ===
|
||||||
|
|
||||||
$def = Get-Content -Raw -Encoding UTF8 $JsonPath | ConvertFrom-Json
|
$def = ConvertFrom-JsonInput (Get-Content -Raw -Encoding UTF8 $JsonPath) $JsonPath
|
||||||
|
|
||||||
# === 3. Form name + header ===
|
# === 3. Form name + header ===
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# form-edit v1.14 — Edit 1C managed form elements (Python port) (+esc_xml/esc_xml_text: разное экранирование атрибута и текста)
|
# form-edit v1.15 — Edit 1C managed form elements (Python port) (+esc_xml/esc_xml_text: разное экранирование атрибута и текста)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
@@ -13,6 +13,29 @@ sys.stderr.reconfigure(encoding="utf-8")
|
|||||||
|
|
||||||
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
||||||
# регистр не различают, в argparse совпадение точное.
|
# регистр не различают, в argparse совпадение точное.
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class CIDict(dict):
|
class CIDict(dict):
|
||||||
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
||||||
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
||||||
@@ -318,7 +341,7 @@ root = tree.getroot()
|
|||||||
# ── 2. Load JSON ────────────────────────────────────────────
|
# ── 2. Load JSON ────────────────────────────────────────────
|
||||||
|
|
||||||
with open(json_path, "r", encoding="utf-8-sig") as f:
|
with open(json_path, "r", encoding="utf-8-sig") as f:
|
||||||
defn = ci_json(json.load(f))
|
defn = ci_json(parse_json_input(f.read(), json_path))
|
||||||
|
|
||||||
# ── 3. Form name + header ───────────────────────────────────
|
# ── 3. Form name + header ───────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# interface-edit v1.18 — Edit 1C CommandInterface.xml (+русские алиасы типов: формы с ё и без)
|
# interface-edit v1.19 — Edit 1C CommandInterface.xml (+русские алиасы типов: формы с ё и без)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)][Alias('Path')][string]$CIPath,
|
[Parameter(Mandatory)][Alias('Path')][string]$CIPath,
|
||||||
@@ -17,6 +17,25 @@ $ErrorActionPreference = "Stop"
|
|||||||
if ($DefinitionFile -and $Operation) { Write-Error "Cannot use both -DefinitionFile and -Operation"; exit 1 }
|
if ($DefinitionFile -and $Operation) { Write-Error "Cannot use both -DefinitionFile and -Operation"; exit 1 }
|
||||||
if (-not $DefinitionFile -and -not $Operation) { Write-Error "Either -DefinitionFile or -Operation is required"; exit 1 }
|
if (-not $DefinitionFile -and -not $Operation) { Write-Error "Either -DefinitionFile or -Operation is required"; exit 1 }
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
|
|
||||||
# --- Resolve path ---
|
# --- Resolve path ---
|
||||||
if (-not [System.IO.Path]::IsPathRooted($CIPath)) {
|
if (-not [System.IO.Path]::IsPathRooted($CIPath)) {
|
||||||
$CIPath = Join-Path (Get-Location).Path $CIPath
|
$CIPath = Join-Path (Get-Location).Path $CIPath
|
||||||
@@ -351,10 +370,10 @@ function Ensure-Section([string]$sectionName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# --- Parse value: string or JSON array ---
|
# --- Parse value: string or JSON array ---
|
||||||
function Parse-ValueList([string]$val) {
|
function Parse-ValueList([string]$val, [string]$opName) {
|
||||||
$val = $val.Trim()
|
$val = $val.Trim()
|
||||||
if ($val.StartsWith("[")) {
|
if ($val.StartsWith("[")) {
|
||||||
$arr = $val | ConvertFrom-Json
|
$arr = ConvertFrom-JsonInput $val "-Value for operation '$opName'" "a JSON array of command names"
|
||||||
$result = @(); foreach ($item in $arr) { $result += "$item" }
|
$result = @(); foreach ($item in $arr) { $result += "$item" }
|
||||||
return ,$result
|
return ,$result
|
||||||
}
|
}
|
||||||
@@ -519,7 +538,7 @@ function Do-Show([string[]]$commands) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Do-Place([string]$jsonVal) {
|
function Do-Place([string]$jsonVal) {
|
||||||
$def = $jsonVal | ConvertFrom-Json
|
$def = ConvertFrom-JsonInput $jsonVal "-Value for operation 'place'" "a JSON object {command, group}"
|
||||||
$cmdName = Normalize-CmdName "$($def.command)"
|
$cmdName = Normalize-CmdName "$($def.command)"
|
||||||
$groupName = "$($def.group)"
|
$groupName = "$($def.group)"
|
||||||
if (-not $cmdName -or -not $groupName) { Write-Error "place requires {command, group}"; exit 1 }
|
if (-not $cmdName -or -not $groupName) { Write-Error "place requires {command, group}"; exit 1 }
|
||||||
@@ -552,7 +571,7 @@ function Do-Place([string]$jsonVal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Do-Order([string]$jsonVal) {
|
function Do-Order([string]$jsonVal) {
|
||||||
$def = $jsonVal | ConvertFrom-Json
|
$def = ConvertFrom-JsonInput $jsonVal "-Value for operation 'order'" "a JSON object {group, commands:[...]}"
|
||||||
$groupName = "$($def.group)"
|
$groupName = "$($def.group)"
|
||||||
$commands = @($def.commands | ForEach-Object { Normalize-CmdName "$_" })
|
$commands = @($def.commands | ForEach-Object { Normalize-CmdName "$_" })
|
||||||
if (-not $groupName -or $commands.Count -eq 0) { Write-Error "order requires {group, commands:[...]}"; exit 1 }
|
if (-not $groupName -or $commands.Count -eq 0) { Write-Error "order requires {group, commands:[...]}"; exit 1 }
|
||||||
@@ -590,7 +609,7 @@ function Do-Order([string]$jsonVal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Do-SubsystemOrder([string]$jsonVal) {
|
function Do-SubsystemOrder([string]$jsonVal) {
|
||||||
$parsed = $jsonVal | ConvertFrom-Json
|
$parsed = ConvertFrom-JsonInput $jsonVal "-Value for operation 'subsystem-order'" "a JSON array of subsystem paths"
|
||||||
$subsystems = @(); foreach ($s in $parsed) { $subsystems += "$s" }
|
$subsystems = @(); foreach ($s in $parsed) { $subsystems += "$s" }
|
||||||
if ($subsystems.Count -eq 0) { Write-Error "subsystem-order requires array of subsystem paths"; exit 1 }
|
if ($subsystems.Count -eq 0) { Write-Error "subsystem-order requires array of subsystem paths"; exit 1 }
|
||||||
|
|
||||||
@@ -618,7 +637,7 @@ function Do-SubsystemOrder([string]$jsonVal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Do-GroupOrder([string]$jsonVal) {
|
function Do-GroupOrder([string]$jsonVal) {
|
||||||
$parsed = $jsonVal | ConvertFrom-Json
|
$parsed = ConvertFrom-JsonInput $jsonVal "-Value for operation 'group-order'" "a JSON array of group names"
|
||||||
$groups = @(); foreach ($g in $parsed) { $groups += "$g" }
|
$groups = @(); foreach ($g in $parsed) { $groups += "$g" }
|
||||||
if ($groups.Count -eq 0) { Write-Error "group-order requires array of group names"; exit 1 }
|
if ($groups.Count -eq 0) { Write-Error "group-order requires array of group names"; exit 1 }
|
||||||
|
|
||||||
@@ -652,7 +671,7 @@ if ($DefinitionFile) {
|
|||||||
$DefinitionFile = Join-Path (Get-Location).Path $DefinitionFile
|
$DefinitionFile = Join-Path (Get-Location).Path $DefinitionFile
|
||||||
}
|
}
|
||||||
$jsonText = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
$jsonText = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
||||||
$ops = $jsonText | ConvertFrom-Json
|
$ops = ConvertFrom-JsonInput $jsonText $DefinitionFile
|
||||||
if ($ops -is [System.Array]) {
|
if ($ops -is [System.Array]) {
|
||||||
foreach ($op in $ops) { $operations += $op }
|
foreach ($op in $ops) { $operations += $op }
|
||||||
} else {
|
} else {
|
||||||
@@ -669,8 +688,8 @@ foreach ($op in $operations) {
|
|||||||
$opValue = if ($opValueRaw -is [string]) { $opValueRaw } else { $opValueRaw | ConvertTo-Json -Compress }
|
$opValue = if ($opValueRaw -is [string]) { $opValueRaw } else { $opValueRaw | ConvertTo-Json -Compress }
|
||||||
|
|
||||||
switch ($opName) {
|
switch ($opName) {
|
||||||
"hide" { Do-Hide (Parse-ValueList $opValue) }
|
"hide" { Do-Hide (Parse-ValueList $opValue $opName) }
|
||||||
"show" { Do-Show (Parse-ValueList $opValue) }
|
"show" { Do-Show (Parse-ValueList $opValue $opName) }
|
||||||
"place" { Do-Place $opValue }
|
"place" { Do-Place $opValue }
|
||||||
"order" { Do-Order $opValue }
|
"order" { Do-Order $opValue }
|
||||||
"subsystem-order" { Do-SubsystemOrder $opValue }
|
"subsystem-order" { Do-SubsystemOrder $opValue }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# interface-edit v1.18 — Edit 1C CommandInterface.xml (+русские алиасы типов: формы с ё и без)
|
# interface-edit v1.19 — Edit 1C CommandInterface.xml (+русские алиасы типов: формы с ё и без)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -348,10 +348,32 @@ def import_ci_fragment(xml_string):
|
|||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
def parse_value_list(val):
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_value_list(val, op_name):
|
||||||
val = val.strip()
|
val = val.strip()
|
||||||
if val.startswith("["):
|
if val.startswith("["):
|
||||||
arr = ci_json(json.loads(val))
|
arr = ci_json(parse_json_input(val, "-Value for operation '%s'" % op_name, "a JSON array of command names"))
|
||||||
return [str(item) for item in arr]
|
return [str(item) for item in arr]
|
||||||
return [val]
|
return [val]
|
||||||
|
|
||||||
@@ -647,7 +669,8 @@ def main():
|
|||||||
|
|
||||||
def do_place(json_val):
|
def do_place(json_val):
|
||||||
nonlocal add_count, modify_count
|
nonlocal add_count, modify_count
|
||||||
defn = ci_json(json_val if isinstance(json_val, dict) else json.loads(json_val))
|
defn = ci_json(json_val if isinstance(json_val, dict) else parse_json_input(
|
||||||
|
json_val, "-Value for operation 'place'", "a JSON object {command, group}"))
|
||||||
cmd_name = normalize_cmd_name(str(defn["command"]))
|
cmd_name = normalize_cmd_name(str(defn["command"]))
|
||||||
group_name = str(defn["group"])
|
group_name = str(defn["group"])
|
||||||
if not cmd_name or not group_name:
|
if not cmd_name or not group_name:
|
||||||
@@ -675,7 +698,8 @@ def main():
|
|||||||
|
|
||||||
def do_order(json_val):
|
def do_order(json_val):
|
||||||
nonlocal add_count, remove_count
|
nonlocal add_count, remove_count
|
||||||
defn = ci_json(json_val if isinstance(json_val, dict) else json.loads(json_val))
|
defn = ci_json(json_val if isinstance(json_val, dict) else parse_json_input(
|
||||||
|
json_val, "-Value for operation 'order'", "a JSON object {group, commands:[...]}"))
|
||||||
group_name = str(defn["group"])
|
group_name = str(defn["group"])
|
||||||
commands = [normalize_cmd_name(str(c)) for c in defn["commands"]]
|
commands = [normalize_cmd_name(str(c)) for c in defn["commands"]]
|
||||||
if not group_name or not commands:
|
if not group_name or not commands:
|
||||||
@@ -709,7 +733,8 @@ def main():
|
|||||||
|
|
||||||
def do_subsystem_order(json_val):
|
def do_subsystem_order(json_val):
|
||||||
nonlocal add_count, remove_count
|
nonlocal add_count, remove_count
|
||||||
parsed = ci_json(json_val if isinstance(json_val, list) else json.loads(json_val))
|
parsed = ci_json(json_val if isinstance(json_val, list) else parse_json_input(
|
||||||
|
json_val, "-Value for operation 'subsystem-order'", "a JSON array of subsystem paths"))
|
||||||
subsystems = [str(s) for s in parsed]
|
subsystems = [str(s) for s in parsed]
|
||||||
if not subsystems:
|
if not subsystems:
|
||||||
print("subsystem-order requires array of subsystem paths", file=sys.stderr)
|
print("subsystem-order requires array of subsystem paths", file=sys.stderr)
|
||||||
@@ -734,7 +759,8 @@ def main():
|
|||||||
|
|
||||||
def do_group_order(json_val):
|
def do_group_order(json_val):
|
||||||
nonlocal add_count, remove_count
|
nonlocal add_count, remove_count
|
||||||
parsed = ci_json(json_val if isinstance(json_val, list) else json.loads(json_val))
|
parsed = ci_json(json_val if isinstance(json_val, list) else parse_json_input(
|
||||||
|
json_val, "-Value for operation 'group-order'", "a JSON array of group names"))
|
||||||
groups = [str(g) for g in parsed]
|
groups = [str(g) for g in parsed]
|
||||||
if not groups:
|
if not groups:
|
||||||
print("group-order requires array of group names", file=sys.stderr)
|
print("group-order requires array of group names", file=sys.stderr)
|
||||||
@@ -764,7 +790,7 @@ def main():
|
|||||||
if not os.path.isabs(def_file):
|
if not os.path.isabs(def_file):
|
||||||
def_file = os.path.join(os.getcwd(), def_file)
|
def_file = os.path.join(os.getcwd(), def_file)
|
||||||
with open(def_file, "r", encoding="utf-8-sig") as fh:
|
with open(def_file, "r", encoding="utf-8-sig") as fh:
|
||||||
ops = ci_json(json.loads(fh.read()))
|
ops = ci_json(parse_json_input(fh.read(), def_file))
|
||||||
if isinstance(ops, list):
|
if isinstance(ops, list):
|
||||||
operations = ops
|
operations = ops
|
||||||
else:
|
else:
|
||||||
@@ -779,9 +805,9 @@ def main():
|
|||||||
op_value = op.get("value", args.Value or "")
|
op_value = op.get("value", args.Value or "")
|
||||||
|
|
||||||
if op_key == "hide":
|
if op_key == "hide":
|
||||||
do_hide(parse_value_list(op_value))
|
do_hide(parse_value_list(op_value, op_name))
|
||||||
elif op_key == "show":
|
elif op_key == "show":
|
||||||
do_show(parse_value_list(op_value))
|
do_show(parse_value_list(op_value, op_name))
|
||||||
elif op_key == "place":
|
elif op_key == "place":
|
||||||
do_place(op_value)
|
do_place(op_value)
|
||||||
elif op_key == "order":
|
elif op_key == "order":
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# meta-compile v1.95 — Compile 1C metadata object from JSON
|
# meta-compile v1.96 — Compile 1C metadata object from JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -9,6 +9,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# --- 1. Load and validate JSON ---
|
# --- 1. Load and validate JSON ---
|
||||||
@@ -19,7 +38,7 @@ if (-not (Test-Path $JsonPath)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$json = Get-Content -Raw -Encoding UTF8 $JsonPath
|
$json = Get-Content -Raw -Encoding UTF8 $JsonPath
|
||||||
$def = $json | ConvertFrom-Json
|
$def = ConvertFrom-JsonInput $json $JsonPath
|
||||||
|
|
||||||
# --- Support guard (Ext/ParentConfigurations.bin) ---
|
# --- Support guard (Ext/ParentConfigurations.bin) ---
|
||||||
# See docs/1c-support-state-spec.md. Blocks edits of vendor objects "на замке" /
|
# See docs/1c-support-state-spec.md. Blocks edits of vendor objects "на замке" /
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# meta-compile v1.95 — Compile 1C metadata object from JSON
|
# meta-compile v1.96 — Compile 1C metadata object from JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -23,6 +23,29 @@ sys.stderr.reconfigure(encoding="utf-8")
|
|||||||
# молча терял свойства DSL, написанные в другом регистре. Обёртки ниже выравнивают поведение.
|
# молча терял свойства DSL, написанные в другом регистре. Обёртки ниже выравнивают поведение.
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class CIDict(dict):
|
class CIDict(dict):
|
||||||
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
||||||
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
||||||
@@ -377,7 +400,7 @@ if not os.path.isfile(json_path):
|
|||||||
with open(json_path, 'r', encoding='utf-8-sig') as f:
|
with open(json_path, 'r', encoding='utf-8-sig') as f:
|
||||||
json_text = f.read()
|
json_text = f.read()
|
||||||
|
|
||||||
defn = ci_json(json.loads(json_text))
|
defn = ci_json(parse_json_input(json_text, json_path))
|
||||||
|
|
||||||
assert_edit_allowed(output_dir, "editable")
|
assert_edit_allowed(output_dir, "editable")
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# meta-edit v1.38 — Edit existing 1C metadata object XML
|
# meta-edit v1.39 — Edit existing 1C metadata object XML
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[string]$DefinitionFile,
|
[string]$DefinitionFile,
|
||||||
@@ -31,6 +31,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -122,7 +141,7 @@ if ($DefinitionFile) {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
$jsonText = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
$jsonText = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
||||||
$def = $jsonText | ConvertFrom-Json
|
$def = ConvertFrom-JsonInput $jsonText $DefinitionFile
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Resolve object path ---
|
# --- Resolve object path ---
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# meta-edit v1.38 — Edit existing 1C metadata object XML
|
# meta-edit v1.39 — Edit existing 1C metadata object XML
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -13,6 +13,29 @@ from lxml import etree
|
|||||||
|
|
||||||
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
||||||
# регистр не различают, в argparse совпадение точное.
|
# регистр не различают, в argparse совпадение точное.
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class CIDict(dict):
|
class CIDict(dict):
|
||||||
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
||||||
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
||||||
@@ -3255,7 +3278,7 @@ def main():
|
|||||||
if not os.path.exists(args.DefinitionFile):
|
if not os.path.exists(args.DefinitionFile):
|
||||||
die(f"Definition file not found: {args.DefinitionFile}")
|
die(f"Definition file not found: {args.DefinitionFile}")
|
||||||
with open(args.DefinitionFile, "r", encoding="utf-8-sig") as f:
|
with open(args.DefinitionFile, "r", encoding="utf-8-sig") as f:
|
||||||
definition = ci_json(json.load(f))
|
definition = ci_json(parse_json_input(f.read(), args.DefinitionFile))
|
||||||
|
|
||||||
# --- Resolve object path ---
|
# --- Resolve object path ---
|
||||||
object_path = args.ObjectPath
|
object_path = args.ObjectPath
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# mxl-compile v1.51 — Compile 1C spreadsheet from JSON
|
# mxl-compile v1.52 — Compile 1C spreadsheet from JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -9,6 +9,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# --- Support guard (Ext/ParentConfigurations.bin) ---
|
# --- Support guard (Ext/ParentConfigurations.bin) ---
|
||||||
@@ -190,7 +209,7 @@ if (-not (Test-Path $JsonPath)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$json = Get-Content -Raw -Encoding UTF8 $JsonPath
|
$json = Get-Content -Raw -Encoding UTF8 $JsonPath
|
||||||
$def = $json | ConvertFrom-Json
|
$def = ConvertFrom-JsonInput $json $JsonPath
|
||||||
|
|
||||||
# Проверяем НАЛИЧИЕ ключа, а не истинность значения: `columns: 0` — осмысленная величина
|
# Проверяем НАЛИЧИЕ ключа, а не истинность значения: `columns: 0` — осмысленная величина
|
||||||
# (раскладка по умолчанию пустая, все строки живут в именованных раскладках), а пустой
|
# (раскладка по умолчанию пустая, все строки живут в именованных раскладках), а пустой
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# mxl-compile v1.51 — Compile 1C spreadsheet from JSON
|
# mxl-compile v1.52 — Compile 1C spreadsheet from JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
import argparse
|
import argparse
|
||||||
import hashlib
|
import hashlib
|
||||||
@@ -13,6 +13,29 @@ from lxml import etree
|
|||||||
|
|
||||||
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
||||||
# регистр не различают, в argparse совпадение точное.
|
# регистр не различают, в argparse совпадение точное.
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class CIDict(dict):
|
class CIDict(dict):
|
||||||
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
||||||
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
||||||
@@ -805,7 +828,7 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
with open(json_path, 'r', encoding='utf-8-sig') as f:
|
with open(json_path, 'r', encoding='utf-8-sig') as f:
|
||||||
defn = ci_json(json.load(f))
|
defn = ci_json(parse_json_input(f.read(), json_path))
|
||||||
|
|
||||||
# Проверяем НАЛИЧИЕ ключа, а не истинность значения: `columns: 0` — осмысленная величина
|
# Проверяем НАЛИЧИЕ ключа, а не истинность значения: `columns: 0` — осмысленная величина
|
||||||
# (раскладка по умолчанию пустая, все строки живут в именованных раскладках), а пустой
|
# (раскладка по умолчанию пустая, все строки живут в именованных раскладках), а пустой
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# role-compile v1.28 — Compile 1C role from JSON
|
# role-compile v1.29 — Compile 1C role from JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -9,6 +9,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# --- Support guard (Ext/ParentConfigurations.bin) ---
|
# --- Support guard (Ext/ParentConfigurations.bin) ---
|
||||||
@@ -150,7 +169,7 @@ if (-not (Test-Path $JsonPath)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$json = Get-Content -Raw -Encoding UTF8 $JsonPath
|
$json = Get-Content -Raw -Encoding UTF8 $JsonPath
|
||||||
$def = $json | ConvertFrom-Json
|
$def = ConvertFrom-JsonInput $json $JsonPath
|
||||||
|
|
||||||
if (-not $def.name) {
|
if (-not $def.name) {
|
||||||
Write-Error "JSON must have 'name' field (role programmatic name)"
|
Write-Error "JSON must have 'name' field (role programmatic name)"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# role-compile v1.28 — Compile 1C role from JSON
|
# role-compile v1.29 — Compile 1C role from JSON
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
@@ -13,6 +13,29 @@ from lxml import etree
|
|||||||
|
|
||||||
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
||||||
# регистр не различают, в argparse совпадение точное.
|
# регистр не различают, в argparse совпадение точное.
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class CIDict(dict):
|
class CIDict(dict):
|
||||||
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
||||||
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
||||||
@@ -1082,7 +1105,7 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
with open(json_path, 'r', encoding='utf-8-sig') as f:
|
with open(json_path, 'r', encoding='utf-8-sig') as f:
|
||||||
defn = ci_json(json.load(f))
|
defn = ci_json(parse_json_input(f.read(), json_path))
|
||||||
|
|
||||||
if not defn.get('name'):
|
if not defn.get('name'):
|
||||||
print("JSON must have 'name' field (role programmatic name)", file=sys.stderr)
|
print("JSON must have 'name' field (role programmatic name)", file=sys.stderr)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# skd-compile v1.117 — Compile 1C DCS from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
# skd-compile v1.118 — Compile 1C DCS from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[string]$DefinitionFile,
|
[string]$DefinitionFile,
|
||||||
@@ -8,6 +8,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# --- Support guard (Ext/ParentConfigurations.bin) ---
|
# --- Support guard (Ext/ParentConfigurations.bin) ---
|
||||||
@@ -161,11 +180,13 @@ if ($DefinitionFile) {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
$json = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
$json = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
||||||
|
$jsonSource = $DefinitionFile
|
||||||
} else {
|
} else {
|
||||||
$json = $Value
|
$json = $Value
|
||||||
|
$jsonSource = "-Value"
|
||||||
}
|
}
|
||||||
|
|
||||||
$def = $json | ConvertFrom-Json
|
$def = ConvertFrom-JsonInput $json $jsonSource
|
||||||
|
|
||||||
# --- Sentinel check: refuse to compile if JSON contains skd-decompile sentinels ---
|
# --- Sentinel check: refuse to compile if JSON contains skd-decompile sentinels ---
|
||||||
# These mark places the decompiler couldn't reverse cleanly; user must resolve
|
# These mark places the decompiler couldn't reverse cleanly; user must resolve
|
||||||
@@ -1806,7 +1827,7 @@ while ($scanDir) {
|
|||||||
}
|
}
|
||||||
foreach ($stylesFile in $searchPaths) {
|
foreach ($stylesFile in $searchPaths) {
|
||||||
if (Test-Path $stylesFile) {
|
if (Test-Path $stylesFile) {
|
||||||
$userStyles = Get-Content -Raw -Encoding UTF8 $stylesFile | ConvertFrom-Json
|
$userStyles = ConvertFrom-JsonInput (Get-Content -Raw -Encoding UTF8 $stylesFile) $stylesFile
|
||||||
foreach ($prop in $userStyles.PSObject.Properties) {
|
foreach ($prop in $userStyles.PSObject.Properties) {
|
||||||
$preset = @{}
|
$preset = @{}
|
||||||
# Start from 'data' defaults
|
# Start from 'data' defaults
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# skd-compile v1.117 — Compile 1C DCS from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
# skd-compile v1.118 — Compile 1C DCS from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
@@ -12,6 +12,29 @@ from lxml import etree
|
|||||||
|
|
||||||
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
||||||
# регистр не различают, в argparse совпадение точное.
|
# регистр не различают, в argparse совпадение точное.
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class CIDict(dict):
|
class CIDict(dict):
|
||||||
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
||||||
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
||||||
@@ -1629,7 +1652,7 @@ def load_user_styles(base_dir, output_path=None):
|
|||||||
for p in search_paths:
|
for p in search_paths:
|
||||||
if os.path.isfile(p):
|
if os.path.isfile(p):
|
||||||
with open(p, 'r', encoding='utf-8-sig') as f:
|
with open(p, 'r', encoding='utf-8-sig') as f:
|
||||||
user_styles = ci_json(json.load(f))
|
user_styles = ci_json(parse_json_input(f.read(), p))
|
||||||
for name, overrides in user_styles.items():
|
for name, overrides in user_styles.items():
|
||||||
base = dict(AREA_STYLE_PRESETS.get(name, AREA_STYLE_PRESETS['data']))
|
base = dict(AREA_STYLE_PRESETS.get(name, AREA_STYLE_PRESETS['data']))
|
||||||
base.update(overrides)
|
base.update(overrides)
|
||||||
@@ -3063,10 +3086,12 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
with open(def_file, 'r', encoding='utf-8-sig') as f:
|
with open(def_file, 'r', encoding='utf-8-sig') as f:
|
||||||
json_text = f.read()
|
json_text = f.read()
|
||||||
|
json_source = def_file
|
||||||
else:
|
else:
|
||||||
json_text = args.Value
|
json_text = args.Value
|
||||||
|
json_source = "-Value"
|
||||||
|
|
||||||
defn = ci_json(json.loads(json_text))
|
defn = ci_json(parse_json_input(json_text, json_source))
|
||||||
|
|
||||||
if not defn.get('dataSets') or len(defn['dataSets']) == 0:
|
if not defn.get('dataSets') or len(defn['dataSets']) == 0:
|
||||||
print("JSON must have at least one entry in 'dataSets'", file=sys.stderr)
|
print("JSON must have at least one entry in 'dataSets'", file=sys.stderr)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# skd-decompile v0.92 — Decompile 1C DCS Template.xml to JSON DSL (draft)
|
# skd-decompile v0.93 — Decompile 1C DCS Template.xml to JSON DSL (draft)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -9,6 +9,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# --- 0. Resolve and validate input ---
|
# --- 0. Resolve and validate input ---
|
||||||
@@ -1140,7 +1159,7 @@ function Load-UserStyles {
|
|||||||
if (-not $dirPath) { return }
|
if (-not $dirPath) { return }
|
||||||
$stylesPath = Join-Path $dirPath 'skd-styles.json'
|
$stylesPath = Join-Path $dirPath 'skd-styles.json'
|
||||||
if (-not (Test-Path $stylesPath)) { return }
|
if (-not (Test-Path $stylesPath)) { return }
|
||||||
$raw = Get-Content -Raw -Encoding UTF8 $stylesPath | ConvertFrom-Json
|
$raw = ConvertFrom-JsonInput (Get-Content -Raw -Encoding UTF8 $stylesPath) $stylesPath
|
||||||
$script:existingUserPresetsRaw = $raw
|
$script:existingUserPresetsRaw = $raw
|
||||||
foreach ($prop in $raw.PSObject.Properties) {
|
foreach ($prop in $raw.PSObject.Properties) {
|
||||||
# Compile-логика: data defaults → built-in if name match → user keys
|
# Compile-логика: data defaults → built-in if name match → user keys
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# skd-decompile v0.92 — Decompile 1C DCS Template.xml to JSON DSL (draft)
|
# skd-decompile v0.93 — Decompile 1C DCS Template.xml to JSON DSL (draft)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
@@ -9,6 +9,29 @@ import xml.etree.ElementTree as ET
|
|||||||
|
|
||||||
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
||||||
# регистр не различают, в argparse совпадение точное.
|
# регистр не различают, в argparse совпадение точное.
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def ci_parse_args(parser, argv=None):
|
def ci_parse_args(parser, argv=None):
|
||||||
"""parse_args по правилам PS: имена параметров и значения choices регистронезависимы."""
|
"""parse_args по правилам PS: имена параметров и значения choices регистронезависимы."""
|
||||||
argv = list(sys.argv[1:] if argv is None else argv)
|
argv = list(sys.argv[1:] if argv is None else argv)
|
||||||
@@ -1362,9 +1385,8 @@ def load_user_styles(dir_path):
|
|||||||
styles_path = os.path.join(dir_path, 'skd-styles.json')
|
styles_path = os.path.join(dir_path, 'skd-styles.json')
|
||||||
if not os.path.exists(styles_path):
|
if not os.path.exists(styles_path):
|
||||||
return
|
return
|
||||||
import json as _json
|
|
||||||
with open(styles_path, 'r', encoding='utf-8-sig') as f:
|
with open(styles_path, 'r', encoding='utf-8-sig') as f:
|
||||||
raw = _json.load(f)
|
raw = parse_json_input(f.read(), styles_path)
|
||||||
existing_user_presets_raw = raw
|
existing_user_presets_raw = raw
|
||||||
for prop_name, prop_value in raw.items():
|
for prop_name, prop_value in raw.items():
|
||||||
preset = {}
|
preset = {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# subsystem-compile v1.26 — Create 1C subsystem from JSON definition
|
# subsystem-compile v1.27 — Create 1C subsystem from JSON definition
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[string]$DefinitionFile,
|
[string]$DefinitionFile,
|
||||||
@@ -9,6 +9,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# --- 1. Load JSON ---
|
# --- 1. Load JSON ---
|
||||||
@@ -30,11 +49,13 @@ if ($DefinitionFile) {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
$json = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
$json = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
||||||
|
$jsonSource = $DefinitionFile
|
||||||
} else {
|
} else {
|
||||||
$json = $Value
|
$json = $Value
|
||||||
|
$jsonSource = "-Value"
|
||||||
}
|
}
|
||||||
|
|
||||||
$def = $json | ConvertFrom-Json
|
$def = ConvertFrom-JsonInput $json $jsonSource
|
||||||
|
|
||||||
if (-not $def.name) {
|
if (-not $def.name) {
|
||||||
Write-Error "JSON must have 'name' field"
|
Write-Error "JSON must have 'name' field"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# subsystem-compile v1.26 — Create 1C subsystem from JSON definition
|
# subsystem-compile v1.27 — Create 1C subsystem from JSON definition
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
@@ -13,6 +13,29 @@ from lxml import etree
|
|||||||
|
|
||||||
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
||||||
# регистр не различают, в argparse совпадение точное.
|
# регистр не различают, в argparse совпадение точное.
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class CIDict(dict):
|
class CIDict(dict):
|
||||||
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
||||||
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
||||||
@@ -470,10 +493,12 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
with open(def_file, 'r', encoding='utf-8-sig') as f:
|
with open(def_file, 'r', encoding='utf-8-sig') as f:
|
||||||
json_text = f.read()
|
json_text = f.read()
|
||||||
|
json_source = def_file
|
||||||
else:
|
else:
|
||||||
json_text = args.Value
|
json_text = args.Value
|
||||||
|
json_source = "-Value"
|
||||||
|
|
||||||
defn = ci_json(json.loads(json_text))
|
defn = ci_json(parse_json_input(json_text, json_source))
|
||||||
|
|
||||||
if not defn.get('name'):
|
if not defn.get('name'):
|
||||||
print("JSON must have 'name' field", file=sys.stderr)
|
print("JSON must have 'name' field", file=sys.stderr)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# subsystem-edit v1.21 — Edit existing 1C subsystem XML (+тип Bot; cfe-diff/cfe-borrow: недостающие типы)
|
# subsystem-edit v1.22 — Edit existing 1C subsystem XML (+тип Bot; cfe-diff/cfe-borrow: недостающие типы)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)][Alias('Path')][string]$SubsystemPath,
|
[Parameter(Mandatory)][Alias('Path')][string]$SubsystemPath,
|
||||||
@@ -10,6 +10,25 @@ param(
|
|||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# --- Разбор пользовательского JSON ---
|
||||||
|
# Одна строка в stderr вместо дампа исключения ConvertFrom-Json (issue #80): агент по стектрейсу
|
||||||
|
# идёт чинить скрипт, а не свой вызов. $source — файл или параметр. $expected заполняем только
|
||||||
|
# для полиморфного входа: у файла подсказка была бы наполнителем.
|
||||||
|
# Возврат через -NoEnumerate: без него одноэлементный
|
||||||
|
# JSON-массив разворачивался бы в скаляр вторым анруллингом.
|
||||||
|
function ConvertFrom-JsonInput([string]$text, [string]$source, [string]$expected) {
|
||||||
|
try {
|
||||||
|
$parsed = $text | ConvertFrom-Json
|
||||||
|
} catch {
|
||||||
|
$what = if ($expected) { "$source expects $expected" } else { "Invalid JSON in $source" }
|
||||||
|
$got = ($text -replace '\s+', ' ').Trim()
|
||||||
|
if ($got.Length -gt 60) { $got = $got.Substring(0, 60) + '...' }
|
||||||
|
[Console]::Error.WriteLine("[ERROR] ${what}, got: ${got} ($($_.Exception.Message))")
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output -NoEnumerate $parsed
|
||||||
|
}
|
||||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
|
||||||
# --- Content type normalization (plural→singular, Russian→English) ---
|
# --- Content type normalization (plural→singular, Russian→English) ---
|
||||||
@@ -429,10 +448,10 @@ function Expand-SelfClosingElement($container, $parentIndent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# --- Parse value: string or JSON array ---
|
# --- Parse value: string or JSON array ---
|
||||||
function Parse-ValueList([string]$val) {
|
function Parse-ValueList([string]$val, [string]$opName) {
|
||||||
$val = $val.Trim()
|
$val = $val.Trim()
|
||||||
if ($val.StartsWith("[")) {
|
if ($val.StartsWith("[")) {
|
||||||
$arr = $val | ConvertFrom-Json
|
$arr = ConvertFrom-JsonInput $val "-Value for operation '$opName'" "a JSON array of object names"
|
||||||
$result = @(); foreach ($item in $arr) { $result += "$item" }
|
$result = @(); foreach ($item in $arr) { $result += "$item" }
|
||||||
return ,$result
|
return ,$result
|
||||||
}
|
}
|
||||||
@@ -565,7 +584,7 @@ function Do-RemoveChild([string]$childName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Do-SetProperty([string]$jsonVal) {
|
function Do-SetProperty([string]$jsonVal) {
|
||||||
$propDef = $jsonVal | ConvertFrom-Json
|
$propDef = ConvertFrom-JsonInput $jsonVal "-Value for operation 'set-property'" "a JSON object {name, value}"
|
||||||
$propName = "$($propDef.name)"
|
$propName = "$($propDef.name)"
|
||||||
$propValue = "$($propDef.value)"
|
$propValue = "$($propDef.value)"
|
||||||
|
|
||||||
@@ -639,7 +658,7 @@ if ($DefinitionFile) {
|
|||||||
$DefinitionFile = Join-Path (Get-Location).Path $DefinitionFile
|
$DefinitionFile = Join-Path (Get-Location).Path $DefinitionFile
|
||||||
}
|
}
|
||||||
$jsonText = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
$jsonText = Get-Content -Raw -Encoding UTF8 $DefinitionFile
|
||||||
$ops = $jsonText | ConvertFrom-Json
|
$ops = ConvertFrom-JsonInput $jsonText $DefinitionFile
|
||||||
if ($ops -is [System.Array]) {
|
if ($ops -is [System.Array]) {
|
||||||
foreach ($op in $ops) { $operations += $op }
|
foreach ($op in $ops) { $operations += $op }
|
||||||
} else {
|
} else {
|
||||||
@@ -654,8 +673,8 @@ foreach ($op in $operations) {
|
|||||||
$opValue = if ($op.value) { "$($op.value)" } else { "$Value" }
|
$opValue = if ($op.value) { "$($op.value)" } else { "$Value" }
|
||||||
|
|
||||||
switch ($opName) {
|
switch ($opName) {
|
||||||
"add-content" { Do-AddContent (Parse-ValueList $opValue) }
|
"add-content" { Do-AddContent (Parse-ValueList $opValue $opName) }
|
||||||
"remove-content" { Do-RemoveContent (Parse-ValueList $opValue) }
|
"remove-content" { Do-RemoveContent (Parse-ValueList $opValue $opName) }
|
||||||
"add-child" { Do-AddChild $opValue }
|
"add-child" { Do-AddChild $opValue }
|
||||||
"remove-child" { Do-RemoveChild $opValue }
|
"remove-child" { Do-RemoveChild $opValue }
|
||||||
"set-property" { Do-SetProperty $opValue }
|
"set-property" { Do-SetProperty $opValue }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# subsystem-edit v1.21 — Edit existing 1C subsystem XML (+тип Bot; cfe-diff/cfe-borrow: недостающие типы)
|
# subsystem-edit v1.22 — Edit existing 1C subsystem XML (+тип Bot; cfe-diff/cfe-borrow: недостающие типы)
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -13,6 +13,29 @@ from lxml import etree
|
|||||||
|
|
||||||
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
# Регистронезависимый ввод — паритет с PS1: в PowerShell имена параметров и [ValidateSet]
|
||||||
# регистр не различают, в argparse совпадение точное.
|
# регистр не различают, в argparse совпадение точное.
|
||||||
|
|
||||||
|
def parse_json_input(text, source, expected=None):
|
||||||
|
"""Разбор пользовательского JSON: одна строка в stderr вместо traceback (issue #80).
|
||||||
|
|
||||||
|
expected заполняем только для полиморфного входа: у файла подсказка
|
||||||
|
была бы наполнителем — имя файла и текст парсера самодостаточны.
|
||||||
|
|
||||||
|
Импорты внутри тела: копия функции живёт в навыках с разными именами модулей
|
||||||
|
(skd-decompile импортирует json локально как _json), а тело обязано быть одинаковым.
|
||||||
|
"""
|
||||||
|
import json as _pj
|
||||||
|
import sys as _psys
|
||||||
|
try:
|
||||||
|
return _pj.loads(text)
|
||||||
|
except ValueError as exc:
|
||||||
|
what = "%s expects %s" % (source, expected) if expected else "Invalid JSON in %s" % source
|
||||||
|
got = " ".join(str(text).split())
|
||||||
|
if len(got) > 60:
|
||||||
|
got = got[:60] + "..."
|
||||||
|
print("[ERROR] %s, got: %s (%s)" % (what, got, exc), file=_psys.stderr)
|
||||||
|
_psys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class CIDict(dict):
|
class CIDict(dict):
|
||||||
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
# Ключи храним КАК ЕСТЬ: часть из них — имена объектов (табличные части, стандартные
|
||||||
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
# реквизиты), они попадают в XML. Регистронезависим только поиск. Порядок вставки
|
||||||
@@ -515,11 +538,11 @@ def import_fragment(xml_string, doc_root):
|
|||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
|
|
||||||
def parse_value_list(val):
|
def parse_value_list(val, op_name):
|
||||||
"""Parse a string or JSON array into a list of strings."""
|
"""Parse a string or JSON array into a list of strings."""
|
||||||
val = val.strip()
|
val = val.strip()
|
||||||
if val.startswith("["):
|
if val.startswith("["):
|
||||||
arr = ci_json(json.loads(val))
|
arr = ci_json(parse_json_input(val, "-Value for operation '%s'" % op_name, "a JSON array of object names"))
|
||||||
return [str(item) for item in arr]
|
return [str(item) for item in arr]
|
||||||
return [val]
|
return [val]
|
||||||
|
|
||||||
@@ -777,7 +800,8 @@ def main():
|
|||||||
|
|
||||||
def do_set_property(json_val):
|
def do_set_property(json_val):
|
||||||
nonlocal modify_count
|
nonlocal modify_count
|
||||||
prop_def = ci_json(json.loads(json_val))
|
prop_def = ci_json(parse_json_input(
|
||||||
|
json_val, "-Value for operation 'set-property'", "a JSON object {name, value}"))
|
||||||
prop_name = str(prop_def["name"])
|
prop_name = str(prop_def["name"])
|
||||||
prop_value = str(prop_def.get("value", ""))
|
prop_value = str(prop_def.get("value", ""))
|
||||||
|
|
||||||
@@ -874,7 +898,7 @@ def main():
|
|||||||
if not os.path.isabs(def_file):
|
if not os.path.isabs(def_file):
|
||||||
def_file = os.path.join(os.getcwd(), def_file)
|
def_file = os.path.join(os.getcwd(), def_file)
|
||||||
with open(def_file, "r", encoding="utf-8-sig") as fh:
|
with open(def_file, "r", encoding="utf-8-sig") as fh:
|
||||||
ops = ci_json(json.loads(fh.read()))
|
ops = ci_json(parse_json_input(fh.read(), def_file))
|
||||||
if isinstance(ops, list):
|
if isinstance(ops, list):
|
||||||
operations = ops
|
operations = ops
|
||||||
else:
|
else:
|
||||||
@@ -889,9 +913,9 @@ def main():
|
|||||||
op_value = op.get("value", args.Value or "")
|
op_value = op.get("value", args.Value or "")
|
||||||
|
|
||||||
if op_key == "add-content":
|
if op_key == "add-content":
|
||||||
do_add_content(parse_value_list(op_value))
|
do_add_content(parse_value_list(op_value, op_name))
|
||||||
elif op_key == "remove-content":
|
elif op_key == "remove-content":
|
||||||
do_remove_content(parse_value_list(op_value))
|
do_remove_content(parse_value_list(op_value, op_name))
|
||||||
elif op_key == "add-child":
|
elif op_key == "add-child":
|
||||||
do_add_child(op_value)
|
do_add_child(op_value)
|
||||||
elif op_key == "remove-child":
|
elif op_key == "remove-child":
|
||||||
|
|||||||
@@ -295,6 +295,7 @@ ibcmd-проход автоматически `○ skipped`, если рядом
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `name` | да | Название теста (отображается в отчёте) |
|
| `name` | да | Название теста (отображается в отчёте) |
|
||||||
| `input` | нет | JSON-объект, передаётся навыку через temp-файл |
|
| `input` | нет | JSON-объект, передаётся навыку через temp-файл |
|
||||||
|
| `inputRaw` | нет | Строка, пишется во входной файл дословно. Нужна для негативных кейсов про битый JSON: через `input` такой вход невыразим — `JSON.stringify` всегда даёт валидный документ. Приоритетнее `input` |
|
||||||
| `params` | нет | Параметры для `case.<field>` и `workPath` маппинга |
|
| `params` | нет | Параметры для `case.<field>` и `workPath` маппинга |
|
||||||
| `setup` | нет | Переопределение setup из `_skill.json` |
|
| `setup` | нет | Переопределение setup из `_skill.json` |
|
||||||
| `outputPath` | нет | Относительный путь для навыков с `-OutputPath` |
|
| `outputPath` | нет | Относительный путь для навыков с `-OutputPath` |
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Строка вместо JSON у set-panels: ожидаемая форма в сообщении (issue #80)",
|
||||||
|
"input": [
|
||||||
|
{
|
||||||
|
"operation": "set-panels",
|
||||||
|
"value": "Левая панель"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expectError": "-Value for operation 'set-panels' expects a JSON object with panel layout"
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "Битый JSON в файле определения: в сообщении есть имя файла (issue #80)",
|
||||||
|
"preRun": [
|
||||||
|
{
|
||||||
|
"script": "subsystem-compile/scripts/subsystem-compile",
|
||||||
|
"input": {
|
||||||
|
"name": "Продажи"
|
||||||
|
},
|
||||||
|
"args": {
|
||||||
|
"-DefinitionFile": "{inputFile}",
|
||||||
|
"-OutputDir": "{workDir}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"params": {
|
||||||
|
"ciPath": "Subsystems/Продажи/CommandInterface"
|
||||||
|
},
|
||||||
|
"inputRaw": "{ \"operation\": \"hide\",",
|
||||||
|
"expectError": "Invalid JSON in",
|
||||||
|
"expect": {
|
||||||
|
"stderrContains": "__input.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "Строка вместо JSON у order: сообщение с ожидаемой формой, а не стектрейс (issue #80)",
|
||||||
|
"preRun": [
|
||||||
|
{
|
||||||
|
"script": "subsystem-compile/scripts/subsystem-compile",
|
||||||
|
"input": {
|
||||||
|
"name": "Продажи"
|
||||||
|
},
|
||||||
|
"args": {
|
||||||
|
"-DefinitionFile": "{inputFile}",
|
||||||
|
"-OutputDir": "{workDir}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"params": {
|
||||||
|
"ciPath": "Subsystems/Продажи/CommandInterface"
|
||||||
|
},
|
||||||
|
"input": [
|
||||||
|
{
|
||||||
|
"operation": "order",
|
||||||
|
"value": "Catalog.Товары"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expectError": "-Value for operation 'order' expects a JSON object {group, commands:[...]}"
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "group-order из одного элемента: массив не разворачивается в скаляр",
|
||||||
|
"preRun": [
|
||||||
|
{
|
||||||
|
"script": "subsystem-compile/scripts/subsystem-compile",
|
||||||
|
"input": {
|
||||||
|
"name": "Продажи"
|
||||||
|
},
|
||||||
|
"args": {
|
||||||
|
"-DefinitionFile": "{inputFile}",
|
||||||
|
"-OutputDir": "{workDir}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"params": {
|
||||||
|
"ciPath": "Subsystems/Продажи/CommandInterface"
|
||||||
|
},
|
||||||
|
"input": [
|
||||||
|
{
|
||||||
|
"operation": "group-order",
|
||||||
|
"value": "[\"NavigationPanel.Important\"]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expect": {
|
||||||
|
"stdoutContains": "Set group order: 1 entries"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,252 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
|
||||||
|
<Configuration uuid="UUID-001">
|
||||||
|
<InternalInfo>
|
||||||
|
<xr:ContainedObject>
|
||||||
|
<xr:ClassId>UUID-002</xr:ClassId>
|
||||||
|
<xr:ObjectId>UUID-003</xr:ObjectId>
|
||||||
|
</xr:ContainedObject>
|
||||||
|
<xr:ContainedObject>
|
||||||
|
<xr:ClassId>UUID-004</xr:ClassId>
|
||||||
|
<xr:ObjectId>UUID-005</xr:ObjectId>
|
||||||
|
</xr:ContainedObject>
|
||||||
|
<xr:ContainedObject>
|
||||||
|
<xr:ClassId>UUID-006</xr:ClassId>
|
||||||
|
<xr:ObjectId>UUID-007</xr:ObjectId>
|
||||||
|
</xr:ContainedObject>
|
||||||
|
<xr:ContainedObject>
|
||||||
|
<xr:ClassId>UUID-008</xr:ClassId>
|
||||||
|
<xr:ObjectId>UUID-009</xr:ObjectId>
|
||||||
|
</xr:ContainedObject>
|
||||||
|
<xr:ContainedObject>
|
||||||
|
<xr:ClassId>UUID-010</xr:ClassId>
|
||||||
|
<xr:ObjectId>UUID-011</xr:ObjectId>
|
||||||
|
</xr:ContainedObject>
|
||||||
|
<xr:ContainedObject>
|
||||||
|
<xr:ClassId>UUID-012</xr:ClassId>
|
||||||
|
<xr:ObjectId>UUID-013</xr:ObjectId>
|
||||||
|
</xr:ContainedObject>
|
||||||
|
<xr:ContainedObject>
|
||||||
|
<xr:ClassId>UUID-014</xr:ClassId>
|
||||||
|
<xr:ObjectId>UUID-015</xr:ObjectId>
|
||||||
|
</xr:ContainedObject>
|
||||||
|
</InternalInfo>
|
||||||
|
<Properties>
|
||||||
|
<Name>TestConfig</Name>
|
||||||
|
<Synonym>
|
||||||
|
<v8:item>
|
||||||
|
<v8:lang>ru</v8:lang>
|
||||||
|
<v8:content>TestConfig</v8:content>
|
||||||
|
</v8:item>
|
||||||
|
</Synonym>
|
||||||
|
<Comment/>
|
||||||
|
<NamePrefix/>
|
||||||
|
<ConfigurationExtensionCompatibilityMode>Version8_3_24</ConfigurationExtensionCompatibilityMode>
|
||||||
|
<DefaultRunMode>ManagedApplication</DefaultRunMode>
|
||||||
|
<UsePurposes>
|
||||||
|
<v8:Value xsi:type="app:ApplicationUsePurpose">PlatformApplication</v8:Value>
|
||||||
|
</UsePurposes>
|
||||||
|
<ScriptVariant>Russian</ScriptVariant>
|
||||||
|
<DefaultRoles/>
|
||||||
|
<Vendor/>
|
||||||
|
<Version/>
|
||||||
|
<UpdateCatalogAddress/>
|
||||||
|
<IncludeHelpInContents>false</IncludeHelpInContents>
|
||||||
|
<UseManagedFormInOrdinaryApplication>false</UseManagedFormInOrdinaryApplication>
|
||||||
|
<UseOrdinaryFormInManagedApplication>false</UseOrdinaryFormInManagedApplication>
|
||||||
|
<AdditionalFullTextSearchDictionaries/>
|
||||||
|
<CommonSettingsStorage/>
|
||||||
|
<ReportsUserSettingsStorage/>
|
||||||
|
<ReportsVariantsStorage/>
|
||||||
|
<FormDataSettingsStorage/>
|
||||||
|
<DynamicListsUserSettingsStorage/>
|
||||||
|
<URLExternalDataStorage/>
|
||||||
|
<Content/>
|
||||||
|
<DefaultReportForm/>
|
||||||
|
<DefaultReportVariantForm/>
|
||||||
|
<DefaultReportSettingsForm/>
|
||||||
|
<DefaultReportAppearanceTemplate/>
|
||||||
|
<DefaultDynamicListSettingsForm/>
|
||||||
|
<DefaultSearchForm/>
|
||||||
|
<DefaultDataHistoryChangeHistoryForm/>
|
||||||
|
<DefaultDataHistoryVersionDataForm/>
|
||||||
|
<DefaultDataHistoryVersionDifferencesForm/>
|
||||||
|
<DefaultCollaborationSystemUsersChoiceForm/>
|
||||||
|
<RequiredMobileApplicationPermissions/>
|
||||||
|
<UsedMobileApplicationFunctionalities>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>Biometrics</app:functionality>
|
||||||
|
<app:use>true</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>Location</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>BackgroundLocation</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>BluetoothPrinters</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>WiFiPrinters</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>Contacts</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>Calendars</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>PushNotifications</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>LocalNotifications</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>InAppPurchases</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>PersonalComputerFileExchange</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>Ads</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>NumberDialing</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>CallProcessing</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>CallLog</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>AutoSendSMS</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>ReceiveSMS</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>SMSLog</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>Camera</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>Microphone</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>MusicLibrary</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>PictureAndVideoLibraries</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>AudioPlaybackAndVibration</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>BackgroundAudioPlaybackAndVibration</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>InstallPackages</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>OSBackup</app:functionality>
|
||||||
|
<app:use>true</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>ApplicationUsageStatistics</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>BarcodeScanning</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>BackgroundAudioRecording</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>AllFilesAccess</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>Videoconferences</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>NFC</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>DocumentScanning</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>SpeechToText</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>Geofences</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>IncomingShareRequests</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
<app:functionality>
|
||||||
|
<app:functionality>AllIncomingShareRequestsTypesProcessing</app:functionality>
|
||||||
|
<app:use>false</app:use>
|
||||||
|
</app:functionality>
|
||||||
|
</UsedMobileApplicationFunctionalities>
|
||||||
|
<StandaloneConfigurationRestrictionRoles/>
|
||||||
|
<MobileApplicationURLs/>
|
||||||
|
<AllowedIncomingShareRequestTypes/>
|
||||||
|
<MainClientApplicationWindowMode>Normal</MainClientApplicationWindowMode>
|
||||||
|
<DefaultInterface/>
|
||||||
|
<DefaultStyle/>
|
||||||
|
<DefaultLanguage>Language.Русский</DefaultLanguage>
|
||||||
|
<BriefInformation/>
|
||||||
|
<DetailedInformation/>
|
||||||
|
<Copyright/>
|
||||||
|
<VendorInformationAddress/>
|
||||||
|
<ConfigurationInformationAddress/>
|
||||||
|
<DataLockControlMode>Managed</DataLockControlMode>
|
||||||
|
<ObjectAutonumerationMode>NotAutoFree</ObjectAutonumerationMode>
|
||||||
|
<ModalityUseMode>DontUse</ModalityUseMode>
|
||||||
|
<SynchronousPlatformExtensionAndAddInCallUseMode>DontUse</SynchronousPlatformExtensionAndAddInCallUseMode>
|
||||||
|
<InterfaceCompatibilityMode>TaxiEnableVersion8_2</InterfaceCompatibilityMode>
|
||||||
|
<DatabaseTablespacesUseMode>DontUse</DatabaseTablespacesUseMode>
|
||||||
|
<CompatibilityMode>Version8_3_24</CompatibilityMode>
|
||||||
|
<DefaultConstantsForm/>
|
||||||
|
</Properties>
|
||||||
|
<ChildObjects>
|
||||||
|
<Language>Русский</Language>
|
||||||
|
<Subsystem>Продажи</Subsystem>
|
||||||
|
</ChildObjects>
|
||||||
|
</Configuration>
|
||||||
|
</MetaDataObject>
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ClientApplicationInterface xmlns="http://v8.1c.ru/8.2/managed-application/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="InterfaceLayouter">
|
||||||
|
<top>
|
||||||
|
<panel id="UUID-001">
|
||||||
|
<uuid>UUID-002</uuid>
|
||||||
|
</panel>
|
||||||
|
</top>
|
||||||
|
<left>
|
||||||
|
<panel id="UUID-003">
|
||||||
|
<uuid>UUID-004</uuid>
|
||||||
|
</panel>
|
||||||
|
</left>
|
||||||
|
<panelDef id="UUID-004"/>
|
||||||
|
<panelDef id="UUID-005"/>
|
||||||
|
<panelDef id="UUID-006"/>
|
||||||
|
<panelDef id="UUID-002"/>
|
||||||
|
<panelDef id="UUID-007"/>
|
||||||
|
</ClientApplicationInterface>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
|
||||||
|
<Language uuid="UUID-001">
|
||||||
|
<Properties>
|
||||||
|
<Name>Русский</Name>
|
||||||
|
<Synonym>
|
||||||
|
<v8:item>
|
||||||
|
<v8:lang>ru</v8:lang>
|
||||||
|
<v8:content>Русский</v8:content>
|
||||||
|
</v8:item>
|
||||||
|
</Synonym>
|
||||||
|
<Comment/>
|
||||||
|
<LanguageCode>ru</LanguageCode>
|
||||||
|
</Properties>
|
||||||
|
</Language>
|
||||||
|
</MetaDataObject>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
|
||||||
|
<Subsystem uuid="UUID-001">
|
||||||
|
<Properties>
|
||||||
|
<Name>Продажи</Name>
|
||||||
|
<Synonym>
|
||||||
|
<v8:item>
|
||||||
|
<v8:lang>ru</v8:lang>
|
||||||
|
<v8:content>Продажи</v8:content>
|
||||||
|
</v8:item>
|
||||||
|
</Synonym>
|
||||||
|
<Comment/>
|
||||||
|
<IncludeHelpInContents>true</IncludeHelpInContents>
|
||||||
|
<IncludeInCommandInterface>true</IncludeInCommandInterface>
|
||||||
|
<UseOneCommand>false</UseOneCommand>
|
||||||
|
<Explanation/>
|
||||||
|
<Picture/>
|
||||||
|
<Content/>
|
||||||
|
</Properties>
|
||||||
|
<ChildObjects/>
|
||||||
|
</Subsystem>
|
||||||
|
</MetaDataObject>
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CommandInterface xmlns="http://v8.1c.ru/8.3/xcf/extrnprops" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.17">
|
||||||
|
<GroupsOrder>
|
||||||
|
<Group>NavigationPanel.Important</Group>
|
||||||
|
</GroupsOrder>
|
||||||
|
</CommandInterface>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "Битый JSON в файле определения: сообщение с именем файла, а не стектрейс (issue #80)",
|
||||||
|
"inputRaw": "{ \"name\": \"Сломано\",",
|
||||||
|
"expectError": "Invalid JSON in",
|
||||||
|
"expect": {
|
||||||
|
"stderrContains": "__input.json",
|
||||||
|
"filesAbsent": [
|
||||||
|
"Subsystems"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -394,6 +394,19 @@ const FAMILIES = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ─── Разбор пользовательского JSON ─────────────────────────────────────
|
||||||
|
// Сообщение об ошибке разбора одинаково во всех навыках (issue #80): стектрейс парсера
|
||||||
|
// агент читает как «скрипт сломан» и идёт чинить не то место. Вся специфика навыка —
|
||||||
|
// в аргументах source/expected на месте вызова, тело функции общее.
|
||||||
|
{
|
||||||
|
name: 'parse_json_input', py: 'parse_json_input', ps1: 'ConvertFrom-JsonInput',
|
||||||
|
variants: [
|
||||||
|
{ id: 'base', authority: 'interface-edit',
|
||||||
|
consumers: ['cf-edit', 'form-compile', 'form-edit', 'meta-compile', 'meta-edit', 'mxl-compile',
|
||||||
|
'role-compile', 'skd-compile', 'skd-decompile', 'subsystem-compile', 'subsystem-edit'] },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// ─── Семьи, разъехавшиеся целиком ───────────────────────────────────────────
|
// ─── Семьи, разъехавшиеся целиком ───────────────────────────────────────────
|
||||||
|
|||||||
+11
-3
@@ -799,7 +799,12 @@ async function runCaseAsync(testCase, opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write input
|
// Write input
|
||||||
if (caseData.input !== undefined) {
|
// inputRaw пишется дословно: негативный кейс про битый JSON через case.input невыразим —
|
||||||
|
// JSON.stringify всегда даёт валидный документ.
|
||||||
|
if (caseData.inputRaw !== undefined) {
|
||||||
|
inputFile = join(workDir, '__input.json');
|
||||||
|
writeFileSync(inputFile, caseData.inputRaw, 'utf8');
|
||||||
|
} else if (caseData.input !== undefined) {
|
||||||
inputFile = join(workDir, '__input.json');
|
inputFile = join(workDir, '__input.json');
|
||||||
writeFileSync(inputFile, JSON.stringify(caseData.input, null, 2), 'utf8');
|
writeFileSync(inputFile, JSON.stringify(caseData.input, null, 2), 'utf8');
|
||||||
}
|
}
|
||||||
@@ -1020,8 +1025,11 @@ function runCase(testCase, opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Write input JSON if needed
|
// 3. Write input JSON if needed (inputRaw — дословно, см. выше)
|
||||||
if (caseData.input !== undefined) {
|
if (caseData.inputRaw !== undefined) {
|
||||||
|
inputFile = join(workDir, '__input.json');
|
||||||
|
writeFileSync(inputFile, caseData.inputRaw, 'utf8');
|
||||||
|
} else if (caseData.input !== undefined) {
|
||||||
inputFile = join(workDir, '__input.json');
|
inputFile = join(workDir, '__input.json');
|
||||||
writeFileSync(inputFile, JSON.stringify(caseData.input, null, 2), 'utf8');
|
writeFileSync(inputFile, JSON.stringify(caseData.input, null, 2), 'utf8');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user