Helps your create a security (sandbox) custom form.
npm install --save @airtasker/form-schema-compiler
This assumes that you’re using npm package manager with a module bundler like Webpack or Browserify to consume CommonJS modules.
If you don’t yet use npm or a modern module bundler, and would rather prefer a single-file UMD build that makes FormSchemaCompiler
available as a global object.
Compile an airtasker form schema to an AST (abstract structure tree).
schema
: Airtaker form schemaoptions
: {typeCompilers
}typeCompilers
: { [TYPE
]:createCompiler()
:{[before(schema)
], [after(AST)
]}}: you can add custom components compiler. it have high priority than default components compiler.
Apply an AST.
-
ast
: an compiled AST -
options
: {variableGetter(name)
,applyComponents
}variableGetter(name)
(function): if there is a identifier type, will use this function to get variable valueapplyComponents(componentASTs)
(function): components type handler.
a const file
export const TYPES = {
Numeric: "Numeric",
String: "String",
Boolean: "Boolean",
Object: "Object",
Array: "Array",
Null: "Null",
RegExp: "RegExp",
Identifier: "Identifier",
Keyword: 'Keyword',
AssignExpression: "AssignExpression",
ObjectExpression: "ObjectExpression",
ObjectProperty: "ObjectProperty",
ArrayExpression: "ArrayExpression",
BinaryExpression: "BinaryExpression",
UnaryExpression: "UnaryExpression",
CallExpression: "CallExpression",
TemplateLiteral: "TemplateLiteral",
MemberExpression: "MemberExpression",
IfStatement: "IfStatement",
Components: "Components",
Operator: "Operator",
Punctuation: "Punctuation",
Raw: "Raw",
Program: 'Program',
BlockStatement: 'BlockStatement',
PropertyBinding: 'PropertyBinding',
EventBinding: 'EventBinding',
};
export const PRIMITIVES = [
TYPES.Numeric,
TYPES.String,
TYPES.Boolean,
TYPES.Null
];
export const OBJECTS = [TYPES.RegExp, TYPES.Identifier, TYPES.Component];
export const EXPRESSIONS = [
TYPES.ObjectExpression,
TYPES.ArrayExpression,
TYPES.BinaryExpression,
TYPES.AssignExpression,
TYPES.CallExpression,
TYPES.UnaryExpression,
TYPES.TemplateLiteral,
];
export const OPERATORS = {
Assign: "=",
Add: "+",
Subtract: "-",
Multiply: "*",
Remainder: "%",
Divide: "/",
GreaterThan: ">",
GreaterThanOrEqualTo: ">=",
LessThan: "<",
LessThanOrEqualTo: "<=",
EqualTo: "is",
NotEqualTo: "isnt",
And: "and",
Or: "or",
Match: "match",
Not: "not"
};
export const PRECEDENCE = {
[OPERATORS.Assign]: 1,
[OPERATORS.Or]: 2,
[OPERATORS.And]: 3,
[OPERATORS.GreaterThan]: 7,
[OPERATORS.GreaterThanOrEqualTo]: 7,
[OPERATORS.LessThan]: 7,
[OPERATORS.LessThanOrEqualTo]: 7,
[OPERATORS.EqualTo]: 7,
[OPERATORS.NotEqualTo]: 7,
[OPERATORS.Match]: 7,
[OPERATORS.Add]: 10,
[OPERATORS.Subtract]: 10,
[OPERATORS.Multiply]: 20,
[OPERATORS.Divide]: 20,
[OPERATORS.Remainder]: 20
};
export const BOOLEANS = ["false", "true"];
export const IF_KEYWORDS = {
If: 'if',
Else: 'else',
Then: 'then'
}
export const KEYWORDS = [...BOOLEANS, ...Object.values(IF_KEYWORDS)];
export const PUNCTUATIONS = {
Braces: ["{", "}"],
SquareBrackets: ["[", "]"],
Parentheses: ["(", ")"],
Separator: ",",
Colon: ":",
BackQuote: "`",
SemiColon: ";",
};
export const ANNOTATION_TYPES = {
[TYPES.PropertyBinding]: TYPES.PropertyBinding,
[TYPES.EventBinding]: TYPES.EventBinding,
Template: "Template",
Components: "Components",
TwoWayBinding: "TwoWayBinding"
};
export const ANNOTATIONS = {
[ANNOTATION_TYPES.PropertyBinding]: ["{", "}"],
[ANNOTATION_TYPES.Template]: ["#", "#"],
[ANNOTATION_TYPES.Components]: ["<", ">"],
[ANNOTATION_TYPES.EventBinding]: ["(", ")"],
[ANNOTATION_TYPES.TwoWayBinding]: ["[", "]"]
};
Airtasker form schema using JSON schema.
-
key
: no annotation, compile as json
compile{ key: "1", key2: 1, key3: null, key4: true, key5: [], key6: {} }
to
{ key: {type: "String", value: "1"}, key2: {type: "Number", value: 1}, key3: {type: "Null", value: null}, key4: {type: "Boolean", value: true}, key5: {type: "Array", value: []}, key6: {type: "Object", value: {}} }
-
<key>
: component annotation
compile{"<key>": {/*component schema*/}}
to
{"key": {/*component ast*/}}
-
[key]
: two way data binding
compile{"[key]": "foo"}
to
{"key": { type: "identifier", name: "foo" }
-
#key#
: string template
compile{"#key#": "foo{"bar"}"}
to
{ "key": { type: "BinaryExpression", left: { type: "String", value: "foo" }, operator: "+", right: { type: "callExpression", callee: { type: "identifier", name: "toString" }, arguments: [{ type: "identifier", name: "bar" }] } } }
-
{key}
: expression
compile{ "{key}": "1 + 2", "{key2}": "{k: 1, date: dueDate}" }
to
{ "key": { type: "BinaryExpression", left: { type: "Numeric", value: "1" }, operator: "+", right: { type: "Numeric", value: "2" }, } }
-
(key)
: event binding, eventValue is a special identifier that's reference the action callback value
compile{"(click)": "doAction(eventValue)"}
to
{ "onClick": { type: "callExpression", callee: { type: "identifier", name: "doAction" }, arguments: [{ type: "identifier", name: "eventValue" }] } }
MIT