If you’re familiar with JavaScript, you can think of Origami as JavaScript expressions plus paths.
Origami also includes some minor adaptations that make it easier for you to type expressions in a command line.
This page enumerates the differences between Origami and JavaScript expressions.
Identifiers and references
Like JavaScript, Origami is a dynamic language; you do not need to specify the type of something when defining it.
- Unlike JavaScript variable declarations (which are statements, not expressions), defining something in Origami is implicit; you do not need to prefix a declaration with
let
orconst
. - In order to allow you to directly reference files by name, most file names are legal identifiers in Origami. For example,
index.html
is not a legal JavaScript identifier but is legal in Origami. - The following special characters in identifiers must be escaped with a
\
backslash:
(){}[]<>-=,/:`"'#→⇒
- Web URLs like
https://example.com
are valid references in Origami. - File paths like
/Users/alice/myProject/data.json
are valid references in Origami. - Scope in Origami is defined more broadly than in JavaScript. Code in a JavaScript module can only reference things outside the module via explicit
import
statements. Origami expressions can implicitly reference anything within a project.
Basic numbers but no math
Origami has signed integers and floating point numbers so that you can pass numeric values to functions. Beyond that, Origami does not currently support:
- No binary, octal, hex, exponential notation
- No math operators
- No logical operators
- No comparison operators
- No bitwise operators
- No ternary operator
- No nullish coalescing operator
String literals
Strings with double quotes and single quotes are essentially the same as in JavaScript.
Template literals
Origami template literals look like JavaScript’s.
Expressions inside an Origami template placeholder can directly return complex values like arrays, objects, or trees. Origami will perform a depth-first traversal of the result and concatenate all the values into the final string result:
`Some letters: ${["a", "b", "c"]}.` // Some letters: abc.
Origami templates will await
an asynchronous substitution that returns a Promise
.
Origami does not support JavaScript tagged templates.
Array and object literals
Origami’s syntax for constructing array and object literals is very similar to JavaScript’s:
{
color: "Blue",
size: 20,
values: [2, 4, 6]
}
- A newline can be used as an alternative separator instead of a comma in array literals, object literals, and tree literals (below).
- Origami array and object literals support JavaScript spread syntax.
- An Origami object cannot define indirect property accessors the way JavaScript can with
[ ]
bracket notation. - An Origami object can define
get
methods (see below) but notset
methods.
Because Origami identifiers (above) like index.html
can include periods, in Origami, you must reference object properties with /
path syntax instead of JavaScript’s .
period operator. If the above object is available as obj
, then obj/color
will be “Blue”.
Likewise, to reference a specific array value in Origami, use /
path syntax instead of JavaScript’s [ ]
brackets. Here obj/values/0
will be 2.
When traversing objects like arrays and objects, Origami coerces them to an abstract tree structure. An Origami tree is like a minimalist, asynchronous JavaScript Map. See the AsyncTree interface for details.
Origami lets you define property getters with an abbreviated syntax that uses =
equals signs instead of :
colons:
{
index.html = createPage()
}
Whenever this object is asked for the value of index.html
, Origami will invoke the indicated expression — here, createPage()
— and return that result. The above is roughly equivalent to the following JavaScript syntax:
/* JavaScript approximation of the above */
{
get ["index.html"]() { return createPage(); }
}
JavaScript doesn’t prevent you from having a function like createPage
be an asynchronous function, but does prevent you from explicitly marking a property getter like this as async
. Origami assumes that any object property may be potentially async, and so will await
its value before attempting to use it.
No control structures
As an expression language, Origami does not include any of JavaScript’s control structures like for
or while
loops.
Function calls
Function calls in Origami look similar to functions in JavaScript:
myFunction()
fn(a, b, c)
To use Origami to call a function defined in a JavaScript file, you must use the JavaScript file’s name, including the .js
(or .mjs
) extension:
greet.js("Alice")
Origami assumes that any function might be async
, so implicitly uses await
when calling them.
The Origami language runtime itself is written in JavaScript, so types such as numbers, strings, and objects are actually the same as in JavaScript. E.g., if you pass an Origami object to a JavaScript function, the value will be a regular JavaScript object.
Lambda functions
Origami supports a lambda function syntax similar to JavaScript’s:
(x) => fn(x)
Origami requires the parenthesis around the lambda parameters. (JavaScript allows you to omit the parenthesis for a lambda with a single parameter.)
Origami lambda functions are more basic that JavaScript lambda functions:
- No default parameters
- No rest parameters
- No destructuring in parameters
For ease of use in a command shell with the Origami CLI, the Origami language supports a shorthand lambda syntax:
=fn x
This avoids the need to escape the >
greater than sign or ()
parentheses, which are typically interpreted by a shell.
Implied exports and imports
Any Origami file with the .ori
extension will have its contents interpreted as an Origami expression. The result of this expression is implicitly exported and available from outside the file — unlike JavaScript, there is no need to explicitly export
a value.
This JavaScript:
// message.js
export default "This file exports this message.";
does the same thing as this message.ori
file which implies a default export
:
// message.ori
"This file exports this message.";
Likewise, because Origami scope includes the surrounding files, it is not necessary to explicitly import
values; you can directly reference files by their names.
A JavaScript file might import the above message and incorporate it into an object with:
// site.js
import message from "./message.js";
export default {
"index.html": message,
};
An Origami file could do the same thing with:
// site.ori
{
index.html: message.ori/
}
Here the trailing /
slash is used to get the evaluated contents of message.ori
.