diff --git a/.eslintrc.js b/.eslintrc.js index d0ee50e..7421837 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,16 +1,24 @@ module.exports = { - 'env': { + env: { 'browser': true, 'commonjs': true, 'es6': true, 'jest': true, 'node': true, }, - 'parser': 'babel-eslint', - 'parserOptions': { + parser: 'babel-eslint', + parserOptions: { ecmaVersion: 7, sourceType: 'module' }, - 'plugins': ['import'], - 'extends': 'eslint:recommended', + plugins: ['import', 'flowtype', 'prettier'], + + extends: [ + "plugin:prettier/recommended", + ], + + rules: { + "prettier/prettier": "error" + }, + }; diff --git a/.flowconfig b/.flowconfig index 4a58bdc..6c76730 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,4 +1,5 @@ [ignore] +.*/node_modules/.* [include] diff --git a/package.json b/package.json index f5c4e28..010ed82 100644 --- a/package.json +++ b/package.json @@ -24,10 +24,14 @@ "babel-preset-es2015": "^6.24.0", "babel-preset-stage-0": "^6.22.0", "eslint": "^3.18.0", + "eslint-config-prettier": "^2.9.0", + "eslint-plugin-flowtype": "^2.47.1", "eslint-plugin-import": "^2.2.0", + "eslint-plugin-prettier": "^2.6.0", "flow-bin": "^0.42.0", "jest": "^20.0.0", - "jest-fetch-mock": "^1.0.8" + "jest-fetch-mock": "^1.0.8", + "prettier": "^1.12.1" }, "dependencies": { "babel-runtime": "^6.23.0", @@ -37,6 +41,8 @@ "scripts": { "test": "jest", "lint": "eslint src && flow check", + "fix": "eslint --fix src", + "eslint-check": "eslint --print-config .eslintrc.js | eslint-config-prettier-check", "build": "babel src -d lib --ignore '*.test.js'" }, "jest": { diff --git a/src/Api.js b/src/Api.js index 413689e..df17533 100644 --- a/src/Api.js +++ b/src/Api.js @@ -1,11 +1,11 @@ // @flow -import Resource from './Resource'; +import Resource from "./Resource"; type ApiOptions = { title?: string, - resources?: Map, -} + resources?: Map +}; /** * @property {string} entrypoint - The URL of the API's entrypoint @@ -20,12 +20,12 @@ export default class Api { constructor(entrypoint: string, options: ApiOptions = {}) { this.entrypoint = entrypoint; - Object.keys(options).forEach((key) => { + Object.keys(options).forEach(key => { Object.defineProperty(this, key, { readable: true, writable: true, enumerable: true, - value: options[key], + value: options[key] }); }); } diff --git a/src/Field.js b/src/Field.js index cbd3640..1fd19ad 100644 --- a/src/Field.js +++ b/src/Field.js @@ -7,7 +7,8 @@ type FieldOptions = { required?: boolean, description?: string, maxCardinality?: number, -} + deprecated?: boolean +}; /** * @property {string} name - The name of this field @@ -22,12 +23,12 @@ export default class Field { constructor(name: string, options: FieldOptions = {}) { this.name = name; - Object.keys(options).forEach((key) => { + Object.keys(options).forEach(key => { Object.defineProperty(this, key, { readable: true, writable: true, enumerable: true, - value: options[key], + value: options[key] }); }); } diff --git a/src/Operation.js b/src/Operation.js index 30619f0..bcf2edc 100644 --- a/src/Operation.js +++ b/src/Operation.js @@ -4,7 +4,8 @@ type OperationOptions = { method?: string, returns?: string, types?: Array, -} + deprecated?: boolean +}; /** * @property {string} name - The name of this operation @@ -19,12 +20,12 @@ export default class Operation { constructor(name: string, options: OperationOptions = {}) { this.name = name; - Object.keys(options).forEach((key) => { + Object.keys(options).forEach(key => { Object.defineProperty(this, key, { readable: true, writable: true, enumerable: true, - value: options[key], + value: options[key] }); }); } diff --git a/src/Resource.js b/src/Resource.js index 9b846d8..868c094 100644 --- a/src/Resource.js +++ b/src/Resource.js @@ -1,14 +1,15 @@ // @flow -import Field from './Field'; -import Operation from './Operation'; +import Field from "./Field"; +import Operation from "./Operation"; type ResourceOptions = { id?: string, title?: string, + deprecated?: boolean, readableFields?: Field[], writableFields?: Field[], - operations?: Operation[], + operations?: Operation[] }; /** @@ -28,12 +29,12 @@ export default class Resource { this.name = name; this.url = url; - Object.keys(options).forEach((key) => { + Object.keys(options).forEach(key => { Object.defineProperty(this, key, { readable: true, writable: true, enumerable: true, - value: options[key], + value: options[key] }); }); } diff --git a/src/hydra/fetchJsonLd.js b/src/hydra/fetchJsonLd.js index 5aaff41..50bd171 100644 --- a/src/hydra/fetchJsonLd.js +++ b/src/hydra/fetchJsonLd.js @@ -6,30 +6,39 @@ * @return {Promise.} An object with a response key (the original HTTP response) and an optional body key (the parsed JSON-LD body) */ export default function fetchJsonLd(url, options = {}) { - const jsonLdMimeType = 'application/ld+json'; + const jsonLdMimeType = "application/ld+json"; - if ('undefined' === typeof options.headers) { + if ("undefined" === typeof options.headers) { options.headers = new Headers(); } - if (null === options.headers.get('Accept')) { - options.headers.set('Accept', jsonLdMimeType); + if (null === options.headers.get("Accept")) { + options.headers.set("Accept", jsonLdMimeType); } - if ('undefined' !== options.body && !(typeof FormData !== 'undefined' && options.body instanceof FormData) && null === options.headers.get('Content-Type')) { - options.headers.set('Content-Type', jsonLdMimeType); + if ( + "undefined" !== options.body && + !(typeof FormData !== "undefined" && options.body instanceof FormData) && + null === options.headers.get("Content-Type") + ) { + options.headers.set("Content-Type", jsonLdMimeType); } - return fetch(url, options) - .then(response => { - const { headers, status } = response; - if (204 === status) { - return Promise.resolve({ response }); - } - if (500 <= status || !headers.has('Content-Type') || !headers.get('Content-Type').includes(jsonLdMimeType)) { - return Promise.reject({ response }); - } + return fetch(url, options).then(response => { + const { headers, status } = response; + if (204 === status) { + return Promise.resolve({ response }); + } + if ( + 500 <= status || + !headers.has("Content-Type") || + !headers.get("Content-Type").includes(jsonLdMimeType) + ) { + return Promise.reject({ response }); + } - return Promise.resolve(response.json().then(body => ({ response, body, document: body }))); - }); + return Promise.resolve( + response.json().then(body => ({ response, body, document: body })) + ); + }); } diff --git a/src/hydra/fetchJsonLd.test.js b/src/hydra/fetchJsonLd.test.js index d0ecfae..69181eb 100644 --- a/src/hydra/fetchJsonLd.test.js +++ b/src/hydra/fetchJsonLd.test.js @@ -1,52 +1,72 @@ -import fetchJsonLd from './fetchJsonLd'; +import fetchJsonLd from "./fetchJsonLd"; -test('fetch a JSON-LD document', () => { - fetch.mockResponseOnce(`{ +test("fetch a JSON-LD document", () => { + fetch.mockResponseOnce( + `{ "@context": "http://json-ld.org/contexts/person.jsonld", "@id": "http://dbpedia.org/resource/John_Lennon", "name": "John Lennon", "born": "1940-10-09", "spouse": "http://dbpedia.org/resource/Cynthia_Lennon" -}`, {status: 200, statusText: 'OK', headers: new Headers({'Content-Type': 'application/ld+json'})}); - - return fetchJsonLd('/foo.jsonld').then(data => { - expect(data.response.ok).toBe(true); - expect(data.body.name).toBe('John Lennon'); +}`, + { + status: 200, + statusText: "OK", + headers: new Headers({ "Content-Type": "application/ld+json" }) } ); + + return fetchJsonLd("/foo.jsonld").then(data => { + expect(data.response.ok).toBe(true); + expect(data.body.name).toBe("John Lennon"); + }); }); -test('fetch a non JSON-LD document', () => { - fetch.mockResponseOnce(`Hello`, {status: 200, statusText: 'OK', headers: new Headers({'Content-Type': 'text/html'})}); +test("fetch a non JSON-LD document", () => { + fetch.mockResponseOnce(`Hello`, { + status: 200, + statusText: "OK", + headers: new Headers({ "Content-Type": "text/html" }) + }); - return fetchJsonLd('/foo.jsonld').catch(data => { - expect(data.response.ok).toBe(true); - expect(typeof data.body).toBe('undefined'); - } - ); + return fetchJsonLd("/foo.jsonld").catch(data => { + expect(data.response.ok).toBe(true); + expect(typeof data.body).toBe("undefined"); + }); }); -test('fetch an error', () => { - fetch.mockResponseOnce(`{ +test("fetch an error", () => { + fetch.mockResponseOnce( + `{ "@context": "http://json-ld.org/contexts/person.jsonld", "@id": "http://dbpedia.org/resource/John_Lennon", "name": "John Lennon", "born": "1940-10-09", "spouse": "http://dbpedia.org/resource/Cynthia_Lennon" -}`, {status: 400, statusText: 'Bad Request', headers: new Headers({'Content-Type': 'application/ld+json'})}); +}`, + { + status: 400, + statusText: "Bad Request", + headers: new Headers({ "Content-Type": "application/ld+json" }) + } + ); - return fetchJsonLd('/foo.jsonld').catch(({response}) => { + return fetchJsonLd("/foo.jsonld").catch(({ response }) => { response.json().then(body => { expect(response.ok).toBe(false); - expect(body.born).toBe('1940-10-09'); + expect(body.born).toBe("1940-10-09"); }); }); }); -test('fetch an empty document', () => { - fetch.mockResponseOnce('', {status: 204, statusText: 'No Content', headers: new Headers({'Content-Type': 'text/html'})}); +test("fetch an empty document", () => { + fetch.mockResponseOnce("", { + status: 204, + statusText: "No Content", + headers: new Headers({ "Content-Type": "text/html" }) + }); - return fetchJsonLd('/foo.jsonld').then(data => { + return fetchJsonLd("/foo.jsonld").then(data => { expect(data.response.ok).toBe(true); expect(data.body).toBe(undefined); }); diff --git a/src/hydra/index.js b/src/hydra/index.js index 478e7d1..b27e9af 100644 --- a/src/hydra/index.js +++ b/src/hydra/index.js @@ -1,2 +1,4 @@ -export fetchJsonLd from './fetchJsonLd'; -export parseHydraDocumentation, { getDocumentationUrlFromHeaders } from './parseHydraDocumentation'; +export fetchJsonLd from "./fetchJsonLd"; +export parseHydraDocumentation, { + getDocumentationUrlFromHeaders +} from "./parseHydraDocumentation"; diff --git a/src/hydra/parseHydraDocumentation.js b/src/hydra/parseHydraDocumentation.js index 79862c8..dbd2ea3 100644 --- a/src/hydra/parseHydraDocumentation.js +++ b/src/hydra/parseHydraDocumentation.js @@ -1,10 +1,10 @@ -import {promises} from 'jsonld'; -import get from 'lodash.get'; -import Api from '../Api' -import Field from '../Field' -import Resource from '../Resource' -import Operation from '../Operation' -import fetchJsonLd from './fetchJsonLd'; +import { promises } from "jsonld"; +import get from "lodash.get"; +import Api from "../Api"; +import Field from "../Field"; +import Resource from "../Resource"; +import Operation from "../Operation"; +import fetchJsonLd from "./fetchJsonLd"; /** * Extracts the short name of a resource. @@ -25,29 +25,40 @@ function guessNameFromUrl(url, entrypointUrl) { * @return {object} */ function findSupportedClass(docs, classToFind) { - const supportedClasses = get(docs, '[0]["http://www.w3.org/ns/hydra/core#supportedClass"]'); + const supportedClasses = get( + docs, + '[0]["http://www.w3.org/ns/hydra/core#supportedClass"]' + ); if (!Array.isArray(supportedClasses)) { - throw new Error('The API documentation has no "http://www.w3.org/ns/hydra/core#supportedClass" key or its value is not an array.'); + throw new Error( + 'The API documentation has no "http://www.w3.org/ns/hydra/core#supportedClass" key or its value is not an array.' + ); } for (const supportedClass of supportedClasses) { - if (supportedClass['@id'] === classToFind) { + if (supportedClass["@id"] === classToFind) { return supportedClass; } } - throw new Error(`The class "${classToFind}" is not defined in the API documentation.`); + throw new Error( + `The class "${classToFind}" is not defined in the API documentation.` + ); } export function getDocumentationUrlFromHeaders(headers) { - const linkHeader = headers.get('Link'); + const linkHeader = headers.get("Link"); if (!linkHeader) { throw new Error('The response has no "Link" HTTP header.'); } - const matches = linkHeader.match(/<(.+)>; rel="http:\/\/www.w3.org\/ns\/hydra\/core#apiDocumentation"/); + const matches = linkHeader.match( + /<(.+)>; rel="http:\/\/www.w3.org\/ns\/hydra\/core#apiDocumentation"/ + ); if (!matches[1]) { - throw new Error('The "Link" HTTP header is not of the type "http://www.w3.org/ns/hydra/core#apiDocumentation".'); + throw new Error( + 'The "Link" HTTP header is not of the type "http://www.w3.org/ns/hydra/core#apiDocumentation".' + ); } return matches[1]; @@ -61,42 +72,57 @@ export function getDocumentationUrlFromHeaders(headers) { * @return {Promise} */ function fetchEntrypointAndDocs(entrypointUrl, options = {}) { - return fetchJsonLd(entrypointUrl, options).then(d => { - const docsUrl = getDocumentationUrlFromHeaders(d.response.headers); - - return { - entrypointUrl, - docsUrl, - entrypoint: d.body, - response: d.response - } - }).then(data => - fetchJsonLd(data.docsUrl, options).then(d => { - data.docs = d.body; - - return data; - }).then(data => - promises.expand(data.docs, { base: data.docsUrl, documentLoader: (input) => fetchJsonLd(input, options) }).then(docs => { - data.docs = docs; - - return data; - }) - ).then(data => - promises.expand(data.entrypoint, { base: data.entrypointUrl, documentLoader: (input) => fetchJsonLd(input, options) }).then(entrypoint => { - data.entrypoint = entrypoint; - - return data; + return fetchJsonLd(entrypointUrl, options) + .then(d => { + const docsUrl = getDocumentationUrlFromHeaders(d.response.headers); + + return { + entrypointUrl, + docsUrl, + entrypoint: d.body, + response: d.response + }; + }) + .then(data => + fetchJsonLd(data.docsUrl, options) + .then(d => { + data.docs = d.body; + + return data; }) - ) - ); + .then(data => + promises + .expand(data.docs, { + base: data.docsUrl, + documentLoader: input => fetchJsonLd(input, options) + }) + .then(docs => { + data.docs = docs; + + return data; + }) + ) + .then(data => + promises + .expand(data.entrypoint, { + base: data.entrypointUrl, + documentLoader: input => fetchJsonLd(input, options) + }) + .then(entrypoint => { + data.entrypoint = entrypoint; + + return data; + }) + ) + ); } function removeTrailingSlash(url) { if (/\/$/.test(url)) { - url = url.slice(0, -1) + url = url.slice(0, -1); } - return url + return url; } /** @@ -107,30 +133,51 @@ function removeTrailingSlash(url) { */ function findRelatedClass(docs, property) { // Use the entrypoint property's owl:equivalentClass if available - if (Array.isArray(property['http://www.w3.org/2000/01/rdf-schema#range'])) { - for (const range of property['http://www.w3.org/2000/01/rdf-schema#range']) { - const onProperty = get(range, '["http://www.w3.org/2002/07/owl#equivalentClass"][0]["http://www.w3.org/2002/07/owl#onProperty"][0]["@id"]'); - const allValuesFrom = get(range, '["http://www.w3.org/2002/07/owl#equivalentClass"][0]["http://www.w3.org/2002/07/owl#allValuesFrom"][0]["@id"]'); - - if (allValuesFrom && 'http://www.w3.org/ns/hydra/core#member' === onProperty) { + if (Array.isArray(property["http://www.w3.org/2000/01/rdf-schema#range"])) { + for (const range of property[ + "http://www.w3.org/2000/01/rdf-schema#range" + ]) { + const onProperty = get( + range, + '["http://www.w3.org/2002/07/owl#equivalentClass"][0]["http://www.w3.org/2002/07/owl#onProperty"][0]["@id"]' + ); + const allValuesFrom = get( + range, + '["http://www.w3.org/2002/07/owl#equivalentClass"][0]["http://www.w3.org/2002/07/owl#allValuesFrom"][0]["@id"]' + ); + + if ( + allValuesFrom && + "http://www.w3.org/ns/hydra/core#member" === onProperty + ) { return findSupportedClass(docs, allValuesFrom); } } } // As a fallback, find an operation available on the property of the entrypoint returning the searched type (usually POST) - for (const entrypointSupportedOperation of property['http://www.w3.org/ns/hydra/core#supportedOperation']) { - if (!entrypointSupportedOperation['http://www.w3.org/ns/hydra/core#returns']) { + for (const entrypointSupportedOperation of property[ + "http://www.w3.org/ns/hydra/core#supportedOperation" + ]) { + if ( + !entrypointSupportedOperation["http://www.w3.org/ns/hydra/core#returns"] + ) { continue; } - const returns = get(entrypointSupportedOperation, '["http://www.w3.org/ns/hydra/core#returns"][0]["@id"]'); - if ('string' === typeof returns && 0 !== returns.indexOf('http://www.w3.org/ns/hydra/core')) { + const returns = get( + entrypointSupportedOperation, + '["http://www.w3.org/ns/hydra/core#returns"][0]["@id"]' + ); + if ( + "string" === typeof returns && + 0 !== returns.indexOf("http://www.w3.org/ns/hydra/core") + ) { return findSupportedClass(docs, returns); } } - throw new Error(`Cannot find the class related to ${property['@id']}.`); + throw new Error(`Cannot find the class related to ${property["@id"]}.`); } /** @@ -145,8 +192,14 @@ export default function parseHydraDocumentation(entrypointUrl, options = {}) { return fetchEntrypointAndDocs(entrypointUrl, options).then( ({ entrypoint, docs, response }) => { - const resources = [], fields = [], operations = []; - const title = get(docs, '[0]["http://www.w3.org/ns/hydra/core#title"][0]["@value"]', 'API Platform'); + const resources = [], + fields = [], + operations = []; + const title = get( + docs, + '[0]["http://www.w3.org/ns/hydra/core#title"][0]["@value"]', + "API Platform" + ); const entrypointType = get(entrypoint, '[0]["@type"][0]'); if (!entrypointType) { @@ -154,65 +207,144 @@ export default function parseHydraDocumentation(entrypointUrl, options = {}) { } const entrypointClass = findSupportedClass(docs, entrypointType); - if (!Array.isArray(entrypointClass['http://www.w3.org/ns/hydra/core#supportedProperty'])) { - throw new Error('The entrypoint definition has no "http://www.w3.org/ns/hydra/core#supportedProperty" key or it is not an array.'); + if ( + !Array.isArray( + entrypointClass["http://www.w3.org/ns/hydra/core#supportedProperty"] + ) + ) { + throw new Error( + 'The entrypoint definition has no "http://www.w3.org/ns/hydra/core#supportedProperty" key or it is not an array.' + ); } // Add resources - for (const properties of entrypointClass['http://www.w3.org/ns/hydra/core#supportedProperty']) { - const readableFields = [], resourceFields = [], writableFields = [], resourceOperations = []; - - const property = get(properties, '["http://www.w3.org/ns/hydra/core#property"][0]'); + for (const properties of entrypointClass[ + "http://www.w3.org/ns/hydra/core#supportedProperty" + ]) { + const readableFields = [], + resourceFields = [], + writableFields = [], + resourceOperations = []; + + const property = get( + properties, + '["http://www.w3.org/ns/hydra/core#property"][0]' + ); if (!property) { continue; } // Add fields const relatedClass = findRelatedClass(docs, property); - for (const supportedProperties of relatedClass['http://www.w3.org/ns/hydra/core#supportedProperty']) { - const supportedProperty = get(supportedProperties, '["http://www.w3.org/ns/hydra/core#property"][0]'); - const range = get(supportedProperty, '["http://www.w3.org/2000/01/rdf-schema#range"][0]["@id"]', null); + for (const supportedProperties of relatedClass[ + "http://www.w3.org/ns/hydra/core#supportedProperty" + ]) { + const supportedProperty = get( + supportedProperties, + '["http://www.w3.org/ns/hydra/core#property"][0]' + ); + const range = get( + supportedProperty, + '["http://www.w3.org/2000/01/rdf-schema#range"][0]["@id"]', + null + ); const field = new Field( - supportedProperty['http://www.w3.org/2000/01/rdf-schema#label'][0]['@value'], + supportedProperty["http://www.w3.org/2000/01/rdf-schema#label"][0][ + "@value" + ], { - id: supportedProperty['@id'], + id: supportedProperty["@id"], range: range, - reference: 'http://www.w3.org/ns/hydra/core#Link' === get(property, '["@type"][0]') ? range : null, // Will be updated in a subsequent pass - required: get(supportedProperties, '["http://www.w3.org/ns/hydra/core#required"][0]["@value"]', false), - description: get(supportedProperties, '["http://www.w3.org/ns/hydra/core#description"][0]["@value"]', ''), - maxCardinality: get(supportedProperty, '["http://www.w3.org/2002/07/owl#maxCardinality"][0]["@value"]', null), - }, + reference: + "http://www.w3.org/ns/hydra/core#Link" === + get(property, '["@type"][0]') + ? range + : null, // Will be updated in a subsequent pass + required: get( + supportedProperties, + '["http://www.w3.org/ns/hydra/core#required"][0]["@value"]', + false + ), + description: get( + supportedProperties, + '["http://www.w3.org/ns/hydra/core#description"][0]["@value"]', + "" + ), + maxCardinality: get( + supportedProperty, + '["http://www.w3.org/2002/07/owl#maxCardinality"][0]["@value"]', + null + ), + deprecated: get( + supportedProperties, + '["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]', + false + ) + } ); fields.push(field); resourceFields.push(field); - if (get(supportedProperties, '["http://www.w3.org/ns/hydra/core#readable"][0]["@value"]')) { + if ( + get( + supportedProperties, + '["http://www.w3.org/ns/hydra/core#readable"][0]["@value"]' + ) + ) { readableFields.push(field); } - if (get(supportedProperties, '["http://www.w3.org/ns/hydra/core#writable"][0]["@value"]')) { + if ( + get( + supportedProperties, + '["http://www.w3.org/ns/hydra/core#writable"][0]["@value"]' + ) + ) { writableFields.push(field); } } // parse entrypoint's operations (a.k.a. collection operations) - if (property['http://www.w3.org/ns/hydra/core#supportedOperation']) { - for (const entrypointOperation of property['http://www.w3.org/ns/hydra/core#supportedOperation']) { - if (!entrypointOperation['http://www.w3.org/ns/hydra/core#returns']) { + if (property["http://www.w3.org/ns/hydra/core#supportedOperation"]) { + for (const entrypointOperation of property[ + "http://www.w3.org/ns/hydra/core#supportedOperation" + ]) { + if ( + !entrypointOperation["http://www.w3.org/ns/hydra/core#returns"] + ) { continue; } - const range = entrypointOperation['http://www.w3.org/ns/hydra/core#returns'][0]['@id']; + const range = + entrypointOperation["http://www.w3.org/ns/hydra/core#returns"][0][ + "@id" + ]; const operation = new Operation( - entrypointOperation['http://www.w3.org/2000/01/rdf-schema#label'][0]['@value'], + entrypointOperation[ + "http://www.w3.org/2000/01/rdf-schema#label" + ][0]["@value"], { - method: entrypointOperation['http://www.w3.org/ns/hydra/core#method'][0]['@value'], - expects: entrypointOperation['http://www.w3.org/ns/hydra/core#expects'] && entrypointOperation['http://www.w3.org/ns/hydra/core#expects'][0]['@id'], + method: + entrypointOperation[ + "http://www.w3.org/ns/hydra/core#method" + ][0]["@value"], + expects: + entrypointOperation[ + "http://www.w3.org/ns/hydra/core#expects" + ] && + entrypointOperation[ + "http://www.w3.org/ns/hydra/core#expects" + ][0]["@id"], returns: range, - types: entrypointOperation['@type'], - }, + types: entrypointOperation["@type"], + deprecated: get( + entrypointOperation, + '["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]', + false + ) + } ); resourceOperations.push(operation); @@ -221,54 +353,90 @@ export default function parseHydraDocumentation(entrypointUrl, options = {}) { } // parse resource operations (a.k.a. item operations) - for (const supportedOperation of relatedClass['http://www.w3.org/ns/hydra/core#supportedOperation']) { - if (!supportedOperation['http://www.w3.org/ns/hydra/core#returns']) { + for (const supportedOperation of relatedClass[ + "http://www.w3.org/ns/hydra/core#supportedOperation" + ]) { + if (!supportedOperation["http://www.w3.org/ns/hydra/core#returns"]) { continue; } - const range = supportedOperation['http://www.w3.org/ns/hydra/core#returns'][0]['@id']; + const range = + supportedOperation["http://www.w3.org/ns/hydra/core#returns"][0][ + "@id" + ]; const operation = new Operation( - supportedOperation['http://www.w3.org/2000/01/rdf-schema#label'][0]['@value'], + supportedOperation["http://www.w3.org/2000/01/rdf-schema#label"][0][ + "@value" + ], { - method: supportedOperation['http://www.w3.org/ns/hydra/core#method'][0]['@value'], - expects: supportedOperation['http://www.w3.org/ns/hydra/core#expects'] && supportedOperation['http://www.w3.org/ns/hydra/core#expects'][0]['@id'], + method: + supportedOperation["http://www.w3.org/ns/hydra/core#method"][0][ + "@value" + ], + expects: + supportedOperation["http://www.w3.org/ns/hydra/core#expects"] && + supportedOperation[ + "http://www.w3.org/ns/hydra/core#expects" + ][0]["@id"], returns: range, - types: supportedOperation['@type'], - }, + types: supportedOperation["@type"], + deprecated: get( + supportedOperation, + '["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]', + false + ) + } ); resourceOperations.push(operation); operations.push(operation); } - const url = get(entrypoint, `[0]["${property['@id']}"][0]["@id"]`); + const url = get(entrypoint, `[0]["${property["@id"]}"][0]["@id"]`); if (!url) { - throw new Error(`Unable to find the URL for "${property['@id']}".`); + throw new Error(`Unable to find the URL for "${property["@id"]}".`); } - resources.push(new Resource( - guessNameFromUrl(url, entrypointUrl), - url, - { - id: relatedClass['@id'], - title: get(relatedClass, '["http://www.w3.org/ns/hydra/core#title"][0]["@value"]', ''), + resources.push( + new Resource(guessNameFromUrl(url, entrypointUrl), url, { + id: relatedClass["@id"], + title: get( + relatedClass, + '["http://www.w3.org/ns/hydra/core#title"][0]["@value"]', + "" + ), fields: resourceFields, readableFields, writableFields, - operations: resourceOperations - } - )); + operations: resourceOperations, + deprecated: get( + relatedClass, + '["http://www.w3.org/2002/07/owl#deprecated"][0]["@value"]', + false + ) + }) + ); } // Resolve references for (const field of fields) { if (null !== field.reference) { - field.reference = resources.find(resource => resource.id === field.reference) || null; + field.reference = + resources.find(resource => resource.id === field.reference) || null; } } - return Promise.resolve({ api: new Api(entrypointUrl, {title, resources}), response , status: response.status }); + return Promise.resolve({ + api: new Api(entrypointUrl, { title, resources }), + response, + status: response.status + }); }, - ({ response }) => Promise.reject({ api: new Api(entrypointUrl, {resources: []}), response, status: get(response, 'status') }) + ({ response }) => + Promise.reject({ + api: new Api(entrypointUrl, { resources: [] }), + response, + status: get(response, "status") + }) ); } diff --git a/src/hydra/parseHydraDocumentation.test.js b/src/hydra/parseHydraDocumentation.test.js index 1f68e60..9b72c2a 100644 --- a/src/hydra/parseHydraDocumentation.test.js +++ b/src/hydra/parseHydraDocumentation.test.js @@ -1,4 +1,4 @@ -import parseHydraDocumentation from './parseHydraDocumentation'; +import parseHydraDocumentation from "./parseHydraDocumentation"; const entrypoint = `{ "@context": { @@ -15,13 +15,18 @@ const entrypoint = `{ "customResource": { "@id": "Entrypoint/customResource", "@type": "@id" + }, + "deprecatedResource": { + "@id": "Entrypoint/deprecatedResource", + "@type": "@id" } }, "@id": "/", "@type": "Entrypoint", "book": "/books", "review": "/reviews", - "customResource": "/customResources" + "customResource": "/customResources", + "deprecatedResource": "/deprecated_resources" }`; const docs = `{ @@ -313,6 +318,45 @@ const docs = `{ } ] }, + { + "@id": "#DeprecatedResource", + "@type": "hydra:Class", + "rdfs:label": "DeprecatedResource", + "hydra:title": "DeprecatedResource", + "hydra:supportedProperty": [ + { + "@type": "hydra:SupportedProperty", + "hydra:property": { + "@id": "#DeprecatedResource/deprecatedField", + "@type": "rdf:Property", + "rdfs:label": "deprecatedField", + "domain": "#DeprecatedResource", + "range": "xmls:string" + }, + "hydra:title": "deprecatedField", + "hydra:required": true, + "hydra:readable": true, + "hydra:writable": true, + "hydra:description": "", + "owl:deprecated": true + } + ], + "hydra:supportedOperation": [ + { + "@type": [ + "hydra:Operation", + "schema:FindAction" + ], + "hydra:method": "GET", + "hydra:title": "Retrieves DeprecatedResource resource.", + "owl:deprecated": true, + "rdfs:label": "Retrieves DeprecatedResource resource.", + "returns": "#DeprecatedResource" + } + ], + "hydra:description": "This is a dummy entity. Remove it!", + "owl:deprecated": true + }, { "@id": "#Entrypoint", "@type": "hydra:Class", @@ -326,13 +370,13 @@ const docs = `{ "domain": "#Entrypoint", "rdfs:label": "The collection of Book resources", "rdfs:range": [ - {"@id": "hydra:PagedCollection"}, - { - "owl:equivalentClass": { - "owl:onProperty": {"@id": "hydra:member"}, - "owl:allValuesFrom": {"@id": "http://schema.org/Book"} - } + {"@id": "hydra:PagedCollection"}, + { + "owl:equivalentClass": { + "owl:onProperty": {"@id": "hydra:member"}, + "owl:allValuesFrom": {"@id": "http://schema.org/Book"} } + } ] }, "hydra:title": "The collection of Book resources", @@ -398,7 +442,48 @@ const docs = `{ "hydra:title": "The collection of custom resources", "hydra:readable": true, "hydra:writable": false - } + }, + { + "@type": "hydra:SupportedProperty", + "hydra:property": { + "@id": "#Entrypoint/deprecatedResource", + "@type": "hydra:Link", + "domain": "#Entrypoint", + "rdfs:label": "The collection of DeprecatedResource resources", + "rdfs:range": [ + { + "@id": "hydra:Collection" + }, + { + "owl:equivalentClass": { + "owl:onProperty": { + "@id": "hydra:member" + }, + "owl:allValuesFrom": { + "@id": "#DeprecatedResource" + } + } + } + ], + "hydra:supportedOperation": [ + { + "@type": [ + "hydra:Operation", + "schema:FindAction" + ], + "hydra:method": "GET", + "hydra:title": "Retrieves the collection of DeprecatedResource resources.", + "owl:deprecated": true, + "rdfs:label": "Retrieves the collection of DeprecatedResource resources.", + "returns": "hydra:Collection" + } + ] + }, + "hydra:title": "The collection of DeprecatedResource resources", + "hydra:readable": true, + "hydra:writable": false, + "owl:deprecated": true + } ], "hydra:supportedOperation": { "@type": "hydra:Operation", @@ -468,497 +553,595 @@ const docs = `{ }`; const book = { - "name": "books", - "url": "http://localhost/books", - "id": "http://schema.org/Book", - "title": "Book", - "fields": [ + name: "books", + url: "http://localhost/books", + id: "http://schema.org/Book", + title: "Book", + fields: [ { - "name": "isbn", - "id": "http://schema.org/isbn", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "The ISBN of the book", - "maxCardinality": null, + name: "isbn", + id: "http://schema.org/isbn", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "The ISBN of the book", + maxCardinality: null, + deprecated: false }, { - "name": "name", - "id": "http://schema.org/name", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "The name of the item", - "maxCardinality": null, + name: "name", + id: "http://schema.org/name", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "The name of the item", + maxCardinality: null, + deprecated: false }, { - "name": "description", - "id": "http://schema.org/description", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": false, - "description": "A description of the item", - "maxCardinality": null, + name: "description", + id: "http://schema.org/description", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: false, + description: "A description of the item", + maxCardinality: null, + deprecated: false }, { - "name": "author", - "id": "http://schema.org/author", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "The author of this content or rating. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably", - "maxCardinality": null, + name: "author", + id: "http://schema.org/author", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: + "The author of this content or rating. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably", + maxCardinality: null, + deprecated: false }, { - "name": "dateCreated", - "id": "http://schema.org/dateCreated", - "range": "http://www.w3.org/2001/XMLSchema#dateTime", - "reference": null, - "required": true, - "description": "The date on which the CreativeWork was created or the item was added to a DataFeed", - "maxCardinality": null, + name: "dateCreated", + id: "http://schema.org/dateCreated", + range: "http://www.w3.org/2001/XMLSchema#dateTime", + reference: null, + required: true, + description: + "The date on which the CreativeWork was created or the item was added to a DataFeed", + maxCardinality: null, + deprecated: false } ], - "readableFields": [ + readableFields: [ { - "name": "isbn", - "id": "http://schema.org/isbn", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "The ISBN of the book", - "maxCardinality": null, + name: "isbn", + id: "http://schema.org/isbn", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "The ISBN of the book", + maxCardinality: null, + deprecated: false }, { - "name": "name", - "id": "http://schema.org/name", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "The name of the item", - "maxCardinality": null, + name: "name", + id: "http://schema.org/name", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "The name of the item", + maxCardinality: null, + deprecated: false }, { - "name": "description", - "id": "http://schema.org/description", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": false, - "description": "A description of the item", - "maxCardinality": null, + name: "description", + id: "http://schema.org/description", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: false, + description: "A description of the item", + maxCardinality: null, + deprecated: false }, { - "name": "author", - "id": "http://schema.org/author", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "The author of this content or rating. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably", - "maxCardinality": null, + name: "author", + id: "http://schema.org/author", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: + "The author of this content or rating. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably", + maxCardinality: null, + deprecated: false }, { - "name": "dateCreated", - "id": "http://schema.org/dateCreated", - "range": "http://www.w3.org/2001/XMLSchema#dateTime", - "reference": null, - "required": true, - "description": "The date on which the CreativeWork was created or the item was added to a DataFeed", - "maxCardinality": null, + name: "dateCreated", + id: "http://schema.org/dateCreated", + range: "http://www.w3.org/2001/XMLSchema#dateTime", + reference: null, + required: true, + description: + "The date on which the CreativeWork was created or the item was added to a DataFeed", + maxCardinality: null, + deprecated: false } ], - "writableFields": [ + writableFields: [ { - "name": "isbn", - "id": "http://schema.org/isbn", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "The ISBN of the book", - "maxCardinality": null, + name: "isbn", + id: "http://schema.org/isbn", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "The ISBN of the book", + maxCardinality: null, + deprecated: false }, { - "name": "name", - "id": "http://schema.org/name", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "The name of the item", - "maxCardinality": null, + name: "name", + id: "http://schema.org/name", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "The name of the item", + maxCardinality: null, + deprecated: false }, { - "name": "description", - "id": "http://schema.org/description", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": false, - "description": "A description of the item", - "maxCardinality": null, + name: "description", + id: "http://schema.org/description", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: false, + description: "A description of the item", + maxCardinality: null, + deprecated: false }, { - "name": "author", - "id": "http://schema.org/author", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "The author of this content or rating. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably", - "maxCardinality": null, + name: "author", + id: "http://schema.org/author", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: + "The author of this content or rating. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably", + maxCardinality: null, + deprecated: false }, { - "name": "dateCreated", - "id": "http://schema.org/dateCreated", - "range": "http://www.w3.org/2001/XMLSchema#dateTime", - "reference": null, - "required": true, - "description": "The date on which the CreativeWork was created or the item was added to a DataFeed", - "maxCardinality": null, + name: "dateCreated", + id: "http://schema.org/dateCreated", + range: "http://www.w3.org/2001/XMLSchema#dateTime", + reference: null, + required: true, + description: + "The date on which the CreativeWork was created or the item was added to a DataFeed", + maxCardinality: null, + deprecated: false } ], - "operations": [ + operations: [ { - "name": "Retrieves Book resource.", - "method": "GET", - "returns": "http://schema.org/Book", - "types": ["http://www.w3.org/ns/hydra/core#Operation"], + name: "Retrieves Book resource.", + method: "GET", + returns: "http://schema.org/Book", + types: ["http://www.w3.org/ns/hydra/core#Operation"], + deprecated: false }, { - "name": "Replaces the Book resource.", - "method": "PUT", - "expects": "http://schema.org/Book", - "returns": "http://schema.org/Book", - "types": ["http://www.w3.org/ns/hydra/core#ReplaceResourceOperation"], + name: "Replaces the Book resource.", + method: "PUT", + expects: "http://schema.org/Book", + returns: "http://schema.org/Book", + types: ["http://www.w3.org/ns/hydra/core#ReplaceResourceOperation"], + deprecated: false }, { - "name": "Deletes the Book resource.", - "method": "DELETE", - "returns": "http://www.w3.org/2002/07/owl#Nothing", - "types": ["http://www.w3.org/ns/hydra/core#Operation"], + name: "Deletes the Book resource.", + method: "DELETE", + returns: "http://www.w3.org/2002/07/owl#Nothing", + types: ["http://www.w3.org/ns/hydra/core#Operation"], + deprecated: false } - ] + ], + deprecated: false }; const review = { - "name": "reviews", - "url": "http://localhost/reviews", - "id": "http://schema.org/Review", - "title": "Review", - "fields": [ + name: "reviews", + url: "http://localhost/reviews", + id: "http://schema.org/Review", + title: "Review", + fields: [ { - "name": "reviewBody", - "id": "http://schema.org/reviewBody", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": false, - "description": "The actual body of the review", - "maxCardinality": null, + name: "reviewBody", + id: "http://schema.org/reviewBody", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: false, + description: "The actual body of the review", + maxCardinality: null, + deprecated: false }, { - "name": "rating", - "id": "http://localhost/docs.jsonld#Review/rating", - "range": "http://www.w3.org/2001/XMLSchema#integer", - "reference": null, - "required": false, - "description": "", - "maxCardinality": null, + name: "rating", + id: "http://localhost/docs.jsonld#Review/rating", + range: "http://www.w3.org/2001/XMLSchema#integer", + reference: null, + required: false, + description: "", + maxCardinality: null, + deprecated: false }, { - "name": "itemReviewed", - "id": "http://schema.org/itemReviewed", - "range": "http://schema.org/Book", - "reference": book, - "required": true, - "description": "The item that is being reviewed/rated", - "maxCardinality": 1, + name: "itemReviewed", + id: "http://schema.org/itemReviewed", + range: "http://schema.org/Book", + reference: book, + required: true, + description: "The item that is being reviewed/rated", + maxCardinality: 1, + deprecated: false } ], - "readableFields": [ + readableFields: [ { - "name": "reviewBody", - "id": "http://schema.org/reviewBody", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": false, - "description": "The actual body of the review", - "maxCardinality": null, + name: "reviewBody", + id: "http://schema.org/reviewBody", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: false, + description: "The actual body of the review", + maxCardinality: null, + deprecated: false }, { - "name": "rating", - "id": "http://localhost/docs.jsonld#Review/rating", - "range": "http://www.w3.org/2001/XMLSchema#integer", - "reference": null, - "required": false, - "description": "", - "maxCardinality": null, + name: "rating", + id: "http://localhost/docs.jsonld#Review/rating", + range: "http://www.w3.org/2001/XMLSchema#integer", + reference: null, + required: false, + description: "", + maxCardinality: null, + deprecated: false }, { - "name": "itemReviewed", - "id": "http://schema.org/itemReviewed", - "range": "http://schema.org/Book", - "reference": book, - "required": true, - "description": "The item that is being reviewed/rated", - "maxCardinality": 1, + name: "itemReviewed", + id: "http://schema.org/itemReviewed", + range: "http://schema.org/Book", + reference: book, + required: true, + description: "The item that is being reviewed/rated", + maxCardinality: 1, + deprecated: false } ], - "writableFields": [ + writableFields: [ { - "name": "reviewBody", - "id": "http://schema.org/reviewBody", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": false, - "description": "The actual body of the review", - "maxCardinality": null, + name: "reviewBody", + id: "http://schema.org/reviewBody", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: false, + description: "The actual body of the review", + maxCardinality: null, + deprecated: false }, { - "name": "rating", - "id": "http://localhost/docs.jsonld#Review/rating", - "range": "http://www.w3.org/2001/XMLSchema#integer", - "reference": null, - "required": false, - "description": "", - "maxCardinality": null, + name: "rating", + id: "http://localhost/docs.jsonld#Review/rating", + range: "http://www.w3.org/2001/XMLSchema#integer", + reference: null, + required: false, + description: "", + maxCardinality: null, + deprecated: false }, { - "name": "itemReviewed", - "id": "http://schema.org/itemReviewed", - "range": "http://schema.org/Book", - "reference": book, - "required": true, - "description": "The item that is being reviewed/rated", - "maxCardinality": 1, + name: "itemReviewed", + id: "http://schema.org/itemReviewed", + range: "http://schema.org/Book", + reference: book, + required: true, + description: "The item that is being reviewed/rated", + maxCardinality: 1, + deprecated: false } ], - "operations": [ + operations: [ { - "name": "Retrieves the collection of Review resources.", - "method": "GET", - "returns": "http://www.w3.org/ns/hydra/core#PagedCollection", - "types": [ - "http://www.w3.org/ns/hydra/core#Operation" - ], + name: "Retrieves the collection of Review resources.", + method: "GET", + returns: "http://www.w3.org/ns/hydra/core#PagedCollection", + types: ["http://www.w3.org/ns/hydra/core#Operation"], + deprecated: false }, { - "name": "Creates a Review resource.", - "method": "POST", - "expects": "http://schema.org/Review", - "returns": "http://schema.org/Review", - "types": [ - "http://www.w3.org/ns/hydra/core#CreateResourceOperation" - ], + name: "Creates a Review resource.", + method: "POST", + expects: "http://schema.org/Review", + returns: "http://schema.org/Review", + types: ["http://www.w3.org/ns/hydra/core#CreateResourceOperation"], + deprecated: false }, { - "name": "Retrieves Review resource.", - "method": "GET", - "returns": "http://schema.org/Review", - "types": ["http://www.w3.org/ns/hydra/core#Operation"], + name: "Retrieves Review resource.", + method: "GET", + returns: "http://schema.org/Review", + types: ["http://www.w3.org/ns/hydra/core#Operation"], + deprecated: false }, { - "name": "Replaces the Review resource.", - "method": "PUT", - "expects": "http://schema.org/Review", - "returns": "http://schema.org/Review", - "types": ["http://www.w3.org/ns/hydra/core#ReplaceResourceOperation"], + name: "Replaces the Review resource.", + method: "PUT", + expects: "http://schema.org/Review", + returns: "http://schema.org/Review", + types: ["http://www.w3.org/ns/hydra/core#ReplaceResourceOperation"], + deprecated: false }, { - "name": "Deletes the Review resource.", - "method": "DELETE", - "returns": "http://www.w3.org/2002/07/owl#Nothing", - "types": ["http://www.w3.org/ns/hydra/core#Operation"], + name: "Deletes the Review resource.", + method: "DELETE", + returns: "http://www.w3.org/2002/07/owl#Nothing", + types: ["http://www.w3.org/ns/hydra/core#Operation"], + deprecated: false } - ] + ], + deprecated: false }; const customResource = { - "name": "customResources", - "url": "http://localhost/customResources", - "id": "http://localhost/docs.jsonld#CustomResource", - "title": "CustomResource", - "fields": [ + name: "customResources", + url: "http://localhost/customResources", + id: "http://localhost/docs.jsonld#CustomResource", + title: "CustomResource", + fields: [ { - "name": "label", - "id": "http://localhost/docs.jsonld#CustomResource/label", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "", - "maxCardinality": null, + name: "label", + id: "http://localhost/docs.jsonld#CustomResource/label", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "", + maxCardinality: null, + deprecated: false }, { - "name": "description", - "id": "http://localhost/docs.jsonld#CustomResource/description", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "", - "maxCardinality": null, + name: "description", + id: "http://localhost/docs.jsonld#CustomResource/description", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "", + maxCardinality: null, + deprecated: false }, { - "name": "sanitizedDescription", - "id": "http://localhost/docs.jsonld#CustomResource/sanitizedDescription", - "range": null, - "reference": null, - "required": false, - "description": "", - "maxCardinality": null, + name: "sanitizedDescription", + id: "http://localhost/docs.jsonld#CustomResource/sanitizedDescription", + range: null, + reference: null, + required: false, + description: "", + maxCardinality: null, + deprecated: false } ], - "readableFields": [ + readableFields: [ { - "name": "label", - "id": "http://localhost/docs.jsonld#CustomResource/label", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "", - "maxCardinality": null, + name: "label", + id: "http://localhost/docs.jsonld#CustomResource/label", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "", + maxCardinality: null, + deprecated: false }, { - "name": "description", - "id": "http://localhost/docs.jsonld#CustomResource/description", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "", - "maxCardinality": null, + name: "description", + id: "http://localhost/docs.jsonld#CustomResource/description", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "", + maxCardinality: null, + deprecated: false }, { - "name": "sanitizedDescription", - "id": "http://localhost/docs.jsonld#CustomResource/sanitizedDescription", - "range": null, - "reference": null, - "required": false, - "description": "", - "maxCardinality": null, + name: "sanitizedDescription", + id: "http://localhost/docs.jsonld#CustomResource/sanitizedDescription", + range: null, + reference: null, + required: false, + description: "", + maxCardinality: null, + deprecated: false } ], - "writableFields": [ + writableFields: [ { - "name": "label", - "id": "http://localhost/docs.jsonld#CustomResource/label", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "", - "maxCardinality": null, + name: "label", + id: "http://localhost/docs.jsonld#CustomResource/label", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "", + maxCardinality: null, + deprecated: false }, { - "name": "description", - "id": "http://localhost/docs.jsonld#CustomResource/description", - "range": "http://www.w3.org/2001/XMLSchema#string", - "reference": null, - "required": true, - "description": "", - "maxCardinality": null, + name: "description", + id: "http://localhost/docs.jsonld#CustomResource/description", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "", + maxCardinality: null, + deprecated: false } ], - "operations": [ + operations: [ { - "name": "Retrieves the collection of custom resources.", - "method": "GET", - "returns": "http://www.w3.org/ns/hydra/core#PagedCollection", - "types": [ - "http://www.w3.org/ns/hydra/core#Operation" - ], + name: "Retrieves the collection of custom resources.", + method: "GET", + returns: "http://www.w3.org/ns/hydra/core#PagedCollection", + types: ["http://www.w3.org/ns/hydra/core#Operation"], + deprecated: false }, { - "name": "Creates a custom resource.", - "method": "POST", - "expects": "http://localhost/docs.jsonld#CustomResource", - "returns": "http://localhost/docs.jsonld#CustomResource", - "types": [ - "http://www.w3.org/ns/hydra/core#CreateResourceOperation" - ], + name: "Creates a custom resource.", + method: "POST", + expects: "http://localhost/docs.jsonld#CustomResource", + returns: "http://localhost/docs.jsonld#CustomResource", + types: ["http://www.w3.org/ns/hydra/core#CreateResourceOperation"], + deprecated: false }, { - "name": "Retrieves custom resources.", - "method": "GET", - "returns": "http://localhost/docs.jsonld#CustomResource", - "types": ["http://www.w3.org/ns/hydra/core#Operation"], + name: "Retrieves custom resources.", + method: "GET", + returns: "http://localhost/docs.jsonld#CustomResource", + types: ["http://www.w3.org/ns/hydra/core#Operation"], + deprecated: false }, { - "name": "Creates a custom resource.", - "method": "POST", - "expects": "http://localhost/docs.jsonld#CustomResource", - "returns": "http://localhost/docs.jsonld#CustomResource", - "types": ["http://www.w3.org/ns/hydra/core#CreateResourceOperation"], + name: "Creates a custom resource.", + method: "POST", + expects: "http://localhost/docs.jsonld#CustomResource", + returns: "http://localhost/docs.jsonld#CustomResource", + types: ["http://www.w3.org/ns/hydra/core#CreateResourceOperation"], + deprecated: false } - ] + ], + deprecated: false +}; + +const deprecatedResource = { + name: "deprecated_resources", + url: "http://localhost/deprecated_resources", + id: "http://localhost/docs.jsonld#DeprecatedResource", + title: "DeprecatedResource", + fields: [ + { + name: "deprecatedField", + id: "http://localhost/docs.jsonld#DeprecatedResource/deprecatedField", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "", + maxCardinality: null, + deprecated: true + } + ], + readableFields: [ + { + name: "deprecatedField", + id: "http://localhost/docs.jsonld#DeprecatedResource/deprecatedField", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "", + maxCardinality: null, + deprecated: true + } + ], + writableFields: [ + { + name: "deprecatedField", + id: "http://localhost/docs.jsonld#DeprecatedResource/deprecatedField", + range: "http://www.w3.org/2001/XMLSchema#string", + reference: null, + required: true, + description: "", + maxCardinality: null, + deprecated: true + } + ], + operations: [ + { + name: "Retrieves the collection of DeprecatedResource resources.", + method: "GET", + returns: "http://www.w3.org/ns/hydra/core#Collection", + types: ["http://www.w3.org/ns/hydra/core#Operation", "schema:FindAction"], + deprecated: true + }, + { + name: "Retrieves DeprecatedResource resource.", + method: "GET", + returns: "http://localhost/docs.jsonld#DeprecatedResource", + types: ["http://www.w3.org/ns/hydra/core#Operation", "schema:FindAction"], + deprecated: true + } + ], + deprecated: true }; const expectedApi = { - "entrypoint": "http://localhost", - "title": "API Platform's demo", - "resources": [ - book, - review, - customResource - ] + entrypoint: "http://localhost", + title: "API Platform's demo", + resources: [book, review, customResource, deprecatedResource] }; const init = { status: 200, - statusText: 'OK', + statusText: "OK", headers: new Headers({ - 'Link': '; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"', - 'Content-Type': 'application/ld+json' + Link: + '; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"', + "Content-Type": "application/ld+json" }) }; -test('parse a Hydra documentation', () => { - fetch.mockResponses( - [entrypoint, init], - [docs, init], - ); +test("parse a Hydra documentation", () => { + fetch.mockResponses([entrypoint, init], [docs, init]); - const options = {headers: new Headers({'CustomHeader': 'customValue'})}; + const options = { headers: new Headers({ CustomHeader: "customValue" }) }; - return parseHydraDocumentation('http://localhost', options).then(data => { - expect(JSON.stringify(data.api, null, 2)).toBe(JSON.stringify(expectedApi, null, 2)); - expect(data.response).toBeDefined(); - expect(data.status).toBe(200); + return parseHydraDocumentation("http://localhost", options).then(data => { + expect(JSON.stringify(data.api, null, 2)).toBe( + JSON.stringify(expectedApi, null, 2) + ); + expect(data.response).toBeDefined(); + expect(data.status).toBe(200); - expect(fetch).toHaveBeenCalledTimes(2); - expect(fetch).toHaveBeenLastCalledWith('http://localhost/docs.jsonld', options); - } - ); + expect(fetch).toHaveBeenCalledTimes(2); + expect(fetch).toHaveBeenLastCalledWith( + "http://localhost/docs.jsonld", + options + ); + }); }); -test('parse a Hydra documentation (http://localhost/)', () => { - fetch.mockResponses( - [entrypoint, init], - [docs, init], - ); +test("parse a Hydra documentation (http://localhost/)", () => { + fetch.mockResponses([entrypoint, init], [docs, init]); - return parseHydraDocumentation('http://localhost/').then(data => { - expect(JSON.stringify(data.api, null, 2)).toBe(JSON.stringify(expectedApi, null, 2)); - expect(data.response).toBeDefined(); - expect(data.status).toBe(200); - } - ); + return parseHydraDocumentation("http://localhost/").then(data => { + expect(JSON.stringify(data.api, null, 2)).toBe( + JSON.stringify(expectedApi, null, 2) + ); + expect(data.response).toBeDefined(); + expect(data.status).toBe(200); + }); }); - -test('parse a Hydra documentation without authorization', () => { +test("parse a Hydra documentation without authorization", () => { const init = { status: 401, - statusText: 'Unauthorized', + statusText: "Unauthorized" }; const expectedApi = { - entrypoint: 'http://localhost', - resources: [], + entrypoint: "http://localhost", + resources: [] }; const expectedResponse = { code: 401, - message: 'JWT Token not found' + message: "JWT Token not found" }; - fetch.mockResponses( - [JSON.stringify(expectedResponse), init], - ); + fetch.mockResponses([JSON.stringify(expectedResponse), init]); - return parseHydraDocumentation('http://localhost').catch(async data => { + return parseHydraDocumentation("http://localhost").catch(async data => { expect(data.api).toEqual(expectedApi); expect(data.response).toBeDefined(); await expect(data.response.json()).resolves.toEqual(expectedResponse); @@ -990,13 +1173,9 @@ test('Parse entrypoint without "@type" key', () => { "customResource": "/customResources" }`; + fetch.mockResponses([entrypoint, init], [docs, init]); - fetch.mockResponses( - [entrypoint, init], - [docs, init], - ); - - parseHydraDocumentation('http://localhost/').catch(data => { + parseHydraDocumentation("http://localhost/").catch(data => { expect(data.message).toBe('The API entrypoint has no "@type" key.'); }); }); @@ -1037,14 +1216,12 @@ test('Parse entrypoint class without "supportedClass" key', () => { "hydra:entrypoint": "/" }`; + fetch.mockResponses([entrypoint, init], [docs, init]); - fetch.mockResponses( - [entrypoint, init], - [docs, init], - ); - - parseHydraDocumentation('http://localhost/').catch(data => { - expect(data.message).toBe('The API documentation has no "http://www.w3.org/ns/hydra/core#supportedClass" key or its value is not an array.'); + parseHydraDocumentation("http://localhost/").catch(data => { + expect(data.message).toBe( + 'The API documentation has no "http://www.w3.org/ns/hydra/core#supportedClass" key or its value is not an array.' + ); }); }); @@ -1097,44 +1274,35 @@ test('Parse entrypoint class without "supportedProperty" key', () => { ] }`; + fetch.mockResponses([entrypoint, init], [docs, init]); - fetch.mockResponses( - [entrypoint, init], - [docs, init], - ); - - parseHydraDocumentation('http://localhost/').catch(data => { - expect(data.message).toBe('The entrypoint definition has no "http://www.w3.org/ns/hydra/core#supportedProperty" key or it is not an array.'); + parseHydraDocumentation("http://localhost/").catch(data => { + expect(data.message).toBe( + 'The entrypoint definition has no "http://www.w3.org/ns/hydra/core#supportedProperty" key or it is not an array.' + ); }); }); - -test('Invalid docs JSON', () => { +test("Invalid docs JSON", () => { const docs = `{foo,}`; - fetch.mockResponses( - [entrypoint, init], - [docs, init], - ); + fetch.mockResponses([entrypoint, init], [docs, init]); - parseHydraDocumentation('http://localhost/').catch(data => { - expect(data).toHaveProperty('api'); - expect(data).toHaveProperty('response'); - expect(data).toHaveProperty('status'); + parseHydraDocumentation("http://localhost/").catch(data => { + expect(data).toHaveProperty("api"); + expect(data).toHaveProperty("response"); + expect(data).toHaveProperty("status"); }); }); -test('Invalid entrypoint JSON', () => { +test("Invalid entrypoint JSON", () => { const entrypoint = `{foo,}`; - fetch.mockResponses( - [entrypoint, init], - [docs, init], - ); + fetch.mockResponses([entrypoint, init], [docs, init]); - parseHydraDocumentation('http://localhost/').catch(data => { - expect(data).toHaveProperty('api'); - expect(data).toHaveProperty('response'); - expect(data).toHaveProperty('status'); + parseHydraDocumentation("http://localhost/").catch(data => { + expect(data).toHaveProperty("api"); + expect(data).toHaveProperty("response"); + expect(data).toHaveProperty("status"); }); }); diff --git a/src/index.js b/src/index.js index 8ed12ce..8e84d8f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ -export Api from './Api'; -export Resource from './Resource'; -export Field from './Field'; -export * from './hydra'; +export Api from "./Api"; +export Resource from "./Resource"; +export Field from "./Field"; +export * from "./hydra";