Socket
Socket
Sign inDemoInstall

druxt

Package Overview
Dependencies
Maintainers
1
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

druxt - npm Package Compare versions

Comparing version 0.3.4 to 0.4.0

nuxt/store.js

555

dist/druxt.esm.js
import { resolve } from 'path';
import axios from 'axios';
import { stringify } from 'querystring';
import md5 from 'md5';

@@ -330,2 +333,12 @@ /**

});
// Add Vuex plugin.
this.addPlugin({
src: resolve(__dirname, '../nuxt/store.js'),
fileName: 'store/druxt.js',
options: options
});
// Enable Vuex Store.
this.options.store = true;
};

@@ -467,2 +480,292 @@

/**
* Druxt JSON:API client.
*/
var DruxtClient = function DruxtClient(baseUrl, options) {
if ( options === void 0 ) options = {};
// Check for URL.
if (!baseUrl) {
throw new Error('The \'baseUrl\' parameter is required.')
}
// Setup Axios.
var axiosSettings = { baseURL: baseUrl };
if (typeof options.axios === 'object') {
axiosSettings = Object.assign(axiosSettings, options.axios);
delete options.axios;
}
/**
* The Axios instance.
*
* @see {@link https://github.com/axios/axios#instance-methods}
* @type {object}
*/
this.axios = axios.create(axiosSettings);
/**
* Druxt base options.
* @type {object}
* @private
*/
this.options = Object.assign({}, {endpoint: '/jsonapi',
jsonapiResourceConfig: 'jsonapi_resource_config--jsonapi_resource_config'},
options);
};
/**
* Add headers to the Axios instance.
*
* @example @lang js
* this.$druxt.addHeaders({ 'Authorization': `Basic ${token}` })
*
* @param {object} headers - An object containing HTTP headers.
*/
DruxtClient.prototype.addHeaders = function addHeaders (headers) {
if (typeof headers === 'undefined') {
return false
}
for (var name in headers) {
this.axios.defaults.headers.common[name] = headers[name];
}
};
/**
* Build query URL.
*
* @example @lang js
* const query = new DrupalJsonApiParams()
* query.addFilter('status', '1')
* const queryUrl = this.$druxt.buildQueryUrl(resourceUrl, query)
*
* @param {string} url - The base query URL.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @return {string} The URL with query string.
*/
DruxtClient.prototype.buildQueryUrl = function buildQueryUrl (url, query) {
if (!query) {
return url
}
// If Query is string...
if (typeof query === 'string') {
return query.charAt(0) === '?' ? url + query : [url, query].join('?')
}
// If Query is object with 'getQueryString' function, (e.g., drupal-jsonapi-params)...
if (typeof query === 'object' && typeof query.getQueryString === 'function') {
return [url, query.getQueryString()].join('?')
}
// If query is object...
if (typeof query === 'object' && Object.keys(query).length) {
return [url, stringify(query)].join('?')
}
// Else...
return url
};
/**
* Check response for permissions.
*
* @todo - Move this to utils?
*
* @param {object} res - Axios GET request response object.
*
* @private
*/
DruxtClient.prototype.checkPermissions = function checkPermissions (res) {
// Error handling: Required permissions.
if (res.data.meta && res.data.meta.omitted) {
var permissions = {};
delete res.data.meta.omitted.links.help;
for (var key in res.data.meta.omitted.links) {
var link = res.data.meta.omitted.links[key];
var match = link.meta.detail.match(/'(.*?)'/);
if (match && match[1]) {
permissions[match[1]] = true;
}
}
if (Object.keys(permissions).length) {
throw new TypeError(((res.data.meta.omitted.detail) + "\n\n Required permissions: " + (Object.keys(permissions).join(', ')) + "."))
}
}
};
/**
* Get a collection of resources from the JSON:API server.
*
* @param {string} type - The JSON:API Resource type.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @returns {object} The JSON:API collection response.
*
* @example @lang js
* const collection = await this.$druxt.getCollection('node--recipe')
*/
DruxtClient.prototype.getCollection = async function getCollection (type, query) {
var ref = await this.getIndex(type);
var href = ref.href;
if (!href) {
return false
}
var url = this.buildQueryUrl(href, query);
var res = await this.axios.get(url);
this.checkPermissions(res);
return res.data
};
/**
* Get all resources of a collection.
*
* @param {string} type - The JSON:API Resource type.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @returns {object[]} An array of JSON:API collections.
*
* @example @lang js
* const collections = await this.$druxt.getCollectionAll('node--recipe', 'fields[node--recipe]=title')
*/
DruxtClient.prototype.getCollectionAll = async function getCollectionAll (type, query) {
var collections = [];
var res = await this.getCollection(type, query);
collections.push(res);
while (((res.links || {}).next || {}).href) {
query = res.links.next.href.split('?')[1];
res = await this.getCollection(type, query);
collections.push(res);
}
return collections
};
/**
* Get index of all available resources, or the optionally specified resource.
*
* @example @lang js
* const { href } = await this.$druxt.getIndex('node--article')
*
* @param {string} resource - (Optional) A specific resource to query.
*
* @returns {object} The resource index object or the specified resource.
*/
DruxtClient.prototype.getIndex = async function getIndex (resource) {
if (this.index && !resource) {
return this.index
}
if (this.index && resource) {
return this.index[resource] ? this.index[resource] : false
}
var index = await this.axios.get(this.options.endpoint);
this.index = index.data.links;
// Use JSON API resource config to decorate the index.
if (this.index[this.options.jsonapiResourceConfig]) {
var resources = await this.axios.get(this.index[this.options.jsonapiResourceConfig].href);
for (var resourceType in resources.data.data) {
var resource$1 = resources.data.data[resourceType];
var internal = resource$1.attributes.drupal_internal__id.split('--');
var item = {
resourceType: resource$1.attributes.resourceType,
entityType: internal[0],
bundle: internal[1],
resourceFields: resource$1.attributes.resourceFields
};
var id = [item.entityType, item.bundle].join('--');
this.index[id] = Object.assign({}, item,
this.index[id]);
}
}
if (resource) {
return this.index[resource] ? this.index[resource] : false
}
return this.index
};
/**
* Get a JSON:API resource by type and ID.
*
* @example @lang js
* const data = await this.$druxt.getResource('node--article', id)
*
* @param {string} type - The JSON:API Resource type.
* @param {string} id - The Drupal resource UUID.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @returns {object} The JSON:API resource data.
*/
DruxtClient.prototype.getResource = async function getResource (type, id, query) {
if (!id || !type) {
return false
}
var ref = await this.getIndex(type);
var href = ref.href;
if (!href) {
href = this.options.endpoint + '/' + type.replace('--', '/');
}
var url = this.buildQueryUrl((href + "/" + id), query);
try {
var resource = await this.axios.get(url);
return resource.data
} catch (e) {
return false
}
};
/**
* DruxtClient options object.
*
* @typedef {object} DruxtClientOptions
*
* @param {object} [axios] - Axios instance settings.
* @param {string} [endpoint=jsonapi] - The JSON:API endpoint.
* @param {string} [jsonapiResourceConfig=jsonapi_resource_config--jsonapi_resource_config] -
* The JSON:API resource config type, used for [JSON:API Extras](https://www.drupal.org/project/jsonapi_extras) support.
*
* @see {@link https://github.com/axios/axios#request-config}
*
* @example @lang js
* {
* axios: {
* headers: { 'X-Custom-Header': true },
* },
* endpoint: 'api',
* }
*/
/**
* @typedef {string|object} DruxtClientQuery
*
* A correctly formatted JSON:API query string or object.
*
* @example
* page[limit]=5&page[offset]=5
*
* @example @lang js
* new DrupalJsonApiParams().addPageLimit(5)
*
* @see {@link https://www.npmjs.com/package/drupal-jsonapi-params}
*/
/**
* Vue.js Mixin to add Druxt component theming to a Druxt module.

@@ -571,3 +874,253 @@ *

var DruxtStore = function (ref) {
var store = ref.store;
if (typeof store === 'undefined') {
throw new TypeError('Vuex store not found.')
}
/**
* @namespace
*/
var namespace = 'druxt';
/**
* The DruxtStore Vuex module.
*
* Provides a Vuex state object, mutations and actions for interacting with the DruxtClient.
*
* @name druxt
* @module druxt
*/
var module = {
namespaced: true,
/**
* Vuex State object.
*
* @name state
* @type {object}
* @property {DruxtClientCollections} collections - JSON:API resource collections store.
* @property {object} resources - JSON:API resources store.
* @readonly
*/
state: function () { return ({
collections: {},
resources: {}
}); },
/**
* Vuex Mutations.
*/
mutations: {
/**
* @name addCollection
* @mutator {object} addCollection=collections Adds a JSON:API collection to the Vuex state object.
* @param {addCollectionContext} context
*
* @example @lang js
* this.$store.commit('druxt/addCollection', { collection, type, hash })
*/
addCollection: function addCollection (state, ref) {
var collection = ref.collection;
var type = ref.type;
var hash = ref.hash;
if (!state.collections[type]) { state.collections[type] = {}; }
state.collections[type][hash] = collection;
},
/**
* @name addResource
* @mutator {object} addResource=resources Adds a JSON:API resource to the Vuex state object.
* @param {addResourceContext} context
*
* @example @lang js
* this.$store.commit('druxt/addResource', { resource, hash })
*/
addResource: function addResource (state, ref) {
var resource = ref.resource;
var hash = ref.hash;
var ref$1 = (resource || {}).data || {};
var id = ref$1.id;
var type = ref$1.type;
if (!id || !type) {
// @TODO - Error?
return
}
if (!state.resources[type]) { state.resources[type] = {}; }
if (!state.resources[type][id]) { state.resources[type][id] = {}; }
state.resources[type][id][hash] = resource;
},
},
/**
* Vuex Actions.
*/
actions: {
/**
* Get collection of resources.
*
* @name getCollection
* @action getCollection
* @param {getCollectionContext} context
* @return {object[]} Array of Drupal JSON:API resource data.
*
* @example @lang js
* // Load all currently published Articles.
* const resources = await this.$store.dispatch('druxt/getCollection', {
* type: 'node--article',
* query: new DrupalJsonApiParams().addFilter('status', '1'),
* })
*/
getCollection: async function getCollection (ref, ref$1) {
var commit = ref.commit;
var state = ref.state;
var type = ref$1.type;
var query = ref$1.query;
var hash = query ? md5(this.$druxt.buildQueryUrl('', query)) : '_default';
if ((state.collections[type] || {})[hash]) {
return state.collections[type][hash]
}
var collection = await this.$druxt.getCollection(type, query);
commit('addCollection', { collection: collection, type: type, hash: hash });
var data = (collection || {}).data || [];
data.map(function (resource) {
commit('addResource', { resource: { data: resource }, hash: hash });
});
return collection
},
/**
* Get JSON:API Resource.
*
* - Executes query against Drupal JSON:API.
* - Caches result in the Vuex store.
* - Returns cached result from Vuex store when available.
*
* @name getResource
* @action getResource=resources
* @param {getResourceContext} context
* @return {object} The Drupal JSON:API resource.
*
* @example @lang js
* const resource = await this.$store.dispatch('druxt/getResource', { type: 'node--article', id })
*/
getResource: async function getResource (ref, ref$1) {
var commit = ref.commit;
var state = ref.state;
var type = ref$1.type;
var id = ref$1.id;
var query = ref$1.query;
var hash = query ? md5(this.$druxt.buildQueryUrl('', query)) : '_default';
if (typeof ((state.resources[type] || {})[id] || {})[hash] !== 'undefined') {
return state.resources[type][id][hash]
}
var resource = await this.$druxt.getResource(type, id, query);
commit('addResource', { resource: resource, hash: hash });
return resource
},
}
};
store.registerModule(namespace, module, {
preserveState: Boolean(store.state[namespace])
});
};
/**
* Parameters for the `addCollection` mutation.
*
* @typedef {object} addCollectionContext
*
* @param {object} collection - A collection of JSON:API resources.
* @param {string} type - The JSON:API collection resource type.
* @param {string} hash - An md5 hash of the query string.
*
* @example @lang js
* {
* collection: {
* jsonapi: {},
* data: [{}],
* links: {}
* },
* type: 'node--page',
* hash: '_default'
* }
*/
/**
* Parameters for the `addResource` mutation.
*
* @typedef {object} addResourceContext
*
* @param {object} resource - The JSON:API resource.
* @param {string} hash - An md5 hash of the query string.
*
* @example @lang js
* {
* resource: {
* jsonapi: {},
* data: {},
* links: {}
* },
* hash: '_default'
* }
*/
/**
* Parameters for the `getCollection` action.
*
* @typedef {object} getCollectionContext
*
* @param {string} type - The JSON:API collection resource type.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @example @lang js
* {
* type: 'node--page',
* query: new DrupalJsonApiParams().addFilter('status', '1')
* }
*/
/**
* Parameters for the `getResource` action.
*
* @typedef {object} getResourceContext
*
* @param {string} type - The JSON:API Resource type.
* @param {string} id - The Drupal resource UUID.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @example @lang js
* {
* type: 'node--page',
* id: 'd8dfd355-7f2f-4fc3-a149-288e4e293bdd'
* }
*/
/**
* @typedef {string|object} DruxtClientQuery
*
* A correctly formatted JSON:API query string or object.
*
* @example
* page[limit]=5&page[offset]=5
*
* @example @lang js
* new DrupalJsonApiParams().addPageLimit(5)
*
* @see {@link https://www.npmjs.com/package/drupal-jsonapi-params}
*/
export default DruxtNuxtModule;
export { __vue_component__ as Druxt, DruxtClass, DruxtComponentMixin, __vue_component__$1 as DruxtWrapper };
export { __vue_component__ as Druxt, DruxtClass, DruxtClient, DruxtComponentMixin, DruxtStore, __vue_component__$1 as DruxtWrapper };

2

dist/druxt.min.js

@@ -1,1 +0,1 @@

var Druxt=function(t,n){"use strict";function e(t,n,e,o,r,a,i,p,s,u){"boolean"!=typeof i&&(s=p,p=i,i=!1);var c,d="function"==typeof e?e.options:e;if(t&&t.render&&(d.render=t.render,d.staticRenderFns=t.staticRenderFns,d._compiled=!0,r&&(d.functional=!0)),o&&(d._scopeId=o),a?(c=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),n&&n.call(this,s(t)),t&&t._registeredComponents&&t._registeredComponents.add(a)},d._ssrRegister=c):n&&(c=i?function(t){n.call(this,u(t,this.$root.$options.shadowRoot))}:function(t){n.call(this,p(t))}),c)if(d.functional){var f=d.render;d.render=function(t,n){return c.call(n),f(t,n)}}else{var l=d.beforeCreate;d.beforeCreate=l?[].concat(l,c):[c]}return e}var o=e({},undefined,{name:"Druxt",props:{inner:{type:[Object,Boolean],default:function(){return{component:"div",propsData:{}}}},module:{type:String,required:!0},propsData:{type:Object,default:function(){return{}}},wrapper:{type:[Object,Boolean],default:function(){return{component:"div",propsData:{}}}}},data:function(){return{component:{is:void 0,propsData:{}}}},created:function(){this.setModuleComponent()},methods:{setModuleComponent:function(){var t="Druxt"+this.module.split("-").map((function(t){return t.charAt(0).toUpperCase()+t.slice(1)})).join("");this.$options.components[t]&&(this.component.is=t,this.component.propsData=this.propsData)}},render:function(t){var n=t(this.component.is,{props:Object.assign({},{wrapper:this.inner},this.component.propsData,this.$attrs)});return(this.wrapper||{}).component?t(this.wrapper.component,{props:this.wrapper.propsData},[n]):n}},undefined,undefined,undefined,!1,void 0,void 0,void 0),r=e({render:function(){var t=this,n=t.$createElement;return(t._self._c||n)("div",[t._t("default")],2)},staticRenderFns:[]},undefined,{name:"DruxtWrapper"},undefined,false,undefined,!1,void 0,void 0,void 0),a=function(){};a.prototype.getComponents=function(t,n,e,o){void 0===e&&(e=!1);var r=[],a={};return n.filter((function(t){return Array.isArray(t)})).map((function(n){var e=[];n.map((function(n){var r=e.length?[].concat(e[0].parts):[];r.push(n);var a=[].concat(r);"string"==typeof o||!1===o&&void 0!==o||!((t||{}).$options||{}).name||(o=t.$options.name.match(/[A-Z][a-z]+/g).map((function(t){return t.toLowerCase()})).join("-")),o&&a.unshift(o);var i=a.map((function(t){return t.toLowerCase().replace(/--|_/g,"-")})).join("-"),p=i.replace(/((\b|[^a-zA-Z0-9]+)[a-zA-Z0-9])/gi,(function(t,n,e){return t.toUpperCase().replace(e,"")})),s=!1;for(var u of[i,p])if(void 0!==(((t||{}).$options||{}).components||{})[u]){s=!0;break}e.unshift({global:s,kebab:i,parts:r,pascal:p,prefix:o})})),e.map((function(t){a[t.pascal]||(a[t.pascal]=!0,r.push(t))}))})),r.filter((function(t){return t.global||!!e})).sort((function(t,n){return n.parts.length-t.parts.length}))},a.prototype.getModuleData=async function(t){if("function"!=typeof((t||{}).$options||{}).druxt)return!1;var n=await t.$options.druxt({vm:t});return(t.$options||{}).name&&(n.name=t.$options.name.match(/[A-Z][a-z]+/g).map((function(t){return t.toLowerCase()})).join("-")),n};var i={components:{DruxtWrapper:r},data:function(){return{component:{is:"DruxtWrapper",options:[],propsData:{}}}},props:{wrapper:{type:Object,default:function(){return{component:"div",propsData:{}}}}},fetch:async function(){var t=new a,n=await t.getModuleData(this);if(this.component.propsData=n.propsData||{},n.componentOptions){var e=t.getComponents(this,n.componentOptions,!0);this.component.options=e.map((function(t){return t.pascal}));var o=e.filter((function(t){return t.global}));o.length&&(this.component.is=o[0].pascal)}}};return t.Druxt=o,t.DruxtClass=a,t.DruxtComponentMixin=i,t.DruxtWrapper=r,t.default=function(t){void 0===t&&(t={});var e=Object.assign({},t,(this.options||{}).druxt);this.addPlugin({src:n.resolve(__dirname,"../nuxt/plugin.js"),fileName:"druxt.js",options:e})},t}({},path);
var Druxt=function(t,e,n,o,r){"use strict";function i(t,e,n,o,r,i,a,s,u,p){"boolean"!=typeof a&&(u=s,s=a,a=!1);var c,d="function"==typeof n?n.options:n;if(t&&t.render&&(d.render=t.render,d.staticRenderFns=t.staticRenderFns,d._compiled=!0,r&&(d.functional=!0)),o&&(d._scopeId=o),i?(c=function(t){(t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext)||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),e&&e.call(this,u(t)),t&&t._registeredComponents&&t._registeredComponents.add(i)},d._ssrRegister=c):e&&(c=a?function(t){e.call(this,p(t,this.$root.$options.shadowRoot))}:function(t){e.call(this,s(t))}),c)if(d.functional){var l=d.render;d.render=function(t,e){return c.call(e),l(t,e)}}else{var f=d.beforeCreate;d.beforeCreate=f?[].concat(f,c):[c]}return n}n=n&&Object.prototype.hasOwnProperty.call(n,"default")?n.default:n,r=r&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r;var a=i({},undefined,{name:"Druxt",props:{inner:{type:[Object,Boolean],default:function(){return{component:"div",propsData:{}}}},module:{type:String,required:!0},propsData:{type:Object,default:function(){return{}}},wrapper:{type:[Object,Boolean],default:function(){return{component:"div",propsData:{}}}}},data:function(){return{component:{is:void 0,propsData:{}}}},created:function(){this.setModuleComponent()},methods:{setModuleComponent:function(){var t="Druxt"+this.module.split("-").map((function(t){return t.charAt(0).toUpperCase()+t.slice(1)})).join("");this.$options.components[t]&&(this.component.is=t,this.component.propsData=this.propsData)}},render:function(t){var e=t(this.component.is,{props:Object.assign({},{wrapper:this.inner},this.component.propsData,this.$attrs)});return(this.wrapper||{}).component?t(this.wrapper.component,{props:this.wrapper.propsData},[e]):e}},undefined,undefined,undefined,!1,void 0,void 0,void 0),s=i({render:function(){var t=this,e=t.$createElement;return(t._self._c||e)("div",[t._t("default")],2)},staticRenderFns:[]},undefined,{name:"DruxtWrapper"},undefined,false,undefined,!1,void 0,void 0,void 0),u=function(){};u.prototype.getComponents=function(t,e,n,o){void 0===n&&(n=!1);var r=[],i={};return e.filter((function(t){return Array.isArray(t)})).map((function(e){var n=[];e.map((function(e){var r=n.length?[].concat(n[0].parts):[];r.push(e);var i=[].concat(r);"string"==typeof o||!1===o&&void 0!==o||!((t||{}).$options||{}).name||(o=t.$options.name.match(/[A-Z][a-z]+/g).map((function(t){return t.toLowerCase()})).join("-")),o&&i.unshift(o);var a=i.map((function(t){return t.toLowerCase().replace(/--|_/g,"-")})).join("-"),s=a.replace(/((\b|[^a-zA-Z0-9]+)[a-zA-Z0-9])/gi,(function(t,e,n){return t.toUpperCase().replace(n,"")})),u=!1;for(var p of[a,s])if(void 0!==(((t||{}).$options||{}).components||{})[p]){u=!0;break}n.unshift({global:u,kebab:a,parts:r,pascal:s,prefix:o})})),n.map((function(t){i[t.pascal]||(i[t.pascal]=!0,r.push(t))}))})),r.filter((function(t){return t.global||!!n})).sort((function(t,e){return e.parts.length-t.parts.length}))},u.prototype.getModuleData=async function(t){if("function"!=typeof((t||{}).$options||{}).druxt)return!1;var e=await t.$options.druxt({vm:t});return(t.$options||{}).name&&(e.name=t.$options.name.match(/[A-Z][a-z]+/g).map((function(t){return t.toLowerCase()})).join("-")),e};var p=function(t,e){if(void 0===e&&(e={}),!t)throw new Error("The 'baseUrl' parameter is required.");var o={baseURL:t};"object"==typeof e.axios&&(o=Object.assign(o,e.axios),delete e.axios),this.axios=n.create(o),this.options=Object.assign({},{endpoint:"/jsonapi",jsonapiResourceConfig:"jsonapi_resource_config--jsonapi_resource_config"},e)};p.prototype.addHeaders=function(t){if(void 0===t)return!1;for(var e in t)this.axios.defaults.headers.common[e]=t[e]},p.prototype.buildQueryUrl=function(t,e){return e?"string"==typeof e?"?"===e.charAt(0)?t+e:[t,e].join("?"):"object"==typeof e&&"function"==typeof e.getQueryString?[t,e.getQueryString()].join("?"):"object"==typeof e&&Object.keys(e).length?[t,o.stringify(e)].join("?"):t:t},p.prototype.checkPermissions=function(t){if(t.data.meta&&t.data.meta.omitted){var e={};for(var n in delete t.data.meta.omitted.links.help,t.data.meta.omitted.links){var o=t.data.meta.omitted.links[n].meta.detail.match(/'(.*?)'/);o&&o[1]&&(e[o[1]]=!0)}if(Object.keys(e).length)throw new TypeError(t.data.meta.omitted.detail+"\n\n Required permissions: "+Object.keys(e).join(", ")+".")}},p.prototype.getCollection=async function(t,e){var n=(await this.getIndex(t)).href;if(!n)return!1;var o=this.buildQueryUrl(n,e),r=await this.axios.get(o);return this.checkPermissions(r),r.data},p.prototype.getCollectionAll=async function(t,e){var n=[],o=await this.getCollection(t,e);for(n.push(o);((o.links||{}).next||{}).href;)e=o.links.next.href.split("?")[1],o=await this.getCollection(t,e),n.push(o);return n},p.prototype.getIndex=async function(t){if(this.index&&!t)return this.index;if(this.index&&t)return!!this.index[t]&&this.index[t];var e=await this.axios.get(this.options.endpoint);if(this.index=e.data.links,this.index[this.options.jsonapiResourceConfig]){var n=await this.axios.get(this.index[this.options.jsonapiResourceConfig].href);for(var o in n.data.data){var r=n.data.data[o],i=r.attributes.drupal_internal__id.split("--"),a={resourceType:r.attributes.resourceType,entityType:i[0],bundle:i[1],resourceFields:r.attributes.resourceFields},s=[a.entityType,a.bundle].join("--");this.index[s]=Object.assign({},a,this.index[s])}}return t?!!this.index[t]&&this.index[t]:this.index},p.prototype.getResource=async function(t,e,n){if(!e||!t)return!1;var o=(await this.getIndex(t)).href;o||(o=this.options.endpoint+"/"+t.replace("--","/"));var r=this.buildQueryUrl(o+"/"+e,n);try{return(await this.axios.get(r)).data}catch(t){return!1}};var c={components:{DruxtWrapper:s},data:function(){return{component:{is:"DruxtWrapper",options:[],propsData:{}}}},props:{wrapper:{type:Object,default:function(){return{component:"div",propsData:{}}}}},fetch:async function(){var t=new u,e=await t.getModuleData(this);if(this.component.propsData=e.propsData||{},e.componentOptions){var n=t.getComponents(this,e.componentOptions,!0);this.component.options=n.map((function(t){return t.pascal}));var o=n.filter((function(t){return t.global}));o.length&&(this.component.is=o[0].pascal)}}};return t.Druxt=a,t.DruxtClass=u,t.DruxtClient=p,t.DruxtComponentMixin=c,t.DruxtStore=function(t){var e=t.store;if(void 0===e)throw new TypeError("Vuex store not found.");var n="druxt",o={namespaced:!0,state:function(){return{collections:{},resources:{}}},mutations:{addCollection:function(t,e){var n=e.collection,o=e.type,r=e.hash;t.collections[o]||(t.collections[o]={}),t.collections[o][r]=n},addResource:function(t,e){var n=e.resource,o=e.hash,r=(n||{}).data||{},i=r.id,a=r.type;i&&a&&(t.resources[a]||(t.resources[a]={}),t.resources[a][i]||(t.resources[a][i]={}),t.resources[a][i][o]=n)}},actions:{getCollection:async function(t,e){var n=t.commit,o=t.state,i=e.type,a=e.query,s=a?r(this.$druxt.buildQueryUrl("",a)):"_default";if((o.collections[i]||{})[s])return o.collections[i][s];var u=await this.$druxt.getCollection(i,a);return n("addCollection",{collection:u,type:i,hash:s}),((u||{}).data||[]).map((function(t){n("addResource",{resource:{data:t},hash:s})})),u},getResource:async function(t,e){var n=t.commit,o=t.state,i=e.type,a=e.id,s=e.query,u=s?r(this.$druxt.buildQueryUrl("",s)):"_default";if(void 0!==((o.resources[i]||{})[a]||{})[u])return o.resources[i][a][u];var p=await this.$druxt.getResource(i,a,s);return n("addResource",{resource:p,hash:u}),p}}};e.registerModule(n,o,{preserveState:Boolean(e.state.druxt)})},t.DruxtWrapper=s,t.default=function(t){void 0===t&&(t={});var n=Object.assign({},t,(this.options||{}).druxt);this.addPlugin({src:e.resolve(__dirname,"../nuxt/plugin.js"),fileName:"druxt.js",options:n}),this.addPlugin({src:e.resolve(__dirname,"../nuxt/store.js"),fileName:"store/druxt.js",options:n}),this.options.store=!0},t}({},path,axios,querystring,md5);

@@ -1,2 +0,2 @@

'use strict';Object.defineProperty(exports,'__esModule',{value:true});var path=require('path');/**
'use strict';Object.defineProperty(exports,'__esModule',{value:true});function _interopDefault(e){return(e&&(typeof e==='object')&&'default'in e)?e['default']:e}var path=require('path'),axios=_interopDefault(require('axios')),querystring=require('querystring'),md5=_interopDefault(require('md5'));/**
* The Vue.js Druxt component.

@@ -318,2 +318,12 @@ *

});
// Add Vuex plugin.
this.addPlugin({
src: path.resolve(__dirname, '../nuxt/store.js'),
fileName: 'store/druxt.js',
options: options
});
// Enable Vuex Store.
this.options.store = true;
};

@@ -451,2 +461,290 @@

*//**
* Druxt JSON:API client.
*/
var DruxtClient = function DruxtClient(baseUrl, options) {
if ( options === void 0 ) options = {};
// Check for URL.
if (!baseUrl) {
throw new Error('The \'baseUrl\' parameter is required.')
}
// Setup Axios.
var axiosSettings = { baseURL: baseUrl };
if (typeof options.axios === 'object') {
axiosSettings = Object.assign(axiosSettings, options.axios);
delete options.axios;
}
/**
* The Axios instance.
*
* @see {@link https://github.com/axios/axios#instance-methods}
* @type {object}
*/
this.axios = axios.create(axiosSettings);
/**
* Druxt base options.
* @type {object}
* @private
*/
this.options = Object.assign({}, {endpoint: '/jsonapi',
jsonapiResourceConfig: 'jsonapi_resource_config--jsonapi_resource_config'},
options);
};
/**
* Add headers to the Axios instance.
*
* @example @lang js
* this.$druxt.addHeaders({ 'Authorization': `Basic ${token}` })
*
* @param {object} headers - An object containing HTTP headers.
*/
DruxtClient.prototype.addHeaders = function addHeaders (headers) {
if (typeof headers === 'undefined') {
return false
}
for (var name in headers) {
this.axios.defaults.headers.common[name] = headers[name];
}
};
/**
* Build query URL.
*
* @example @lang js
* const query = new DrupalJsonApiParams()
* query.addFilter('status', '1')
* const queryUrl = this.$druxt.buildQueryUrl(resourceUrl, query)
*
* @param {string} url - The base query URL.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @return {string} The URL with query string.
*/
DruxtClient.prototype.buildQueryUrl = function buildQueryUrl (url, query) {
if (!query) {
return url
}
// If Query is string...
if (typeof query === 'string') {
return query.charAt(0) === '?' ? url + query : [url, query].join('?')
}
// If Query is object with 'getQueryString' function, (e.g., drupal-jsonapi-params)...
if (typeof query === 'object' && typeof query.getQueryString === 'function') {
return [url, query.getQueryString()].join('?')
}
// If query is object...
if (typeof query === 'object' && Object.keys(query).length) {
return [url, querystring.stringify(query)].join('?')
}
// Else...
return url
};
/**
* Check response for permissions.
*
* @todo - Move this to utils?
*
* @param {object} res - Axios GET request response object.
*
* @private
*/
DruxtClient.prototype.checkPermissions = function checkPermissions (res) {
// Error handling: Required permissions.
if (res.data.meta && res.data.meta.omitted) {
var permissions = {};
delete res.data.meta.omitted.links.help;
for (var key in res.data.meta.omitted.links) {
var link = res.data.meta.omitted.links[key];
var match = link.meta.detail.match(/'(.*?)'/);
if (match && match[1]) {
permissions[match[1]] = true;
}
}
if (Object.keys(permissions).length) {
throw new TypeError(((res.data.meta.omitted.detail) + "\n\n Required permissions: " + (Object.keys(permissions).join(', ')) + "."))
}
}
};
/**
* Get a collection of resources from the JSON:API server.
*
* @param {string} type - The JSON:API Resource type.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @returns {object} The JSON:API collection response.
*
* @example @lang js
* const collection = await this.$druxt.getCollection('node--recipe')
*/
DruxtClient.prototype.getCollection = async function getCollection (type, query) {
var ref = await this.getIndex(type);
var href = ref.href;
if (!href) {
return false
}
var url = this.buildQueryUrl(href, query);
var res = await this.axios.get(url);
this.checkPermissions(res);
return res.data
};
/**
* Get all resources of a collection.
*
* @param {string} type - The JSON:API Resource type.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @returns {object[]} An array of JSON:API collections.
*
* @example @lang js
* const collections = await this.$druxt.getCollectionAll('node--recipe', 'fields[node--recipe]=title')
*/
DruxtClient.prototype.getCollectionAll = async function getCollectionAll (type, query) {
var collections = [];
var res = await this.getCollection(type, query);
collections.push(res);
while (((res.links || {}).next || {}).href) {
query = res.links.next.href.split('?')[1];
res = await this.getCollection(type, query);
collections.push(res);
}
return collections
};
/**
* Get index of all available resources, or the optionally specified resource.
*
* @example @lang js
* const { href } = await this.$druxt.getIndex('node--article')
*
* @param {string} resource - (Optional) A specific resource to query.
*
* @returns {object} The resource index object or the specified resource.
*/
DruxtClient.prototype.getIndex = async function getIndex (resource) {
if (this.index && !resource) {
return this.index
}
if (this.index && resource) {
return this.index[resource] ? this.index[resource] : false
}
var index = await this.axios.get(this.options.endpoint);
this.index = index.data.links;
// Use JSON API resource config to decorate the index.
if (this.index[this.options.jsonapiResourceConfig]) {
var resources = await this.axios.get(this.index[this.options.jsonapiResourceConfig].href);
for (var resourceType in resources.data.data) {
var resource$1 = resources.data.data[resourceType];
var internal = resource$1.attributes.drupal_internal__id.split('--');
var item = {
resourceType: resource$1.attributes.resourceType,
entityType: internal[0],
bundle: internal[1],
resourceFields: resource$1.attributes.resourceFields
};
var id = [item.entityType, item.bundle].join('--');
this.index[id] = Object.assign({}, item,
this.index[id]);
}
}
if (resource) {
return this.index[resource] ? this.index[resource] : false
}
return this.index
};
/**
* Get a JSON:API resource by type and ID.
*
* @example @lang js
* const data = await this.$druxt.getResource('node--article', id)
*
* @param {string} type - The JSON:API Resource type.
* @param {string} id - The Drupal resource UUID.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @returns {object} The JSON:API resource data.
*/
DruxtClient.prototype.getResource = async function getResource (type, id, query) {
if (!id || !type) {
return false
}
var ref = await this.getIndex(type);
var href = ref.href;
if (!href) {
href = this.options.endpoint + '/' + type.replace('--', '/');
}
var url = this.buildQueryUrl((href + "/" + id), query);
try {
var resource = await this.axios.get(url);
return resource.data
} catch (e) {
return false
}
};
/**
* DruxtClient options object.
*
* @typedef {object} DruxtClientOptions
*
* @param {object} [axios] - Axios instance settings.
* @param {string} [endpoint=jsonapi] - The JSON:API endpoint.
* @param {string} [jsonapiResourceConfig=jsonapi_resource_config--jsonapi_resource_config] -
* The JSON:API resource config type, used for [JSON:API Extras](https://www.drupal.org/project/jsonapi_extras) support.
*
* @see {@link https://github.com/axios/axios#request-config}
*
* @example @lang js
* {
* axios: {
* headers: { 'X-Custom-Header': true },
* },
* endpoint: 'api',
* }
*/
/**
* @typedef {string|object} DruxtClientQuery
*
* A correctly formatted JSON:API query string or object.
*
* @example
* page[limit]=5&page[offset]=5
*
* @example @lang js
* new DrupalJsonApiParams().addPageLimit(5)
*
* @see {@link https://www.npmjs.com/package/drupal-jsonapi-params}
*//**
* Vue.js Mixin to add Druxt component theming to a Druxt module.

@@ -553,2 +851,250 @@ *

* }
*/exports.Druxt=__vue_component__;exports.DruxtClass=DruxtClass;exports.DruxtComponentMixin=DruxtComponentMixin;exports.DruxtWrapper=__vue_component__$1;exports.default=DruxtNuxtModule;
*/var DruxtStore = function (ref) {
var store = ref.store;
if (typeof store === 'undefined') {
throw new TypeError('Vuex store not found.')
}
/**
* @namespace
*/
var namespace = 'druxt';
/**
* The DruxtStore Vuex module.
*
* Provides a Vuex state object, mutations and actions for interacting with the DruxtClient.
*
* @name druxt
* @module druxt
*/
var module = {
namespaced: true,
/**
* Vuex State object.
*
* @name state
* @type {object}
* @property {DruxtClientCollections} collections - JSON:API resource collections store.
* @property {object} resources - JSON:API resources store.
* @readonly
*/
state: function () { return ({
collections: {},
resources: {}
}); },
/**
* Vuex Mutations.
*/
mutations: {
/**
* @name addCollection
* @mutator {object} addCollection=collections Adds a JSON:API collection to the Vuex state object.
* @param {addCollectionContext} context
*
* @example @lang js
* this.$store.commit('druxt/addCollection', { collection, type, hash })
*/
addCollection: function addCollection (state, ref) {
var collection = ref.collection;
var type = ref.type;
var hash = ref.hash;
if (!state.collections[type]) { state.collections[type] = {}; }
state.collections[type][hash] = collection;
},
/**
* @name addResource
* @mutator {object} addResource=resources Adds a JSON:API resource to the Vuex state object.
* @param {addResourceContext} context
*
* @example @lang js
* this.$store.commit('druxt/addResource', { resource, hash })
*/
addResource: function addResource (state, ref) {
var resource = ref.resource;
var hash = ref.hash;
var ref$1 = (resource || {}).data || {};
var id = ref$1.id;
var type = ref$1.type;
if (!id || !type) {
// @TODO - Error?
return
}
if (!state.resources[type]) { state.resources[type] = {}; }
if (!state.resources[type][id]) { state.resources[type][id] = {}; }
state.resources[type][id][hash] = resource;
},
},
/**
* Vuex Actions.
*/
actions: {
/**
* Get collection of resources.
*
* @name getCollection
* @action getCollection
* @param {getCollectionContext} context
* @return {object[]} Array of Drupal JSON:API resource data.
*
* @example @lang js
* // Load all currently published Articles.
* const resources = await this.$store.dispatch('druxt/getCollection', {
* type: 'node--article',
* query: new DrupalJsonApiParams().addFilter('status', '1'),
* })
*/
getCollection: async function getCollection (ref, ref$1) {
var commit = ref.commit;
var state = ref.state;
var type = ref$1.type;
var query = ref$1.query;
var hash = query ? md5(this.$druxt.buildQueryUrl('', query)) : '_default';
if ((state.collections[type] || {})[hash]) {
return state.collections[type][hash]
}
var collection = await this.$druxt.getCollection(type, query);
commit('addCollection', { collection: collection, type: type, hash: hash });
var data = (collection || {}).data || [];
data.map(function (resource) {
commit('addResource', { resource: { data: resource }, hash: hash });
});
return collection
},
/**
* Get JSON:API Resource.
*
* - Executes query against Drupal JSON:API.
* - Caches result in the Vuex store.
* - Returns cached result from Vuex store when available.
*
* @name getResource
* @action getResource=resources
* @param {getResourceContext} context
* @return {object} The Drupal JSON:API resource.
*
* @example @lang js
* const resource = await this.$store.dispatch('druxt/getResource', { type: 'node--article', id })
*/
getResource: async function getResource (ref, ref$1) {
var commit = ref.commit;
var state = ref.state;
var type = ref$1.type;
var id = ref$1.id;
var query = ref$1.query;
var hash = query ? md5(this.$druxt.buildQueryUrl('', query)) : '_default';
if (typeof ((state.resources[type] || {})[id] || {})[hash] !== 'undefined') {
return state.resources[type][id][hash]
}
var resource = await this.$druxt.getResource(type, id, query);
commit('addResource', { resource: resource, hash: hash });
return resource
},
}
};
store.registerModule(namespace, module, {
preserveState: Boolean(store.state[namespace])
});
};
/**
* Parameters for the `addCollection` mutation.
*
* @typedef {object} addCollectionContext
*
* @param {object} collection - A collection of JSON:API resources.
* @param {string} type - The JSON:API collection resource type.
* @param {string} hash - An md5 hash of the query string.
*
* @example @lang js
* {
* collection: {
* jsonapi: {},
* data: [{}],
* links: {}
* },
* type: 'node--page',
* hash: '_default'
* }
*/
/**
* Parameters for the `addResource` mutation.
*
* @typedef {object} addResourceContext
*
* @param {object} resource - The JSON:API resource.
* @param {string} hash - An md5 hash of the query string.
*
* @example @lang js
* {
* resource: {
* jsonapi: {},
* data: {},
* links: {}
* },
* hash: '_default'
* }
*/
/**
* Parameters for the `getCollection` action.
*
* @typedef {object} getCollectionContext
*
* @param {string} type - The JSON:API collection resource type.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @example @lang js
* {
* type: 'node--page',
* query: new DrupalJsonApiParams().addFilter('status', '1')
* }
*/
/**
* Parameters for the `getResource` action.
*
* @typedef {object} getResourceContext
*
* @param {string} type - The JSON:API Resource type.
* @param {string} id - The Drupal resource UUID.
* @param {DruxtClientQuery} [query] - A correctly formatted JSON:API query string or object.
*
* @example @lang js
* {
* type: 'node--page',
* id: 'd8dfd355-7f2f-4fc3-a149-288e4e293bdd'
* }
*/
/**
* @typedef {string|object} DruxtClientQuery
*
* A correctly formatted JSON:API query string or object.
*
* @example
* page[limit]=5&page[offset]=5
*
* @example @lang js
* new DrupalJsonApiParams().addPageLimit(5)
*
* @see {@link https://www.npmjs.com/package/drupal-jsonapi-params}
*/exports.Druxt=__vue_component__;exports.DruxtClass=DruxtClass;exports.DruxtClient=DruxtClient;exports.DruxtComponentMixin=DruxtComponentMixin;exports.DruxtStore=DruxtStore;exports.DruxtWrapper=__vue_component__$1;exports.default=DruxtNuxtModule;
import Vue from 'vue'
import { Druxt, DruxtWrapper } from 'druxt'
import { Druxt, DruxtClient, DruxtWrapper } from 'druxt'

@@ -15,1 +15,18 @@ // Install the Druxt Vue.js component.

})
export default (context, inject) => {
const baseUrl = '<%= options.baseUrl %>'
const options = {}
<% if (options.endpoint) { %>
options.endpoint = '<%= options.endpoint %>'
<% } %>
<% if (typeof options.axios === 'object') { %>
// Axios settings.
options.axios = <%= JSON.stringify(options.axios) %>
<% } %>
const druxt = new DruxtClient(baseUrl, options)
inject('druxt', druxt)
}
{
"name": "druxt",
"version": "0.3.4",
"version": "0.4.0",
"description": "A Bridge between frameworks, NuxtJS in the front, Drupal in the back.",

@@ -34,4 +34,4 @@ "repository": {

"dev": "nodemon --ext js,vue --exec 'npm run lint && npm run build && npm run test'",
"docs:dev": "npx druxt-docgen dev",
"docs:build": "npx druxt-docgen build",
"docs:dev": "npx druxt-docgen -c vuepress.config dev",
"docs:build": "npx druxt-docgen -c vuepress.config build",
"lint": "eslint --ext .js,.vue src",

@@ -47,3 +47,5 @@ "start": "npm run dev",

"dependencies": {
"axios": "^0.21.1",
"codecov": "^3.8.1",
"querystring": "^0.2.0",
"vuex": "^3.6.0"

@@ -62,2 +64,3 @@ },

"cross-env": "^6.0.3",
"druxt-docgen": "^0.4.0",
"eslint": "^6.7.2",

@@ -64,0 +67,0 @@ "eslint-plugin-vue": "^6.2.2",

@@ -21,5 +21,25 @@ # DruxtJS; A bridge between frameworks.

## Usage
### DruxtClient
The DruxtClient is the communication layer between Nuxt and the Drupal JSON:API.
**Example:**
```js
const { DruxtClient } = require('druxt')
const druxt = new DruxtClient('https://demo-api.druxtjs.org')
druxt.getCollection('node--page').then((res) => {
...
})
```
Get started with the [Guide](https://druxtjs.org/guide/) and [API Documentation](https://druxtjs.org/api/client).
### Nuxt Module / Plugin
The Nuxt module adds the Vue components, Vuex store and DruxtClient plugin to your Nuxt application.
Add module to `nuxt.config.js`

@@ -38,3 +58,21 @@

The `$druxt` plugin gives your Nuxt application access to the `DruxtClient`.
**Example:**
```vue
<script>
export default {
data: () => ({ page: null }),
async fetch() {
this.page = await this.$druxt.getResource({
type: 'node--page',
id: 'd8dfd355-7f2f-4fc3-a149-288e4e293bdd',
})
},
}
</script>
```
### The Druxt component

@@ -41,0 +79,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc