The language is designed to be entirely agnostic and platform-independent — It is primarily designed as a comment block above javascript and YAML. By building the schema language as a general-purpose compiler, we have full control over syntax or where it can be used and can build documentation or metadata (such as JSON schema) across the board anywhere in our content.
The schema language may be compiled to more than one target. Currently, it compiles to JSONSchema — but Jekyll and HTML for self-documentation are in the future roadmap.
When the target is JSONSchema, the blocks of comments are translated directly into metadata that is used in Forge. Forge uses the React-JSONschema-forms
project to generate forms that facilitate building and customizing blocks and components for page and pattern creation.
Previously, TOML files were stored in the components repository that became very hard to update and maintain. By designing a language that can be used in comments directly above blocks of javascript and YAML, we can verify and validate metadata at compile-time with esdoc
in addition to immediate pull requests instead of maintaining multiple repositories with toml and its complexity with JSON schema.
The goal of the language is to simplify complexity as much as possible and resemble other compile-time annotation languages such as Doxygen
or dartdoc
— while providing enough tools to at least match the requirements of jsonschema-forms. The grammar for the language can be found here.
A document
is a collection of directives
, props
(that has types
, features
, with or without flags
), and containers
of nested structures. Containers
may themselves have directives
, props
, placeholders
, and containers
that may be nested infinitely. Note that all indentation is optional.
A document describes pieces of content such as SDK blocks, components, patterns, and even pages, and their data structure.
This language was designed internally to receive feedback and encompass all of our needs for content and forge. Please send pull requests or comments!
Example: (based on this) and it compiles to this JSONSchema.
/**
* @View
*
* @name email
* @type block
* @description Email block
* @content
* @prop @required button_text type={string} title="Button Text" description="Enter Details for Email"
* @prop @advanced button_class type={string} title="Button Class" description="CSS Class(es) for button"
* @prop @advanced email_form_class type={string} description="CSS Class(es) for email form"
*/
Example 2:
/**
* @View
*
* @name button
* @type block
* @description button block
* @content
* @contains @array_of 'buttons' with:
* @includes @optional blocks: {{blocks}}
* @prop id type={string} description="button id"
*
* @prop class type={string} description="class name(s)"
*
* @prop @required text type={string} description="button text"
*
* @prop [type] description="type of button event"
* "open_modal"
* "action"
*
* @prop modal_id type={string} title="modal target id" \
* description="a modal id target"
*
* @prop target_id type={string} title="target id" \
* description="a target id for your action"
*
* @prop [action] title="action name" description="action to be performed"
* "toggle_visibility"
* @end
*/
A directive
is a metadata tag for a container or global structure in a document.
There are 3 different types of directives — global
and container level
and placeholder.
Global Directives | Description | Parameters | Example |
---|---|---|---|
@View |
Marks the beginning of document. | none | @View |
@name |
Name of content for document. | {String} |
@name email |
@type |
Type of content. (e.g. block, component) | {String} |
@type block |
@description |
Description of content | {String} |
@description My super cool block |
@content |
(Optional) Marks the end of global directives. | none | @content |
Container Directives | Description | Parameters | Example |
---|---|---|---|
@title |
Title of object block structure. | {Quote-String} |
@title "header region" |
@minimum |
A minimum of objects in block structure. | {Number} |
@minimum 2 |
@maximum |
A maximum of objects in block structure. | {Number} |
@maximum 5 |
Placeholder Directives | Description | Parameters | Example |
---|---|---|---|
@includes |
Injects a region for nested blocks or components in current structure. | {String} title: {{injection-type}} |
|
@excludes |
Excludes a block or component type during an @includes . |
{String} title: {{type}} |
|
Props are data properties of content in a container or global structure. They are the properties that can be defined in page YAML or in Forge jsonschema-forms.
A prop contains an identifier (name of the prop) with many attributes. header
and description
are the standard but ANY attribute may be defined; additionally delimited across more than one line with the backslash.
There are 2 different types of props — data
and enum
— each may have multiple flags
, types
, and one feature
. The enum
type has its identifier enclosed in [
]
.
Examples:
* @prop @required title type={string} header="A title" description="A very cool title for this course content" language="en" @allow richText
Enum
props are for multiple-selection data attributes.
* @prop @advanced [animation] type={string} title="Animation style" default="bounce"
* "bounce"
* "pulse"
* "swing"
* "tada"
* "jello"
Flags | Description | Parameters | Example |
---|---|---|---|
@required |
This prop is required. | none | @prop @required allowMultiple type={boolean} title="Allow multiple items" |
@advanced |
This prop is particularly complex and may be hidden by default | none | @prop @advanced allowMultiple type={boolean} title="Allow multiple items" |
Types | Example |
---|---|
string |
@prop header type={string} |
number |
@prop amount type={number} |
boolean |
@prop collapsible type={boolean} |
null |
@prop doNothing type={null} |
undefined |
none |
Features | Description | Parameters | Example |
---|---|---|---|
@allow |
Allows a widget type in forge for a prop (ui schema) | {String} |
@prop icon_header type={string} title="font awesome icon" @allow iconPicker |
Containers are nested structures within content such as inputs in a form or text items in a list. Placeholders allow containers to have rendered nested child SDK blocks or component types. Containers may themselves have containers.
Containers may have Container directives
as described above for metadata on their definition. Moveover, they can be defined with flags.
The @end
tag at the end of containers are required; this facilitates stacking and nesting of many.
There are 2 types of containers - regular
and @array_of
. The regular container
are objects and are generally for placeholders that can render nested child SDK blocks or some other defined content structure. The @array_of
is a container definition with more granular control of its content and meaning.
Example:
* @contains 'region' with:
* @title 'items'
* @includes blocks: {{blocks}}
* @end
* @contains @array_of 'bellows' with:
* @title "bellows"
* @minimum 2
* @maximum 5
* @prop @required @advanced class type={string} description="class name(s)"
* @prop header type={string} title="header" description="expandable "
* @prop description type={string} title="description" \
* header="expandable header text for this bellow"
* @prop icon_header type={string} title="font awesome icon" @allow iconPicker
* @end