json-tots
Version:
Template of Templates, a.k.a Template Should Eat Itself
239 lines (237 loc) • 11 kB
JavaScript
"use strict";
var _Object$keys = require("@babel/runtime-corejs3/core-js-stable/object/keys");
var _Object$getOwnPropertySymbols = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols");
var _filterInstanceProperty2 = require("@babel/runtime-corejs3/core-js-stable/instance/filter");
var _Object$getOwnPropertyDescriptor = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor");
var _forEachInstanceProperty = require("@babel/runtime-corejs3/core-js-stable/instance/for-each");
var _Object$getOwnPropertyDescriptors = require("@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors");
var _Object$defineProperties = require("@babel/runtime-corejs3/core-js-stable/object/define-properties");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/map"));
var _startsWith = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/starts-with"));
var _concat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/concat"));
var _reduce = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/reduce"));
var _filter = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/filter"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = _filterInstanceProperty2(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context5, _context6; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty(_context5 = ownKeys(Object(source), !0)).call(_context5, function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : _forEachInstanceProperty(_context6 = ownKeys(Object(source))).call(_context6, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } return target; }
/* eslint-disable array-callback-return */
var traverse = require('traverse');
var jp = require('jsonpath');
var F = require('functional-pipelines');
var defaultConfig = {
"throws": false,
nullifyMissing: true,
operators: {
constraints: {
'?': {
drop: true
},
'!': {
nullable: true
}
}
}
};
var bins = require('./core/builtins');
var _require = require('./core/render'),
renderStringNode = _require.renderStringNode,
renderFunctionExpressionNode = _require.renderFunctionExpressionNode,
renderArrayNode = _require.renderArrayNode,
renderData = _require.data;
var _require2 = require('./core/operators'),
jpify = _require2.jpify;
var _require3 = require('./core/policy/key/run-policy'),
runPolicy = _require3.runPolicy;
/**
* Transforms JSON document using a JSON template
* @param template Template JSON
* @param sources A map of alternative document-sources, including `default` source
* @param tags Reference to a map that gets populated with Tags
* @param functions A map of user-defined function, if name-collision occurs with builtin functions, user-defined functions take precedence
* @param args A map of extended arguments to @function expressions, args keys are either functionName (if used only once), functionKey (if globally unique) or functionPath which is unique but ugliest option to write
* @param config Allows to override defaultConfig
* @param builtins A map of builtin functions, defaults to ./core/builtins.js functions
* @returns {function(*=): *}
*/
var transform = function transform(template) {
var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref$meta = _ref.meta,
meta = _ref$meta === void 0 ? 0 : _ref$meta,
_ref$sources = _ref.sources,
sources = _ref$sources === void 0 ? {
"default": {}
} : _ref$sources,
_ref$tags = _ref.tags,
tags = _ref$tags === void 0 ? {} : _ref$tags,
_ref$functions = _ref.functions,
functions = _ref$functions === void 0 ? {} : _ref$functions,
_ref$args = _ref.args,
args = _ref$args === void 0 ? {} : _ref$args,
_ref$config = _ref.config,
config = _ref$config === void 0 ? defaultConfig : _ref$config;
var _ref2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
_ref2$builtins = _ref2.builtins,
builtins = _ref2$builtins === void 0 ? bins : _ref2$builtins;
return function (document) {
var result;
functions = _objectSpread(_objectSpread({}, bins), functions);
var options = {
meta: meta,
sources: _objectSpread(_objectSpread({}, sources), {}, {
origin: document
}),
tags: tags,
functions: functions,
args: args,
config: config
};
if (F.isString(template)) {
var _renderStringNode = renderStringNode({
node: template,
path: ['$']
}, options);
result = _renderStringNode.rendered;
} else {
var _context;
result = (0, _map["default"])(_context = traverse(template)).call(_context, function (node) {
var self = this;
var contextRef = self;
var rendered;
var asts;
if (F.isFunction(node)) {
rendered = node(document);
} else if (F.isString(node)) {
if ((0, _startsWith["default"])(node).call(node, '@')) {
var _renderFunctionExpres = renderFunctionExpressionNode(contextRef, options, document);
rendered = _renderFunctionExpres.rendered;
} else {
var _renderStringNode2 = renderStringNode(contextRef, options);
rendered = _renderStringNode2.rendered;
asts = _renderStringNode2.asts;
}
} else if (F.isArray(node)) {
var _renderArrayNode = renderArrayNode(contextRef, options);
rendered = _renderArrayNode.rendered;
asts = _renderArrayNode.asts;
} else {
rendered = node;
}
if (self.isRoot) {
return;
}
if (rendered === undefined) {
if (jp.value(config, '$.operators.constraints["?"].drop')) {
self.remove(true);
} else {
self.update(null);
}
} else if (rendered === null) {
if (jp.value(config, '$.operators.constraints["!"].nullable')) {
self.update(null);
} else {
var _context2;
throw new Error((0, _concat["default"])(_context2 = "Missing required attribute: [".concat(jp.stringify(self.path), ": ")).call(_context2, asts ? asts[0].source : '', "]"));
}
} else if (F.isReduced(rendered)) {
self.update(F.unreduced(rendered), true); // stopHere, don't traverse children
} else {
self.update(rendered);
}
});
}
return result;
};
};
var reRenderTags = function reRenderTags(template) {
var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref3$meta = _ref3.meta,
meta = _ref3$meta === void 0 ? 0 : _ref3$meta,
_ref3$sources = _ref3.sources,
sources = _ref3$sources === void 0 ? {
"default": {}
} : _ref3$sources,
_ref3$tags = _ref3.tags,
tags = _ref3$tags === void 0 ? {} : _ref3$tags,
_ref3$functions = _ref3.functions,
functions = _ref3$functions === void 0 ? {} : _ref3$functions,
_ref3$args = _ref3.args,
args = _ref3$args === void 0 ? {} : _ref3$args,
_ref3$config = _ref3.config,
config = _ref3$config === void 0 ? defaultConfig : _ref3$config;
var _ref4 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
_ref4$builtins = _ref4.builtins,
builtins = _ref4$builtins === void 0 ? bins : _ref4$builtins;
return function (document) {
var _context3;
return (0, _reduce["default"])(F).call(F, function (template, _ref5) {
var path = _ref5.path,
tag = _ref5.tag,
source = _ref5.source,
templatePath = _ref5.templatePath,
tagPath = _ref5.tagPath;
var value = tags[tagPath];
var rendered = jp.value(template, path).replace(source, value);
jp.value(template, path, rendered);
return template;
}, function () {
return template;
}, (0, _filter["default"])(_context3 = sources['@@next']).call(_context3, function (job) {
return job['type'] === '@@tag';
}));
};
};
var applyPolicies = function applyPolicies(template) {
var _ref6 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
_ref6$meta = _ref6.meta,
meta = _ref6$meta === void 0 ? 0 : _ref6$meta,
_ref6$sources = _ref6.sources,
sources = _ref6$sources === void 0 ? {
"default": {}
} : _ref6$sources,
_ref6$tags = _ref6.tags,
tags = _ref6$tags === void 0 ? {} : _ref6$tags,
_ref6$functions = _ref6.functions,
functions = _ref6$functions === void 0 ? {} : _ref6$functions,
_ref6$args = _ref6.args,
args = _ref6$args === void 0 ? {} : _ref6$args,
_ref6$config = _ref6.config,
config = _ref6$config === void 0 ? defaultConfig : _ref6$config;
var _ref7 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
_ref7$builtins = _ref7.builtins,
builtins = _ref7$builtins === void 0 ? bins : _ref7$builtins;
return function (document) {
var _context4;
return (0, _reduce["default"])(F).call(F, function (acc, _ref8) {
var path = _ref8.path,
tag = _ref8.tag,
source = _ref8.source,
templatePath = _ref8.templatePath,
tagPath = _ref8.tagPath;
var policy = jp.value(sources, jpify(tag));
var _runPolicy = runPolicy(policy, acc, document)({
path: path,
tag: tag,
source: source,
templatePath: templatePath,
tagPath: tagPath
}),
rendered = _runPolicy.template,
tPath = _runPolicy.templatePath;
return rendered;
}, function () {
return template;
}, (0, _filter["default"])(_context4 = sources['@@next']).call(_context4, function (job) {
return job['type'] === '@@policy';
}));
};
};
module.exports = {
transform: transform,
reRenderTags: reRenderTags,
applyPolicies: applyPolicies,
data: _objectSpread(_objectSpread({}, renderData), {}, {
defaultConfig: defaultConfig
})
};