# 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