Jora
Jora is a JavaScript object query engine and language for processing and querying JSON-like data structures efficiently. While currently in a beta development phase (v1.0.0-beta.15), it is considered stable, though its syntax might undergo changes in future releases. The project maintains a relatively frequent release cadence for beta versions, actively introducing new features, improvements, and addressing issues. Jora distinguishes itself with a compact, JavaScript-like syntax for common data manipulation tasks, tolerant query execution that simply returns nothing for unreachable paths instead of throwing errors, and automatic aggregation and deduplication of values. It also includes advanced features like a stat collecting mode for powering suggestions in editors and an extensible Domain Specific Language (DSL) via custom methods and assertions, making it highly adaptable for complex data transformations. It is a core component within the Discovery.js ecosystem, used for data visualization and building interactive reports.
Common errors
-
Method "foo" is not defined
cause Attempting to use a custom method named `foo` that has not been registered with Jora.fixRegister your custom method using `jora.setup({ methods: { foo: (value) => ... } })` before compiling the query. -
SyntaxError: Duplicate parameter name '$a'
cause A Jora function expression within your query defines the same parameter name more than once, which is now disallowed.fixModify the function definition to use unique parameter names for each argument, e.g., `($a, $b) => expr`. -
Error: Built-in method "length" cannot be overridden
cause Attempting to define a custom method or assertion with a name that conflicts with an existing built-in Jora method or assertion (e.g., `length`, `count`, `map`).fixRename your custom method or assertion to avoid conflict with Jora's built-in functions. Refer to Jora documentation for a list of built-ins. -
Error: Unexpected token <
cause Your Jora query contains a function definition using the deprecated `<expr>` syntax, which has been removed.fixUpdate the function definition to use the modern Jora function syntax, such as `$arg => expr` or `($a, $b) => expr`.
Warnings
- breaking The Jora project is still in beta, and its syntax is explicitly noted as subject to change in future releases. Queries written against current beta versions might require adjustments when upgrading.
- breaking The signature for the `setup()` function was changed from `setup(methods)` to `setup({ methods })`. Directly passing the methods dictionary will no longer work.
- breaking Support for a legacy function syntax, i.e., `<expr>`, was removed. Queries using this format will fail to parse.
- breaking Duplicate parameter names in function definitions (e.g., `($a, $a) => expr`) are now prohibited and will cause a compilation error.
- breaking The behavior of `this` within custom methods and assertions defined as functions was changed. `this` now includes a `context` reference to the query context.
- breaking A JavaScript injection vulnerability in queries using escape sequences (e.g., `{\u005balert\u00281\u0029\u005d: 'test'}`) was fixed. While a fix, this might subtly change behavior for queries that intentionally or unintentionally relied on such constructions.
- gotcha It is no longer possible to override built-in methods and assertions using the `setup()` or `jora()` functions. Attempting to do so will result in an error.
Install
-
npm install jora -
yarn add jora -
pnpm add jora
Imports
- jora
const jora = require('jora')import jora from 'jora'
- setup
import jora, { setup } from 'jora'; jora.setup(...)import { setup } from 'jora' - syntax
import { JoraSyntax } from 'jora'import { syntax } from 'jora'
Quickstart
import jora, { setup } from 'jora';
// Setup custom methods and assertions globally (optional)
setup({
methods: {
addOne: (value) => value + 1,
sumAll: (arr) => arr.reduce((acc, current) => acc + current, 0),
},
assertions: {
isPositive: (value) => value > 0,
hasTag: (value, tag) => Array.isArray(value) && value.includes(tag),
}
});
const data = [
{ id: 1, name: 'Apple', price: 1.2, tags: ['fruit', 'sweet'] },
{ id: 2, name: 'Banana', price: 0.8, tags: ['fruit'] },
{ id: 3, name: 'Carrot', price: 0.5, tags: ['vegetable', 'root'] },
{ id: 4, name: 'Milk', price: 2.5, tags: ['dairy', 'drink'] },
{ id: 5, name: 'Orange', price: 1.5, tags: ['fruit', 'citrus'] }
];
// Compile a query using custom methods and assertions
const query = jora(`
.[tags.hasTag('fruit') and price.isPositive()] | {
count: count(),
avgPrice: avg(price),
names: name.addOne()
}
`);
// Execute the compiled query against the data
const result = query(data);
console.log(JSON.stringify(result, null, 2));
/*
Expected output:
{
"count": 3,
"avgPrice": 1.1666666666666667,
"names": [
"Apple1",
"Banana1",
"Orange1"
]
}
*/