191 lines
3.9 KiB
Go
191 lines
3.9 KiB
Go
package topdata
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
func isNullLike(value any) bool {
|
|
if value == nil {
|
|
return true
|
|
}
|
|
text, ok := value.(string)
|
|
if !ok {
|
|
return false
|
|
}
|
|
return strings.TrimSpace(text) == nullValue
|
|
}
|
|
|
|
func normalizeWikiMetadataKey(key string) string {
|
|
switch normalizeMetadataKey(key) {
|
|
case "reqfeats", "req_feats":
|
|
return "reqfeats"
|
|
case "generate", "wikigenerate":
|
|
return "generate"
|
|
case "canonical", "wikicanonical":
|
|
return "canonical"
|
|
case "status", "wikistatus":
|
|
return "status"
|
|
case "progressionnotes", "progression_notes", "classprogressionnotes", "class_progression_notes":
|
|
return "progression_notes"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func legacyWikiMetadataField(key string) string {
|
|
switch normalizeMetadataKey(key) {
|
|
case "wikireqfeats":
|
|
return "reqfeats"
|
|
case "wikigenerate":
|
|
return "generate"
|
|
case "wikicanonical":
|
|
return "canonical"
|
|
case "wikistatus":
|
|
return "status"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func parseWikiMetadata(raw any) (map[string]any, error) {
|
|
obj, ok := raw.(map[string]any)
|
|
if !ok {
|
|
return nil, fmt.Errorf("must be an object")
|
|
}
|
|
wiki := map[string]any{}
|
|
for key, value := range obj {
|
|
normalized := normalizeWikiMetadataKey(key)
|
|
if normalized == "" {
|
|
return nil, fmt.Errorf("unknown field %q", key)
|
|
}
|
|
if isNullLike(value) {
|
|
continue
|
|
}
|
|
wiki[normalized] = cloneAuthoringValue(value)
|
|
}
|
|
return wiki, nil
|
|
}
|
|
|
|
func mergeMetadataMaps(base, overlay map[string]any) map[string]any {
|
|
if len(base) == 0 && len(overlay) == 0 {
|
|
return nil
|
|
}
|
|
out := map[string]any{}
|
|
for key, value := range base {
|
|
out[key] = cloneAuthoringValue(value)
|
|
}
|
|
for key, value := range overlay {
|
|
baseValue, hasBase := out[key]
|
|
baseMap, baseIsMap := baseValue.(map[string]any)
|
|
valueMap, valueIsMap := value.(map[string]any)
|
|
if hasBase && baseIsMap && valueIsMap {
|
|
out[key] = mergeMetadataMaps(baseMap, valueMap)
|
|
continue
|
|
}
|
|
out[key] = cloneAuthoringValue(value)
|
|
}
|
|
if len(out) == 0 {
|
|
return nil
|
|
}
|
|
return out
|
|
}
|
|
|
|
func parseExistingMetadata(row map[string]any) (map[string]any, error) {
|
|
rawMeta, ok := lookupField(row, "meta")
|
|
if !ok {
|
|
return nil, nil
|
|
}
|
|
return parseRowMetadata(rawMeta)
|
|
}
|
|
|
|
func setLegacyWikiMetadata(row map[string]any, field string, value any) error {
|
|
wikiKey := legacyWikiMetadataField(field)
|
|
if wikiKey == "" {
|
|
return nil
|
|
}
|
|
|
|
meta, err := parseExistingMetadata(row)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if meta == nil {
|
|
meta = map[string]any{}
|
|
}
|
|
|
|
wiki, _ := meta["wiki"].(map[string]any)
|
|
if wiki == nil {
|
|
wiki = map[string]any{}
|
|
}
|
|
|
|
if isNullLike(value) {
|
|
delete(wiki, wikiKey)
|
|
} else {
|
|
wiki[wikiKey] = cloneAuthoringValue(value)
|
|
}
|
|
|
|
if len(wiki) == 0 {
|
|
delete(meta, "wiki")
|
|
} else {
|
|
meta["wiki"] = wiki
|
|
}
|
|
if len(meta) == 0 {
|
|
delete(row, "meta")
|
|
} else {
|
|
row["meta"] = meta
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func canonicalizeWikiMetadataDocument(obj map[string]any) {
|
|
if rawColumns, ok := obj["columns"].([]any); ok {
|
|
filtered := make([]any, 0, len(rawColumns))
|
|
for _, raw := range rawColumns {
|
|
column, ok := raw.(string)
|
|
if ok && isAuthoringOnlyField(column) {
|
|
continue
|
|
}
|
|
filtered = append(filtered, raw)
|
|
}
|
|
obj["columns"] = filtered
|
|
}
|
|
if rows, ok := obj["rows"].([]any); ok {
|
|
for _, raw := range rows {
|
|
row, ok := raw.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
canonicalizeWikiMetadataRow(row)
|
|
}
|
|
}
|
|
if entries, ok := obj["entries"].(map[string]any); ok {
|
|
for _, raw := range entries {
|
|
row, ok := raw.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
canonicalizeWikiMetadataRow(row)
|
|
}
|
|
}
|
|
if overrides, ok := obj["overrides"].([]any); ok {
|
|
for _, raw := range overrides {
|
|
row, ok := raw.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
canonicalizeWikiMetadataRow(row)
|
|
}
|
|
}
|
|
}
|
|
|
|
func canonicalizeWikiMetadataRow(row map[string]any) {
|
|
for _, field := range []string{"WIKIREQFEATS", "WIKIGENERATE", "WIKICANONICAL", "WIKISTATUS"} {
|
|
value, ok := row[field]
|
|
if !ok {
|
|
continue
|
|
}
|
|
_ = setLegacyWikiMetadata(row, field, value)
|
|
delete(row, field)
|
|
}
|
|
}
|