Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions packages/utils.parser/spec/parserBehaviors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,83 @@ describe('the bindings parser', function () {
assert.equal(bindings.attr().kv, 'Sam')
})

describe('shorthand (ES6) object properties', function () {
it('parses a shorthand property immediately followed by }', function () {
const bindings = new Parser().parse('x:{a}', ctxStub({ a: 1 }))
assert.deepEqual(Object.keys(bindings.x()), ['a'])
assert.equal(bindings.x().a, 1)
})

it('parses multiple shorthand properties with no trailing comma', function () {
const bindings = new Parser().parse('x:{a,b,c}', ctxStub({ a: 1, b: 2, c: 3 }))
assert.deepEqual(Object.keys(bindings.x()), ['a', 'b', 'c'])
})

it('parses a shorthand property mixed with explicit key:value pairs', function () {
const bindings = new Parser().parse('x:{a:1,b}', ctxStub({ b: 2 }))
assert.deepEqual(Object.keys(bindings.x()), ['a', 'b'])
assert.equal(bindings.x().b, 2)
})

it('still parses a trailing comma after a shorthand property (regression guard)', function () {
const bindings = new Parser().parse('x:{a,}', ctxStub({ a: 1 }))
assert.deepEqual(Object.keys(bindings.x()), ['a'])
})

it('parses a shorthand-object literal as a bare function-call argument', function () {
const foo = (o: any) => o.a
const bindings = new Parser().parse('x: foo({a})', ctxStub({ foo, a: 1 }))
assert.equal(bindings.x(), 1)
})

it('parses a shorthand-object literal as a bare array element', function () {
const bindings = new Parser().parse('x: [{a}]', ctxStub({ a: 1 }))
assert.deepEqual(Object.keys(bindings.x()[0]), ['a'])
})
})

describe('quoted binding names containing terminator characters', function () {
// name() must not stop at ':', whitespace, ',', '|', or '}' while inside
// a quoted (enclosedBy) name -- those characters only terminate an
// unquoted name; a quote should keep scanning through to its closing quote.
it('parses a double-quoted name containing }', function () {
const bindings = new Parser().parse('"a}b": 1')
assert.deepEqual(Object.keys(bindings), ['a}b'])
assert.equal(bindings['a}b'](), 1)
})

it('parses a single-quoted name containing }', function () {
const bindings = new Parser().parse("'a}b': 1")
assert.deepEqual(Object.keys(bindings), ['a}b'])
assert.equal(bindings['a}b'](), 1)
})

it('parses a quoted name containing a space', function () {
const bindings = new Parser().parse('"a b": 1')
assert.deepEqual(Object.keys(bindings), ['a b'])
assert.equal(bindings['a b'](), 1)
})

it('parses a quoted name containing a comma', function () {
const bindings = new Parser().parse('"a,b": 1, c: 2')
assert.deepEqual(Object.keys(bindings), ['a,b', 'c'])
assert.equal(bindings['a,b'](), 1)
assert.equal(bindings.c(), 2)
})

it('parses a quoted name containing a pipe', function () {
const bindings = new Parser().parse('"a|b": 1')
assert.deepEqual(Object.keys(bindings), ['a|b'])
assert.equal(bindings['a|b'](), 1)
})

it('parses a quoted name containing a colon', function () {
const bindings = new Parser().parse('"a:b": 1')
assert.deepEqual(Object.keys(bindings), ['a:b'])
assert.equal(bindings['a:b'](), 1)
})
})

it('parses object: attr: {name: observable(value)}', function () {
const binding = 'attr : { klass: kValue }',
context = ctxStub({ kValue: observable('Gollum') }),
Expand Down
2 changes: 1 addition & 1 deletion packages/utils.parser/src/Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export default class Parser {
this.error('Object name: ' + name + ' missing closing ' + enclosedBy)
}
return name
} else if (ch === ':' || ch <= ' ' || ch === ',' || ch === '|') {
} else if (!enclosedBy && (ch === ':' || ch <= ' ' || ch === ',' || ch === '|' || ch === '}')) {
return name
}
name += ch
Expand Down