@communities-webruntime/services
Version:
If you would like to run Lightning Web Runtime without the CLI, we expose some of our programmatic APIs available in Node.js. If you're looking for the CLI documentation [you can find that here](https://www.npmjs.com/package/@communities-webruntime/cli).
100 lines • 3.98 kB
JavaScript
;
/** @hidden */
/**
* Copyright (c) 2019, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
const beautify = require('js-beautify');
const ROUTE_PARAM_REFERENCE = 'routeParams';
const CMP_REFERENCE = 'cmp';
const EXPRESSION_REGEX_INNER_CAPTURE = /\{!\s*([a-zA-Z0-9_.]+)\s*\}/;
const DEFAULT_ATTRIBUTES = '(cmp) => ({})';
/**
* Generates the Javascript for the function that takes a component and returns the attribute set
* with resolved references to route parameters.
* e.g. (cmp) => ( { ...attributeSet... } )
*
* @param {Object} attributeSet the aggregated component attributes for a view
*/
function generateAttributesJS(attributeSet) {
const attributeSetString = attributeSetToJS(attributeSet);
return `(${CMP_REFERENCE}) => (${beautify(attributeSetString)})`;
}
/**
* Converts the attribute set of a view to Javascript.
*
* @param {Object} attributeSet the aggregated component attributes for a view
*/
function attributeSetToJS(attributeSet) {
let attributeSetString = '{';
let cmpIdx = 0;
Object.entries(attributeSet).forEach(([cmpNameKey, cmpAttributes]) => {
// Exclude empty component attribute maps
if (Object.keys(cmpAttributes).length === 0) {
return;
}
if (cmpIdx++ > 0) {
attributeSetString += ',';
}
attributeSetString += `"${cmpNameKey}": {`;
let attrIdx = 0;
Object.entries(cmpAttributes).forEach(([attributeName, attributeValue]) => {
if (attrIdx++ > 0) {
attributeSetString += ',';
}
attributeSetString += `"${attributeName}":${attributeValueToJS(attributeValue)}`;
});
attributeSetString += `}`;
});
attributeSetString += '}';
return attributeSetString;
}
/**
* Convert an attribute value to Javascript.
* The value is resolved as necessary in the Javascript.
*
* @param {*} attributeValue value of the attribute
*/
function attributeValueToJS(attributeValue) {
if (typeof attributeValue === 'string' &&
attributeValue.match(EXPRESSION_REGEX_INNER_CAPTURE)) {
// Resolve any {!EL}
return resolveStringAttribute(attributeValue);
}
return JSON.stringify(attributeValue);
}
/**
* Evaluates if a string attribute contains any {!expression} and replaces any instances with a reference to route param(s).
* If the param is not present, the value defaults to an empty string.
* e.g. "prefix {!recordId} postfix" => "prefix " + (cmp.routeParams["recordId"] || '') + " postfix"
*
* Note: This assumes that values from cmp.routeParams will always evaluate to strings (and never numbers).
*
* @param {string} attributeValue string attribute value containing an {!expression}
*/
function resolveStringAttribute(attributeValue) {
let remainderOfString = attributeValue;
let match = EXPRESSION_REGEX_INNER_CAPTURE.exec(remainderOfString);
const segments = [];
while (match) {
const prefix = remainderOfString.substring(0, match.index);
if (prefix) {
segments.push(JSON.stringify(prefix));
}
const exprKey = match[1].trim(); // capture group, e.g. "recordId" from "{! recordId }"
// Default to empty string if route param not present
const routeParamRef = `(${CMP_REFERENCE}.${ROUTE_PARAM_REFERENCE}["${exprKey}"] || '')`;
segments.push(routeParamRef);
// Check for more matches
remainderOfString = remainderOfString.substring(match.index + match[0].length);
match = EXPRESSION_REGEX_INNER_CAPTURE.exec(remainderOfString);
}
if (remainderOfString) {
segments.push(JSON.stringify(remainderOfString));
}
return segments.join(' + ');
}
module.exports = { generateAttributesJS, DEFAULT_ATTRIBUTES };
//# sourceMappingURL=attributes-js-generator.js.map