toml: support arrays in value key query syntax (#12527)
parent
82010e729d
commit
4b9e8e243c
|
@ -0,0 +1,32 @@
|
||||||
|
import toml
|
||||||
|
|
||||||
|
const toml_text = '
|
||||||
|
modules = [ "ui", "toml" ]
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
[[themes]]
|
||||||
|
name = "Dracula"
|
||||||
|
colors = [ "red", "black", "white" ]
|
||||||
|
|
||||||
|
[[themes]]
|
||||||
|
name = "Lemon"
|
||||||
|
colors = [
|
||||||
|
"green",
|
||||||
|
"yellow",
|
||||||
|
[ "transparent" ]
|
||||||
|
]
|
||||||
|
'
|
||||||
|
|
||||||
|
fn test_value_query_in_array() {
|
||||||
|
toml_doc := toml.parse(toml_text) or { panic(err) }
|
||||||
|
mut value := toml_doc.value('themes[0].colors[1]').string()
|
||||||
|
assert value == 'black'
|
||||||
|
value = toml_doc.value('themes[1].colors[0]').string()
|
||||||
|
assert value == 'green'
|
||||||
|
value = toml_doc.value('themes[1].colors[2].[0]').string()
|
||||||
|
assert value == 'transparent'
|
||||||
|
value = toml_doc.value('modules[1]').string()
|
||||||
|
assert value == 'toml'
|
||||||
|
value = toml_doc.value('errors[11]').default_to('<none>').string()
|
||||||
|
assert value == '<none>'
|
||||||
|
}
|
|
@ -156,28 +156,48 @@ pub fn (d Doc) to_any() Any {
|
||||||
}
|
}
|
||||||
|
|
||||||
// value queries a value from the TOML document.
|
// value queries a value from the TOML document.
|
||||||
// `key` should be in "dotted" form (`a.b.c`).
|
// `key` supports a small query syntax scheme:
|
||||||
// `key` supports quoted keys like `a."b.c"`.
|
// Maps can be queried in "dotted" form e.g. `a.b.c`.
|
||||||
|
// quoted keys are supported as `a."b.c"` or `a.'b.c'`.
|
||||||
|
// Arrays can be queried with `a[0].b[1].[2]`.
|
||||||
pub fn (d Doc) value(key string) Any {
|
pub fn (d Doc) value(key string) Any {
|
||||||
values := d.ast.table as map[string]ast.Value
|
|
||||||
key_split := parse_dotted_key(key) or { return Any(Null{}) }
|
key_split := parse_dotted_key(key) or { return Any(Null{}) }
|
||||||
return d.value_(values, key_split)
|
return d.value_(d.ast.table, key_split)
|
||||||
}
|
}
|
||||||
|
|
||||||
// value_ returns the value found at `key` in the map `values` as `Any` type.
|
// value_ returns the value found at `key` in the map `values` as `Any` type.
|
||||||
fn (d Doc) value_(values map[string]ast.Value, key []string) Any {
|
fn (d Doc) value_(value ast.Value, key []string) Any {
|
||||||
value := values[key[0]] or {
|
assert key.len > 0
|
||||||
return Any(Null{})
|
mut ast_value := ast.Value(ast.Null{})
|
||||||
// TODO decide this
|
mut index := -1
|
||||||
// panic(@MOD + '.' + @STRUCT + '.' + @FN + ' key "$key[0]" does not exist')
|
mut k := key[0]
|
||||||
|
if k.contains('[') {
|
||||||
|
index = k.all_after('[').all_before(']').int()
|
||||||
|
if k.starts_with('[') {
|
||||||
|
k = '' // k.all_after(']')
|
||||||
|
} else {
|
||||||
|
k = k.all_before('[')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if k == '' {
|
||||||
|
a := value as []ast.Value
|
||||||
|
ast_value = a[index] or { return Any(Null{}) }
|
||||||
|
}
|
||||||
|
|
||||||
|
if value is map[string]ast.Value {
|
||||||
|
ast_value = value[k] or { return Any(Null{}) }
|
||||||
|
if index > -1 {
|
||||||
|
a := ast_value as []ast.Value
|
||||||
|
ast_value = a[index] or { return Any(Null{}) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if key.len <= 1 {
|
||||||
|
return d.ast_to_any(ast_value)
|
||||||
}
|
}
|
||||||
// `match` isn't currently very suitable for these types of sum type constructs...
|
// `match` isn't currently very suitable for these types of sum type constructs...
|
||||||
if value is map[string]ast.Value {
|
if ast_value is map[string]ast.Value || ast_value is []ast.Value {
|
||||||
if key.len <= 1 {
|
return d.value_(ast_value, key[1..])
|
||||||
return d.ast_to_any(value)
|
|
||||||
}
|
|
||||||
m := (value as map[string]ast.Value)
|
|
||||||
return d.value_(m, key[1..])
|
|
||||||
}
|
}
|
||||||
return d.ast_to_any(value)
|
return d.ast_to_any(value)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue