New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

krl-compiler

Package Overview
Dependencies
Maintainers
2
Versions
125
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

krl-compiler - npm Package Compare versions

Comparing version 0.52.3 to 1.0.0-alpha.0

src/c/EventGroupOperator.js

15

package.json
{
"name": "krl-compiler",
"version": "0.52.3",
"version": "1.0.0-alpha.0",
"description": "KRL compiler",

@@ -33,3 +33,3 @@ "main": "src/index.js",

"devDependencies": {
"ava": "^1.2.1",
"ava": "^2.1.0",
"contra": "^1.9.4",

@@ -44,7 +44,10 @@ "diff-lines": "^1.1.0",

"estree-loc": "^2.0.0",
"krl-parser": "^0.52.3",
"lodash": "^4.17.4",
"minimist": "^1.2.0"
"krl-parser": "^1.0.0-alpha.0",
"krl-stdlib": "^1.0.0-alpha.0",
"lodash": "^4.17.11",
"minimist": "^1.2.5",
"symbol-table": "^1.3.1",
"to-js-identifier": "^1.0.0"
},
"gitHead": "90020b0033b51d5bd3c3606466a92da3308fb6b7"
"gitHead": "26aee8aeb73a2450f9224f2d8d81f3a3d49b33f2"
}

50

src/c/Action.js

@@ -1,2 +0,2 @@

var _ = require('lodash')
const _ = require('lodash')

@@ -11,13 +11,41 @@ module.exports = function (ast, comp, e) {

return e('acall', e('id', 'runAction'), [
e('id', 'ctx'),
ast.action.domain
? e('str', ast.action.domain, ast.action.loc)
: e('void', e('number', 0)),
e('str', ast.action.value),
comp(ast.args),
e('array', _.map(ast.setting, function (set) {
return e('str', set.value, set.loc)
}))
let actionFn = comp(ast.action, { isGoingToBeApplied: true })
let actionType = actionFn.$$Annotation
? actionFn.$$Annotation.type
: 'Unknown'
switch (actionType) {
case 'Action':
case 'ActionFunction':
break// great!
case 'Unknown':
// runtime check the type
actionFn = e('call', e('id', '$ctx.krl.assertAction'), [actionFn])
break// ok
default:
throw comp.error(ast.action.loc, 'Not an action: ' + actionType)
}
let estree = e('acall', actionFn, [
comp.scope.has('$$is_inside_fn_or_action_body$$')
? e('this')
: e('id', '$ctx'),
comp(ast.args)
])
if (_.size(ast.setting) === 1) {
const id = ast.setting[0]
comp.scope.set(id.value, { type: 'Unknown' })
return e('var',
e('id', comp.jsId(id.value), id.loc),
estree,
id.loc
)
} else if (_.size(ast.setting) > 1) {
throw comp.error(ast.setting[1].loc, 'Actions only return on value')
} else {
return e(';', estree, ast.loc)
}
}

@@ -10,3 +10,3 @@ var _ = require('lodash')

body.push(e('var', 'fired', condition))
body.push(e('var', '$fired', condition))

@@ -25,3 +25,3 @@ var ifBody = []

return e('case', e('string', action.label.value, action.label.loc), [
e(';', comp(action), action.loc),
comp(action),
e('break', action.loc)

@@ -35,3 +35,3 @@ ], action.loc)

return e('case', e('number', i, action.loc), [
e(';', comp(action), action.loc),
comp(action),
e('break', action.loc)

@@ -41,5 +41,5 @@ ], action.loc)

} else if (blockType === 'every') {
ifBody = ifBody.concat(_.map(ast.actions, function (action) {
return e(';', comp(action))
}))
_.map(ast.actions, function (action) {
ifBody.push(comp(action))
})
} else {

@@ -49,5 +49,5 @@ throw new Error('ActionBlock.blockType = "' + blockType + '" not supported')

body.push(e('if', e('id', 'fired'), e('block', ifBody)))
body.push(e('if', e('id', '$fired'), e('block', ifBody)))
return body
}
var _ = require('lodash')
var callStdLibFn = require('../utils/callStdLibFn')
module.exports = function (ast, comp, e) {
if (ast.callee.type === 'DomainIdentifier' &&
ast.callee.domain === 'event' &&
ast.callee.value === 'attrs'
) {
throw comp.error(ast.callee.loc, '`event:attrs` is a Map, not a Function. Use `event:attrs{key}` instead')
}
let callee
let args
if (ast.callee.type === 'MemberExpression' &&

@@ -14,41 +22,53 @@ ast.callee.method === 'dot' &&

return e('acall', e('id', 'ctx.applyFn'), [
comp(ast.callee.property),
e('id', 'ctx'),
comp(_.assign({}, ast.args, {
// inject left-hand of the dot as the first argument
args: [ast.callee.object].concat(ast.args.args)
}))
])
}
callee = comp(ast.callee.property)
args = comp(_.assign({}, ast.args, {
// inject left-hand of the dot as the first argument
args: [ast.callee.object].concat(ast.args.args)
}))
if (ast.callee.type === 'DomainIdentifier' &&
ast.callee.domain === 'event' &&
ast.callee.value === 'attrs'
) {
comp.warn(ast.callee.loc, 'DEPRECATED change `event:attrs()` to `event:attrs`')
return comp(ast.callee)
// event:attrs("the_attr")
if (ast.callee.object.type === 'DomainIdentifier' &&
ast.callee.object.domain === 'event' &&
ast.callee.object.value === 'attrs' &&
ast.callee.property.type === 'Identifier' &&
ast.callee.property.value === 'get'
) {
let arg0 = ast.args.args[0]
if (arg0 && arg0.type === 'String') {
comp.eventScope.addAttr(arg0.value)
}
}
} else if (ast.callee.type === 'DomainIdentifier') {
callee = comp(ast.callee, { isGoingToBeApplied: true })
args = comp(ast.args)
if (ast.callee.domain === 'event' && ast.callee.value === 'attr') {
let arg0 = ast.args.args[0]
if (arg0 && arg0.type === 'String') {
comp.eventScope.addAttr(arg0.value)
}
}
} else {
callee = comp(ast.callee)
args = comp(ast.args)
}
if (ast.callee.type === 'DomainIdentifier' &&
ast.callee.domain === 'keys'
) {
var domainId = 'keys:' + ast.callee.value
if (ast.args.args.length > 0) {
comp.warn(ast.callee.loc, 'DEPRECATED change `' + domainId + '(name)` to `' + domainId + '{name}`')
return callStdLibFn(e, 'get', [
comp(ast.callee),
comp(ast.args.args[0])
], ast.loc)
} else {
comp.warn(ast.callee.loc, 'DEPRECATED change `' + domainId + '()` to `' + domainId + '`')
return comp(ast.callee)
}
let calleeType = callee.$$Annotation
? callee.$$Annotation.type
: 'Unknown'
switch (calleeType) {
case 'Function':
break// great!
case 'Unknown':
// runtime check the type
callee = e('call', e('id', '$ctx.krl.assertFunction'), [callee])
break// ok
default:
throw comp.error(ast.callee.loc, 'Not a function: ' + calleeType)
}
return e('acall', e('id', 'ctx.applyFn'), [
comp(ast.callee),
e('id', 'ctx'),
comp(ast.args)
return e('acall', callee, [
e('id', '$ctx'),
args
])
}
module.exports = function (ast, comp, e) {
if (ast.variable.domain !== 'ent') {
throw comp.error(ast.loc, 'ClearPersistentVariable only works for `ent:`, not `' + ast.op + ':`')
}
var key = e('str', ast.variable.value, ast.variable.loc)
if (ast.path_expression) {
key = e('obj', {
key: key,
path: comp(ast.path_expression)
})
// TODO optimize
return e(';', e('acall', e('id', '$ctx.rsCtx.putEnt'), [
key,
e('acall', e('id', '$stdlib.delete'), [
e('id', '$ctx'),
e('array', [
e('acall', e('id', '$ctx.rsCtx.getEnt'), [key]),
comp(ast.path_expression)
])
])
]))
}
return e(';', e('acall', e('id', 'ctx.modules.del'), [
e('id', 'ctx'),
e('str', ast.variable.domain, ast.variable.loc),
key
]))
return e(';', e('acall', e('id', '$ctx.rsCtx.delEnt'), [key]))
}

@@ -1,14 +0,1 @@

var callStdLibFn = require('../utils/callStdLibFn')
var ePathSet = function (ast, comp, e, path) {
return e(';', e('call', e('id', 'ctx.scope.set'), [
e('str', ast.left.object.value, ast.left.loc),
callStdLibFn(e, 'set', [
comp(ast.left.object),
path,
comp(ast.right)
], ast.left.loc)
]))
}
module.exports = function (ast, comp, e) {

@@ -19,20 +6,24 @@ if (ast.op !== '=') {

if (ast.left.type === 'MemberExpression') {
// TODO This is actually an assignment, should we allow this?
if (ast.left.method === 'path') {
return ePathSet(ast, comp, e, comp(ast.left.property))
} else if (ast.left.method === 'index') {
return ePathSet(ast, comp, e, e('array', [
comp(ast.left.property)
], ast.left.property.loc))
}
} else if (ast.left.type === 'Identifier') {
if (ast.left.value === 'null') {
throw comp.error(ast.loc, 'Cannot declare: ' + ast.left.value)
}
return e(';', e('call', e('id', 'ctx.scope.set'), [
e('str', ast.left.value, ast.left.loc),
comp(ast.right)
]))
throw comp.error(ast.left.loc, 'This is an assignment, not a declaration')
}
throw comp.error(ast.loc, 'Cannot declare ' + ast.left.type)
if (ast.left.type !== 'Identifier') {
throw comp.error(ast.loc, 'Cannot declare ' + ast.left.type)
}
if (ast.left.value === 'null') {
throw comp.error(ast.loc, 'Cannot declare: ' + ast.left.value)
}
if (ast.right.type === 'Function' || ast.right.type === 'Action') {
// for recursion, declare the symbol first, then assign type if found
comp.scope.set(ast.left.value, { type: 'Unknown' })
}
const estree = comp(ast.right)
comp.scope.set(ast.left.value, estree.$$Annotation
? estree.$$Annotation
: { type: 'Unknown' })
return e('const',
e('id', comp.jsId(ast.left.value), ast.left.loc),
estree
)
}
var _ = require('lodash')
var declarationBlock = require('../utils/declarationBlock')
module.exports = function (ast, comp, e) {
var body = comp(ast.params)
var body = []
_.each(ast.body, function (d) {
body.push(comp(d))
})
comp.scope.push()
comp.scope.set('$$is_inside_fn_or_action_body$$', true)
// compile the params first, so params get defined in comp.scope before the action body compiles
const { params, defaultSetups } = comp(ast.params)
body = body.concat(defaultSetups)
body = body.concat(declarationBlock(ast.body, comp))
body = body.concat(comp(ast.action_block))
body.push(e('return', e('array', _.map(ast.returns, function (ret) {
return comp(ret)
}))))
if (ast.return) {
body.push(e('return', comp(ast.return)))
}
comp.scope.pop()
var paramNames = []
var paramOrder = e('array', _.map(ast.params.params, function (p) {
paramNames.push(p.id.value)
return e('string', p.id.value, p.id.loc)
}), ast.params.loc)
return e('call', e('id', 'ctx.mkAction'), [
const estree = e('call', e('id', '$ctx.krl.Action'), [
paramOrder,
e('asyncfn', [
'ctx',
'args',
'runAction'
], body)
{
type: 'FunctionExpression',
params: params,
body: {
type: 'BlockStatement',
body: body
},
async: true
}
])
estree.$$Annotation = {
type: 'Action',
params: paramNames
}
return estree
}

@@ -1,7 +0,26 @@

module.exports = function (ast, comp, e) {
return e('acall', e('id', 'ctx.modules.get'), [
e('id', 'ctx'),
e('str', ast.domain),
e('str', ast.value)
])
module.exports = function (ast, comp, e, context) {
if (ast.domain === 'ent') {
return e('acall', e('id', '$ctx.rsCtx.getEnt'), [
e('str', ast.value)
])
}
if (ast.domain === 'event' && ast.value === 'attrs') {
return e('id', '$event.data.attrs')
}
if (ast.domain === 'event' && ast.value === 'eci') {
return e('id', '$event.eci')
}
if (ast.domain === 'event' && ast.value === 'attr') {
comp.warn(ast.loc, 'event:attr(key) is deprecated. Use event:attrs{key} instead')
}
const mod = e('get', e('call', e('id', '$ctx.module'), [
e('str', ast.domain)
]), e('str', ast.value))
if (context && context.isGoingToBeApplied) {
return mod
}
return e('call', mod, [e('id', '$ctx')])
}
module.exports = function (ast, comp, e) {
return e(
ast.level === 'error' ? 'return' : ';',
e('acall', e('id', 'ctx.raiseError'), [
e('id', 'ctx'),
e('string', ast.level),
comp(ast.expression)
const ruleName = comp.scope.get('$rule_name')
const raise = e(';', e('acall', e('id', '$ctx.rsCtx.raiseEvent'), [
e('str', 'system'),
e('str', 'error'),
e('obj', {
level: e('string', ast.level),
data: comp(ast.expression),
rid: e('id', '$ctx.rsCtx.ruleset.rid'),
rule_name: typeof ruleName === 'string'
? e('string', ruleName)
: e('null'),
genus: e('string', 'user')
}),
e('id', '$ctx.rsCtx.ruleset.rid')
]))
if (ast.level === 'error') {
return e('block', [
e(';', e('call', e('id', '$last'), [])),
e(';', e('call', e('id', '$ctx.rsCtx.clearSchedule'), [])),
raise,
e('return')
])
)
}
return raise
}

@@ -10,30 +10,10 @@ var _ = require('lodash')

comp.eventScope.add(ast.event_domain.value, ast.event_type.value)
var fnBody = []
if (ast.where) {
// inject attrs as varibles in the scope
fnBody.push(e('var', 'event_attrs', e('acall',
e('id', 'ctx.modules.get'),
[e('id', 'ctx'), e('str', 'event'), e('str', 'attrs')]
)))
var attrKeys = e('call', e('id', 'Object.keys'), [e('id', 'event_attrs')])
fnBody.push(e(';', e('call', e('.', attrKeys, e('id', 'forEach')), [
e('fn', ['attr'], [
// don't stomp over global scope
e('if', e('!', e('call', e('id', 'ctx.scope.has'), [e('id', 'attr')])),
e(';', e('call', e('id', 'ctx.scope.set'), [
e('id', 'attr'),
e('get', e('id', 'event_attrs'), e('id', 'attr'))
]))
)
])
])))
}
if (!_.isEmpty(ast.event_attrs)) {
// select when domain type <attr> re#..#
fnBody.push(e('var', 'matches', e('array', [])))
fnBody.push(e('var', 'setting', e('obj', {})))
fnBody.push(e('var', 'm'))

@@ -48,8 +28,17 @@ fnBody.push(e('var', 'j'))

var key = e('string', a.key.value, a.key.loc)
var attr = e('call', id('getAttrString'), [id('ctx', a.key.loc), key], a.key.loc)
comp.eventScope.addAttr(a.key.value)
var regexExec = e('.', comp(a.value), id('exec', a.value.loc), a.value.loc)
fnBody.push(e(';', e('=', id('m'), e('call', regexExec, [attr], a.value.loc), a.value.loc)))
fnBody.push(e(';', e('=', id('m'), e('call', regexExec, [
e('?', e('call', e('id', 'Object.prototype.hasOwnProperty.call'), [id('$event.data.attrs'), key]), e('call', e('id', '$stdlib.as', a.key.loc), [
e('id', '$ctx', a.key.loc),
e('array', [
e('get', id('$event.data.attrs'), key, a.key.loc),
e('str', 'String', a.key.loc)
], a.key.loc)
], a.key.loc), e('str', '', a.key.loc))
], a.value.loc), a.value.loc)))
// if !m, then the EventExpression doesn't match
fnBody.push(e('if', e('!', id('m')), e('return', e('false'))))
fnBody.push(e('if', e('!', id('m')), e('return', e('obj', { match: e(false) }))))

@@ -68,11 +57,19 @@ // append to matches

_.each(ast.setting, function (s, i) {
fnBody.push(e(';',
e('call', e('id', 'setting', s.loc), [
e('str', s.value, s.loc),
e('get', e('id', 'matches', s.loc), e('num', i, s.loc), s.loc)
], s.loc), s.loc))
comp.scope.set(s.value, { type: 'String' })
comp.scope.get('$selectVars').push(s.value)
fnBody.push(
e('var',
comp.jsId(s.value),
e('=',
e('get', e('id', 'setting', s.loc), e('str', s.value, s.loc), s.loc),
e('get', e('id', 'matches', s.loc), e('num', i, s.loc), s.loc),
s.loc
),
s.loc
)
)
})
if (ast.where) {
fnBody.push(e('if', e('!', comp(ast.where)), e('return', e('false'))))
fnBody.push(e('if', e('!', comp(ast.where)), e('return', e('obj', { match: e(false) }))))
}

@@ -82,25 +79,48 @@

fnBody.push(e(';',
e('acall',
e('id', 'aggregateEvent', ast.aggregator.loc),
[
e('id', 'ctx', ast.aggregator.loc),
e('string', ast.aggregator.op, ast.aggregator.loc),
e('array', _.map(ast.aggregator.args, function (a, i) {
return e('array', [
e('string', a.value, a.loc),
e('get', e('id', 'matches', a.loc), e('num', i, a.loc), a.loc)
], a.loc)
}), ast.aggregator.loc)
],
ast.aggregator.loc
e('=',
e('id', '$state', ast.aggregator.loc),
e('acall',
e('id', '$ctx.krl.aggregateEvent', ast.aggregator.loc),
[
e('id', '$state', ast.aggregator.loc),
e('string', ast.aggregator.op, ast.aggregator.loc),
e('array', _.map(ast.aggregator.args, function (a, i) {
comp.scope.set(a.value, { type: 'Unknown' })
comp.scope.get('$selectVars').push(a.value)
return e('array', [
e('string', a.value, a.loc),
e('get', e('id', 'matches', a.loc), e('num', i, a.loc), a.loc)
], a.loc)
}), ast.aggregator.loc)
],
ast.aggregator.loc
), ast.aggregator.loc
), ast.aggregator.loc))
}
if (fnBody.length === 0) {
return e(true)
const ee = [
e('str', `${ast.event_domain.value}:${ast.event_type.value}`)
]
if (fnBody.length > 0) {
fnBody.push(e('return', e('obj', {
match: e(true),
state: _.isEmpty(ast.event_attrs)
? e('id', '$state')
: e('call', e('id', 'Object.assign'), [
e('obj', {}),
e('id', '$state'),
e('obj', {
setting: e('call', e('id', 'Object.assign'), [
e('obj', {}),
e('||', e('id', '$state.setting'), e('obj', {})),
e('id', 'setting')
])
})
])
})))
ee.push(e('asyncfn', ['$event', '$state'], fnBody))
}
fnBody.push(e('return', e(true)))
return e('asyncfn', ['ctx', 'aggregateEvent', 'getAttrString', 'setting'], fnBody)
return e('call', e('id', '$ctx.krl.SelectWhen.e'), ee)
}

@@ -23,5 +23,3 @@ var _ = require('lodash')

}
return e('asyncfn', ['ctx'], [
e('return', e('*', comp(ast.expression), e('num', multiplier)))
])
return e('*', comp(ast.expression), e('num', multiplier))
}
var _ = require('lodash')
var declarationBlock = require('../utils/declarationBlock')
module.exports = function (ast, comp, e) {
var body = comp(ast.params)
var body = []
_.each(ast.body, function (part, i) {
return body.push(comp(part))
})
comp.scope.push()
comp.scope.set('$$is_inside_fn_or_action_body$$', true)
// compile the params first, so params get defined in comp.scope before the function body compiles
const { params, defaultSetups } = comp(ast.params)
body = body.concat(defaultSetups)
body = body.concat(declarationBlock(ast.body, comp))
body.push(e('return', comp(ast.return)))
comp.scope.pop()
var paramNames = []
var paramOrder = e('array', _.map(ast.params.params, function (p) {
paramNames.push(p.id.value)
return e('string', p.id.value, p.id.loc)
}), ast.params.loc)
return e('call', e('id', 'ctx.mkFunction'), [
const estree = e('call', e('id', '$ctx.krl.Function'), [
paramOrder,
e('asyncfn', ['ctx', 'args'], body)
{
type: 'FunctionExpression',
params: params,
body: {
type: 'BlockStatement',
body: body
},
async: true
}
])
estree.$$Annotation = {
type: 'Function',
params: paramNames
}
return estree
}

@@ -6,5 +6,5 @@ module.exports = function (ast, comp, e) {

// if not inside a foreach, consider it true
e('===', e('typeof', e('id', 'foreach_is_final')), e('string', 'undefined')),
e('===', e('typeof', e('id', '$foreach_is_final')), e('string', 'undefined')),
// inside a foreach `foreach_is_final` is defined
e('id', 'foreach_is_final')
e('id', '$foreach_is_final')
),

@@ -11,0 +11,0 @@ comp(ast.statement)

@@ -0,3 +1,17 @@

const krlStdlib = require('krl-stdlib')
module.exports = function (ast, comp, e, context) {
return e('call', e('id', 'ctx.scope.get'), [e('str', ast.value)])
const id = ast.value
if (krlStdlib.stdlib[id] && !comp.stdlibToInject[id] && comp.scope.getItsHeight(id) === 1) {
comp.stdlibToInject[id] = ast
}
const estree = e('id', comp.jsId(id))
const scopeMeta = comp.scope.get(id)
if (typeof scopeMeta.type === 'string' && scopeMeta.type !== 'Unknown') {
estree.$$Annotation = scopeMeta
}
return estree
}
module.exports = function (ast, comp, e) {
return e(';', e('call', e('id', 'ctx.stopRulesetExecution'), [e('id', 'ctx')]))
return e('return', e('call', e('id', '$last'), []))
}
module.exports = function (ast, comp, e) {
return e(';', e('call', e('id', 'ctx.log'), [
e('string', ast.level),
return e(';', e('call', e('id', '$ctx.log.' + ast.level), [
comp(ast.expression)
]))
}

@@ -14,13 +14,28 @@ var callStdLibFn = require('../utils/callStdLibFn')

if (ast.object.type === 'DomainIdentifier' &&
(ast.object.domain === 'ent' || ast.object.domain === 'app')
(ast.object.domain === 'ent')
) {
return e('acall', e('id', 'ctx.modules.get'), [
e('id', 'ctx'),
e('str', ast.object.domain),
e('obj', {
key: e('str', ast.object.value),
path: comp(ast.property)
})
], ast.loc)
// TODO use optimized version
// TODO return e('acall', e('id', '$ctx.rsCtx.getEnt'), [
// TODO e('str', ast.object.value),
// TODO comp(ast.property)
// TODO ])
return e('acall', e('id', '$stdlib.get'), [
e('id', '$ctx'),
e('array', [
e('acall', e('id', '$ctx.rsCtx.getEnt'), [
e('str', ast.object.value)
]),
comp(ast.property)
])
])
}
if (ast.object.type === 'DomainIdentifier' &&
ast.object.domain === 'event' &&
ast.object.value === 'attrs'
) {
const val = ast.property
if (val && val.type === 'String') {
comp.eventScope.addAttr(val.value)
}
}
return callStdLibFn(e, 'get', [

@@ -27,0 +42,0 @@ comp(ast.object),

module.exports = function (ast, comp, e) {
var mkIdStr = function () {
return e('string', ast.id.value, ast.id.loc)
}
comp.scope.set(ast.id.value, { type: 'Unknown' })
var getArg = e('get', e('id', 'args'), mkIdStr())
let estree = e('id', comp.jsId(ast.id.value), ast.id.loc)
var val = getArg
if (ast['default']) {
// only evaluate default if needed i.e. default may be calling an function
val = e('?',
e('call', e('id', 'args.hasOwnProperty'), [mkIdStr()]),
getArg,
comp(ast['default'])
)
const dflt = comp(ast['default'])
if (dflt.$$Annotation) {
comp.scope.set(ast.id.value, dflt.$$Annotation)
}
estree = {
type: 'AssignmentPattern',
left: estree,
right: comp(ast['default'])
}
}
return e(';', e('call', e('id', 'ctx.scope.set'), [
mkIdStr(),
val
]))
return estree
}

@@ -1,7 +0,11 @@

var _ = require('lodash')
const _ = require('lodash')
module.exports = function (ast, comp, e) {
var usedIds = {}
var hasSeenDefault = false
return _.map(ast.params, function (param) {
const usedIds = {}
let hasSeenDefault = false
// javascript doesn't allow `await` in the defaults, so we need to do those in the function body
const defaultSetups = []
const params = _.map(ast.params, function (param) {
var id = param.id.value

@@ -18,4 +22,27 @@ if (usedIds[id]) {

}
return comp(param)
const estree = comp(param)
if (estree.type === 'AssignmentPattern') {
switch (estree.right.type) {
case 'Literal':
break
default:
const right = estree.right
estree.right = e('id', '$default')
defaultSetups.push(e('if',
e('==', estree.left, e('id', '$default')),
e('block', [
e(';', e('=', estree.left, right))
])
))
}
}
return estree
})
return {
params,
defaultSetups
}
}

@@ -5,4 +5,4 @@ module.exports = function (ast, comp, e) {

}
if (ast.left.type !== 'DomainIdentifier' || !/^(ent|app)$/.test(ast.left.domain)) {
throw comp.error(ast.left.loc, 'PersistentVariableAssignment - only works on ent:* or app:* variables')
if (ast.left.type !== 'DomainIdentifier' || !/^ent$/.test(ast.left.domain)) {
throw comp.error(ast.left.loc, 'PersistentVariableAssignment - only works on ent:* variables')
}

@@ -26,8 +26,8 @@

// Use the optimized append
return e(';', e('acall', e('id', 'ctx.modules.append'), [
e('id', 'ctx'),
e('str', ast.left.domain, ast.left.loc),
e('str', ast.left.value, ast.left.loc),
e('array', comp(ast.right.args.args))
]))
// TODO return e(';', e('acall', e('id', 'ctx.modules.append'), [
// TODO e('id', 'ctx'),
// TODO e('str', ast.left.domain, ast.left.loc),
// TODO e('str', ast.left.value, ast.left.loc),
// TODO e('array', comp(ast.right.args.args))
// TODO ]))
}

@@ -42,11 +42,20 @@ }

if (ast.path_expression) {
key = e('obj', {
key: key,
path: comp(ast.path_expression)
})
// TODO use optimized version
// TODO key = e('obj', {
// TODO key: key
// TODO })
return e(';', e('acall', e('id', '$ctx.rsCtx.putEnt'), [
key,
e('acall', e('id', '$stdlib.set'), [
e('id', '$ctx'),
e('array', [
e('acall', e('id', '$ctx.rsCtx.getEnt'), [key]),
comp(ast.path_expression),
valueToStore
])
])
]))
}
return e(';', e('acall', e('id', 'ctx.modules.set'), [
e('id', 'ctx'),
e('str', ast.left.domain, ast.left.loc),
return e(';', e('acall', e('id', '$ctx.rsCtx.putEnt'), [
key,

@@ -53,0 +62,0 @@ valueToStore

module.exports = function (ast, comp, e) {
const args = {}
// TODO ?? for_rid: ast.for_rid ? comp(ast.for_rid) : e('nil')
const attrs = ast.event_attrs ? comp(ast.event_attrs) : e('nil')
if (ast.event_domainAndType) {
args.domainAndType = comp(ast.event_domainAndType)
} else {
args.domain = e('string', ast.event_domain.value, ast.event_domain.loc)
args.type = comp(ast.event_type)
// TODO
return e('block', [
e(
'let',
e('id', '$parts'),
e(
'call',
e(
'.',
e(
'call',
e(
'.',
e('call', e('id', '$ctx.krl.toString'), [
comp(ast.event_domainAndType)
]),
e('id', 'replace')
),
[
{
type: 'Literal',
regex: {
pattern: '\\s+',
flags: 'g'
}
},
e('str', '')
]
),
e('id', 'split')
),
[e('str', ':')]
)
),
e(
';',
e('acall', e('id', '$ctx.rsCtx.raiseEvent'), [
e('get', e('id', '$parts'), e('num', 0)),
e(
'call',
e(
'.',
e('call', e('.', e('id', '$parts'), e('id', 'slice')), [
e('num', 1)
]),
e('id', 'join')
),
[e('str', ':')]
),
attrs
])
)
])
}
args.attributes = ast.event_attrs ? comp(ast.event_attrs) : e('nil')
args.for_rid = ast.for_rid ? comp(ast.for_rid) : e('nil')
return e(';', e('acall', e('id', 'ctx.raiseEvent'), [e('obj', args)]))
return e(
';',
e('acall', e('id', '$ctx.rsCtx.raiseEvent'), [
e('string', ast.event_domain.value, ast.event_domain.loc),
comp(ast.event_type),
attrs
])
)
}
var _ = require('lodash')
var declarationBlock = require('../utils/declarationBlock')
module.exports = function (ast, comp, e) {
var rule = {
name: e('string', ast.name.value, ast.name.loc)
}
function Rule (ast, comp, e) {
// TODO use symbol-table to store ast.name.value
if (ast.rule_state !== 'active') {
rule.rule_state = e('string', ast.rule_state)
comp.warn(ast.loc, 'rule ' + ast.name.value + ' is inactive, i.e. commented out')
return e('obj', rule)
return e(';', e('null'))
}

@@ -16,6 +13,35 @@ if (!ast.select) {

}
rule.select = comp(ast.select)
var ruleBody = []
comp.scope.set('$selectVars', [])
const selectWhenRule = comp(ast.select)
var ruleBody = [
e(';', e('call', e('id', '$ctx.setCurrentRuleName'), [e('str', ast.name.value)])),
e(';', e('call', e('id', '$ctx.log.debug'), [
e('str', 'rule selected'),
e('obj', { rule_name: e('str', ast.name.value) })
]))
]
const selectVars = _.uniq(comp.scope.get('$selectVars'))
_.each(selectVars, function (selectVar) {
ruleBody.push(e('var', comp.jsId(selectVar), e('get', e('id', '$state.setting'), e('str', selectVar))))
})
if (_.size(selectVars) > 0) {
ruleBody.push(e(';', e('=', e('id', 'this.rule.state'), e('call', e('id', 'Object.assign'), [
e('obj', {}),
e('id', '$state'),
e('obj', {
setting: e('obj', {})
})
]))))
}
_.each(ast.foreach, function (foreach) {
_.each(foreach.setting, function (set, i) {
comp.scope.set(set.value, { type: 'Unknown' })
})
})
if (!_.isEmpty(ast.prelude)) {

@@ -27,8 +53,12 @@ ruleBody = ruleBody.concat(declarationBlock(ast.prelude, comp))

} else {
ruleBody.push(e('var', 'fired', e('true')))
ruleBody.push(e('var', '$fired', e('true')))
}
ruleBody.push(e('if', e('id', 'fired'),
e(';', e('call', e('id', 'ctx.emit'), [e('str', 'debug'), e('str', 'fired')])),
e(';', e('call', e('id', 'ctx.emit'), [e('str', 'debug'), e('str', 'not fired')]))
ruleBody.push(e('if', e('id', '$fired'),
e(';', e('call', e('id', '$ctx.log.debug'), [
e('str', 'fired')
])),
e(';', e('call', e('id', '$ctx.log.debug'), [
e('str', 'not fired')
]))
))

@@ -56,5 +86,23 @@

rule.body = e('asyncfn', ['ctx', 'runAction', 'toPairs'], ruleBody)
return e(';', e('call', e('id', '$rs.when'), [
selectWhenRule,
e('asyncfn', ['$event', '$state', '$last'], [
{
type: 'TryStatement',
block: e('block',
ruleBody
),
finalizer: e('block', [
e(';', e('call', e('id', '$ctx.setCurrentRuleName'), [e('null')]))
])
}])
]))
}
return e('obj', rule)
module.exports = function (ast, comp, e) {
comp.scope.push()
comp.scope.set('$rule_name', ast.name.value)
const estree = Rule(ast, comp, e)
comp.scope.pop()
return estree
}

@@ -1,9 +0,9 @@

var _ = require('lodash')
const _ = require('lodash')
var mkId = function (e, i, key) {
return e('id', 'foreach' + i + '_' + key)
function mkId (e, i, key) {
return e('id', '$foreach' + i + '_' + key)
}
var mkIsFinal = function (e, nIndexes) {
var mkEq = function (i) {
function mkIsFinal (e, nIndexes) {
function mkEq (i) {
return e(

@@ -15,4 +15,4 @@ '===',

}
var curr = mkEq(0)
var i = 1
let curr = mkEq(0)
let i = 1
while (i < nIndexes) {

@@ -26,15 +26,15 @@ curr = e('&&', curr, mkEq(i))

module.exports = function (ast, comp, e, context) {
var id = function (key) {
function id (key) {
return mkId(e, context.foreach_i, key)
}
var stmts = []
let stmts = []
var body = []
let body = []
if (context.foreach_n_left === 0) {
// the last loop
body.push(e('var', 'foreach_is_final', mkIsFinal(e, context.foreach_i + 1)))
body.push(e('let', '$foreach_is_final', mkIsFinal(e, context.foreach_i + 1)))
}
_.each(ast.setting, function (set, i) {
var val
let val
if (i === 0) {

@@ -47,12 +47,10 @@ val = e('get', e('get', id('pairs'), id('i')), e('number', 1))// value

}
body.push(e(';', e('call', e('id', 'ctx.scope.set'), [
e('string', set.value, set.loc),
val
])))
comp.scope.set(set.value, { type: 'Unknown' })
body.push(e('let', comp.jsId(set.value), val, set.loc))
})
body = body.concat(context.foreach_body)
stmts.push(e('var', id('pairs'), e('call', e('id', 'toPairs'), [comp(ast.expression)])))
stmts.push(e('var', id('len'), e('.', id('pairs'), e('id', 'length'))))
stmts.push(e('var', id('i')))
stmts.push(e('let', id('pairs'), e('call', e('id', '$ctx.krl.toPairs'), [comp(ast.expression)])))
stmts.push(e('let', id('len'), e('.', id('pairs'), e('id', 'length'))))
stmts.push(e('let', id('i')))
stmts.push(e('for',

@@ -59,0 +57,0 @@ e('=', id('i'), e('number', 0)),

module.exports = function (ast, comp, e) {
var body = []
if (ast.fired) {
body.push(e('if', e('id', 'fired'), e('block', comp(ast.fired))))
body.push(e('if', e('id', '$fired'), e('block', comp(ast.fired))))
}
if (ast.notfired) {
body.push(e('if', e('!', e('id', 'fired')), e('block', comp(ast.notfired))))
body.push(e('if', e('!', e('id', '$fired')), e('block', comp(ast.notfired))))
}

@@ -9,0 +9,0 @@ if (ast.always) {

@@ -1,471 +0,39 @@

var _ = require('lodash')
module.exports = function (ast, comp, e) {
if (ast.kind === 'when') {
const selectWhenRule = comp(ast.event)
var wrapInOr = function (states) {
if (_.size(states) === 1) {
return _.head(states)
}
return ['or', _.head(states), wrapInOr(_.tail(states))]
}
var permute = function (arr) {
return arr.reduce(function permute (res, item, key, arr) {
return res.concat(arr.length > 1
? arr
.slice(0, key)
.concat(arr.slice(key + 1))
.reduce(permute, [])
.map(function (perm) {
return [item].concat(perm)
})
: item
)
}, [])
}
var StateMachine = function () {
var start = _.uniqueId('state_')
var end = _.uniqueId('state_')
var transitions = []
var join = function (state1, state2) {
_.each(transitions, function (t) {
if (t[0] === state1) {
t[0] = state2
}
if (t[2] === state1) {
t[2] = state2
}
})
}
return {
start: start,
end: end,
add: function (fromState, onEvent, toState) {
transitions.push([fromState, onEvent, toState])
},
getTransitions: function () {
return transitions
},
concat: function (other) {
_.each(other.getTransitions(), function (t) {
transitions.push(_.cloneDeep(t))
})
},
join: join,
optimize: function () {
// Find all cases where the same event goes to different states and join those states into one
while (true) {
let toJoin = []
let groupped = {}
_.each(transitions, function (t) {
var key = t[0] + JSON.stringify(t[1])// stringify b/c ["not","expr_1"]
var state = t[2]
if (_.has(groupped, key)) {
if (state !== groupped[key]) {
toJoin.push([state, groupped[key]])
}
} else {
groupped[key] = state
}
})
if (toJoin.length === 0) {
break
}
toJoin.forEach(function (j) {
join(j[0], j[1])
})
}
// Remove duplicate transitions
let tree = {}
_.each(transitions, function (t) {
_.set(tree, [JSON.stringify(t[1]), t[0], t[2]], true)
})
transitions = []
_.each(tree, function (froms, onEvent) {
_.each(froms, function (tos, fromState) {
_.each(tos, function (bool, toState) {
transitions.push([fromState, JSON.parse(onEvent), toState])
})
})
})
},
compile: function () {
// we want to ensure we get the same output on every compile
// that is why we are re-naming states and sorting the output
var outStates = {}
outStates[start] = 'start'
outStates[end] = 'end'
var i = 0
var toOutState = function (state) {
if (_.has(outStates, state)) {
return outStates[state]
}
outStates[state] = 's' + (i++)
return outStates[state]
}
var outTransitions = _.sortBy(_.map(transitions, function (t) {
return [toOutState(t[0]), t[1], toOutState(t[2])]
}), function (t) {
var score = 0
if (t[0] === 'start') {
score -= Infinity
}
if (t[0] === 'end') {
score += Infinity
}
if (/^s[0-9]+$/.test(t[0])) {
score += _.parseInt(t[0].substring(1), 10) || 0
}
return score
})
var stm = {}
_.each(outTransitions, function (t) {
if (!_.has(stm, t[0])) {
stm[t[0]] = []
}
stm[t[0]].push([t[1], t[2]])
})
return stm
if (ast.within) {
return e('call', e('id', '$ctx.krl.SelectWhen.within'), [
comp(ast.within),
selectWhenRule,
e('fn', ['$event', '$state'], [
e('return', e('call', e('id', 'Object.assign'), [
e('obj', {}),
e('id', '$state'),
e('obj', {
setting: e('obj', {})
})
]))
])
])
}
}
}
var toLispArgs = function (ast, traverse) {
return _.map(ast.args, traverse)
}
return selectWhenRule
} else if (ast.kind === 'where') {
const expr = comp(ast.expression)
var eventOps = {
'before': {
toLispArgs: toLispArgs,
mkStateMachine: function (args, evalEELisp) {
var s = StateMachine()
var prev
_.each(args, function (arg, j) {
var a = evalEELisp(arg)
s.concat(a)
if (j === 0) {
s.join(a.start, s.start)
}
if (j === _.size(args) - 1) {
s.join(a.end, s.end)
}
if (prev) {
s.join(prev.end, a.start)
}
prev = a
})
return s
}
},
'after': {
toLispArgs: toLispArgs,
mkStateMachine: function (args, evalEELisp) {
var s = StateMachine()
var prev
_.each(_.range(_.size(args) - 1, -1), function (i, j) {
var a = evalEELisp(args[i])
s.concat(a)
if (j === 0) {
s.join(a.start, s.start)
}
if (j === _.size(args) - 1) {
s.join(a.end, s.end)
}
if (prev) {
s.join(prev.end, a.start)
}
prev = a
})
return s
}
},
'then': {
toLispArgs: toLispArgs,
mkStateMachine: function (args, evalEELisp) {
var s = StateMachine()
var mergePoints = []
var prev
_.each(args, function (arg, j) {
var a = evalEELisp(arg)
s.concat(a)
if (j === 0) {
s.join(a.start, s.start)
}
if (j === _.size(args) - 1) {
s.join(a.end, s.end)
}
if (prev) {
s.join(prev.end, a.start)
mergePoints.push(a.start)
}
prev = a
})
var transitions = s.getTransitions()
_.each(mergePoints, function (daState) {
// if not daState return to start
var notB = wrapInOr(_.uniq(_.compact(_.map(transitions, function (t) {
if (t[0] === daState) {
return ['not', t[1]]
}
}))))
s.add(daState, notB, s.start)
})
return s
}
},
'and': {
toLispArgs: toLispArgs,
mkStateMachine: function (args, evalEELisp) {
var s = StateMachine()
_.each(permute(_.range(0, _.size(args))), function (indices) {
var prev
_.each(indices, function (i, j) {
var a = evalEELisp(args[i])
s.concat(a)
if (j === 0) {
s.join(a.start, s.start)
}
if (j === _.size(indices) - 1) {
s.join(a.end, s.end)
}
if (prev) {
s.join(prev.end, a.start)
}
prev = a
})
})
return s
}
},
'or': {
toLispArgs: toLispArgs,
mkStateMachine: function (args, evalEELisp) {
var s = StateMachine()
_.each(args, function (arg) {
var a = evalEELisp(arg)
s.concat(a)
s.join(a.start, s.start)
s.join(a.end, s.end)
})
return s
}
},
'between': {
toLispArgs: toLispArgs,
mkStateMachine: function (args, evalEELisp) {
var s = StateMachine()
var a = evalEELisp(args[0])
var b = evalEELisp(args[1])
var c = evalEELisp(args[2])
s.concat(a)
s.concat(b)
s.concat(c)
s.join(b.start, s.start)
s.join(b.end, a.start)
s.join(a.end, c.start)
s.join(c.end, s.end)
return s
}
},
'not between': {
toLispArgs: toLispArgs,
mkStateMachine: function (args, evalEELisp) {
var s = StateMachine()
var a = evalEELisp(args[0])
var b = evalEELisp(args[1])
var c = evalEELisp(args[2])
s.concat(a)
s.concat(b)
s.concat(c)
// start:b -> c -> end
s.join(b.start, s.start)
s.join(b.end, c.start)
s.join(c.end, s.end)
// a -> start
s.join(a.start, c.start)
s.join(a.end, s.start)
return s
}
},
'any': {
toLispArgs: function (ast, traverse) {
var num = _.head(ast.args)
return [num.value].concat(_.map(_.tail(ast.args), traverse))
},
mkStateMachine: function (args, evalEELisp) {
var s = StateMachine()
var num = _.head(args)
var eventexs = _.tail(args)
var indicesGroups = _.uniqWith(_.map(permute(_.range(0, _.size(eventexs))), function (indices) {
return _.take(indices, num)
}), _.isEqual)
_.each(indicesGroups, function (indices) {
indices = _.take(indices, num)
var prev
_.each(indices, function (i, j) {
var a = evalEELisp(eventexs[i])
s.concat(a)
if (j === 0) {
s.join(a.start, s.start)
}
if (j === _.size(indices) - 1) {
s.join(a.end, s.end)
}
if (prev) {
s.join(prev.end, a.start)
}
prev = a
})
})
return s
}
},
'count': {
toLispArgs: function (ast, traverse) {
return [ast.n.value].concat(_.map([ast.event], traverse))
},
mkStateMachine: function (args, evalEELisp) {
var s = StateMachine()
var num = _.head(args)
var eventex = _.head(_.tail(args))
var prev
_.each(_.range(0, num), function (i, j) {
var a = evalEELisp(eventex)
s.concat(a)
if (j === 0) {
s.join(a.start, s.start)
}
if (j === num - 1) {
s.join(a.end, s.end)
}
if (prev) {
s.join(prev.end, a.start)
}
prev = a
})
return s
}
},
'repeat': {
toLispArgs: function (ast, traverse) {
return [ast.n.value].concat(_.map([ast.event], traverse))
},
mkStateMachine: function (args, evalEELisp) {
var s = StateMachine()
var num = _.head(args)
var eventex = _.head(_.tail(args))
var prev
_.each(_.range(0, num), function (i, j) {
var a = evalEELisp(eventex)
s.concat(a)
if (j === 0) {
s.join(a.start, s.start)
}
if (j === num - 1) {
s.join(a.end, s.end)
}
if (prev) {
s.join(prev.end, a.start)
}
prev = a
})
s.add(s.end, eventex, s.end)
return s
}
return e('call', e('id', '$ctx.krl.SelectWhen.e'),
[
e('str', '*'),
e('asyncfn', ['$event', '$state'], [
e('return', e('obj', {
match: expr,
state: e('id', '$state')
}))
])
]
)
}
}
module.exports = function (ast, comp, e) {
if (ast.kind !== 'when') {
throw new Error('RuleSelect.kind not supported: ' + ast.kind)
}
var eeId = 0
var graph = {}
var onEE = function (ast) {
var domain = ast.event_domain.value
var type = ast.event_type.value
var ee = comp(ast)
var id = 'expr_' + (eeId++)
_.set(graph, [domain, type, id], ee)
return id
}
var traverse = function (ast) {
switch (ast.type) {
case 'EventExpression':
return onEE(ast)
case 'EventOperator':
case 'EventGroupOperator':
if (!_.has(eventOps, ast.op)) {
throw new Error(ast.type + '.op not supported: ' + ast.op)
}
return [ast.op].concat(eventOps[ast.op].toLispArgs(ast, traverse))
default:
throw new Error('invalid event ast node: ' + ast.type)
}
}
var evalEELisp = function (lisp) {
var s
if (_.isString(lisp)) {
s = StateMachine()
s.add(s.start, lisp, s.end)
return s
}
if (_.has(eventOps, lisp[0])) {
s = eventOps[lisp[0]].mkStateMachine(lisp.slice(1), evalEELisp)
s.optimize()
return s
} else {
throw new Error('EventOperator.op not supported: ' + ast.op)
}
}
var lisp = traverse(ast.event)
var stateMachine = evalEELisp(lisp)
var r = {
graph: e('obj', _.mapValues(graph, function (types, domain) {
return e('obj', _.mapValues(types, function (exprs, type) {
return e('obj', exprs)
}))
})),
state_machine: e('json', stateMachine.compile())
}
if (ast.within) {
r.within = comp(ast.within)
}
return e('obj', r)
throw new Error('RuleSelect.kind not supported: ' + ast.kind)
}

@@ -5,22 +5,175 @@ var _ = require('lodash')

module.exports = function (ast, comp, e) {
var rulesObj = {}
_.each(ast.rules, function (rule) {
if (_.has(rulesObj, rule.name.value)) {
throw comp.error(rule.name.loc, 'Duplicate rule name: ' + rule.name.value)
}
rulesObj[rule.name.value] = comp(rule)
})
var rs = {
rid: comp(ast.rid)
}
if (ast.version) {
comp.warn(ast.loc, 'ruleset{version ...} is deprecated. Use ruleset{meta{version ...}} instead')
ast.meta.properties.push({
loc: ast.version.loc,
type: 'RulesetMetaProperty',
key: { loc: ast.version.loc, type: 'Keyword', value: 'version' },
value: ast.version
})
}
const shares = []
const provides = []
const esBodyModules = []
if (ast.meta) {
rs.meta = comp(ast.meta)
_.each(ast.meta.properties, function (prop) {
if (prop.key.value === 'shares') {
_.each(prop.value.ids, function (id) {
shares.push(id)
})
} else if (prop.key.value === 'provides') {
_.each(prop.value.ids, function (id) {
provides.push(id)
})
} else if (prop.key.value === 'configure') {
for (const dec of prop.value.declarations) {
const estree = comp(dec.right)
comp.scope.set(dec.left.value, estree.$$Annotation || { type: 'Unknown' })
esBodyModules.push(e('const', comp.jsId(dec.left.value), e('call', e('id', '$ctx.configure', dec.loc), [
e('str', dec.left.value, dec.left.loc),
estree
], dec.loc), dec.left.loc))
}
} else if (prop.key.value === 'use') {
const ast = prop.value
if (ast.kind !== 'module') {
throw comp.error(ast.loc, `use ${ast.kind} is not supported`)
}
const args = [
e('str', ast.rid.value, ast.rid.loc),
ast.alias
? e('str', ast.alias.value, ast.alias.loc)
: e('null', ast.rid.loc)
]
if (ast['with']) {
const withObj = {}
for (const dec of ast['with']) {
withObj[dec.left.value] = comp(dec.right)
}
args.push(e('obj', withObj, ast.loc))
}
esBodyModules.push(e(';', e('acall', e('id', '$ctx.useModule', prop.loc), args, prop.loc), prop.loc))
}
})
}
if (!_.isEmpty(ast.global)) {
rs.global = e('asyncfn', ['ctx'], declarationBlock(ast.global, comp))
const esBodyGlobal = declarationBlock(ast.global, comp)
const esBodyRules = []
esBodyRules.push(e('const', '$rs', e('new', e('id', '$ctx.krl.SelectWhen.SelectWhen'), [])))
const rulesObj = {}
_.each(ast.rules, function (rule) {
if (rulesObj[rule.name.value]) {
throw comp.error(rule.name.loc, 'Duplicate rule name: ' + rule.name.value)
}
rulesObj[rule.name.value] = true
esBodyRules.push(comp(rule))
})
const testingJSON = {
queries: [],
events: comp.eventScope.getTestingJSON()
}
rs.rules = e('obj', rulesObj)
const queries = {}
for (const share of shares) {
const annotation = comp.scope.get(share.value)
if (!annotation) {
throw comp.error(share.loc, 'Trying to share: ' + share.value + ' but it\'s not defined in global')
}
if (annotation && annotation.type === 'Action') {
throw comp.error(annotation.loc, 'Actions cannot be used queries: ' + share.value)
} else {
queries[share.value] = e('fn', ['query', 'qid'], [
e(';', e('call', e('id', '$ctx.setQuery'), [e('call', e('id', 'Object.assign'), [
e('obj', {}),
e('id', 'query'),
e('obj', { qid: e('id', 'qid') })
])])),
{
type: 'TryStatement',
block: e('block', [
annotation && annotation.type === 'Function'
? e('return', e('call', e('id', comp.jsId(share.value)), [e('id', '$ctx'), e('id', 'query.args')]))
: e('return', e('id', comp.jsId(share.value)))
]),
finalizer: e('block', [
e(';', e('call', e('id', '$ctx.setQuery'), [e('null')]))
])
}
])
testingJSON.queries.push({
name: share.value,
args: annotation && annotation.type === 'Function'
? annotation.params
: []
})
}
}
queries['__testing'] = e('fn', [], [e('return', e('id', comp.jsId('__testing')))])
let esBody = []
esBody.push(e('const', '$default', e('call', e('id', 'Symbol'), [e('str', 'default')])))
esBody.push(e('const', '$ctx', e('call', e('id', '$mkCtx'), [e('id', '$rsCtx')])))
esBody.push(e('const', '$stdlib', e('call', e('id', '$ctx.module'), [e('str', 'stdlib')])))
_.each(comp.stdlibToInject, function (ast, id) {
esBody.push(e('const', comp.jsId(id), e('get', e('id', '$stdlib', ast.loc), e('str', id, ast.loc), ast.loc), ast.loc))
})
esBody.push(e('const'
, '__testing1' // NOTE not using comp.jsId b/c we want this var to be the root scope so it can be shadowed
, e('json', testingJSON)
))
esBody = esBody.concat(esBodyModules)
esBody = esBody.concat(esBodyGlobal)
esBody = esBody.concat(esBodyRules)
const returnObj = {
event: e('asyncfn', ['event', 'eid'], [
e(';', e('call', e('id', '$ctx.setEvent'), [e('call', e('id', 'Object.assign'), [
e('obj', {}),
e('id', 'event'),
e('obj', { eid: e('id', 'eid') })
])])),
{
type: 'TryStatement',
block: e('block', [
e(';', e('acall', e('id', '$rs.send'), [e('id', 'event')]))
]),
finalizer: e('block', [
e(';', e('call', e('id', '$ctx.setEvent'), [e('null')]))
])
},
e('return', e('call', e('id', '$ctx.drainDirectives'), []))
]),
query: e('obj', queries)
}
if (provides.length > 0) {
const provideObj = {}
for (const provide of provides) {
const annotation = comp.scope.get(provide.value)
if (!annotation) {
throw comp.error(provide.loc, 'Trying to provide: ' + provide.value + ' but it\'s not defined in global')
}
provideObj[provide.value] = e('id', comp.jsId(provide.value))
}
returnObj.provides = e('obj', provideObj)
}
esBody.push(e('return', e('obj', returnObj)))
rs.init = e('asyncfn', ['$rsCtx', '$mkCtx'], esBody)
return [
e(';', e('=', e('id', 'module.exports'), e('obj', rs)))
e(';', e('=', e('id', 'module.exports'),
e('obj', rs)
))
]
}
var _ = require('lodash')
var propTypes = {
'version': function (props, comp, e) {
if (_.size(props) > 1) {
throw comp.error(props[1].loc, 'only 1 meta.version allowed')
}
return comp(_.head(props).value)
},
'name': function (props, comp, e) {
if (_.size(props) !== 1) {
throw new Error('only 1 meta.name allowed')
if (_.size(props) > 1) {
throw comp.error(props[1].loc, 'only 1 meta.name allowed')
}

@@ -11,4 +17,4 @@ return comp(_.head(props).value)

'description': function (props, comp, e) {
if (_.size(props) !== 1) {
throw new Error('only 1 meta.description allowed')
if (_.size(props) > 1) {
throw comp.error(props[1].loc, 'only 1 meta.description allowed')
}

@@ -18,4 +24,4 @@ return comp(_.head(props).value)

'author': function (props, comp, e) {
if (_.size(props) !== 1) {
throw new Error('only 1 meta.author allowed')
if (_.size(props) > 1) {
throw comp.error(props[1].loc, 'only 1 meta.author allowed')
}

@@ -25,6 +31,8 @@ return comp(_.head(props).value)

'logging': function (props, comp, e) {
if (_.size(props) !== 1) {
throw new Error('only 1 meta.logging allowed')
if (_.size(props) > 1) {
throw comp.error(props[1].loc, 'only 1 meta.logging allowed')
}
return comp(_.head(props).value)
const prop = _.head(props)
comp.warn(prop.loc, 'DEPRECATED meta.logging is no longer needed, logging is always on')
return comp(prop.value)
},

@@ -41,7 +49,6 @@ 'use': function (props, comp, e) {

}
if (ast.version) {
obj.version = comp(ast.version)
}
if (ast['with']) {
obj['with'] = e('asyncfn', ['ctx'], comp(ast['with']), ast['with'].loc)
obj['with'] = e('arr', ast['with'].map(dec => {
return e('str', dec.left.value, dec.left.loc)
}))
}

@@ -52,7 +59,11 @@ return e('obj', obj, ast.loc)

'configure': function (props, comp, e) {
if (_.size(props) !== 1) {
throw new Error('only 1 meta.configure allowed')
const ids = []
for (const ast of props) {
for (const dec of ast.value.declarations) {
ids.push(dec.left)
}
}
var ast = _.head(props)
return e('asyncfn', ['ctx'], comp(ast.value.declarations), ast.value.loc)
return e('arr', _.map(ids, function (id) {
return e('str', id.value, id.loc)
}))
},

@@ -70,39 +81,2 @@ 'shares': function (props, comp, e) {

}))
},
'provides_keys': function (props, comp, e) {
var json = {}
_.each(props, function (p) {
_.each(p.value.ids, function (idAst) {
var id = idAst.value
if (!_.has(json, id)) {
json[id] = { to: [] }
}
_.each(p.value.rulesets, function (r) {
json[id].to.push(r.value)
})
})
})
return e('json', json)
},
'keys': function (props, comp, e) {
var obj = {}
_.each(props, function (p) {
switch (_.get(p, ['value', 1, 'type'])) {
case 'String':
break
case 'Map':
_.each(p.value[1].value, function (pair) {
var vAstType = pair.value.type
if (vAstType !== 'String') {
throw new Error('A ruleset key that is Map, can only use Strings as values')
}
})
break
default:
throw new Error('Ruleset keys must be a String, or Map of Strings')
}
obj[p.value[0].value] = comp(p.value[1])
})
return e('obj', obj)
}

@@ -114,10 +88,10 @@ }

if (p.type !== 'RulesetMetaProperty') {
throw new Error('RulesetMeta.properties should all be RulesetMetaProperty ast nodes')
throw comp.error(p.loc, 'RulesetMeta.properties should all be RulesetMetaProperty ast nodes')
}
if (p.key.type !== 'Keyword') {
throw new Error('RulesetMetaProperty.key should a Keyword')
throw comp.error(p.key.loc, 'RulesetMetaProperty.key should a Keyword')
}
if (_.has(p.value, 'operator')) {
if (p.value.operator.type !== 'Keyword') {
throw new Error('RulesetMetaProperty.operator should a Keyword')
throw comp.error(p.value.operator.loc, 'RulesetMetaProperty.operator should a Keyword')
}

@@ -129,3 +103,3 @@ return p.key.value + '_' + p.value.operator.value

if (!_.has(propTypes, key)) {
throw new Error('RulesetMetaProperty not supported: ' + key)
throw comp.error(props[0].loc, 'RulesetMetaProperty not supported: ' + key)
}

@@ -132,0 +106,0 @@ return propTypes[key](props, comp, e)

@@ -1,6 +0,7 @@

var _ = require('lodash')
const _ = require('lodash')
module.exports = function (ast, comp, e) {
var args = {
attributes: ast.event_attrs ? comp(ast.event_attrs) : e('nil')
const args = {
eci: e('id', '$event.eci'),
attrs: ast.event_attrs ? comp(ast.event_attrs) : e('nil')
}

@@ -12,18 +13,25 @@

args.domain = e('string', ast.event_domain.value, ast.event_domain.loc)
args.type = comp(ast.event_type)
args.name = comp(ast.event_type)
}
let addFunction
if (_.has(ast, 'at')) {
args.at = comp(ast.at)
}
if (_.has(ast, 'timespec')) {
args.time = comp(ast.at)
addFunction = 'at'
} else if (_.has(ast, 'timespec')) {
args.timespec = comp(ast.timespec)
addFunction = 'repeat'
} else {
throw comp.error(ast.loc, 'error')
}
var moduleCall = e('acall', e('id', 'ctx.scheduleEvent'), [e('obj', args)])
var moduleCall = e('acall', e('get', e('call', e('id', '$ctx.module'), [e('str', 'schedule')]), e('str', addFunction)), [e('id', '$ctx'), e('obj', args)])
if (ast.setting) {
return e(';', e('call', e('id', 'ctx.scope.set', ast.setting.loc), [
e('str', ast.setting.value, ast.setting.loc),
moduleCall
], ast.setting.loc))
comp.scope.set(ast.setting.value, { type: 'Unknown' })
return e('var',
e('id', comp.jsId(ast.setting.value), ast.setting.loc),
moduleCall,
ast.setting.loc
)
} else {

@@ -30,0 +38,0 @@ return e(';', moduleCall)

var _ = require('lodash')
var mkTree = require('estree-builder')
var krlStdlib = require('krl-stdlib')
var toJsIdentifier = require('to-js-identifier')
var SymbolTableStack = require('symbol-table/stack')

@@ -19,2 +22,4 @@ var compByType = {

'EventExpression': require('./c/EventExpression'),
'EventGroupOperator': require('./c/EventGroupOperator'),
'EventOperator': require('./c/EventOperator'),
'EventWithin': require('./c/EventWithin'),

@@ -106,2 +111,45 @@ 'Function': require('./c/Function'),

var scope = SymbolTableStack()
// inject stdlib into the root scope
Object.keys(krlStdlib.stdlib).forEach(id => {
scope.set(id, { type: krlStdlib.krl.typeOf(krlStdlib.stdlib[id]) })
})
scope.set('__testing', { type: 'Map' })// defined in root scope so it can be shadowed in global
scope.push()// new scope for user's KRL code
var stdlibToInject = {}
var eventScope = (function () {
const map = {}
return {
add (domain, name) {
const rname = scope.get('$rule_name')
const path = [rname, domain, name]
if (!_.has(map, path)) {
_.set(map, path, { attrs: {} })
}
},
addAttr (key) {
const rname = scope.get('$rule_name')
for (const domain of Object.keys(map[rname] || {})) {
for (const name of Object.keys(map[rname][domain])) {
_.set(map, [rname, domain, name, 'attrs', key], true)
}
}
},
getTestingJSON () {
const result = []
for (const rname of Object.keys(map)) {
for (const domain of Object.keys(map[rname])) {
for (const name of Object.keys(map[rname][domain])) {
const e = map[rname][domain][name]
const attrs = Object.keys(e.attrs)
result.push({ domain, name, attrs })
}
}
}
return result
}
}
}())
var compile = function compile (ast, context) {

@@ -125,2 +173,11 @@ if (_.isArray(ast)) {

comp.warn = warn
comp.scope = scope
comp.eventScope = eventScope
comp.stdlibToInject = stdlibToInject
comp.jsId = function (id) {
if (!comp.scope.has(id)) {
throw comp.error(ast.loc, 'Undefined id: ' + id)
}
return toJsIdentifier(id) + scope.getItsHeight(id)
}

@@ -141,16 +198,17 @@ var estree

var body = compile(ast)
body = _.isArray(body) ? body : [body]
body = body.map(function (estree) {
if (!/Statement/.test(estree.type)) {
return mkTree(';', estree, estree.loc)
var rid
if (ast && ast.type === 'Ruleset') {
if (ast.rid && ast.rid.type === 'RulesetID') {
rid = ast.rid.value
}
return estree
})
}
var estree = compile(ast)
estree = _.isArray(estree) ? estree : []
return {
body: body,
warnings: warnings
rid,
estree,
warnings
}
}

@@ -22,3 +22,3 @@ var _ = require('lodash')

'type': 'Program',
'body': compiled.body
'body': compiled.estree
}, {

@@ -38,2 +38,3 @@ format: {

code: out.code,
rid: compiled.rid,
warnings: compiled.warnings

@@ -40,0 +41,0 @@ }

module.exports = function (e, domain, id, args, loc) {
var moduleVal = e('acall',
e('id', 'ctx.modules.get', loc),
[
e('id', 'ctx', loc),
e('str', domain, loc),
e('str', id, loc)
],
var moduleVal = e('get',
e('call', e('id', '$ctx.module', loc), [
e('str', domain, loc)
], loc),
e('str', id, loc),
loc
)
return e('acall', e('id', 'ctx.applyFn'), [
moduleVal,
e('id', 'ctx', loc),
return e('acall', moduleVal, [
e('id', '$ctx', loc),
args
], loc)
}
var _ = require('lodash')
module.exports = function (e, name, args, loc) {
return e('acall', e('id', 'ctx.applyFn'), [
e('call', e('id', 'ctx.scope.get', loc), [e('string', name, loc)], loc),
e('id', 'ctx'),
return e('acall', e('get', e('id', '$stdlib'), e('str', name)), [
e('id', '$ctx'),
_.isArray(args)

@@ -8,0 +7,0 @@ ? e('array', args)

var _ = require('lodash')
module.exports = function (astList, comp) {
var usedIDs = {}
return _.map(astList, function (ast) {
var id
if (ast.type === 'Declaration') {
if (ast.left.type === 'Identifier') {
id = ast.left.value
}
} else {
const declaredIds = []
const compiled = {}
for (const ast of astList) {
if (ast.type !== 'Declaration' || ast.left.type !== 'Identifier') {
throw comp.error(ast.loc, 'Only declarations should be in this block')
}
if (id) {
if (usedIDs[id]) {
// TODO make this an error, but right now some code relies on this
comp.warn(ast.loc, 'Duplicate declaration: ' + id)
}
usedIDs[id] = true
const id = ast.left.value
if (declaredIds.includes(id)) {
throw comp.error(ast.loc, 'Duplicate declaration: ' + id)
}
return comp(ast)
declaredIds.push(id)
if (ast.right.type === 'Function' || ast.right.type === 'Action') {
// don't compile yet, compile all expression declarations first
comp.scope.set(ast.left.value, { type: 'Unknown' })
} else {
compiled[id] = comp(ast)
}
}
// second pass for functions/actions
for (const ast of astList) {
const id = ast.left.value
if (!compiled[id]) {
compiled[id] = comp(ast)
}
}
return _.map(declaredIds, function (id) {
return compiled[id]
})
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc