Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F77571918
interpolate.js
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Thu, Aug 15, 06:18
Size
6 KB
Mime Type
text/x-c++
Expires
Sat, Aug 17, 06:18 (2 d)
Engine
blob
Format
Raw Data
Handle
19887832
Attached To
rOACCT Open Access Compliance Check Tool (OACCT)
interpolate.js
View Options
'use strict';
const colors = require('ansi-colors');
const clean = (str = '') => {
return typeof str === 'string' ? str.replace(/^['"]|['"]$/g, '') : '';
};
/**
* This file contains the interpolation and rendering logic for
* the Snippet prompt.
*/
class Item {
constructor(token) {
this.name = token.key;
this.field = token.field || {};
this.value = clean(token.initial || this.field.initial || '');
this.message = token.message || this.name;
this.cursor = 0;
this.input = '';
this.lines = [];
}
}
const tokenize = async(options = {}, defaults = {}, fn = token => token) => {
let unique = new Set();
let fields = options.fields || [];
let input = options.template;
let tabstops = [];
let items = [];
let keys = [];
let line = 1;
if (typeof input === 'function') {
input = await input();
}
let i = -1;
let next = () => input[++i];
let peek = () => input[i + 1];
let push = token => {
token.line = line;
tabstops.push(token);
};
push({ type: 'bos', value: '' });
while (i < input.length - 1) {
let value = next();
if (/^[^\S\n ]$/.test(value)) {
push({ type: 'text', value });
continue;
}
if (value === '\n') {
push({ type: 'newline', value });
line++;
continue;
}
if (value === '\\') {
value += next();
push({ type: 'text', value });
continue;
}
if ((value === '$' || value === '#' || value === '{') && peek() === '{') {
let n = next();
value += n;
let token = { type: 'template', open: value, inner: '', close: '', value };
let ch;
while ((ch = next())) {
if (ch === '}') {
if (peek() === '}') ch += next();
token.value += ch;
token.close = ch;
break;
}
if (ch === ':') {
token.initial = '';
token.key = token.inner;
} else if (token.initial !== void 0) {
token.initial += ch;
}
token.value += ch;
token.inner += ch;
}
token.template = token.open + (token.initial || token.inner) + token.close;
token.key = token.key || token.inner;
if (defaults.hasOwnProperty(token.key)) {
token.initial = defaults[token.key];
}
token = fn(token);
push(token);
keys.push(token.key);
unique.add(token.key);
let item = items.find(item => item.name === token.key);
token.field = fields.find(ch => ch.name === token.key);
if (!item) {
item = new Item(token);
items.push(item);
}
item.lines.push(token.line - 1);
continue;
}
let last = tabstops[tabstops.length - 1];
if (last.type === 'text' && last.line === line) {
last.value += value;
} else {
push({ type: 'text', value });
}
}
push({ type: 'eos', value: '' });
return { input, tabstops, unique, keys, items };
};
module.exports = async prompt => {
let options = prompt.options;
let required = new Set(options.required === true ? [] : (options.required || []));
let defaults = { ...options.values, ...options.initial };
let { tabstops, items, keys } = await tokenize(options, defaults);
let result = createFn('result', prompt, options);
let format = createFn('format', prompt, options);
let isValid = createFn('validate', prompt, options, true);
let isVal = prompt.isValue.bind(prompt);
return async(state = {}, submitted = false) => {
let index = 0;
state.required = required;
state.items = items;
state.keys = keys;
state.output = '';
let validate = async(value, state, item, index) => {
let error = await isValid(value, state, item, index);
if (error === false) {
return 'Invalid field ' + item.name;
}
return error;
};
for (let token of tabstops) {
let value = token.value;
let key = token.key;
if (token.type !== 'template') {
if (value) state.output += value;
continue;
}
if (token.type === 'template') {
let item = items.find(ch => ch.name === key);
if (options.required === true) {
state.required.add(item.name);
}
let val = [item.input, state.values[item.value], item.value, value].find(isVal);
let field = item.field || {};
let message = field.message || token.inner;
if (submitted) {
let error = await validate(state.values[key], state, item, index);
if ((error && typeof error === 'string') || error === false) {
state.invalid.set(key, error);
continue;
}
state.invalid.delete(key);
let res = await result(state.values[key], state, item, index);
state.output += colors.unstyle(res);
continue;
}
item.placeholder = false;
let before = value;
value = await format(value, state, item, index);
if (val !== value) {
state.values[key] = val;
value = prompt.styles.typing(val);
state.missing.delete(message);
} else {
state.values[key] = void 0;
val = `<${message}>`;
value = prompt.styles.primary(val);
item.placeholder = true;
if (state.required.has(key)) {
state.missing.add(message);
}
}
if (state.missing.has(message) && state.validating) {
value = prompt.styles.warning(val);
}
if (state.invalid.has(key) && state.validating) {
value = prompt.styles.danger(val);
}
if (index === state.index) {
if (before !== value) {
value = prompt.styles.underline(value);
} else {
value = prompt.styles.heading(colors.unstyle(value));
}
}
index++;
}
if (value) {
state.output += value;
}
}
let lines = state.output.split('\n').map(l => ' ' + l);
let len = items.length;
let done = 0;
for (let item of items) {
if (state.invalid.has(item.name)) {
item.lines.forEach(i => {
if (lines[i][0] !== ' ') return;
lines[i] = state.styles.danger(state.symbols.bullet) + lines[i].slice(1);
});
}
if (prompt.isValue(state.values[item.name])) {
done++;
}
}
state.completed = ((done / len) * 100).toFixed(0);
state.output = lines.join('\n');
return state.output;
};
};
function createFn(prop, prompt, options, fallback) {
return (value, state, item, index) => {
if (typeof item.field[prop] === 'function') {
return item.field[prop].call(prompt, value, state, item, index);
}
return [fallback, value].find(v => prompt.isValue(v));
};
}
Event Timeline
Log In to Comment