Fix #3: コメントを追加
This commit is contained in:
@@ -95,6 +95,9 @@ Notes:
|
|||||||
}
|
}
|
||||||
|
|
||||||
var out []byte
|
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) {
|
if isTabular(opt.from) && isTabular(opt.to) {
|
||||||
t, err := parseTable(input, opt.from, opt.sheet)
|
t, err := parseTable(input, opt.from, opt.sheet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -366,6 +369,8 @@ func writeXLSX(t table, sheet string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(t.Header) > 0 {
|
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)
|
end, _ := excelize.CoordinatesToCellName(len(t.Header), 1)
|
||||||
style, _ := f.NewStyle(&excelize.Style{Font: &excelize.Font{Bold: true}})
|
style, _ := f.NewStyle(&excelize.Style{Font: &excelize.Font{Bold: true}})
|
||||||
_ = f.SetCellStyle(sheet, "A1", end, style)
|
_ = f.SetCellStyle(sheet, "A1", end, style)
|
||||||
@@ -401,6 +406,7 @@ func valueToTable(value any) table {
|
|||||||
}
|
}
|
||||||
flatRows = append(flatRows, flat)
|
flatRows = append(flatRows, flat)
|
||||||
}
|
}
|
||||||
|
// Stable column ordering keeps generated CSV/TSV/XLSX diffs predictable.
|
||||||
sort.Strings(header)
|
sort.Strings(header)
|
||||||
rows := make([][]string, 0, len(flatRows))
|
rows := make([][]string, 0, len(flatRows))
|
||||||
for _, flat := range flatRows {
|
for _, flat := range flatRows {
|
||||||
@@ -418,6 +424,8 @@ func recordsFromValue(value any) []any {
|
|||||||
case []any:
|
case []any:
|
||||||
return v
|
return v
|
||||||
case map[string]any:
|
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"} {
|
for _, key := range []string{"rows", "records", "items"} {
|
||||||
if rows, ok := v[key].([]any); ok {
|
if rows, ok := v[key].([]any); ok {
|
||||||
return rows
|
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) {
|
func flatten(prefix string, value any, out map[string]string) {
|
||||||
switch v := value.(type) {
|
switch v := value.(type) {
|
||||||
case map[string]any:
|
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 {
|
func tableToRecords(t table) []map[string]any {
|
||||||
var records []map[string]any
|
var records []map[string]any
|
||||||
for _, row := range t.Rows {
|
for _, row := range t.Rows {
|
||||||
@@ -501,6 +513,8 @@ func tableToRecords(t table) []map[string]any {
|
|||||||
return records
|
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 {
|
func parseCell(s string) any {
|
||||||
s = strings.TrimSpace(s)
|
s = strings.TrimSpace(s)
|
||||||
if s == "" {
|
if s == "" {
|
||||||
@@ -523,6 +537,8 @@ func parseCell(s string) any {
|
|||||||
|
|
||||||
var pathTokenRE = regexp.MustCompile(`([^\.\[\]]+)|\[(\d+)\]`)
|
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) {
|
func setPath(root map[string]any, path string, value any) {
|
||||||
tokens := parsePath(path)
|
tokens := parsePath(path)
|
||||||
if len(tokens) == 0 {
|
if len(tokens) == 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user