logos-delivery/tools/confutils/config_option_meta.nim
NagyZoltanPeter 4a6ad73235
Chore: adapt debugapi to wakonodeconf (#3745)
* logosdelivery_get_available_configs collects and format WakuNodeConf options
* simplify debug config output
2026-03-03 23:48:00 +01:00

144 lines
4.5 KiB
Nim

import std/[macros]
type ConfigOptionMeta* = object
fieldName*: string
typeName*: string
cliName*: string
desc*: string
defaultValue*: string
command*: string
proc getPragmaValue(pragmaNode: NimNode, pragmaName: string): string {.compileTime.} =
if pragmaNode.kind != nnkPragma:
return ""
for item in pragmaNode:
if item.kind == nnkExprColonExpr and item[0].eqIdent(pragmaName):
return item[1].repr
return ""
proc getFieldName(fieldNode: NimNode): string {.compileTime.} =
case fieldNode.kind
of nnkPragmaExpr:
if fieldNode.len >= 1:
return getFieldName(fieldNode[0])
of nnkPostfix:
if fieldNode.len >= 2:
return getFieldName(fieldNode[1])
of nnkIdent, nnkSym:
return fieldNode.strVal
else:
discard
return fieldNode.repr
proc getFieldAndPragma(
fieldDef: NimNode
): tuple[fieldName, typeName: string, pragmaNode: NimNode] {.compileTime.} =
if fieldDef.kind != nnkIdentDefs:
return ("", "", newNimNode(nnkEmpty))
let declaredField = fieldDef[0]
var typeNode = fieldDef[1]
var pragmaNode = newNimNode(nnkEmpty)
if declaredField.kind == nnkPragmaExpr:
pragmaNode = declaredField[1]
elif typeNode.kind == nnkPragmaExpr:
pragmaNode = typeNode[1]
typeNode = typeNode[0]
return (getFieldName(declaredField), typeNode.repr, pragmaNode)
proc makeMetaNode(
fieldName, typeName, cliName, desc, defaultValue, command: string
): NimNode {.compileTime.} =
result = newTree(
nnkObjConstr,
ident("ConfigOptionMeta"),
newTree(nnkExprColonExpr, ident("fieldName"), newLit(fieldName)),
newTree(nnkExprColonExpr, ident("typeName"), newLit(typeName)),
newTree(nnkExprColonExpr, ident("cliName"), newLit(cliName)),
newTree(nnkExprColonExpr, ident("desc"), newLit(desc)),
newTree(nnkExprColonExpr, ident("defaultValue"), newLit(defaultValue)),
newTree(nnkExprColonExpr, ident("command"), newLit(command)),
)
macro extractConfigOptionMeta*(T: typedesc): untyped =
proc findFirstRecList(n: NimNode): NimNode {.compileTime.} =
if n.kind == nnkRecList:
return n
for child in n:
let found = findFirstRecList(child)
if not found.isNil:
return found
return nil
proc collectRecList(
recList: NimNode, metas: var seq[NimNode], commandCtx: string
) {.compileTime.} =
for child in recList:
case child.kind
of nnkIdentDefs:
let (fieldName, typeName, pragmaNode) = getFieldAndPragma(child)
if fieldName.len == 0:
continue
let cliName = block:
let n = getPragmaValue(pragmaNode, "name")
if n.len > 0: n else: fieldName
let desc = getPragmaValue(pragmaNode, "desc")
let defaultValue = getPragmaValue(pragmaNode, "defaultValue")
metas.add(
makeMetaNode(fieldName, typeName, cliName, desc, defaultValue, commandCtx)
)
of nnkRecCase:
let discriminator = child[0]
if discriminator.kind == nnkIdentDefs:
let (fieldName, typeName, pragmaNode) = getFieldAndPragma(discriminator)
if fieldName.len > 0:
let cliName = block:
let n = getPragmaValue(pragmaNode, "name")
if n.len > 0: n else: fieldName
let desc = getPragmaValue(pragmaNode, "desc")
let defaultValue = getPragmaValue(pragmaNode, "defaultValue")
metas.add(
makeMetaNode(fieldName, typeName, cliName, desc, defaultValue, commandCtx)
)
for i in 1 ..< child.len:
let branch = child[i]
case branch.kind
of nnkOfBranch:
let branchCtx = branch[0].repr
for j in 1 ..< branch.len:
if branch[j].kind == nnkRecList:
collectRecList(branch[j], metas, branchCtx)
of nnkElse:
for j in 0 ..< branch.len:
if branch[j].kind == nnkRecList:
collectRecList(branch[j], metas, commandCtx)
else:
discard
else:
discard
let typeInst = getTypeInst(T)
var targetType = T
if typeInst.kind == nnkBracketExpr and typeInst.len >= 2:
targetType = typeInst[1]
let typeImpl = getImpl(targetType)
let recList = findFirstRecList(typeImpl)
if recList.isNil:
return newTree(nnkPrefix, ident("@"), newNimNode(nnkBracket))
var metas: seq[NimNode] = @[]
collectRecList(recList, metas, "")
let bracket = newNimNode(nnkBracket)
for node in metas:
bracket.add(node)
result = newTree(nnkPrefix, ident("@"), bracket)