├── .gitignore ├── test ├── support │ ├── entrypoint.json │ └── api.json └── test.js ├── examples ├── api-demo-model.html ├── calendar.js ├── api-demo-model.js └── api-demo.js ├── package.json ├── LICENSE.md ├── lib ├── validation.js ├── utils.js ├── model.js ├── core.js └── http-client.js ├── hydra-core.js ├── prepublish.js ├── README.md └── dist ├── hydra-core.min.js ├── hydra-core.js.map ├── hydra-core.js └── hydra-core.min.js.map /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules -------------------------------------------------------------------------------- /test/support/entrypoint.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": {"@vocab": "http://www.w3.org/ns/hydra/core#"}, 3 | "@id": "/hydra/api-demo/", 4 | "@type": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint", 5 | "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/issues": {"@id": "/hydra/api-demo/issues/"}, 6 | "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/registerUser": {"@id": "/hydra/api-demo/users/"}, 7 | "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/users": {"@id": "/hydra/api-demo/users/"} 8 | } -------------------------------------------------------------------------------- /examples/api-demo-model.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hydra-core", 3 | "version": "0.0.2", 4 | "description": "Core Hydra API", 5 | "main": "hydra-core.js", 6 | "scripts": { 7 | "prepublish": "node prepublish.js", 8 | "test": "node_modules/.bin/mocha" 9 | }, 10 | "keywords": [ 11 | "hydra" 12 | ], 13 | "author": "bergi@axolotlfarm.org", 14 | "license": "MIT", 15 | "readmeFilename": "README.md", 16 | "repository": { 17 | "type": "git", 18 | "url": "git://github.com/bergos/hydra-core.git" 19 | }, 20 | "dependencies": { 21 | "es6-promise": "2.*", 22 | "jsonld": "0.3.*", 23 | "lodash": "3.*", 24 | "request": "2.*" 25 | }, 26 | "devDependencies": { 27 | "browserify": "10.*", 28 | "exorcist": "0.4.0", 29 | "mocha": "2.*", 30 | "uglifyjs": "2.*" 31 | } 32 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # License 2 | The MIT License (MIT) 3 | Copyright © 2012–2015 Thomas Bergwinkl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /lib/validation.js: -------------------------------------------------------------------------------- 1 | var 2 | hydra = require('./core'), 3 | utils = require('./utils'), 4 | jsonldp = utils.require('jsonld').promises(); 5 | 6 | 7 | hydra.simpleValidateClass = function (object, read, write) { 8 | var self = this; 9 | 10 | if (!object) { 11 | return Promise.resolve(); 12 | } 13 | 14 | return jsonldp.expand(object) 15 | .then(function (expanded) { 16 | if (expanded.length > 1) { 17 | return Promise.reject(new Error('object contains multiple subjects')); 18 | } 19 | 20 | expanded = expanded.shift(); 21 | 22 | if (!('@type' in expanded)) { 23 | return Promise.reject(new Error('@type missing')); 24 | } 25 | 26 | if (utils.toArray(expanded['@type']).indexOf(self.iri) < 0) { 27 | return Promise.reject(new Error('expected class <' + self.iri + '>')); 28 | } 29 | 30 | var error = self.properties 31 | .map(function (property) { 32 | if (property.readonly && property.iri in object) { 33 | return new Error('readonly property <' + property.iri + '> filled with value "' + object[property.iri] + '"'); 34 | } 35 | 36 | return false; 37 | }) 38 | .filter(function (error) { 39 | return !!error; 40 | }) 41 | .shift(); 42 | 43 | if (error) { 44 | return Promise.reject(error); 45 | } 46 | 47 | return Promise.resolve(); 48 | }); 49 | }; 50 | 51 | -------------------------------------------------------------------------------- /hydra-core.js: -------------------------------------------------------------------------------- 1 | var 2 | hydra = require('./lib/core'), 3 | utils = require('./lib/utils'); 4 | 5 | 6 | require('./lib/http-client'); 7 | require('./lib/model'); 8 | require('./lib/validation'); 9 | 10 | 11 | hydra.loadApi = function (url) { 12 | return hydra.httpClient.request('GET', url) 13 | .then(function (response) { 14 | return hydra.api(response.body, url); 15 | }) 16 | .then(function (api) { 17 | api.iri = url; 18 | 19 | return api; 20 | }); 21 | }; 22 | 23 | 24 | hydra.documentFromResponse = function (response) { 25 | return hydra.httpClient.apiLink(response.headers, response.request.url) 26 | .then(function (apiUrl) { 27 | return hydra.loadApi(apiUrl); 28 | }) 29 | .then(function (api) { 30 | return hydra.document(api, response.body, response.request.url); 31 | }) 32 | .then(function (document) { 33 | return hydra.httpClient.contentLocation(response.headers, response.request.url) 34 | .then(function (contentLocation) { 35 | document.iri = contentLocation || response.request.url; 36 | 37 | return document; 38 | }); 39 | }); 40 | }; 41 | 42 | 43 | hydra.loadDocument = function (url) { 44 | return hydra.httpClient.request('GET', url) 45 | .then(function (response) { 46 | return hydra.documentFromResponse(response, url); 47 | }); 48 | }; 49 | 50 | 51 | // export utils 52 | hydra.utils = utils; 53 | 54 | 55 | // set defaults 56 | hydra.defaults = {}; 57 | hydra.defaults.invokeOperation = hydra.httpClient.jsonLdInvoke; 58 | hydra.defaults.validateClass = hydra.simpleValidateClass; 59 | hydra.defaults.model = {}; 60 | hydra.defaults.model.createInvoke = hydra.model.createHttpJsonLdInvoke; 61 | hydra.defaults.model.invokeOperation = hydra.httpClient.rawJsonLdInvoke; 62 | 63 | 64 | module.exports = hydra; 65 | -------------------------------------------------------------------------------- /examples/calendar.js: -------------------------------------------------------------------------------- 1 | global.Promise = require('es6-promise').Promise; 2 | 3 | var 4 | hydra = require('../'); 5 | 6 | 7 | var ns = { 8 | context: { '@vocab': 'http://schema.org/' }, 9 | EntryPoint: 'http://schema.org/EntryPoint', 10 | Event: 'http://schema.org/Event', 11 | Person: 'http://schema.org/Person', 12 | event: 'http://schema.org/event', 13 | invite: 'http://schema.org/invite', 14 | invitee: 'http://schema.org/invitee' 15 | }; 16 | 17 | 18 | var eventData = { 19 | '@context': ns.context, 20 | startDate: '2015-06-16T00:00:00Z', 21 | name: 'Test Event', 22 | description: 'This is a test event created by hydra core' 23 | }; 24 | 25 | 26 | var person = { 27 | '@type': ns.Person, 28 | '@id': 'https://bergnet.org/people/bergi/card#me' 29 | }; 30 | 31 | 32 | // create a entry point object 33 | hydra.model.load('http://localhost:8080/', {'@context': ns.context}) 34 | .then(function (entryPoint) { 35 | console.log('loaded entry point: <' + entryPoint.document.iri + '>'); 36 | 37 | // create a event object based on eventData 38 | return hydra.model.create(entryPoint.api.findClass(ns.Event), eventData) 39 | .then(function (event) { 40 | console.log('created event from abstract class with name: ' + event.name); 41 | 42 | // call the post method of property event 43 | return entryPoint.event['@post'](event); 44 | }); 45 | }) 46 | .then(function (event) { 47 | console.log('added event to calendar: <' + event['@id'] + '>'); 48 | 49 | // call the patch method of property invite 50 | return event.invite['@patch'](person); 51 | }) 52 | .then(function () { 53 | // no content in response -> Promise.resolve === success 54 | 55 | console.log('invited: <' + person['@id'] + '>'); 56 | }) 57 | .catch(function (error) { 58 | console.error(error.stack); 59 | }); 60 | -------------------------------------------------------------------------------- /prepublish.js: -------------------------------------------------------------------------------- 1 | var 2 | exec = require('child_process').exec; 3 | 4 | 5 | var run = function (command) { 6 | return new Promise(function (resolve, reject) { 7 | exec(command, function (error, stdout, stderr) { 8 | if (error != null) { 9 | return reject(error); 10 | } 11 | 12 | if (stderr.trim() !== '') { 13 | console.error(stderr.trim()); 14 | } 15 | 16 | if (stdout.trim() !== '') { 17 | console.log(stdout.trim()); 18 | } 19 | 20 | resolve(); 21 | }); 22 | }); 23 | }; 24 | 25 | 26 | var browserify = function (source, target, options) { 27 | options = options || {}; 28 | 29 | var cmd = './node_modules/.bin/browserify ' + source + ' -o ' + target; 30 | 31 | if (options.debug) { 32 | cmd += ' --debug'; 33 | } 34 | 35 | if (options.exclude) { 36 | cmd += ' ' + options.exclude 37 | .map(function (exclude) { 38 | return '-u ' + exclude; 39 | }) 40 | .join(' '); 41 | } 42 | 43 | if (options.list) { 44 | cmd += ' --list'; 45 | } 46 | 47 | if (options.noBuiltins) { 48 | cmd += ' --no-builtins'; 49 | } 50 | 51 | if (options.noBundleExternal) { 52 | cmd += ' --no-bundle-external'; 53 | } 54 | 55 | if (options.standalone) { 56 | cmd += ' --standalone=' + options.standalone; 57 | } 58 | 59 | return run(cmd); 60 | }; 61 | 62 | 63 | var exorcist = function (source, target, options) { 64 | options = options || {}; 65 | 66 | var cmd = 'cat ' + source + ' | ./node_modules/.bin/exorcist ' + target + ' > /dev/null'; 67 | 68 | return run(cmd); 69 | }; 70 | 71 | 72 | var uglify = function (source, target, options) { 73 | options = options || {}; 74 | 75 | var cmd = './node_modules/.bin/uglifyjs ' + source + ' -o ' + target; 76 | 77 | 78 | if (options.compress) { 79 | cmd += ' --compress'; 80 | } 81 | 82 | if (options.inSourceMap) { 83 | cmd += ' --in-source-map ' + options.inSourceMap; 84 | } 85 | 86 | if (options.sourceMap) { 87 | cmd += ' --source-map ' + options.sourceMap; 88 | } 89 | 90 | if (options.sourceMapUrl) { 91 | cmd += ' --source-map-url ' + options.sourceMapUrl; 92 | } 93 | 94 | return run(cmd); 95 | }; 96 | 97 | 98 | browserify('hydra-core.js', 'dist/hydra-core.js', { debug: true, noBundleExternal:true, standalone: 'hydra' }) 99 | .then(function () { 100 | return exorcist('dist/hydra-core.js', 'dist/hydra-core.js.map', {}); 101 | }) 102 | .then(function () { 103 | return browserify('hydra-core.js', 'dist/hydra-core.js', { noBundleExternal:true, standalone: 'hydra' }) 104 | }) 105 | .then(function () { 106 | return uglify('dist/hydra-core.js', 'dist/hydra-core.min.js', { 107 | compress: true, 108 | inSourceMap: 'dist/hydra-core.js.map', 109 | sourceMap: 'dist/hydra-core.min.js.map', 110 | sourceMapUrl: 'hydra-core.min.js.map' 111 | }); 112 | }) 113 | .catch(function (error) { 114 | console.error(error.stack); 115 | }); 116 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | var utils = {}; 2 | 3 | 4 | utils.require = function (module) { 5 | var globalModule = module; 6 | 7 | if (globalModule === 'lodash') { 8 | globalModule = '_'; 9 | } 10 | 11 | if (typeof window !== 'undefined' && globalModule in window) { 12 | return window[globalModule]; 13 | } 14 | 15 | return require(module); 16 | }; 17 | 18 | 19 | var 20 | _ = utils.require('lodash'), 21 | jsonldp = utils.require('jsonld').promises(); 22 | 23 | 24 | /** 25 | * Creates a Hydra Collection from a map or array of members 26 | * 27 | * @param iri 28 | * @param members 29 | * @returns {Collection} 30 | */ 31 | utils.collection = function (iri, members) { 32 | return { 33 | '@id': iri, 34 | '@type': 'http://www.w3.org/ns/hydra/core#Collection', 35 | 'http://www.w3.org/ns/hydra/core#member': _.values(members).map(function (member) { 36 | return { 37 | '@id': member['@id'], 38 | '@type': member['@type'] 39 | }; 40 | }) 41 | }; 42 | }; 43 | 44 | /** 45 | * Uses the given context to create a short form of the IRI 46 | * 47 | * @param iri 48 | * @param context 49 | * @returns {Promise} 50 | */ 51 | utils.compactIri = function (iri, context) { 52 | var dummy = {}; 53 | 54 | dummy[iri] = ''; 55 | 56 | return jsonldp.compact(dummy, context) 57 | .then(function (compactDummy) { 58 | return _.keys(compactDummy).pop(); 59 | }); 60 | }; 61 | 62 | /** 63 | * Creates a long version of the IRI using the given base 64 | * 65 | * @param iri 66 | * @param base 67 | * @returns {Promise} 68 | */ 69 | utils.expandIri = function (iri, base) { 70 | if (!base) { 71 | return Promise.resolve(iri); 72 | } 73 | 74 | var dummy = { 75 | '@context': { 76 | '@base': base, 77 | '@vocab': 'http://schema.org/' 78 | }, 79 | 'name': { 80 | '@id': iri 81 | } 82 | }; 83 | 84 | return jsonldp.expand(dummy) 85 | .then(function (expanded) { 86 | return expanded[0]['http://schema.org/name'][0]['@id']; 87 | }); 88 | }; 89 | 90 | /** 91 | * Extracts the IRI of an JSON-LD object 92 | * 93 | * @param obj 94 | * @returns {*} 95 | */ 96 | utils.iri = function (obj) { 97 | obj = utils.unwrap(obj); 98 | 99 | if (!obj) { 100 | return undefined; 101 | } 102 | 103 | if (_.isString(obj)) { 104 | return obj; 105 | } 106 | 107 | if (!('@id' in obj)) { 108 | return undefined; 109 | } 110 | 111 | return obj['@id']; 112 | }; 113 | 114 | /** 115 | * Checks if the given object is a Hydra Collection 116 | * 117 | * @param collection 118 | * @returns {boolean} 119 | */ 120 | utils.isCollection = function (collection) { 121 | if (!_.isObject(collection)) { 122 | return false; 123 | } 124 | 125 | if (!collection.member && !('http://www.w3.org/ns/hydra/core#member' in collection)) { 126 | return false; 127 | } 128 | 129 | return true; 130 | }; 131 | 132 | /** 133 | * Converts single objects and Hydra Collections to Arrays and forwards existing Arrays 134 | * 135 | * @param obj 136 | * @returns {Array} 137 | */ 138 | utils.toArray = function (obj) { 139 | if (!obj) { 140 | return []; 141 | } 142 | 143 | if (utils.isCollection(obj)) { 144 | obj = obj.member; 145 | } 146 | 147 | if (!_.isArray(obj)) { 148 | return [obj]; 149 | } 150 | 151 | return obj; 152 | }; 153 | 154 | /** 155 | * Extracts the first subject of an JSON-Ld object 156 | * 157 | * @param obj 158 | * @returns {*} 159 | */ 160 | utils.unwrap = function (obj) { 161 | if (!obj) { 162 | return undefined; 163 | } 164 | 165 | if (_.isString(obj)) { 166 | return obj; 167 | } 168 | 169 | if ('@graph' in obj) { 170 | obj = obj['@graph']; 171 | } 172 | 173 | if (_.isArray(obj)) { 174 | if (obj.length === 0) { 175 | return undefined; 176 | } else { 177 | obj = obj[0]; 178 | } 179 | } 180 | 181 | return obj; 182 | }; 183 | 184 | 185 | module.exports = utils; -------------------------------------------------------------------------------- /examples/api-demo-model.js: -------------------------------------------------------------------------------- 1 | (function (root, factory) { 2 | if (typeof module !== 'undefined' && module.exports) { 3 | module.exports = factory(require('../')); 4 | } else { 5 | factory(hydra); 6 | } 7 | })(this, function (hydra) { 8 | /** 9 | * This example registers a new user at the Hydra Issue Tracker Demo application [1]. That user is used to create a new 10 | * issue. The issue and user will be deleted afterwards, if "dontDelete" is not changed to "true". The Hydra Console [2] 11 | * can be used to view the created objects. 12 | * 13 | * [1] http://www.markus-lanthaler.com/hydra/api-demo/ 14 | * [2] http://www.markus-lanthaler.com/hydra/console/ 15 | */ 16 | 17 | /** 18 | * !!! change this to true if you want to keep the created objects !!! 19 | */ 20 | var dontDelete = false; 21 | 22 | 23 | var ns = { 24 | EntryPoint: 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint', 25 | Issue: 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue', 26 | User: 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#User', 27 | issues: 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/issues', 28 | registerUser: 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/registerUser' 29 | }; 30 | 31 | 32 | var config = { 33 | //base: 'http://www.markus-lanthaler.com', 34 | base: 'http://localhost:8080', 35 | user: 'hydracore', 36 | email: 'hydracore@test.com', 37 | password: '123456' 38 | }; 39 | 40 | 41 | var credentials = { 42 | user: config.email, 43 | password: config.password 44 | }; 45 | 46 | 47 | var entryPointContext = { 48 | '@context': { 49 | '@vocab': ns.EntryPoint + '/' 50 | } 51 | }; 52 | 53 | 54 | var userContext = { 55 | '@context': { 56 | '@vocab': ns.User + '/' 57 | } 58 | }; 59 | 60 | 61 | var userData = { 62 | '@context': { 63 | '@vocab': ns.User + '/' 64 | }, 65 | // no need to define @type here, because it will be injected with the model 66 | name: config.user, 67 | email: config.email, 68 | password: config.password 69 | }; 70 | 71 | 72 | var issueData = { 73 | '@context': { 74 | '@vocab': ns.Issue + '/' 75 | }, 76 | // no need to define @type here, because it will be injected with the model 77 | title: 'Hydra Core test issue', 78 | description: 'Test issues created by Hydra Core', 79 | is_open: true 80 | }; 81 | 82 | 83 | hydra.model.load(config.base + '/hydra/api-demo/', entryPointContext) 84 | .then(function (entryPoint) { 85 | console.log('loaded entry point: <' + entryPoint.document.iri + '>'); 86 | 87 | return Promise.all([ 88 | hydra.model.create(entryPoint.api.findClass(ns.User), userData), 89 | hydra.model.create(entryPoint.api.findClass(ns.Issue), issueData) 90 | ]).then(function (result) { 91 | var user = result[0]; 92 | var issue = result[1]; 93 | 94 | console.log('created user from abstract class with name: ' + user.name); 95 | console.log('created issue from abstract class with title: ' + issue.title); 96 | 97 | return entryPoint.registerUser['@post'](user, userContext) 98 | .then(function (registeredUser) { 99 | console.log('registered user as: <' + registeredUser['@id'] + '>'); 100 | 101 | return entryPoint.issues['@post'](issue, credentials) 102 | .then(function (createdIssue) { 103 | console.log('submitted issue as: <' + createdIssue['@id'] + '>'); 104 | 105 | if (dontDelete) { 106 | return; 107 | } else { 108 | return createdIssue['@delete'](null, credentials); 109 | } 110 | 111 | 112 | }) 113 | .then(function () { 114 | if (dontDelete) { 115 | return; 116 | } else { 117 | console.log('deleted issue'); 118 | 119 | return registeredUser['@delete'](); 120 | } 121 | }) 122 | .then(function () { 123 | if (!dontDelete) { 124 | console.log('deleted user'); 125 | } 126 | }); 127 | }); 128 | }); 129 | }) 130 | .catch(function (error) { 131 | console.error(error.stack); 132 | }); 133 | }); -------------------------------------------------------------------------------- /examples/api-demo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This example registers a new user at the Hydra Issue Tracker Demo application [1]. That user is used to create a new 3 | * issue. The issue and user will be deleted afterwards, if "dontDelete" is not changed to "true". The Hydra Console [2] 4 | * can be used to view the created objects. 5 | * 6 | * [1] http://www.markus-lanthaler.com/hydra/api-demo/ 7 | * [2] http://www.markus-lanthaler.com/hydra/console/ 8 | */ 9 | 10 | global.Promise = require('es6-promise').Promise; 11 | 12 | 13 | /** 14 | * !!! change this to true if you want to keep the created objects !!! 15 | */ 16 | var dontDelete = false; 17 | 18 | 19 | var 20 | hydra = require('../'), 21 | jsonldp = require('jsonld').promises(); 22 | 23 | 24 | var ns = { 25 | Issue: 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue', 26 | User: 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#User', 27 | issues: 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/issues', 28 | registerUser: 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/registerUser' 29 | }; 30 | 31 | 32 | var config = { 33 | //base: 'http://www.markus-lanthaler.com', 34 | base: 'http://localhost:8080', 35 | user: 'hydracore', 36 | email: 'hydracore@test.com', 37 | password: '123456' 38 | }; 39 | 40 | 41 | var user = { 42 | '@context': { 43 | '@vocab': ns.User + '/' 44 | }, 45 | '@type': ns.User, 46 | name: config.user, 47 | email: config.email, 48 | password: config.password 49 | }; 50 | 51 | 52 | var issue = { 53 | '@context': { 54 | '@vocab': ns.Issue + '/' 55 | }, 56 | '@type': ns.Issue, 57 | title: 'Hydra Core test issue', 58 | description: 'Test issues created by Hydra Core', 59 | is_open: true 60 | }; 61 | 62 | 63 | Promise.resolve() 64 | .then(function () { 65 | return hydra.loadDocument(config.base + '/hydra/api-demo/') 66 | .then(function (document) { 67 | // find "register user" operation using property IRI and method 68 | var registerUser = document.findOperation(ns.registerUser, 'POST').invoke; 69 | 70 | // find "create issue" operation using property IRI and method 71 | var createIssue = document.findOperation(ns.issues, 'POST').invoke; 72 | 73 | // invoke "register user" operation 74 | return registerUser(user) 75 | .then(function (response) { 76 | return jsonldp.compact(response, {'@vocab': 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#User/'}); 77 | }) 78 | .then(function (response) { 79 | user = response; 80 | 81 | console.log('created user <' + user['@id'] + '>'); 82 | console.log(user); 83 | }) 84 | .then(function () { 85 | // invoke "create issue" operation using basic authentication 86 | return createIssue(issue, {user: config.email, password: config.password}); 87 | }) 88 | .then(function (response) { 89 | return jsonldp.compact(response, {'@vocab': 'http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue/'}); 90 | }) 91 | .then(function (response) { 92 | issue = response; 93 | 94 | console.log('created issue <' + issue['@id'] + '>'); 95 | console.log(issue); 96 | }); 97 | }) 98 | }) 99 | .then(function () { 100 | if (dontDelete) { 101 | return Promise.resolve(); 102 | } 103 | 104 | return hydra.loadDocument(issue['@id']) 105 | .then(function (document) { 106 | // find "delete" class operation 107 | var deleteIssue = document.findOperation('DELETE').invoke; 108 | 109 | // invoke "delete" operation using basic authentication 110 | return deleteIssue(null, {user: config.email, password: config.password}) 111 | .then(function () { 112 | console.log('deleted issue <' + issue['@id'] + '>'); 113 | }); 114 | }); 115 | }) 116 | .then(function () { 117 | if (dontDelete) { 118 | return Promise.resolve(); 119 | } 120 | 121 | return hydra.loadDocument(user['@id']) 122 | .then(function (document) { 123 | // find "delete" class operation 124 | var deleteUser = document.findOperation('DELETE').invoke; 125 | 126 | // invoke "delete" operation using basic authentication 127 | return deleteUser(null, {user: config.email, password: config.password}) 128 | .then(function () { 129 | console.log('deleted user <' + user['@id'] + '>'); 130 | }); 131 | }); 132 | }) 133 | .catch(function (error) { 134 | console.error(error.stack); 135 | }); 136 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | global.Promise = require('es6-promise').Promise; 2 | 3 | 4 | var 5 | assert = require('assert'), 6 | fs = require('fs'), 7 | hydra = require('../hydra-core'); 8 | 9 | 10 | var promiseDone = function (done) { 11 | return function () { 12 | done(); 13 | }; 14 | }; 15 | 16 | var promiseError = function (done) { 17 | return function (error) { 18 | done(error.stack); 19 | }; 20 | }; 21 | 22 | 23 | describe('hydra', function () { 24 | var base = 'http://www.markus-lanthaler.com'; 25 | var apiString; 26 | var entryPointString; 27 | 28 | before(function () { 29 | apiString = fs.readFileSync('test/support/api.json').toString(); 30 | entryPointString = fs.readFileSync('test/support/entrypoint.json').toString(); 31 | }); 32 | 33 | describe('utils', function () { 34 | it('finder should find a single item based on iri or given property', function () { 35 | var items = [ 36 | {iri: '1', prop: 'a'}, 37 | {iri: '2', prop: 'b'} 38 | ]; 39 | 40 | var iriFinder = hydra.utils.finder(items); 41 | var propertyFinder = hydra.utils.finder(items, 'prop'); 42 | 43 | assert.equal(iriFinder('3'), undefined, 'unknown item'); 44 | assert.deepEqual(iriFinder('2'), {iri: '2', prop: 'b'}, 'known item'); 45 | assert.equal(propertyFinder('c'), undefined, 'unknown item'); 46 | assert.deepEqual(propertyFinder('a'), {iri: '1', prop: 'a'}, 'known item'); 47 | }); 48 | 49 | it('iri should return the IRI of an JSON-LD object', function () { 50 | assert.equal(hydra.utils.iri(null), undefined, 'null object'); 51 | assert.equal(hydra.utils.iri({}), undefined, 'initial object'); 52 | assert.equal(hydra.utils.iri({'@id': 'a'}), 'a', 'filled object'); 53 | }); 54 | 55 | it('toArray should convert anything to an array', function () { 56 | assert.deepEqual(hydra.utils.toArray(null), [], 'null'); 57 | assert.deepEqual(hydra.utils.toArray('1'), ['1'], 'non array value'); 58 | assert.deepEqual(hydra.utils.toArray(['1', '2']), ['1', '2'], 'array value'); 59 | }); 60 | 61 | it('unwrap should extract the graph of a JSON-LD object', function () { 62 | assert.equal(hydra.utils.unwrap(null), undefined, 'null'); 63 | assert.equal(hydra.utils.unwrap('_:test'), '_:test', 'string'); 64 | assert.deepEqual(hydra.utils.unwrap({'@id': 'test'}), {'@id': 'test'}, 'not wrapped graph'); 65 | assert.deepEqual(hydra.utils.unwrap({'@graph': [{'@id': 'test1'}, {'@id': 'test2'}]}), {'@id': 'test1'}, 'wrapped graph'); 66 | assert.deepEqual(hydra.utils.unwrap({'@graph': []}), undefined, 'empty graph'); 67 | }); 68 | 69 | it('values should return the values of an object', function () { 70 | assert.equal(hydra.utils.values(null), undefined, 'null object'); 71 | assert.deepEqual(hydra.utils.values({}), [], 'initial object'); 72 | assert.deepEqual(hydra.utils.values({a: 'ab', b: 'cd'}), ['ab', 'cd'], 'filled object with two properties'); 73 | }); 74 | }); 75 | 76 | describe('Api', function () { 77 | it('should create a hydra.Api object from a JSON string', function (done) { 78 | hydra.api(apiString, base) 79 | .then(function (api) { 80 | assert(api instanceof hydra.Api); 81 | assert.equal(api.iri, base + '/hydra/api-demo/vocab'); 82 | }) 83 | .then(promiseDone(done)) 84 | .catch(promiseError(done)); 85 | }); 86 | 87 | it('should create a hydra.Api object with classes and operations properties', function (done) { 88 | hydra.api(apiString, base) 89 | .then(function (api) { 90 | assert(Array.isArray(api.classes)); 91 | assert.equal(api.classes.length, 6); 92 | assert(Array.isArray(api.operations)); 93 | assert.equal(api.operations.length, 23); 94 | }) 95 | .then(promiseDone(done)) 96 | .catch(promiseError(done)); 97 | }); 98 | }); 99 | 100 | describe('Document', function () { 101 | it('should create a hydra.Document object from a JSON string', function (done) { 102 | hydra.api(apiString) 103 | .then(function (api) { 104 | return hydra.document(api, entryPointString, base); 105 | }) 106 | .then(function (document) { 107 | assert(document instanceof hydra.Document); 108 | assert.equal(document.iri, base + '/hydra/api-demo/'); 109 | }) 110 | .then(promiseDone(done)) 111 | .catch(promiseError(done)); 112 | }); 113 | 114 | it('should create a hydra.Document object with classes and properties properties', function (done) { 115 | hydra.api(apiString) 116 | .then(function (api) { 117 | return hydra.document(api, entryPointString, base); 118 | }) 119 | .then(function (document) { 120 | assert(Array.isArray(document.classes)); 121 | assert.equal(document.classes.length, 1); 122 | assert(Array.isArray(document.properties)); 123 | assert.equal(document.properties.length, 3); 124 | }) 125 | .then(promiseDone(done)) 126 | .catch(promiseError(done)); 127 | }); 128 | }); 129 | }); -------------------------------------------------------------------------------- /lib/model.js: -------------------------------------------------------------------------------- 1 | var 2 | hydra = require('./core'), 3 | utils = require('./utils'), 4 | _ = utils.require('lodash'), 5 | jsonldp = utils.require('jsonld').promises(); 6 | 7 | 8 | hydra.model = {}; 9 | 10 | 11 | /** 12 | * Creates an invoke function for model objects that compacts the response using the given context 13 | * 14 | * @param operation 15 | * @returns {Function} 16 | */ 17 | hydra.model.createHttpJsonLdInvoke = function (operation) { 18 | return function (input, options) { 19 | options = options || {}; 20 | 21 | var context = {}; 22 | 23 | if ('@context' in this) { 24 | context = this['@context']; 25 | } 26 | 27 | context = options.context || context; 28 | 29 | if (input && input.toJSON) { 30 | input = input.toJSON(); 31 | } 32 | 33 | return hydra.httpClient.rawJsonLdInvoke.call(operation, input, options) 34 | .then(function (response) { 35 | if (!response.body) { 36 | return Promise.resolve(null); 37 | } 38 | 39 | return hydra.documentFromResponse(response) 40 | .then(function (document) { 41 | return jsonldp.compact(response.body, context) 42 | .then(function (output) { 43 | return hydra.model.create(document.classes, output); 44 | }); 45 | }); 46 | }); 47 | }; 48 | }; 49 | 50 | /** 51 | * Converts a model object to serializable object without functions and property flagged with @omit 52 | */ 53 | hydra.model.toJSON = function () { 54 | var copyProperties = function (object, root) { 55 | if (!object) { 56 | return null; 57 | } 58 | 59 | var copy = _.keys(object).reduce(function (json, key) { 60 | var value = object[key]; 61 | 62 | // don't add function properties 63 | if (_.isFunction(value)) { 64 | return json; 65 | } 66 | 67 | // don't add properties with @omit flag 68 | if (_.isObject(value) && '@omit' in value && value['@omit']) { 69 | return json; 70 | } 71 | 72 | if (_.isObject(value)) { 73 | // copy sub properties 74 | json[key] = copyProperties(value, root); 75 | } else { 76 | // copy string values 77 | json[key] = value; 78 | } 79 | 80 | return json; 81 | }, {}); 82 | 83 | // convert to Array if original object was an Array 84 | if (_.isArray(object)) { 85 | copy = _.values(object); 86 | } 87 | 88 | return copy; 89 | }; 90 | 91 | return copyProperties(this); 92 | }; 93 | 94 | /** 95 | * Adds a @omit property to an object to hide it from serialization 96 | * 97 | * @param property 98 | * @returns {Object} 99 | */ 100 | hydra.model.hide = function (property) { 101 | property['@omit'] = true; 102 | 103 | return property; 104 | }; 105 | 106 | /** 107 | * Creates a model object based on one or more classes 108 | * 109 | * @param classes The class or classes the model will be bases on 110 | * @param properties Properties to merge into the model object 111 | * @param options Additional options to control the model creation 112 | * @returns {*} 113 | */ 114 | hydra.model.create = function (classes, properties, options) { 115 | var processOperations = function (root, operations) { 116 | operations.forEach(function (operation) { 117 | var key = '@' + operation.method.toLowerCase(); 118 | 119 | if (!(key in root)) { 120 | root[key] = options.createInvoke(operation).bind(model); 121 | } 122 | }); 123 | 124 | return Promise.resolve(); 125 | }; 126 | 127 | var processProperties = function (root, properties) { 128 | return Promise.all(properties.map(function (property) { 129 | return utils.compactIri(property.iri, model['@context']) 130 | .then(function (key) { 131 | if (!(key in root)) { 132 | root[key] = {}; 133 | } 134 | 135 | return processOperations(root[key], property.operations); 136 | }); 137 | })); 138 | }; 139 | 140 | var processClass = function (apiClass) { 141 | model['@type'].push(apiClass.iri); 142 | 143 | return processOperations(model, apiClass.operations) 144 | .then(function () { 145 | return processProperties(model, apiClass.properties); 146 | }); 147 | }; 148 | 149 | classes = utils.toArray(classes); 150 | 151 | options = options || {}; 152 | options.createInvoke = options.createInvoke || hydra.defaults.model.createInvoke; 153 | 154 | var model = _.clone(properties); 155 | 156 | _.defaults(model, { 157 | '@context': {}, 158 | toJSON: hydra.model.toJSON 159 | }); 160 | 161 | model['@type'] = []; 162 | model.api = classes[0].api || classes[0].abstract.api; 163 | model.api['@omit'] = true; 164 | 165 | if (classes[0].document) { 166 | model.document = classes[0].document; 167 | model.document['@omit'] = true; 168 | } 169 | 170 | return Promise.all(classes.map(function (apiClass) { 171 | return processClass(apiClass); 172 | })).then(function () { 173 | return model; 174 | }); 175 | }; 176 | 177 | /** 178 | * Creates a model object based on a GET request to the given URL 179 | * 180 | * @param url URL 181 | * @param properties Properties that will be merged into the model object 182 | * @param options Options for the request 183 | * @returns {Promise} 184 | */ 185 | hydra.model.load = function (url, properties, options) { 186 | return hydra.loadDocument(url) 187 | .then(function (document) { 188 | return hydra.model.create(document.classes, properties, options); 189 | }); 190 | }; 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hydra Core 2 | 3 | Hydra Core provides basic objects to work with Hydra enabled Web APIs. 4 | 5 | ## Usage 6 | 7 | ### Node.js 8 | 9 | hydra-core is available on `npm`, to install it run: 10 | 11 | ```shell 12 | npm install hydra-core 13 | ``` 14 | 15 | In the code, import hydra-core: 16 | 17 | ```javascript 18 | var hydra = require('hydra-core'); 19 | ``` 20 | 21 | ## Examples 22 | 23 | The examples folder contains working example code for the Hydra Issue Tracker Demo application. 24 | 25 | ```shell 26 | cd examples 27 | node api-demo.js 28 | ``` 29 | 30 | An alternative example code uses the object model to access the Hydra Issue Tracker Demo application. 31 | 32 | ```shell 33 | cd examples 34 | node api-demo-model.js 35 | ``` 36 | 37 | ## API 38 | 39 | ### hydra.Api 40 | 41 | #### classes: 42 | `Array` of `hydra.Class` objects defined in the API documentation. 43 | 44 | #### operations: 45 | `Array` of `hydra.Operation` objects defined in the API documentation. 46 | 47 | #### findClass(iri): 48 | Returns a `hydra.Class` object for the given IRI or `undefined` if the IRI is unknown. 49 | 50 | #### findOperation(iri): 51 | Returns a `hydra.Operation` object for the given IRI or `undefined` if the IRI is unknown. 52 | 53 | ### hydra.Document 54 | 55 | #### classes 56 | `Array` of `hydra.ClassDocument` objects based on `rdf:type` triples in the document. 57 | 58 | #### properties 59 | `Array` of `hydra.PropertyDocument` objects based on triples in the document. 60 | 61 | #### findOperation([propertyIri], method): 62 | Returns a `hydra.OperationDocument` object or `undefined` if the operation was not found. 63 | Searches only in the classes of the document, if only the `method` argument is given. 64 | Searches for operations assigned to the property, if the `propertyIri` arguments is also given. 65 | 66 | #### findProperty 67 | Returns a `hydra.PropertyDocument` object for the given IRI or `undefined` if the IRI is unknown. 68 | 69 | ### hydra.Class 70 | 71 | ### hydra.ClassDocument 72 | 73 | ### hydra.Operation 74 | 75 | ### hydra.OperationDocument 76 | 77 | ### hydra.Property 78 | 79 | ### hydra.PropertyDocument 80 | 81 | ### hydra.api(json, base) 82 | 83 | Parses the given JSON-LD object or string and returns a `hydra.Api` object using a Promise. 84 | The `base` parameter is used to expand the given JSON-LD object. 85 | 86 | ### hydra.document(api, json, base) 87 | 88 | Parses the given JSON-LD object or string and returns a `hydra.Document` object using a Promise. 89 | `api` must be an instance of `hydra.Api`. 90 | The `base` parameter is used to expand the given JSON-LD object. 91 | 92 | ## API Model 93 | 94 | The hydra core object model uses JSON-LD objects extended with functions and additional `@` properties. 95 | Hydra operations are mapped into the objects with the `@` + lower case the HTTP method keys. 96 | For example, if an entry point class contains `http://schema.org/blogPost` property that implements a HTTP POST 97 | method to create a new blog post, the following code could be used: 98 | 99 | ```javascript 100 | // load the entry point from http://example.com/ 101 | hydra.model.load('http://example.com/') 102 | .then(function (entryPoint) { 103 | // create a new blog post using the post method of http://schema.org/blogPost 104 | return entryPoint['http://schema.org/blogPost']['@post']({ 105 | 'http://schema.org/name': 'blog post name', 106 | 'http://schema.org/articleBody': 'this is the content of the blog post' 107 | }); 108 | }) 109 | .then(function (blogPost) { 110 | // write the IRI of the created blog post to the console 111 | console.log(blogPost['@id']); 112 | }); 113 | ``` 114 | 115 | If a JSON-LD context is defined, the objects will be compacted using that context: 116 | 117 | ```javascript 118 | // define the context in the properties object, that will be merged into the model object 119 | hydra.model.load('http://example.com/', {'@context': {'@vocab': 'http://schema.org'}}) 120 | .then(function (entryPoint) { 121 | // works also with the POST operation 122 | return entryPoint.blogPost['@post']({ 123 | '@context': {'@vocab': 'http://schema.org'}, 124 | name: 'blog post name', 125 | articleBody: 'this is the content of the blog post' 126 | }, {'@context': {'@vocab': 'http://schema.org'}}); 127 | }); 128 | ``` 129 | 130 | It's possible to add properties to the model object and hide them from the serialization. 131 | A `@omit: true` key value pair must be added to the property. 132 | The `hydra.model.hide` method can be used for this: 133 | 134 | ```javascript 135 | // assign a new hidden variable 136 | blogPost.privateVariable = hydra.model.hide(privateVariable); 137 | ``` 138 | 139 | Every model object built with `hydra.model.create` contains a hidden variable `api` that contains the API documentation. 140 | That object can be used to create model objects based on classes defined in the API documentation: 141 | 142 | ```javascript 143 | hydra.model.create(entryPoint.api.findClass('http://schema.org/BlogPost')) 144 | .then(function (blogPost) { 145 | }); 146 | ``` 147 | 148 | ### hydra.model.create(classes, properties, options) 149 | 150 | Creates a model object bases on a single or an `Array` of `hydra.Class` or `hydra.ClassDocument`. 151 | The properties object is merged into the model object. 152 | Additional options that control the model object building. 153 | 154 | ### hydra.model.hide(property) 155 | 156 | Adds a `@omit: true` key value pair to the property object and returns that property object. 157 | `property` must be an object. 158 | 159 | ### hydra.model.load(url, properties, options) 160 | 161 | Creates a model object based on the result of a `GET` request to the given `url`. 162 | The `properties` and `options` arguments will be forwarded to the `hydra.model.create` function. 163 | 164 | ### hydra.model.toJSON() 165 | 166 | A `toJSON` function that removes all functions and properties that contain a `@omit: true` key value pair. 167 | -------------------------------------------------------------------------------- /lib/core.js: -------------------------------------------------------------------------------- 1 | var 2 | utils = require('./utils'), 3 | _ = utils.require('lodash'), 4 | jsonldp = utils.require('jsonld').promises(); 5 | 6 | 7 | var hydra = {}; 8 | 9 | 10 | hydra.ns = { 11 | vocab: 'http://www.w3.org/ns/hydra/core#', 12 | apiDocumentation: 'http://www.w3.org/ns/hydra/core#apiDocumentation', 13 | member: 'http://www.w3.org/ns/hydra/core#member' 14 | }; 15 | 16 | 17 | var rdfs = { 18 | ns: { 19 | comment: 'http://www.w3.org/2000/01/rdf-schema#comment', 20 | label: 'http://www.w3.org/2000/01/rdf-schema#label', 21 | range: 'http://www.w3.org/2000/01/rdf-schema#range' 22 | } 23 | }; 24 | 25 | 26 | hydra.Api = function (def) { 27 | var self = this; 28 | 29 | this.iri = utils.iri(def); 30 | 31 | this.init = function () { 32 | var classFrameDef = { 33 | '@context': { 34 | '@vocab': hydra.ns.vocab, 35 | 'label': rdfs.ns.label 36 | }, 37 | '@type': 'Class' 38 | }; 39 | 40 | var operationFrameDef = { 41 | '@context': { 42 | '@vocab': hydra.ns.vocab, 43 | 'label': rdfs.ns.label 44 | }, 45 | '@type': 'Operation' 46 | }; 47 | 48 | return Promise.all([ 49 | jsonldp.frame(def, classFrameDef) 50 | .then(function (classDef) { 51 | self.classDef = classDef; 52 | }), 53 | jsonldp.frame(def, operationFrameDef) 54 | .then(function (operationDef) { 55 | self.operationDef = operationDef; 56 | })]) 57 | .then(function () { 58 | var inits = []; 59 | 60 | self.classes = self.classDef['@graph'].map(function (def) { 61 | var instance = new hydra.Class(self, def); 62 | 63 | inits.push(instance.init()); 64 | 65 | return instance; 66 | }); 67 | 68 | self.findClass = _.find.bind(null, self.classes, 'iri'); 69 | 70 | self.operations = self.operationDef['@graph'].map(function (def) { 71 | var instance = new hydra.Operation(self, def); 72 | 73 | inits.push(instance.init()); 74 | 75 | return instance; 76 | }); 77 | 78 | self.findOperation = _.find.bind(null, self.operations, 'iri'); 79 | 80 | return Promise.all(inits) 81 | .then(function () { 82 | return self; 83 | }); 84 | }); 85 | }; 86 | }; 87 | 88 | 89 | hydra.Document = function (api, def, iri) { 90 | var self = this; 91 | 92 | this.api = api; 93 | this.iri = iri || utils.iri(def); 94 | 95 | this.init = function () { 96 | return Promise.resolve() 97 | .then(function () { 98 | def = utils.unwrap(def); 99 | 100 | if (!('@type' in def)) { 101 | return Promise.reject('type missing'); 102 | } 103 | 104 | self.classes = _.values(def['@type']) 105 | .filter(function (type) { 106 | return !!self.api.findClass(type); 107 | }) 108 | .map(function (type) { 109 | return new hydra.ClassDocument(self, self.api.findClass(type), def); 110 | }); 111 | 112 | self.properties = self.classes 113 | .map(function (documentClass) { 114 | return documentClass.abstract.properties 115 | .filter(function (abstractProperty) { 116 | return abstractProperty.iri in def; 117 | }) 118 | .map(function (abstractProperty) { 119 | return new hydra.PropertyDocument(self, abstractProperty, def[abstractProperty.iri]); 120 | }); 121 | }) 122 | .reduce(function (properties, classProperties) { 123 | return properties.concat(classProperties); 124 | }, []); 125 | 126 | self.findProperty = _.find.bind(null, self.properties, 'iri'); 127 | 128 | self.findOperation = function() { 129 | if (arguments.length === 1) { 130 | var method = arguments[0]; 131 | 132 | return self.classes 133 | .map(function (documentClass) { 134 | return documentClass.findOperation(method); 135 | }) 136 | .shift(); 137 | } else { 138 | var iri = arguments[0]; 139 | var method = arguments[1]; 140 | 141 | var documentProperty = self.findProperty(iri); 142 | 143 | if (!documentProperty) { 144 | return undefined; 145 | } 146 | 147 | return documentProperty.findOperation(method); 148 | } 149 | }; 150 | 151 | return self; 152 | }); 153 | }; 154 | }; 155 | 156 | 157 | hydra.Class = function (api, def) { 158 | var self = this; 159 | 160 | self.api = api; 161 | self.iri = def['@id']; 162 | _.extend(self, def) 163 | 164 | self.init = function () { 165 | return Promise.resolve().then(function () { 166 | self.operations = utils.toArray(def.supportedOperation).map(function (operationDef) { 167 | return self.api.findOperation(operationDef['@id']); 168 | }); 169 | 170 | self.findOperation = _.find.bind(null, self.operations, 'method'); 171 | 172 | self.properties = utils.toArray(def.supportedProperty).map(function (propertyDef) { 173 | return new hydra.Property(self.api, propertyDef); 174 | }); 175 | 176 | self.findProperty = _.find.bind(null, self.properties, 'iri'); 177 | 178 | return self; 179 | }); 180 | }; 181 | 182 | self.validate = hydra.defaults.validateClass; 183 | }; 184 | 185 | 186 | hydra.ClassDocument = function (document, abstract, def) { 187 | this.document = document; 188 | this.iri = abstract.iri; 189 | this.abstract = abstract; 190 | this.label = this.abstract.label; 191 | this.operations = abstract.operations.map(function (operation) { 192 | return new hydra.OperationDocument(document, operation); 193 | }); 194 | this.properties = abstract.properties 195 | .filter(function (property) { 196 | return property.iri in def; 197 | }) 198 | .map(function (property) { 199 | return new hydra.PropertyDocument(document, property, def[property.iri]); 200 | }); 201 | 202 | this.findOperation = _.find.bind(null, this.operations, 'method'); 203 | 204 | this.findProperty = _.find.bind(null, this.properties, 'iri'); 205 | }; 206 | 207 | 208 | hydra.Operation = function (api, def) { 209 | var self = this; 210 | 211 | self.api = api; 212 | self.iri = def['@id']; 213 | _.extend(self, def) 214 | 215 | self.init = function () { 216 | return Promise.resolve().then(function () { 217 | self.method = def.method; 218 | self.statusCodes = def.statusCodes; 219 | self.expects = self.api.findClass(utils.iri(def.expects)); 220 | self.returns = self.api.findClass(utils.iri(def.returns)); 221 | 222 | return self; 223 | }); 224 | }; 225 | }; 226 | 227 | 228 | hydra.OperationDocument = function (document, abstract, def) { 229 | this.document = document; 230 | this.iri = abstract.iri; 231 | this.abstract = abstract; 232 | this.link = !!def ? utils.iri(def) : null; 233 | this.label = this.abstract.label; 234 | this.method = this.abstract.method; 235 | this.statusCodes = this.abstract.statusCodes; 236 | this.expects = this.abstract.expects; 237 | this.returns = this.abstract.returns; 238 | this.invoke = hydra.defaults.invokeOperation.bind(this); 239 | }; 240 | 241 | 242 | hydra.Property = function (api, def) { 243 | var self = this; 244 | 245 | self.api = api; 246 | self.iri = utils.iri(def.property); 247 | _.extend(self, def) 248 | 249 | self.operations = utils.toArray(def.property.supportedOperation) 250 | .map(function (operationDef) { 251 | return self.api.findOperation(utils.iri(operationDef)); 252 | }); 253 | 254 | self.findOperation = _.find.bind(null, self.operations, 'method'); 255 | }; 256 | 257 | 258 | hydra.PropertyDocument = function (document, abstract, def) { 259 | this.document = document; 260 | this.iri = abstract.iri; 261 | this.abstract = abstract; 262 | this.link = !!def ? utils.iri(def) : null; 263 | this.label = this.abstract.label; 264 | this.operations = abstract.operations.map(function (operation) { 265 | return new hydra.OperationDocument(document, operation, def); 266 | }); 267 | 268 | this.findOperation = _.find.bind(null, this.operations, 'method'); 269 | }; 270 | 271 | 272 | hydra.api = function (json, base) { 273 | if (_.isString(json)) { 274 | json = JSON.parse(json); 275 | } 276 | 277 | return jsonldp.expand(json, {base: base}) 278 | .then(function (compact) { 279 | return (new hydra.Api(compact)).init(); 280 | }); 281 | }; 282 | 283 | 284 | hydra.document = function (api, json, base) { 285 | if (_.isString(json)) { 286 | json = JSON.parse(json); 287 | } 288 | 289 | return jsonldp.expand(json, {base: base}) 290 | .then(function (compact) { 291 | return (new hydra.Document(api, compact, base)).init(); 292 | }); 293 | }; 294 | 295 | 296 | module.exports = hydra; 297 | -------------------------------------------------------------------------------- /lib/http-client.js: -------------------------------------------------------------------------------- 1 | var 2 | hydra = require('./core'), 3 | utils = require('./utils'), 4 | jsonld = utils.require('jsonld'), 5 | jsonldp = utils.require('jsonld').promises(); 6 | 7 | 8 | hydra.httpClient = {}; 9 | 10 | 11 | if (typeof XMLHttpRequest !== 'undefined') { 12 | /** 13 | * Converts a string to a UTF-8 encoded string 14 | * @param string The string to encode 15 | * @returns {string} The UTF-8 string 16 | */ 17 | hydra.httpClient.utf8Encode = function (string) { 18 | string = string.replace(/\r\n/g, '\n'); 19 | 20 | var utftext = ''; 21 | 22 | for (var n = 0; n < string.length; n++) { 23 | var c = string.charCodeAt(n); 24 | 25 | if (c < 128) { 26 | utftext += String.fromCharCode(c); 27 | } else if ((c > 127) && (c < 2048)) { 28 | utftext += String.fromCharCode((c >> 6) | 192); 29 | utftext += String.fromCharCode((c & 63) | 128); 30 | } else { 31 | utftext += String.fromCharCode((c >> 12) | 224); 32 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 33 | utftext += String.fromCharCode((c & 63) | 128); 34 | } 35 | } 36 | 37 | return utftext; 38 | }; 39 | 40 | /** 41 | * Converts a string to a base-64 encoded string 42 | * @param input The string to encode 43 | * @returns {string} The base-64 string 44 | */ 45 | hydra.httpClient.base64Encode = function (input) { 46 | var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; 47 | var output = ''; 48 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4; 49 | var i = 0; 50 | 51 | input = hydra.httpClient.utf8Encode(input); 52 | 53 | while (i < input.length) { 54 | chr1 = input.charCodeAt(i++); 55 | chr2 = input.charCodeAt(i++); 56 | chr3 = input.charCodeAt(i++); 57 | 58 | enc1 = chr1 >> 2; 59 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 60 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 61 | enc4 = chr3 & 63; 62 | 63 | if (isNaN(chr2)) { 64 | enc3 = enc4 = 64; 65 | } else if (isNaN(chr3)) { 66 | enc4 = 64; 67 | } 68 | 69 | output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4); 70 | } 71 | 72 | return output; 73 | }; 74 | 75 | /** 76 | * Request implementation using XMLHttpRequest interface 77 | * 78 | * @param method HTTP method 79 | * @param url URL 80 | * @param headers Header key/value pairs 81 | * @param content Content 82 | * @param callback Callback function using with interface: statusCode, headers, content, error 83 | */ 84 | hydra.httpClient.requestAsync = function (method, url, headers, content, callback, options) { 85 | options = options || {}; 86 | 87 | var xhr = new XMLHttpRequest(); 88 | 89 | xhr.onreadystatechange = function () { 90 | if (xhr.readyState === xhr.DONE) { 91 | var 92 | headerLines = xhr.getAllResponseHeaders().split('\r\n'), 93 | resHeaders = {}; 94 | 95 | for (var i = 0; i < headerLines.length; i++) { 96 | var headerLine = headerLines[i].split(': ', 2); 97 | resHeaders[headerLine[0].toLowerCase()] = headerLine[1]; 98 | } 99 | 100 | callback(xhr.status, resHeaders, xhr.responseText); 101 | } 102 | }; 103 | 104 | xhr.open(method, url, true); 105 | 106 | for (var header in headers) { 107 | xhr.setRequestHeader(header, headers[header]); 108 | } 109 | 110 | if (options.user && options.password) { 111 | xhr.setRequestHeader("Authorization", "Basic " + hydra.httpClient.base64Encode(options.user + ":" + options.password)); 112 | } 113 | 114 | xhr.send(content); 115 | }; 116 | } else { 117 | /** 118 | * Request implementation using the npm request module 119 | * 120 | * @param method HTTP method 121 | * @param url URL 122 | * @param headers Header key/value pairs 123 | * @param content Content 124 | * @param callback Callback function using with interface: statusCode, headers, content, error 125 | * @param options Additional options like user or password 126 | */ 127 | hydra.httpClient.requestAsync = function (method, url, headers, content, callback, options) { 128 | var request = require('request'); 129 | 130 | options = options || {}; 131 | 132 | var req = { 133 | method: method, 134 | url: url, 135 | headers: headers, 136 | body: content 137 | }; 138 | 139 | if (options.user && options.password) { 140 | req.auth = { 141 | user: options.user, 142 | password: options.password 143 | }; 144 | } 145 | 146 | request(req, function (error, res, body) { 147 | if (error) { 148 | callback(null, null, null, error); 149 | } else { 150 | callback(res.statusCode, res.headers, body); 151 | } 152 | }); 153 | }; 154 | } 155 | 156 | /** 157 | * Promise request implementation 158 | * 159 | * @param method HTTP method 160 | * @param url URL 161 | * @param headers Header key/value pairs 162 | * @param content Content 163 | * @param options Additional options like user or password 164 | * @returns {Promise} 165 | */ 166 | hydra.httpClient.request = function (method, url, headers, content, options) { 167 | return new Promise(function (resolve, reject) { 168 | hydra.httpClient.requestAsync(method, url, headers, content, function (status, resHeaders, resBody, error) { 169 | var response = { 170 | status: status, 171 | headers: resHeaders, 172 | body: resBody, 173 | request: { 174 | url: url, 175 | method: method, 176 | headers: headers, 177 | body: content 178 | } 179 | }; 180 | 181 | if (error) { 182 | reject(error); 183 | } else if (status >= 400) { 184 | reject(new Error('status code ' + status + ': ' + resBody)); 185 | } else { 186 | resolve(response); 187 | } 188 | }, options); 189 | }); 190 | }; 191 | 192 | /** 193 | * Extracts the Hydra API Documentation value of the Link header field 194 | * 195 | * @param headers 196 | * @param base 197 | * @returns {Promise} 198 | */ 199 | hydra.httpClient.apiLink = function (headers, base) { 200 | if (!('link' in headers)) { 201 | return Promise.resolve(undefined); 202 | } 203 | 204 | var rels = jsonld.parseLinkHeader(headers.link); 205 | 206 | if (!(hydra.ns.apiDocumentation in rels)) { 207 | return Promise.resolve(undefined); 208 | } 209 | 210 | return utils.expandIri(rels[hydra.ns.apiDocumentation].target, base); 211 | }; 212 | 213 | /** 214 | * Extracts the value of the Content-Location header field 215 | * 216 | * @param headers 217 | * @param base 218 | * @returns {*} 219 | */ 220 | hydra.httpClient.contentLocation = function (headers, base) { 221 | if (!('content-location' in headers)) { 222 | return Promise.resolve(undefined); 223 | } 224 | 225 | return utils.expandIri(headers['content-location'], base); 226 | }; 227 | 228 | /** 229 | * Calls an operations with the given headers and content 230 | * 231 | * @param headers 232 | * @param content 233 | * @param options 234 | * @returns {Promise} 235 | */ 236 | hydra.httpClient.rawInvoke = function (headers, content, options) { 237 | var self = this; 238 | 239 | var url = self.link || self.document.iri; 240 | 241 | return hydra.httpClient.request(self.method, url, headers, content, options); 242 | }; 243 | 244 | /** 245 | * Calls an operations with the JSON-LD content and converts the response body to JSON-LD 246 | * 247 | * @param content 248 | * @param options 249 | * @returns {Promise} 250 | */ 251 | hydra.httpClient.rawJsonLdInvoke = function (content, options) { 252 | var self = this; 253 | 254 | var headers = { 255 | 'Accept': 'application/ld+json' 256 | }; 257 | 258 | if (self.method === 'PATCH' || self.method === 'POST' || self.method === 'PUT') { 259 | headers['Content-Type'] = 'application/ld+json'; 260 | } 261 | 262 | return hydra.httpClient.rawInvoke.bind(self)(headers, JSON.stringify(content), options) 263 | .then(function (response) { 264 | if (response.body && response.body.trim() !== '') { 265 | return jsonldp.expand(JSON.parse(response.body), {base: response.request.url}) 266 | .then(function (expandedBody) { 267 | response.body = expandedBody; 268 | 269 | return response; 270 | }) 271 | } else { 272 | response.body = null; 273 | 274 | return response; 275 | } 276 | }); 277 | }; 278 | 279 | /** 280 | * Calls an operations with the JSON-LD content and returns the response body converted to JSON-LD 281 | * 282 | * @param content 283 | * @param options 284 | * @returns {Promise} 285 | */ 286 | hydra.httpClient.jsonLdInvoke = function (content, options) { 287 | var self = this; 288 | 289 | return hydra.httpClient.rawJsonLdInvoke.bind(self)(content, options) 290 | .then(function (response) { 291 | return response.body; 292 | }); 293 | }; 294 | -------------------------------------------------------------------------------- /dist/hydra-core.min.js: -------------------------------------------------------------------------------- 1 | !function(f){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=f();else if("function"==typeof define&&define.amd)define([],f);else{var g;g="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,g.hydra=f()}}(function(){return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;oc?utftext+=String.fromCharCode(c):c>127&&2048>c?(utftext+=String.fromCharCode(c>>6|192),utftext+=String.fromCharCode(63&c|128)):(utftext+=String.fromCharCode(c>>12|224),utftext+=String.fromCharCode(c>>6&63|128),utftext+=String.fromCharCode(63&c|128))}return utftext},hydra.httpClient.base64Encode=function(input){var chr1,chr2,chr3,enc1,enc2,enc3,enc4,keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",output="",i=0;for(input=hydra.httpClient.utf8Encode(input);i>2,enc2=(3&chr1)<<4|chr2>>4,enc3=(15&chr2)<<2|chr3>>6,enc4=63&chr3,isNaN(chr2)?enc3=enc4=64:isNaN(chr3)&&(enc4=64),output=output+keyStr.charAt(enc1)+keyStr.charAt(enc2)+keyStr.charAt(enc3)+keyStr.charAt(enc4);return output},hydra.httpClient.requestAsync=function(method,url,headers,content,callback,options){options=options||{};var xhr=new XMLHttpRequest;xhr.onreadystatechange=function(){if(xhr.readyState===xhr.DONE){for(var headerLines=xhr.getAllResponseHeaders().split("\r\n"),resHeaders={},i=0;i=400?reject(new Error("status code "+status+": "+resBody)):resolve(response)},options)})},hydra.httpClient.apiLink=function(headers,base){if(!("link"in headers))return Promise.resolve(void 0);var rels=jsonld.parseLinkHeader(headers.link);return hydra.ns.apiDocumentation in rels?utils.expandIri(rels[hydra.ns.apiDocumentation].target,base):Promise.resolve(void 0)},hydra.httpClient.contentLocation=function(headers,base){return"content-location"in headers?utils.expandIri(headers["content-location"],base):Promise.resolve(void 0)},hydra.httpClient.rawInvoke=function(headers,content,options){var self=this,url=self.link||self.document.iri;return hydra.httpClient.request(self.method,url,headers,content,options)},hydra.httpClient.rawJsonLdInvoke=function(content,options){var self=this,headers={Accept:"application/ld+json"};return("PATCH"===self.method||"POST"===self.method||"PUT"===self.method)&&(headers["Content-Type"]="application/ld+json"),hydra.httpClient.rawInvoke.bind(self)(headers,JSON.stringify(content),options).then(function(response){return response.body&&""!==response.body.trim()?jsonldp.expand(JSON.parse(response.body),{base:response.request.url}).then(function(expandedBody){return response.body=expandedBody,response}):(response.body=null,response)})},hydra.httpClient.jsonLdInvoke=function(content,options){var self=this;return hydra.httpClient.rawJsonLdInvoke.bind(self)(content,options).then(function(response){return response.body})}},{"./core":2,"./utils":5,request:void 0}],4:[function(require){var hydra=require("./core"),utils=require("./utils"),_=utils.require("lodash"),jsonldp=utils.require("jsonld").promises();hydra.model={},hydra.model.createHttpJsonLdInvoke=function(operation){return function(input,options){options=options||{};var context={};return"@context"in this&&(context=this["@context"]),context=options.context||context,input&&input.toJSON&&(input=input.toJSON()),hydra.httpClient.rawJsonLdInvoke.call(operation,input,options).then(function(response){return response.body?hydra.documentFromResponse(response).then(function(document){return jsonldp.compact(response.body,context).then(function(output){return hydra.model.create(document.classes,output)})}):Promise.resolve(null)})}},hydra.model.toJSON=function(){var copyProperties=function(object,root){if(!object)return null;var copy=_.keys(object).reduce(function(json,key){var value=object[key];return _.isFunction(value)?json:_.isObject(value)&&"@omit"in value&&value["@omit"]?json:(json[key]=_.isObject(value)?copyProperties(value,root):value,json)},{});return _.isArray(object)&&(copy=_.values(object)),copy};return copyProperties(this)},hydra.model.hide=function(property){return property["@omit"]=!0,property},hydra.model.create=function(classes,properties,options){var processOperations=function(root,operations){return operations.forEach(function(operation){var key="@"+operation.method.toLowerCase();key in root||(root[key]=options.createInvoke(operation).bind(model))}),Promise.resolve()},processProperties=function(root,properties){return Promise.all(properties.map(function(property){return utils.compactIri(property.iri,model["@context"]).then(function(key){return key in root||(root[key]={}),processOperations(root[key],property.operations)})}))},processClass=function(apiClass){return model["@type"].push(apiClass.iri),processOperations(model,apiClass.operations).then(function(){return processProperties(model,apiClass.properties)})};classes=utils.toArray(classes),options=options||{},options.createInvoke=options.createInvoke||hydra.defaults.model.createInvoke;var model=_.clone(properties);return _.defaults(model,{"@context":{},toJSON:hydra.model.toJSON}),model["@type"]=[],model.api=classes[0].api||classes[0]["abstract"].api,model.api["@omit"]=!0,classes[0].document&&(model.document=classes[0].document,model.document["@omit"]=!0),Promise.all(classes.map(function(apiClass){return processClass(apiClass)})).then(function(){return model})},hydra.model.load=function(url,properties,options){return hydra.loadDocument(url).then(function(document){return hydra.model.create(document.classes,properties,options)})}},{"./core":2,"./utils":5}],5:[function(require,module){var utils={};utils.require=function(module){var globalModule=module;return"lodash"===globalModule&&(globalModule="_"),"undefined"!=typeof window&&globalModule in window?window[globalModule]:require(module)};var _=utils.require("lodash"),jsonldp=utils.require("jsonld").promises();utils.collection=function(iri,members){return{"@id":iri,"@type":"http://www.w3.org/ns/hydra/core#Collection","http://www.w3.org/ns/hydra/core#member":_.values(members).map(function(member){return{"@id":member["@id"],"@type":member["@type"]}})}},utils.compactIri=function(iri,context){var dummy={};return dummy[iri]="",jsonldp.compact(dummy,context).then(function(compactDummy){return _.keys(compactDummy).pop()})},utils.expandIri=function(iri,base){if(!base)return Promise.resolve(iri);var dummy={"@context":{"@base":base,"@vocab":"http://schema.org/"},name:{"@id":iri}};return jsonldp.expand(dummy).then(function(expanded){return expanded[0]["http://schema.org/name"][0]["@id"]})},utils.iri=function(obj){return obj=utils.unwrap(obj),obj?_.isString(obj)?obj:"@id"in obj?obj["@id"]:void 0:void 0},utils.isCollection=function(collection){return _.isObject(collection)?!1:collection.member||ns.member in collection?!0:!1},utils.toArray=function(obj){return obj?(utils.isCollection(obj)&&(obj=obj.member),_.isArray(obj)?obj:[obj]):[]},utils.unwrap=function(obj){if(!obj)return void 0;if(_.isString(obj))return obj;if("@graph"in obj&&(obj=obj["@graph"]),_.isArray(obj)){if(0===obj.length)return void 0;obj=obj[0]}return obj},module.exports=utils},{}],6:[function(require){var hydra=require("./core"),utils=require("./utils"),jsonldp=utils.require("jsonld").promises();hydra.simpleValidateClass=function(object){var self=this;return object?jsonldp.expand(object).then(function(expanded){if(expanded.length>1)return Promise.reject(new Error("object contains multiple subjects"));if(expanded=expanded.shift(),!("@type"in expanded))return Promise.reject(new Error("@type missing"));if(utils.toArray(expanded["@type"]).indexOf(self.iri)<0)return Promise.reject(new Error("expected class <"+self.iri+">"));var error=self.properties.map(function(property){return property.readonly&&property.iri in object?new Error("readonly property <"+property.iri+'> filled with value "'+object[property.iri]+'"'):!1}).filter(function(error){return!!error}).shift();return error?Promise.reject(error):Promise.resolve()}):Promise.resolve()}},{"./core":2,"./utils":5}]},{},[1])(1)}); 2 | //# sourceMappingURL=hydra-core.min.js.map -------------------------------------------------------------------------------- /test/support/api.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": {"@vocab": "http://www.w3.org/ns/hydra/core#"}, 3 | "@id": "/hydra/api-demo/vocab", 4 | "@type": "ApiDocumentation", 5 | "supportedClass": [ 6 | { 7 | "@id": "http://www.w3.org/ns/hydra/core#Resource", 8 | "@type": "Class", 9 | "supportedOperation": [], 10 | "supportedProperty": [], 11 | "title": "Resource" 12 | }, 13 | { 14 | "@id": "http://www.w3.org/ns/hydra/core#Collection", 15 | "@type": "Class", 16 | "supportedProperty": { 17 | "description": "The members of this collection.", 18 | "property": {"@id": "http://www.w3.org/ns/hydra/core#member"}, 19 | "readonly": false, 20 | "title": "members", 21 | "writeonly": false 22 | }, 23 | "title": "Collection" 24 | }, 25 | { 26 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User", 27 | "@type": "Class", 28 | "http://www.w3.org/2000/01/rdf-schema#comment": "A User represents a person registered in the system.", 29 | "http://www.w3.org/2000/01/rdf-schema#label": "User", 30 | "supportedOperation": [ 31 | { 32 | "@type": "Operation", 33 | "http://www.w3.org/2000/01/rdf-schema#label": "Replaces an existing User entity", 34 | "expects": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 35 | "method": "PUT", 36 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 37 | "statusCodes": { 38 | "http://www.w3.org/2000/01/rdf-schema#comment": "If the User entity wasn't found.", 39 | "statusCode": 404 40 | } 41 | }, 42 | { 43 | "@type": "Operation", 44 | "http://www.w3.org/2000/01/rdf-schema#label": "Deletes a User entity", 45 | "method": "DELETE", 46 | "returns": {"@id": "http://www.w3.org/2002/07/owl#Nothing"}, 47 | "statusCodes": [] 48 | }, 49 | { 50 | "@type": "Operation", 51 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves a User entity", 52 | "method": "GET", 53 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 54 | "statusCodes": [] 55 | } 56 | ], 57 | "supportedProperty": [ 58 | { 59 | "description": "The user's full name", 60 | "property": { 61 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User/name", 62 | "@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property", 63 | "http://www.w3.org/2000/01/rdf-schema#comment": "The user's full name", 64 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 65 | "http://www.w3.org/2000/01/rdf-schema#label": "name", 66 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/2001/XMLSchema#string"}, 67 | "supportedOperation": [] 68 | }, 69 | "readonly": false, 70 | "title": "name", 71 | "writeonly": false 72 | }, 73 | { 74 | "description": "The user's email address", 75 | "property": { 76 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User/email", 77 | "@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property", 78 | "http://www.w3.org/2000/01/rdf-schema#comment": "The user's email address", 79 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 80 | "http://www.w3.org/2000/01/rdf-schema#label": "email", 81 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/2001/XMLSchema#string"}, 82 | "supportedOperation": [] 83 | }, 84 | "readonly": false, 85 | "title": "email", 86 | "writeonly": false 87 | }, 88 | { 89 | "description": "The user's password", 90 | "property": { 91 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User/password", 92 | "@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property", 93 | "http://www.w3.org/2000/01/rdf-schema#comment": "The user's password", 94 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 95 | "http://www.w3.org/2000/01/rdf-schema#label": "password", 96 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/2001/XMLSchema#string"}, 97 | "supportedOperation": [] 98 | }, 99 | "readonly": false, 100 | "title": "password", 101 | "writeonly": true 102 | }, 103 | { 104 | "description": "The issues raised by this user", 105 | "property": { 106 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User/raisedIssues", 107 | "@type": "Link", 108 | "http://www.w3.org/2000/01/rdf-schema#comment": "The issues raised by this user", 109 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 110 | "http://www.w3.org/2000/01/rdf-schema#label": "raised_issues", 111 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/ns/hydra/core#Collection"}, 112 | "supportedOperation": { 113 | "@type": "Operation", 114 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves the issues raised by a User entity", 115 | "method": "GET", 116 | "returns": {"@id": "http://www.w3.org/ns/hydra/core#Collection"}, 117 | "statusCodes": { 118 | "http://www.w3.org/2000/01/rdf-schema#comment": "If the User entity wasn't found.", 119 | "statusCode": 404 120 | } 121 | } 122 | }, 123 | "readonly": true, 124 | "title": "raised_issues", 125 | "writeonly": false 126 | } 127 | ] 128 | }, 129 | { 130 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue", 131 | "@type": "Class", 132 | "http://www.w3.org/2000/01/rdf-schema#comment": "An Issue tracked by the system.", 133 | "http://www.w3.org/2000/01/rdf-schema#label": "Issue", 134 | "supportedOperation": [ 135 | { 136 | "@type": "Operation", 137 | "http://www.w3.org/2000/01/rdf-schema#label": "Replaces an existing Issue entity", 138 | "expects": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 139 | "method": "PUT", 140 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 141 | "statusCodes": { 142 | "http://www.w3.org/2000/01/rdf-schema#comment": "If the Issue entity wasn't found.", 143 | "statusCode": 404 144 | } 145 | }, 146 | { 147 | "@type": "Operation", 148 | "http://www.w3.org/2000/01/rdf-schema#label": "Deletes a Issue entity", 149 | "method": "DELETE", 150 | "returns": {"@id": "http://www.w3.org/2002/07/owl#Nothing"}, 151 | "statusCodes": [] 152 | }, 153 | { 154 | "@type": "Operation", 155 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves a Issue entity", 156 | "method": "GET", 157 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 158 | "statusCodes": [] 159 | } 160 | ], 161 | "supportedProperty": [ 162 | { 163 | "description": "The issue's title", 164 | "property": { 165 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue/title", 166 | "@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property", 167 | "http://www.w3.org/2000/01/rdf-schema#comment": "The issue's title", 168 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 169 | "http://www.w3.org/2000/01/rdf-schema#label": "title", 170 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/2001/XMLSchema#string"}, 171 | "supportedOperation": [] 172 | }, 173 | "readonly": false, 174 | "title": "title", 175 | "writeonly": false 176 | }, 177 | { 178 | "description": "A description of the issue", 179 | "property": { 180 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue/description", 181 | "@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property", 182 | "http://www.w3.org/2000/01/rdf-schema#comment": "A description of the issue", 183 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 184 | "http://www.w3.org/2000/01/rdf-schema#label": "description", 185 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/2001/XMLSchema#string"}, 186 | "supportedOperation": [] 187 | }, 188 | "readonly": false, 189 | "title": "description", 190 | "writeonly": false 191 | }, 192 | { 193 | "description": "Is the issue open?\nUse for 1 yes, 0 for no when modifying this value.", 194 | "property": { 195 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#isOpen", 196 | "@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property", 197 | "http://www.w3.org/2000/01/rdf-schema#comment": "Is the issue open?\nUse for 1 yes, 0 for no when modifying this value.", 198 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 199 | "http://www.w3.org/2000/01/rdf-schema#label": "is_open", 200 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/2001/XMLSchema#boolean"}, 201 | "supportedOperation": [] 202 | }, 203 | "readonly": false, 204 | "title": "is_open", 205 | "writeonly": false 206 | }, 207 | { 208 | "description": "The user who raised the issue", 209 | "property": { 210 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue/raisedBy", 211 | "@type": "Link", 212 | "http://www.w3.org/2000/01/rdf-schema#comment": "The user who raised the issue", 213 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 214 | "http://www.w3.org/2000/01/rdf-schema#label": "raised_by", 215 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 216 | "supportedOperation": { 217 | "@type": "Operation", 218 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves a User entity", 219 | "method": "GET", 220 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 221 | "statusCodes": [] 222 | } 223 | }, 224 | "readonly": true, 225 | "title": "raised_by", 226 | "writeonly": false 227 | }, 228 | { 229 | "description": "The date and time this issue was created", 230 | "property": { 231 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue/createdAt", 232 | "@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property", 233 | "http://www.w3.org/2000/01/rdf-schema#comment": "The date and time this issue was created", 234 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 235 | "http://www.w3.org/2000/01/rdf-schema#label": "created_at", 236 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/2001/XMLSchema#dateTime"}, 237 | "supportedOperation": [] 238 | }, 239 | "readonly": true, 240 | "title": "created_at", 241 | "writeonly": false 242 | }, 243 | { 244 | "description": "The comments associated with this issue", 245 | "property": { 246 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue/comments", 247 | "@type": "Link", 248 | "http://www.w3.org/2000/01/rdf-schema#comment": "The comments associated with this issue", 249 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 250 | "http://www.w3.org/2000/01/rdf-schema#label": "comments", 251 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/ns/hydra/core#Collection"}, 252 | "supportedOperation": [ 253 | { 254 | "@type": "Operation", 255 | "http://www.w3.org/2000/01/rdf-schema#comment": "To create a new Comment you have to be authenticated.", 256 | "http://www.w3.org/2000/01/rdf-schema#label": "Creates a new Comment for a specific issue", 257 | "expects": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment"}, 258 | "method": "POST", 259 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment"}, 260 | "statusCodes": { 261 | "http://www.w3.org/2000/01/rdf-schema#comment": "If the Issue wasn't found.", 262 | "statusCode": 404 263 | } 264 | }, 265 | { 266 | "@type": "Operation", 267 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves all Comment entities for a specific issue", 268 | "method": "GET", 269 | "returns": {"@id": "http://www.w3.org/ns/hydra/core#Collection"}, 270 | "statusCodes": [] 271 | } 272 | ] 273 | }, 274 | "readonly": true, 275 | "title": "comments", 276 | "writeonly": false 277 | } 278 | ] 279 | }, 280 | { 281 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment", 282 | "@type": "Class", 283 | "http://www.w3.org/2000/01/rdf-schema#comment": "Comment", 284 | "http://www.w3.org/2000/01/rdf-schema#label": "Comment", 285 | "supportedOperation": [ 286 | { 287 | "@type": "Operation", 288 | "http://www.w3.org/2000/01/rdf-schema#label": "Replaces an existing Comment entity", 289 | "expects": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment"}, 290 | "method": "PUT", 291 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment"}, 292 | "statusCodes": { 293 | "http://www.w3.org/2000/01/rdf-schema#comment": "If the Comment entity wasn't found.", 294 | "statusCode": 404 295 | } 296 | }, 297 | { 298 | "@type": "Operation", 299 | "http://www.w3.org/2000/01/rdf-schema#label": "Deletes a Comment entity", 300 | "method": "DELETE", 301 | "returns": {"@id": "http://www.w3.org/2002/07/owl#Nothing"}, 302 | "statusCodes": [] 303 | }, 304 | { 305 | "@type": "Operation", 306 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves a Comment entity", 307 | "method": "GET", 308 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment"}, 309 | "statusCodes": [] 310 | } 311 | ], 312 | "supportedProperty": [ 313 | { 314 | "description": "The comment", 315 | "property": { 316 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment/text", 317 | "@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property", 318 | "http://www.w3.org/2000/01/rdf-schema#comment": "The comment", 319 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment"}, 320 | "http://www.w3.org/2000/01/rdf-schema#label": "text", 321 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/2001/XMLSchema#string"}, 322 | "supportedOperation": [] 323 | }, 324 | "readonly": false, 325 | "title": "text", 326 | "writeonly": false 327 | }, 328 | { 329 | "description": "The issue this comment belongs to", 330 | "property": { 331 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment/issue", 332 | "@type": "Link", 333 | "http://www.w3.org/2000/01/rdf-schema#comment": "The issue this comment belongs to", 334 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment"}, 335 | "http://www.w3.org/2000/01/rdf-schema#label": "issue", 336 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 337 | "supportedOperation": [ 338 | { 339 | "@type": "Operation", 340 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves a Issue entity", 341 | "method": "GET", 342 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 343 | "statusCodes": [] 344 | }, 345 | { 346 | "@type": "Operation", 347 | "http://www.w3.org/2000/01/rdf-schema#label": "Replaces an existing Issue entity", 348 | "expects": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 349 | "method": "PUT", 350 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 351 | "statusCodes": { 352 | "http://www.w3.org/2000/01/rdf-schema#comment": "If the Issue entity wasn't found.", 353 | "statusCode": 404 354 | } 355 | } 356 | ] 357 | }, 358 | "readonly": true, 359 | "title": "issue", 360 | "writeonly": false 361 | }, 362 | { 363 | "description": "The user who wrote this comment", 364 | "property": { 365 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment/user", 366 | "@type": "Link", 367 | "http://www.w3.org/2000/01/rdf-schema#comment": "The user who wrote this comment", 368 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment"}, 369 | "http://www.w3.org/2000/01/rdf-schema#label": "user", 370 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 371 | "supportedOperation": { 372 | "@type": "Operation", 373 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves a User entity", 374 | "method": "GET", 375 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 376 | "statusCodes": [] 377 | } 378 | }, 379 | "readonly": true, 380 | "title": "user", 381 | "writeonly": false 382 | }, 383 | { 384 | "description": "The date and time this comment was created", 385 | "property": { 386 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment/createdAt", 387 | "@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property", 388 | "http://www.w3.org/2000/01/rdf-schema#comment": "The date and time this comment was created", 389 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Comment"}, 390 | "http://www.w3.org/2000/01/rdf-schema#label": "created_at", 391 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/2001/XMLSchema#dateTime"}, 392 | "supportedOperation": [] 393 | }, 394 | "readonly": true, 395 | "title": "created_at", 396 | "writeonly": false 397 | } 398 | ] 399 | }, 400 | { 401 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint", 402 | "@type": "Class", 403 | "http://www.w3.org/2000/01/rdf-schema#comment": "The main entry point or homepage of the API.", 404 | "http://www.w3.org/2000/01/rdf-schema#label": "EntryPoint", 405 | "supportedOperation": { 406 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/GET", 407 | "@type": "Operation", 408 | "http://www.w3.org/2000/01/rdf-schema#label": "The APIs main entry point.", 409 | "method": "GET", 410 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint"}, 411 | "statusCodes": [] 412 | }, 413 | "supportedProperty": [ 414 | { 415 | "description": "The collection of all issues", 416 | "property": { 417 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/issues", 418 | "@type": "Link", 419 | "http://www.w3.org/2000/01/rdf-schema#comment": "The collection of all issues", 420 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint"}, 421 | "http://www.w3.org/2000/01/rdf-schema#label": "issues", 422 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/ns/hydra/core#Collection"}, 423 | "supportedOperation": [ 424 | { 425 | "@type": "Operation", 426 | "http://www.w3.org/2000/01/rdf-schema#label": "Creates a new Issue entity", 427 | "expects": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 428 | "method": "POST", 429 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#Issue"}, 430 | "statusCodes": { 431 | "http://www.w3.org/2000/01/rdf-schema#comment": "If the Issue entity was created successfully.", 432 | "statusCode": 201 433 | } 434 | }, 435 | { 436 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/issues/GET", 437 | "@type": "Operation", 438 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves all Issue entities", 439 | "method": "GET", 440 | "returns": {"@id": "http://www.w3.org/ns/hydra/core#Collection"}, 441 | "statusCodes": [] 442 | } 443 | ] 444 | }, 445 | "readonly": true, 446 | "title": "issues", 447 | "writeonly": false 448 | }, 449 | { 450 | "description": "IRI to register a new user", 451 | "property": { 452 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/registerUser", 453 | "@type": "Link", 454 | "http://www.w3.org/2000/01/rdf-schema#comment": "IRI to register a new user", 455 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint"}, 456 | "http://www.w3.org/2000/01/rdf-schema#label": "register_user", 457 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/ns/hydra/core#Resource"}, 458 | "supportedOperation": { 459 | "@type": "Operation", 460 | "http://www.w3.org/2000/01/rdf-schema#label": "Creates a new User entity", 461 | "expects": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 462 | "method": "POST", 463 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 464 | "statusCodes": { 465 | "http://www.w3.org/2000/01/rdf-schema#comment": "If the User entity was created successfully.", 466 | "statusCode": 201 467 | } 468 | } 469 | }, 470 | "readonly": true, 471 | "title": "register_user", 472 | "writeonly": false 473 | }, 474 | { 475 | "description": "If logged in, a link to the user account", 476 | "property": { 477 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/myAccount", 478 | "@type": "Link", 479 | "http://www.w3.org/2000/01/rdf-schema#comment": "If logged in, a link to the user account", 480 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint"}, 481 | "http://www.w3.org/2000/01/rdf-schema#label": "my_account", 482 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 483 | "supportedOperation": { 484 | "@type": "Operation", 485 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves a User entity", 486 | "method": "GET", 487 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 488 | "statusCodes": [] 489 | } 490 | }, 491 | "readonly": true, 492 | "title": "my_account", 493 | "writeonly": false 494 | }, 495 | { 496 | "description": "The collection of all users (for debugging purposes)", 497 | "property": { 498 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/users", 499 | "@type": "Link", 500 | "http://www.w3.org/2000/01/rdf-schema#comment": "The collection of all users (for debugging purposes)", 501 | "http://www.w3.org/2000/01/rdf-schema#domain": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint"}, 502 | "http://www.w3.org/2000/01/rdf-schema#label": "users", 503 | "http://www.w3.org/2000/01/rdf-schema#range": {"@id": "http://www.w3.org/ns/hydra/core#Collection"}, 504 | "supportedOperation": [ 505 | { 506 | "@type": "Operation", 507 | "http://www.w3.org/2000/01/rdf-schema#label": "Creates a new User entity", 508 | "expects": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 509 | "method": "POST", 510 | "returns": {"@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#User"}, 511 | "statusCodes": { 512 | "http://www.w3.org/2000/01/rdf-schema#comment": "If the User entity was created successfully.", 513 | "statusCode": 201 514 | } 515 | }, 516 | { 517 | "@id": "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/users/GET", 518 | "@type": "Operation", 519 | "http://www.w3.org/2000/01/rdf-schema#label": "Retrieves all User entities", 520 | "method": "GET", 521 | "returns": {"@id": "http://www.w3.org/ns/hydra/core#Collection"}, 522 | "statusCodes": [] 523 | } 524 | ] 525 | }, 526 | "readonly": true, 527 | "title": "users", 528 | "writeonly": false 529 | } 530 | ] 531 | } 532 | ] 533 | } -------------------------------------------------------------------------------- /dist/hydra-core.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [ 4 | "node_modules/browserify/node_modules/browser-pack/_prelude.js", 5 | "hydra-core.js", 6 | "lib/core.js", 7 | "lib/http-client.js", 8 | "lib/model.js", 9 | "lib/utils.js", 10 | "lib/validation.js" 11 | ], 12 | "names": [], 13 | "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1SA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", 14 | "file": "generated.js", 15 | "sourceRoot": "", 16 | "sourcesContent": [ 17 | "(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o 127) && (c < 2048)) {\n utftext += String.fromCharCode((c >> 6) | 192);\n utftext += String.fromCharCode((c & 63) | 128);\n } else {\n utftext += String.fromCharCode((c >> 12) | 224);\n utftext += String.fromCharCode(((c >> 6) & 63) | 128);\n utftext += String.fromCharCode((c & 63) | 128);\n }\n }\n\n return utftext;\n };\n\n /**\n * Converts a string to a base-64 encoded string\n * @param input The string to encode\n * @returns {string} The base-64 string\n */\n hydra.httpClient.base64Encode = function (input) {\n var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';\n var output = '';\n var chr1, chr2, chr3, enc1, enc2, enc3, enc4;\n var i = 0;\n\n input = hydra.httpClient.utf8Encode(input);\n\n while (i < input.length) {\n chr1 = input.charCodeAt(i++);\n chr2 = input.charCodeAt(i++);\n chr3 = input.charCodeAt(i++);\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);\n }\n\n return output;\n };\n\n /**\n * Request implementation using XMLHttpRequest interface\n *\n * @param method HTTP method\n * @param url URL\n * @param headers Header key/value pairs\n * @param content Content\n * @param callback Callback function using with interface: statusCode, headers, content, error\n */\n hydra.httpClient.requestAsync = function (method, url, headers, content, callback, options) {\n options = options || {};\n\n var xhr = new XMLHttpRequest();\n\n xhr.onreadystatechange = function () {\n if (xhr.readyState === xhr.DONE) {\n var\n headerLines = xhr.getAllResponseHeaders().split('\\r\\n'),\n resHeaders = {};\n\n for (var i = 0; i < headerLines.length; i++) {\n var headerLine = headerLines[i].split(': ', 2);\n resHeaders[headerLine[0].toLowerCase()] = headerLine[1];\n }\n\n callback(xhr.status, resHeaders, xhr.responseText);\n }\n };\n\n xhr.open(method, url, true);\n\n for (var header in headers) {\n xhr.setRequestHeader(header, headers[header]);\n }\n\n if (options.user && options.password) {\n xhr.setRequestHeader(\"Authorization\", \"Basic \" + hydra.httpClient.base64Encode(options.user + \":\" + options.password));\n }\n\n xhr.send(content);\n };\n} else {\n /**\n * Request implementation using the npm request module\n *\n * @param method HTTP method\n * @param url URL\n * @param headers Header key/value pairs\n * @param content Content\n * @param callback Callback function using with interface: statusCode, headers, content, error\n * @param options Additional options like user or password\n */\n hydra.httpClient.requestAsync = function (method, url, headers, content, callback, options) {\n var request = require('request');\n\n options = options || {};\n\n var req = {\n method: method,\n url: url,\n headers: headers,\n body: content\n };\n\n if (options.user && options.password) {\n req.auth = {\n user: options.user,\n password: options.password\n };\n }\n\n request(req, function (error, res, body) {\n if (error) {\n callback(null, null, null, error);\n } else {\n callback(res.statusCode, res.headers, body);\n }\n });\n };\n}\n\n/**\n * Promise request implementation\n *\n * @param method HTTP method\n * @param url URL\n * @param headers Header key/value pairs\n * @param content Content\n * @param options Additional options like user or password\n * @returns {Promise}\n */\nhydra.httpClient.request = function (method, url, headers, content, options) {\n return new Promise(function (resolve, reject) {\n hydra.httpClient.requestAsync(method, url, headers, content, function (status, resHeaders, resBody, error) {\n var response = {\n status: status,\n headers: resHeaders,\n body: resBody,\n request: {\n url: url,\n method: method,\n headers: headers,\n body: content\n }\n };\n\n if (error) {\n reject(error);\n } else if (status >= 400) {\n reject(new Error('status code ' + status + ': ' + resBody));\n } else {\n resolve(response);\n }\n }, options);\n });\n};\n\n/**\n * Extracts the Hydra API Documentation value of the Link header field\n *\n * @param headers\n * @param base\n * @returns {Promise}\n */\nhydra.httpClient.apiLink = function (headers, base) {\n if (!('link' in headers)) {\n return Promise.resolve(undefined);\n }\n\n var rels = jsonld.parseLinkHeader(headers.link);\n\n if (!(hydra.ns.apiDocumentation in rels)) {\n return Promise.resolve(undefined);\n }\n\n return utils.expandIri(rels[hydra.ns.apiDocumentation].target, base);\n};\n\n/**\n * Extracts the value of the Content-Location header field\n *\n * @param headers\n * @param base\n * @returns {*}\n */\nhydra.httpClient.contentLocation = function (headers, base) {\n if (!('content-location' in headers)) {\n return Promise.resolve(undefined);\n }\n\n return utils.expandIri(headers['content-location'], base);\n};\n\n/**\n * Calls an operations with the given headers and content\n *\n * @param headers\n * @param content\n * @param options\n * @returns {Promise}\n */\nhydra.httpClient.rawInvoke = function (headers, content, options) {\n var self = this;\n\n var url = self.link || self.document.iri;\n\n return hydra.httpClient.request(self.method, url, headers, content, options);\n};\n\n/**\n * Calls an operations with the JSON-LD content and converts the response body to JSON-LD\n *\n * @param content\n * @param options\n * @returns {Promise}\n */\nhydra.httpClient.rawJsonLdInvoke = function (content, options) {\n var self = this;\n\n var headers = {\n 'Accept': 'application/ld+json'\n };\n\n if (self.method === 'PATCH' || self.method === 'POST' || self.method === 'PUT') {\n headers['Content-Type'] = 'application/ld+json';\n }\n\n return hydra.httpClient.rawInvoke.bind(self)(headers, JSON.stringify(content), options)\n .then(function (response) {\n if (response.body && response.body.trim() !== '') {\n return jsonldp.expand(JSON.parse(response.body), {base: response.request.url})\n .then(function (expandedBody) {\n response.body = expandedBody;\n\n return response;\n })\n } else {\n response.body = null;\n\n return response;\n }\n });\n};\n\n/**\n * Calls an operations with the JSON-LD content and returns the response body converted to JSON-LD\n *\n * @param content\n * @param options\n * @returns {Promise}\n */\nhydra.httpClient.jsonLdInvoke = function (content, options) {\n var self = this;\n\n return hydra.httpClient.rawJsonLdInvoke.bind(self)(content, options)\n .then(function (response) {\n return response.body;\n });\n};\n", 21 | "var\n hydra = require('./core'),\n utils = require('./utils'),\n _ = utils.require('lodash'),\n jsonldp = utils.require('jsonld').promises();\n\n\nhydra.model = {};\n\n\n/**\n * Creates an invoke function for model objects that compacts the response using the given context\n *\n * @param operation\n * @returns {Function}\n */\nhydra.model.createHttpJsonLdInvoke = function (operation) {\n return function (input, options) {\n options = options || {};\n\n var context = {};\n\n if ('@context' in this) {\n context = this['@context'];\n }\n\n context = options.context || context;\n\n if (input && input.toJSON) {\n input = input.toJSON();\n }\n\n return hydra.httpClient.rawJsonLdInvoke.call(operation, input, options)\n .then(function (response) {\n if (!response.body) {\n return Promise.resolve(null);\n }\n\n return hydra.documentFromResponse(response)\n .then(function (document) {\n return jsonldp.compact(response.body, context)\n .then(function (output) {\n return hydra.model.create(document.classes, output);\n });\n });\n });\n };\n};\n\n/**\n * Converts a model object to serializable object without functions and property flagged with @omit\n */\nhydra.model.toJSON = function () {\n var copyProperties = function (object, root) {\n if (!object) {\n return null;\n }\n\n var copy = _.keys(object).reduce(function (json, key) {\n var value = object[key];\n\n // don't add function properties\n if (_.isFunction(value)) {\n return json;\n }\n\n // don't add properties with @omit flag\n if (_.isObject(value) && '@omit' in value && value['@omit']) {\n return json;\n }\n\n if (_.isObject(value)) {\n // copy sub properties\n json[key] = copyProperties(value, root);\n } else {\n // copy string values\n json[key] = value;\n }\n\n return json;\n }, {});\n\n // convert to Array if original object was an Array\n if (_.isArray(object)) {\n copy = _.values(object);\n }\n\n return copy;\n };\n\n return copyProperties(this);\n};\n\n/**\n * Adds a @omit property to an object to hide it from serialization\n *\n * @param property\n * @returns {Object}\n */\nhydra.model.hide = function (property) {\n property['@omit'] = true;\n\n return property;\n};\n\n/**\n * Creates a model object based on one or more classes\n *\n * @param classes The class or classes the model will be bases on\n * @param properties Properties to merge into the model object\n * @param options Additional options to control the model creation\n * @returns {*}\n */\nhydra.model.create = function (classes, properties, options) {\n var processOperations = function (root, operations) {\n operations.forEach(function (operation) {\n var key = '@' + operation.method.toLowerCase();\n\n if (!(key in root)) {\n root[key] = options.createInvoke(operation).bind(model);\n }\n });\n\n return Promise.resolve();\n };\n\n var processProperties = function (root, properties) {\n return Promise.all(properties.map(function (property) {\n return utils.compactIri(property.iri, model['@context'])\n .then(function (key) {\n if (!(key in root)) {\n root[key] = {};\n }\n\n return processOperations(root[key], property.operations);\n });\n }));\n };\n\n var processClass = function (apiClass) {\n model['@type'].push(apiClass.iri);\n\n return processOperations(model, apiClass.operations)\n .then(function () {\n return processProperties(model, apiClass.properties);\n });\n };\n\n classes = utils.toArray(classes);\n\n options = options || {};\n options.createInvoke = options.createInvoke || hydra.defaults.model.createInvoke;\n\n var model = _.clone(properties);\n\n _.defaults(model, {\n '@context': {},\n toJSON: hydra.model.toJSON\n });\n\n model['@type'] = [];\n model.api = classes[0].api || classes[0].abstract.api;\n model.api['@omit'] = true;\n\n if (classes[0].document) {\n model.document = classes[0].document;\n model.document['@omit'] = true;\n }\n\n return Promise.all(classes.map(function (apiClass) {\n return processClass(apiClass);\n })).then(function () {\n return model;\n });\n};\n\n/**\n * Creates a model object based on a GET request to the given URL\n *\n * @param url URL\n * @param properties Properties that will be merged into the model object\n * @param options Options for the request\n * @returns {Promise}\n */\nhydra.model.load = function (url, properties, options) {\n return hydra.loadDocument(url)\n .then(function (document) {\n return hydra.model.create(document.classes, properties, options);\n });\n};\n", 22 | "var utils = {};\n\n\nutils.require = function (module) {\n var globalModule = module;\n\n if (globalModule === 'lodash') {\n globalModule = '_';\n }\n\n if (typeof window !== 'undefined' && globalModule in window) {\n return window[globalModule];\n }\n\n return require(module);\n};\n\n\nvar\n _ = utils.require('lodash'),\n jsonldp = utils.require('jsonld').promises();\n\n\n/**\n * Creates a Hydra Collection from a map or array of members\n *\n * @param iri\n * @param members\n * @returns {Collection}\n */\nutils.collection = function (iri, members) {\n return {\n '@id': iri,\n '@type': 'http://www.w3.org/ns/hydra/core#Collection',\n 'http://www.w3.org/ns/hydra/core#member': _.values(members).map(function (member) {\n return {\n '@id': member['@id'],\n '@type': member['@type']\n };\n })\n };\n};\n\n/**\n * Uses the given context to create a short form of the IRI\n *\n * @param iri\n * @param context\n * @returns {Promise}\n */\nutils.compactIri = function (iri, context) {\n var dummy = {};\n\n dummy[iri] = '';\n\n return jsonldp.compact(dummy, context)\n .then(function (compactDummy) {\n return _.keys(compactDummy).pop();\n });\n};\n\n/**\n * Creates a long version of the IRI using the given base\n *\n * @param iri\n * @param base\n * @returns {Promise}\n */\nutils.expandIri = function (iri, base) {\n if (!base) {\n return Promise.resolve(iri);\n }\n\n var dummy = {\n '@context': {\n '@base': base,\n '@vocab': 'http://schema.org/'\n },\n 'name': {\n '@id': iri\n }\n };\n\n return jsonldp.expand(dummy)\n .then(function (expanded) {\n return expanded[0]['http://schema.org/name'][0]['@id'];\n });\n};\n\n/**\n * Extracts the IRI of an JSON-LD object\n *\n * @param obj\n * @returns {*}\n */\nutils.iri = function (obj) {\n obj = utils.unwrap(obj);\n\n if (!obj) {\n return undefined;\n }\n\n if (_.isString(obj)) {\n return obj;\n }\n\n if (!('@id' in obj)) {\n return undefined;\n }\n\n return obj['@id'];\n};\n\n/**\n * Checks if the given object is a Hydra Collection\n *\n * @param collection\n * @returns {boolean}\n */\nutils.isCollection = function (collection) {\n if (_.isObject(collection)) {\n return false;\n }\n\n if (!collection.member && !(ns.member in collection)) {\n return false;\n }\n\n return true;\n};\n\n/**\n * Converts single objects and Hydra Collections to Arrays and forwards existing Arrays\n *\n * @param obj\n * @returns {Array}\n */\nutils.toArray = function (obj) {\n if (!obj) {\n return [];\n }\n\n if (utils.isCollection(obj)) {\n obj = obj.member;\n }\n\n if (!_.isArray(obj)) {\n return [obj];\n }\n\n return obj;\n};\n\n/**\n * Extracts the first subject of an JSON-Ld object\n *\n * @param obj\n * @returns {*}\n */\nutils.unwrap = function (obj) {\n if (!obj) {\n return undefined;\n }\n\n if (_.isString(obj)) {\n return obj;\n }\n\n if ('@graph' in obj) {\n obj = obj['@graph'];\n }\n\n if (_.isArray(obj)) {\n if (obj.length === 0) {\n return undefined;\n } else {\n obj = obj[0];\n }\n }\n\n return obj;\n};\n\n\nmodule.exports = utils;", 23 | "var\n hydra = require('./core'),\n utils = require('./utils'),\n jsonldp = utils.require('jsonld').promises();\n\n\nhydra.simpleValidateClass = function (object, read, write) {\n var self = this;\n\n if (!object) {\n return Promise.resolve();\n }\n\n return jsonldp.expand(object)\n .then(function (expanded) {\n if (expanded.length > 1) {\n return Promise.reject(new Error('object contains multiple subjects'));\n }\n\n expanded = expanded.shift();\n\n if (!('@type' in expanded)) {\n return Promise.reject(new Error('@type missing'));\n }\n\n if (utils.toArray(expanded['@type']).indexOf(self.iri) < 0) {\n return Promise.reject(new Error('expected class <' + self.iri + '>'));\n }\n\n var error = self.properties\n .map(function (property) {\n if (property.readonly && property.iri in object) {\n return new Error('readonly property <' + property.iri + '> filled with value \"' + object[property.iri] + '\"');\n }\n\n return false;\n })\n .filter(function (error) {\n return !!error;\n })\n .shift();\n\n if (error) {\n return Promise.reject(error);\n }\n\n return Promise.resolve();\n });\n};\n\n" 24 | ] 25 | } -------------------------------------------------------------------------------- /dist/hydra-core.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.hydra = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 127) && (c < 2048)) { 395 | utftext += String.fromCharCode((c >> 6) | 192); 396 | utftext += String.fromCharCode((c & 63) | 128); 397 | } else { 398 | utftext += String.fromCharCode((c >> 12) | 224); 399 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 400 | utftext += String.fromCharCode((c & 63) | 128); 401 | } 402 | } 403 | 404 | return utftext; 405 | }; 406 | 407 | /** 408 | * Converts a string to a base-64 encoded string 409 | * @param input The string to encode 410 | * @returns {string} The base-64 string 411 | */ 412 | hydra.httpClient.base64Encode = function (input) { 413 | var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; 414 | var output = ''; 415 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4; 416 | var i = 0; 417 | 418 | input = hydra.httpClient.utf8Encode(input); 419 | 420 | while (i < input.length) { 421 | chr1 = input.charCodeAt(i++); 422 | chr2 = input.charCodeAt(i++); 423 | chr3 = input.charCodeAt(i++); 424 | 425 | enc1 = chr1 >> 2; 426 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 427 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 428 | enc4 = chr3 & 63; 429 | 430 | if (isNaN(chr2)) { 431 | enc3 = enc4 = 64; 432 | } else if (isNaN(chr3)) { 433 | enc4 = 64; 434 | } 435 | 436 | output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4); 437 | } 438 | 439 | return output; 440 | }; 441 | 442 | /** 443 | * Request implementation using XMLHttpRequest interface 444 | * 445 | * @param method HTTP method 446 | * @param url URL 447 | * @param headers Header key/value pairs 448 | * @param content Content 449 | * @param callback Callback function using with interface: statusCode, headers, content, error 450 | */ 451 | hydra.httpClient.requestAsync = function (method, url, headers, content, callback, options) { 452 | options = options || {}; 453 | 454 | var xhr = new XMLHttpRequest(); 455 | 456 | xhr.onreadystatechange = function () { 457 | if (xhr.readyState === xhr.DONE) { 458 | var 459 | headerLines = xhr.getAllResponseHeaders().split('\r\n'), 460 | resHeaders = {}; 461 | 462 | for (var i = 0; i < headerLines.length; i++) { 463 | var headerLine = headerLines[i].split(': ', 2); 464 | resHeaders[headerLine[0].toLowerCase()] = headerLine[1]; 465 | } 466 | 467 | callback(xhr.status, resHeaders, xhr.responseText); 468 | } 469 | }; 470 | 471 | xhr.open(method, url, true); 472 | 473 | for (var header in headers) { 474 | xhr.setRequestHeader(header, headers[header]); 475 | } 476 | 477 | if (options.user && options.password) { 478 | xhr.setRequestHeader("Authorization", "Basic " + hydra.httpClient.base64Encode(options.user + ":" + options.password)); 479 | } 480 | 481 | xhr.send(content); 482 | }; 483 | } else { 484 | /** 485 | * Request implementation using the npm request module 486 | * 487 | * @param method HTTP method 488 | * @param url URL 489 | * @param headers Header key/value pairs 490 | * @param content Content 491 | * @param callback Callback function using with interface: statusCode, headers, content, error 492 | * @param options Additional options like user or password 493 | */ 494 | hydra.httpClient.requestAsync = function (method, url, headers, content, callback, options) { 495 | var request = require('request'); 496 | 497 | options = options || {}; 498 | 499 | var req = { 500 | method: method, 501 | url: url, 502 | headers: headers, 503 | body: content 504 | }; 505 | 506 | if (options.user && options.password) { 507 | req.auth = { 508 | user: options.user, 509 | password: options.password 510 | }; 511 | } 512 | 513 | request(req, function (error, res, body) { 514 | if (error) { 515 | callback(null, null, null, error); 516 | } else { 517 | callback(res.statusCode, res.headers, body); 518 | } 519 | }); 520 | }; 521 | } 522 | 523 | /** 524 | * Promise request implementation 525 | * 526 | * @param method HTTP method 527 | * @param url URL 528 | * @param headers Header key/value pairs 529 | * @param content Content 530 | * @param options Additional options like user or password 531 | * @returns {Promise} 532 | */ 533 | hydra.httpClient.request = function (method, url, headers, content, options) { 534 | return new Promise(function (resolve, reject) { 535 | hydra.httpClient.requestAsync(method, url, headers, content, function (status, resHeaders, resBody, error) { 536 | var response = { 537 | status: status, 538 | headers: resHeaders, 539 | body: resBody, 540 | request: { 541 | url: url, 542 | method: method, 543 | headers: headers, 544 | body: content 545 | } 546 | }; 547 | 548 | if (error) { 549 | reject(error); 550 | } else if (status >= 400) { 551 | reject(new Error('status code ' + status + ': ' + resBody)); 552 | } else { 553 | resolve(response); 554 | } 555 | }, options); 556 | }); 557 | }; 558 | 559 | /** 560 | * Extracts the Hydra API Documentation value of the Link header field 561 | * 562 | * @param headers 563 | * @param base 564 | * @returns {Promise} 565 | */ 566 | hydra.httpClient.apiLink = function (headers, base) { 567 | if (!('link' in headers)) { 568 | return Promise.resolve(undefined); 569 | } 570 | 571 | var rels = jsonld.parseLinkHeader(headers.link); 572 | 573 | if (!(hydra.ns.apiDocumentation in rels)) { 574 | return Promise.resolve(undefined); 575 | } 576 | 577 | return utils.expandIri(rels[hydra.ns.apiDocumentation].target, base); 578 | }; 579 | 580 | /** 581 | * Extracts the value of the Content-Location header field 582 | * 583 | * @param headers 584 | * @param base 585 | * @returns {*} 586 | */ 587 | hydra.httpClient.contentLocation = function (headers, base) { 588 | if (!('content-location' in headers)) { 589 | return Promise.resolve(undefined); 590 | } 591 | 592 | return utils.expandIri(headers['content-location'], base); 593 | }; 594 | 595 | /** 596 | * Calls an operations with the given headers and content 597 | * 598 | * @param headers 599 | * @param content 600 | * @param options 601 | * @returns {Promise} 602 | */ 603 | hydra.httpClient.rawInvoke = function (headers, content, options) { 604 | var self = this; 605 | 606 | var url = self.link || self.document.iri; 607 | 608 | return hydra.httpClient.request(self.method, url, headers, content, options); 609 | }; 610 | 611 | /** 612 | * Calls an operations with the JSON-LD content and converts the response body to JSON-LD 613 | * 614 | * @param content 615 | * @param options 616 | * @returns {Promise} 617 | */ 618 | hydra.httpClient.rawJsonLdInvoke = function (content, options) { 619 | var self = this; 620 | 621 | var headers = { 622 | 'Accept': 'application/ld+json' 623 | }; 624 | 625 | if (self.method === 'PATCH' || self.method === 'POST' || self.method === 'PUT') { 626 | headers['Content-Type'] = 'application/ld+json'; 627 | } 628 | 629 | return hydra.httpClient.rawInvoke.bind(self)(headers, JSON.stringify(content), options) 630 | .then(function (response) { 631 | if (response.body && response.body.trim() !== '') { 632 | return jsonldp.expand(JSON.parse(response.body), {base: response.request.url}) 633 | .then(function (expandedBody) { 634 | response.body = expandedBody; 635 | 636 | return response; 637 | }) 638 | } else { 639 | response.body = null; 640 | 641 | return response; 642 | } 643 | }); 644 | }; 645 | 646 | /** 647 | * Calls an operations with the JSON-LD content and returns the response body converted to JSON-LD 648 | * 649 | * @param content 650 | * @param options 651 | * @returns {Promise} 652 | */ 653 | hydra.httpClient.jsonLdInvoke = function (content, options) { 654 | var self = this; 655 | 656 | return hydra.httpClient.rawJsonLdInvoke.bind(self)(content, options) 657 | .then(function (response) { 658 | return response.body; 659 | }); 660 | }; 661 | 662 | },{"./core":2,"./utils":5,"request":undefined}],4:[function(require,module,exports){ 663 | var 664 | hydra = require('./core'), 665 | utils = require('./utils'), 666 | _ = utils.require('lodash'), 667 | jsonldp = utils.require('jsonld').promises(); 668 | 669 | 670 | hydra.model = {}; 671 | 672 | 673 | /** 674 | * Creates an invoke function for model objects that compacts the response using the given context 675 | * 676 | * @param operation 677 | * @returns {Function} 678 | */ 679 | hydra.model.createHttpJsonLdInvoke = function (operation) { 680 | return function (input, options) { 681 | options = options || {}; 682 | 683 | var context = {}; 684 | 685 | if ('@context' in this) { 686 | context = this['@context']; 687 | } 688 | 689 | context = options.context || context; 690 | 691 | if (input && input.toJSON) { 692 | input = input.toJSON(); 693 | } 694 | 695 | return hydra.httpClient.rawJsonLdInvoke.call(operation, input, options) 696 | .then(function (response) { 697 | if (!response.body) { 698 | return Promise.resolve(null); 699 | } 700 | 701 | return hydra.documentFromResponse(response) 702 | .then(function (document) { 703 | return jsonldp.compact(response.body, context) 704 | .then(function (output) { 705 | return hydra.model.create(document.classes, output); 706 | }); 707 | }); 708 | }); 709 | }; 710 | }; 711 | 712 | /** 713 | * Converts a model object to serializable object without functions and property flagged with @omit 714 | */ 715 | hydra.model.toJSON = function () { 716 | var copyProperties = function (object, root) { 717 | if (!object) { 718 | return null; 719 | } 720 | 721 | var copy = _.keys(object).reduce(function (json, key) { 722 | var value = object[key]; 723 | 724 | // don't add function properties 725 | if (_.isFunction(value)) { 726 | return json; 727 | } 728 | 729 | // don't add properties with @omit flag 730 | if (_.isObject(value) && '@omit' in value && value['@omit']) { 731 | return json; 732 | } 733 | 734 | if (_.isObject(value)) { 735 | // copy sub properties 736 | json[key] = copyProperties(value, root); 737 | } else { 738 | // copy string values 739 | json[key] = value; 740 | } 741 | 742 | return json; 743 | }, {}); 744 | 745 | // convert to Array if original object was an Array 746 | if (_.isArray(object)) { 747 | copy = _.values(object); 748 | } 749 | 750 | return copy; 751 | }; 752 | 753 | return copyProperties(this); 754 | }; 755 | 756 | /** 757 | * Adds a @omit property to an object to hide it from serialization 758 | * 759 | * @param property 760 | * @returns {Object} 761 | */ 762 | hydra.model.hide = function (property) { 763 | property['@omit'] = true; 764 | 765 | return property; 766 | }; 767 | 768 | /** 769 | * Creates a model object based on one or more classes 770 | * 771 | * @param classes The class or classes the model will be bases on 772 | * @param properties Properties to merge into the model object 773 | * @param options Additional options to control the model creation 774 | * @returns {*} 775 | */ 776 | hydra.model.create = function (classes, properties, options) { 777 | var processOperations = function (root, operations) { 778 | operations.forEach(function (operation) { 779 | var key = '@' + operation.method.toLowerCase(); 780 | 781 | if (!(key in root)) { 782 | root[key] = options.createInvoke(operation).bind(model); 783 | } 784 | }); 785 | 786 | return Promise.resolve(); 787 | }; 788 | 789 | var processProperties = function (root, properties) { 790 | return Promise.all(properties.map(function (property) { 791 | return utils.compactIri(property.iri, model['@context']) 792 | .then(function (key) { 793 | if (!(key in root)) { 794 | root[key] = {}; 795 | } 796 | 797 | return processOperations(root[key], property.operations); 798 | }); 799 | })); 800 | }; 801 | 802 | var processClass = function (apiClass) { 803 | model['@type'].push(apiClass.iri); 804 | 805 | return processOperations(model, apiClass.operations) 806 | .then(function () { 807 | return processProperties(model, apiClass.properties); 808 | }); 809 | }; 810 | 811 | classes = utils.toArray(classes); 812 | 813 | options = options || {}; 814 | options.createInvoke = options.createInvoke || hydra.defaults.model.createInvoke; 815 | 816 | var model = _.clone(properties); 817 | 818 | _.defaults(model, { 819 | '@context': {}, 820 | toJSON: hydra.model.toJSON 821 | }); 822 | 823 | model['@type'] = []; 824 | model.api = classes[0].api || classes[0].abstract.api; 825 | model.api['@omit'] = true; 826 | 827 | if (classes[0].document) { 828 | model.document = classes[0].document; 829 | model.document['@omit'] = true; 830 | } 831 | 832 | return Promise.all(classes.map(function (apiClass) { 833 | return processClass(apiClass); 834 | })).then(function () { 835 | return model; 836 | }); 837 | }; 838 | 839 | /** 840 | * Creates a model object based on a GET request to the given URL 841 | * 842 | * @param url URL 843 | * @param properties Properties that will be merged into the model object 844 | * @param options Options for the request 845 | * @returns {Promise} 846 | */ 847 | hydra.model.load = function (url, properties, options) { 848 | return hydra.loadDocument(url) 849 | .then(function (document) { 850 | return hydra.model.create(document.classes, properties, options); 851 | }); 852 | }; 853 | 854 | },{"./core":2,"./utils":5}],5:[function(require,module,exports){ 855 | var utils = {}; 856 | 857 | 858 | utils.require = function (module) { 859 | var globalModule = module; 860 | 861 | if (globalModule === 'lodash') { 862 | globalModule = '_'; 863 | } 864 | 865 | if (typeof window !== 'undefined' && globalModule in window) { 866 | return window[globalModule]; 867 | } 868 | 869 | return require(module); 870 | }; 871 | 872 | 873 | var 874 | _ = utils.require('lodash'), 875 | jsonldp = utils.require('jsonld').promises(); 876 | 877 | 878 | /** 879 | * Creates a Hydra Collection from a map or array of members 880 | * 881 | * @param iri 882 | * @param members 883 | * @returns {Collection} 884 | */ 885 | utils.collection = function (iri, members) { 886 | return { 887 | '@id': iri, 888 | '@type': 'http://www.w3.org/ns/hydra/core#Collection', 889 | 'http://www.w3.org/ns/hydra/core#member': _.values(members).map(function (member) { 890 | return { 891 | '@id': member['@id'], 892 | '@type': member['@type'] 893 | }; 894 | }) 895 | }; 896 | }; 897 | 898 | /** 899 | * Uses the given context to create a short form of the IRI 900 | * 901 | * @param iri 902 | * @param context 903 | * @returns {Promise} 904 | */ 905 | utils.compactIri = function (iri, context) { 906 | var dummy = {}; 907 | 908 | dummy[iri] = ''; 909 | 910 | return jsonldp.compact(dummy, context) 911 | .then(function (compactDummy) { 912 | return _.keys(compactDummy).pop(); 913 | }); 914 | }; 915 | 916 | /** 917 | * Creates a long version of the IRI using the given base 918 | * 919 | * @param iri 920 | * @param base 921 | * @returns {Promise} 922 | */ 923 | utils.expandIri = function (iri, base) { 924 | if (!base) { 925 | return Promise.resolve(iri); 926 | } 927 | 928 | var dummy = { 929 | '@context': { 930 | '@base': base, 931 | '@vocab': 'http://schema.org/' 932 | }, 933 | 'name': { 934 | '@id': iri 935 | } 936 | }; 937 | 938 | return jsonldp.expand(dummy) 939 | .then(function (expanded) { 940 | return expanded[0]['http://schema.org/name'][0]['@id']; 941 | }); 942 | }; 943 | 944 | /** 945 | * Extracts the IRI of an JSON-LD object 946 | * 947 | * @param obj 948 | * @returns {*} 949 | */ 950 | utils.iri = function (obj) { 951 | obj = utils.unwrap(obj); 952 | 953 | if (!obj) { 954 | return undefined; 955 | } 956 | 957 | if (_.isString(obj)) { 958 | return obj; 959 | } 960 | 961 | if (!('@id' in obj)) { 962 | return undefined; 963 | } 964 | 965 | return obj['@id']; 966 | }; 967 | 968 | /** 969 | * Checks if the given object is a Hydra Collection 970 | * 971 | * @param collection 972 | * @returns {boolean} 973 | */ 974 | utils.isCollection = function (collection) { 975 | if (_.isObject(collection)) { 976 | return false; 977 | } 978 | 979 | if (!collection.member && !(ns.member in collection)) { 980 | return false; 981 | } 982 | 983 | return true; 984 | }; 985 | 986 | /** 987 | * Converts single objects and Hydra Collections to Arrays and forwards existing Arrays 988 | * 989 | * @param obj 990 | * @returns {Array} 991 | */ 992 | utils.toArray = function (obj) { 993 | if (!obj) { 994 | return []; 995 | } 996 | 997 | if (utils.isCollection(obj)) { 998 | obj = obj.member; 999 | } 1000 | 1001 | if (!_.isArray(obj)) { 1002 | return [obj]; 1003 | } 1004 | 1005 | return obj; 1006 | }; 1007 | 1008 | /** 1009 | * Extracts the first subject of an JSON-Ld object 1010 | * 1011 | * @param obj 1012 | * @returns {*} 1013 | */ 1014 | utils.unwrap = function (obj) { 1015 | if (!obj) { 1016 | return undefined; 1017 | } 1018 | 1019 | if (_.isString(obj)) { 1020 | return obj; 1021 | } 1022 | 1023 | if ('@graph' in obj) { 1024 | obj = obj['@graph']; 1025 | } 1026 | 1027 | if (_.isArray(obj)) { 1028 | if (obj.length === 0) { 1029 | return undefined; 1030 | } else { 1031 | obj = obj[0]; 1032 | } 1033 | } 1034 | 1035 | return obj; 1036 | }; 1037 | 1038 | 1039 | module.exports = utils; 1040 | },{}],6:[function(require,module,exports){ 1041 | var 1042 | hydra = require('./core'), 1043 | utils = require('./utils'), 1044 | jsonldp = utils.require('jsonld').promises(); 1045 | 1046 | 1047 | hydra.simpleValidateClass = function (object, read, write) { 1048 | var self = this; 1049 | 1050 | if (!object) { 1051 | return Promise.resolve(); 1052 | } 1053 | 1054 | return jsonldp.expand(object) 1055 | .then(function (expanded) { 1056 | if (expanded.length > 1) { 1057 | return Promise.reject(new Error('object contains multiple subjects')); 1058 | } 1059 | 1060 | expanded = expanded.shift(); 1061 | 1062 | if (!('@type' in expanded)) { 1063 | return Promise.reject(new Error('@type missing')); 1064 | } 1065 | 1066 | if (utils.toArray(expanded['@type']).indexOf(self.iri) < 0) { 1067 | return Promise.reject(new Error('expected class <' + self.iri + '>')); 1068 | } 1069 | 1070 | var error = self.properties 1071 | .map(function (property) { 1072 | if (property.readonly && property.iri in object) { 1073 | return new Error('readonly property <' + property.iri + '> filled with value "' + object[property.iri] + '"'); 1074 | } 1075 | 1076 | return false; 1077 | }) 1078 | .filter(function (error) { 1079 | return !!error; 1080 | }) 1081 | .shift(); 1082 | 1083 | if (error) { 1084 | return Promise.reject(error); 1085 | } 1086 | 1087 | return Promise.resolve(); 1088 | }); 1089 | }; 1090 | 1091 | 1092 | },{"./core":2,"./utils":5}]},{},[1])(1) 1093 | }); -------------------------------------------------------------------------------- /dist/hydra-core.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"generated.js","sources":["node_modules/browserify/node_modules/browser-pack/_prelude.js","hydra-core.js","lib/core.js","lib/http-client.js","lib/model.js","lib/utils.js","lib/validation.js"],"names":["f","exports","module","define","amd","g","window","global","self","this","hydra","e","t","n","r","s","o","u","a","require","i","Error","code","l","call","length",1,"utils","loadApi","url","httpClient","request","then","response","api","body","iri","documentFromResponse","apiLink","headers","apiUrl","document","contentLocation","loadDocument","defaults","invokeOperation","jsonLdInvoke","validateClass","simpleValidateClass","model","createInvoke","createHttpJsonLdInvoke","rawJsonLdInvoke","_","jsonldp","promises","ns","vocab","apiDocumentation","member","rdfs","comment","label","range","Api","def","init","classFrameDef","@context","@vocab","@type","operationFrameDef","Promise","all","frame","classDef","operationDef","inits","classes","map","instance","Class","push","findClass","find","bind","operations","Operation","findOperation","Document","resolve","unwrap","values","filter","type","ClassDocument","properties","documentClass","abstractProperty","PropertyDocument","reduce","classProperties","concat","findProperty","arguments","method","shift","documentProperty","undefined","reject","toArray","supportedOperation","supportedProperty","propertyDef","Property","validate","abstract","operation","OperationDocument","property","statusCodes","expects","returns","link","invoke","title","description","readonly","writeonly","json","base","isString","JSON","parse","expand","compact","jsonld","XMLHttpRequest","utf8Encode","string","replace","utftext","c","charCodeAt","String","fromCharCode","base64Encode","input","chr1","chr2","chr3","enc1","enc2","enc3","enc4","keyStr","output","isNaN","charAt","requestAsync","content","callback","options","xhr","onreadystatechange","readyState","DONE","headerLines","getAllResponseHeaders","split","resHeaders","headerLine","toLowerCase","status","responseText","open","header","setRequestHeader","user","password","send","req","auth","error","res","statusCode","resBody","rels","parseLinkHeader","expandIri","target","rawInvoke","Accept","stringify","trim","expandedBody","context","toJSON","create","copyProperties","object","root","copy","keys","key","value","isFunction","isObject","isArray","hide","processOperations","forEach","processProperties","compactIri","processClass","apiClass","clone","load","globalModule","collection","members","@id","http://www.w3.org/ns/hydra/core#member","dummy","compactDummy","pop","@base","name","expanded","obj","isCollection","indexOf"],"mappings":"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AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1SA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACrSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9LA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o 127) && (c < 2048)) {\n utftext += String.fromCharCode((c >> 6) | 192);\n utftext += String.fromCharCode((c & 63) | 128);\n } else {\n utftext += String.fromCharCode((c >> 12) | 224);\n utftext += String.fromCharCode(((c >> 6) & 63) | 128);\n utftext += String.fromCharCode((c & 63) | 128);\n }\n }\n\n return utftext;\n };\n\n /**\n * Converts a string to a base-64 encoded string\n * @param input The string to encode\n * @returns {string} The base-64 string\n */\n hydra.httpClient.base64Encode = function (input) {\n var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';\n var output = '';\n var chr1, chr2, chr3, enc1, enc2, enc3, enc4;\n var i = 0;\n\n input = hydra.httpClient.utf8Encode(input);\n\n while (i < input.length) {\n chr1 = input.charCodeAt(i++);\n chr2 = input.charCodeAt(i++);\n chr3 = input.charCodeAt(i++);\n\n enc1 = chr1 >> 2;\n enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n enc4 = chr3 & 63;\n\n if (isNaN(chr2)) {\n enc3 = enc4 = 64;\n } else if (isNaN(chr3)) {\n enc4 = 64;\n }\n\n output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);\n }\n\n return output;\n };\n\n /**\n * Request implementation using XMLHttpRequest interface\n *\n * @param method HTTP method\n * @param url URL\n * @param headers Header key/value pairs\n * @param content Content\n * @param callback Callback function using with interface: statusCode, headers, content, error\n */\n hydra.httpClient.requestAsync = function (method, url, headers, content, callback, options) {\n options = options || {};\n\n var xhr = new XMLHttpRequest();\n\n xhr.onreadystatechange = function () {\n if (xhr.readyState === xhr.DONE) {\n var\n headerLines = xhr.getAllResponseHeaders().split('\\r\\n'),\n resHeaders = {};\n\n for (var i = 0; i < headerLines.length; i++) {\n var headerLine = headerLines[i].split(': ', 2);\n resHeaders[headerLine[0].toLowerCase()] = headerLine[1];\n }\n\n callback(xhr.status, resHeaders, xhr.responseText);\n }\n };\n\n xhr.open(method, url, true);\n\n for (var header in headers) {\n xhr.setRequestHeader(header, headers[header]);\n }\n\n if (options.user && options.password) {\n xhr.setRequestHeader(\"Authorization\", \"Basic \" + hydra.httpClient.base64Encode(options.user + \":\" + options.password));\n }\n\n xhr.send(content);\n };\n} else {\n /**\n * Request implementation using the npm request module\n *\n * @param method HTTP method\n * @param url URL\n * @param headers Header key/value pairs\n * @param content Content\n * @param callback Callback function using with interface: statusCode, headers, content, error\n * @param options Additional options like user or password\n */\n hydra.httpClient.requestAsync = function (method, url, headers, content, callback, options) {\n var request = require('request');\n\n options = options || {};\n\n var req = {\n method: method,\n url: url,\n headers: headers,\n body: content\n };\n\n if (options.user && options.password) {\n req.auth = {\n user: options.user,\n password: options.password\n };\n }\n\n request(req, function (error, res, body) {\n if (error) {\n callback(null, null, null, error);\n } else {\n callback(res.statusCode, res.headers, body);\n }\n });\n };\n}\n\n/**\n * Promise request implementation\n *\n * @param method HTTP method\n * @param url URL\n * @param headers Header key/value pairs\n * @param content Content\n * @param options Additional options like user or password\n * @returns {Promise}\n */\nhydra.httpClient.request = function (method, url, headers, content, options) {\n return new Promise(function (resolve, reject) {\n hydra.httpClient.requestAsync(method, url, headers, content, function (status, resHeaders, resBody, error) {\n var response = {\n status: status,\n headers: resHeaders,\n body: resBody,\n request: {\n url: url,\n method: method,\n headers: headers,\n body: content\n }\n };\n\n if (error) {\n reject(error);\n } else if (status >= 400) {\n reject(new Error('status code ' + status + ': ' + resBody));\n } else {\n resolve(response);\n }\n }, options);\n });\n};\n\n/**\n * Extracts the Hydra API Documentation value of the Link header field\n *\n * @param headers\n * @param base\n * @returns {Promise}\n */\nhydra.httpClient.apiLink = function (headers, base) {\n if (!('link' in headers)) {\n return Promise.resolve(undefined);\n }\n\n var rels = jsonld.parseLinkHeader(headers.link);\n\n if (!(hydra.ns.apiDocumentation in rels)) {\n return Promise.resolve(undefined);\n }\n\n return utils.expandIri(rels[hydra.ns.apiDocumentation].target, base);\n};\n\n/**\n * Extracts the value of the Content-Location header field\n *\n * @param headers\n * @param base\n * @returns {*}\n */\nhydra.httpClient.contentLocation = function (headers, base) {\n if (!('content-location' in headers)) {\n return Promise.resolve(undefined);\n }\n\n return utils.expandIri(headers['content-location'], base);\n};\n\n/**\n * Calls an operations with the given headers and content\n *\n * @param headers\n * @param content\n * @param options\n * @returns {Promise}\n */\nhydra.httpClient.rawInvoke = function (headers, content, options) {\n var self = this;\n\n var url = self.link || self.document.iri;\n\n return hydra.httpClient.request(self.method, url, headers, content, options);\n};\n\n/**\n * Calls an operations with the JSON-LD content and converts the response body to JSON-LD\n *\n * @param content\n * @param options\n * @returns {Promise}\n */\nhydra.httpClient.rawJsonLdInvoke = function (content, options) {\n var self = this;\n\n var headers = {\n 'Accept': 'application/ld+json'\n };\n\n if (self.method === 'PATCH' || self.method === 'POST' || self.method === 'PUT') {\n headers['Content-Type'] = 'application/ld+json';\n }\n\n return hydra.httpClient.rawInvoke.bind(self)(headers, JSON.stringify(content), options)\n .then(function (response) {\n if (response.body && response.body.trim() !== '') {\n return jsonldp.expand(JSON.parse(response.body), {base: response.request.url})\n .then(function (expandedBody) {\n response.body = expandedBody;\n\n return response;\n })\n } else {\n response.body = null;\n\n return response;\n }\n });\n};\n\n/**\n * Calls an operations with the JSON-LD content and returns the response body converted to JSON-LD\n *\n * @param content\n * @param options\n * @returns {Promise}\n */\nhydra.httpClient.jsonLdInvoke = function (content, options) {\n var self = this;\n\n return hydra.httpClient.rawJsonLdInvoke.bind(self)(content, options)\n .then(function (response) {\n return response.body;\n });\n};\n","var\n hydra = require('./core'),\n utils = require('./utils'),\n _ = utils.require('lodash'),\n jsonldp = utils.require('jsonld').promises();\n\n\nhydra.model = {};\n\n\n/**\n * Creates an invoke function for model objects that compacts the response using the given context\n *\n * @param operation\n * @returns {Function}\n */\nhydra.model.createHttpJsonLdInvoke = function (operation) {\n return function (input, options) {\n options = options || {};\n\n var context = {};\n\n if ('@context' in this) {\n context = this['@context'];\n }\n\n context = options.context || context;\n\n if (input && input.toJSON) {\n input = input.toJSON();\n }\n\n return hydra.httpClient.rawJsonLdInvoke.call(operation, input, options)\n .then(function (response) {\n if (!response.body) {\n return Promise.resolve(null);\n }\n\n return hydra.documentFromResponse(response)\n .then(function (document) {\n return jsonldp.compact(response.body, context)\n .then(function (output) {\n return hydra.model.create(document.classes, output);\n });\n });\n });\n };\n};\n\n/**\n * Converts a model object to serializable object without functions and property flagged with @omit\n */\nhydra.model.toJSON = function () {\n var copyProperties = function (object, root) {\n if (!object) {\n return null;\n }\n\n var copy = _.keys(object).reduce(function (json, key) {\n var value = object[key];\n\n // don't add function properties\n if (_.isFunction(value)) {\n return json;\n }\n\n // don't add properties with @omit flag\n if (_.isObject(value) && '@omit' in value && value['@omit']) {\n return json;\n }\n\n if (_.isObject(value)) {\n // copy sub properties\n json[key] = copyProperties(value, root);\n } else {\n // copy string values\n json[key] = value;\n }\n\n return json;\n }, {});\n\n // convert to Array if original object was an Array\n if (_.isArray(object)) {\n copy = _.values(object);\n }\n\n return copy;\n };\n\n return copyProperties(this);\n};\n\n/**\n * Adds a @omit property to an object to hide it from serialization\n *\n * @param property\n * @returns {Object}\n */\nhydra.model.hide = function (property) {\n property['@omit'] = true;\n\n return property;\n};\n\n/**\n * Creates a model object based on one or more classes\n *\n * @param classes The class or classes the model will be bases on\n * @param properties Properties to merge into the model object\n * @param options Additional options to control the model creation\n * @returns {*}\n */\nhydra.model.create = function (classes, properties, options) {\n var processOperations = function (root, operations) {\n operations.forEach(function (operation) {\n var key = '@' + operation.method.toLowerCase();\n\n if (!(key in root)) {\n root[key] = options.createInvoke(operation).bind(model);\n }\n });\n\n return Promise.resolve();\n };\n\n var processProperties = function (root, properties) {\n return Promise.all(properties.map(function (property) {\n return utils.compactIri(property.iri, model['@context'])\n .then(function (key) {\n if (!(key in root)) {\n root[key] = {};\n }\n\n return processOperations(root[key], property.operations);\n });\n }));\n };\n\n var processClass = function (apiClass) {\n model['@type'].push(apiClass.iri);\n\n return processOperations(model, apiClass.operations)\n .then(function () {\n return processProperties(model, apiClass.properties);\n });\n };\n\n classes = utils.toArray(classes);\n\n options = options || {};\n options.createInvoke = options.createInvoke || hydra.defaults.model.createInvoke;\n\n var model = _.clone(properties);\n\n _.defaults(model, {\n '@context': {},\n toJSON: hydra.model.toJSON\n });\n\n model['@type'] = [];\n model.api = classes[0].api || classes[0].abstract.api;\n model.api['@omit'] = true;\n\n if (classes[0].document) {\n model.document = classes[0].document;\n model.document['@omit'] = true;\n }\n\n return Promise.all(classes.map(function (apiClass) {\n return processClass(apiClass);\n })).then(function () {\n return model;\n });\n};\n\n/**\n * Creates a model object based on a GET request to the given URL\n *\n * @param url URL\n * @param properties Properties that will be merged into the model object\n * @param options Options for the request\n * @returns {Promise}\n */\nhydra.model.load = function (url, properties, options) {\n return hydra.loadDocument(url)\n .then(function (document) {\n return hydra.model.create(document.classes, properties, options);\n });\n};\n","var utils = {};\n\n\nutils.require = function (module) {\n var globalModule = module;\n\n if (globalModule === 'lodash') {\n globalModule = '_';\n }\n\n if (typeof window !== 'undefined' && globalModule in window) {\n return window[globalModule];\n }\n\n return require(module);\n};\n\n\nvar\n _ = utils.require('lodash'),\n jsonldp = utils.require('jsonld').promises();\n\n\n/**\n * Creates a Hydra Collection from a map or array of members\n *\n * @param iri\n * @param members\n * @returns {Collection}\n */\nutils.collection = function (iri, members) {\n return {\n '@id': iri,\n '@type': 'http://www.w3.org/ns/hydra/core#Collection',\n 'http://www.w3.org/ns/hydra/core#member': _.values(members).map(function (member) {\n return {\n '@id': member['@id'],\n '@type': member['@type']\n };\n })\n };\n};\n\n/**\n * Uses the given context to create a short form of the IRI\n *\n * @param iri\n * @param context\n * @returns {Promise}\n */\nutils.compactIri = function (iri, context) {\n var dummy = {};\n\n dummy[iri] = '';\n\n return jsonldp.compact(dummy, context)\n .then(function (compactDummy) {\n return _.keys(compactDummy).pop();\n });\n};\n\n/**\n * Creates a long version of the IRI using the given base\n *\n * @param iri\n * @param base\n * @returns {Promise}\n */\nutils.expandIri = function (iri, base) {\n if (!base) {\n return Promise.resolve(iri);\n }\n\n var dummy = {\n '@context': {\n '@base': base,\n '@vocab': 'http://schema.org/'\n },\n 'name': {\n '@id': iri\n }\n };\n\n return jsonldp.expand(dummy)\n .then(function (expanded) {\n return expanded[0]['http://schema.org/name'][0]['@id'];\n });\n};\n\n/**\n * Extracts the IRI of an JSON-LD object\n *\n * @param obj\n * @returns {*}\n */\nutils.iri = function (obj) {\n obj = utils.unwrap(obj);\n\n if (!obj) {\n return undefined;\n }\n\n if (_.isString(obj)) {\n return obj;\n }\n\n if (!('@id' in obj)) {\n return undefined;\n }\n\n return obj['@id'];\n};\n\n/**\n * Checks if the given object is a Hydra Collection\n *\n * @param collection\n * @returns {boolean}\n */\nutils.isCollection = function (collection) {\n if (_.isObject(collection)) {\n return false;\n }\n\n if (!collection.member && !(ns.member in collection)) {\n return false;\n }\n\n return true;\n};\n\n/**\n * Converts single objects and Hydra Collections to Arrays and forwards existing Arrays\n *\n * @param obj\n * @returns {Array}\n */\nutils.toArray = function (obj) {\n if (!obj) {\n return [];\n }\n\n if (utils.isCollection(obj)) {\n obj = obj.member;\n }\n\n if (!_.isArray(obj)) {\n return [obj];\n }\n\n return obj;\n};\n\n/**\n * Extracts the first subject of an JSON-Ld object\n *\n * @param obj\n * @returns {*}\n */\nutils.unwrap = function (obj) {\n if (!obj) {\n return undefined;\n }\n\n if (_.isString(obj)) {\n return obj;\n }\n\n if ('@graph' in obj) {\n obj = obj['@graph'];\n }\n\n if (_.isArray(obj)) {\n if (obj.length === 0) {\n return undefined;\n } else {\n obj = obj[0];\n }\n }\n\n return obj;\n};\n\n\nmodule.exports = utils;","var\n hydra = require('./core'),\n utils = require('./utils'),\n jsonldp = utils.require('jsonld').promises();\n\n\nhydra.simpleValidateClass = function (object, read, write) {\n var self = this;\n\n if (!object) {\n return Promise.resolve();\n }\n\n return jsonldp.expand(object)\n .then(function (expanded) {\n if (expanded.length > 1) {\n return Promise.reject(new Error('object contains multiple subjects'));\n }\n\n expanded = expanded.shift();\n\n if (!('@type' in expanded)) {\n return Promise.reject(new Error('@type missing'));\n }\n\n if (utils.toArray(expanded['@type']).indexOf(self.iri) < 0) {\n return Promise.reject(new Error('expected class <' + self.iri + '>'));\n }\n\n var error = self.properties\n .map(function (property) {\n if (property.readonly && property.iri in object) {\n return new Error('readonly property <' + property.iri + '> filled with value \"' + object[property.iri] + '\"');\n }\n\n return false;\n })\n .filter(function (error) {\n return !!error;\n })\n .shift();\n\n if (error) {\n return Promise.reject(error);\n }\n\n return Promise.resolve();\n });\n};\n\n"]} --------------------------------------------------------------------------------