Skip to content

Instantly share code, notes, and snippets.

@frozolotl
Last active September 16, 2023 15:04
Show Gist options
  • Save frozolotl/a527ecd9716fe9eb84e0f66b4dcfbc86 to your computer and use it in GitHub Desktop.
Save frozolotl/a527ecd9716fe9eb84e0f66b4dcfbc86 to your computer and use it in GitHub Desktop.
An incomplete implementation of JSONPath in Typst
#let data = (
books: (
(title: "The Final Empire", author: "Brandon Sanderson"),
(title: "The Sword of Kaigen", author: "M.L. Wang"),
),
query: 0,
)
#faux-jsonpath(data, "$.books[0].author")
#faux-jsonpath(data, "$.books[$.query].title")
/// A limited version of JSONPath.
/// It supports the following syntaxes:
/// - `$`: The root object
/// - `@`: The current object
/// - `.field`: Field access
/// - `[0]`: Index by number
/// - `['foo']`: Index by string
#let faux-jsonpath(obj, path) = {
let expr(root, obj, i, path) = {
let current = obj
let i = i
while i < path.len() {
let c = path.at(i)
if c == "$" {
// The root object.
current = root
i += 1
} else if c == "@" {
// The current object.
current = obj
i += 1
} else if c == "." {
// Parse identifier.
i += 1
let match = path.slice(i).match(regex("\p{XID_Start}\p{XID_Continue}*"))
if match == none {
panic("syntax error: invalid field access syntax")
}
current = current.at(match.text)
i += match.end
} else if c == "[" {
i += 1
let (value, i_) = expr(root, current, i, path)
current = current.at(value)
i = i_
if path.at(i) != "]" {
panic("syntax error: missing closing bracket `]`")
}
i += 1
} else if c == "'" {
// Parse string.
i += 1
let start = i
while i < path.len() and path.at(i) != "'" {
i += 1
}
if i == path.len() {
panic("syntax error: missing closing mark `'`")
}
current = path.slice(start, i)
i += 1
break
} else {
// Parse integer.
let match = path.slice(i).match(regex("[0-9]+"))
if match != none {
current = int(match.text)
i += match.end
}
break
}
}
(current, i)
}
let (current, i) = expr(obj, obj, 0, path)
if i != path.len() {
panic("syntax error: unexpected character `" + c + "`")
}
current
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment