implemented module loader for yjs
This commit is contained in:
parent
138afe39dc
commit
6dc347642b
@ -21,31 +21,10 @@ module.exports = function (gulp, helperOptions) {
|
||||
options.regenerator = false
|
||||
// TODO: include './node_modules/gulp-babel/node_modules/babel-core/node_modules/regenerator/runtime.js'
|
||||
}
|
||||
var concatOrder = [
|
||||
'y.js',
|
||||
'Connector.js',
|
||||
'Database.js',
|
||||
'Transaction.js',
|
||||
'Struct.js',
|
||||
'Utils.js',
|
||||
'Databases/RedBlackTree.js',
|
||||
'Databases/Memory.js',
|
||||
'Databases/IndexedDB.js',
|
||||
'Connectors/Test.js',
|
||||
'Types/Array.js',
|
||||
'Types/Map.js',
|
||||
'Types/TextBind.js'
|
||||
]
|
||||
var yjsfiles = concatOrder.map(function (f) {
|
||||
return '../yjs/src/' + f
|
||||
})
|
||||
var files = {
|
||||
dist: helperOptions.polyfills.concat(helperOptions.files.map(function (f) {
|
||||
return 'src/' + f
|
||||
})),
|
||||
test: ['../yjs/src/Helper.spec.js'].concat(yjsfiles).concat(helperOptions.files.map(function (f) {
|
||||
return 'src/' + f
|
||||
}).concat(['src/' + options.testfiles]))
|
||||
dist: helperOptions.entry,
|
||||
specs: helperOptions.specs,
|
||||
src: './src/**/*.js'
|
||||
}
|
||||
|
||||
var babelOptions = {
|
||||
@ -54,38 +33,10 @@ module.exports = function (gulp, helperOptions) {
|
||||
experimental: true
|
||||
}
|
||||
if (options.regenerator) {
|
||||
files.test = helperOptions.polyfills.concat(files.test)
|
||||
files.specs = helperOptions.polyfills.concat(files.specs)
|
||||
} else {
|
||||
babelOptions.blacklist = 'regenerator'
|
||||
}
|
||||
// babelOptions.blacklist = 'regenerator'
|
||||
|
||||
gulp.task('dist', ['build:dist'], function () {
|
||||
function createDist (pipe) {
|
||||
return pipe
|
||||
.pipe($.if(options.debug, $.sourcemaps.init({loadMaps: true})))
|
||||
.pipe($.concat(options.targetName))
|
||||
.pipe($.if(!options.debug && options.regenerator, $.uglify()))
|
||||
.pipe($.if(options.debug, $.sourcemaps.write('.')))
|
||||
.pipe(gulp.dest('./dist/'))
|
||||
}
|
||||
var pipe
|
||||
if (options.browserify || true) {
|
||||
var browserify = require('browserify')
|
||||
var source = require('vinyl-source-stream')
|
||||
var buffer = require('vinyl-buffer')
|
||||
|
||||
pipe = browserify({
|
||||
entries: 'build/' + options.targetName,
|
||||
debug: options.debug
|
||||
}).bundle()
|
||||
.pipe(source(options.targetName))
|
||||
.pipe(buffer())
|
||||
} else {
|
||||
pipe = gulp.src('build/' + options.targetName)
|
||||
}
|
||||
return createDist(pipe)
|
||||
})
|
||||
|
||||
gulp.task('dist', function () {
|
||||
var browserify = require('browserify')
|
||||
@ -99,7 +50,7 @@ module.exports = function (gulp, helperOptions) {
|
||||
.pipe(source(options.targetName))
|
||||
.pipe(buffer())
|
||||
.pipe($.if(options.debug, $.sourcemaps.init({loadMaps: true})))
|
||||
.pipe($.concat(options.targetName))
|
||||
.pipe($.if(!options.debug && options.regenerator, $.babel(babelOptions)))
|
||||
.pipe($.if(!options.debug && options.regenerator, $.uglify()))
|
||||
.pipe($.if(options.debug, $.sourcemaps.write('.')))
|
||||
.pipe(gulp.dest('./dist/'))
|
||||
@ -108,11 +59,46 @@ module.exports = function (gulp, helperOptions) {
|
||||
gulp.task('watch:dist', function (cb) {
|
||||
options.debug = true
|
||||
runSequence('dist', function () {
|
||||
gulp.watch(files.dist, ['dist'])
|
||||
gulp.watch(files.src, ['dist'])
|
||||
cb()
|
||||
})
|
||||
})
|
||||
|
||||
gulp.task('dev:node', ['test'], function () {
|
||||
gulp.watch(files.src, ['test'])
|
||||
})
|
||||
|
||||
gulp.task('spec-build', function () {
|
||||
var browserify = require('browserify')
|
||||
var source = require('vinyl-source-stream')
|
||||
var buffer = require('vinyl-buffer')
|
||||
|
||||
return browserify({
|
||||
entries: files.specs,
|
||||
debug: options.debug
|
||||
}).bundle()
|
||||
.pipe(source('specs.js'))
|
||||
.pipe(buffer())
|
||||
.pipe($.sourcemaps.init({loadMaps: true}))
|
||||
.pipe($.sourcemaps.write())
|
||||
.pipe(gulp.dest('./build/'))
|
||||
})
|
||||
|
||||
gulp.task('dev:browser', ['spec-build'], function () {
|
||||
gulp.watch(files.src, ['spec-build'])
|
||||
return gulp.src('./build/specs.js')
|
||||
.pipe($.jasmineBrowser.specRunner())
|
||||
.pipe($.jasmineBrowser.server({port: options.testport}))
|
||||
})
|
||||
|
||||
gulp.task('test', function () {
|
||||
return gulp.src(files.specs)
|
||||
.pipe($.jasmine({
|
||||
verbose: true,
|
||||
includeStuckTrace: true
|
||||
}))
|
||||
})
|
||||
|
||||
gulp.task('updateSubmodule', function () {
|
||||
return gulp.src('./package.json', {read: false})
|
||||
.pipe($.shell([
|
||||
@ -168,24 +154,4 @@ module.exports = function (gulp, helperOptions) {
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
gulp.task('dev:node', ['test'], function () {
|
||||
gulp.watch(files.dist, ['test'])
|
||||
})
|
||||
|
||||
gulp.task('dev:browser', ['watch:build'], function () {
|
||||
return gulp.src(files.test)
|
||||
.pipe($.watch(['build/**/*']))
|
||||
.pipe($.jasmineBrowser.specRunner())
|
||||
.pipe($.jasmineBrowser.server({port: options.testport}))
|
||||
})
|
||||
|
||||
gulp.task('test', function () {
|
||||
console.log(files.test)
|
||||
return gulp.src('./dist/y.js')
|
||||
.pipe($.jasmine({
|
||||
verbose: true,
|
||||
includeStuckTrace: true
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
24
gulpfile.js
24
gulpfile.js
@ -49,23 +49,15 @@ var runSequence = require('run-sequence').use(gulp)
|
||||
|
||||
require('./gulpfile.helper.js')(gulp, {
|
||||
polyfills: [],
|
||||
files: [
|
||||
'y.js',
|
||||
'Connector.js',
|
||||
'Database.js',
|
||||
'Transaction.js',
|
||||
'Struct.js',
|
||||
'Utils.js',
|
||||
'Databases/RedBlackTree.js',
|
||||
'Databases/Memory.js',
|
||||
'Databases/IndexedDB.js',
|
||||
'Connectors/Test.js',
|
||||
'Types/Array.js',
|
||||
'Types/Map.js',
|
||||
'Types/TextBind.js'
|
||||
],
|
||||
entry: './src/y.js',
|
||||
targetName: 'y.js',
|
||||
moduleName: 'yjs'
|
||||
moduleName: 'yjs',
|
||||
specs: [
|
||||
'./src/Databases/RedBlackTree.spec.js',
|
||||
'./src/Types/Array.spec.js',
|
||||
'./src/Types/Map.spec.js',
|
||||
'./src/Database.spec.js'
|
||||
]
|
||||
})
|
||||
|
||||
gulp.task('dev:examples', ['updateSubmodule', 'watch:dist'], function () {
|
||||
|
@ -68,6 +68,7 @@
|
||||
"run-sequence": "^1.1.4",
|
||||
"standard": "^5.2.2",
|
||||
"vinyl-buffer": "^1.0.0",
|
||||
"vinyl-source-stream": "^1.1.0"
|
||||
"vinyl-source-stream": "^1.1.0",
|
||||
"watchify": "^3.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* globals Y */
|
||||
'use strict'
|
||||
|
||||
module.exports = function (Y) {
|
||||
class AbstractConnector {
|
||||
/*
|
||||
opts contains the following information:
|
||||
@ -326,3 +326,4 @@ class AbstractConnector {
|
||||
}
|
||||
}
|
||||
Y.AbstractConnector = AbstractConnector
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* global getRandom, Y, wait, async */
|
||||
/* global getRandom, wait, async */
|
||||
'use strict'
|
||||
|
||||
module.exports = function (Y) {
|
||||
var globalRoom = {
|
||||
users: {},
|
||||
buffers: {},
|
||||
@ -134,3 +135,4 @@ class Test extends Y.AbstractConnector {
|
||||
}
|
||||
|
||||
Y.Test = Test
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* global Y */
|
||||
'use strict'
|
||||
|
||||
module.exports = function (Y) {
|
||||
/*
|
||||
Partial definition of an OperationStore.
|
||||
TODO: name it Database, operation store only holds operations.
|
||||
@ -339,3 +339,4 @@ class AbstractDatabase {
|
||||
}
|
||||
}
|
||||
Y.AbstractDatabase = AbstractDatabase
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
/* global Y, async, databases */
|
||||
/* global async, databases */
|
||||
/* eslint-env browser,jasmine,console */
|
||||
'use strict'
|
||||
|
||||
var Y = require('./SpecHelper.js')
|
||||
|
||||
for (let database of databases) {
|
||||
describe(`Database (${database})`, function () {
|
||||
|
@ -1,8 +1,6 @@
|
||||
/* global Y */
|
||||
|
||||
'use strict'
|
||||
|
||||
Y.IndexedDB = (function () {
|
||||
module.exports = function (Y) {
|
||||
class Store {
|
||||
constructor (transaction, name) {
|
||||
this.store = transaction.objectStore(name)
|
||||
@ -177,5 +175,5 @@ Y.IndexedDB = (function () {
|
||||
yield window.indexedDB.deleteDatabase(this.namespace)
|
||||
}
|
||||
}
|
||||
return OperationStore
|
||||
})()
|
||||
Y.IndexedDB = OperationStore
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
/* global Y */
|
||||
/* eslint-env browser,jasmine */
|
||||
|
||||
if (typeof window !== 'undefined' && false) {
|
||||
describe('IndexedDB', function () {
|
||||
var ob
|
||||
beforeAll(function () {
|
||||
ob = new Y.IndexedDB(null, {namespace: 'Test', gcTimeout: -1})
|
||||
})
|
||||
|
||||
afterAll(function (done) {
|
||||
ob.requestTransaction(function *() {
|
||||
yield* ob.removeDatabase()
|
||||
ob = null
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
/* global Y */
|
||||
'use strict'
|
||||
|
||||
Y.Memory = (function () {
|
||||
module.exports = function (Y) {
|
||||
class Transaction extends Y.Transaction {
|
||||
constructor (store) {
|
||||
super(store)
|
||||
@ -59,5 +58,5 @@ Y.Memory = (function () {
|
||||
delete this.ds
|
||||
}
|
||||
}
|
||||
return Database
|
||||
})()
|
||||
Y.Memory = Database
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* global Y */
|
||||
'use strict'
|
||||
|
||||
/*
|
||||
This file contains a not so fancy implemantion of a Red Black Tree.
|
||||
*/
|
||||
|
||||
module.exports = function (Y) {
|
||||
class N {
|
||||
// A created node is always red!
|
||||
constructor (val) {
|
||||
@ -487,3 +487,4 @@ class RBTree {
|
||||
}
|
||||
|
||||
Y.utils.RBTree = RBTree
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* global Y */
|
||||
/* eslint-env browser,jasmine,console */
|
||||
'use strict'
|
||||
|
||||
var Y = require('../SpecHelper.js')
|
||||
var numberOfRBTreeTests = 1000
|
||||
|
||||
function itRedNodesDoNotHaveBlackChildren () {
|
||||
|
@ -1,288 +0,0 @@
|
||||
/* global Y */
|
||||
/* eslint-env browser, jasmine */
|
||||
|
||||
/*
|
||||
This is just a compilation of functions that help to test this library!
|
||||
*/
|
||||
|
||||
// When testing, you store everything on the global object. We call it g
|
||||
var g
|
||||
if (typeof global !== 'undefined') {
|
||||
g = global
|
||||
} else if (typeof window !== 'undefined') {
|
||||
g = window
|
||||
} else {
|
||||
throw new Error('No global object?')
|
||||
}
|
||||
g.g = g
|
||||
|
||||
g.YConcurrency_TestingMode = true
|
||||
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000
|
||||
|
||||
g.describeManyTimes = function describeManyTimes (times, name, f) {
|
||||
for (var i = 0; i < times; i++) {
|
||||
describe(name, f)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Wait for a specified amount of time (in ms). defaults to 5ms
|
||||
*/
|
||||
function wait (t) {
|
||||
if (t == null) {
|
||||
t = 5
|
||||
}
|
||||
return new Promise(function (resolve) {
|
||||
setTimeout(function () {
|
||||
resolve()
|
||||
}, t * 2)
|
||||
})
|
||||
}
|
||||
g.wait = wait
|
||||
|
||||
g.databases = ['Memory']
|
||||
if (typeof window !== 'undefined') {
|
||||
g.databases.push('IndexedDB')
|
||||
}
|
||||
|
||||
/*
|
||||
returns a random element of o.
|
||||
works on Object, and Array
|
||||
*/
|
||||
function getRandom (o) {
|
||||
if (o instanceof Array) {
|
||||
return o[Math.floor(Math.random() * o.length)]
|
||||
} else if (o.constructor === Object) {
|
||||
var ks = []
|
||||
for (var key in o) {
|
||||
ks.push(key)
|
||||
}
|
||||
return o[getRandom(ks)]
|
||||
}
|
||||
}
|
||||
g.getRandom = getRandom
|
||||
|
||||
function getRandomNumber (n) {
|
||||
if (n == null) {
|
||||
n = 9999
|
||||
}
|
||||
return Math.floor(Math.random() * n)
|
||||
}
|
||||
g.getRandomNumber = getRandomNumber
|
||||
|
||||
function * applyTransactions (relAmount, numberOfTransactions, objects, users, transactions) {
|
||||
function randomTransaction (root) {
|
||||
var f = getRandom(transactions)
|
||||
f(root)
|
||||
}
|
||||
for (var i = 0; i < numberOfTransactions * relAmount + 1; i++) {
|
||||
var r = Math.random()
|
||||
if (r >= 0.5) {
|
||||
// 50% chance to flush
|
||||
users[0].connector.flushOne() // flushes for some user.. (not necessarily 0)
|
||||
} else if (r >= 0.05) {
|
||||
// 45% chance to create operation
|
||||
randomTransaction(getRandom(objects))
|
||||
} else {
|
||||
// 5% chance to disconnect/reconnect
|
||||
var u = getRandom(users)
|
||||
if (u.connector.isDisconnected()) {
|
||||
yield u.reconnect()
|
||||
} else {
|
||||
yield u.disconnect()
|
||||
}
|
||||
}
|
||||
yield wait()
|
||||
}
|
||||
}
|
||||
|
||||
g.applyRandomTransactionsAllRejoinNoGC = async(function * applyRandomTransactions (users, objects, transactions, numberOfTransactions) {
|
||||
yield* applyTransactions(1, numberOfTransactions, objects, users, transactions)
|
||||
yield users[0].connector.flushAll()
|
||||
yield wait()
|
||||
for (var u in users) {
|
||||
yield users[u].reconnect()
|
||||
}
|
||||
yield wait(100)
|
||||
yield users[0].connector.flushAll()
|
||||
yield g.garbageCollectAllUsers(users)
|
||||
})
|
||||
|
||||
g.applyRandomTransactionsWithGC = async(function * applyRandomTransactions (users, objects, transactions, numberOfTransactions) {
|
||||
yield* applyTransactions(1, numberOfTransactions, objects, users.slice(1), transactions)
|
||||
yield users[0].connector.flushAll()
|
||||
yield g.garbageCollectAllUsers(users)
|
||||
yield wait(100)
|
||||
for (var u in users) {
|
||||
// TODO: here, we enforce that two users never sync at the same time with u[0]
|
||||
// enforce that in the connector itself!
|
||||
yield users[u].reconnect()
|
||||
}
|
||||
yield wait(100)
|
||||
yield users[0].connector.flushAll()
|
||||
yield wait(100)
|
||||
yield g.garbageCollectAllUsers(users)
|
||||
})
|
||||
|
||||
g.garbageCollectAllUsers = async(function * garbageCollectAllUsers (users) {
|
||||
// gc two times because of the two gc phases (really collect everything)
|
||||
yield wait(100)
|
||||
for (var i in users) {
|
||||
yield users[i].db.garbageCollect()
|
||||
yield users[i].db.garbageCollect()
|
||||
}
|
||||
yield wait(100)
|
||||
})
|
||||
|
||||
g.compareAllUsers = async(function * compareAllUsers (users) {
|
||||
var s1, s2 // state sets
|
||||
var ds1, ds2 // delete sets
|
||||
var allDels1, allDels2 // all deletions
|
||||
var db1 = [] // operation store of user1
|
||||
|
||||
// t1 and t2 basically do the same. They define t[1,2], ds[1,2], and allDels[1,2]
|
||||
function * t1 () {
|
||||
s1 = yield* this.getStateSet()
|
||||
ds1 = yield* this.getDeleteSet()
|
||||
allDels1 = []
|
||||
yield* this.ds.iterate(this, null, null, function * (d) {
|
||||
allDels1.push(d)
|
||||
})
|
||||
}
|
||||
function * t2 () {
|
||||
s2 = yield* this.getStateSet()
|
||||
ds2 = yield* this.getDeleteSet()
|
||||
allDels2 = []
|
||||
yield* this.ds.iterate(this, null, null, function * (d) {
|
||||
allDels2.push(d)
|
||||
})
|
||||
}
|
||||
yield users[0].connector.flushAll()
|
||||
yield wait()
|
||||
yield g.garbageCollectAllUsers(users)
|
||||
|
||||
for (var uid = 0; uid < users.length; uid++) {
|
||||
var u = users[uid]
|
||||
u.db.requestTransaction(function * () {
|
||||
// compare deleted ops against deleteStore
|
||||
yield* this.os.iterate(this, null, null, function * (o) {
|
||||
if (o.deleted === true) {
|
||||
expect(yield* this.isDeleted(o.id)).toBeTruthy()
|
||||
}
|
||||
})
|
||||
// compare deleteStore against deleted ops
|
||||
var ds = []
|
||||
yield* this.ds.iterate(this, null, null, function * (d) {
|
||||
ds.push(d)
|
||||
})
|
||||
for (var j in ds) {
|
||||
var d = ds[j]
|
||||
for (var i = 0; i < d.len; i++) {
|
||||
var o = yield* this.getOperation([d.id[0], d.id[1] + i])
|
||||
// gc'd or deleted
|
||||
if (d.gc) {
|
||||
expect(o).toBeFalsy()
|
||||
} else {
|
||||
expect(o.deleted).toBeTruthy()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
// compare allDels tree
|
||||
yield wait()
|
||||
if (s1 == null) {
|
||||
u.db.requestTransaction(function * () {
|
||||
yield* t1.call(this)
|
||||
yield* this.os.iterate(this, null, null, function * (o) {
|
||||
o = Y.utils.copyObject(o)
|
||||
delete o.origin
|
||||
db1.push(o)
|
||||
})
|
||||
})
|
||||
yield wait()
|
||||
} else {
|
||||
// TODO: make requestTransaction return a promise..
|
||||
u.db.requestTransaction(function * () {
|
||||
yield* t2.call(this)
|
||||
expect(s1).toEqual(s2)
|
||||
expect(allDels1).toEqual(allDels2) // inner structure
|
||||
expect(ds1).toEqual(ds2) // exported structure
|
||||
var count = 0
|
||||
yield* this.os.iterate(this, null, null, function * (o) {
|
||||
o = Y.utils.copyObject(o)
|
||||
delete o.origin
|
||||
expect(db1[count++]).toEqual(o)
|
||||
})
|
||||
})
|
||||
yield wait()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
g.createUsers = async(function * createUsers (self, numberOfUsers, database) {
|
||||
if (Y.utils.globalRoom.users[0] != null) {
|
||||
yield Y.utils.globalRoom.users[0].flushAll()
|
||||
}
|
||||
// destroy old users
|
||||
for (var u in Y.utils.globalRoom.users) {
|
||||
Y.utils.globalRoom.users[u].y.destroy()
|
||||
}
|
||||
self.users = null
|
||||
|
||||
var promises = []
|
||||
for (var i = 0; i < numberOfUsers; i++) {
|
||||
promises.push(Y({
|
||||
db: {
|
||||
name: database,
|
||||
namespace: 'User ' + i,
|
||||
cleanStart: true,
|
||||
gcTimeout: -1
|
||||
},
|
||||
connector: {
|
||||
name: 'Test',
|
||||
debug: false
|
||||
}
|
||||
}))
|
||||
}
|
||||
self.users = yield Promise.all(promises)
|
||||
return self.users
|
||||
})
|
||||
|
||||
/*
|
||||
Until async/await arrives in js, we use this function to wait for promises
|
||||
by yielding them.
|
||||
*/
|
||||
function async (makeGenerator) {
|
||||
return function (arg) {
|
||||
var generator = makeGenerator.apply(this, arguments)
|
||||
|
||||
function handle (result) {
|
||||
if (result.done) return Promise.resolve(result.value)
|
||||
|
||||
return Promise.resolve(result.value).then(function (res) {
|
||||
return handle(generator.next(res))
|
||||
}, function (err) {
|
||||
return handle(generator.throw(err))
|
||||
})
|
||||
}
|
||||
try {
|
||||
return handle(generator.next())
|
||||
} catch (ex) {
|
||||
generator.throw(ex)
|
||||
// return Promise.reject(ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
g.async = async
|
||||
|
||||
function logUsers (self) {
|
||||
if (self.constructor === Array) {
|
||||
self = {users: self}
|
||||
}
|
||||
self.users[0].db.logTable()
|
||||
self.users[1].db.logTable()
|
||||
self.users[2].db.logTable()
|
||||
}
|
||||
|
||||
g.logUsers = logUsers
|
@ -1,4 +1,3 @@
|
||||
/* global Y */
|
||||
'use strict'
|
||||
|
||||
/*
|
||||
@ -19,7 +18,7 @@
|
||||
* requiredOps
|
||||
- Operations that are required to execute this operation.
|
||||
*/
|
||||
|
||||
module.exports = function (Y) {
|
||||
var Struct = {
|
||||
/* This is the only operation that is actually not a structure, because
|
||||
it is not stored in the OS. This is why it _does not_ have an id
|
||||
@ -334,3 +333,4 @@ var Struct = {
|
||||
}
|
||||
}
|
||||
Y.Struct = Struct
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* global Y */
|
||||
'use strict'
|
||||
|
||||
/*
|
||||
@ -74,6 +73,7 @@
|
||||
- this is called only by `getOperations(startSS)`. It makes an operation
|
||||
applyable on a given SS.
|
||||
*/
|
||||
module.exports = function (Y) {
|
||||
class Transaction {
|
||||
/*
|
||||
Get a type based on the id of its model.
|
||||
@ -651,3 +651,4 @@ class Transaction {
|
||||
}
|
||||
}
|
||||
Y.Transaction = Transaction
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* global Y */
|
||||
'use strict'
|
||||
|
||||
;(function () {
|
||||
function extend (Y) {
|
||||
class YArray {
|
||||
constructor (os, _model, idArray, valArray) {
|
||||
this.os = os
|
||||
@ -166,7 +165,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
Y.Array = new Y.utils.CustomType({
|
||||
Y.extend('Array', new Y.utils.CustomType({
|
||||
class: YArray,
|
||||
createType: function * YArrayCreator () {
|
||||
var modelid = this.store.getNextOpId()
|
||||
@ -188,5 +187,11 @@
|
||||
})
|
||||
return new YArray(os, model.id, idArray, valArray)
|
||||
}
|
||||
})
|
||||
})()
|
||||
}))
|
||||
}
|
||||
|
||||
if (typeof Y !== 'undefined') {
|
||||
extend(Y)
|
||||
} else {
|
||||
module.exports = extend
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
/* global createUsers, databases, wait, Y, compareAllUsers, getRandomNumber, applyRandomTransactionsAllRejoinNoGC, applyRandomTransactionsWithGC, async, garbageCollectAllUsers, describeManyTimes */
|
||||
/* global createUsers, databases, wait, compareAllUsers, getRandomNumber, applyRandomTransactionsAllRejoinNoGC, applyRandomTransactionsWithGC, async, garbageCollectAllUsers, describeManyTimes */
|
||||
/* eslint-env browser,jasmine */
|
||||
'use strict'
|
||||
|
||||
var Y = require('../SpecHelper.js')
|
||||
var numberOfYArrayTests = 10
|
||||
var repeatArrayTests = 2
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* global Y */
|
||||
'use strict'
|
||||
|
||||
;(function () {
|
||||
module.exports = function (Y) {
|
||||
class YMap {
|
||||
constructor (os, model, contents, opContents) {
|
||||
this._model = model.id
|
||||
@ -292,4 +291,4 @@
|
||||
return new YMap(os, model, contents, opContents)
|
||||
}
|
||||
})
|
||||
})()
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
/* global createUsers, Y, databases, compareAllUsers, getRandomNumber, applyRandomTransactionsAllRejoinNoGC, applyRandomTransactionsWithGC, async, describeManyTimes */
|
||||
/* global createUsers, databases, compareAllUsers, getRandomNumber, applyRandomTransactionsAllRejoinNoGC, applyRandomTransactionsWithGC, async, describeManyTimes */
|
||||
/* eslint-env browser,jasmine */
|
||||
'use strict'
|
||||
|
||||
var Y = require('../SpecHelper.js')
|
||||
var numberOfYMapTests = 10
|
||||
var repeatMapTeasts = 1
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
/* global Y */
|
||||
'use strict'
|
||||
|
||||
;(function () {
|
||||
module.exports = function (Y) {
|
||||
class YTextBind extends Y.Array['class'] {
|
||||
constructor (os, _model, idArray, valArray) {
|
||||
super(os, _model, idArray, valArray)
|
||||
@ -287,4 +286,4 @@
|
||||
return new YTextBind(os, model.id, idArray, valArray)
|
||||
}
|
||||
})
|
||||
})()
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
/* global Y */
|
||||
'use strict'
|
||||
|
||||
/*
|
||||
@ -21,6 +20,9 @@
|
||||
database request to finish). EventHandler will help you to make your type
|
||||
synchronously.
|
||||
*/
|
||||
module.exports = function (Y) {
|
||||
Y.utils = {}
|
||||
|
||||
class EventHandler {
|
||||
/*
|
||||
onevent: is called when the structure changes.
|
||||
@ -196,3 +198,4 @@ function compareIds (id1, id2) {
|
||||
}
|
||||
}
|
||||
Y.utils.compareIds = compareIds
|
||||
}
|
||||
|
63
src/y.js
63
src/y.js
@ -1,7 +1,63 @@
|
||||
/* @flow */
|
||||
'use strict'
|
||||
|
||||
require('./Connector.js')(Y)
|
||||
require('./Database.js')(Y)
|
||||
require('./Transaction.js')(Y)
|
||||
require('./Struct.js')(Y)
|
||||
require('./Utils.js')(Y)
|
||||
require('./Databases/RedBlackTree.js')(Y)
|
||||
require('./Databases/Memory.js')(Y)
|
||||
require('./Databases/IndexedDB.js')(Y)
|
||||
require('./Connectors/Test.js')(Y)
|
||||
|
||||
var requiringModules = {}
|
||||
|
||||
module.exports = Y
|
||||
|
||||
Y.extend = function (name, value) {
|
||||
Y[name] = value
|
||||
var resolves = requiringModules[name]
|
||||
if (requiringModules[name] != null) {
|
||||
for (var i = 0; i < resolves.length; i++) {
|
||||
resolves[i]()
|
||||
}
|
||||
delete requiringModules[name]
|
||||
}
|
||||
}
|
||||
|
||||
require('./Types/Array.js')(Y)
|
||||
require('./Types/Map.js')(Y)
|
||||
require('./Types/TextBind.js')(Y)
|
||||
|
||||
function Y (opts) {
|
||||
opts.types = opts.types != null ? opts.types : []
|
||||
var modules = [opts.db.name, opts.connector.name].concat(opts.types)
|
||||
var promises = []
|
||||
for (var i = 0; i < modules.length; i++) {
|
||||
if (Y[modules[i]] == null) {
|
||||
try {
|
||||
require(modules[i])(Y)
|
||||
} catch (e) {
|
||||
// module does not exist
|
||||
if (window != null) {
|
||||
if (requiringModules[modules[i]] == null) {
|
||||
var imported = document.createElement('script')
|
||||
var name = modules[i].toLowerCase()
|
||||
imported.src = opts.sourceDir + '/y-' + name + '/y-' + name + '.js'
|
||||
document.head.appendChild(imported)
|
||||
requiringModules[modules[i]] = []
|
||||
}
|
||||
promises.push(new Promise(function (resolve) {
|
||||
requiringModules[modules[i]].push(resolve)
|
||||
}))
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.all(promises).then(function () {
|
||||
return new Promise(function (resolve) {
|
||||
var yconfig = new YConfig(opts, function () {
|
||||
yconfig.db.whenUserIdSet(function () {
|
||||
@ -9,6 +65,7 @@ function Y (opts) {
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
class YConfig {
|
||||
@ -49,9 +106,3 @@ class YConfig {
|
||||
if (typeof window !== 'undefined') {
|
||||
window.Y = Y
|
||||
}
|
||||
|
||||
if (typeof YConcurrency_TestingMode !== 'undefined') {
|
||||
g.Y = Y //eslint-disable-line
|
||||
// debugger //eslint-disable-line
|
||||
}
|
||||
Y.utils = {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user