Fix #3: コメントを追加
This commit is contained in:
@@ -95,6 +95,9 @@ Notes:
|
||||
}
|
||||
|
||||
var out []byte
|
||||
// Use table as the common representation whenever either side is a
|
||||
// spreadsheet-like format. Structured formats can then share the same
|
||||
// flatten/restore path for CSV, TSV, and XLSX.
|
||||
if isTabular(opt.from) && isTabular(opt.to) {
|
||||
t, err := parseTable(input, opt.from, opt.sheet)
|
||||
if err != nil {
|
||||
@@ -366,6 +369,8 @@ func writeXLSX(t table, sheet string) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
if len(t.Header) > 0 {
|
||||
// The generated workbook is meant for editing, so keep the header row
|
||||
// visible and visually distinct.
|
||||
end, _ := excelize.CoordinatesToCellName(len(t.Header), 1)
|
||||
style, _ := f.NewStyle(&excelize.Style{Font: &excelize.Font{Bold: true}})
|
||||
_ = f.SetCellStyle(sheet, "A1", end, style)
|
||||
@@ -401,6 +406,7 @@ func valueToTable(value any) table {
|
||||
}
|
||||
flatRows = append(flatRows, flat)
|
||||
}
|
||||
// Stable column ordering keeps generated CSV/TSV/XLSX diffs predictable.
|
||||
sort.Strings(header)
|
||||
rows := make([][]string, 0, len(flatRows))
|
||||
for _, flat := range flatRows {
|
||||
@@ -418,6 +424,8 @@ func recordsFromValue(value any) []any {
|
||||
case []any:
|
||||
return v
|
||||
case map[string]any:
|
||||
// Common wrapper keys let TOML and object-shaped inputs represent a
|
||||
// table without adding a format-specific flag.
|
||||
for _, key := range []string{"rows", "records", "items"} {
|
||||
if rows, ok := v[key].([]any); ok {
|
||||
return rows
|
||||
@@ -429,6 +437,8 @@ func recordsFromValue(value any) []any {
|
||||
}
|
||||
}
|
||||
|
||||
// flatten converts nested values into spreadsheet-safe column paths such as
|
||||
// user.name and items[0].sku.
|
||||
func flatten(prefix string, value any, out map[string]string) {
|
||||
switch v := value.(type) {
|
||||
case map[string]any:
|
||||
@@ -485,6 +495,8 @@ func scalarString(value any) string {
|
||||
}
|
||||
}
|
||||
|
||||
// tableToRecords restores each row by interpreting header cells as path
|
||||
// expressions. Empty headers are ignored so spare spreadsheet columns are safe.
|
||||
func tableToRecords(t table) []map[string]any {
|
||||
var records []map[string]any
|
||||
for _, row := range t.Rows {
|
||||
@@ -501,6 +513,8 @@ func tableToRecords(t table) []map[string]any {
|
||||
return records
|
||||
}
|
||||
|
||||
// parseCell keeps spreadsheet round trips useful while avoiding broad type
|
||||
// inference that could surprise users editing IDs or codes.
|
||||
func parseCell(s string) any {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
@@ -523,6 +537,8 @@ func parseCell(s string) any {
|
||||
|
||||
var pathTokenRE = regexp.MustCompile(`([^\.\[\]]+)|\[(\d+)\]`)
|
||||
|
||||
// setPath creates maps and slices as needed for dotted and indexed header
|
||||
// paths. Invalid intermediate shapes are left unchanged instead of guessing.
|
||||
func setPath(root map[string]any, path string, value any) {
|
||||
tokens := parsePath(path)
|
||||
if len(tokens) == 0 {
|
||||
|
||||
Reference in New Issue
Block a user