Refactor: migrate POSIX scaffolding to CBOR and JSONC
This commit is contained in:
@@ -9,6 +9,22 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/tailscale/hujson"
|
||||
)
|
||||
|
||||
const (
|
||||
posixSettingsFileName = "settings.cbor"
|
||||
posixLayoutFileName = "layout.cbor"
|
||||
posixHomeFileName = "home.cbor"
|
||||
posixUsersFileName = "users.cbor"
|
||||
posixACLFileName = "acl.cbor"
|
||||
posixFolderFileName = "folder.cbor"
|
||||
posixItemFileName = "item.cbor"
|
||||
posixDataFileName = "data.cbor"
|
||||
posixSchemaFileName = "schema.json"
|
||||
posixManifestFileName = "manifest.jsonc"
|
||||
)
|
||||
|
||||
func samePath(left, right string) bool {
|
||||
@@ -125,14 +141,93 @@ func writeJSONFile(path string, payload any) error {
|
||||
return os.WriteFile(path, data, 0o644)
|
||||
}
|
||||
|
||||
func readJSONFileMap(path string) map[string]any {
|
||||
func writeJSONCFile(path string, payload any) error {
|
||||
parentDir := filepath.Dir(path)
|
||||
if err := os.MkdirAll(parentDir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := json.MarshalIndent(payload, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content := append([]byte("// This file is JSONC. Comments and trailing commas are allowed.\n"), data...)
|
||||
content = append(content, '\n')
|
||||
return os.WriteFile(path, content, 0o644)
|
||||
}
|
||||
|
||||
func writeCBORFile(path string, payload any) error {
|
||||
parentDir := filepath.Dir(path)
|
||||
if err := os.MkdirAll(parentDir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := cbor.Marshal(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, data, 0o644)
|
||||
}
|
||||
|
||||
func readStructuredFileMap(path string) map[string]any {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return map[string]any{}
|
||||
}
|
||||
var payload map[string]any
|
||||
if err := json.Unmarshal(data, &payload); err != nil || payload == nil {
|
||||
var payload any
|
||||
switch strings.ToLower(filepath.Ext(path)) {
|
||||
case ".cbor":
|
||||
err = cbor.Unmarshal(data, &payload)
|
||||
case ".json":
|
||||
err = json.Unmarshal(data, &payload)
|
||||
case ".jsonc":
|
||||
payload, err = decodeJSONCToAny(data)
|
||||
default:
|
||||
return map[string]any{}
|
||||
}
|
||||
return payload
|
||||
if err != nil || payload == nil {
|
||||
return map[string]any{}
|
||||
}
|
||||
normalized, ok := normalizeStructuredValue(payload).(map[string]any)
|
||||
if !ok || normalized == nil {
|
||||
return map[string]any{}
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
|
||||
func decodeJSONCToAny(data []byte) (any, error) {
|
||||
ast, err := hujson.Parse(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ast.Standardize()
|
||||
standardized := ast.Pack()
|
||||
var payload any
|
||||
if err := json.Unmarshal(standardized, &payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
func normalizeStructuredValue(value any) any {
|
||||
switch typed := value.(type) {
|
||||
case map[string]any:
|
||||
normalized := make(map[string]any, len(typed))
|
||||
for key, child := range typed {
|
||||
normalized[key] = normalizeStructuredValue(child)
|
||||
}
|
||||
return normalized
|
||||
case map[any]any:
|
||||
normalized := make(map[string]any, len(typed))
|
||||
for key, child := range typed {
|
||||
normalized[fmt.Sprint(key)] = normalizeStructuredValue(child)
|
||||
}
|
||||
return normalized
|
||||
case []any:
|
||||
normalized := make([]any, len(typed))
|
||||
for index, child := range typed {
|
||||
normalized[index] = normalizeStructuredValue(child)
|
||||
}
|
||||
return normalized
|
||||
default:
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user