mq is a command-line tool that processes Markdown using a syntax similar to jq. It’s written in Rust, allowing you to easily slice, filter, map, and transform structured data.
Why mq?
mq makes working with Markdown files as easy as jq makes working with JSON. It’s especially useful for:
- LLM Workflows: Efficiently manipulate and process Markdown used in LLM prompts and outputs
- Documentation Management: Extract, transform, and organize content across multiple documentation files
- Content Analysis: Quickly extract specific sections or patterns from Markdown documents
- Batch Processing: Apply consistent transformations across multiple Markdown files
Features
- Slice and Filter: Extract specific parts of your Markdown documents with ease.
- Map and Transform: Apply transformations to your Markdown content.
- Command-line Interface: Simple and intuitive CLI for quick operations.
- Extensibility: Easily extendable with custom functions.
- Built-in support: Filter and transform content with many built-in functions and selectors.
- REPL Support: Interactive command-line REPL for testing and experimenting.
- IDE Support: VSCode Extension and Language Server Protocol (LSP) support for custom function development.
This section guides you through the installation of mq.
Install
To install mq
, you can use cargo
:
cargo install --git https://github.com/harehare/mq.git mq-cli
# Installing from cargo is under preparation.
cargo install mq-cli
Docker
$ docker run --rm ghcr.io/harehare/mq:0.1.0-preview
Visual Studio Code Extension
You can install the VSCode extension from the Visual Studio Marketplace.
Playground
An Online Playground is available, powered by WebAssembly.
Example
under preparation
Hello world
# Hello world
select(or(.[], .code, .h)) | upcase() | add(" Hello World")
Markdown TOC
.h
| let link = to_link(add("#", to_text(self)), to_text(self), "")
| if (is_h1()):
to_md_list(link, 1)
elif (is_h2()):
to_md_list(link, 2)
elif (is_h3()):
to_md_list(link, 3)
elif (is_h4()):
to_md_list(link, 4)
elif (is_h5()):
to_md_list(link, 5)
else:
None
Exclude code
select(not(.code))
Extract js code
.code("js")
Extract table
.[1][]
Extract list
.[1]
Extract MDX
select(is_mdx())
Custom function
def snake_to_camel(x):
let words = split(x, "_")
| foreach (word, words):
let first_char = upcase(first(word))
| let rest_str = downcase(slice(word, 1, len(word)))
| add(first_char, rest_str);
| join("");
| snake_to_camel()
Generate sitemap
def sitemap(item, base_url):
let path = replace(to_text(item), ".md", ".html")
| let loc = add(base_url, path)
| s"<url>
<loc>${loc}</loc>
<priority>1.0</priority>
</url>";
This is a reference documentation for the mq.
CLI
The mq command-line interface provides tools for querying and manipulating markdown content. Below is the complete reference for all available commands and options.
Usage: mq [OPTIONS] [QUERY OR FILE] [FILES]... [COMMAND]
Commands:
repl Start a REPL session for interactive query execution
fmt Format mq or markdown files based on specified formatting options
completion Generate shell completion scripts for supported shells
docs Show functions documentation for the query
help Print this message or the help of the given subcommand(s)
Arguments:
[QUERY OR FILE]
[FILES]...
Options:
-f, --from-file load filter from the file
-R, --raw-input Reads each line as a string
-n, --null-input Use empty string as the single input value
-L, --directory <MODULE_DIRECTORIES> Search modules from the directory
-M, --module-names <MODULE_NAMES> Load additional modules from specified files
--args <NAME> <VALUE> Sets string that can be referenced at runtime
--rawfile <NAME> <FILE> Sets file contents that can be referenced at runtime
--mdx Enable MDX parsing
-c, --compact-output pretty print
-F, --output-format <OUTPUT_FORMAT> Compact instead of pretty-printed output [default: markdown] [possible values: markdown, html, text]
-U, --update Update the input markdown
--unbuffered Unbuffered output
--list-style <LIST_STYLE> Set the list style for markdown output [default: dash] [possible values: dash, plus, star]
-o, --output <FILE> Output to the specified file
-v, --verbose... Increase logging verbosity
-q, --quiet... Decrease logging verbosity
-h, --help Print help
-V, --version Print version
Examples:
To filter markdown nodes:
$ mq 'query' file.md
To read query from file:
$ mq -f 'file' file.md
To start a REPL session:
$ mq repl
To format mq file:
$ mq fmt --check file.mq
Types and Values
Values
42
(a number)"Hello, world!"
(a string)array(1, 2, 3)
(an array)true
,false
(a boolean)None
Types
Type | Description | Examples |
---|---|---|
Number | Represents numeric values. | 1 , 3.14 , -42 |
String | Represents sequences of characters, including Unicode code points and escape sequences in the form of \{0x000} . | "hello" , "123" , "😊" , "\u{1F600}" |
Boolean | Represents truth values. | true , false |
Array | Represents ordered collections of values. | array(1, 2, 3) |
Function | Represents executable code. | def foo(): 42; let name = def foo(): 42; |
Environment Variables
A module handling environment-specific functionality.
__FILE__
: Contains the path to the file currently being processed.
Conditional expressions and comparison operators in mq allow for decision-making based on the evaluation of conditions, enabling dynamic behavior in your queries.
Conditionals
mq supports standard conditional operations through the following functions:
and(a, b)
- Returns true if botha
andb
are trueor(a, b)
- Returns true if eithera
orb
is truenot(a)
- Returns true ifa
is false
Examples
# Basic comparisons
and(true, true, true)
# => true
or(true, false, true)
# => true
not(false)
# => true
Comparisons
mq provides comparison functionality through built-in functions.
Basic Comparisons
Standard comparison operators are supported:
eq(a, b)
- Returns true ifa
equalsb
ne(a, b)
- Returns true ifa
does not equalb
gt(a, b)
- Returns true ifa
is greater thanb
gte(a, b)
- Returns true ifa
is greater than or equal tob
lt(a, b)
- Returns true ifa
is less thanb
lte(a, b)
- Returns true ifa
is less than or equal tob
Examples
# Basic comparisons
eq(1, 1)
# => true
gt(2, 1)
# => true
lte("a", "b")
# => true
# String comparisons
eq("hello", "hello")
# => true
gt("xyz", "abc")
# => true
# Numeric comparisons
gte(5.5, 5.0)
# => true
lt(-1, 0)
# => true
# Logical operations
and(true, false)
# => false
or(true, false)
# => true
not(false)
# => true
# Complex conditions
and(gt(x, 0), lt(x, 10))
# => true if 0 < x < 10
This section outlines the syntax rules in mq, providing a clear reference for writing valid code.
Pipe Operator
A functional operator that allows chaining multiple filter operations together.
Usage
The pipe operator (|
) enables sequential processing of filters, where the output of one filter becomes the input of the next filter.
Examples
# Basic pipe usage
42 | add(1) | mul(2)
# => 86
# Multiple transformations
let mul2 = def mul2(x): mul(x, 2);
let gt4 = def gt4(x): gt(x, 4);
array(1, 2, 3) | map(mul2) | filter(gt4)
# => [6]
# Function composition
let double = def _double(x): mul(x, 2);
let add_one = def _add_one(x): add(x, 1);
5 | double(self) | add_one(self)
# => 11
? Operator
The ? operator is a safe navigation operator that provides null-safe operations.
Usage
When applied to a None value, the ? operator prevents errors by returning None instead of raising an exception.
Examples
# Safe access with ? operator
let x = None | x | add?(1)
# => None
# Chaining with ? operator
None | add?(1) | mul?(2)
# => None
# Normal operation when value exists
42 | add?(1)
# => 43
Environment variables
Environment variables can be referenced using $XXX syntax, where XXX represents the name of the environment variable. For example:
$PATH
- References the PATH environment variable$HOME
- References the HOME environment variable$USER
- References the current user’s username
This syntax is commonly used in shell scripts and configuration files to access system-level environment variables.
Def Expression
The def expression defines reusable functions with parameters:
Examples
# Function that doubles input
def double(x):
mul(x, 2);
# Function with conditional logic
def is_positive(x):
gt(x, 0);
# Composition of functions
def add_then_double(x, y):
add(x, y) | double(self);
Let Expression
The let expression binds a value to an identifier for later use:
# Binds 42 to x
let x = 42
# Uses x in an expression
let y = add(x, 1)
# Binds `add` function to z
let z = def _add(x): add(x, 1); | z(1)
If Expression
The if expression evaluates a condition and executes code based on the result:
if (eq(x, 1)):
"one"
elif (eq(x, 2)):
"two"
else:
"other"
The if expression can be nested and chained with elif and else clauses. The conditions must evaluate to boolean values.
While Expression
The while loop repeatedly executes code while a condition is true:
let i = 0 |
while (lt(i, 3)):
let i = add(i, 1) | i;
# => [1, 2, 3]
The while
loop in this context returns an array containing all elements processed during the iteration. As the loop executes, it collects each processed value into an array, which is then returned as the final result once the loop condition becomes false.
Key points:
- Creates a new array from loop iterations
- Each loop cycle’s result is added to the array
- Returns the complete array after all iterations
- Similar to map/collect functionality but with while loop control
Until Expression
The until loop repeatedly executes code until a condition becomes true:
let x = 5 |
until(gt(x, 0)):
let x = sub(x, 1) | x;
# => 0
Until loops are similar to while loops but continue until the condition becomes true instead of while the condition remains true.
Foreach Expression
The foreach loop iterates over elements in an array:
let items = array(1, 2, 3) |
foreach (x, items):
sub(x, 1);
# => array(0, 1, 2)
Foreach loops are useful for:
- Processing arrays element by element
- Mapping operations across collections
- Filtering and transforming data
Comments
Similar to jq, comments starting with #
are doc-comments.
# doc-comment
let value = add(2, 3);
Include
Loads functions from an external file using the syntax include "module_name"
.
The include directive searches for .mq files in the following locations:
$HOME/.mq
- User’s home directory mq folder$ORIGIN/../lib/mq
- Library directory relative to the source file$ORIGIN/../lib
- Parent lib directory relative to the source file
include "module_name"
Examples
# Include math functions from math.mq
include "math"
# Now we can use functions defined in math.mq
let result = add(2, 3)
Self
The current value being processed can be referenced as self
. When there are insufficient arguments provided in a method call, the current value (self
) is automatically passed as the first argument.
Examples
# These expressions are equivalent
"hello" | upcase()
"hello" | upcase(self)
String Interpolation
String Interpolation allow embedding expressions directly inside string literals. In mq, an interpolated string is prefixed with s"
and variables can be embedded using ${}
syntax.
Syntax
s"text ${ident} more text"
Examples
let name = "Alice"
| let age = 30
| s"Hello, my name is ${name} and I am ${age} years old."
# => Output: "Hello, my name is Alice and I am 30 years old."
This page provides an introduction to the built-in selectors and functions available in mq. These are predefined components that you can use in your queries without having to define them yourself.
Builtin functions
Function Name | Description | Parameters | Example |
---|---|---|---|
abs | Returns the absolute value of the given number. | number | abs(number) |
add | Adds two values. | value1 , value2 | add(value1, value2) |
and | Performs a logical AND operation on two boolean values. | value1 , value2 | and(value1, value2) |
array | Creates an array from the given values. | values | array(values) |
arrays | Returns array if input is array, None otherwise | a | arrays(a) |
assert | Verifies that a condition is true and raises an error if it’s false. | cond | assert(cond) |
assert | Asserts that two values are equal, returns the value if true, otherwise raises an error. | value1 , value2 | assert(value1, value2) |
base64 | Encodes the given string to base64. | input | base64(input) |
base64d | Decodes the given base64 string. | input | base64d(input) |
booleans | Returns boolean if input is boolean, None otherwise | b | booleans(b) |
ceil | Rounds the given number up to the nearest integer. | number | ceil(number) |
compact | Removes None values from the given array. | array | compact(array) |
contains | Checks if string contains a substring | haystack , needle | contains(haystack, needle) |
csv2table | Convert csv string to markdown table | csv | csv2table(csv) |
debug | Prints the debug information of the given value. | value | debug(value) |
del | Deletes the element at the specified index in the array or string. | array_or_string , index | del(array_or_string, index) |
div | Divides the first value by the second value. | value1 , value2 | div(value1, value2) |
downcase | Converts the given string to lowercase. | input | downcase(input) |
ends_with | Checks if the given string ends with the specified substring. | string , substring | ends_with(string, substring) |
eq | Checks if two values are equal. | value1 , value2 | eq(value1, value2) |
error | Raises a user-defined error with the specified message. | message | error(message) |
explode | Splits the given string into an array of characters. | string | explode(string) |
filter | Filters the elements of an array based on a provided callback function. | v , f | filter(v, f) |
first | Returns the first element of an array | arr | first(arr) |
floor | Rounds the given number down to the nearest integer. | number | floor(number) |
from_date | Converts a date string to a timestamp. | date_str | from_date(date_str) |
get_md_list_level | Returns the indent level of a markdown list node. | list | get_md_list_level(list) |
get_title | Returns the title of a markdown node. | node | get_title(node) |
gsub | Replaces all occurrences matching a regular expression pattern with the replacement string. | pattern , from , to | gsub(pattern, from, to) |
gt | Checks if the first value is greater than the second value. | value1 , value2 | gt(value1, value2) |
gte | Checks if the first value is greater than or equal to the second value. | value1 , value2 | gte(value1, value2) |
halt | Terminates the program with the given exit code. | exit_code | halt(exit_code) |
halt_error | Halts execution with error code 5 | halt_error() | |
implode | Joins an array of characters into a string. | array | implode(array) |
index | Finds the first occurrence of a substring in the given string. | string , substring | index(string, substring) |
is_array | Checks if input is an array | a | is_array(a) |
is_bool | Checks if input is a boolean | b | is_bool(b) |
is_code | Checks if markdown is code block | md | is_code(md) |
is_em | Checks if markdown is emphasis | md | is_em(md) |
is_empty | Checks if string or array is empty | s | is_empty(s) |
is_h | Checks if markdown is heading | md | is_h(md) |
is_h1 | Checks if markdown is h1 heading | md | is_h1(md) |
is_h2 | Checks if markdown is h2 heading | md | is_h2(md) |
is_h3 | Checks if markdown is h3 heading | md | is_h3(md) |
is_h4 | Checks if markdown is h4 heading | md | is_h4(md) |
is_h5 | Checks if markdown is h5 heading | md | is_h5(md) |
is_html | Checks if markdown is html | md | is_html(md) |
is_list | Checks if markdown is list | list | is_list(list) |
is_list1 | Checks if markdown is list with indentation level 1 | list | is_list1(list) |
is_list2 | Checks if markdown is list with indentation level 2 | list | is_list2(list) |
is_list3 | Checks if markdown is list with indentation level 3 | list | is_list3(list) |
is_markdown | Checks if input is markdown | m | is_markdown(m) |
is_mdx | Checks if markdown is MDX | mdx | is_mdx(mdx) |
is_mdx_flow_expression | Checks if markdown is MDX Flow Expression | mdx | is_mdx_flow_expression(mdx) |
is_mdx_js_esm | Checks if markdown is MDX Js Esm | mdx | is_mdx_js_esm(mdx) |
is_mdx_jsx_flow_element | Checks if markdown is MDX Jsx Flow Element | mdx | is_mdx_jsx_flow_element(mdx) |
is_mdx_jsx_text_element | Checks if markdown is MDX Jsx Text Element | mdx | is_mdx_jsx_text_element(mdx) |
is_mdx_text_expression | Checks if markdown is MDX Text Expression | mdx | is_mdx_text_expression(mdx) |
is_none | Checks if input is None | n | is_none(n) |
is_number | Checks if input is a number | n | is_number(n) |
is_string | Checks if input is a string | s | is_string(s) |
is_text | Checks if markdown is text | text | is_text(text) |
is_toml | Checks if markdown is toml | md | is_toml(md) |
is_yaml | Checks if markdown is yaml | md | is_yaml(md) |
join | Joins the elements of an array into a string with the given separator. | array , separator | join(array, separator) |
last | Returns the last element of an array | arr | last(arr) |
len | Returns the length of the given string or array. | value | len(value) |
lt | Checks if the first value is less than the second value. | value1 , value2 | lt(value1, value2) |
lte | Checks if the first value is less than or equal to the second value. | value1 , value2 | lte(value1, value2) |
ltrimstr | Removes prefix string from input if it exists | s , left | ltrimstr(s, left) |
map | Applies a given function to each element of the provided array and returns a new array with the results. | v , f | map(v, f) |
markdowns | Returns markdown if input is markdown, None otherwise | m | markdowns(m) |
match | Finds all matches of the given pattern in the string. | string , pattern | match(string, pattern) |
max | Returns the maximum of two values. | value1 , value2 | max(value1, value2) |
min | Returns the minimum of two values. | value1 , value2 | min(value1, value2) |
mod | Calculates the remainder of the division of the first value by the second value. | value1 , value2 | mod(value1, value2) |
mul | Multiplies two values. | value1 , value2 | mul(value1, value2) |
ne | Checks if two values are not equal. | value1 , value2 | ne(value1, value2) |
not | Performs a logical NOT operation on a boolean value. | value | not(value) |
now | Returns the current timestamp. | now() | |
nth | Gets the element at the specified index in the array or string. | array_or_string , index | nth(array_or_string, index) |
numbers | Returns number if input is number, None otherwise | n | numbers(n) |
or | Performs a logical OR operation on two boolean values. | value1 , value2 | or(value1, value2) |
pow | Raises the base to the power of the exponent. | base , exponent | pow(base, exponent) |
range | Creates an array of numbers within the specified range. | start , end | range(start, end) |
repeat | Repeats the given string a specified number of times. | string , count | repeat(string, count) |
replace | Replaces all occurrences of a substring with another substring. | string , from , to | replace(string, from, to) |
reverse | Reverses the given string or array. | value | reverse(value) |
rindex | Finds the last occurrence of a substring in the given string. | string , substring | rindex(string, substring) |
round | Rounds the given number to the nearest integer. | number | round(number) |
rtrimstr | Removes suffix string from input if it exists | s , right | rtrimstr(s, right) |
select | Returns value if condition is true, None otherwise | v , f | select(v, f) |
set_md_check | Creates a markdown list node with the given checked state. | list , checked | set_md_check(list, checked) |
slice | Extracts a substring from the given string. | string , start , end | slice(string, start, end) |
sort | Sorts the elements of the given array. | array | sort(array) |
split | Splits the given string by the specified separator. | string , separator | split(string, separator) |
starts_with | Checks if the given string starts with the specified substring. | string , substring | starts_with(string, substring) |
sub | Subtracts the second value from the first value. | value1 , value2 | sub(value1, value2) |
test | Tests if string matches a pattern | s , pattern | test(s, pattern) |
to_array | Converts input to an array | a | to_array(a) |
to_code | Creates a markdown code block with the given value and language. | value , language | to_code(value, language) |
to_code_inline | Creates an inline markdown code node with the given value. | value | to_code_inline(value) |
to_csv | Converts the given value to a CSV. | value | to_csv(value) |
to_date | Converts a timestamp to a date string with the given format. | timestamp , format | to_date(timestamp, format) |
to_date_iso8601 | Formats a date to ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ) | d | to_date_iso8601(d) |
to_em | Creates a markdown emphasis (italic) node with the given value. | value | to_em(value) |
to_h | Creates a markdown heading node with the given value and depth. | value , depth | to_h(value, depth) |
to_hr | Creates a markdown horizontal rule node. | to_hr() | |
to_html | Converts the given markdown string to HTML. | markdown | to_html(markdown) |
to_image | Creates a markdown image node with the given URL, alt text, and title. | url , alt , title | to_image(url, alt, title) |
to_link | Creates a markdown link node with the given url and title. | url , value , title | to_link(url, value, title) |
to_math | Creates a markdown math block with the given value. | value | to_math(value) |
to_math_inline | Creates an inline markdown math node with the given value. | value | to_math_inline(value) |
to_md_list | Creates a markdown list node with the given value and indent level. | value , indent | to_md_list(value, indent) |
to_md_name | Returns the name of the given markdown node. | markdown | to_md_name(markdown) |
to_md_table_row | Creates a markdown table row node with the given values. | cells | to_md_table_row(cells) |
to_md_text | Creates a markdown text node with the given value. | value | to_md_text(value) |
to_number | Converts the given value to a number. | value | to_number(value) |
to_string | Converts the given value to a string. | value | to_string(value) |
to_strong | Creates a markdown strong (bold) node with the given value. | value | to_strong(value) |
to_text | Converts the given markdown node to plain text. | markdown | to_text(markdown) |
to_tsv | Converts the given value to a TSV. | value | to_tsv(value) |
trim | Trims whitespace from both ends of the given string. | input | trim(input) |
trunc | Truncates the given number to an integer by removing the fractional part. | number | trunc(number) |
tsv2table | Convert tsv string to markdown table | tsv | tsv2table(tsv) |
type | Returns the type of the given value. | value | type(value) |
uniq | Removes duplicate elements from the given array. | array | uniq(array) |
upcase | Converts the given string to uppercase. | input | upcase(input) |
update | Update the value with specified value. | target_value , source_value | update(target_value, source_value) |
url_encode | URL-encodes the given string. | input | url_encode(input) |
Builtin selectors
Selector Name | Description | Parameters | Example |
---|---|---|---|
.h , .h(depth) | Selects a heading node with the specified depth. | None, depth | .h , .h(6) |
.h1 | Selects a heading node with the 1 depth. | None | .h1 |
.h2 | Selects a heading node with the 2 depth. | None | .h2 |
.h3 | Selects a heading node with the 3 depth. | None | .h3 |
.h4 | Selects a heading node with the 4 depth. | None | .h4 |
.h5 | Selects a heading node with the 5 depth. | None | .h5 |
.# | Selects a heading node with the 1 depth. | None | .# |
.## | Selects a heading node with the 2 depth. | None | .## |
.### | Selects a heading node with the 3 depth. | None | .### |
.#### | Selects a heading node with the 4 depth. | None | .#### |
.##### | Selects a heading node with the 5 depth. | None | .##### |
.code | Selects a code block node with the specified language. | lang | .code "rust" |
.code_inline | Selects an inline code node. | None | .code_inline |
.inline_math | Selects an inline math node. | None | .inline_math |
.strong | Selects a strong (bold) node. | None | .strong |
.emphasis | Selects an emphasis (italic) node. | None | .emphasis |
.delete | Selects a delete (strikethrough) node. | None | .delete |
.link | Selects a link node. | None | .link |
.link_ref | Selects a link reference node. | None | .link_ref |
.image | Selects an image node. | None | .image |
.heading | Selects a heading node with the specified depth. | None | .heading 1 |
.horizontal_rule | Selects a horizontal rule node. | None | .horizontal_rule |
.blockquote | Selects a blockquote node. | None | .blockquote |
.[][] | Selects a table cell node with the specified row and column. | row , column | .[1][1] |
.html ,.<> | Selects an HTML node. | None | .html , .<> |
.footnote | Selects a footnote node. | None | .footnote |
.mdx_jsx_flow_element | Selects an MDX JSX flow element node. | None | .mdx_jsx_flow_element |
.list ,.[] | Selects a list node with the specified index and checked state. | indent | .list(1) , .[1] |
.mdx_js_esm | Selects an MDX JS ESM node. | None | .mdx_js_esm |
.toml | Selects a TOML node. | None | .toml |
.text | Selects a Text node. | None | .text |
.yaml | Selects a YAML node. | None | .yaml |
.break | Selects a break node. | None | .break |
.mdx_text_expression | Selects an MDX text expression node. | None | .mdx_text_expression |
.footnote_ref | Selects a footnote reference node. | None | .footnote_ref |
.image_ref | Selects an image reference node. | None | .image_ref |
.mdx_jsx_text_element | Selects an MDX JSX text element node. | None | .mdx_jsx_text_element |
.math | Selects a math node. | None | .math |
.math_inline | Selects a math inline node. | None | .math_inline |
.mdx_flow_expression | Selects an MDX flow expression node. | None | .mdx_flow_expression |
.definition | Selects a definition node. | None | .definition |