While patterns are used to match against AST nodes, functions are used as replacement values. Thus, functions can only be used on the right hand side of GritQL queries. Specifically:
- In assignments:
$x = function_call()
- In insertions:
$x += 'function_call()
- In rewrites:
$x => function_call()
Function definitions
Just like with patterns, custom functions can be defined using the function
keyword. Functions must have a name, and can optionally take parameters.
The body of the function consists of predicates and conditions (like those inside a where clause) that are evaluated in order.
The final line of the function should be return
followed by the value to return.
// define a lines function function lines($string) { return split($string, separator=`\n`) } // Define a my_todo function function my_todo($target, $message) { if($message <: undefined) { $message = "This requires manual intervention." }, $lines = lines(string = $message), $lines <: some bubble($result) $x where { if ($result <: undefined) { $result = `// TODO: $x` } else { $result += `\n// $x` } }, $target_lines = lines(string = $target), $target_lines <: some bubble($result) $x where { $result += `\n// $x` }, return $result, } // Use the my_todo function `module.exports = $_` as $x => my_todo(target=$x, message=`Fix this\nAnd that`)
module.exports = { king, queen: '8', };
// TODO: Fix this // And that // module.exports = { // king, // queen: '8', // };
Function parameter names can be omitted as long as arguments are provided in the same order as the parameters are defined. For example, the my_todo
function from above could be called like this:
`module.exports = $_` as $x => my_todo($x, `Fix this\nAnd that`)
JavaScript functions
Warning: This is an alpha feature in active development, without stability guarantees. Please contact us on Discord or Slack if you have any questions.
Functions are not limited to using GritQL. By including js
after the function parameters, you can define a function that is implemented in JavaScript.
language js function fizzbuzz($x) js { // Use $var.text to access the binding's value const parsed = parseInt($x.text, 10); let output = ''; if (parsed % 3 === 0) output += 'Fizz'; if (parsed % 5 === 0) output += 'Buzz'; return output || parsed; } `console.log($x)` => fizzbuzz($x)
console.log(3); console.log(8); console.log(10); console.log(15);
Fizz; 8; Buzz; FizzBuzz;
Limitations
- JavaScript functions must return a stringable value. This means that the return value must be a string, or an object with a
toString
method. - Functions are executed in a WebAssembly sandbox. They cannot access the filesystem or make network requests.
- If the function throws an error, the pattern will error and fail to match.
- Parameters are accessible only via the
$variable.text
property. Metavariables without a string representation cannot be accessed. If you need to parse a parameter as a number, you can useparseInt
orparseFloat
. - Foreign functions cannot bind new variables. They can only access the variables that are passed in as parameters.
Built-in functions
GritQL provides several built-in functions that can be used in queries targeting any language.
capitalize
capitalize
takes a string and returns a new string with the first character capitalized.
capitalize(string = "hello") // "Hello"
trim
trim(s)
returns a new string with the whitespace removed from the beginning and end of s
.
trim(string = " hello ", trim_chars = " ") // returns "hello"
join
join(delimiter, strings)
concatenates a list of strings
with a delimiter
to form a single string.
join(list = ["a", "b", "c"], separator = "_") // returns "a_b_c" join(list = ["a", "b", "c"], separator = "") // returns "abc"
todo
In some cases, a transformation cannot be completed fully automatically. You can use the todo
function to mark a target
snippet as incomplete and add a comment to the generated code. An optional message
can be provided to give more information about the incomplete transformation.
or { `console.log($msg)` => todo(target=$msg), `console.error($msg)` as $log => todo(target=$log, message="Consider a lower error level.") }
console.log("hello"); console.error("This is an error");
// TODO: This requires manual intervention. // "hello" // TODO: Consider a lower error level. // console.error("This is an error")
lowercase
lowercase
takes a string and returns a new string with all characters lowercased.
lowercase(string = "HELLO") // "hello" lowercase(string = "Hello") // "hello" lowercase(string = "hello") // "hello"
length
length(target=$items)
returns the number of elements in a target
list. It can also be used to get the length of a target string.
length(target=[7, 8, 9]) // returns 3 length(target="hello") // returns 5
uppercase
uppercase
takes a string and returns a new string with all characters uppercased.
uppercase(string = "HELLO") // "HELLO" uppercase(string = "Hello") // "HELLO" uppercase(string = "hello") // "HELLO"