UNPKG

@bbob/plugin-helper

Version:

Set of utils to help write plugins for @bbob/core

227 lines (221 loc) 7.35 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.BbobPluginHelper = {})); })(this, (function (exports) { 'use strict'; const N = '\n'; const TAB = '\t'; const F = '\f'; const R = '\r'; const EQ = '='; const QUOTEMARK = '"'; const SPACE = ' '; const OPEN_BRAKET = '['; const CLOSE_BRAKET = ']'; const SLASH = '/'; const BACKSLASH = '\\'; function isTagNode(el) { return typeof el === 'object' && el !== null && 'tag' in el; } function isStringNode(el) { return typeof el === 'string'; } // check string is end of line function isEOL(el) { return el === N; } function keysReduce(obj, reduce, def) { const keys = Object.keys(obj); return keys.reduce((acc, key)=>reduce(acc, key, obj), def); } function getNodeLength(node) { if (isTagNode(node) && Array.isArray(node.content)) { return node.content.reduce((count, contentNode)=>{ return count + getNodeLength(contentNode); }, 0); } if (isStringNode(node)) { return String(node).length; } return 0; } function appendToNode(node, value) { if (Array.isArray(node.content)) { node.content.push(value); } } /** * Replaces " to &qquot; * @param {string} value */ function escapeAttrValue(value) { return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;')// eslint-disable-next-line no-script-url .replace(/(javascript|data|vbscript|file):/gi, '$1%3A'); } /** * @deprecated use escapeAttrValue */ const escapeHTML = escapeAttrValue; /** * Accept name and value and return valid html5 attribute string */ function attrValue(name, value) { // in case of performance switch(typeof value){ case 'boolean': return value ? `${name}` : ''; case 'number': return `${name}="${value}"`; case 'string': return `${name}="${escapeAttrValue(value)}"`; case 'object': return `${name}="${escapeAttrValue(JSON.stringify(value))}"`; default: return ''; } } /** * Transforms attrs to html params string * @example * attrsToString({ 'foo': true, 'bar': bar' }) => 'foo="true" bar="bar"' */ function attrsToString(values) { // To avoid some malformed attributes if (values == null) { return ''; } return keysReduce(values, (arr, key, obj)=>[ ...arr, attrValue(key, obj[key]) ], [ '' ]).join(' '); } /** * Gets value from * @example * getUniqAttr({ 'foo': true, 'bar': bar' }) => 'bar' */ function getUniqAttr(attrs) { return keysReduce(attrs || {}, (res, key, obj)=>obj[key] === key ? obj[key] : null, null); } const getTagAttrs = (tag, params)=>{ const uniqAttr = getUniqAttr(params); if (uniqAttr) { const tagAttr = attrValue(tag, uniqAttr); const attrs = { ...params }; delete attrs[String(uniqAttr)]; const attrsStr = attrsToString(attrs); return `${tagAttr}${attrsStr}`; } return `${tag}${attrsToString(params)}`; }; const toString = (node, openTag, closeTag)=>{ if (isTagNode(node)) { return node.toString({ openTag, closeTag }); } return String(node); }; const nodeTreeToString = (content, openTag, closeTag)=>{ if (Array.isArray(content)) { return content.reduce((r, node)=>{ if (node !== null) { return r + toString(node, openTag, closeTag); } return r; }, ''); } if (content) { return toString(content, openTag, closeTag); } return null; }; class TagNode { get length() { return getNodeLength(this); } attr(name, value) { if (typeof value !== 'undefined') { this.attrs[name] = value; } return this.attrs[name]; } append(value) { return appendToNode(this, value); } setStart(value) { this.start = value; } setEnd(value) { this.end = value; } toTagStart({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) { const tagAttrs = getTagAttrs(String(this.tag), this.attrs); return `${openTag}${tagAttrs}${closeTag}`; } toTagEnd({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) { return `${openTag}${SLASH}${this.tag}${closeTag}`; } toTagNode() { return new TagNode(this.tag, this.attrs, this.content, this.start, this.end); } toString({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) { const content = this.content ? nodeTreeToString(this.content, openTag, closeTag) : ''; const tagStart = this.toTagStart({ openTag, closeTag }); if (this.content === null || Array.isArray(this.content) && this.content.length === 0) { return tagStart; } return `${tagStart}${content}${this.toTagEnd({ openTag, closeTag })}`; } toJSON() { return { tag: this.tag, attrs: this.attrs, content: this.content, start: this.start, end: this.end }; } static create(tag, attrs = {}, content = null, start) { return new TagNode(tag, attrs, content, start); } static isOf(node, type) { return node.tag === type; } constructor(tag, attrs, content, start, end){ this.tag = tag; this.attrs = attrs; this.content = content; this.start = start; this.end = end; } } exports.BACKSLASH = BACKSLASH; exports.CLOSE_BRAKET = CLOSE_BRAKET; exports.EQ = EQ; exports.F = F; exports.N = N; exports.OPEN_BRAKET = OPEN_BRAKET; exports.QUOTEMARK = QUOTEMARK; exports.R = R; exports.SLASH = SLASH; exports.SPACE = SPACE; exports.TAB = TAB; exports.TagNode = TagNode; exports.appendToNode = appendToNode; exports.attrValue = attrValue; exports.attrsToString = attrsToString; exports.escapeAttrValue = escapeAttrValue; exports.escapeHTML = escapeHTML; exports.getNodeLength = getNodeLength; exports.getUniqAttr = getUniqAttr; exports.isEOL = isEOL; exports.isStringNode = isStringNode; exports.isTagNode = isTagNode; }));