mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-08-13 15:03:20 +03:00
fix(mxl-decompile,mxl-compile): дробный размер шрифта
Размер шрифта в платформенных макетах бывает дробным (8.3, 6.8, 9.8, 11.3, 14.3). Оба навыка приводили его к целому: py падал голым ValueError на int(), ps1 ТИХО округлял через [int] — снова шумный отказ против тихой порчи, как было с col. Найдено раундтрипом по корпусу ERP 8.3.24: на стратифицированной выборке из 40 макетов это давало 12 отказов декомпиляции — 30% выборки и ВСЕ отказы этого этапа. После правки декомпиляция не падает ни на одном, цикл переживают 14 макетов вместо 10. Размер читается инвариантной культурой и остаётся целым, когда дробной части нет, иначе "10" превратилось бы в "10.0". Эмиссия в XML тоже переведена на инвариантную культуру: интерполяция строкой отдавала бы "8,3" под русской локалью. Правка на ps1, зазеркалена в py. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ec7e72d0a4
commit
f6a478c85c
@@ -1,4 +1,4 @@
|
||||
# mxl-compile v1.16 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
||||
# mxl-compile v1.17 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -209,10 +209,29 @@ $defaultWidth = if ($def.defaultWidth) { [int]$def.defaultWidth } else { 10 }
|
||||
$fontMap = [ordered]@{} # name -> 0-based index
|
||||
$fontEntries = @() # array of hashtables
|
||||
|
||||
# Размер шрифта бывает дробным (8.3, 11.3). [int] его ТИХО округлял. Читаем инвариантной
|
||||
# культурой и держим целым, когда дробной части нет, — иначе "10" стало бы "10.0".
|
||||
function ConvertTo-FontSize {
|
||||
param($raw)
|
||||
$s = [string]$raw
|
||||
if ([string]::IsNullOrWhiteSpace($s)) { return 0 }
|
||||
$d = 0.0
|
||||
if (-not [double]::TryParse($s, [System.Globalization.NumberStyles]::Float,
|
||||
[System.Globalization.CultureInfo]::InvariantCulture, [ref]$d)) { return 0 }
|
||||
if ($d -eq [math]::Floor($d)) { return [int]$d }
|
||||
return $d
|
||||
}
|
||||
|
||||
# Число в XML-атрибут: интерполяция строкой отдала бы "8,3" под русской культурой.
|
||||
function Format-Num {
|
||||
param($v)
|
||||
return [System.Convert]::ToString($v, [System.Globalization.CultureInfo]::InvariantCulture)
|
||||
}
|
||||
|
||||
function Add-Font {
|
||||
param([string]$name, $fontDef)
|
||||
$face = if ($fontDef.face) { $fontDef.face } else { "Arial" }
|
||||
$size = if ($fontDef.size) { [int]$fontDef.size } else { 10 }
|
||||
$size = if ($fontDef.size) { ConvertTo-FontSize $fontDef.size } else { 10 }
|
||||
$bold = if ($fontDef.bold -eq $true) { "true" } else { "false" }
|
||||
$italic = if ($fontDef.italic -eq $true) { "true" } else { "false" }
|
||||
$underline = if ($fontDef.underline -eq $true) { "true" } else { "false" }
|
||||
@@ -1012,7 +1031,7 @@ if ($hasThickBorders) {
|
||||
|
||||
# 7i. Font palette
|
||||
foreach ($fe in $fontEntries) {
|
||||
X "`t<font faceName=`"$($fe.Face)`" height=`"$($fe.Size)`" bold=`"$($fe.Bold)`" italic=`"$($fe.Italic)`" underline=`"$($fe.Underline)`" strikeout=`"$($fe.Strikeout)`" kind=`"Absolute`" scale=`"100`"/>"
|
||||
X "`t<font faceName=`"$($fe.Face)`" height=`"$(Format-Num $fe.Size)`" bold=`"$($fe.Bold)`" italic=`"$($fe.Italic)`" underline=`"$($fe.Underline)`" strikeout=`"$($fe.Strikeout)`" kind=`"Absolute`" scale=`"100`"/>"
|
||||
}
|
||||
|
||||
# 7j. Format palette
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# mxl-compile v1.16 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
||||
# mxl-compile v1.17 — Compile 1C spreadsheet from JSON (+write_xml_file/write_utf8_bom: общий эталон записи)
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
import argparse
|
||||
import json
|
||||
@@ -297,6 +297,19 @@ def format_rank(ver):
|
||||
return int(m.group(1)) * 100 + int(m.group(2)) if m else 0
|
||||
|
||||
|
||||
def to_font_size(raw):
|
||||
"""Размер шрифта бывает дробным (8.3, 11.3). int() на таком падал, ps1 ТИХО округлял.
|
||||
Целое держим целым, иначе "10" превратилось бы в "10.0"."""
|
||||
s = str(raw).strip() if raw is not None else ''
|
||||
if not s:
|
||||
return 0
|
||||
try:
|
||||
d = float(s)
|
||||
except (TypeError, ValueError):
|
||||
return 0
|
||||
return int(d) if d == int(d) else d
|
||||
|
||||
|
||||
def parse_col_value(val):
|
||||
"""Позиция колонки как целое, иначе None. Аналог [int]::TryParse в ps1:
|
||||
целое из JSON приходит int, "3" — строкой, 3.0 — float (ps1 печатает такое как "3")."""
|
||||
@@ -351,7 +364,7 @@ def main():
|
||||
|
||||
def add_font(name, font_def):
|
||||
face = font_def.get('face', 'Arial') if font_def else 'Arial'
|
||||
size = int(font_def.get('size', 10)) if font_def else 10
|
||||
size = to_font_size(font_def.get('size', 10)) if font_def else 10
|
||||
bold = 'true' if font_def and font_def.get('bold') is True else 'false'
|
||||
italic = 'true' if font_def and font_def.get('italic') is True else 'false'
|
||||
underline = 'true' if font_def and font_def.get('underline') is True else 'false'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# mxl-decompile v1.2 — Decompile 1C spreadsheet to JSON
|
||||
# mxl-decompile v1.3 — Decompile 1C spreadsheet to JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
param(
|
||||
[Parameter(Mandatory)]
|
||||
@@ -31,11 +31,25 @@ $ns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
|
||||
# --- 2. Extract font palette ---
|
||||
|
||||
# Размер шрифта бывает дробным (8.3, 11.3 — в корпусе ERP это треть макетов). [int] его
|
||||
# ТИХО округлял, а py-порт падал на int(). Читаем инвариантной культурой и держим целым,
|
||||
# когда дробной части нет, — иначе "10" превратилось бы в "10.0".
|
||||
function ConvertTo-FontSize {
|
||||
param($raw)
|
||||
$s = [string]$raw
|
||||
if ([string]::IsNullOrWhiteSpace($s)) { return 0 }
|
||||
$d = 0.0
|
||||
if (-not [double]::TryParse($s, [System.Globalization.NumberStyles]::Float,
|
||||
[System.Globalization.CultureInfo]::InvariantCulture, [ref]$d)) { return 0 }
|
||||
if ($d -eq [math]::Floor($d)) { return [int]$d }
|
||||
return $d
|
||||
}
|
||||
|
||||
$rawFonts = @()
|
||||
foreach ($fNode in $root.SelectNodes("d:font", $ns)) {
|
||||
$rawFonts += @{
|
||||
Face = $fNode.GetAttribute("faceName")
|
||||
Size = [int]$fNode.GetAttribute("height")
|
||||
Size = ConvertTo-FontSize $fNode.GetAttribute("height")
|
||||
Bold = $fNode.GetAttribute("bold") -eq "true"
|
||||
Italic = $fNode.GetAttribute("italic") -eq "true"
|
||||
Underline = $fNode.GetAttribute("underline") -eq "true"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# mxl-decompile v1.2 — Decompile 1C spreadsheet to JSON
|
||||
# mxl-decompile v1.3 — Decompile 1C spreadsheet to JSON
|
||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||
|
||||
import argparse
|
||||
@@ -56,6 +56,19 @@ def text_of(node):
|
||||
return None
|
||||
|
||||
|
||||
def to_font_size(raw):
|
||||
"""Размер шрифта бывает дробным (8.3, 11.3 — в корпусе ERP это треть макетов).
|
||||
int() на таком падал, а ps1 ТИХО округлял. Целое держим целым, иначе "10" → "10.0"."""
|
||||
s = str(raw).strip() if raw is not None else ''
|
||||
if not s:
|
||||
return 0
|
||||
try:
|
||||
d = float(s)
|
||||
except (TypeError, ValueError):
|
||||
return 0
|
||||
return int(d) if d == int(d) else d
|
||||
|
||||
|
||||
def int_of(node, default=0):
|
||||
if node is not None and node.text:
|
||||
return int(node.text)
|
||||
@@ -207,7 +220,7 @@ def main():
|
||||
for f_node in findall(root, "d:font"):
|
||||
raw_fonts.append({
|
||||
"Face": f_node.get("faceName", ""),
|
||||
"Size": int(f_node.get("height", "0")),
|
||||
"Size": to_font_size(f_node.get("height", "0")),
|
||||
"Bold": f_node.get("bold") == "true",
|
||||
"Italic": f_node.get("italic") == "true",
|
||||
"Underline": f_node.get("underline") == "true",
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "Дробный размер шрифта сохраняется",
|
||||
"input": {
|
||||
"columns": 2,
|
||||
"fonts": {
|
||||
"default": { "face": "Arial", "size": 10 },
|
||||
"мелкий": { "face": "Arial", "size": 8.3 },
|
||||
"крупный": { "face": "Arial", "size": 11.3, "bold": true }
|
||||
},
|
||||
"styles": {
|
||||
"мелкий": { "font": "мелкий" },
|
||||
"крупный": { "font": "крупный" }
|
||||
},
|
||||
"areas": [
|
||||
{
|
||||
"name": "Шапка",
|
||||
"rows": [
|
||||
{ "cells": [{ "col": 1, "style": "крупный", "text": "Заголовок" }, { "col": 2, "style": "мелкий", "text": "сноска" }] }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"outputPath": "Template.xml"
|
||||
},
|
||||
"validatePath": "Template.xml",
|
||||
"expect": {
|
||||
"files": ["Template.xml"],
|
||||
"fileContains": {
|
||||
"file": "Template.xml",
|
||||
"text": ["height=\"8.3\"", "height=\"11.3\"", "height=\"10\""]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document xmlns="http://v8.1c.ru/8.2/data/spreadsheet" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<languageSettings>
|
||||
<currentLanguage>ru</currentLanguage>
|
||||
<defaultLanguage>ru</defaultLanguage>
|
||||
<languageInfo>
|
||||
<id>ru</id>
|
||||
<code>Русский</code>
|
||||
<description>Русский</description>
|
||||
</languageInfo>
|
||||
</languageSettings>
|
||||
<columns>
|
||||
<size>2</size>
|
||||
</columns>
|
||||
<rowsItem>
|
||||
<index>0</index>
|
||||
<row>
|
||||
<c>
|
||||
<i>0</i>
|
||||
<c>
|
||||
<f>2</f>
|
||||
<tl>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Заголовок</v8:content>
|
||||
</v8:item>
|
||||
</tl>
|
||||
</c>
|
||||
</c>
|
||||
<c>
|
||||
<i>1</i>
|
||||
<c>
|
||||
<f>3</f>
|
||||
<tl>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>сноска</v8:content>
|
||||
</v8:item>
|
||||
</tl>
|
||||
</c>
|
||||
</c>
|
||||
</row>
|
||||
</rowsItem>
|
||||
<templateMode>true</templateMode>
|
||||
<defaultFormatIndex>1</defaultFormatIndex>
|
||||
<height>1</height>
|
||||
<vgRows>1</vgRows>
|
||||
<namedItem xsi:type="NamedItemCells">
|
||||
<name>Шапка</name>
|
||||
<area>
|
||||
<type>Rows</type>
|
||||
<beginRow>0</beginRow>
|
||||
<endRow>0</endRow>
|
||||
<beginColumn>-1</beginColumn>
|
||||
<endColumn>-1</endColumn>
|
||||
</area>
|
||||
</namedItem>
|
||||
<font faceName="Arial" height="10" bold="false" italic="false" underline="false" strikeout="false" kind="Absolute" scale="100"/>
|
||||
<font faceName="Arial" height="8.3" bold="false" italic="false" underline="false" strikeout="false" kind="Absolute" scale="100"/>
|
||||
<font faceName="Arial" height="11.3" bold="true" italic="false" underline="false" strikeout="false" kind="Absolute" scale="100"/>
|
||||
<format>
|
||||
<width>10</width>
|
||||
</format>
|
||||
<format>
|
||||
<font>2</font>
|
||||
<fillType>Text</fillType>
|
||||
</format>
|
||||
<format>
|
||||
<font>1</font>
|
||||
<fillType>Text</fillType>
|
||||
</format>
|
||||
</document>
|
||||
Reference in New Issue
Block a user