diff --git a/declarations/Structs.js b/declarations/Structs.js index 7044e20d..e65c7207 100644 --- a/declarations/Structs.js +++ b/declarations/Structs.js @@ -1,7 +1,7 @@ /* @flow */ type UserId = string -type Id = [UserId, number] +type Id = [UserId, number|string] /* type Struct = { @@ -11,6 +11,7 @@ type Struct = { target?: Id, struct: 'Insert' | 'Delete' }*/ + type Struct = Insertion | Deletion type Operation = Struct @@ -31,6 +32,19 @@ type Deletion = { struct: 'Delete' } +type MapStruct = { + id: Id, + type: TypeNames, + map: any +} + +type ListStruct = { + id: Id, + type: TypeNames, + start: Id, + end: Id +} + type MessageSyncStep1 = { type: 'sync step 1', diff --git a/declarations/Y.js b/declarations/Y.js index 6c730a76..9a91a83d 100644 --- a/declarations/Y.js +++ b/declarations/Y.js @@ -14,6 +14,8 @@ type YConfig = { root: Object } +type TypeName = 'array' | 'map' | 'text' + declare var YConcurrency_TestingMode : boolean type Transaction = Generator diff --git a/dist b/dist index b471c91d..434432a7 160000 --- a/dist +++ b/dist @@ -1 +1 @@ -Subproject commit b471c91d1d70b1d9e31ba81664d8fab4aff414a2 +Subproject commit 434432a742088e4f53aee0230353c18b5e621211 diff --git a/gulpfile.helper.js b/gulpfile.helper.js index aafa6980..f4f15243 100644 --- a/gulpfile.helper.js +++ b/gulpfile.helper.js @@ -31,7 +31,9 @@ module.exports = function (gulp, helperOptions) { } if (options.includeRuntime) { - files.dist = ['node_modules/regenerator/runtime.js', files.dist] + files.distEs5 = ['node_modules/regenerator/runtime.js', files.dist] + } else { + files.distEs5 = [files.dist] } gulp.task('dist:es5', function () { @@ -39,14 +41,14 @@ module.exports = function (gulp, helperOptions) { presets: ['es2015'] } return (browserify({ - entries: files.dist, + entries: files.distEs5, debug: true }).transform('babelify', babelOptions) .bundle() .pipe(source(options.targetName)) .pipe(buffer()) .pipe($.sourcemaps.init({loadMaps: true})) - .pipe($.uglify()) + .pipe($.if(!options.debug, $.uglify())) .pipe($.sourcemaps.write('.')) .pipe(gulp.dest('./dist/'))) }) diff --git a/gulpfile.js b/gulpfile.js index da21661d..7ea185a7 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -59,9 +59,9 @@ require('./gulpfile.helper.js')(gulp, { ] }) -gulp.task('dev:examples', ['updateSubmodule', 'watch:dist'], function () { +gulp.task('dev:examples', ['watch:dist'], function () { // watch all distfiles and copy them to bower_components - var distfiles = ['./dist/*.js', './dist/*.js.map', '../y-*/dist/*.js', '../y-*/dist/*.js.map'] + var distfiles = ['./dist/*.{js,es6}', './dist/*.{js,es6}.map', '../y-*/dist/*.{js,es6}', '../y-*/dist/*.{js,es6}.map'] gulp.src(distfiles) .pipe($.watch(distfiles)) .pipe($.rename(function (path) { diff --git a/src/Database.js b/src/Database.js index c1441769..57aa3884 100644 --- a/src/Database.js +++ b/src/Database.js @@ -186,8 +186,8 @@ module.exports = function (Y /* :any */) { } } getNextOpId () { - if (this._temporaryUserIdGenerator != null) { - return this._temporaryUserIdGenerator() + if (this._nextUserId != null) { + return this._nextUserId } else if (this.userId == null) { throw new Error('OperationStore not yet initialized!') } else { @@ -390,7 +390,7 @@ module.exports = function (Y /* :any */) { } } requestTransaction (makeGen/* :any */, callImmediately) { - if (callImmediately) { + if (true || callImmediately) { // TODO: decide whether this is ok or not.. this.waitingTransactions.push(makeGen) if (!this.transactionInProgress) { this.transactionInProgress = true diff --git a/src/SpecHelper.js b/src/SpecHelper.js index da92a2c3..a1c70a0c 100644 --- a/src/SpecHelper.js +++ b/src/SpecHelper.js @@ -85,7 +85,7 @@ function * applyTransactions (relAmount, numberOfTransactions, objects, users, t var r = Math.random() if (r >= 0.5) { // 50% chance to flush - Y.utils.globalRoom.flushOne() // flushes for some user.. (not necessarily 0) + yield Y.utils.globalRoom.flushOne() // flushes for some user.. (not necessarily 0) } else if (r >= 0.05) { // 45% chance to create operation randomTransaction(getRandom(objects)) @@ -245,6 +245,9 @@ g.createUsers = async(function * createUsers (self, numberOfUsers, database) { connector: { name: 'Test', debug: false + }, + share: { + root: 'Map' } })) } diff --git a/src/Transaction.js b/src/Transaction.js index fdec1074..e78339b0 100644 --- a/src/Transaction.js +++ b/src/Transaction.js @@ -91,7 +91,7 @@ module.exports = function (Y/* :any */) { var sid = JSON.stringify(id) var t = this.store.initializedTypes[sid] if (t == null) { - var op = yield* this.getOperation(id) + var op/* :MapStruct | ListStruct */ = yield* this.getOperation(id) if (op != null) { t = yield* Y[op.type].initType.call(this, this.store, op) this.store.initializedTypes[sid] = t @@ -398,7 +398,7 @@ module.exports = function (Y/* :any */) { if (o.parent != null) { // remove gc'd op from parent, if it exists - var parent = yield* this.getOperation(o.parent) + var parent /* MapOperation */ = yield* this.getOperation(o.parent) var setParent = false // whether to save parent to the os if (o.parentSub != null) { if (Y.utils.compareIds(parent.map[o.parentSub], o.id)) { @@ -558,8 +558,23 @@ module.exports = function (Y/* :any */) { }) } } - * getOperation (id) { - return yield* this.os.find(id) + * getOperation (id/* :any */)/* :Transaction */ { + var o = yield* this.os.find(id) + if (o != null || id[0] != '_') { + return o + } else { + // need to generate this operation + if (this.store._nextUserId == null) { + var typename= id[1].split('_')[0] + this.store._nextUserId = id + yield* Y[typename].createType.call(this) + delete this.store._nextUserId + return yield* this.os.find(id) + } else { + // Can only generate one operation at a time + return null + } + } } * removeOperation (id) { yield* this.os.delete(id) diff --git a/src/Types/Map.spec.js b/src/Types/Map.spec.js index e07d50ad..4a8b73f0 100644 --- a/src/Types/Map.spec.js +++ b/src/Types/Map.spec.js @@ -3,7 +3,7 @@ 'use strict' var Y = require('../SpecHelper.js') -var numberOfYMapTests = 500 +var numberOfYMapTests = 50 var repeatMapTeasts = 1 for (let database of databases) { @@ -12,10 +12,10 @@ for (let database of databases) { beforeEach(async(function * (done) { yield createUsers(this, 5, database) - y1 = this.users[0].root - y2 = this.users[1].root - y3 = this.users[2].root - y4 = this.users[3].root + y1 = this.users[0].share.root + y2 = this.users[1].share.root + y3 = this.users[2].share.root + y4 = this.users[3].share.root flushAll = Y.utils.globalRoom.flushAll done() })) @@ -30,7 +30,7 @@ for (let database of databases) { expect(y1.get('stuff')).toEqual('stuffy') yield flushAll() for (var key in this.users) { - var u = this.users[key].root + var u = this.users[key].share.root expect(u.get('stuff')).toEqual('stuffy') } done() @@ -56,7 +56,7 @@ for (let database of databases) { yield flushAll() for (var key in this.users) { - var r = this.users[key].root + var r = this.users[key].share.root expect(r.get('stuff')).toEqual('stuffy') } done() @@ -69,7 +69,7 @@ for (let database of databases) { yield flushAll() for (var key in this.users) { var u = this.users[key] - expect(u.root.get('stuff')).toEqual('c0') + expect(u.share.root.get('stuff')).toEqual('c0') } done() })) @@ -82,7 +82,7 @@ for (let database of databases) { for (var key in this.users) { var u = this.users[key] - expect(u.root.get('stuff')).toBeUndefined() + expect(u.share.root.get('stuff')).toBeUndefined() } done() })) @@ -96,7 +96,7 @@ for (let database of databases) { for (var key in this.users) { var u = this.users[key] - expect(u.root.get('stuff')).toEqual('c0') + expect(u.share.root.get('stuff')).toEqual('c0') } done() })) @@ -116,7 +116,7 @@ for (let database of databases) { for (var key in this.users) { var u = this.users[key] - expect(u.root.get('stuff')).toBeUndefined() + expect(u.share.root.get('stuff')).toBeUndefined() } done() })) @@ -199,7 +199,7 @@ for (let database of databases) { var promises = [] for (var u = 0; u < this.users.length; u++) { - promises.push(this.users[u].root.get('Map')) + promises.push(this.users[u].share.root.get('Map')) } this.maps = yield Promise.all(promises) done() diff --git a/src/y.js b/src/y.js index 1d3db613..5f9cb162 100644 --- a/src/y.js +++ b/src/y.js @@ -22,6 +22,10 @@ Y.extend = function (name, value) { Y.requestModules = requestModules function requestModules (modules) { + // determine if this module was compiled for es5 or es6 (y.js vs. y.es6) + // if Insert.execute is a Function, then it isnt a generator.. + // then load the es5(.js) files.. + var extention = Y.Struct.Insert.execute.constructor === Function ? '.js' : '.es6' var promises = [] for (var i = 0; i < modules.length; i++) { var modulename = 'y-' + modules[i].toLowerCase() @@ -33,7 +37,7 @@ function requestModules (modules) { // module does not exist if (typeof window !== 'undefined') { var imported = document.createElement('script') - imported.src = Y.sourceDir + '/' + modulename + '/' + modulename + '.js' + imported.src = Y.sourceDir + '/' + modulename + '/' + modulename + extention document.head.appendChild(imported) let requireModule = {} @@ -69,26 +73,28 @@ type DbOptions = MemoryOptions | IndexedDBOptions type WebRTCOptions = { name: 'webrtc', room: string -} +} type WebsocketsClientOptions = { name: 'websockets-client', room: string } type ConnectionOptions = WebRTCOptions | WebsocketsClientOptions -type TypesOptions = Array<'array'|'map'|'text'> - type YOptions = { connector: ConnectionOptions, db: DbOptions, - types: TypesOptions, - sourceDir: string + types: Array, + sourceDir: string, + share: {[key: string]: TypeName} } */ function Y (opts/* :YOptions */) /* :Promise */ { opts.types = opts.types != null ? opts.types : [] var modules = [opts.db.name, opts.connector.name].concat(opts.types) + for (var name in opts.share) { + modules.push(opts.share[name]) + } Y.sourceDir = opts.sourceDir return Y.requestModules(modules).then(function () { return new Promise(function (resolve) { @@ -105,19 +111,18 @@ class YConfig { /* :: db: Y.AbstractDatabase; connector: Y.AbstractConnector; + share: {[key: string]: any}; */ constructor (opts, callback) { this.db = new Y[opts.db.name](this, opts.db) this.connector = new Y[opts.connector.name](this, opts.connector) + var share = {} + this.share = share this.db.requestTransaction(function * requestTransaction () { - // create initial Map type - this.store._temporaryUserIdGenerator = function () { - return ['_', 0] + // create shared object + for (var propertyname in opts.share) { + share[propertyname] = yield* this.getType(['_', opts.share[propertyname] + '_' + propertyname]) } - var typeid = yield* Y.Map.createType.call(this) - var type = yield* this.getType(typeid) - this.store.y.root = type - this.store._temporaryUserIdGenerator = null setTimeout(callback, 0) }) }