Commit 6465fb74 authored by Guillaume Royer's avatar Guillaume Royer

chore: create bundle for node, browsers and commonjs

parent 4855eabd
{
"parserOptions": {
"ecmaVersion": 2017,
"sourceType": "module"
},
"env": {
"browser": true,
"node": true
},
"extends": "eslint:recommended",
"rules": {
"no-empty": ["error", {
"allowEmptyCatch": true
}],
"max-len": ["error", 80],
"space-before-function-paren": ["error", {
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}],
"one-var": ["error", {
"var": "always",
"const": "never",
"let": "never"
}]
}
}
......@@ -5,4 +5,5 @@
#dolphin
.directory
node_modules/*
\ No newline at end of file
node_modules/*
package-lock.json
dist/jio-*.js
lib/
.eslintrc.json
.htaccess
COPYING
Gruntfile.js
Makefile
rollup.config.js
......@@ -17,6 +17,7 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
module.exports = function (grunt) {
"use strict";
......@@ -41,6 +42,7 @@ module.exports = function (grunt) {
];
};
grunt.loadNpmTasks('gruntify-eslint');
grunt.loadNpmTasks('grunt-jslint');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
......@@ -59,10 +61,7 @@ module.exports = function (grunt) {
directives: {
maxlen: 100,
indent: 2,
maxerr: 3,
predef: [
'module'
]
maxerr: 3
}
},
grunt: {
......@@ -78,66 +77,18 @@ module.exports = function (grunt) {
]
}
},
jio: {
src: ['src/jio.js'],
directives: {
maxlen: 80,
indent: 2,
maxerr: 3,
nomen: true
}
},
jio_storages: {
src: ['src/jio.storage/*.js'],
directives: {
maxlen: 80,
indent: 2,
maxerr: 3,
predef: [
'define',
'exports',
'require',
'window',
'jIO',
'complex_queries'
]
}
},
jiodate: {
src: ['src/jio.date/jiodate.js'],
directives: {
maxlen: 80,
indent: 2,
maxerr: 3,
predef: [
'jIO'
]
},
},
tests: {
src: ['test/**/*.js'],
directives: {
maxlen: 80,
indent: 2,
maxerr: 3,
predef: [
'RSVP',
'QUnit',
'jIO'
]
},
},
queries: {
src: ['src/queries/*.js'],
exclude: [
'src/queries/parser-begin.js',
'src/queries/parser-end.js'
'test/node/**/*.js'
],
directives: {
maxlen: 80,
indent: 2,
maxerr: 3,
predef: [
'RSVP',
'QUnit',
'jIO'
]
}
......@@ -155,12 +106,68 @@ module.exports = function (grunt) {
'QUnit',
'jIO'
]
},
}
}
},
eslint: {
options: {
maxWarnings: 3
},
jio: {
src: [
'src/jio.bundle.js',
'src/jio.js',
'src/storage.js',
'src/utils-compat.js',
'src/utils.js'
]
},
jio_storages: {
src: ['src/jio.storage/*.js']
},
jiodate: {
src: ['src/jio.date/jiodate.js']
},
queries: {
src: ['src/queries/query.js']
},
nodeTests: {
src: ['test/node/**/*.js']
}
},
concat: {
options: {
separator: ';'
separator: ';',
process: function (src, filepath) {
// skip process libs
if (
filepath.indexOf('node_modules/') === 0 ||
filepath.indexOf('lib/') === 0
) {
return src;
}
var importRegex = new RegExp(
"import" +
"(?:[\"'\\s]*([\\w*{}\\n\\r\\t, ]+)from\\s*)?" +
"[\"'\\s].*([@\\w/_-]+)[\"'\\s].*;" +
"(\\r\\n\\t|\\n|\\r\\t)?$",
'gm'
),
exportRegex = new RegExp(
"export" +
"(?:[\"'\\s]*([\\w*{}\\n\\r\\t, ]+))?" +
"[\"'\\s].*([@\\w/_-]+)[\"'\\s].*;" +
"(\\r\\n\\t|\\n|\\r\\t)?$",
'gm'
);
return src
// remove import statements
.replace(importRegex, '')
// remove export statements
.replace(exportRegex, '');
}
},
jio: {
// duplicate files are ignored
......@@ -178,7 +185,11 @@ module.exports = function (grunt) {
'src/jio.date/*.js',
'src/jio-begin.js',
'src/jio.js',
'src/storage.js',
'src/utils.js',
'src/jio-end.js',
'node_modules/rusha/rusha.js',
......@@ -258,11 +269,11 @@ module.exports = function (grunt) {
files: [
'<%= jslint.npm.src %>',
'<%= jslint.grunt.src %>',
'<%= jslint.jio.src %>',
'<%= jslint.jiodate.src %>',
'<%= jslint.jio_storages.src %>',
'<%= jslint.tests.src %>',
'<%= jslint.queries.src %>',
'<%= eslint.jio.src %>',
'<%= eslint.jiodate.src %>',
'<%= eslint.jio_storages.src %>',
'<%= eslint.queries.src %>',
'<%= concat.jio.src %>',
'<%= qunit.files %>',
'test/**/*.js',
......@@ -300,7 +311,7 @@ module.exports = function (grunt) {
grunt.registerTask('default', ['all']);
grunt.registerTask('all', ['lint', 'build']);
grunt.registerTask('lint', ['jslint']);
grunt.registerTask('lint', ['jslint', 'eslint']);
grunt.registerTask('test', ['qunit']);
grunt.registerTask('server', ['connect:client', 'watch']);
grunt.registerTask('build', ['concat', 'copy']);
......
......@@ -2,19 +2,40 @@
jIO is a promised-based JavaScript library that offers connectors to many storages (Dropbox, webdav, IndexedDB, GDrive, ...) using a single API. jIO supports offline use, replication, encryption and synchronization as well as querying of stored documents and attachments allowing to build complex client-side centric web applications.
### jIO Documentation
## jIO Documentation
The documentation can be found on [https://jio.nexedi.com/](https://jio.nexedi.com/)
### jIO Quickstart
## jIO Quickstart
git clone https://lab.nexedi.com/nexedi/jio.git
npm install
grunt server
### jIO Code
## jIO Code
RenderJS source code is hosted on Gitlab at [https://lab.nexedi.com/nexedi/jio](https://lab.nexedi.com/nexedi/jio) (Github [mirror](https://github.com/nexedi/jio/) - please use the issue tracker on Gitlab)
### jIO Test
## jIO Test
You can run tests after installing and building jIO by opening the */test/* folder
## Build with rollup
```
$ npm install -g rollup
$ rollup -c
```
## jIO for Node.js
1. Install the package
```sh
$ npm install --save https://lab.nexedi.com/nexedi/jio.git
```
2. Import the library and create your first storage:
```javascript
const { jIO } = require('jio/dist/node/jio.js');
const jio = jIO.createJIO({
type: 'memory'
});
```
/*eslint no-console: "off"*/
const { jIO } = require('../dist/node/jio');
const tests = async () => {
try {
const memory = jIO.createJIO({
type: 'memory'
});
console.log(memory.__type === 'memory');
const id = await memory.put('1', {
foo: 'bar'
});
console.log(id === '1');
let results = await memory.allDocs();
console.log(results.data.total_rows === 1);
process.exit(0);
}
catch (err) {
console.error('error', err);
process.exit(1);
}
};
tests();
......@@ -8,12 +8,14 @@
"Sven Franck <sven.franck@nexedi.com>"
],
"description": "Client-side JavaScript library to manage documents across multiple storages",
"main": "jio.js",
"main": "dist/node/jio.js",
"module": "dist/jio.module.js",
"directories": {
"example": "examples",
"test": "test"
},
"scripts": {
"start": "./node_modules/.bin/grunt server",
"test": "./node_modules/.bin/grunt test",
"lint": "./node_modules/.bin/grunt lint",
"prepublish": "./node_modules/.bin/grunt build"
......@@ -29,28 +31,39 @@
"cloud"
],
"dependencies": {
"form-data": "^2.3.2",
"jquery": "^3.3.1",
"moment": "2.21.0",
"rsvp": "git+https://lab.nexedi.com/nexedi/rsvp.js.git",
"rusha": "0.8.2",
"sjcl": "^1.0.7",
"urijs": "^1.19.1",
"uritemplate": "git+https://lab.nexedi.com/nexedi/uritemplate-js.git",
"moment": "2.21.0",
"rusha": "0.8.2"
"xhr2": "^0.1.4"
},
"devDependencies": {
"renderjs": "git+https://lab.nexedi.com/nexedi/renderjs.git",
"connect-livereload": "~0.3.0",
"grunt": "0.4.x",
"grunt-cli": "~0.1.11",
"grunt-contrib-concat": "0.3.x",
"grunt-contrib-connect": "~0.5.0",
"grunt-contrib-copy": "~0.4.1",
"grunt-contrib-qunit": "~0.3.0",
"qunitjs": "~1.23.1",
"qunit-tap": "1.5.0",
"grunt-contrib-uglify": "0.2.x",
"grunt-contrib-watch": "~0.5.3",
"grunt-jslint": "~1.0.0",
"lz-string": "^1.4.4",
"sinon": "~1.7.3",
"jison": "~0.4.16",
"connect-livereload": "~0.3.0",
"grunt-open": "~0.2.2",
"grunt-contrib-connect": "~0.5.0"
"gruntify-eslint": "^5.0.0",
"jison": "~0.4.16",
"lz-string": "^1.4.4",
"qunit-tap": "1.5.0",
"qunitjs": "~1.23.1",
"renderjs": "git+https://lab.nexedi.com/nexedi/renderjs.git",
"rollup-plugin-commonjs": "^9.1.5",
"rollup-plugin-hypothetical": "^2.1.0",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-resolve": "^3.3.0",
"sinon": "~1.7.3"
},
"engines": {
"npm": ">=1.3"
......
import resolve from 'rollup-plugin-node-resolve';
import commonJS from 'rollup-plugin-commonjs';
import builtins from 'rollup-plugin-node-builtins';
import hypothetical from 'rollup-plugin-hypothetical';
export default [{
input: 'src/node/jio.js',
output: {
file: 'dist/node/jio.js',
format: 'cjs'
},
plugins: [
builtins()
]
}, {
external: [
'rsvp',
'xhr2',
'form-data',
'jquery',
'sjcl'
],
input: 'src/jio.bundle.js',
output: [{
file: 'dist/jio.bundle.js',
format: 'iife',
name: 'jIOBundle',
footer: `
for (var i in jIOBundle) {
if (jIOBundle.hasOwnProperty(i)) {
window[i] = jIOBundle[i];
}
}
`,
outro: `
exports.moment = moment;
exports.LZString = lzString;
`,
globals: {
rsvp: 'RSVP',
rusha: 'Rusha',
'form-data': 'FormData',
jquery: 'jQuery',
xhr2: 'XMLHttpRequest',
sjcl: 'sjcl',
http: 'http',
https: 'https',
os: 'os',
url: 'url'
}
}],
plugins: [
hypothetical({
allowFallthrough: true,
files: {
process: `
export default window;
`
}
}),
resolve(),
commonJS({
include: 'node_modules/**'
})
]
}, {
external: [
'rsvp',
'jquery',
'sjcl',
'rusha',
'lz-string',
'uritemplate',
'urijs',
'moment'
],
input: 'src/jio.bundle.js',
output: [{
file: 'dist/jio.module.js',
format: 'cjs'
}],
plugins: [
// skip require libs already included in window
// do not include them in `external: []`
hypothetical({
allowFallthrough: true,
files: {
'form-data': `
export default window.FormData;
`,
xhr2: `
export default window.XMLHttpRequest;
`,
process: `
export default window;
`
}
}),
resolve(),
commonJS({
include: 'node_modules/**'
})
]
}];
/*
* Copyright 2018, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
(function(RSVP) {
"use strict";
var jiodates = window,
queries = window;
/*
* Copyright 2018, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
window.jIO = jIO;
}(RSVP));
import { jIO, jiodate } from './jio';
import './storage';
import './jio.storage/cloudooostorage';
import './jio.storage/cryptstorage';
import './jio.storage/davstorage';
import './jio.storage/documentstorage';
import './jio.storage/drivetojiomapping';
import './jio.storage/dropboxstorage';
import './jio.storage/erp5storage';
import './jio.storage/fbstorage';
import './jio.storage/gdrivestorage';
// import './jio.storage/gidstorage';
import './jio.storage/httpstorage';
import './jio.storage/indexeddbstorage';
// import './jio.storage/indexstorage';
import './jio.storage/localstorage';
import './jio.storage/memorystorage';
// import './jio.storage/multisplitstorage';
import './jio.storage/parserstorage';
// import './jio.storage/qiniustorage';
import './jio.storage/querystorage';
// import './jio.storage/replicaterevisionstorage';
import './jio.storage/replicatestorage';
// import './jio.storage/revisionstorage';
// import './jio.storage/s3storage';
// import './jio.storage/searchableencryptionstorage';
import './jio.storage/shastorage';
// import './jio.storage/splitstorage';
import './jio.storage/unionstorage';
import './jio.storage/uuidstorage';
import './jio.storage/websqlstorage';
// import './jio.storage/xwikistorage';
import './jio.storage/zipstorage';
export {
jIO,
jiodate
};
......@@ -17,9 +17,18 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global window, moment */
/*jslint nomen: true, maxlen: 200*/
(function (window, moment) {
/*eslint max-len: ["error", 200], no-useless-escape: "off"*/
/*global window */
import moment from 'moment';
var moduleExports = {};
try {
moduleExports = window;
} catch (err) {}
(function (moduleExports, moment) {
"use strict";
// /**
......@@ -183,17 +192,7 @@
};
// _export('JIODate', JIODate);
//
// _export('YEAR', YEAR);
// _export('MONTH', MONTH);
// _export('DAY', DAY);
// _export('HOUR', HOUR);
// _export('MIN', MIN);
// _export('SEC', SEC);
// _export('MSEC', MSEC);
window.jiodate = {
moduleExports.jiodate = {
JIODate: JIODate,
YEAR: YEAR,
MONTH: MONTH,
......@@ -203,4 +202,6 @@
SEC: SEC,
MSEC: MSEC
};
}(window, moment));
}(moduleExports, moment));
export default moduleExports;
......@@ -17,551 +17,31 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global window, RSVP, Blob, XMLHttpRequest, QueryFactory, Query, atob,
FileReader, ArrayBuffer, Uint8Array, navigator */
(function (window, RSVP, Blob, QueryFactory, Query, atob,
FileReader, ArrayBuffer, Uint8Array, navigator) {
"use strict";
if (window.openDatabase === undefined) {
window.openDatabase = function () {
throw new Error('WebSQL is not supported by ' + navigator.userAgent);
};
}
/* Safari does not define DOMError */
if (window.DOMError === undefined) {
window.DOMError = {};
}
var util = {},
jIO;
function jIOError(message, status_code) {
if ((message !== undefined) && (typeof message !== "string")) {
throw new TypeError('You must pass a string.');
}
this.message = message || "Default Message";
this.status_code = status_code || 500;
}
jIOError.prototype = new Error();
jIOError.prototype.constructor = jIOError;
util.jIOError = jIOError;
/**
* Send request with XHR and return a promise. xhr.onload: The promise is
* resolved when the status code is lower than 400 with the xhr object as
* first parameter. xhr.onerror: reject with xhr object as first
* parameter. xhr.onprogress: notifies the xhr object.
*
* @param {Object} param The parameters
* @param {String} [param.type="GET"] The request method
* @param {String} [param.dataType=""] The data type to retrieve
* @param {String} param.url The url
* @param {Any} [param.data] The data to send
* @param {Number} param.timeout The request timeout value
* @param {Function} [param.beforeSend] A function called just before the
* send request. The first parameter of this function is the XHR object.
* @return {Promise} The promise
*/
function ajax(param) {
var xhr = new XMLHttpRequest();
return new RSVP.Promise(function (resolve, reject, notify) {
var k;
xhr.open(param.type || "GET", param.url, true);
xhr.responseType = param.dataType || "";
if (typeof param.headers === 'object' && param.headers !== null) {
for (k in param.headers) {
if (param.headers.hasOwnProperty(k)) {
xhr.setRequestHeader(k, param.headers[k]);
}
}
}
xhr.addEventListener("load", function (e) {
if (e.target.status >= 400) {
return reject(e);
}
resolve(e);
});
xhr.addEventListener("error", reject);
xhr.addEventListener("progress", notify);
if (typeof param.xhrFields === 'object' && param.xhrFields !== null) {
for (k in param.xhrFields) {
if (param.xhrFields.hasOwnProperty(k)) {
xhr[k] = param.xhrFields[k];
}
}
}
if (param.timeout !== undefined && param.timeout !== 0) {
xhr.timeout = param.timeout;
xhr.ontimeout = function () {
return reject(new jIO.util.jIOError("Gateway Timeout", 504));
};
}
if (typeof param.beforeSend === 'function') {
param.beforeSend(xhr);
}
xhr.send(param.data);
}, function () {
xhr.abort();
});
}
util.ajax = ajax;
function readBlobAsText(blob, encoding) {
var fr = new FileReader();
return new RSVP.Promise(function (resolve, reject, notify) {
fr.addEventListener("load", resolve);
fr.addEventListener("error", reject);
fr.addEventListener("progress", notify);
fr.readAsText(blob, encoding);
}, function () {
fr.abort();
});
}
util.readBlobAsText = readBlobAsText;
function readBlobAsArrayBuffer(blob) {
var fr = new FileReader();
return new RSVP.Promise(function (resolve, reject, notify) {
fr.addEventListener("load", resolve);
fr.addEventListener("error", reject);
fr.addEventListener("progress", notify);
fr.readAsArrayBuffer(blob);
}, function () {
fr.abort();
});
}
util.readBlobAsArrayBuffer = readBlobAsArrayBuffer;
function readBlobAsDataURL(blob) {
var fr = new FileReader();
return new RSVP.Promise(function (resolve, reject, notify) {
fr.addEventListener("load", resolve);
fr.addEventListener("error", reject);
fr.addEventListener("progress", notify);
fr.readAsDataURL(blob);
}, function () {
fr.abort();
});
}
util.readBlobAsDataURL = readBlobAsDataURL;
function stringify(obj) {
// Implement a stable JSON.stringify
// Object's keys are alphabetically ordered
var key,
key_list,
i,
value,
result_list;
if (obj === undefined) {
return undefined;
}
if (obj === null) {
return 'null';
}
if (obj.constructor === Object) {
key_list = Object.keys(obj).sort();
result_list = [];
for (i = 0; i < key_list.length; i += 1) {
key = key_list[i];
value = stringify(obj[key]);
if (value !== undefined) {
result_list.push(stringify(key) + ':' + value);
}
}
return '{' + result_list.join(',') + '}';
}
if (obj.constructor === Array) {
result_list = [];
for (i = 0; i < obj.length; i += 1) {
result_list.push(stringify(obj[i]));
}
return '[' + result_list.join(',') + ']';
}
return JSON.stringify(obj);
}
util.stringify = stringify;
function base64toBlob(b64String, mimeString) {
var byteString = atob(b64String),
// write the bytes of the string to an ArrayBuffer
arrayBuffer = new ArrayBuffer(byteString.length),
_ia = new Uint8Array(arrayBuffer),
i;
for (i = 0; i < byteString.length; i += 1) {
_ia[i] = byteString.charCodeAt(i);
}
return new Blob([arrayBuffer], {type: mimeString});
}
util.base64toBlob = base64toBlob;
// https://gist.github.com/davoclavo/4424731
function dataURItoBlob(dataURI) {
if (dataURI === 'data:') {
return new Blob();
}
// convert base64 to raw binary data held in a string
var mimeString = dataURI.split(',')[0].split(':')[1];
mimeString = mimeString.slice(0, mimeString.length - ";base64".length);
return base64toBlob(dataURI.split(',')[1], mimeString);
}
util.dataURItoBlob = dataURItoBlob;
// tools
function checkId(argument_list, storage, method_name) {
if (typeof argument_list[0] !== 'string' || argument_list[0] === '') {
throw new jIO.util.jIOError(
"Document id must be a non empty string on '" + storage.__type +
"." + method_name + "'.",
400
);
}
}
function checkAttachmentId(argument_list, storage, method_name) {
if (typeof argument_list[1] !== 'string' || argument_list[1] === '') {
throw new jIO.util.jIOError(
"Attachment id must be a non empty string on '" + storage.__type +
"." + method_name + "'.",
400
);
}
}
function ensurePushableQueue(callback, argument_list, context) {
var result;
try {
result = callback.apply(context, argument_list);
} catch (e) {
return new RSVP.Queue()
.push(function returnPushableError() {
return RSVP.reject(e);
});
}
if (result instanceof RSVP.Queue) {
return result;
}
return new RSVP.Queue()
.push(function returnPushableResult() {
return result;
});
}
function declareMethod(klass, name, precondition_function, post_function) {
klass.prototype[name] = function () {
var argument_list = arguments,
context = this,
precondition_result,
storage_method,
queue;
// Precondition function are not asynchronous
if (precondition_function !== undefined) {
precondition_result = precondition_function.apply(
context.__storage,
[argument_list, context, name]
);
}
import jiodates from './jio.date/jiodate';
import queries from './queries/query';
storage_method = context.__storage[name];
if (storage_method === undefined) {
throw new jIO.util.jIOError(
"Capacity '" + name + "' is not implemented on '" +
context.__type + "'",
501
);
}
queue = ensurePushableQueue(storage_method, argument_list,
context.__storage);
if (post_function !== undefined) {
queue
.push(function (result) {
return post_function.call(
context,
argument_list,
result,
precondition_result
);
});
}
return queue;
};
// Allow chain
return this;
}
/////////////////////////////////////////////////////////////////
// jIO Storage Proxy
/////////////////////////////////////////////////////////////////
function JioProxyStorage(type, storage) {
if (!(this instanceof JioProxyStorage)) {
return new JioProxyStorage();
}
this.__type = type;
this.__storage = storage;
}
declareMethod(JioProxyStorage, "put", checkId, function (argument_list) {
return argument_list[0];
});
declareMethod(JioProxyStorage, "get", checkId);
declareMethod(JioProxyStorage, "bulk");
declareMethod(JioProxyStorage, "remove", checkId, function (argument_list) {
return argument_list[0];
});
JioProxyStorage.prototype.post = function () {
var context = this,
argument_list = arguments;
return ensurePushableQueue(function () {
var storage_method = context.__storage.post;
if (storage_method === undefined) {
throw new jIO.util.jIOError(
"Capacity 'post' is not implemented on '" + context.__type + "'",
501
);
}
return context.__storage.post.apply(context.__storage, argument_list);
});
};
declareMethod(JioProxyStorage, 'putAttachment', function (argument_list,
storage,
method_name) {
checkId(argument_list, storage, method_name);
checkAttachmentId(argument_list, storage, method_name);
var options = argument_list[3] || {};
if (typeof argument_list[2] === 'string') {
argument_list[2] = new Blob([argument_list[2]], {
"type": options._content_type || options._mimetype ||
"text/plain;charset=utf-8"
});
} else if (!(argument_list[2] instanceof Blob)) {
throw new jIO.util.jIOError(
'Attachment content is not a blob',
400
);
}
});
declareMethod(JioProxyStorage, 'removeAttachment', function (argument_list,
storage,
method_name) {
checkId(argument_list, storage, method_name);
checkAttachmentId(argument_list, storage, method_name);
});
declareMethod(JioProxyStorage, 'getAttachment', function (argument_list,
storage,
method_name) {
var result = "blob";
// if (param.storage_spec.type !== "indexeddb" &&
// param.storage_spec.type !== "dav" &&
// (param.kwargs._start !== undefined
// || param.kwargs._end !== undefined)) {
// restCommandRejecter(param, [
// 'bad_request',
// 'unsupport',
// '_start, _end not support'
// ]);
// return false;
// }
checkId(argument_list, storage, method_name);
checkAttachmentId(argument_list, storage, method_name);
// Drop optional parameters, which are only used in postfunction
if (argument_list[2] !== undefined) {
result = argument_list[2].format || result;
delete argument_list[2].format;
}
return result;
}, function (argument_list, blob, convert) {
var result;
if (!(blob instanceof Blob)) {
throw new jIO.util.jIOError(
"'getAttachment' (" + argument_list[0] + " , " +
argument_list[1] + ") on '" + this.__type +
"' does not return a Blob.",
501
);
}
if (convert === "blob") {
result = blob;
} else if (convert === "data_url") {
result = new RSVP.Queue()
.push(function () {
return jIO.util.readBlobAsDataURL(blob);
})
.push(function (evt) {
return evt.target.result;
});
} else if (convert === "array_buffer") {
result = new RSVP.Queue()
.push(function () {
return jIO.util.readBlobAsArrayBuffer(blob);
})
.push(function (evt) {
return evt.target.result;
});
} else if (convert === "text") {
result = new RSVP.Queue()
.push(function () {
return jIO.util.readBlobAsText(blob);
})
.push(function (evt) {
return evt.target.result;
});
} else if (convert === "json") {
result = new RSVP.Queue()
.push(function () {
return jIO.util.readBlobAsText(blob);
})
.push(function (evt) {
return JSON.parse(evt.target.result);
});
} else {
throw new jIO.util.jIOError(
this.__type + ".getAttachment format: '" + convert +
"' is not supported",
400
);
}
return result;
});
JioProxyStorage.prototype.buildQuery = function () {
var storage_method = this.__storage.buildQuery,
context = this,
argument_list = arguments;
if (storage_method === undefined) {
throw new jIO.util.jIOError(
"Capacity 'buildQuery' is not implemented on '" + this.__type + "'",
501
);
}
return ensurePushableQueue(storage_method, argument_list,
context.__storage);
};
JioProxyStorage.prototype.hasCapacity = function (name) {
var storage_method = this.__storage.hasCapacity,
capacity_method = this.__storage[name];
if (capacity_method !== undefined) {
return true;
}
if ((storage_method === undefined) ||
!storage_method.apply(this.__storage, arguments)) {
throw new jIO.util.jIOError(
"Capacity '" + name + "' is not implemented on '" + this.__type + "'",
501
);
}
return true;
};
JioProxyStorage.prototype.allDocs = function (options) {
var context = this;
if (options === undefined) {
options = {};
}
return ensurePushableQueue(function () {
if (context.hasCapacity("list") &&
((options.query === undefined) || context.hasCapacity("query")) &&
((options.sort_on === undefined) || context.hasCapacity("sort")) &&
((options.select_list === undefined) ||
context.hasCapacity("select")) &&
((options.include_docs === undefined) ||
context.hasCapacity("include")) &&
((options.limit === undefined) || context.hasCapacity("limit"))) {
return context.buildQuery(options)
.push(function (result) {
return {
data: {
rows: result,
total_rows: result.length
}
};
});
}
});
};
declareMethod(JioProxyStorage, "allAttachments", checkId);
declareMethod(JioProxyStorage, "repair");
JioProxyStorage.prototype.repair = function () {
var context = this,
argument_list = arguments;
return ensurePushableQueue(function () {
var storage_method = context.__storage.repair;
if (storage_method !== undefined) {
return context.__storage.repair.apply(context.__storage,
argument_list);
}
});
};
/////////////////////////////////////////////////////////////////
// Storage builder
/////////////////////////////////////////////////////////////////
function JioBuilder() {
if (!(this instanceof JioBuilder)) {
return new JioBuilder();
}
this.__storage_types = {};
}
JioBuilder.prototype.createJIO = function (storage_spec, util) {
if (typeof storage_spec.type !== 'string') {
throw new TypeError("Invalid storage description");
}
if (!this.__storage_types[storage_spec.type]) {
throw new TypeError("Unknown storage '" + storage_spec.type + "'");
}
return new JioProxyStorage(
storage_spec.type,
new this.__storage_types[storage_spec.type](storage_spec, util)
);
};
JioBuilder.prototype.addStorage = function (type, Constructor) {
if (typeof type !== 'string') {
throw new TypeError(
"jIO.addStorage(): Argument 1 is not of type 'string'"
);
}
if (typeof Constructor !== 'function') {
throw new TypeError("jIO.addStorage(): " +
"Argument 2 is not of type 'function'");
}
if (this.__storage_types[type] !== undefined) {
throw new TypeError("jIO.addStorage(): Storage type already exists");
}
this.__storage_types[type] = Constructor;
};
JioBuilder.prototype.util = util;
JioBuilder.prototype.QueryFactory = QueryFactory;
JioBuilder.prototype.Query = Query;
/////////////////////////////////////////////////////////////////
// global
/////////////////////////////////////////////////////////////////
jIO = new JioBuilder();
window.jIO = jIO;
}(window, RSVP, Blob, QueryFactory, Query, atob,
FileReader, ArrayBuffer, Uint8Array, navigator));
/**
* jIO Storage Builder
*/
function JioBuilder() {
if (!(this instanceof JioBuilder)) {
return new JioBuilder();
}
}
JioBuilder.prototype.util = {};
JioBuilder.prototype.Query = queries.Query;
JioBuilder.prototype.QueryFactory = queries.QueryFactory;
var jIO = new JioBuilder(),
jiodate = jiodates.jiodate,
SimpleQuery = queries.SimpleQuery,
ComplexQuery = queries.ComplexQuery;
export {
jIO,
jiodate,
SimpleQuery,
ComplexQuery
};
......@@ -18,8 +18,11 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global jIO, RSVP, DOMParser, XMLSerializer*/
/*global DOMParser, XMLSerializer*/
import RSVP from 'rsvp';
import { jIO } from '../jio';
(function (jIO, RSVP, DOMParser, XMLSerializer) {
"use strict";
......@@ -43,7 +46,7 @@
}
/**
* convert a blob
* convert a blob
* from a format to another
* return converted blob.
**/
......@@ -84,7 +87,7 @@
* The jIO CloudoooStorage extension
*
* Convert attachment : att_id?from="format"&to="format"
*
*
* @class CloudoooStorage
* @constructor
*/
......
......@@ -18,8 +18,11 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer*/
/*global DOMException, crypto, Uint8Array, ArrayBuffer*/
import RSVP from 'rsvp';
import { jIO } from '../jio';
import { Blob } from '../utils-compat';
(function (jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer) {
"use strict";
......
......@@ -18,8 +18,11 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global jIO, RSVP, DOMParser, Blob */
/*global DOMParser */
import RSVP from 'rsvp';
import { jIO } from '../jio';
import { Blob } from '../utils-compat';
// JIO Dav Storage Description :
// {
......
......@@ -17,9 +17,15 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global Blob, RSVP, unescape, escape*/
(function (jIO, Blob, RSVP, unescape, escape) {
/*eslint no-unsafe-negation: "off"*/
/*global unescape, escape*/
import RSVP from 'rsvp';
import { jIO } from '../jio';
import { Blob, btoa, atob } from '../utils-compat';
(function (jIO, Blob, RSVP, unescape, escape, atob, btoa) {
"use strict";
/**
* The jIO DocumentStorage extension
......@@ -37,18 +43,18 @@
DOCUMENT_REGEXP = new RegExp("^jio_document/([\\w=]+)" +
DOCUMENT_EXTENSION + "$"),
ATTACHMENT_REGEXP = new RegExp("^jio_attachment/([\\w=]+)/([\\w=]+)$"),
btoa = function (str) {
return window.btoa(unescape(encodeURIComponent(str)));
btoaU = function (str) {
return btoa(unescape(encodeURIComponent(str)));
},
atob = function (str) {
return decodeURIComponent(escape(window.atob(str)));
atobU = function (str) {
return decodeURIComponent(escape(atob(str)));
};
function getSubAttachmentIdFromParam(id, name) {
if (name === undefined) {
return 'jio_document/' + btoa(id) + DOCUMENT_EXTENSION;
return 'jio_document/' + btoaU(id) + DOCUMENT_EXTENSION;
}
return 'jio_attachment/' + btoa(id) + "/" + btoa(name);
return 'jio_attachment/' + btoaU(id) + "/" + btoaU(name);
}
DocumentStorage.prototype.get = function (id) {
......@@ -70,8 +76,8 @@
if (ATTACHMENT_REGEXP.test(key)) {
exec = ATTACHMENT_REGEXP.exec(key);
try {
if (atob(exec[1]) === id) {
attachments[atob(exec[2])] = {};
if (atobU(exec[1]) === id) {
attachments[atobU(exec[2])] = {};
}
} catch (error) {
// Check if unable to decode base64 data
......@@ -142,7 +148,7 @@
attachment = undefined;
if (DOCUMENT_REGEXP.test(key)) {
try {
id = atob(DOCUMENT_REGEXP.exec(key)[1]);
id = atobU(DOCUMENT_REGEXP.exec(key)[1]);
} catch (error) {
// Check if unable to decode base64 data
if (!error instanceof ReferenceError) {
......@@ -155,8 +161,8 @@
} else if (ATTACHMENT_REGEXP.test(key)) {
exec = ATTACHMENT_REGEXP.exec(key);
try {
id = atob(exec[1]);
attachment = atob(exec[2]);
id = atobU(exec[1]);
attachment = atobU(exec[2]);
} catch (error) {
// Check if unable to decode base64 data
if (!error instanceof ReferenceError) {
......@@ -209,7 +215,7 @@
if (DOCUMENT_REGEXP.test(key)) {
try {
result.push({
id: atob(DOCUMENT_REGEXP.exec(key)[1]),
id: atobU(DOCUMENT_REGEXP.exec(key)[1]),
value: {}
});
} catch (error) {
......@@ -249,4 +255,4 @@
jIO.addStorage('document', DocumentStorage);
}(jIO, Blob, RSVP, unescape, escape));
}(jIO, Blob, RSVP, unescape, escape, atob, btoa));
......@@ -17,8 +17,11 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global RSVP, Blob*/
import RSVP from 'rsvp';
import { jIO } from '../jio';
import { Blob } from '../utils-compat';
(function (jIO, RSVP, Blob) {
"use strict";
......
......@@ -17,12 +17,15 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
import RSVP from 'rsvp';
import { jIO } from '../jio';
import { Blob } from '../utils-compat';
/**
* JIO Dropbox Storage. Type = "dropbox".
* Dropbox "database" storage.
*/
/*global Blob, jIO, RSVP*/
/*jslint nomen: true*/
(function (jIO, RSVP, Blob, JSON) {
"use strict";
......
......@@ -17,16 +17,20 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
import RSVP from 'rsvp';
import URI from 'urijs';
import UriTemplate from 'uritemplate';
import FormData from 'form-data';
import { jIO, SimpleQuery, ComplexQuery } from '../jio';
import { Blob } from '../utils-compat';
// JIO ERP5 Storage Description :
// {
// type: "erp5"
// url: {string}
// }
/*jslint nomen: true, unparam: true */
/*global jIO, UriTemplate, FormData, RSVP, URI, Blob,
SimpleQuery, ComplexQuery*/
(function (jIO, UriTemplate, FormData, RSVP, URI, Blob,
SimpleQuery, ComplexQuery) {
"use strict";
......
......@@ -17,8 +17,11 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true */
/*global RSVP, UriTemplate*/
import RSVP from 'rsvp';
import UriTemplate from 'uritemplate';
import { jIO } from '../jio';
(function (jIO, RSVP, UriTemplate) {
"use strict";
......@@ -130,4 +133,4 @@
jIO.addStorage('facebook', FBStorage);
}(jIO, RSVP, UriTemplate));
\ No newline at end of file
}(jIO, RSVP, UriTemplate));
......@@ -17,12 +17,18 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global JSON*/
import RSVP from 'rsvp';
import UriTemplate from 'uritemplate';
import { jIO } from '../jio';
import { Blob } from '../utils-compat';
/**
* JIO Google Drive Storage. Type = "gdrive".
* Google Drive "database" storage.
*/
/*global jIO, Blob, RSVP, UriTemplate, JSON*/
/*jslint nomen: true*/
(function (jIO, Blob, RSVP, UriTemplate, JSON) {
"use strict";
......
......@@ -19,7 +19,6 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global define, jIO */
/**
......
......@@ -17,8 +17,11 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global RSVP, Blob*/
/*jslint nomen: true*/
import RSVP from 'rsvp';
import { jIO } from '../jio';
import { Blob } from '../utils-compat';
(function (jIO, RSVP, Blob) {
"use strict";
......@@ -114,4 +117,4 @@
jIO.addStorage('http', HttpStorage);
}(jIO, RSVP, Blob));
\ No newline at end of file
}(jIO, RSVP, Blob));
......@@ -18,6 +18,12 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global indexedDB, Math, IDBKeyRange, IDBOpenDBRequest, DOMError*/
import RSVP from 'rsvp';
import { jIO } from '../jio';
import { Blob } from '../utils-compat';
/**
* JIO Indexed Database Storage.
*
......@@ -41,10 +47,6 @@
* - https://developer.mozilla.org/en-US/docs/IndexedDB/Using_IndexedDB
*/
/*jslint nomen: true */
/*global indexedDB, jIO, RSVP, Blob, Math, IDBKeyRange, IDBOpenDBRequest,
DOMError, Event*/
(function (indexedDB, jIO, RSVP, Blob, Math, IDBKeyRange, IDBOpenDBRequest,
DOMError) {
"use strict";
......@@ -543,4 +545,7 @@
};
jIO.addStorage("indexeddb", IndexedDBStorage);
}(indexedDB, jIO, RSVP, Blob, Math, IDBKeyRange, IDBOpenDBRequest, DOMError));
/* Safari does not define DOMError */
}(indexedDB, jIO, RSVP, Blob, Math, IDBKeyRange, IDBOpenDBRequest,
DOMError || {}));
......@@ -19,7 +19,6 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true, regexp: true */
/*global window, exports, require, define, jIO, RSVP */
/**
......
......@@ -18,8 +18,10 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global jIO, sessionStorage, localStorage, RSVP */
/*global sessionStorage, localStorage */
import RSVP from 'rsvp';
import { jIO } from '../jio';
/**
* JIO Local Storage. Type = 'local'.
......
......@@ -18,8 +18,8 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global jIO, RSVP*/
import RSVP from 'rsvp';
import { jIO } from '../jio';
/**
* JIO Memory Storage. Type = 'memory'.
......
......@@ -18,7 +18,6 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint indent:2, maxlen: 80, nomen: true */
/*global jIO, define, Blob */
/**
......
......@@ -17,8 +17,11 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global jIO, DOMParser, Node */
/*global DOMParser, Node */
import { jIO } from '../jio';
(function (jIO, DOMParser, Node) {
"use strict";
......
......@@ -18,6 +18,9 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global JSON, FormData, btoa, Blob, jIO, RSVP, UriTemplate, crypto,
Uint8Array, TextEncoder*/
/**
* JIO Qiniu Storage. Type = "qiniu".
* Qiniu "database" storage.
......@@ -28,9 +31,6 @@
* - disable getAttachment HTTP cache
*/
/*global JSON, FormData, btoa, Blob, jIO, RSVP, UriTemplate, crypto,
Uint8Array, TextEncoder*/
/*jslint nomen: true*/
(function (JSON, FormData, btoa, Blob, jIO, RSVP, UriTemplate, Crypto,
Uint8Array, TextEncoder) {
"use strict";
......
......@@ -17,8 +17,10 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global RSVP, jiodate*/
import RSVP from 'rsvp';
import { jIO, jiodate } from '../jio';
(function (jIO, RSVP, jiodate) {
"use strict";
......
......@@ -302,7 +302,7 @@
};
functions.repair_sub_storages_count = 0;
functions.repairAllSubStoragesCallback = function (method,
index, err, response) {
index, err) {
/*jslint unparam: true */
if (err) {
return command.error(err);
......@@ -573,7 +573,7 @@
}
};
functions.putAttachments = function (param, attachment_to_put) {
return function (method, index, err, response) {
return function (method, index, err) {
/*jslint unparam: true */
var i, attachment;
if (err) {
......@@ -606,9 +606,9 @@
}
};
};
functions.putAttachmentCallback = function (param) {
functions.putAttachmentCallback = function () {
/*jslint unparam: true */
return function (method, index, err, response) {
return function (method, index, err) {
if (err) {
return callback(err, undefined);
}
......
......@@ -19,8 +19,9 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global jIO, RSVP, Rusha*/
import RSVP from 'rsvp';
import Rusha from 'rusha';
import { jIO } from '../jio';
(function (jIO, RSVP, Rusha, stringify) {
"use strict";
......
......@@ -17,7 +17,7 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global jIO, hex_sha256, define */
/**
......
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, btoa, b64_hmac_sha1, jQuery, XMLHttpRequest, XHRwrapper,
/*global define, jIO, btoa, b64_hmac_sha1, jQuery, XMLHttpRequest,
FormData*/
/**
/**
* JIO S3 Storage. Type = "s3".
* Amazon S3 "database" storage.
*/
......
......@@ -4,7 +4,6 @@
** 31/01/2014 **
***********************************************************************/
/*jslint indent:2,maxlen:80,nomen:true*/
/*global jIO, define, exports, require, sjcl*/
(function (dependencies, module) {
......
......@@ -18,14 +18,14 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global Rusha*/
import Rusha from 'rusha';
import { jIO } from '../jio';
/**
* JIO Sha Storage. Type = 'sha'.
*/
(function (Rusha) {
(function (jIO, Rusha) {
"use strict";
var rusha = new Rusha();
......@@ -72,4 +72,4 @@
jIO.addStorage('sha', ShaStorage);
}(Rusha));
}(jIO, Rusha));
......@@ -18,7 +18,6 @@
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint indent:2, maxlen: 80, nomen: true */
/*global jIO, define, Blob */
/**
......
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, test_util, RSVP, test, ok, deepEqual, module, stop,
start, hex_sha256 */
start */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
......
......@@ -17,15 +17,16 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true */
/*global RSVP*/
import RSVP from 'rsvp';
import { jIO } from '../jio';
/**
* JIO Union Storage. Type = 'union'.
* This provide a unified access other multiple storage.
* New document are created in the first sub storage.
* Document are searched in each sub storage until it is found.
*
*
*
* Storage Description:
*
......
......@@ -17,7 +17,9 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
import { jIO } from '../jio';
(function (jIO) {
"use strict";
......
......@@ -17,17 +17,27 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global openDatabase, navigator*/
import RSVP from 'rsvp';
import { jIO } from '../jio';
import { Blob } from '../utils-compat';
/**
* JIO Websql Storage. Type = "websql".
* websql "database" storage.
*/
/*global Blob, jIO, RSVP, openDatabase*/
/*jslint nomen: true*/
(function (jIO, RSVP, Blob, openDatabase) {
"use strict";
if (openDatabase === undefined) {
openDatabase = function () {
throw new Error('WebSQL is not supported by ' + navigator.userAgent);
};
}
/**
* The JIO Websql Storage extension
*
......
/*jslint
indent: 2,
maxlen: 80,
plusplus: true,
nomen: true,
regexp: true
*/
/*eslint no-useless-escape: "off"*/
/*global
define: true,
exports: true,
......@@ -15,6 +9,7 @@
XMLHttpRequest,
FormData
*/
/**
* JIO XWiki Storage. Type = 'xwiki'.
* XWiki Document/Attachment storage.
......
......@@ -17,9 +17,15 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true*/
/*global RSVP, Blob, LZString, DOMException*/
(function (RSVP, Blob, LZString, DOMException) {
/*global DOMException*/
import RSVP from 'rsvp';
import LZString from 'lz-string';
import { jIO } from '../jio';
import { Blob } from '../utils-compat';
(function (jIO, RSVP, Blob, LZString, DOMException) {
"use strict";
/**
......@@ -130,4 +136,4 @@
};
jIO.addStorage('zip', ZipStorage);
}(RSVP, Blob, LZString, DOMException));
}(jIO, RSVP, Blob, LZString, DOMException));
import { jIO } from '../jio';
import '../storage';
import '../jio.storage/documentstorage';
import '../jio.storage/dropboxstorage';
import '../jio.storage/erp5storage';
import '../jio.storage/memorystorage';
import '../jio.storage/querystorage';
import '../jio.storage/replicatestorage';
export {
jIO
};
/*
* Copyright 2013, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
// parser-begin.js
/**
* Parse a text request to a json query object tree
*
* @param {String} string The string to parse
* @return {Object} The json query tree
*/
function parseStringToObject(string) {
var arrayExtend = function () {
var j, i, newlist = [], list_list = arguments;
for (j = 0; j < list_list.length; j += 1) {
for (i = 0; i < list_list[j].length; i += 1) {
newlist.push(list_list[j][i]);
}
}
return newlist;
}, mkSimpleQuery = function (key, value, operator) {
var object = {"type": "simple", "key": key, "value": value};
if (operator !== undefined) {
object.operator = operator;
}
return object;
}, mkNotQuery = function (query) {
if (query.operator === "NOT") {
return query.query_list[0];
}
return {"type": "complex", "key": "", "operator": "NOT", "query_list": [query]};
}, mkComplexQuery = function (key, operator, query_list) {
var i, query_list2 = [];
for (i = 0; i < query_list.length; i += 1) {
if (query_list[i].operator === operator) {
query_list2 = arrayExtend(query_list2, query_list[i].query_list);
} else {
query_list2.push(query_list[i]);
}
}
return {type:"complex",key:key,operator:operator,query_list:query_list2};
}, querySetKey = function (query, key) {
if (({simple: 1, complex: 1})[query.type] && !query.key) {
query.key = key;
return true;
}
return false;
},
error_offsets = [],
error_lookaheads = [],
error_count = 0,
result;
// build/parser.js
/* parser generated by jison 0.4.16 */
/*
Returns a Parser object of the following structure:
Parser: {
yy: {}
}
Parser.prototype: {
yy: {},
trace: function(),
symbols_: {associative list: name ==> number},
terminals_: {associative list: number ==> name},
productions_: [...],
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
table: [...],
defaultActions: {...},
parseError: function(str, hash),
parse: function(input),
lexer: {
EOF: 1,
parseError: function(str, hash),
setInput: function(input),
input: function(),
unput: function(str),
more: function(),
less: function(n),
pastInput: function(),
upcomingInput: function(),
showPosition: function(),
test_match: function(regex_match_array, rule_index),
next: function(),
lex: function(),
begin: function(condition),
popState: function(),
_currentRules: function(),
topState: function(),
pushState: function(condition),
options: {
ranges: boolean (optional: true ==> token location info will include a .range[] member)
flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)
},
performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
rules: [...],
conditions: {associative list: name ==> set},
}
}
token location info (@$, _$, etc.): {
first_line: n,
last_line: n,
first_column: n,
last_column: n,
range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)
}
the parseError function receives a 'hash' object with these members for lexer and parser errors: {
text: (matched text)
token: (the produced terminal token, if any)
line: (yylineno)
}
while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
loc: (yylloc)
expected: (string describing the set of expected tokens)
recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
}
*/
var parser = (function(){
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,5],$V1=[1,7],$V2=[1,8],$V3=[1,10],$V4=[1,12],$V5=[1,6,7,15],$V6=[1,6,7,9,12,14,15,16,19,21],$V7=[1,6,7,9,11,12,14,15,16,19,21],$V8=[2,17];
var parser = {trace: function trace() { },
yy: {},
symbols_: {"error":2,"begin":3,"search_text":4,"end":5,"EOF":6,"NEWLINE":7,"and_expression":8,"OR":9,"boolean_expression":10,"AND":11,"NOT":12,"expression":13,"LEFT_PARENTHESE":14,"RIGHT_PARENTHESE":15,"WORD":16,"DEFINITION":17,"value":18,"OPERATOR":19,"string":20,"QUOTE":21,"QUOTED_STRING":22,"$accept":0,"$end":1},
terminals_: {2:"error",6:"EOF",7:"NEWLINE",9:"OR",11:"AND",12:"NOT",14:"LEFT_PARENTHESE",15:"RIGHT_PARENTHESE",16:"WORD",17:"DEFINITION",19:"OPERATOR",21:"QUOTE",22:"QUOTED_STRING"},
productions_: [0,[3,2],[5,0],[5,1],[5,1],[4,1],[4,2],[4,3],[8,1],[8,3],[10,2],[10,1],[13,3],[13,3],[13,1],[18,2],[18,1],[20,1],[20,3]],
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
/* this == yyval */
var $0 = $$.length - 1;
switch (yystate) {
case 1:
return $$[$0-1];
break;
case 5: case 8: case 11: case 14: case 16:
this.$ = $$[$0];
break;
case 6:
this.$ = mkComplexQuery('', 'AND', [$$[$0-1], $$[$0]]);
break;
case 7:
this.$ = mkComplexQuery('', 'OR', [$$[$0-2], $$[$0]]);
break;
case 9:
this.$ = mkComplexQuery('', 'AND', [$$[$0-2], $$[$0]]);
break;
case 10:
this.$ = mkNotQuery($$[$0]);
break;
case 12:
this.$ = $$[$0-1];
break;
case 13:
querySetKey($$[$0], $$[$0-2]); this.$ = $$[$0];
break;
case 15:
$$[$0].operator = $$[$0-1] ; this.$ = $$[$0];
break;
case 17:
this.$ = mkSimpleQuery('', $$[$0]);
break;
case 18:
this.$ = mkSimpleQuery('', $$[$0-1]);
break;
}
},
table: [{3:1,4:2,8:3,10:4,12:$V0,13:6,14:$V1,16:$V2,18:9,19:$V3,20:11,21:$V4},{1:[3]},{1:[2,2],5:13,6:[1,14],7:[1,15]},o($V5,[2,5],{8:3,10:4,13:6,18:9,20:11,4:16,9:[1,17],12:$V0,14:$V1,16:$V2,19:$V3,21:$V4}),o($V6,[2,8],{11:[1,18]}),{13:19,14:$V1,16:$V2,18:9,19:$V3,20:11,21:$V4},o($V7,[2,11]),{4:20,8:3,10:4,12:$V0,13:6,14:$V1,16:$V2,18:9,19:$V3,20:11,21:$V4},o($V7,$V8,{17:[1,21]}),o($V7,[2,14]),{16:[1,23],20:22,21:$V4},o($V7,[2,16]),{22:[1,24]},{1:[2,1]},{1:[2,3]},{1:[2,4]},o($V5,[2,6]),{4:25,8:3,10:4,12:$V0,13:6,14:$V1,16:$V2,18:9,19:$V3,20:11,21:$V4},{8:26,10:4,12:$V0,13:6,14:$V1,16:$V2,18:9,19:$V3,20:11,21:$V4},o($V7,[2,10]),{15:[1,27]},{13:28,14:$V1,16:$V2,18:9,19:$V3,20:11,21:$V4},o($V7,[2,15]),o($V7,$V8),{21:[1,29]},o($V5,[2,7]),o($V6,[2,9]),o($V7,[2,12]),o($V7,[2,13]),o($V7,[2,18])],
defaultActions: {13:[2,1],14:[2,3],15:[2,4]},
parseError: function parseError(str, hash) {
if (hash.recoverable) {
this.trace(str);
} else {
function _parseError (msg, hash) {
this.message = msg;
this.hash = hash;
}
_parseError.prototype = new Error();
throw new _parseError(str, hash);
}
},
parse: function parse(input) {
var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
var args = lstack.slice.call(arguments, 1);
var lexer = Object.create(this.lexer);
var sharedState = { yy: {} };
for (var k in this.yy) {
if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
sharedState.yy[k] = this.yy[k];
}
}
lexer.setInput(input, sharedState.yy);
sharedState.yy.lexer = lexer;
sharedState.yy.parser = this;
if (typeof lexer.yylloc == 'undefined') {
lexer.yylloc = {};
}
var yyloc = lexer.yylloc;
lstack.push(yyloc);
var ranges = lexer.options && lexer.options.ranges;
if (typeof sharedState.yy.parseError === 'function') {
this.parseError = sharedState.yy.parseError;
} else {
this.parseError = Object.getPrototypeOf(this).parseError;
}
function popStack(n) {
stack.length = stack.length - 2 * n;
vstack.length = vstack.length - n;
lstack.length = lstack.length - n;
}
_token_stack:
var lex = function () {
var token;
token = lexer.lex() || EOF;
if (typeof token !== 'number') {
token = self.symbols_[token] || token;
}
return token;
};
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
while (true) {
state = stack[stack.length - 1];
if (this.defaultActions[state]) {
action = this.defaultActions[state];
} else {
if (symbol === null || typeof symbol == 'undefined') {
symbol = lex();
}
action = table[state] && table[state][symbol];
}
if (typeof action === 'undefined' || !action.length || !action[0]) {
var errStr = '';
expected = [];
for (p in table[state]) {
if (this.terminals_[p] && p > TERROR) {
expected.push('\'' + this.terminals_[p] + '\'');
}
}
if (lexer.showPosition) {
errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
} else {
errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
}
this.parseError(errStr, {
text: lexer.match,
token: this.terminals_[symbol] || symbol,
line: lexer.yylineno,
loc: yyloc,
expected: expected
});
}
if (action[0] instanceof Array && action.length > 1) {
throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
}
switch (action[0]) {
case 1:
stack.push(symbol);
vstack.push(lexer.yytext);
lstack.push(lexer.yylloc);
stack.push(action[1]);
symbol = null;
if (!preErrorSymbol) {
yyleng = lexer.yyleng;
yytext = lexer.yytext;
yylineno = lexer.yylineno;
yyloc = lexer.yylloc;
if (recovering > 0) {
recovering--;
}
} else {
symbol = preErrorSymbol;
preErrorSymbol = null;
}
break;
case 2:
len = this.productions_[action[1]][1];
yyval.$ = vstack[vstack.length - len];
yyval._$ = {
first_line: lstack[lstack.length - (len || 1)].first_line,
last_line: lstack[lstack.length - 1].last_line,
first_column: lstack[lstack.length - (len || 1)].first_column,
last_column: lstack[lstack.length - 1].last_column
};
if (ranges) {
yyval._$.range = [
lstack[lstack.length - (len || 1)].range[0],
lstack[lstack.length - 1].range[1]
];
}
r = this.performAction.apply(yyval, [
yytext,
yyleng,
yylineno,
sharedState.yy,
action[1],
vstack,
lstack
].concat(args));
if (typeof r !== 'undefined') {
return r;
}
if (len) {
stack = stack.slice(0, -1 * len * 2);
vstack = vstack.slice(0, -1 * len);
lstack = lstack.slice(0, -1 * len);
}
stack.push(this.productions_[action[1]][0]);
vstack.push(yyval.$);
lstack.push(yyval._$);
newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
stack.push(newState);
break;
case 3:
return true;
}
}
return true;
}};
/* generated by jison-lex 0.3.4 */
var lexer = (function(){
var lexer = ({
EOF:1,
parseError:function parseError(str, hash) {
if (this.yy.parser) {
this.yy.parser.parseError(str, hash);
} else {
throw new Error(str);
}
},
// resets the lexer, sets new input
setInput:function (input, yy) {
this.yy = yy || this.yy || {};
this._input = input;
this._more = this._backtrack = this.done = false;
this.yylineno = this.yyleng = 0;
this.yytext = this.matched = this.match = '';
this.conditionStack = ['INITIAL'];
this.yylloc = {
first_line: 1,
first_column: 0,
last_line: 1,
last_column: 0
};
if (this.options.ranges) {
this.yylloc.range = [0,0];
}
this.offset = 0;
return this;
},
// consumes and returns one char from the input
input:function () {
var ch = this._input[0];
this.yytext += ch;
this.yyleng++;
this.offset++;
this.match += ch;
this.matched += ch;
var lines = ch.match(/(?:\r\n?|\n).*/g);
if (lines) {
this.yylineno++;
this.yylloc.last_line++;
} else {
this.yylloc.last_column++;
}
if (this.options.ranges) {
this.yylloc.range[1]++;
}
this._input = this._input.slice(1);
return ch;
},
// unshifts one char (or a string) into the input
unput:function (ch) {
var len = ch.length;
var lines = ch.split(/(?:\r\n?|\n)/g);
this._input = ch + this._input;
this.yytext = this.yytext.substr(0, this.yytext.length - len);
//this.yyleng -= len;
this.offset -= len;
var oldLines = this.match.split(/(?:\r\n?|\n)/g);
this.match = this.match.substr(0, this.match.length - 1);
this.matched = this.matched.substr(0, this.matched.length - 1);
if (lines.length - 1) {
this.yylineno -= lines.length - 1;
}
var r = this.yylloc.range;
this.yylloc = {
first_line: this.yylloc.first_line,
last_line: this.yylineno + 1,
first_column: this.yylloc.first_column,
last_column: lines ?
(lines.length === oldLines.length ? this.yylloc.first_column : 0)
+ oldLines[oldLines.length - lines.length].length - lines[0].length :
this.yylloc.first_column - len
};
if (this.options.ranges) {
this.yylloc.range = [r[0], r[0] + this.yyleng - len];
}
this.yyleng = this.yytext.length;
return this;
},
// When called from action, caches matched text and appends it on next action
more:function () {
this._more = true;
return this;
},
// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
reject:function () {
if (this.options.backtrack_lexer) {
this._backtrack = true;
} else {
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), {
text: "",
token: null,
line: this.yylineno
});
}
return this;
},
// retain first n characters of the match
less:function (n) {
this.unput(this.match.slice(n));
},
// displays already matched input, i.e. for error messages
pastInput:function () {
var past = this.matched.substr(0, this.matched.length - this.match.length);
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
},
// displays upcoming input, i.e. for error messages
upcomingInput:function () {
var next = this.match;
if (next.length < 20) {
next += this._input.substr(0, 20-next.length);
}
return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
},
// displays the character position where the lexing error occurred, i.e. for error messages
showPosition:function () {
var pre = this.pastInput();
var c = new Array(pre.length + 1).join("-");
return pre + this.upcomingInput() + "\n" + c + "^";
},
// test the lexed token: return FALSE when not a match, otherwise return token
test_match:function (match, indexed_rule) {
var token,
lines,
backup;
if (this.options.backtrack_lexer) {
// save context
backup = {
yylineno: this.yylineno,
yylloc: {
first_line: this.yylloc.first_line,
last_line: this.last_line,
first_column: this.yylloc.first_column,
last_column: this.yylloc.last_column
},
yytext: this.yytext,
match: this.match,
matches: this.matches,
matched: this.matched,
yyleng: this.yyleng,
offset: this.offset,
_more: this._more,
_input: this._input,
yy: this.yy,
conditionStack: this.conditionStack.slice(0),
done: this.done
};
if (this.options.ranges) {
backup.yylloc.range = this.yylloc.range.slice(0);
}
}
lines = match[0].match(/(?:\r\n?|\n).*/g);
if (lines) {
this.yylineno += lines.length;
}
this.yylloc = {
first_line: this.yylloc.last_line,
last_line: this.yylineno + 1,
first_column: this.yylloc.last_column,
last_column: lines ?
lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
this.yylloc.last_column + match[0].length
};
this.yytext += match[0];
this.match += match[0];
this.matches = match;
this.yyleng = this.yytext.length;
if (this.options.ranges) {
this.yylloc.range = [this.offset, this.offset += this.yyleng];
}
this._more = false;
this._backtrack = false;
this._input = this._input.slice(match[0].length);
this.matched += match[0];
token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
if (this.done && this._input) {
this.done = false;
}
if (token) {
return token;
} else if (this._backtrack) {
// recover context
for (var k in backup) {
this[k] = backup[k];
}
return false; // rule action called reject() implying the next rule should be tested instead.
}
return false;
},
// return next match in input
next:function () {
if (this.done) {
return this.EOF;
}
if (!this._input) {
this.done = true;
}
var token,
match,
tempMatch,
index;
if (!this._more) {
this.yytext = '';
this.match = '';
}
var rules = this._currentRules();
for (var i = 0; i < rules.length; i++) {
tempMatch = this._input.match(this.rules[rules[i]]);
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
match = tempMatch;
index = i;
if (this.options.backtrack_lexer) {
token = this.test_match(tempMatch, rules[i]);
if (token !== false) {
return token;
} else if (this._backtrack) {
match = false;
continue; // rule action called reject() implying a rule MISmatch.
} else {
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
return false;
}
} else if (!this.options.flex) {
break;
}
}
}
if (match) {
token = this.test_match(match, rules[index]);
if (token !== false) {
return token;
}
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
return false;
}
if (this._input === "") {
return this.EOF;
} else {
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
text: "",
token: null,
line: this.yylineno
});
}
},
// return next match that has a token
lex:function lex() {
var r = this.next();
if (r) {
return r;
} else {
return this.lex();
}
},
// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
begin:function begin(condition) {
this.conditionStack.push(condition);
},
// pop the previously active lexer condition state off the condition stack
popState:function popState() {
var n = this.conditionStack.length - 1;
if (n > 0) {
return this.conditionStack.pop();
} else {
return this.conditionStack[0];
}
},
// produce the lexer rule set which is active for the currently active lexer condition state
_currentRules:function _currentRules() {
if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
} else {
return this.conditions["INITIAL"].rules;
}
},
// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
topState:function topState(n) {
n = this.conditionStack.length - 1 - Math.abs(n || 0);
if (n >= 0) {
return this.conditionStack[n];
} else {
return "INITIAL";
}
},
// alias for begin(condition)
pushState:function pushState(condition) {
this.begin(condition);
},
// return the number of states currently on the stack
stateStackSize:function stateStackSize() {
return this.conditionStack.length;
},
options: {},
performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
var YYSTATE=YY_START;
switch($avoiding_name_collisions) {
case 0:this.begin("letsquote"); return "QUOTE";
break;
case 1:this.popState(); this.begin("endquote"); return "QUOTED_STRING";
break;
case 2:this.popState(); return "QUOTE";
break;
case 3:/* skip whitespace */
break;
case 4:return "LEFT_PARENTHESE";
break;
case 5:return "RIGHT_PARENTHESE";
break;
case 6:return "AND";
break;
case 7:return "OR";
break;
case 8:return "NOT";
break;
case 9:return "DEFINITION";
break;
case 10:return 19;
break;
case 11:return 16;
break;
case 12:return 6;
break;
}
},
rules: [/^(?:")/,/^(?:(\\"|[^"])*)/,/^(?:")/,/^(?:[^\S]+)/,/^(?:\()/,/^(?:\))/,/^(?:AND\b)/,/^(?:OR\b)/,/^(?:NOT\b)/,/^(?::)/,/^(?:(!?=|<=?|>=?))/,/^(?:[^\s\n"():><!=]+)/,/^(?:$)/],
conditions: {"endquote":{"rules":[2],"inclusive":false},"letsquote":{"rules":[1],"inclusive":false},"INITIAL":{"rules":[0,3,4,5,6,7,8,9,10,11,12],"inclusive":true}}
});
return lexer;
})();
parser.lexer = lexer;
function Parser () {
this.yy = {};
}
Parser.prototype = parser;parser.Parser = Parser;
return new Parser;
})();
// parser-end.js
return parser.parse(string);
}; // parseStringToObject
export {
parseStringToObject
};
......@@ -17,9 +17,19 @@
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*global RSVP, window, parseStringToObject*/
/*jslint nomen: true, maxlen: 90*/
(function (RSVP, window, parseStringToObject) {
/*eslint max-len: ["error", 90], no-useless-escape: "off"*/
/*global window*/
import RSVP from 'rsvp';
import { parseStringToObject } from './parser-final';
var moduleExports = {};
try {
moduleExports = window;
} catch (err) {}
(function (RSVP, moduleExports, parseStringToObject) {
"use strict";
var query_class_dict = {},
......@@ -576,7 +586,6 @@
* #crossLink "Query/toString:method"
*/
ComplexQuery.prototype.toString = function () {
/*global objectToSearchText */
return objectToSearchText(this.toJSON());
};
......@@ -1079,9 +1088,11 @@
Query.parseStringToObject = parseStringToObject;
Query.objectToSearchText = objectToSearchText;
window.Query = Query;
window.SimpleQuery = SimpleQuery;
window.ComplexQuery = ComplexQuery;
window.QueryFactory = QueryFactory;
moduleExports.Query = Query;
moduleExports.SimpleQuery = SimpleQuery;
moduleExports.ComplexQuery = ComplexQuery;
moduleExports.QueryFactory = QueryFactory;
}(RSVP, moduleExports, parseStringToObject));
}(RSVP, window, parseStringToObject));
export default moduleExports;
/*
* Copyright 2014, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
import RSVP from 'rsvp';
import { jIO } from './jio';
import { declareMethod, ensurePushableQueue } from './utils';
import { Blob } from './utils-compat';
// tools
function checkId(argument_list, storage, method_name) {
if (typeof argument_list[0] !== 'string' || argument_list[0] === '') {
throw new jIO.util.jIOError(
"Document id must be a non empty string on '" + storage.__type +
"." + method_name + "'.",
400
);
}
}
function checkAttachmentId(argument_list, storage, method_name) {
if (typeof argument_list[1] !== 'string' || argument_list[1] === '') {
throw new jIO.util.jIOError(
"Attachment id must be a non empty string on '" + storage.__type +
"." + method_name + "'.",
400
);
}
}
function JioProxyStorage(type, storage) {
if (!(this instanceof JioProxyStorage)) {
return new JioProxyStorage();
}
this.__type = type;
this.__storage = storage;
}
declareMethod(JioProxyStorage, 'put', checkId, function (argument_list) {
return argument_list[0];
});
declareMethod(JioProxyStorage, 'get', checkId);
declareMethod(JioProxyStorage, 'bulk');
declareMethod(JioProxyStorage, 'remove', checkId, function (argument_list) {
return argument_list[0];
});
/**
* @returns RSVP.Queue
*/
JioProxyStorage.prototype.post = function () {
var context = this,
argument_list = arguments;
return ensurePushableQueue(function () {
var storage_method = context.__storage.post;
if (storage_method === undefined) {
throw new jIO.util.jIOError(
"Capacity 'post' is not implemented on '" + context.__type + "'",
501
);
}
return context.__storage.post.apply(context.__storage, argument_list);
});
};
declareMethod(JioProxyStorage, 'putAttachment', function (
argument_list, storage, method_name
) {
checkId(argument_list, storage, method_name);
checkAttachmentId(argument_list, storage, method_name);
var options = argument_list[3] || {};
if (typeof argument_list[2] === 'string') {
argument_list[2] = new Blob([argument_list[2]], {
type: options._content_type || options._mimetype ||
'text/plain;charset=utf-8'
});
} else if (!(argument_list[2] instanceof Blob)) {
throw new jIO.util.jIOError(
'Attachment content is not a blob',
400
);
}
});
declareMethod(JioProxyStorage, 'removeAttachment', function (
argument_list, storage, method_name
) {
checkId(argument_list, storage, method_name);
checkAttachmentId(argument_list, storage, method_name);
});
declareMethod(JioProxyStorage, 'getAttachment', function (
argument_list, storage, method_name
) {
var result = 'blob';
// if (param.storage_spec.type !== 'indexeddb' &&
// param.storage_spec.type !== 'dav' &&
// (param.kwargs._start !== undefined
// || param.kwargs._end !== undefined)) {
// restCommandRejecter(param, [
// 'bad_request',
// 'unsupport',
// '_start, _end not support'
// ]);
// return false;
// }
checkId(argument_list, storage, method_name);
checkAttachmentId(argument_list, storage, method_name);
// Drop optional parameters, which are only used in postfunction
if (argument_list[2] !== undefined) {
result = argument_list[2].format || result;
delete argument_list[2].format;
}
return result;
}, function (argument_list, blob, convert) {
var result;
if (!(blob instanceof Blob)) {
throw new jIO.util.jIOError(
"'getAttachment' (" + argument_list[0] + " , " +
argument_list[1] + ") on '" + this.__type +
"' does not return a Blob.",
501
);
}
if (convert === 'blob') {
result = blob;
} else if (convert === 'data_url') {
result = new RSVP.Queue()
.push(function () {
return jIO.util.readBlobAsDataURL(blob);
})
.push(function (evt) {
return evt.target.result;
});
} else if (convert === 'array_buffer') {
result = new RSVP.Queue()
.push(function () {
return jIO.util.readBlobAsArrayBuffer(blob);
})
.push(function (evt) {
return evt.target.result;
});
} else if (convert === 'text') {
result = new RSVP.Queue()
.push(function () {
return jIO.util.readBlobAsText(blob);
})
.push(function (evt) {
return evt.target.result;
});
} else if (convert === 'json') {
result = new RSVP.Queue()
.push(function () {
return jIO.util.readBlobAsText(blob);
})
.push(function (evt) {
return JSON.parse(evt.target.result);
});
} else {
throw new jIO.util.jIOError(
this.__type + ".getAttachment format: '" + convert +
"' is not supported",
400
);
}
return result;
});
JioProxyStorage.prototype.buildQuery = function () {
var storage_method = this.__storage.buildQuery,
context = this,
argument_list = arguments;
if (storage_method === undefined) {
throw new jIO.util.jIOError(
"Capacity 'buildQuery' is not implemented on '" + this.__type + "'",
501
);
}
return ensurePushableQueue(storage_method, argument_list,
context.__storage);
};
JioProxyStorage.prototype.hasCapacity = function (name) {
var storage_method = this.__storage.hasCapacity,
capacity_method = this.__storage[name];
if (capacity_method !== undefined) {
return true;
}
if ((storage_method === undefined) ||
!storage_method.apply(this.__storage, arguments)) {
throw new jIO.util.jIOError(
"Capacity '" + name + "' is not implemented on '" + this.__type + "'",
501
);
}
return true;
};
JioProxyStorage.prototype.allDocs = function (options) {
var context = this;
if (options === undefined) {
options = {};
}
return ensurePushableQueue(function () {
if (context.hasCapacity('list') &&
((options.query === undefined) || context.hasCapacity('query')) &&
((options.sort_on === undefined) || context.hasCapacity('sort')) &&
((options.select_list === undefined) ||
context.hasCapacity('select')) &&
((options.include_docs === undefined) ||
context.hasCapacity('include')) &&
((options.limit === undefined) || context.hasCapacity('limit'))) {
return context.buildQuery(options)
.push(function (result) {
return {
data: {
rows: result,
total_rows: result.length
}
};
});
}
});
};
declareMethod(JioProxyStorage, 'allAttachments', checkId);
declareMethod(JioProxyStorage, 'repair');
JioProxyStorage.prototype.repair = function () {
var context = this,
argument_list = arguments;
return ensurePushableQueue(function () {
var storage_method = context.__storage.repair;
if (storage_method !== undefined) {
return context.__storage.repair.apply(
context.__storage, argument_list
);
}
});
};
var storageTypes = {};
function createJIO(config, util) {
if (typeof config.type !== 'string') {
throw new TypeError("Invalid storage description");
}
if (!storageTypes[config.type]) {
throw new TypeError("Unknown storage '" + config.type + "'");
}
return new JioProxyStorage(
config.type,
new storageTypes[config.type](config, util)
);
}
jIO.createJIO = createJIO;
function addStorage(type, Constructor) {
if (typeof type !== 'string') {
throw new TypeError(
"jIO.addStorage(): Argument 1 is not of type 'string'"
);
}
if (typeof Constructor !== 'function') {
throw new TypeError(
"jIO.addStorage(): Argument 2 is not of type 'function'"
);
}
if (storageTypes[type] !== undefined) {
throw new TypeError(
"jIO.addStorage(): Storage type already exists"
);
}
storageTypes[type] = Constructor;
}
jIO.addStorage = addStorage;
/*
* Copyright 2014, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/* global window, WeakMap, Buffer, ArrayBuffer, Uint8Array */
/**
* Compatibility functions with node.js
*/
import process from 'process';
var EventTarget,
Blob,
FileReader,
html5weakmap;
try {
EventTarget = window.EventTarget;
Blob = window.Blob;
FileReader = window.FileReader;
} catch (error) {
html5weakmap = new WeakMap();
EventTarget = function EventTarget() {
html5weakmap.set(this, Object.create(null));
};
EventTarget.prototype.addEventListener = function (type, listener) {
if (typeof listener !== 'function') {
return;
}
var em = html5weakmap.get(this);
type = type.toString();
if (em[type]) {
em[type].push(listener);
} else {
em[type] = [listener];
}
};
EventTarget.prototype.removeEventListener = function (type, listener) {
if (typeof listener !== 'function') {
return;
}
var em = html5weakmap.get(this),
i,
listeners = em[type];
type = type.toString();
if (listeners) {
for (i = 0; i < listeners.length; ++i) {
if (listeners[i] === listener) {
if (listeners.length === 1) {
delete em[type];
return;
}
listeners.splice(i, 1);
return;
}
}
}
};
EventTarget.prototype.dispatchEvent = function (event) {
var type = event.type.toString(),
em = html5weakmap.get(this),
ontype = 'on' + type,
i,
listeners;
if (typeof this[ontype] === 'function') {
try {
this[ontype](event);
} catch (ignore) {}
}
listeners = em[type];
if (listeners) {
for (i = 0; i < listeners.length; ++i) {
try {
listeners[i](event);
} catch (ignore) {}
}
}
};
Blob = function Blob(blobParts, options) {
// https://developer.mozilla.org/en-US/docs/Web/API/Blob
var i,
priv = {},
buffers = [];
html5weakmap.set(this, priv);
for (i = 0; i < blobParts.length; ++i) {
if (Buffer.isBuffer(blobParts[i])) {
buffers.push(blobParts[i]);
} else if (blobParts[i] instanceof Blob) {
buffers.push(html5weakmap.get(blobParts[i]).data);
} else if (blobParts[i] instanceof ArrayBuffer) {
buffers.push(new Buffer(new Uint8Array(blobParts[i])));
} else {
buffers.push(new Buffer('' + blobParts[i]));
}
}
priv.data = Buffer.concat(buffers);
Object.defineProperty(this, 'size', {
enumerable: true,
value: priv.data.length
});
Object.defineProperty(this, 'type', {
enumerable: true,
value: options ? '' + (options.type || '') : ''
});
};
Blob.prototype.size = 0;
Blob.prototype.type = '';
Blob.prototype.slice = function (start, end, contentType) {
return new Blob([html5weakmap.get(this).data.slice(start, end)], {
type: contentType
});
};
FileReader = function FileReader() {
EventTarget.call(this);
};
FileReader.prototype = Object.create(EventTarget.prototype);
Object.defineProperty(FileReader, 'constructor', {
value: FileReader
});
FileReader.prototype.readAsText = function (blob) {
var target = this,
priv = html5weakmap.get(blob),
result = priv.data.toString(),
event = Object.freeze({
type: 'load',
target: target
});
process.nextTick(function () {
target.result = result;
target.dispatchEvent(event);
});
};
FileReader.prototype.readAsArrayBuffer = function (blob) {
var target = this,
priv = html5weakmap.get(blob),
result = new Uint8Array(priv.data).buffer,
event = Object.freeze({
type: 'load',
target: target
});
process.nextTick(function () {
target.result = result;
target.dispatchEvent(event);
});
};
FileReader.prototype.readAsDataURL = function (blob) {
var target = this,
priv = html5weakmap.get(blob),
result = 'data:' + blob.type + ';base64,' + priv.data.toString('base64'),
event = Object.freeze({
type: 'load',
target: target
});
process.nextTick(function () {
target.result = result;
target.dispatchEvent(event);
});
};
}
function atob(str) {
try {
return window.atob(str);
}
catch (err) {
var buffer;
if (str instanceof Buffer) {
buffer = str;
}
else {
buffer = Buffer.from(str.toString(), 'base64');
}
return buffer.toString('binary');
}
}
function btoa(str) {
try {
return window.btoa(str);
}
catch (err) {
var buffer;
if (str instanceof Buffer) {
buffer = str;
}
else {
buffer = Buffer.from(str.toString(), 'binary');
}
return buffer.toString('base64');
}
}
export {
EventTarget,
Blob,
FileReader,
atob,
btoa
};
/*
* Copyright 2014, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/* global ArrayBuffer, Uint8Array */
import RSVP from 'rsvp';
import XMLHttpRequest from 'xhr2';
import { jIO } from './jio';
import { Blob, FileReader, atob } from './utils-compat';
/**
* @returns RSVP.Queue
*/
function ensurePushableQueue(callback, argument_list, context) {
var result;
try {
result = callback.apply(context, argument_list);
} catch (e) {
return new RSVP.Queue()
.push(function returnPushableError() {
return RSVP.reject(e);
});
}
if (result instanceof RSVP.Queue) {
return result;
}
return new RSVP.Queue().push(function () {
return result;
});
}
function declareMethod(klass, name, precondition_function, post_function) {
klass.prototype[name] = function () {
var argument_list = arguments,
context = this,
precondition_result,
storage_method,
queue;
// Precondition function are not asynchronous
if (precondition_function !== undefined) {
precondition_result = precondition_function.apply(
context.__storage,
[argument_list, context, name]
);
}
storage_method = context.__storage[name];
if (storage_method === undefined) {
throw new jIO.util.jIOError(
"Capacity '" + name + "' is not implemented on '" +
context.__type + "'",
501
);
}
queue = ensurePushableQueue(
storage_method, argument_list, context.__storage
);
if (post_function !== undefined) {
queue
.push(function (result) {
return post_function.call(
context,
argument_list,
result,
precondition_result
);
});
}
return queue;
};
// Allow chain
return this;
}
function jIOError(message, status_code) {
if ((message !== undefined) && (typeof message !== 'string')) {
throw new TypeError('You must pass a string.');
}
this.message = message || 'Default Message';
this.status_code = status_code || 500;
}
jIOError.prototype = new Error();
jIOError.prototype.constructor = jIOError;
jIO.util.jIOError = jIOError;
/**
* Send request with XHR and return a promise. xhr.onload: The promise is
* resolved when the status code is lower than 400 with the xhr object as
* first parameter. xhr.onerror: reject with xhr object as first
* parameter. xhr.onprogress: notifies the xhr object.
*
* @param param The parameters
* @param {string} param.type The request method
* @param {string} param.dataType The data type to retrieve
* @param {string} param.url The url
* @param {any} param.data The data to send
* @param {any} param.headers The HTTP headers sent with the request
* @param {number} param.timeout The request timeout value
* @param {Function} param.beforeSend A function called just before the
* send request. The first parameter of this function is the XHR object.
* @return {Promise} The promise
*/
function ajax(param) {
var xhr = new XMLHttpRequest();
return new RSVP.Promise(function (resolve, reject, notify) {
var k;
xhr.open(param.type || "GET", param.url, true);
xhr.responseType = param.dataType || "";
if (typeof param.headers === 'object' && param.headers !== null) {
for (k in param.headers) {
if (param.headers.hasOwnProperty(k)) {
xhr.setRequestHeader(k, param.headers[k]);
}
}
}
xhr.addEventListener("load", function (e) {
if (e.target.status >= 400) {
return reject(e);
}
resolve(e);
});
xhr.addEventListener("error", reject);
xhr.addEventListener("progress", function (e) {
if (notify) {
notify(e);
}
});
if (typeof param.xhrFields === 'object' && param.xhrFields !== null) {
for (k in param.xhrFields) {
if (param.xhrFields.hasOwnProperty(k)) {
xhr[k] = param.xhrFields[k];
}
}
}
if (param.timeout !== undefined && param.timeout !== 0) {
xhr.timeout = param.timeout;
xhr.ontimeout = function () {
return reject(new jIO.util.jIOError("Gateway Timeout", 504));
};
}
if (typeof param.beforeSend === 'function') {
param.beforeSend(xhr);
}
xhr.send(param.data);
}, function () {
xhr.abort();
});
}
jIO.util.ajax = ajax;
function base64toBlob(b64String, mimeString) {
var byteString = atob(b64String),
// write the bytes of the string to an ArrayBuffer
arrayBuffer = new ArrayBuffer(byteString.length),
_ia = new Uint8Array(arrayBuffer),
i;
for (i = 0; i < byteString.length; i += 1) {
_ia[i] = byteString.charCodeAt(i);
}
return new Blob([arrayBuffer], {type: mimeString});
}
jIO.util.base64toBlob = base64toBlob;
// https://gist.github.com/davoclavo/4424731
function dataURItoBlob(dataURI) {
if (dataURI === 'data:') {
return new Blob();
}
// convert base64 to raw binary data held in a string
var mimeString = dataURI.split(',')[0].split(':')[1];
mimeString = mimeString.slice(0, mimeString.length - ';base64'.length);
return base64toBlob(dataURI.split(',')[1], mimeString);
}
jIO.util.dataURItoBlob = dataURItoBlob;
function readBlobAsDataURL(blob) {
var fr = new FileReader();
return new RSVP.Promise(function (resolve, reject, notify) {
fr.addEventListener('load', resolve);
fr.addEventListener('error', reject);
fr.addEventListener('progress', notify);
fr.readAsDataURL(blob);
}, function () {
fr.abort();
});
}
jIO.util.readBlobAsDataURL = readBlobAsDataURL;
function readBlobAsText(blob, encoding) {
var fr = new FileReader();
return new RSVP.Promise(function (resolve, reject, notify) {
fr.addEventListener('load', resolve);
fr.addEventListener('error', reject);
fr.addEventListener('progress', notify);
fr.readAsText(blob, encoding);
}, function () {
fr.abort();
});
}
jIO.util.readBlobAsText = readBlobAsText;
function readBlobAsArrayBuffer(blob) {
var fr = new FileReader();
return new RSVP.Promise(function (resolve, reject, notify) {
fr.addEventListener('load', resolve);
fr.addEventListener('error', reject);
fr.addEventListener('progress', notify);
fr.readAsArrayBuffer(blob);
}, function () {
fr.abort();
});
}
jIO.util.readBlobAsArrayBuffer = readBlobAsArrayBuffer;
function stringify(obj) {
// Implement a stable JSON.stringify
// Object's keys are alphabetically ordered
var key,
key_list,
i,
value,
result_list;
if (obj === undefined) {
return undefined;
}
if (obj === null) {
return 'null';
}
if (obj.constructor === Object) {
key_list = Object.keys(obj).sort();
result_list = [];
for (i = 0; i < key_list.length; i += 1) {
key = key_list[i];
value = stringify(obj[key]);
if (value !== undefined) {
result_list.push(stringify(key) + ':' + value);
}
}
return '{' + result_list.join(',') + '}';
}
if (obj.constructor === Array) {
result_list = [];
for (i = 0; i < obj.length; i += 1) {
result_list.push(stringify(obj[i]));
}
return '[' + result_list.join(',') + ']';
}
return JSON.stringify(obj);
}
jIO.util.stringify = stringify;
export {
declareMethod,
ensurePushableQueue,
jIOError,
ajax,
base64toBlob,
dataURItoBlob,
readBlobAsDataURL,
readBlobAsText,
readBlobAsArrayBuffer,
stringify
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment