Schema
// @namespace Schema
import { Schema } from 'rcfm'
Custom Types
@typedef {Object} SchemaInstance
@description - DSL 解析器实例
Class Methods
.create()
创建一个 DSL 解析器实例。
// Schema.create(options)
// @param {Object} [options = {}]
// @prop {Function} [options.parseExpression] - 自定义布尔表达式运算函数,应返回布尔值。
// 当不设定时,使用默认求值逻辑,即只有当表达式结果为 true 时为真,否则为假。
// @prop {Function} [options.parseReference] - 自定义 Interpolation 解析函数,应返回解析结果。
// 当不设定时,所有 Interpolation 的解析结果均为 undefined。
// @returns {SchemaInstance}
// @example - 创建实例
const schema = Schema.create({
parseReference (ref) {
const students = [
{name: 'Jerry', score: 69}, {name: 'Laura', score: 79},
{name: 'James', score: 70}, {name: 'Tomas', score: 80}
]
// 自定义 Interpolation 引用路径分割符号
const [name, prop] = ref.split(".")
// 自定义 Interpolation 引用路径解析逻辑
const student = students.find((s) => s.name === name)
return student ? student[prop] : undefined
},
parseExpression (exp) {
// 自定义布尔表达式语法
const matched = exp.match(/(\d+)\s+(.+)\s+(\d+)/)
if (!matched) { return false }
let [statement, scoreA, keyword, scoreB] = matched
// 自定义布尔表达式运算逻辑
if (keyword === 'was higher than') {
return parseFloat(scoreA) > parseFloat(scoreB)
} else if (keyword === 'was less than') {
return parseFloat(scoreA) < parseFloat(scoreB)
} else {
throw new Error(`Unsupported keyword "${keyword}".`)
}
}
})
// @example - 解析 DSL
// returns - "Boys won!"
schema.parse([
{
when: [
"<< Jerry.score >> was higher than << James.score >>",
{and: "<< Laura.score >> was higher than << Tomas.score >>"}
],
then: "Girls won!"
},
{
when: [
"<< James.score >> was higher than << Jerry.score >>",
{and: "<< Tomas.score >> was higher than << Laura.score >>"}
],
then: "Boys won!"
},
{
else: "The two teams drew."
}
])
Instance Methods
#parse()
解析 DSL。
// schema#parse(statement)
// @param {*} statement - 待解析的 DSL,也可以是任意数据。
// 如 statment 包含 DSL,则解析结果中 DSL 部分会被其解析结果替换。
// @returns {*} - 返回解析结果
// @example - 创建实例
const schema = Schema.create({
parseReference (ref) {
const students = [
{name: 'Jerry', score: 69}, {name: 'Laura', score: 79},
{name: 'James', score: 70}, {name: 'Tomas', score: 80}
]
// 自定义 Interpolation 引用路径分割符号
const [name, prop] = ref.split(".")
// 自定义 Interpolation 引用路径解析逻辑
const student = students.find((s) => s.name === name)
return student ? student[prop] : undefined
},
parseExpression (exp) {
// 自定义布尔表达式语法
const matched = exp.match(/(\d+)\s+(.+)\s+(\d+)/)
if (!matched) { return false }
let [statement, scoreA, keyword, scoreB] = matched
// 自定义布尔表达式运算逻辑
if (keyword === 'was higher than') {
return parseFloat(scoreA) > parseFloat(scoreB)
} else if (keyword === 'was less than') {
return parseFloat(scoreA) < parseFloat(scoreB)
} else {
throw new Error(`Unsupported keyword "${keyword}".`)
}
}
})
// @example - 解析 DSL
// returns - "Boys won!"
schema.parse([
{
when: [
"<< Jerry.score >> was higher than << James.score >>",
{and: "<< Laura.score >> was higher than << Tomas.score >>"}
],
then: "Girls won!"
},
{
when: [
"<< James.score >> was higher than << Jerry.score >>",
{and: "<< Tomas.score >> was higher than << Laura.score >>"}
],
then: "Boys won!"
},
{
else: "The two teams drew."
}
])
#possibilities()
返回 DSL 各分支结果组成的数组。
// schema#possibilities(statement)
// @param {*} statement - ConditionStatement,也可以是任意数据
// @returns {null | Array} - 当 statement 包含 ConditionStatement 时返回数组,否则返回 null。
// @example - 获取条件分支结果
// returns - ["Girls won!", "Boys won!", "The two teams drew."]
schema.possibilities([
100, true, false, 'hello',
{
when: [
"<< Jerry.score >> was higher than << James.score >>",
{and: "<< Laura.score >> was higher than << Tomas.score >>"}
],
then: "Girls won!"
},
{
when: [
"<< James.score >> was higher than << Jerry.score >>",
{and: "<< Tomas.score >> was higher than << Laura.score >>"}
],
then: "Boys won!"
},
{
else: "The two teams drew."
}
])
// @example - 对不包含 ConditionStatement 的数据调用
// returns - null
schema.possibilities([
100, true, false, 'hello', {name: 'jim'}, [1, 2, 3]
])
#references()
搜集 DSL 中的 Interpolation 引用路径。
// schema#references(statement, options)
// @param {*} statement
// @param {Object} [options = {}]
// @prop {boolean} [options.unique = true] - 是否过滤掉重复的路径
// @returns {Array | null}
// @example
// returns ['name', 'age', 'gender', 'address', 'hobby']
schema.references([
{prop: 1}, {prop: true},
{prop: {prop: [{prop: '<< name >>'}, '<< age >><< name >>']}},
['<< gender >>', {prop: [{prop: [{prop: '<< address >><<age>>'}]}]}],
'<< hobby >>'
])
// @example
// returns ['name', 'age', 'name', 'gender', 'address', 'age', 'hobby']
schema.references([
{prop: 1}, {prop: true},
{prop: {prop: [{prop: '<< name >>'}, '<< age >><< name >>']}},
['<< gender >>', {prop: [{prop: [{prop: '<< address >><<age>>'}]}]}],
'<< hobby >>'
], {unique: false})
#replace()
替换 DSL 中的 Interpolation 引用路径。
// schema#replace(statement, pairs)
// @param {*} statement
// @param {Object} pairs - 以旧引用路径为 key,新引用路径为 value 构成的对象
// @returns {*}
// @example
// returns -
// [
// {prop: 1}, {prop: true},
// {prop: {prop: [{prop: '<< username >>'}, '<< age >><< username >>']}},
// ['<< gender >>', {prop: [{prop: [{prop: '<< location >><<age>>'}]}]}],
// '<< hobby >>', 1, true, false
// ]
schema.replace([
{prop: 1}, {prop: true},
{prop: {prop: [{prop: '<< name >>'}, '<< age >><< name >>']}},
['<< gender >>', {prop: [{prop: [{prop: '<< address >><<age>>'}]}]}],
'<< hobby >>', 1, true, false
], {name: 'username', address: 'location'})