178 lines
4.8 KiB
Nim
178 lines
4.8 KiB
Nim
# SPDX-License-Identifier: LSL-1.0
|
|
# Copyright (c) 2026 Markus Maiwald
|
|
# Stewardship: Self Sovereign Society Foundation
|
|
#
|
|
# This file is part of the Nexus Sovereign Core.
|
|
# See legal/LICENSE_SOVEREIGN.md for license terms.
|
|
|
|
## KDL Parser Integration for NIP
|
|
## Provides KDL parsing functionality for NIP configuration and package files
|
|
|
|
import std/[tables, options]
|
|
import kdl
|
|
|
|
# Re-export main types
|
|
export kdl.KdlVal, kdl.KdlNode, kdl.KdlDoc, kdl.KValKind, kdl.KdlError
|
|
|
|
# Helper procs for easier value access
|
|
proc getString*(val: KdlVal): string =
|
|
## Get string value, raises if not a string
|
|
if val.kind != KString:
|
|
raise newException(ValueError, "KdlVal is not a string")
|
|
val.str
|
|
|
|
proc getInt*(val: KdlVal): int64 =
|
|
## Get int value, raises if not an int
|
|
if val.kind != KInt:
|
|
raise newException(ValueError, "KdlVal is not an int")
|
|
val.num
|
|
|
|
proc getFloat*(val: KdlVal): float64 =
|
|
## Get float value, raises if not a float
|
|
if val.kind != KFloat:
|
|
raise newException(ValueError, "KdlVal is not a float")
|
|
val.fnum
|
|
|
|
proc getBool*(val: KdlVal): bool =
|
|
## Get bool value, raises if not a bool
|
|
if val.kind != KBool:
|
|
raise newException(ValueError, "KdlVal is not a bool")
|
|
val.boolean
|
|
|
|
proc isString*(val: KdlVal): bool =
|
|
## Check if value is a string
|
|
val.kind == KString
|
|
|
|
proc isInt*(val: KdlVal): bool =
|
|
## Check if value is an int
|
|
val.kind == KInt
|
|
|
|
proc isFloat*(val: KdlVal): bool =
|
|
## Check if value is a float
|
|
val.kind == KFloat
|
|
|
|
proc isBool*(val: KdlVal): bool =
|
|
## Check if value is a bool
|
|
val.kind == KBool
|
|
|
|
proc isNull*(val: KdlVal): bool =
|
|
## Check if value is null
|
|
val.kind == KNull
|
|
|
|
# Helper procs for node access
|
|
proc getArg*(node: KdlNode, idx: int): KdlVal =
|
|
## Get argument by index
|
|
if idx < 0 or idx >= node.args.len:
|
|
raise newException(IndexDefect, "Argument index out of bounds")
|
|
node.args[idx]
|
|
|
|
proc getArgString*(node: KdlNode, idx: int): string =
|
|
## Get string argument by index
|
|
node.getArg(idx).getString()
|
|
|
|
proc getArgInt*(node: KdlNode, idx: int): int64 =
|
|
## Get int argument by index
|
|
node.getArg(idx).getInt()
|
|
|
|
proc getArgBool*(node: KdlNode, idx: int): bool =
|
|
## Get bool argument by index
|
|
node.getArg(idx).getBool()
|
|
|
|
proc getProp*(node: KdlNode, key: string): KdlVal =
|
|
## Get property by key
|
|
if not node.props.hasKey(key):
|
|
raise newException(KeyError, "Property not found: " & key)
|
|
node.props[key]
|
|
|
|
proc getPropString*(node: KdlNode, key: string): string =
|
|
## Get string property by key
|
|
node.getProp(key).getString()
|
|
|
|
proc getPropInt*(node: KdlNode, key: string): int64 =
|
|
## Get int property by key
|
|
node.getProp(key).getInt()
|
|
|
|
proc getPropBool*(node: KdlNode, key: string): bool =
|
|
## Get bool property by key
|
|
node.getProp(key).getBool()
|
|
|
|
proc getPropString*(node: KdlNode, key: string, default: string): string =
|
|
## Get string property by key with default
|
|
if node.props.hasKey(key):
|
|
node.props[key].getString()
|
|
else:
|
|
default
|
|
|
|
proc getPropInt*(node: KdlNode, key: string, default: int64): int64 =
|
|
## Get int property by key with default
|
|
if node.props.hasKey(key):
|
|
node.props[key].getInt()
|
|
else:
|
|
default
|
|
|
|
proc getPropBool*(node: KdlNode, key: string, default: bool): bool =
|
|
## Get bool property by key with default
|
|
if node.props.hasKey(key):
|
|
node.props[key].getBool()
|
|
else:
|
|
default
|
|
|
|
proc hasProp*(node: KdlNode, key: string): bool =
|
|
## Check if node has a property
|
|
node.props.hasKey(key)
|
|
|
|
proc findChild*(node: KdlNode, name: string): Option[KdlNode] =
|
|
## Find first child node by name
|
|
for child in node.children:
|
|
if child.name == name:
|
|
return some(child)
|
|
none(KdlNode)
|
|
|
|
proc findChildren*(node: KdlNode, name: string): seq[KdlNode] =
|
|
## Find all child nodes by name
|
|
result = @[]
|
|
for child in node.children:
|
|
if child.name == name:
|
|
result.add(child)
|
|
|
|
# Document helpers
|
|
proc findNode*(doc: KdlDoc, name: string): Option[KdlNode] =
|
|
## Find first top-level node by name
|
|
for node in doc:
|
|
if node.name == name:
|
|
return some(node)
|
|
none(KdlNode)
|
|
|
|
proc findNodes*(doc: KdlDoc, name: string): seq[KdlNode] =
|
|
## Find all top-level nodes by name
|
|
result = @[]
|
|
for node in doc:
|
|
if node.name == name:
|
|
result.add(node)
|
|
|
|
# Parsing functions
|
|
proc parseKdlString*(content: string): KdlDoc =
|
|
## Parse KDL from string
|
|
try:
|
|
result = kdl.parseKdl(content)
|
|
except KdlError as e:
|
|
raise newException(ValueError, "KDL parse error: " & e.msg)
|
|
|
|
proc parseKdlFile*(path: string): KdlDoc =
|
|
## Parse KDL from file
|
|
try:
|
|
result = kdl.parseKdlFile(path)
|
|
except KdlError as e:
|
|
raise newException(ValueError, "KDL parse error in file " & path & ": " & e.msg)
|
|
except IOError as e:
|
|
raise newException(IOError, "Failed to read file " & path & ": " & e.msg)
|
|
|
|
# Serialization
|
|
proc toKdlString*(doc: KdlDoc): string =
|
|
## Convert KdlDoc to string
|
|
$doc
|
|
|
|
proc toKdlString*(node: KdlNode): string =
|
|
## Convert KdlNode to string
|
|
$node
|