Skip to content

Commit 6c1dc82

Browse files
committed
🚩 Add strict flag
This change adds a `strict` flag to control whether we have the stricter type checking introduced in #40 Strict mode will be off by default (to maintain compatibility with old `json0` versions). In order to add this flag, we also add a new `options` object to the `type`. Strict mode is enabled on the type by setting the flag: ```js type.options.strict = true ``` Note that `text0` will share the same options as `json0` (ie enabling strict mode for `json0` also enables it for `text0`). In this change we also tidy up some unused utility functions from a previous commit.
1 parent b89153c commit 6c1dc82

File tree

4 files changed

+54
-38
lines changed

4 files changed

+54
-38
lines changed

‎lib/json0.js‎

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,14 @@ var clone = function(o) {
4343
return JSON.parse(JSON.stringify(o));
4444
};
4545

46-
var validateListIndex = function(key) {
47-
if (typeof key !== 'number')
48-
throw new Error('List index must be a number');
49-
};
50-
51-
var validateObjectKey = function (key) {
52-
if (typeof key !== 'string')
53-
throw new Error('Object key must be a number');
54-
};
55-
5646
/**
5747
* JSON OT Type
5848
* @type {*}
5949
*/
6050
var json = {
6151
name: 'json0',
62-
uri: 'http://sharejs.org/types/JSONv0'
52+
uri: 'http://sharejs.org/types/JSONv0',
53+
options: require('./options')
6354
};
6455

6556
// You can register another OT type as a subtype in a JSON document using
@@ -172,10 +163,10 @@ json.apply = function(snapshot, op) {
172163
elem = elem[key];
173164
key = p;
174165

175-
if (isArray(elem) && typeof key !== 'number')
166+
if (json.options.strict && isArray(elem) && typeof key !== 'number')
176167
throw new Error('List index must be a number');
177168

178-
if (isObject(elem) && typeof key !== 'string')
169+
if (json.options.strict && isObject(elem) && typeof key !== 'string')
179170
throw new Error('Object key must be a string');
180171

181172
if (parent == null)
@@ -191,7 +182,7 @@ json.apply = function(snapshot, op) {
191182
if (typeof elem[key] != 'number')
192183
throw new Error('Referenced element not a number');
193184

194-
if (typeof c.na !== 'number')
185+
if (json.options.strict && typeof c.na !== 'number')
195186
throw new Error('Number addition is not a number');
196187

197188
elem[key] += c.na;
@@ -219,7 +210,7 @@ json.apply = function(snapshot, op) {
219210

220211
// List move
221212
else if (c.lm !== void 0) {
222-
if (typeof c.lm !== 'number')
213+
if (json.options.strict && typeof c.lm !== 'number')
223214
throw new Error('List move target index must be a number');
224215

225216
json.checkList(elem);

‎lib/options.js‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
strict: false
3+
};

‎lib/text0.js‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
var text = module.exports = {
2525
name: 'text0',
2626
uri: 'http://sharejs.org/types/textv0',
27+
options: require('./options'),
2728
create: function(initial) {
2829
if ((initial != null) && typeof initial !== 'string') {
2930
throw new Error('Initial data must be a string');
@@ -61,7 +62,7 @@ text.apply = function(snapshot, op) {
6162
var deleted;
6263

6364
var type = typeof snapshot;
64-
if (type !== 'string')
65+
if (text.options.strict && type !== 'string')
6566
throw new Error('text0 operations cannot be applied to type: ' + type);
6667

6768
checkValidOp(op);

‎test/json0.coffee‎

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,18 @@ genTests = (type) ->
6464
c_s = type.apply leftHas, right_
6565
assert.deepEqual s_c, c_s
6666

67-
it 'throws when adding a string to a number', ->
68-
assert.throws -> type.apply 1, [{p: [], na: 'a'}]
67+
describe 'strict', ->
68+
beforeEach ->
69+
type.options.strict = true
6970

70-
it 'throws when adding a number to a string', ->
71-
assert.throws -> type.apply 'a', [{p: [], na: 1}]
71+
afterEach ->
72+
type.options.strict = false
73+
74+
it 'throws when adding a string to a number', ->
75+
assert.throws -> type.apply 1, [{p: [], na: 'a'}]
76+
77+
it 'throws when adding a number to a string', ->
78+
assert.throws -> type.apply 'a', [{p: [], na: 1}]
7279

7380
# Strings should be handled internally by the text type. We'll just do some basic sanity checks here.
7481
describe 'string', ->
@@ -138,23 +145,30 @@ genTests = (type) ->
138145
assert.deepEqual ['a', 'b', 'c'], type.apply ['b', 'a', 'c'], [{p:[1], lm:0}]
139146
assert.deepEqual ['a', 'b', 'c'], type.apply ['b', 'a', 'c'], [{p:[0], lm:1}]
140147

141-
it 'throws when keying a list replacement with a string', ->
142-
assert.throws -> type.apply ['a', 'b', 'c'], [{p: ['0'], li: 'x', ld: 'a'}]
148+
describe 'strict', ->
149+
beforeEach ->
150+
type.options.strict = true
151+
152+
afterEach ->
153+
type.options.strict = false
143154

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

147-
it 'throws when keying a list deletion with a string', ->
148-
assert.throws -> type.apply ['a', 'b', 'c'], [{p: ['0'], ld: 'a'}]
158+
it 'throws when keying a list insertion with a string', ->
159+
assert.throws -> type.apply ['a', 'b', 'c'], [{p: ['0'], li: 'x'}]
149160

150-
it 'throws when keying a list move with a string', ->
151-
assert.throws -> type.apply ['a', 'b', 'c'], [{p: ['0'], lm: 0}]
161+
it 'throws when keying a list deletion with a string', ->
162+
assert.throws -> type.apply ['a', 'b', 'c'], [{p: ['0'], ld: 'a'}]
152163

153-
it 'throws when specifying a string as a list move target', ->
154-
assert.throws -> type.apply ['a', 'b', 'c'], [{p: [1], lm: '0'}]
164+
it 'throws when keying a list move with a string', ->
165+
assert.throws -> type.apply ['a', 'b', 'c'], [{p: ['0'], lm: 0}]
155166

156-
it 'throws when an array index part-way through the path is a string', ->
157-
assert.throws -> type.apply {arr:[{x:'a'}]}, [{p:['arr', '0', 'x'], od: 'a'}]
167+
it 'throws when specifying a string as a list move target', ->
168+
assert.throws -> type.apply ['a', 'b', 'c'], [{p: [1], lm: '0'}]
169+
170+
it 'throws when an array index part-way through the path is a string', ->
171+
assert.throws -> type.apply {arr:[{x:'a'}]}, [{p:['arr', '0', 'x'], od: 'a'}]
158172

159173
###
160174
'null moves compose to nops', ->
@@ -418,14 +432,21 @@ genTests = (type) ->
418432
assert.deepEqual [], type.transform [{p:['k'], od:'x'}], [{p:['k'], od:'x'}], 'left'
419433
assert.deepEqual [], type.transform [{p:['k'], od:'x'}], [{p:['k'], od:'x'}], 'right'
420434

421-
it 'throws when the insertion key is a number', ->
422-
assert.throws -> type.apply {'1':'a'}, [{p:[2], oi: 'a'}]
435+
describe 'strict', ->
436+
beforeEach ->
437+
type.options.strict = true
438+
439+
afterEach ->
440+
type.options.strict = false
441+
442+
it 'throws when the insertion key is a number', ->
443+
assert.throws -> type.apply {'1':'a'}, [{p:[2], oi: 'a'}]
423444

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

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

430451
describe 'randomizer', ->
431452
@timeout 20000

0 commit comments

Comments
 (0)