diff --git a/Plugger/1.0.9/Plugger.js b/Plugger/1.0.9/Plugger.js new file mode 100644 index 0000000000..daa7307d60 --- /dev/null +++ b/Plugger/1.0.9/Plugger.js @@ -0,0 +1,674 @@ +/* +========================================================= +Name : Plugger +GitHub : https://github.com/TimRohr22/Cauldron/tree/master/Plugger +Roll20 Contact : timmaugh +Version : 1.0.9 +Last Update : 17 MAY 2024 +========================================================= +*/ +var API_Meta = API_Meta || {}; +API_Meta.Plugger = { offset: Number.MAX_SAFE_INTEGER, lineCount: -1 }; +{ + try { throw new Error(''); } catch (e) { API_Meta.Plugger.offset = (parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/, '$1'), 10) - (13)); } +} + +const Plugger = (() => { + const apiproject = 'Plugger'; + const version = '1.0.9'; + const schemaVersion = 0.1; + API_Meta[apiproject].version = version; + const vd = new Date(1715952845199); + const versionInfo = () => { + log(`\u0166\u0166 ${apiproject} v${API_Meta[apiproject].version}, ${vd.getFullYear()}/${vd.getMonth() + 1}/${vd.getDate()} \u0166\u0166 -- offset ${API_Meta[apiproject].offset}`); + if (!state.hasOwnProperty(apiproject) || state[apiproject].version !== schemaVersion) { + log(` > Updating ${apiproject} Schema to v${schemaVersion} <`); + switch (state[apiproject] && state[apiproject].version) { + + case 0.1: + /* break; // intentional dropthrough */ /* falls through */ + + case 'UpdateSchemaVersion': + state[apiproject].version = schemaVersion; + break; + + default: + state[apiproject] = { + version: schemaVersion, + }; + break; + } + } + }; + const logsig = () => { + // initialize shared namespace for all signed projects, if needed + state.torii = state.torii || {}; + // initialize siglogged check, if needed + state.torii.siglogged = state.torii.siglogged || false; + state.torii.sigtime = state.torii.sigtime || Date.now() - 3001; + if (!state.torii.siglogged || Date.now() - state.torii.sigtime > 3000) { + const logsig = '\n' + + ' _____________________________________________ ' + '\n' + + ' )_________________________________________( ' + '\n' + + ' )_____________________________________( ' + '\n' + + ' ___| |_______________| |___ ' + '\n' + + ' |___ _______________ ___| ' + '\n' + + ' | | | | ' + '\n' + + ' | | | | ' + '\n' + + ' | | | | ' + '\n' + + ' | | | | ' + '\n' + + ' | | | | ' + '\n' + + '______________|_|_______________|_|_______________' + '\n' + + ' ' + '\n'; + log(`${logsig}`); + state.torii.siglogged = true; + state.torii.sigtime = Date.now(); + } + return; + }; + + const nestlog = (stmt, ilvl = 0, logcolor = '', boolog = false) => { + if (isNaN(ilvl)) { + ilvl = 0; + log(`Next statement fed a NaN value for the indentation.`); + } + if ((state[apiproject] && state[apiproject].logging === true) || boolog) { + let l = `${Array(ilvl + 1).join("==")}${stmt}`; + if (logcolor) { + // l = /:/.test(l) ? `${l.replace(/:/, ':')}` : `${l}`; + } + log(l); + } + }; + + const escapeRegExp = (string) => { return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); }; + const assertstart = rx => new RegExp(`^${rx.source}`, rx.flags); + const getfirst = (cmd, ...args) => { + // pass in objects of form: {type: 'text', rx: /regex/} + // return object of form : {regex exec object with property 'type': 'text'} + + let ret = {}; + let r; + args.find(a => { + r = a.rx.exec(cmd); + if (r && (!ret.length || r.index < ret.index)) { + ret = Object.assign(r, { type: a.type }); + } + a.lastIndex = 0; + }, ret); + return ret; + }; + + // REGEX STATEMENTS ===================================== + const evalrx = /(\()?{&\s*eval(?:\((?[^)]+)\)){0,1}\s*}((?<=\({&\s*eval(?:\(([^)]+)\)){0,1}\s*})\)|\1)\s*/i, + evalendrx = /(\()?{&\s*\/\s*eval\s*}((?<=\({&\s*\/\s*eval\s*})\)|\1)/i; + + // TAG RX SETS REGISTRY ================================= + const tagrxset = { + 'eval': { opentag: evalrx, endtag: evalendrx } + }; + + // TOKEN MARKERS ======================================== + const eostm = { rx: /$/, type: 'eos' }, + evaltm = { rx: evalrx, type: 'eval' }, + evalendtm = { rx: evalendrx, type: 'evalend' }; + + // END TOKEN REGISTRY =================================== + const endtokenregistry = { + main: [eostm], + eval: [evalendtm], + }; + + const tokenizeOps = (msg, msgstate, status, notes) => { + class TextToken { + constructor() { + this.type = 'text'; + this.escape = ''; + this.value = ''; + } + } + class PlugEvalToken { + constructor() { + this.type = 'eval'; + this.contents = []; + } + } + + const getTextToken = (c) => { + let logcolor = 'lawngreen'; + nestlog(`TEXT INPUT: ${c.cmd}`, c.indent, logcolor, msgstate.logging); + let markers = []; + c.looptype = c.looptype || ''; + switch (c.looptype) { + case 'eval': + default: + markers = [evaltm, evalendtm, eostm]; + break; + } + let res = getfirst(c.cmd, ...markers); + let index = res.index; + let token = new TextToken(); + token.value = c.cmd.slice(0, index); + nestlog(`TEXT KEEPS: ${token.value}`, c.indent, logcolor, msgstate.logging); + return { token: token, index: index }; + }; + const getPlugEvalToken = (c) => { + // receives object in the form of: + // {cmd: command line slice, indent: #, overallindex: #, looptype: text} + let logcolor = 'yellow'; + let index = 0; + let evalopenres = tagrxset[c.looptype].opentag.exec(c.cmd); + if (evalopenres) { + nestlog(`${c.looptype.toUpperCase()} TOKEN INPUT: ${c.cmd}`, c.indent, logcolor, msgstate.logging); + let token = new PlugEvalToken(); + token.escape = evalopenres.groups && evalopenres.groups.escape && evalopenres.groups.escape.length ? evalopenres.groups.escape : ''; + let index = evalopenres[0].length; + + // content and nested evals + nestlog(`BUILDING CONTENT: ${c.cmd.slice(index)}`, c.indent + 1, 'lightseagreen', msgstate.logging); + let contentres = evalval({ cmd: c.cmd.slice(index), indent: c.indent + 1, type: c.looptype, overallindex: c.overallindex + index, looptype: c.looptype }); + if (contentres.error) return contentres; + token.contents = contentres.tokens; + index += contentres.index; + nestlog(`ENDING CONTENT: ${c.cmd.slice(index)}`, c.indent + 1, 'lightseagreen', msgstate.logging); + + // closing bracket of eval tag + let evalendres = tagrxset[c.looptype].endtag.exec(c.cmd.slice(index)); + if (!evalendres) { + status.push('unresolved'); + notes.push(`Unexpected token at ${c.overallindex + index}. Expected end of ${c.looptype.toUpperCase()} structure ('{& eval}'), but saw: ${c.cmd.slice(index, index + 10)}`); + return { error: `Unexpected token at ${c.overallindex + index}. Expected end of ${c.looptype.toUpperCase()} structure ('{& eval}'), but saw: ${c.cmd.slice(index, index + 10)}` }; + } + index += evalendres[0].length; + nestlog(`${c.looptype.toUpperCase()} TOKEN OUTPUT: ${JSON.stringify(token)}`, c.indent, logcolor, msgstate.logging); + return { token: token, index: index }; + } else { + status.push('unresolved'); + notes.push(`Unexpected token at ${c.overallindex + index}. Expected an ${c.looptype.toUpperCase()} structure, but saw: ${c.cmd.slice(index, index + 10)}`); + return { error: `Unexpected token at ${c.overallindex + index}. Expected an ${c.looptype.toUpperCase()} structure, but saw: ${c.cmd.slice(index, index + 10)}` }; + } + }; + const evalval = c => { + // expects an object in the form of: + // { cmd: text, indent: #, overallindex: #, type: text, overallindex: #, looptype: text } + let tokens = []; // main output array + let logcolor = 'aqua'; + let loopstop = false; + let tokenres = {}; + let index = 0; + let loopindex = 0; + nestlog(`${c.looptype.toUpperCase()} BEGINS`, c.indent, logcolor, msgstate.logging); + while (!loopstop) { + loopindex = index; + if (assertstart(tagrxset[c.looptype].opentag).test(c.cmd.slice(index))) { + status.push('changed'); + tokenres = getPlugEvalToken({ cmd: c.cmd.slice(index), indent: c.indent + 1, overallindex: c.overallindex + index, looptype: c.looptype }); + } else { + tokenres = getTextToken({ cmd: c.cmd.slice(index), indent: c.indent + 1, overallindex: c.overallindex + index, looptype: c.looptype }); + } + if (tokenres) { + if (tokenres.error) { return tokenres; } + tokens.push(tokenres.token); + index += tokenres.index; + } + if (loopindex === index) { // nothing detected, loop never ends + return { error: `Unexpected token at ${c.overallindex + index}.` }; + } + loopstop = (getfirst(c.cmd.slice(index), ...endtokenregistry[c.type]).index === 0); + } + nestlog(`${c.looptype.toUpperCase()} ENDS`, c.indent, logcolor, msgstate.logging); + return { tokens: tokens, index: index }; + }; + + return evalval({ cmd: msg.content, indent: 0, type: 'main', overallindex: 0, looptype: 'eval' }); + }; + + const reconstructOps = (o, msg, msgstate, status, notes) => { + const runPlugin = c => { + const evalstmtrx = /^\s*(?