UNPKG

liferay-theme-tasks

Version:

A set of tasks for building and deploying Liferay Portal themes.

318 lines (251 loc) 6.3 kB
/** * SPDX-FileCopyrightText: © 2017 Liferay, Inc. <https://liferay.com> * SPDX-License-Identifier: MIT */ const fs = require('fs-extra'); const _ = require('lodash'); const path = require('path'); const util = require('util'); const xml2js = require('xml2js'); const project = require('../../lib/project'); const QUERY_ELEMENTS = { 'color-scheme': 'id', 'layout-templates.0.custom.0.layout-template': 'id', 'layout-templates.0.standard.0.layout-template': 'id', 'portlet-decorator': 'id', 'roles': 'single', 'settings.0.setting': 'key', }; const STR_LOOK_AND_FEEL = 'look-and-feel'; const THEME_CHILD_ORDER = [ '$', 'root-path', 'templates-path', 'css-path', 'images-path', 'javascript-path', 'virtual-path', 'template-extension', 'settings', 'control-panel-theme', 'page-theme', 'wap-theme', 'roles', 'color-scheme', 'layout-templates', 'portlet-decorator', ]; function buildXML(lookAndFeelJSON, doctypeElement) { const themeQuery = 'look-and-feel.theme.0'; let themeElement = _.get(lookAndFeelJSON, themeQuery); themeElement = _.reduce( THEME_CHILD_ORDER, (result, item) => { if (themeElement[item]) { result[item] = themeElement[item]; } return result; }, {} ); _.set(lookAndFeelJSON, themeQuery, themeElement); const builder = new xml2js.Builder({ renderOpts: { indent: '\t', pretty: true, }, xmldec: { encoding: null, standalone: null, }, }); let xml = builder.buildObject(lookAndFeelJSON); xml = xml.replace(/(<\?xml.*>)/, '$1\n' + doctypeElement + '\n'); return xml; } function correctJSONIdentifiers(lookAndFeelJSON, name) { const themeAttrs = lookAndFeelJSON[STR_LOOK_AND_FEEL].theme[0].$; if (name !== themeAttrs.name) { themeAttrs.name = name; themeAttrs.id = _.kebabCase(name); } return lookAndFeelJSON; } function getLookAndFeelDoctype(themePath) { const xmlString = readLookAndFeelXML(themePath); let match; if (xmlString) { match = xmlString.match(/(<!DOCTYPE.*>)/); } return match ? match[0] : null; } function getLookAndFeelDoctypeByVersion(version) { version += '.0'; return util.format( '<!DOCTYPE look-and-feel PUBLIC "-//Liferay//DTD Look and Feel %s//EN" "http://www.liferay.com/dtd/liferay-look-and-feel_%s.dtd">', version, version.replace(/\./g, '_') ); } function getLookAndFeelJSON(themePath, callback) { const xmlString = readLookAndFeelXML(themePath); if (!xmlString) { return callback(); } xml2js.parseString(xmlString, (error, result) => { if (error) { throw error; } callback(result); }); } function getNameFromPluginPackageProperties(themePath) { const {pathSrc} = project.options; const pluginPackageProperties = fs.readFileSync( path.join( themePath, pathSrc.asNative, 'WEB-INF', 'liferay-plugin-package.properties' ), { encoding: 'utf8', } ); const match = pluginPackageProperties.match(/name=(.*)/); return match ? match[1] : null; } function mergeLookAndFeelJSON(themePath, lookAndFeelJSON, callback) { getLookAndFeelJSON(themePath, (json) => { if (_.isEmpty(lookAndFeelJSON)) { lookAndFeelJSON = json; } else if (json) { lookAndFeelJSON = mergeJSON(lookAndFeelJSON, json); } // eslint-disable-next-line @liferay/no-dynamic-require const {liferayTheme: themeInfo} = require(path.join( themePath, 'package.json' )); const baseTheme = themeInfo.baseTheme; if (_.isObject(baseTheme)) { themePath = path.join(themePath, 'node_modules', baseTheme.name); mergeLookAndFeelJSON(themePath, lookAndFeelJSON, callback); } else { callback(lookAndFeelJSON); } }); } function readLookAndFeelXML(themePath) { let xmlString = xmlCache[themePath]; if (xmlString) { return xmlString; } const lookAndFeelDefaultPath = path.join( themePath, 'src', 'WEB-INF', 'liferay-look-and-feel.xml' ); const {pathSrc} = project.options; let lookAndFeelPath = path.join( themePath, pathSrc.asNative, 'WEB-INF', 'liferay-look-and-feel.xml' ); try { fs.statSync(lookAndFeelPath); } catch (error) { lookAndFeelPath = lookAndFeelDefaultPath; } try { xmlString = fs.readFileSync(lookAndFeelPath, 'utf8'); xmlCache[themePath] = xmlString; } catch (error) { // Swallow. } return xmlString; } module.exports = { buildXML, correctJSONIdentifiers, getLookAndFeelDoctype, getLookAndFeelDoctypeByVersion, getLookAndFeelJSON, getNameFromPluginPackageProperties, mergeLookAndFeelJSON, readLookAndFeelXML, }; const xmlCache = {}; function extractThemeElement(object, key) { return object[STR_LOOK_AND_FEEL].theme[0][key]; } function mergeJSON(themeObj, baseThemeObj) { _.forEach(QUERY_ELEMENTS, (item, index) => { let mergedElement; const queryString = 'look-and-feel.theme.0.' + index; const baseThemeElement = _.get(baseThemeObj, queryString); const themeElement = _.get(themeObj, queryString); if (item === 'value') { mergedElement = mergeThemeElementByValue( themeElement, baseThemeElement ); } else if (item === 'single') { mergedElement = themeElement || baseThemeElement; } else { mergedElement = mergeThemeElementById( themeElement, baseThemeElement, item ); } if (mergedElement) { _.set(themeObj, queryString, mergedElement); } }); return themeObj; } function mergeThemeElementById(themeElements, baseThemeElements, identifier) { if (!themeElements || !baseThemeElements) { return themeElements ? themeElements : baseThemeElements; } identifier = identifier || 'id'; const allElements = themeElements.concat(baseThemeElements); const elementIds = []; return _.reduce( allElements, (result, item) => { const id = item.$[identifier]; if (elementIds.indexOf(id) < 0) { elementIds.push(id); result.push(item); } return result; }, [] ); } function mergeThemeElementByValue(themeElements, baseThemeElements) { if (!themeElements || !baseThemeElements) { return themeElements ? themeElements : baseThemeElements; } return _.uniq(themeElements.concat(baseThemeElements)); } // Export private methods when in tests if (typeof jest !== 'undefined') { Object.assign(module.exports, { extractThemeElement, mergeJSON, mergeThemeElementById, mergeThemeElementByValue, xmlCache, }); }