QuantumJS
Edit Page
Core Concepts
This file explains some of the concepts used in quantumjs, including the pipeline, file transforms and entity transforms.
The Pipeline
One key feature that quantum has is the way in which it turns markup into html. It uses a chain of FileTransform functions to apply various transforms to get the output in the right format before turning it into html.
Taking this approach allows multiple useful features to be added on top of the basic markup language (versioning, automatic table of contents generation, templating logic and more).
A typical pipeline for turning quantum markup into html
Read index.umCustom TransformsHTMLHTML StringifyWrite index.htmlQuantum ASTQuantum ASTQuantum Virtual DomHTML String
The AST (abstract syntax tree)
Parsing is the process of turning the markup text into Entity AST objects that can be more easily manipulated.
The quantum markup language is designed tobe easy to work with once parsed as well as provide the ability to use EntityTransform functions as well as FileTransform functions to manipulate the output of a page.
A basic example of the AST for some Quantum markup can be seen below:
Example Markup
Quantum
@type param1 param2
  @otherType: Content
Example Result
{
  type: 'type',
  params: ['param1', 'param2'],
  content: [
    {
      type: 'otherType',
      params: [],
      content: ['Content']
}
]
}
Note
There are some helper apis for working with the parsed AST.
See the quantum-core module docs for more information.
File Transforms
A file transform lets you alter the parsed AST of an entire file before it is rendered out to HTML. A file transform is simply a function.
Here is a file transform that does absolutely nothing:
function identityTransform (file) {
  return file
}
A file transform is a function that takes a File, modifies it and returns the modified File (or an array of File objects)
File Transform Api
FileTransformfileFileFile / Array[File]
A function that takes a file and returns a new file with a transformation applied. This transfomation can be anything - from converting quantum-ast to html, or a transformation that replaces variables in the markup with values from template.
Example
Javascript
const path = require('path')

// The htmlRenamer from 'quantum-html'
// renames name.html to name/index.html and leaves index.html as it is
function htmlRenamer () {
  return (file) => {
    if (path.extname(file.info.dest) === '.html') {
      const filenameWithoutExtension = path.basename(file.info.dest).replace('.html', '')
      const rootPath = path.dirname(file.info.dest)
      return file.clone({
        info: file.info.clone({
          dest: filenameWithoutExtension === 'index' ? file.info.dest : path.join(rootPath, filenameWithoutExtension, 'index.html')
})
})
} else {
  return file
}
}
}
Arguments
fileFile
The file to transform
Returns
The transformed file
Entities
An entity looks like this in markup:
@type param1 param2: Content
The @ denotes the start of a new entity.
When parsed it looks like this:
{
  type: 'type',
  params: ['param1', 'param2'],
  content: ['Content']
}
Entity Objects
An entity consists of entities with three properties, type params and content
Entity
.
Properties
contentArray[String / Entity]
The content of the current entity.
It contains all the string content as well as the nested entities of the current entity.
paramsArray[String]
The params for an entity
For the following entity:
@type param1 param2
The params is:
['param1', 'param2']
typeString
The @ type of the entity, e.g for @code the type is 'code'
Entity Transforms
Entity transforms convert an entity from AST to virtual dom. An entity transform is just a function.
Here's an example entity transform:
const dom = require('quantum-dom')
function notice (selection, transformer) {
  return dom.create('div').class('notice')
    .add(dom.create('div').class('notice-header').text(selection.ps()))
    .add(dom.create('div').class('notice-body').add(selection.cs()))
}
This would convert the following markup:
@notice Warning: There is something you should know
into
<div class="notice">
  <div class="notice-header">Warning</div>
  <div class="notice-body">There is something you should know</div>
</div>
Entity Transform API
EntityTransformselectionSelectiontransformerFunctionmetaObject
A function that takes a Selection and converts it to a dom Element
Arguments
selectionSelection
The Selection to transform.
transformerselectionSelection
The transformer created in the buildDOM function.
It is bootstrapped to itself to allow children to be transformed.
Example
function customTransform (selection, transformer) {
  return dom.create('div').class('custom-class')
    // Transform the content of the selection
    .add(selection.transform(transformer))
}
Arguments
selectionSelection
The Selection to transform.
meta
The meta object as defined in buildDOM options. This should only be used in custom entity transforms.
Custom Entity Transform Example
The following shows a full example of how to create a custom entity transform using the quantum-dom and quantum-html modules:
Example Markup
custom.js (Javascript)
const dom = require('quantum-dom')

// creates a sign in block for the @signIn entity
function signIn (selection) {
  return dom.create('div').class('sign-in')
    .add(dom.create('input').class('username-input'))
    .add(dom.create('input').class('password-input'))
    .add(dom.create('button').class('sign-in-button').text('Sign in'))
}

function entityTransforms () {
  return Object.freeze({
    signIn
})
}

module.exports = {
  entityTransforms
}
quantum.config.js (Javascript)
const custom = require('./custom.js')
const html = require('quantum-html')

const htmlOptions = {
  entityTransforms: {
    custom: custom.entityTransforms()
}
}

module.exports = {
  pipeline: [
    html(htmlOptions)
],
pages: 'index.um'
}
index.um (Quantum)
@signIn
Example Result
Calling quantum build would render the index.um pageand output to target/index.html
<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1"></meta>
</head>
<body class="qm-body-font">
  <!-- the result of the @signIn transform -->
  <div class="sign-in">
    <input class="username-input"></input>
    <input class="password-input"></input>
    <button class="sign-in-button">Sign in</button>
</div>
</body>
</html>