Skip to content
Snippets Groups Projects
Commit b2817e9b authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

#20 #21 #22 #23

parent 1b3bdd2f
No related branches found
No related tags found
No related merge requests found
Showing
with 1325 additions and 85 deletions
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -69,7 +69,7 @@
},
"codepen": {
"enable_for": [
"examples"
"examples","tutorials"
],
"options": {
"title": "awaken the monster in you; javascript library by schukai GmbH",
......
......@@ -2,11 +2,14 @@
All notable changes to this project will be documented in this file.
## [1.7.0] - 2021-07-31
## [1.7.0] - 2021-08-07
### Added
- [new Monster.DOM.CustomElement](https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/20)
- [new Monster.DOM.Theme](https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/21)
- [new Monster.Types.getType](https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/22)
- [new Monster.Data.buildMap](https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/23)
## [1.6.0] - 2021-07-29
......
/** Monster 1.7.0, © 2021 schukai GmbH, Released under the AGPL 3.0 License. */
'use strict';import{Monster}from"../namespace.js";import{isFunction}from"../types/is.js";import{validateString}from"../types/validate.js";import{Pathfinder}from"./pathfinder.js";function buildMap(subject,selector,valuePath,keyPath,filter){validateString(selector);const result=new Map;let finder=new Pathfinder(subject);let map=finder.getVia(selector);if(!(map instanceof Map)){return result}map.forEach((v,k,m)=>{if(isFunction(filter)){if(filter.call(m,v,k)!==true)return}k=build(v,keyPath,k);v=build(v,valuePath);result.set(k,v)});return result}function build(subject,definition,defaultValue){if(definition===undefined)return defaultValue?defaultValue:subject;validateString(definition);const regexp=/(?<placeholder>\$\{(?<path>[a-z.-]*)\})/gm;const array=[...definition.matchAll(regexp)];let finder=new Pathfinder(subject);if(array.length===0){return finder.getVia(definition)}array.forEach(a=>{let groups=a?.["groups"];let placeholder=groups?.["placeholder"];if(placeholder===undefined)return;let path=groups?.["path"];let v=finder.getVia(path);definition=definition.replaceAll(placeholder,v)});return definition}Monster.assignToNamespace("Monster.Data",buildMap);export{Monster,buildMap};
/** Monster 1.7.0, © 2021 schukai GmbH, Released under the AGPL 3.0 License. */
'use strict';import{Monster}from"../namespace.js";import{isObject,isArray,isInteger}from"../types/is.js";import{validateString,validateInteger}from"../types/validate.js";import{Base}from"../types/base.js";import{Stack}from"../types/stack.js";const DELIMITER=".";class Pathfinder extends Base{constructor(object){super();this.object=object}getVia(path){validateString(path);return getValueViaPath(this.object,path)}setVia(path,value){validateString(path);setValueViaPath(this.object,path,value);return this}deleteVia(path){validateString(path);deleteValueViaPath(this.object,path);return this}exists(path){validateString(path);try{getValueViaPath(this.object,path,true);return true}catch(e){}return false}}Monster.assignToNamespace("Monster.Data",Pathfinder);export{Monster,Pathfinder};function getValueViaPath(object,path,check){if(path===""){return object}let parts=path.split(DELIMITER);let current=parts.shift();if(isObject(object)||isArray(object)){let anchor;if(object instanceof Map||object instanceof WeakMap){anchor=object.get(current)}else if(object instanceof Set||object instanceof WeakSet){current=parseInt(current);validateInteger(current);anchor=[...object]?.[current]}else if(object instanceof WeakRef){throw Error("unsupported action for this data type")}else if(isArray(object)){current=parseInt(current);validateInteger(current);anchor=object?.[current]}else{anchor=object?.[current]}if(isObject(anchor)||isArray(anchor)){return getValueViaPath(anchor,parts.join(DELIMITER),check)}if(parts.length>0){throw Error("the journey is not at its end ("+parts.join(DELIMITER)+")")}if(check===true&&!object.hasOwnProperty(current)){throw Error("unknown value")}return anchor}throw TypeError("unsupported type")}function setValueViaPath(object,path,value){let parts=path.split(DELIMITER);let last=parts.pop();let subpath=parts.join(DELIMITER);let stack=new Stack;let current=subpath;while(true){try{getValueViaPath(object,current,true);break}catch(e){}stack.push(current);parts.pop();current=parts.join(DELIMITER);if(current==="")break}while(!stack.isEmpty()){current=stack.pop();let obj={};if(!stack.isEmpty()){let n=stack.peek().split(DELIMITER).pop();if(isInteger(parseInt(n))){obj=[]}}setValueViaPath(object,current,obj)}let anchor=getValueViaPath(object,subpath);if(!isObject(object)&&!isArray(object)){throw TypeError("unsupported type: "+typeof object)}if(anchor instanceof Map||anchor instanceof WeakMap){anchor.set(last,value)}else if(anchor instanceof Set||anchor instanceof WeakSet){anchor.append(value)}else if(anchor instanceof WeakRef){throw Error("unsupported action for this data type")}else if(isArray(anchor)){last=parseInt(last);validateInteger(last);anchor[last]=value}else{anchor[last]=value}return}function deleteValueViaPath(object,path){const parts=path.split(DELIMITER);let last=parts.pop();const subpath=parts.join(DELIMITER);const anchor=getValueViaPath.call(this,object,subpath);if(anchor instanceof Map){anchor.delete(last)}else if(anchor instanceof Set||anchor instanceof WeakMap||anchor instanceof WeakSet||anchor instanceof WeakRef){throw Error("unsupported action for this data type")}else if(isArray(anchor)){last=parseInt(last);validateInteger(last);delete anchor[last]}else{delete anchor[last]}return}
'use strict';import{Monster}from"../namespace.js";import{isObject,isArray,isInteger}from"../types/is.js";import{validateString,validateInteger}from"../types/validate.js";import{Base}from"../types/base.js";import{Stack}from"../types/stack.js";const DELIMITER=".";const WILDCARD="*";class Pathfinder extends Base{constructor(object){super();this.object=object;this.wildCard=WILDCARD}setWildCard(wildcard){validateString(wildcard);this.wildCard=wildcard;return this}getVia(path){validateString(path);return getValueViaPath.call(this,this.object,path)}setVia(path,value){validateString(path);setValueViaPath.call(this,this.object,path,value);return this}deleteVia(path){validateString(path);deleteValueViaPath.call(this,this.object,path);return this}exists(path){validateString(path);try{getValueViaPath.call(this,this.object,path,true);return true}catch(e){}return false}}Monster.assignToNamespace("Monster.Data",Pathfinder);export{Monster,Pathfinder};function iterate(subject,path,check){const result=new Map;if(isObject(subject)||isArray(subject)){for(const[key,value]of Object.entries(subject)){result.set(key,getValueViaPath.call(this,value,path,check))}}else{let key=path.split(DELIMITER).shift();result.set(key,getValueViaPath.call(this,subject,path,check))}return result}function getValueViaPath(subject,path,check){if(path===""){return subject}let parts=path.split(DELIMITER);let current=parts.shift();if(current===this.wildCard){return iterate.call(this,subject,parts.join(DELIMITER),check)}if(isObject(subject)||isArray(subject)){let anchor;if(subject instanceof Map||subject instanceof WeakMap){anchor=subject.get(current)}else if(subject instanceof Set||subject instanceof WeakSet){current=parseInt(current);validateInteger(current);anchor=[...subject]?.[current]}else if(subject instanceof WeakRef){throw Error("unsupported action for this data type")}else if(isArray(subject)){current=parseInt(current);validateInteger(current);anchor=subject?.[current]}else{anchor=subject?.[current]}if(isObject(anchor)||isArray(anchor)){return getValueViaPath.call(this,anchor,parts.join(DELIMITER),check)}if(parts.length>0){throw Error("the journey is not at its end ("+parts.join(DELIMITER)+")")}if(check===true&&!subject.hasOwnProperty(current)){throw Error("unknown value")}return anchor}throw TypeError("unsupported type "+typeof subject)}function setValueViaPath(object,path,value){validateString(path);let parts=path.split(DELIMITER);let last=parts.pop();let subpath=parts.join(DELIMITER);let stack=new Stack;let current=subpath;while(true){try{getValueViaPath.call(this,object,current,true);break}catch(e){}stack.push(current);parts.pop();current=parts.join(DELIMITER);if(current==="")break}while(!stack.isEmpty()){current=stack.pop();let obj={};if(!stack.isEmpty()){let n=stack.peek().split(DELIMITER).pop();if(isInteger(parseInt(n))){obj=[]}}setValueViaPath.call(this,object,current,obj)}let anchor=getValueViaPath.call(this,object,subpath);if(!isObject(object)&&!isArray(object)){throw TypeError("unsupported type: "+typeof object)}if(anchor instanceof Map||anchor instanceof WeakMap){anchor.set(last,value)}else if(anchor instanceof Set||anchor instanceof WeakSet){anchor.append(value)}else if(anchor instanceof WeakRef){throw Error("unsupported action for this data type")}else if(isArray(anchor)){last=parseInt(last);validateInteger(last);anchor[last]=value}else{anchor[last]=value}return}function deleteValueViaPath(object,path){const parts=path.split(DELIMITER);let last=parts.pop();const subpath=parts.join(DELIMITER);const anchor=getValueViaPath.call(this,object,subpath);if(anchor instanceof Map){anchor.delete(last)}else if(anchor instanceof Set||anchor instanceof WeakMap||anchor instanceof WeakSet||anchor instanceof WeakRef){throw Error("unsupported action for this data type")}else if(isArray(anchor)){last=parseInt(last);validateInteger(last);delete anchor[last]}else{delete anchor[last]}return}
/** Monster 1.7.0, © 2021 schukai GmbH, Released under the AGPL 3.0 License. */
'use strict';import{Monster}from"../namespace.js";function typeOf(value){let type={}.toString.call(value).match(/\s([a-zA-Z]+)/)[1];if("Object"===type){const results=/^(class|function)\s+(\w+)/.exec(value.constructor.toString());type=results&&results.length>2?results[2]:""}return type.toLowerCase()}Monster.assignToNamespace("Monster.Types",typeOf);export{Monster,typeOf};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
'use strict';
/**
* @author schukai GmbH
*/
import {Monster} from '../namespace.js';
import {isFunction} from "../types/is.js";
import {validateString} from "../types/validate.js";
import {Pathfinder} from "./pathfinder.js";
/**
* With the help of the function `buildMap()`, maps can be easily created from data objects.
*
* Either a simple definition `a.b.c` or a template `${a.b.c}` can be specified as the path.
* Key and value can be either a definition or a template. The key does not have to be defined.
*
* You can call the method via the monster namespace `Monster.Data.buildMap()`.
*
* ```
* <script type="module">
* import {Monster} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.7.0/dist/modules/data/buildmap.js';
* console.log(Monster.Data.buildMap())
* </script>
* ```
*
* Alternatively, you can also integrate this function individually.
*
* ```
* <script type="module">
* import {buildMap} from 'https://cdn.jsdelivr.net/npm/@schukai/monster@1.7.0/dist/modules/types/buildmap.js';
* console.log(buildMap())
* </script>
* ```
*
* @example
*
* // a typical data structure as reported by an api
*
* let map;
* let obj = {
* "data": [
* {
* "id": 10,
* "name": "Cassandra",
* "address": {
* "street": "493-4105 Vulputate Street",
* "city": "Saumur",
* "zip": "52628"
* }
* },
* {
* "id": 20,
* "name": "Holly",
* "address": {
* "street": "1762 Eget Rd.",
* "city": "Schwalbach",
* "zip": "952340"
* }
* },
* {
* "id": 30,
* "name": "Guy",
* "address": {
* "street": "957-388 Sollicitudin Avenue",
* "city": "Panchià",
* "zip": "420729"
* }
* }
* ]
* };
*
* // The function is passed this data structure and with the help of the selector `'data.*'` the data to be considered are selected.
* // The key is given by a simple definition `'id'` and the value is given by a template `'${name} (${address.zip} ${address.city})'`.
* map = buildMap(obj, 'data.*', '${name} (${address.zip} ${address.city})', 'id');
* console.log(map);
*
* // ↦ Map(3) {
* // '10' => 'Cassandra (52628 Saumur)',
* // '20' => 'Holly (952340 Schwalbach)',
* // '30' => 'Guy (420729 Panchià)'
* // }
*
* // If no key is specified, the key from the selection, here the array index, is taken.
* map = buildMap(obj, 'data.*', '${name} (${address.zip} ${address.city})');
* console.log(map);
*
* // ↦ Map(3) {
* // '0' => 'Cassandra (52628 Saumur)',
* // '1' => 'Holly (952340 Schwalbach)',
* // '2' => 'Guy (420729 Panchià)'
* // }
*
* // a filter (function(value, key) {}) can be specified to accept only defined entries.
* map = buildMap(obj, 'data.*', '${name} (${address.zip} ${address.city})', 'id', function (value, key) {
* return (value['id'] >= 20) ? true : false
* });
* console.log(map);
*
* // ↦ Map(2) {
* // 20 => 'Holly (952340 Schwalbach)',
* // 30 => 'Guy (420729 Panchià)'
* // }
*
* @param {*} subject
* @param {string} selector
* @param {string|undefined} valuePath
* @param {string|undefined} keyPath
* @param {function|undefined} filter
* @return {*}
*/
function buildMap(subject, selector, valuePath, keyPath, filter) {
validateString(selector);
const result = new Map
let finder = new Pathfinder(subject);
let map = finder.getVia(selector);
if (!(map instanceof Map)) {
return result;
}
map.forEach((v, k, m) => {
if (isFunction(filter)) {
if (filter.call(m, v, k)!==true) return;
}
k = build(v, keyPath, k);
v = build(v, valuePath);
result.set(k, v);
});
return result;
}
/**
* @private
* @param {*} subject
* @param {string|undefined} definition
* @param {*} defaultValue
* @return {*}
*/
function build(subject, definition, defaultValue) {
if (definition === undefined) return defaultValue ? defaultValue : subject;
validateString(definition);
const regexp = /(?<placeholder>\$\{(?<path>[a-z.-]*)\})/gm
const array = [...definition.matchAll(regexp)];
let finder = new Pathfinder(subject);
if (array.length === 0) {
return finder.getVia(definition);
}
array.forEach((a) => {
let groups = a?.['groups'];
let placeholder = groups?.['placeholder']
if (placeholder === undefined) return;
let path = groups?.['path']
let v = finder.getVia(path);
definition = definition.replaceAll(placeholder, v);
})
return definition;
}
Monster.assignToNamespace('Monster.Data', buildMap);
export {Monster, buildMap}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment