UNPKG

@indra.ai/feectingdeva

Version:

The Feecting Deva manages all the parsing of feecting language in deva.world.

315 lines (250 loc) 14 kB
"use strict" const fs = require('fs'); const path = require('path'); const basePath = path.join(__dirname, '..', '..'); function formatDate(d, format='long', time=false, locale='en-US') { if (!d) d = Date.now(); d = new Date(d); const formats = { long: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }, long_month: { year: 'numeric', month: 'long', day: 'numeric'}, short: { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' }, short_month: { year: 'numeric', month: 'short', day: 'numeric' }, year: { year: 'numeric' }, month: { month: 'long' }, day: { day: 'long' } }; const theDate = d.toLocaleDateString(locale, formats[format]); const theTime = d.toLocaleTimeString(locale); if (format === 'time') return theTime; return !time ? theDate : `${theDate} - ${theTime}`; } class Parser { constructor(opts) { this.id = opts.id; this.key = opts.key; this.cmd = opts.cmd; this.params = opts.params; this.vars = opts.vars || {}; this.talk = opts.talk || []; this.text = opts.text || false; this.html = false; this.client = opts.client || false; this.agent = opts.agent || false; this.container = opts.container || false; } uid() { return Math.floor(Math.random() * Date.now()); } /*********** func: formatHTML params: text - text string to format describe: the main formatting function where feecting text is converted into HTML. ***********/ formatHTML() { this.text = '\n' + this.text.replace(/\@\@/g, '@'); this.html = this.text // main label formatting .replace(/\n::BEGIN:(\w+)?:?(.+)?/g, '<div class="CONTAINER $1" data-id="$2">') .replace(/\n::END:(\w+)?:?(md5|sha256|sha512)?:?(.+)?/g, '</div>') .replace(/\n?\s+?\/\/(.+)/g, '<div class="comment">$1</div>') .replace(/(\n)(var):(.+)\r?/g, `$1<div class="item $2"><span class="label">$2</span><span class="value">$3</span></div>`) .replace(/(\n)(var)\[(.+)\]:(.+)\r?/g, `$1<div class="item $2"><span class="label">$3</span><span class="value">$4</span></div>`) .replace(/::begin:(\w+)?:?(.+)?/g, '<div class="box $1" data-id="$2">') .replace(/::end:(\w+)?:?(md5|sha256|sha512)?-?(.+)?/g, '</div>') .replace(/\n####\s?(.+)/g, `<h4>$1</h4>`) .replace(/\n###\s?(.+)/g, `<h3>$1</h3>`) .replace(/\n##\s?(.+)/g, `<h2>$1</h2>`) .replace(/\n#\s?(.+)/g, `<h1>$1</h1>`) .replace(/(\n)={4,}\n/g, `$1<hr class="double xsmall" />`) .replace(/(\n)={3}\n/g, `$1<hr class="double small" />`) .replace(/(\n)={2}\n/g, `$1<hr class="double medium" />`) .replace(/(\n)={1}\n/g, `$1<hr class="double large" />`) .replace(/(\n)-{4,}\n/g, `$1<hr class="single xsmall"/>`) .replace(/(\n)-{3}\n/g, `$1<hr class="single small"/>`) .replace(/(\n)-{2}\n/g, `$1<hr class="single medium"/>`) .replace(/(\n)-{1}\n/g, `$1<hr class="single large"/>`) .replace(/(\*\*|__)(?=(?:(?:[^`]*`[^`\r\n]*`)*[^`]*$))(?![^\/<]*>.*<\/.+>)(.*?)\1/gi, `<strong>$2</strong>`) .replace(/```(.*?)```/sg, '\n<pre><code>$1</code></pre>\n') .replace(/`(.*?)`/gi, '<code>$1</code>') // .replace(/(\*\*)(.+)?(\*\*)/g, `<b>$2</b>`) // .replace(/(\s)(\#.+?)(\b)/g, `$1<span class="tag thing">$2</span>$3`) // .replace(/(\s)(\@.+?)(\b)/g, `$1<span class="tag person">$2</span>$3`) // .replace(/(\s)(\$.+?)(\b)/g, `$1<span class="tag place">$2</span>$3`) // .replace(/(\s)(\!.+?)(\b)/g, `$1<span class="tag bang">$2</span>$3`) // // .replace(/(\s)\_([#|@|$|!].+?)(\b)/gi, `$1$2$3`) // image processing regex .replace(/\nimage:\s?(.+)/g, `<div class="image"><img src="$1" /></div>`) .replace(/\n(avatar|thumbnail):\s?(.+)/g, `<div class="$1"><img src="$2" /></div>`) .replace(/\n?img:\s?(.+)\/(.+)\/(\d+)\/avatar/g, `<button class="btn avi" data-cmd="#space $2:$1 $3/main:look"><img src="/asset/$1/$2/$3/avatar" /></button>`) .replace(/\n?img:\s?(.+)/g, `<div class="image"><img src="/asset/$1" /></div>`) .replace(/\n(select)\[(.+):(.+)\]:(.+)/gi, `<div class="item $1"><span class="label" data-index="$2">$3</span><span class="input"><button type="button" class="input-select" name="$1" data-cloudbtn="$2">$4</button></span></div>`) .replace(/(\n?)(cloudconf)\[(.+)\]:(.+)/g, '$1<button class="btn $2" title="$3" data-cloudbtn="$4">$3</button>') .replace(/(\n?)(cloud)\[(.+)\]:(.+)/g, '$1<button class="btn cloudbtn" title="$3" data-cloudbtn="$4">$3</button>') .replace(/(\n?)(cloudcmd)\[(.+)\]:(.+)/g, '$1<button class="btn cloudcmd" title="$3" data-cloudcmd="$4">$3</button>') .replace(/(\n)?(look)\[(.+)\]:(.+)/g, '$1<button class="btn $2" title="$3" data-cloudcmd="look $4">$3</button>') .replace(/(\n?)(button)\[(.+)\]:(.+)/g, '$1<button class="btn $2" title="$3" data-button="$4">$3</button>') // cmd/tty tag parser .replace(/(\n)(cmd|tty):(.+)\r?/g, `$1<div class="item $2"><span class="label">$2</span><span class="value"><button class="btn $2" alt="$2" data-$2="$3"></button>$3</span></div>`) .replace(/(\n)(cmd|tty)\[(.+)\]:(.+)\r?/g, `$1<div class="item $2"><span class="label">$2</span><span class="value"><button class="btn $2" alt="$2 $4" data-$2="$4">$3</button></span></div>`) .replace(/\n(\d+)\. (.+)/g, `<div class="number-item" data-label="$1">$2</div>`) .replace(/\n> (.+)\r?/g, `<div class="list-item">$1</div>`) .replace(/\n- (.+)\r?/g, `<div class="line-item">$1</div>`) // pdf links .replace(/(\n)(pdf):\s?(.+)/g, `$1<div class="$2"><iframe width="100%" height="100%" src="$3" frameborder="0"></iframe></div>`) // youtube links .replace(/\nyoutube:\s?(.+)/g, `\n<div class="center youtube-video-player"><iframe src="https://www.youtube.com/embed/$1" frameborder="0"></iframe></div>`) // youtube links .replace(/\nmap:\s?(.+)/g, `\n<div class="center google-map-player"><iframe src="https://www.google.com/maps/embed?pb=$1" frameborder="0" width="650" height="400" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe></div>`) // youtube links with parameters .replace(/(\n)(youtube)\[play\]:\s?(.+)/g, `\n<div class="center youtube-video-player"><iframe src="https://www.youtube.com/embed/$3?&autoplay=1" frameborder="0"></iframe></div>`) // links // link with just url .replace(/(\n?)(link):\s?(.+)/g, `$1<div class="item $2"><span class="label">link</span><span class="value"><a href="$3" class="$2" alt="$2" target="_blank">$3</a></span></div>`) // link with bracket label/text .replace(/(\n?)(link)\[(.+)\]:\s?(.+)/g, `$1<div class="item $2"><span class="label">link</span><span class="value"><a href="$4" class="$2" alt="$3" target="$2">$3</a></span></div>`) // numbered list item of href links .replace(/(\n?)(href)\[(\d+):(.+)\]:\s?(.+)(\r?)/g, `\n<div class="number-item" data-label="$3"><a href="$5" class="$2" alt="$4">$4</a></div>\r`) // standard href .replace(/(\n?)(href)\[(.+)\]:\s?(.+)(\r?)/g, `\n<a href="$4" class="$2" alt="$3">$3</a>\r`) .replace(/(\n)(audio)\[(tts)\]:\s?(.+)/g, `$1<div class="item $2 $3"><span class="label">$2</span><span class="value"><audio src="$4" controls autoplay></audio></span></div>`) // audio feature .replace(/(\n)(audio):\s?(.+)/g, `$1<div class="item $2"><span class="label">$2</span><span class="value"><audio class="$2-player" src="$3" controls></audio></span></div>`) .replace(/\[PRESS RETURN\]/g, '<div class="press_return"><button class="btn return" title="Press Return" data-cloudbtn="">Press Return</button><div>') .replace(/\n(l):\s?(.+)/gi, `<div class="line">$2</div>`) .replace(/\n(gate)\[(.+)\]:\s?(.+)/gi, `<p><button class="btn speak" alt="Gateway" data-cmd="#gate $2 $3">💬</button> $3</p>`) .replace(/\n(p|h1|h2|h3|h4|h5|article|div|span)\[speak\]:\s?(.+)/gi, `<$1><button class="btn speak" alt="Speak" data-cmd="#voice say $2">💬</button> $2</$1>`) .replace(/\n(p|h1|h2|h3|h4|h5|article)\[speak\:(.+)?]:\s?(.+)/gi, `<$1><button class="btn speak" alt="Speak" data-cmd="#voice say:$2 $3">💬</button> $3</$1>`) .replace(/\n(data)\[(.+)?]:\s?(.+)/gi, `<div class="box data"><p>$3</p><button class="btn data" alt="Data" data-cmd="#data $2 $3">$2</button></div>`) .replace(/\n(live)\[(.+)]:\s?(.+)/gi, `<div class="box chat"><button class="btn chat" alt="Live Chat" data-cmd="#$2 $1 $3">💬</button> #$2 > $3</div>`) .replace(/\n(p|div|span|h1|h2|h3|h4|h5|article|section|br):\s?(.+)/gi, `<$1>$2</$1>`) .replace(/\n(\w+):\s?(.+)/gi, `<div class="item $1"><span class="label">$1</span><span class="value">$2</span></div>`) .replace(/\n(\s{2})?(\w+):\s?(.+)/gi, `<div class="item $2 indent1"><span class="label">$2</span><span class="value">$3</span></div>`) .replace(/\n(\s{4})?(\w+):\s?(.+)/gi, `<div class="item $2 indent2"><span class="label">$2</span><span class="value">$3</span></div>`) .replace(/\n(\s{6})?(\w+):\s?(.+)/gi, `<div class="item $2 indent3"><span class="label">$2</span><span class="value">$3</span></div>`) // strong format .trim(); // set the container // if (this.container) this.html = `<div class="${this.container}">${this.html}</div>`; // .replace(/(.+)\n\n/g, '<p>$1</p>') // .replace(/(.+)\n/g, '<div class="line">$1</div>') // .replace(/\n/g, '<div class="line br"></div>') // .replace(/\n\r?/g, '<div class="line"></div>'); // .replace(/(.*)/g, '<div class="line">$1</div>'); // Reference to https://github.com/sindresorhus/ansi-regex let cssStyle = []; if (this.vars.bgcolor) cssStyle.push(`--browser-item-bgcolor:${this.vars.bgcolor.value}`); if (this.vars.bg) cssStyle.push(`--browser-item-image: url(${this.vars.bg.value})`); if (this.vars.color) cssStyle.push(`--browser-item-color: ${this.vars.color.value}`); if (this.vars.size) cssStyle.push(`--browser-item-size: ${this.vars.size.value}`); if (cssStyle.length) { this.html = `<section class="cover" style="${cssStyle.join(';')}">${this.html}</section>`; } return this.html; } /*********** func: _extractVars describe: Recursive function to extract variables from a text string. params: text - text string to extract variables from. ***********/ _extractVars() { if (!this.text) return false; const reggie = this.text.match(/\n(\#|\@|\$)(.+)\s?=\s?(.+)/); if (!reggie) return; this.vars[reggie[2].trim()] = { type: reggie[1].trim(), name: reggie[2].trim(), value: reggie[3].trim(), } this.text = this.text.replace(reggie[0], `\nvar[${reggie[1].trim()}${reggie[2].trim()}]:${reggie[3].trim()}\r`); return this._extractVars(); } /*********** func: getVars params: text - initial text string to get variables from. describe: this is a helper function to recursive _extractVars. ***********/ getVars(opts) { if (!this.text) return false; const {id, q} = opts; const {client, agent, data} = q; const {colors} = agent.prompt; const _profile = []; _profile.push(`::begin:profile`); for (let x in agent.profile) { _profile.push(`${x}: ${agent.profile[x]}`); } _profile.push(`::end:profile\n`); const profile = _profile.join('\n'); this.text = this.text.replace(/::id::/g, id) .replace(/::date::/g, formatDate(Date.now(), 'long', true)) .replace(/::agent_id::/g, agent.id) .replace(/::agent_key::/g, agent.key) .replace(/::agent_name::/g, agent.profile.name) .replace(/::agent_color::/g, agent.profile.color) .replace(/::agent_bgcolor::/g, agent.profile.bgcolor) .replace(/::agent_describe::/g, agent.profile.describe) .replace(/::agent_background::/g, agent.profile.background) .replace(/::agent_emoji::/g, agent.prompt.emoji) .replace(/::agent_avatar::/g, agent.profile.avatar) .replace(/::client_id::/g, client.id) .replace(/::client_name::/g, client.profile.name) .replace(/::profile::/g, profile); return this._extractVars(); } /*********** func: extractTalk params: text - text string to extract talk triggers from. describe: extract talk functions from a text string to communication with other agents/deva. ***********/ _extractTalk() { if (!this.text) return false; const id = this.uid(); const reggie = (/(^|\n)talk:\s?(.+)/i).exec(this.text); if (!reggie) return; const placeholder = `::${id}::`; this.talk.push({ id, placeholder, value: reggie[2], }); this.text = this.text.replace(reggie[0], '\n' + placeholder + '\n') return this._extractTalk(); } /*********** func: getTalk params: text - text string to parse the talk triggers from. describe: Helper function to initiate recursive _extractTalk. ***********/ getTalk() { if (!this.text) return false; return this._extractTalk(); } } module.exports = (opts) => { const {meta, text, client, agent} = opts.q; const key = agent ? agent.key : client.key; const parser = new Parser({ id: opts.id, key, cmd: meta.params.shift(), container: meta.params.length ? meta.params.join(' ') : false, params: meta.params, text, client, agent, }); parser.getVars(opts); parser.getTalk(); return { text: parser.text.replace(/\\(#|@|$)/g, `$1`), html: parser.formatHTML(), data: { id: parser.id, params: parser.params, vars: parser.vars, talk: parser.talk, }, } }