Compare commits

..

8 Commits

Author SHA1 Message Date
Julien Fontanet
a4ab028ad6 feat(complex-matcher): 0.2.0 2018-01-25 16:57:29 +01:00
Julien Fontanet
9fc6013934 feat(xen-api): 0.16.3 2018-01-24 14:07:32 +01:00
Julien Fontanet
8a02d557f4 feat(xen-api): handle ghost tasks (#35)
See vatesfr/xo-web#2579
2018-01-24 14:06:46 +01:00
Julien Fontanet
bdddea2e29 feat(complex-matcher): support numbers (#32) 2018-01-17 12:06:44 +01:00
Julien Fontanet
be4ca0eede chore(complex-matcher): remove @babel/polyfill
Should be unnecessary.
2018-01-17 11:01:32 +01:00
Julien Fontanet
316d71b34d chore(xen-api): remove unused import 2018-01-11 11:22:16 +01:00
Julien Fontanet
b3bc9a2edd fix(package): update xen-api to 0.16.2 2018-01-09 17:48:04 +01:00
Julien Fontanet
90369acb63 fix(xen-api): remove undefined fields during preparation 2018-01-09 17:47:46 +01:00
7 changed files with 118 additions and 43 deletions

View File

@@ -1,11 +1,12 @@
const { NODE_ENV = 'development' } = process.env
const dependencies = require('./package').dependencies || {}
const NODE_ENV = process.env.NODE_ENV || 'development'
const __PROD__ = NODE_ENV === 'production'
const __TEST__ = NODE_ENV === 'test'
module.exports = {
comments: !__PROD__,
compact: __PROD__,
ignore: __TEST__ ? undefined : [ /\.spec\.js$/ ],
ignore: __TEST__ ? undefined : [/\.spec\.js$/],
plugins: ['lodash'],
presets: [
[
@@ -20,7 +21,7 @@ module.exports = {
node: '4',
}
: { node: 'current' },
useBuiltIns: 'usage',
useBuiltIns: '@babel/polyfill' in dependencies && 'usage',
},
],
],

View File

@@ -1,6 +1,6 @@
{
"name": "complex-matcher",
"version": "0.1.1",
"version": "0.2.0",
"license": "ISC",
"description": "",
"keywords": [],
@@ -24,7 +24,6 @@
"node": ">=4"
},
"dependencies": {
"@babel/polyfill": "7.0.0-beta.37",
"lodash": "^4.17.4"
},
"devDependencies": {
@@ -37,9 +36,10 @@
},
"scripts": {
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
"clean": "rimraf dist/",
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
"prebuild": "rimraf dist/",
"predev": "npm run prebuild",
"prepublishOnly": "npm run build"
"prebuild": "yarn run clean",
"predev": "yarn run clean",
"prepublishOnly": "yarn run build"
}
}

View File

@@ -1,6 +1,7 @@
import * as CM from './'
export const pattern = 'foo !"\\\\ \\"" name:|(wonderwoman batman) hasCape?'
export const pattern =
'foo !"\\\\ \\"" name:|(wonderwoman batman) hasCape? age:32'
export const ast = new CM.And([
new CM.String('foo'),
@@ -10,4 +11,5 @@ export const ast = new CM.And([
new CM.Or([new CM.String('wonderwoman'), new CM.String('batman')])
),
new CM.TruthyProperty('hasCape'),
new CM.Property('age', new CM.Number(32)),
])

View File

@@ -141,6 +141,23 @@ export class Not extends Node {
}
}
export class NumberNode extends Node {
constructor (value) {
super()
this.value = value
}
match (value) {
return value === this.value
}
toString () {
return String(this.value)
}
}
export { NumberNode as Number }
export class Property extends Node {
constructor (name, child) {
super()
@@ -159,9 +176,10 @@ export class Property extends Node {
}
const escapeChar = char => '\\' + char
const formatString = value => isRawString(value)
? value
: `"${value.replace(/\\|"/g, escapeChar)}"`
const formatString = value =>
Number.isNaN(+value)
? isRawString(value) ? value : `"${value.replace(/\\|"/g, escapeChar)}"`
: `"${value}"`
export class StringNode extends Node {
constructor (value) {
@@ -214,14 +232,15 @@ export class TruthyProperty extends Node {
// terms = null || term+
// *null = /$/
// term = ws (and | or | not | property | truthyProperty | string) ws
// term = ws (and | or | not | property | truthyProperty | numberOrString) ws
// ws = ' '*
// *and = "(" terms ")"
// *or = "|" ws "(" terms ")"
// *not = "!" term
// *property = string ws ":" term
// *truthyProperty = string ws "?"
// *string = quotedString | rawString
// numberOrString = string
// string = quotedString | rawString
// quotedString = "\"" ( /[^"\]/ | "\\\\" | "\\\"" )+
// rawString = /[a-z0-9-_.]+/i
export const parse = invoke(() => {
@@ -263,7 +282,7 @@ export const parse = invoke(() => {
parseNot() ||
parseProperty() ||
parseTruthyProperty() ||
parseString()
parseNumberOrString()
if (child) {
parseWs()
return child
@@ -308,16 +327,27 @@ export const parse = invoke(() => {
input[i++] === ':' &&
(child = parseTerm())
) {
return new Property(name.value, child)
return new Property(name, child)
}
})
const parseNumberOrString = () => {
let str = parseQuotedString()
if (str !== undefined) {
return new StringNode(str)
}
str = parseRawString()
if (str !== undefined) {
const asNum = +str
return Number.isNaN(asNum) ? new StringNode(str) : new NumberNode(asNum)
}
}
const parseString = () => {
let value
if (
(value = parseQuotedString()) !== undefined ||
(value = parseRawString()) !== undefined
) {
return new StringNode(value)
return value
}
}
const parseQuotedString = backtrace(() => {
@@ -350,7 +380,7 @@ export const parse = invoke(() => {
const parseTruthyProperty = backtrace(() => {
let name
if ((name = parseString()) && parseWs() && input[i++] === '?') {
return new TruthyProperty(name.value)
return new TruthyProperty(name)
}
})

View File

@@ -24,6 +24,20 @@ describe('parse', () => {
it('supports an empty string', () => {
expect(parse('')).toEqual(new Null())
})
it('differentiate between numbers and numbers in strings', () => {
let node
node = parse('32')
expect(node.match(32)).toBe(true)
expect(node.match('32')).toBe(false)
expect(node.toString()).toBe('32')
node = parse('"32"')
expect(node.match(32)).toBe(false)
expect(node.match('32')).toBe(true)
expect(node.toString()).toBe('"32"')
})
})
describe('setPropertyClause', () => {

View File

@@ -1,6 +1,6 @@
{
"name": "xen-api",
"version": "0.16.1",
"version": "0.16.3",
"license": "ISC",
"description": "Connector to the Xen API",
"keywords": [

View File

@@ -13,7 +13,6 @@ import {
isInteger,
isObject,
map,
mapValues,
noop,
omit,
reduce,
@@ -153,7 +152,17 @@ const prepareParam = param => {
return param
}
return (isArray(param) ? map : mapValues)(param, prepareParam)
if (isArray(param)) {
return map(param, prepareParam)
}
const values = {}
forEach(param, (value, key) => {
if (value !== undefined) {
values[key] = prepareParam(value)
}
})
return values
}
// -------------------------------------------------------------------
@@ -226,6 +235,8 @@ export class Xapi extends EventEmitter {
// Memoize this function _addObject().
this._getPool = () => this._pool
this._nTasks = 0
const objects = this._objects = new Collection()
objects.getKey = getKey
@@ -761,7 +772,22 @@ export class Xapi extends EventEmitter {
if (type === 'pool') {
this._pool = object
const eventWatchers = this._eventWatchers
if (eventWatchers !== undefined) {
forEach(object.other_config, (_, key) => {
const eventWatcher = eventWatchers[key]
if (eventWatcher !== undefined) {
delete eventWatchers[key]
eventWatcher(object)
}
})
}
} else if (type === 'task') {
if (prev === undefined) {
++this._nTasks
}
const taskWatchers = this._taskWatchers
const taskWatcher = taskWatchers[ref]
if (
@@ -771,16 +797,18 @@ export class Xapi extends EventEmitter {
delete taskWatchers[ref]
}
}
return object
}
_removeObject (ref) {
_removeObject (type, ref) {
const byRefs = this._objectsByRefs
const object = byRefs[ref]
if (object !== undefined) {
this._objects.unset(object.$id)
delete byRefs[ref]
if (type === 'task') {
--this._nTasks
}
}
const taskWatchers = this._taskWatchers
@@ -792,26 +820,12 @@ export class Xapi extends EventEmitter {
}
_processEvents (events) {
const eventWatchers = this._eventWatchers
forEach(events, event => {
let object
const { ref } = event
const { class: type, ref } = event
if (event.operation === 'del') {
this._removeObject(ref)
this._removeObject(type, ref)
} else {
const type = event.class
object = this._addObject(type, ref, event.snapshot)
if (eventWatchers !== undefined && type === 'pool') {
forEach(object.other_config, (_, key) => {
const eventWatcher = eventWatchers[key]
if (eventWatcher !== undefined) {
delete eventWatchers[key]
eventWatcher(object)
}
})
}
this._addObject(type, ref, event.snapshot)
}
})
}
@@ -823,10 +837,24 @@ export class Xapi extends EventEmitter {
60 + 0.1, // Force float.
]).then(onSuccess, onFailure)
const onSuccess = ({token, events}) => {
const onSuccess = ({ events, token, valid_ref_counts: { task } }) => {
this._fromToken = token
this._processEvents(events)
if (task !== this._nTasks) {
forEach(this.objects.all, object => {
if (object.$type === 'task') {
this._removeObject('task', object.$ref)
}
})
this._sessionCall('task.get_all_records').then(tasks => {
forEach(tasks, (task, ref) => {
this._addObject('task', ref, task)
})
}).catch(noop)
}
const debounce = this._debounce
return debounce != null
? pDelay(debounce).then(loop)