builder/lib/tasks/buildThemes.js

  1. const path = require("path");
  2. const themeBuilder = require("../processors/themeBuilder");
  3. const ReaderCollectionPrioritized = require("@ui5/fs").ReaderCollectionPrioritized;
  4. const fsInterface = require("@ui5/fs").fsInterface;
  5. const log = require("@ui5/logger").getLogger("builder:tasks:buildThemes");
  6. /**
  7. * Task to build a library theme.
  8. *
  9. * @public
  10. * @alias module:@ui5/builder.tasks.buildThemes
  11. * @param {object} parameters Parameters
  12. * @param {module:@ui5/fs.DuplexCollection} parameters.workspace DuplexCollection to read and write files
  13. * @param {module:@ui5/fs.AbstractReader} parameters.dependencies Reader or Collection to read dependency files
  14. * @param {object} parameters.options Options
  15. * @param {string} parameters.options.projectName Project name
  16. * @param {string} parameters.options.inputPattern Search pattern for *.less files to be built
  17. * @param {string} [parameters.options.librariesPattern] Search pattern for .library files
  18. * @param {string} [parameters.options.themesPattern] Search pattern for sap.ui.core theme folders
  19. * @param {boolean} [parameters.options.compress=true]
  20. * @param {boolean} [parameters.options.cssVariables=false]
  21. * @returns {Promise<undefined>} Promise resolving with <code>undefined</code> once data has been written
  22. */
  23. module.exports = async function({
  24. workspace, dependencies,
  25. options: {
  26. projectName, inputPattern, librariesPattern, themesPattern, compress, cssVariables
  27. }
  28. }) {
  29. const combo = new ReaderCollectionPrioritized({
  30. name: `theme - prioritize workspace over dependencies: ${projectName}`,
  31. readers: [workspace, dependencies]
  32. });
  33. compress = compress === undefined ? true : compress;
  34. const pAllResources = workspace.byGlob(inputPattern);
  35. let pAvailableLibraries;
  36. let pAvailableThemes;
  37. if (librariesPattern) {
  38. // If a librariesPattern is given
  39. // we will use it to reduce the set of libraries a theme will be built for
  40. pAvailableLibraries = combo.byGlob(librariesPattern);
  41. }
  42. if (themesPattern) {
  43. // If a themesPattern is given
  44. // we will use it to reduce the set of themes that will be built
  45. pAvailableThemes = combo.byGlob(themesPattern, {nodir: false});
  46. }
  47. /* Don't try to build themes for libraries that are not available
  48. (maybe replace this with something more aware of which dependencies are optional and therefore
  49. legitimately missing and which not (fault case))
  50. */
  51. let availableLibraries;
  52. if (pAvailableLibraries) {
  53. availableLibraries = [];
  54. (await pAvailableLibraries).forEach((resource) => {
  55. const library = path.dirname(resource.getPath());
  56. if (!availableLibraries.includes(library)) {
  57. availableLibraries.push(library);
  58. }
  59. });
  60. }
  61. let availableThemes;
  62. if (pAvailableThemes) {
  63. availableThemes = (await pAvailableThemes)
  64. .filter((resource) => resource.getStatInfo().isDirectory())
  65. .map((resource) => {
  66. return path.basename(resource.getPath());
  67. });
  68. }
  69. let allResources = await pAllResources;
  70. const isAvailable = function(resource) {
  71. let libraryAvailable = false;
  72. let themeAvailable = false;
  73. const resourcePath = resource.getPath();
  74. const themeName = path.basename(path.dirname(resourcePath));
  75. if (!availableLibraries || availableLibraries.length === 0) {
  76. libraryAvailable = true; // If no libraries are found, build themes for all libraries
  77. } else {
  78. for (let i = availableLibraries.length - 1; i >= 0; i--) {
  79. if (resourcePath.startsWith(availableLibraries[i])) {
  80. libraryAvailable = true;
  81. }
  82. }
  83. }
  84. if (!availableThemes || availableThemes.length === 0) {
  85. themeAvailable = true; // If no themes are found, build all themes
  86. } else {
  87. themeAvailable = availableThemes.includes(themeName);
  88. }
  89. if (log.isLevelEnabled("verbose")) {
  90. if (!libraryAvailable) {
  91. log.verbose(`Skipping ${resourcePath}: Library is not available`);
  92. }
  93. if (!themeAvailable) {
  94. log.verbose(`Skipping ${resourcePath}: sap.ui.core theme '${themeName}' is not available. ` +
  95. "If you experience missing themes, check whether you have added the corresponding theme " +
  96. "library to your projects dependencies and make sure that your custom themes contain " +
  97. "resources for the sap.ui.core namespace.");
  98. }
  99. }
  100. // Only build if library and theme are available
  101. return libraryAvailable && themeAvailable;
  102. };
  103. if (availableLibraries || availableThemes) {
  104. if (log.isLevelEnabled("verbose")) {
  105. log.verbose("Filtering themes to be built:");
  106. if (availableLibraries) {
  107. log.verbose(`Available libraries: ${availableLibraries.join(", ")}`);
  108. }
  109. if (availableThemes) {
  110. log.verbose(`Available sap.ui.core themes: ${availableThemes.join(", ")}`);
  111. }
  112. }
  113. allResources = allResources.filter(isAvailable);
  114. }
  115. const processedResources = await themeBuilder({
  116. resources: allResources,
  117. fs: fsInterface(combo),
  118. options: {
  119. compress,
  120. cssVariables: !!cssVariables
  121. }
  122. });
  123. await Promise.all(processedResources.map((resource) => {
  124. return workspace.write(resource);
  125. }));
  126. };