StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
StackGenVis/frontend/node_modules/layouts/index.js

267 lines
5.9 KiB

'use strict';
var path = require('path');
var utils = require('./utils');
/**
* Expose `layouts`
*/
module.exports = renderLayouts;
/**
* Cache compiled delimiter regex.
*
* If delimiters need to be generated, this ensures that
* runtime compilation only happens once.
*/
var cache = {};
/**
* Wrap one or more layouts around `string`.
*
* ```js
* renderLayouts(string, layoutName, layouts, options, fn);
* ```
*
* @param {String} `string` The string to wrap with a layout.
* @param {String} `layoutName` The name (key) of the layout object to use.
* @param {Object} `layouts` Object of layout objects.
* @param {Object} `options` Optionally define a `defaultLayout` (string), pass custom delimiters (`layoutDelims`) to use as the placeholder for the content insertion point, or change the name of the placeholder tag with the `tag` option.
* @param {Function} `fn` Optionally pass a function to modify the context as each layout is applied.
* @return {String} Returns the original string wrapped with one or more layouts.
* @api public
*/
function renderLayouts(str, name, layouts, opts, fn) {
if (isBuffer(str)) {
str = String(str);
}
if (typeof str !== 'string') {
throw new TypeError('expected content to be a string.');
}
if (typeof name !== 'string') {
throw new TypeError('expected layout name to be a string.');
}
if (typeof opts === 'function') {
fn = opts;
opts = {};
}
opts = opts || {};
var layout = {};
var depth = 0;
var prev;
// `view` is the object we'll use to store the result
var view = {options: {}, history: []};
name = assertLayout(name, opts.defaultLayout);
// recursively resolve layouts
while (name && (prev !== name) && (layout = utils.getView(name, layouts))) {
prev = name;
var delims = opts.layoutDelims;
// `data` is passed to `wrapLayout` to resolve layouts
// to the values on the data object.
var data = {};
var tag = opts.tag || 'body';
data[tag] = str;
// get info about the current layout
var obj = new Layout({
name: name,
layout: layout,
before: str,
depth: depth++
});
// get the delimiter regex
var re = makeDelimiterRegex(delims, tag);
// ensure that content is a string
var content = String(layout.content);
if (!re.test(content)) {
throw error(re, name, tag);
}
// inject the string into the layout
str = wrapLayout(content, data, re, name, tag);
obj.after = str;
// if a callback is passed, allow it modify the result
if (typeof fn === 'function') {
fn(obj, view, depth);
}
// push info about the layout onto `history`
view.history.push(obj);
// should we recurse again?
// does the `layout` specify another layout?
name = assertLayout(layout.layout, opts.defaultLayout);
}
if (typeof name === 'string' && prev !== name) {
throw new Error('could not find layout "' + name + '"');
}
view.options = opts;
view.result = str;
return view;
}
/**
* Create a new layout in the layout stack.
*
* @param {Object} `view` The layout view object
* @param {Number} `depth` Current stack depth
*/
function Layout(view) {
this.layout = view.layout;
this.layout.name = view.name;
this.before = view.before;
this.depth = view.depth;
return this;
}
/**
* Assert whether or not a layout should be used based on
* the given `value`.
*
* - If a layout should be used, the name of the layout is returned.
* - If not, `null` is returned.
*
* @param {*} `value`
* @return {String|Null} Returns `true` or `null`.
* @api private
*/
function assertLayout(value, defaultLayout) {
if (value === false || (value && utils.isFalsey(value))) {
return null;
} else if (!value || value === true) {
return defaultLayout || null;
} else {
return value;
}
}
/**
* Resolve template strings to the values on the given
* `data` object.
*/
function wrapLayout(str, data, re, name, tag) {
return str.replace(re, function(_, tagName) {
var m = data[tagName.trim()];
if (typeof m === 'undefined') {
throw error(re, name, tag);
}
return m;
});
}
/**
* Make delimiter regex.
*
* @param {Sring|Array|RegExp} `syntax`
* @return {RegExp}
*/
function makeDelimiterRegex(syntax, tag) {
if (!syntax) {
syntax = makeTag(tag, ['{%', '%}']);
}
if (syntax instanceof RegExp) {
return syntax;
}
var name = syntax + '';
if (cache.hasOwnProperty(name)) {
return cache[name];
}
if (typeof syntax === 'string') {
return new RegExp(syntax, 'g');
}
return (cache[name] = utils.delims(syntax));
}
/**
* Cast `val` to a string.
*/
function makeTag(val, delims) {
return delims[0].trim()
+ ' ('
+ String(val).trim()
+ ') '
+ delims[1].trim();
}
/**
* Format an error message
*/
function error(re, name, tag) {
var delims = matchDelims(re, tag);
return new Error('cannot find "' + delims + '" in "' + name + '"');
}
/**
* Only used if an error is thrown. Attempts to recreate
* delimiters for the error message.
*/
var types = {
'{%=': function(str) {
return '{%= ' + str + ' %}';
},
'{%-': function(str) {
return '{%- ' + str + ' %}';
},
'{%': function(str) {
return '{% ' + str + ' %}';
},
'{{': function(str) {
return '{{ ' + str + ' }}';
},
'<%': function(str) {
return '<% ' + str + ' %>';
},
'<%=': function(str) {
return '<%= ' + str + ' %>';
},
'<%-': function(str) {
return '<%- ' + str + ' %>';
}
};
function matchDelims(re, str) {
var ch = re.source.slice(0, 4);
if (/[\\]/.test(ch.charAt(0))) {
ch = ch.slice(1);
}
if (!/[-=]/.test(ch.charAt(2))) {
ch = ch.slice(0, 2);
} else {
ch = ch.slice(0, 3);
}
return types[ch](str);
}
/**
* Return true if the given value is a buffer
*/
function isBuffer(val) {
if (val && val.constructor && typeof val.constructor.isBuffer === 'function') {
return val.constructor.isBuffer(val);
}
return false;
}