@dgayerie/siren
Version:
A lightweight library to easily integrate JSON Hypermedia with Siren format. https://github.com/kevinswiber/siren
1 lines • 5.08 kB
JavaScript
const entitySymbol=Symbol(),subEntitiesSymbol=Symbol(),postConstructSymbol=Symbol();class SirenError extends Error{constructor(t){super(t)}}function areEqual(t,e){return Array.isArray(t)?Array.isArray(e)&&t.length===e.length&&t.every((t=>e.includes(t))):t===e}const siren={};class QueryBuilder{constructor(t){this.listOfElements=t,this.filters=[]}withRel(...t){return this.filters.push((e=>areEqual(e.rel,t))),this}withClass(...t){return this.filters.push((e=>areEqual(e.class,t))),this}ofType(t){return this.filters.push((e=>e.type===t)),this}getAll(){return this.listOfElements.filter((t=>this.filters.every((e=>e(t)))))}exists(){return this.get()!==emptyEntity}get(){const t=t=>this.filters.every((e=>e(t)));for(const e of this.listOfElements)if(t(e))return e;return emptyEntity}}export class SirenQuery{constructor(t){this.entity=siren.entity(t)}get entities(){return new QueryBuilder(this.entity.entities())}get links(){return new QueryBuilder(this.entity.links())}get entitiesAndLinks(){return new QueryBuilder([...this.entity.entities(),...this.entity.links()])}}export class SirenEntity{constructor(t,e){this[entitySymbol]=t,"function"==typeof e&&(this[postConstructSymbol]=e,e(this))}get query(){return new SirenQuery(this)}hasClass(t){return!!this[entitySymbol].class&&this[entitySymbol].class.includes(t)}get class(){return this[entitySymbol].class||[]}get title(){return this[entitySymbol].title||""}get type(){return this[entitySymbol].type||""}get properties(){return null!==this[entitySymbol].properties&&void 0!==this[entitySymbol].properties||(this[entitySymbol].properties={}),this[entitySymbol].properties}get href(){return this[entitySymbol].href?this[entitySymbol].href:this.link("self").href}get rel(){return this[entitySymbol].rel}property(t,e){const i=this.properties[t];return null==i?e:i}setProperty(t,e){this[entitySymbol].properties[t]=e}links(t){const e=this[entitySymbol].links||[];return t?("string"==typeof t&&(t=[t]),Array.isArray(t)?e.filter((e=>areEqual(t,e.rel))):e.filter((e=>{for(const i in t)if(!areEqual(e[i],t[i]))return!1;return!0}))):e}hasLink(t){return siren.isLink(this.link(t))}link(t){if("string"==typeof t&&(t=[t]),Array.isArray(t)){for(const e of this.links())if(areEqual(t,e.rel))return e}else for(const e of this.links()){let i=!0;for(const n in t)if(!areEqual(t[n],e[n])){i=!1;break}if(i)return e}return emptyLink}setLink(t){null!==this[entitySymbol].links&&void 0!==this[entitySymbol].links||(this[entitySymbol].links=[]);const e=this[entitySymbol].links;for(let i=0;i<e.length;++i)if(areEqual(e[i].rel,t.rel))return void(e[i]=t);this[entitySymbol].links.push(t)}setLinkHref(t,e){null!==this[entitySymbol].links&&void 0!==this[entitySymbol].links||(this[entitySymbol].links=[]),Array.isArray(t)||(t=[t]);for(const i of this[entitySymbol].links)if(areEqual(i.rel,t))return void(i.href=e);this[entitySymbol].links.push({rel:t,href:e})}addLink(t){null!==this[entitySymbol].links&&void 0!==this[entitySymbol].links||(this[entitySymbol].links=[]),this[entitySymbol].links.push(t)}hasEntity(t,e){if(this[entitySymbol].entities){"string"==typeof t&&(t=[t]),"string"==typeof e&&(e=[e]);for(const i of this[entitySymbol].entities)if(areEqual(i.rel,t)){if(!e)return!0;if(areEqual(i.class,e))return!0}}return!1}entities(t,e){return!this[subEntitiesSymbol]&&this[entitySymbol].entities&&(this[subEntitiesSymbol]=this[entitySymbol].entities.map((t=>siren.entity(t,this[postConstructSymbol])))),t?("string"==typeof t&&(t=[t]),"string"==typeof e&&(e=[e]),e?this.entities().filter((e=>areEqual(e.rel,t))).filter((t=>areEqual(t.class,e))):this.entities().filter((e=>areEqual(e.rel,t)))):this[subEntitiesSymbol]||[]}entity(t,e){"string"==typeof t&&(t=[t]),"string"==typeof e&&(e=[e]);for(const i of this.entities())if(areEqual(i.rel,t)){if(!e)return i;if(areEqual(i.class,e))return i}return emptyEntity}toJSON(){return this[entitySymbol]}}const emptyEntity=Object.freeze(new SirenEntity({})),emptyLink=Object.freeze({});siren.mimeType="application/vnd.siren+json",siren.entity=function(t,e){return t?siren.isEntity(t)?t:new SirenEntity(t,e):emptyEntity},siren.isEntity=function(t){return t instanceof SirenEntity},siren.isLink=function(t){return!!(t&&t.href&&t.rel)},siren.isSubEntity=function(t){return!(!siren.isEntity(t)||!t.rel)},siren.isSubEntityEmbeddedLink=function(t){return!(!siren.isEntity(t)||!siren.isLink(t))},siren.request=function(t){let e;if(siren.isLink(t)?e=t:siren.isEntity(t)&&(e=t.link("self")),!siren.isLink(e))throw new SirenError("No link information found to create request for this entity");const i=new Headers;return e.type?i.set("Accept",e.type):i.set("Accept",`${siren.mimeType},application/json;q=0.9,*/*;q=0.8`),new Request(e.href,{method:"GET",headers:i})},siren.visitLinks=function(t,e,i=!1){if(siren.isEntity(t)){"string"==typeof t[entitySymbol].href&&e(t[entitySymbol]);for(const i of t.links())siren.isLink(i)&&e(i);if(i)for(const i of t.entities())siren.visitLinks(i,e)}else siren.isLink(t)&&e(t)},siren.same=function(t,e){if(!t||!e)return!1;const i=t.href,n=e.href;return!!i&&i===n};export default siren;