Skip to content

Commit

Permalink
Merge pull request #40 from reedsy/stricter-types
Browse files Browse the repository at this point in the history
🥅 Stricter types in `apply()`
  • Loading branch information
nornagon authored Jul 7, 2021
2 parents 9df44f0 + 237f6a9 commit afa00e0
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
22 changes: 22 additions & 0 deletions lib/json0.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ var clone = function(o) {
return JSON.parse(JSON.stringify(o));
};

var validateListIndex = function(key) {
if (typeof key !== 'number')
throw new Error('List index must be a number');
};

var validateObjectKey = function (key) {
if (typeof key !== 'string')
throw new Error('Object key must be a number');
};

/**
* JSON OT Type
* @type {*}
Expand Down Expand Up @@ -162,6 +172,12 @@ json.apply = function(snapshot, op) {
elem = elem[key];
key = p;

if (isArray(elem) && typeof key !== 'number')
throw new Error('List index must be a number');

if (isObject(elem) && typeof key !== 'string')
throw new Error('Object key must be a string');

if (parent == null)
throw new Error('Path invalid');
}
Expand All @@ -175,6 +191,9 @@ json.apply = function(snapshot, op) {
if (typeof elem[key] != 'number')
throw new Error('Referenced element not a number');

if (typeof c.na !== 'number')
throw new Error('Number addition is not a number');

elem[key] += c.na;
}

Expand All @@ -200,6 +219,9 @@ json.apply = function(snapshot, op) {

// List move
else if (c.lm !== void 0) {
if (typeof c.lm !== 'number')
throw new Error('List move target index must be a number');

json.checkList(elem);
if (c.lm != key) {
var e = elem[key];
Expand Down
4 changes: 4 additions & 0 deletions lib/text0.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ var checkValidOp = function(op) {
text.apply = function(snapshot, op) {
var deleted;

var type = typeof snapshot;
if (type !== 'string')
throw new Error('text0 operations cannot be applied to type: ' + type);

checkValidOp(op);
for (var i = 0; i < op.length; i++) {
var component = op[i];
Expand Down
38 changes: 38 additions & 0 deletions test/json0.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ genTests = (type) ->
c_s = type.apply leftHas, right_
assert.deepEqual s_c, c_s

it 'throws when adding a string to a number', ->
assert.throws -> type.apply 1, [{p: [], na: 'a'}]

it 'throws when adding a number to a string', ->
assert.throws -> type.apply 'a', [{p: [], na: 1}]

# Strings should be handled internally by the text type. We'll just do some basic sanity checks here.
describe 'string', ->
Expand All @@ -72,6 +77,12 @@ genTests = (type) ->
assert.deepEqual 'bc', type.apply 'abc', [{p:[0], sd:'a'}]
assert.deepEqual {x:'abc'}, type.apply {x:'a'}, [{p:['x', 1], si:'bc'}]

it 'throws when the target is not a string', ->
assert.throws -> type.apply [1], [{p: [0], si: 'a'}]

it 'throws when the inserted content is not a string', ->
assert.throws -> type.apply 'a', [{p: [0], si: 1}]

describe '#transform()', ->
it 'splits deletes', ->
assert.deepEqual type.transform([{p:[0], sd:'ab'}], [{p:[1], si:'x'}], 'left'), [{p:[0], sd:'a'}, {p:[1], sd:'b'}]
Expand Down Expand Up @@ -127,6 +138,24 @@ genTests = (type) ->
assert.deepEqual ['a', 'b', 'c'], type.apply ['b', 'a', 'c'], [{p:[1], lm:0}]
assert.deepEqual ['a', 'b', 'c'], type.apply ['b', 'a', 'c'], [{p:[0], lm:1}]

it 'throws when keying a list replacement with a string', ->
assert.throws -> type.apply ['a', 'b', 'c'], [{p: ['0'], li: 'x', ld: 'a'}]

it 'throws when keying a list insertion with a string', ->
assert.throws -> type.apply ['a', 'b', 'c'], [{p: ['0'], li: 'x'}]

it 'throws when keying a list deletion with a string', ->
assert.throws -> type.apply ['a', 'b', 'c'], [{p: ['0'], ld: 'a'}]

it 'throws when keying a list move with a string', ->
assert.throws -> type.apply ['a', 'b', 'c'], [{p: ['0'], lm: 0}]

it 'throws when specifying a string as a list move target', ->
assert.throws -> type.apply ['a', 'b', 'c'], [{p: [1], lm: '0'}]

it 'throws when an array index part-way through the path is a string', ->
assert.throws -> type.apply {arr:[{x:'a'}]}, [{p:['arr', '0', 'x'], od: 'a'}]

###
'null moves compose to nops', ->
assert.deepEqual [], type.compose [], [{p:[3],lm:3}]
Expand Down Expand Up @@ -389,6 +418,15 @@ genTests = (type) ->
assert.deepEqual [], type.transform [{p:['k'], od:'x'}], [{p:['k'], od:'x'}], 'left'
assert.deepEqual [], type.transform [{p:['k'], od:'x'}], [{p:['k'], od:'x'}], 'right'

it 'throws when the insertion key is a number', ->
assert.throws -> type.apply {'1':'a'}, [{p:[2], oi: 'a'}]

it 'throws when the deletion key is a number', ->
assert.throws -> type.apply {'1':'a'}, [{p:[1], od: 'a'}]

it 'throws when an object key part-way through the path is a number', ->
assert.throws -> type.apply {'1': {x: 'a'}}, [{p:[1, 'x'], od: 'a'}]

describe 'randomizer', ->
@timeout 20000
@slow 6000
Expand Down

0 comments on commit afa00e0

Please sign in to comment.