From 75dfffc84995f4290cd17570f3a0d282f30b46f8 Mon Sep 17 00:00:00 2001 From: Ben Moroze Date: Fri, 17 Apr 2020 11:30:50 -0400 Subject: [PATCH] Release 8.2.0 --- README.md | 4 +- RELEASENOTES.md | 2 +- lib/buildCommon.js | 600 +++++++++++++--------- lib/defaultconfig.js | 726 +++++++++++++-------------- lib/rjsConfigGenerator.js | 807 +++++++++++++++--------------- lib/serveWebFileChangeHandler.js | 373 +++++++------- lib/templates/pack/component.json | 2 +- package.json | 4 +- 8 files changed, 1340 insertions(+), 1178 deletions(-) diff --git a/README.md b/README.md index a5dcef7..eca2545 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# @oracle/oraclejet-tooling 8.1.0 +# @oracle/oraclejet-tooling 8.2.0 ## About the tooling API This tooling API contains methods to build and serve Oracle JET web and hybrid mobile apps. It is intended to be used with task running tools such as grunt or gulp. The APIs can also be invoked directly. @@ -6,7 +6,7 @@ This tooling API contains methods to build and serve Oracle JET web and hybrid m This is an open source project maintained by Oracle Corp. ## Installation -This module will be automatically installed when you scaffold a web or hybrid mobile app following the [Oracle JET Developers Guide](http://www.oracle.com/pls/topic/lookup?ctx=jet810&id=homepage). +This module will be automatically installed when you scaffold a web or hybrid mobile app following the [Oracle JET Developers Guide](http://www.oracle.com/pls/topic/lookup?ctx=jet820&id=homepage). ## [Contributing](https://github.com/oracle/oraclejet-tooling/blob/master/CONTRIBUTING.md) Oracle JET is an open source project. Pull Requests are currently not being accepted. See diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c34fc24..d4afb8c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,6 +1,6 @@ ## Release Notes for oraclejet-tooling ## -### 8.1.0 +### 8.2.0 * No changes ### 5.2.0 diff --git a/lib/buildCommon.js b/lib/buildCommon.js index c264646..61065e2 100644 --- a/lib/buildCommon.js +++ b/lib/buildCommon.js @@ -392,173 +392,235 @@ function _stagePackComponent(context, type, srcPath, destPath, destPathRelease) }); } +/** + * ## _isTypePack + * + * Returns true if the componentJson is a pack. + * + * @private + * @param {Object} componentJson + * @returns {boolean} + */ +function _isTypePack(componentJson) { + if (util.hasProperty(componentJson, 'type') && componentJson.type === 'pack') return true; + return false; +} + // Optimize the component (using the requireJS optimizer) -function _rjsOptimizeComponent(context, singleton, masterPathObj, baseUrl, name, out, packName, packPath, extraExcludes, extraEmpties) { // eslint-disable-line max-len - util.log(`Running component requirejs task, pack: ${packName} name: ${name}`); - const rConfig = { - baseUrl, - name, - out, - optimize: context.opts.requireJsComponent.optimize, - buildCSS: context.opts.requireJsComponent.buildCSS, - separateCSS: context.opts.requireJsComponent.separateCSS, - generateSourceMaps: context.opts.requireJsComponent.generateSourceMaps - }; +function _rjsOptimizeComponentSetup(context, singleton, masterPathObj, baseUrl, name, out, packName, packPath, extraExcludes, extraEmpties) { // eslint-disable-line max-len + return new Promise((resolve, reject) => { + try { + util.log(`Running component requirejs task, pack: ${packName} name: ${name}`); + const rConfig = { + baseUrl, + name, + out, + optimize: context.opts.requireJsComponent.optimize, + buildCSS: context.opts.requireJsComponent.buildCSS, + separateCSS: context.opts.requireJsComponent.separateCSS, + generateSourceMaps: context.opts.requireJsComponent.generateSourceMaps + }; + + // Note - getMasterPathsMapping returns the paths with the prepended ../../.. + // Specific libraries need to be defined and excluded in the rjsConfig. + // The remainder of the paths are set to empty. + const excludePaths = ['css', 'ojL10n', 'text', 'normalize', 'css-builder']; + Object.keys(masterPathObj).forEach((lib) => { + if (!excludePaths.includes(lib)) { + masterPathObj[lib] = 'empty:'; // eslint-disable-line no-param-reassign + } + }); - // Note - getMasterPathsMapping returns the paths with the prepended ../../.. - // Specific libraries need to be defined and excluded in the rjsConfig. - // The remainder of the paths are set to empty. - const excludePaths = ['css', 'ojL10n', 'text', 'normalize', 'css-builder']; - Object.keys(masterPathObj).forEach((lib) => { - if (!excludePaths.includes(lib)) { - masterPathObj[lib] = 'empty:'; // eslint-disable-line no-param-reassign - } - }); + rConfig.paths = masterPathObj; - rConfig.paths = masterPathObj; + // Construct the exclude path. + const exclude = []; + Object.keys(masterPathObj).forEach((lib) => { + // Exclude any path assigned to empty + if (masterPathObj[lib] !== 'empty:') { + exclude.push(lib); + } + }); + rConfig.exclude = exclude; - // Construct the exclude path. - const exclude = []; - Object.keys(masterPathObj).forEach((lib) => { - // Exclude any path assigned to empty - if (masterPathObj[lib] !== 'empty:') { - exclude.push(lib); - } - }); - rConfig.exclude = exclude; + if (extraExcludes) { + extraExcludes.forEach((ex) => { + rConfig.paths[ex.name] = ex.path; + rConfig.exclude.push(ex.name); + }); + } - if (extraExcludes) { - extraExcludes.forEach((ex) => { - rConfig.paths[ex.name] = ex.path; - rConfig.exclude.push(ex.name); - }); - } + // The extraEmpties parameter is used to exclude resource + // members in the minification of a pack. + // For example: + // rConfig.paths['oj-jspack/resourcemember'] = "empty:"; + if (extraEmpties) { + extraEmpties.forEach((ex) => { + rConfig.paths[ex] = 'empty:'; + }); + } - // The extraEmpties parameter is used to exclude resource - // members in the minification of a pack. - // For example: - // rConfig.paths['oj-jspack/resourcemember'] = "empty:"; - if (extraEmpties) { - extraEmpties.forEach((ex) => { - rConfig.paths[ex] = 'empty:'; - }); - } + // If we are dealing with a defined pack - set up the path + if (packName && packPath) { + rConfig.paths[packName] = packPath; + } - // If we are dealing with a defined pack - set up the path - if (packName && packPath) { - rConfig.paths[packName] = packPath; - } + context.opts.componentRequireJs = rConfig; // eslint-disable-line no-param-reassign + resolve(context); + } catch (error) { + reject(error); + } + }); +} - context.opts.componentRequireJs = rConfig; // eslint-disable-line no-param-reassign +function _rjsOptimizeComponentInvoker(context, out) { return new Promise((resolve, reject) => { try { - hookRunner('before_component_optimize', context) - .then(requirejs.optimize( - context.opts.componentRequireJs, - () => { - // Minify component with terser unless user has - // turned off optimize with the --optimize=none flag - if (context.opts.optimize === 'none') { + requirejs.optimize( + context.opts.componentRequireJs, + () => { + // Minify component with terser unless user has + // turned off optimize with the --optimize=none flag + if (context.opts.optimize === 'none') { + resolve(context); + } else { + // fs.readFileSync(out); + _writeUglyCodeToFile( + [{ dest: out, src: out }], + context.opts.terser.options, + true, + true + ).then(() => { resolve(context); - } else { - // fs.readFileSync(out); - _writeUglyCodeToFile( - [{ dest: out, src: out }], - context.opts.terser.options - ).then(() => { - resolve(context); - }).catch((minifyError) => { - util.log.error(minifyError); - }); - } - }, - (err) => { - util.log(err); - reject(err); - })); + }).catch((minifyError) => { + util.log.error(minifyError); + }); + } + }, + (err) => { + util.log(err); + reject(err); + }); } catch (error) { reject(error); } }); } -function _isTypeCompositeOrResource(componentJson) { - if (!util.hasProperty(componentJson, 'type')) return true; - if (util.hasProperty(componentJson, 'type') && - ((componentJson.type === 'resource') || componentJson.type === 'composite')) return true; - return false; +// Optimize the component (using the requireJS optimizer) +function _rjsOptimizeComponent(context, singleton, masterPathObj, baseUrl, name, out, packName, packPath, extraExcludes, extraEmpties) { // eslint-disable-line max-len + util.log(`Running requirejs component optimize task. ${name}`); + const promiseFuncRJSComp = [ + () => _rjsOptimizeComponentSetup(context, singleton, masterPathObj, baseUrl, name, out, packName, packPath, extraExcludes, extraEmpties), // eslint-disable-line max-len + () => hookRunner('before_component_optimize', context), + () => _rjsOptimizeComponentInvoker(context, out) + ]; + return util.runPromisesInSeries(promiseFuncRJSComp); } -// -// Get the resource dependencies for a component. -// These are subsequently used in the RJS path config. -// -// A resource dependency may 'pack' or 'non'pack'. -// -// Example 1 : 'non-pack' dependency: -// -// "dependencies": { "oj-common-resources": "1.0.0" } -// Here, we expect to see -// 'oj-common/resources': 'empty' -// in the RJS path. -// -// Path substitution: Note that we replace the '-resources' with a path -// since 'oj-common' will not necessarily be in the rjs path config. -// Also note that the componentNames set data structure is used -// to look up any component prefixes that may require path substitution. -// -// Example 2 : 'pack' dependency: -// -// A pack will list its dependencies as follows: -// { -// "name": "oj-jspack-packmember", -// "pack": "oj-jspack", -// ... -// "dependencies": { -// "oj-jspack-resourcemember": "1.0.0" -// } -// } -// -// And the following transformation would -// For example: -// oj-jspack-resourcemember -> oj-jspack/resourcemember -// -function _getResourceDependencies(packName, subComponentJson) { + +/** + * ## _getReferenceDependencies + * + * @private + * @param {Object} context + * @param {String} packName + * @param {Object} subComponentJson + * @returns {Object} + * + * Determine a component's reference dependencies, retuning a mapping object. + * + */ +function _getReferenceDependencies(context, packName, componentJson) { + const allReferenceMappings = {}; + if (!componentJson.dependencies) return allReferenceMappings; + + let componentName; + Object.keys(componentJson.dependencies).forEach((el) => { + // Check if the dependency begins with the packname, such as oj-jspack/resourcemember + if (el.indexOf(packName) === 0) { + // Rewrite to cross-platform path + const resourceDependencyIndex = packName.length + 1; + componentName = `${packName}/${el.substring(resourceDependencyIndex)}`; + } else { + // case for a singleton dependency. + componentName = el; + } + const dependentComponentJson = _getComponentJson(context, componentName); + if (dependentComponentJson.type === 'reference') { + const refPath = + pathGenerator.getReferencePath(context.buildType, true, dependentComponentJson); + Object.entries(refPath).forEach(([key, value]) => { + allReferenceMappings[key] = value; + }); + } + }); + return allReferenceMappings; +} + +/** + * ## _getResourceDependencies + * + * @private + * @param {Object} context + * @param {String} packName + * @param {Object} subComponentJson + * @returns {Object} + * + * Determine a component's resource dependencies and return a mapping object. + * + * A pack will list its dependencies as follows: + * + * { + * "name": "oj-jspack-packmember", + * "pack": "oj-jspack", + * ... + * "dependencies": { + * "oj-jspack-resourcemember": "1.0.0", + * "oj-ref-calendar": "3.1.0", + * } + * } + * + * The following function returns a set of dependencies + * which will be set to empty during rjs component minification + * + * For example: + * + * oj-jspack-resourcemember is transformed to oj-jspack/resourcemember + * + * The dependency may also omit the pack, as in + * + * "oj-ref-calendar": "3.1.0", + * + * In this case oj-ref-calendar is transformed to itself. + */ +function _getResourceDependencies(context, packName, componentJson) { // Figure out what resources we are dependent on. const allResourceEmpty = new Set(); - if (!subComponentJson.dependencies) return allResourceEmpty; - Object.keys(subComponentJson.dependencies).forEach((el) => { - const packNameIndex = el.indexOf(packName); - if (packNameIndex === -1) { - // Handle the case where the dependency is on a 'non-pack' component - // (As in Example 1) - let matchedPrefix = false; - const componentNamesArray = Array.from(componentNames); - componentNamesArray.some((item) => { - if (el.indexOf(item) === 0 && el.length > item.length) { - // We found a match at the beginning of the string. - // For example, for 'oj-common-resources', we transform to 'oj-common/resources' - // given a component named 'oj-common' - const emptyDep = `${item}/${el.substring(item.length + 1)}`; - allResourceEmpty.add(emptyDep); - matchedPrefix = true; - return true; - } - return false; - }); - if (!matchedPrefix) { - allResourceEmpty.add(el); - } + if (!componentJson.dependencies) return allResourceEmpty; + + let emptyDep; + // el should be componentName + Object.keys(componentJson.dependencies).forEach((componentName) => { + // Check if the dependency begins with the packname, such as oj-jspack/resourcemember + if (componentName.indexOf(packName) === 0) { + // Rewrite to cross-platform path + const resourceDependencyIndex = packName.length + 1; + emptyDep = `${packName}/${componentName.substring(resourceDependencyIndex)}`; } else { - // Handle case where the dependency is part of the pack (Example 2) - const resourceDependencyIndex = el.indexOf(packName) + packName.length + 1; - const emptyDep = `${packName}/${el.substring(resourceDependencyIndex)}`; - allResourceEmpty.add(emptyDep); + const dependentComponentJson = _getComponentJson(context, componentName); + // Set resource components to empty, + // but don't set reference components to empty. + if (dependentComponentJson.type !== 'reference') { + emptyDep = componentName; + } } + allResourceEmpty.add(emptyDep); }); return allResourceEmpty; } + // Minfy a singleton or a pack component. // Note that we may need to call requireJs on several components in the pack case // so we resolve the return only after ALL the requireJs calls. @@ -581,6 +643,7 @@ function _minifyComponentInternal(context, componentJson, componentName, srcBase } else { util.log.error('Missing name property for pack.'); } + if (util.hasProperty(componentJson, 'dependencies')) { // Copy the components listed in each dependency. Object.keys(componentJson.dependencies).forEach((el) => { @@ -588,7 +651,7 @@ function _minifyComponentInternal(context, componentJson, componentName, srcBase const packComponentName = el.substring(packName.length + 1); const srcPathPack = path.join(srcBase, packName, packComponentVersion, packComponentName); // eslint-disable-line max-len const destPathPackRelease = path.join(destBase, packName, packComponentVersion, 'min', packComponentName); // eslint-disable-line max-len - const baseUrl = path.join(destBase, packName, packComponentVersion, 'min'); + const baseUrlNoMin = path.join(destBase, packName, packComponentVersion); const subComponentJson = util.readJsonAndReturnObject(path.join(srcPathPack, 'component.json')); if (util.hasProperty(componentJson, 'type')) { @@ -619,9 +682,8 @@ function _minifyComponentInternal(context, componentJson, componentName, srcBase }); const name = `${packName}/${packComponentName}/${moduleName}`; const out = `${path.join(destPathPackRelease, moduleName)}.js`; - promises.push(() => - _rjsOptimizeComponent(context, false, pathGenerator.getMasterPathsMapping(context), baseUrl, name, out, packName, '.', excludes)); // eslint-disable-line max-len + _rjsOptimizeComponent(context, false, pathGenerator.getMasterPathsMappingSingleton(context), baseUrlNoMin, name, out, packName, '.', excludes)); // eslint-disable-line max-len }); } break; @@ -642,7 +704,6 @@ function _minifyComponentInternal(context, componentJson, componentName, srcBase const srcPathPack = path.join(srcBase, packName, packComponentVersion, packComponentName); // eslint-disable-line max-len const destPathPackRelease = path.join(destBase, packName, packComponentVersion, 'min', packComponentName); // eslint-disable-line max-len const baseUrlNoMin = path.join(destBase, packName, packComponentVersion); - const baseUrl = path.join(destBase, packName, packComponentVersion, 'min'); const subComponentJson = util.readJsonAndReturnObject(path.join(srcPathPack, 'component.json')); if (util.hasProperty(componentJson, 'type')) { @@ -651,7 +712,8 @@ function _minifyComponentInternal(context, componentJson, componentName, srcBase case 'resource': { break; } - case 'composite': { + case 'composite': + default: { // For component "component-d" of pack "demo-bundled" // the name would be: "demo-bundled/component-d/loader" const name = `${packName}/${packComponentName}/loader`; @@ -659,18 +721,12 @@ function _minifyComponentInternal(context, componentJson, componentName, srcBase // "web/js/jet-composites/demo-bundled/1.0.0/component-d/min/loader.js"; // const out = path.join(destPathPack, 'min', 'loader.js'); const out = path.join(destPathPackRelease, 'loader.js'); - const emptyResources = _getResourceDependencies(packName, subComponentJson); + const emptyResources = + _getResourceDependencies(context, packName, subComponentJson); + const refDep = + _getReferenceDependencies(context, packName, subComponentJson); promises.push(() => - _rjsOptimizeComponent(context, false, pathGenerator.getMasterPathsMapping(context), baseUrl, name, out, packName, '.', null, emptyResources)); // eslint-disable-line max-len - break; - } - default: { - const name = `${packName}/${packComponentName}/loader`; - const out = path.join(destPathPackRelease, 'loader.js'); - const emptyResources = _getResourceDependencies(packName, subComponentJson); - - promises.push(() => - _rjsOptimizeComponent(context, true, pathGenerator.getMasterPathsMappingSingleton(context), baseUrlNoMin, name, out, packName, '.', null, emptyResources)); // eslint-disable-line max-len + _rjsOptimizeComponent(context, false, pathGenerator.getMasterPathsMappingSingleton(context), baseUrlNoMin, name, out, packName, '.', null, emptyResources, refDep)); // eslint-disable-line max-len break; } } @@ -706,8 +762,8 @@ function _minifyComponentInternal(context, componentJson, componentName, srcBase const bundleContents = `define(["${componentJson.bundles[bundleKey].join('","')}"], function(){});`; const seedBundle = `${path.join(destPath, bundleComponentName)}.js`; fs.writeFileSync(seedBundle, bundleContents); - const baseUrl = path.join(destBase, packName, componentJson.version, 'min'); - promises.push(() => _rjsOptimizeComponent(context, false, pathGenerator.getMasterPathsMapping(context), baseUrl, bundleComponentName, seedBundle, packName, '.')); // eslint-disable-line max-len + const baseUrlNoMin = path.join(destBase, packName, componentJson.version); + promises.push(() => _rjsOptimizeComponent(context, false, pathGenerator.getMasterPathsMapping(context), baseUrlNoMin, bundleComponentName, seedBundle, packName, '.')); // eslint-disable-line max-len }); } break; @@ -720,17 +776,18 @@ function _minifyComponentInternal(context, componentJson, componentName, srcBase break; } } else { - const destPathSingleton = path.join(destBase, componentName, componentJson.version); + // has no type + const baseUrlNoMin = path.join(destBase, componentName, componentJson.version); // The default component type is 'composite' const name = `${componentName}/loader`; // Example for component 'demo-singleton': // "out": web/js/jet-composites/demo-singleton/1.0.0/min/loader.js - const out = path.join(destPathSingleton, 'min', 'loader.js'); + const out = path.join(baseUrlNoMin, 'min', 'loader.js'); // Code path for a singleton component. // (when no componentJson.type property exists). - promises.push(() => _rjsOptimizeComponent(context, true, pathGenerator.getMasterPathsMappingSingleton(context), destPathSingleton, name, out, componentName, '.')); // eslint-disable-line max-len + const emptyResources = _getResourceDependencies(context, componentJson.pack, componentJson); + promises.push(() => _rjsOptimizeComponent(context, true, pathGenerator.getMasterPathsMappingSingleton(context), baseUrlNoMin, name, out, componentName, '.', null, emptyResources)); // eslint-disable-line max-len } - util.runPromisesInSeries(promises, context) .then((data) => { resolve(data); @@ -751,7 +808,7 @@ function _copySingleCcaInternal(context, componentJson, componentName, srcBase, let srcPath = path.join(srcBase, componentName); let destPath = path.join(destBase, componentName, componentJson.version); // Handle pack components - if (util.hasProperty(componentJson, 'type') && componentJson.type === 'pack') { + if (_isTypePack(componentJson)) { // copy the top-level files of the pack. // For example, for demo-bundled, we copy all files in the top level // from: src/js/jet-composites/demo-bundled/ @@ -786,11 +843,13 @@ function _copySingleCcaInternal(context, componentJson, componentName, srcBase, destPath = path.join(destBase, packName, packComponentVersion, packComponentName); const destPathRelease = path.join(destBase, packName, packComponentVersion, 'min', packComponentName); const subComponentJson = util.readJsonAndReturnObject(path.join(srcPath, 'component.json')); - // Note - a pack cannot have a pack dependency. - if (_isTypeCompositeOrResource(subComponentJson)) { + if (!_isTypePack(subComponentJson)) { promises.push( _stagePackComponent(context, subComponentJson.type, srcPath, destPath, destPathRelease)); + } else { + // Flag an error if there is a pack within a pack. + util.log.error(`A pack within a pack is not supported (pack name ${packName}, component ${el})`); } } else { // Flag an error if component is NOT prefixed with pack name @@ -1138,6 +1197,111 @@ function _getComponentBasePaths({ context, component, minify = false }) { }; } +/** + * ## _getComponentJson + * @private + * @param {object} context build context + * @param {String} component name + * @returns {object} component.json file + */ +function _getComponentJson(context, componentName) { + const basePaths = _getComponentBasePaths({ context, component: componentName }); + const componentDirPath = `${basePaths.srcBase}/${componentName}/${CONSTANTS.JET_COMPONENT_JSON}`; + return util.readJsonAndReturnObject(`${componentDirPath}`); +} + +/** + * ## _requireJsInvoker + * + * Invokes requirejs.optimize with context.opts.requireJs parameter. + * + * @private + * @param {object} context build context + * @returns {Promise} promise + */ +function _requireJsInvoker(context) { + return new Promise((resolve, reject) => { + requirejs.optimize(context.opts.requireJs, () => { + util.log('Task requirejs finished.'); + resolve(context); + }, (err) => { + util.log(err); + reject(err); + }); + }); +} + +/** + * ## _requireJsInvoker + * + * Invokes requirejs.optimize with context.opts.requireJsEs5 parameter. + * + * @private + * @param {object} context build context + * @returns {Promise} promise + */ +function _requireJsInvokerEs5(context) { + return new Promise((resolve, reject) => { + requirejs.optimize(context.opts.requireJsEs5, () => { + util.log('Task requirejs ES5 finished.'); + context.opts.isRequireJsEs5 = false; // eslint-disable-line no-param-reassign + resolve(context); + }, (err) => { + context.opts.isRequireJsEs5 = false; // eslint-disable-line no-param-reassign + util.log(err); + reject(err); + }); + }); +} + +/** + * ## _requireJsSetup + * + * Setups up context.opts for requireJs. + * + * @private + * @param {object} context build context + * @returns {Promise} promise + */ +function _requireJsSetup(context) { + return new Promise((resolve, reject) => { + try { + // copy the paths mapping into requireJs.paths + const pathsObj = pathGenerator.getPathsMapping(context, true, false); + // assign paths obj. - making accessible to the before_optimize hook. + context.opts.requireJs.paths = pathsObj; // eslint-disable-line no-param-reassign + context.opts.isRequireJsEs5 = false; // eslint-disable-line no-param-reassign + resolve(context); + } catch (error) { + reject(error); + } + }); +} + +/** + * ## _requireJsSetupEs5 + * + * Setups up context.opts for requireJsEs5. + * + * @private + * @param {object} context build context + * @returns {Promise} promise + */ +function _requireJsSetupEs5(context) { + return new Promise((resolve, reject) => { + try { + // copy the paths mapping into requireJs.paths + const pathsObj = pathGenerator.getPathsMapping(context, true, true); + // assign paths obj. - making accessible to the before_optimize hook. + context.opts.requireJsEs5.paths = pathsObj; // eslint-disable-line no-param-reassign + context.opts.isRequireJsEs5 = true; // eslint-disable-line no-param-reassign + resolve(context); + } catch (error) { + reject(error); + } + }); +} + module.exports = { minifyComponent: function _minifyComponent(context, componentJson, componentName) { @@ -1326,46 +1490,22 @@ module.exports = { requireJs: function _requireJs(context) { util.log('Running requirejs task.'); - - // copy the paths mapping into requireJs.paths - const pathsObj = pathGenerator.getPathsMapping(context, true, false); - // assign paths obj. - making accessible to the before_optimize hook. - context.opts.requireJs.paths = pathsObj; // eslint-disable-line no-param-reassign - context.opts.isRequireJsEs5 = false; // eslint-disable-line no-param-reassign - - return new Promise((resolve, reject) => { - hookRunner('before_optimize', context) - .then(requirejs.optimize(context.opts.requireJs, () => { - util.log('Task requirejs finished *.'); - resolve(context); - }, (err) => { - util.log(err); - reject(err); - })); - }); + const promiseFuncRJS = [ + () => _requireJsSetup(context), + () => hookRunner('before_optimize', context), + () => _requireJsInvoker(context) + ]; + return util.runPromisesInSeries(promiseFuncRJS); }, requireJsEs5: function _requireJsEs5(context) { - util.log('Running requirejs tasks for ES5.'); - - // copy the paths mapping into requireJs.paths - const pathsObj = pathGenerator.getPathsMapping(context, true, true); - // assign paths obj. - making accessible to the before_optimize hook. - context.opts.requireJsEs5.paths = pathsObj; // eslint-disable-line no-param-reassign - context.opts.isRequireJsEs5 = true; // eslint-disable-line no-param-reassign - - return new Promise((resolve, reject) => { - hookRunner('before_optimize', context) - .then(requirejs.optimize(context.opts.requireJsEs5, () => { - util.log('Task requirejs ES5 finished *.'); - context.opts.isRequireJsEs5 = false; // eslint-disable-line no-param-reassign - resolve(context); - }, (err) => { - context.opts.isRequireJsEs5 = false; // eslint-disable-line no-param-reassign - util.log(err); - reject(err); - })); - }); + util.log('Running requirejs task for ES5.'); + const promiseFuncRJSES5 = [ + () => _requireJsSetupEs5(context), + () => hookRunner('before_optimize', context), + () => _requireJsInvokerEs5(context) + ]; + return util.runPromisesInSeries(promiseFuncRJSES5); }, css: function _compileCss(context) { @@ -1633,10 +1773,9 @@ module.exports = { runAllComponentHooks: function _runAllComponentHooks(context) { return new Promise((resolve, reject) => { util.log('runAllComponentHooks '); - // util.log('runAllComponentHooks ' + JSON.stringify(context, null, ' ')); // strip down the context parameter. - // const newContext = util.processContextForHooks(context); - const newContext = context; + const newContext = util.processContextForHooks(context); + const javascriptSrcBase = path.join( config('paths').src.common, config('paths').src.javascript, @@ -1651,30 +1790,33 @@ module.exports = { ...glob.sync(path.join(javascriptSrcBase, '**/component.json')), ...glob.sync(path.join(typescriptSrcBase, '**/component.json')), ]; - - util.runPromiseIterator(components, (componentPath) => { // eslint-disable-line arrow-body-style, max-len - return new Promise((resolve2, reject2) => { - util.log(`runAllComponentHooks for component: ${JSON.stringify(componentPath)}`); - const componentJson = util.readJsonAndReturnObject(componentPath); - if (componentJson) { - newContext.componentConfig = componentJson; - hookRunner('after_component_build', newContext) - .then((data) => { - util.log(`runAllComponentHooks for component: ${JSON.stringify(componentPath)} finished`); - resolve2(data); - }) - .catch((err) => { - util.log(err); - reject2(err); - }); - } - }); // this one - }).then((data) => { - resolve(data); - }).catch((err) => { - util.log(err); - reject(err); - }); + if (components.length === 0) { + resolve(context); + } else { + util.runPromiseIterator(components, (componentPath) => { // eslint-disable-line arrow-body-style, max-len + return new Promise((resolve2, reject2) => { + util.log(`runAllComponentHooks for component: ${JSON.stringify(componentPath)}`); + const componentJson = util.readJsonAndReturnObject(componentPath); + if (componentJson) { + newContext.componentConfig = componentJson; + hookRunner('after_component_build', newContext) + .then((data) => { + util.log(`runAllComponentHooks for component: ${JSON.stringify(componentPath)} finished`); + resolve2(data); + }) + .catch((err) => { + util.log(err); + reject2(err); + }); + } + }); + }).then((data) => { + resolve(data); + }).catch((err) => { + util.log(err); + reject(err); + }); + } // else components.length === 0 }); }, diff --git a/lib/defaultconfig.js b/lib/defaultconfig.js index a4c82de..63f9333 100644 --- a/lib/defaultconfig.js +++ b/lib/defaultconfig.js @@ -2,366 +2,366 @@ Copyright (c) 2015, 2020, Oracle and/or its affiliates. The Universal Permissive License (UPL), Version 1.0 */ -'use strict'; - -const path = require('path'); -const fs = require('fs'); -const util = require('./util'); - -module.exports = { - build: { - - stagingPath: paths => paths.staging.stagingPath, - - injectPaths: paths => ({ - startTag: '// injector:mainReleasePaths', - endTag: '// endinjector', - mainJs: `${paths.staging.stagingPath}/${paths.src.javascript}/main.js`, - destMainJs: `${paths.staging.stagingPath}/${paths.src.javascript}/bundle-temp.js`, - destMainJsEs5: `${paths.staging.stagingPath}/${paths.src.javascript}/bundle-temp_es5.js`, - }), - - // - // The first block directive copies all .js from src dir, (excluding main.js - // and also excluding the jet-composites/ directory). - // We exclude the jet-composites/ dir because the component - // version naming is not identical under the src/ and web/ path. - // - terser: paths => ({ - fileList: [ - { - cwd: `${paths.src.common}/${paths.src.javascript}`, - src: ['**/*.js', '!main.js', `!${paths.composites}/**/*.js`], - dest: `${paths.staging.stagingPath}/${paths.src.javascript}` - }, - { - cwd: `${paths.staging.stagingPath}/${paths.src.typescript}`, - src: ['**/*.js'], - dest: `${paths.staging.stagingPath}/${paths.src.javascript}` - }, - { - cwd: `${paths.staging.stagingPath}/${paths.src.javascript}`, - src: ['bundle-temp.js', 'bundle-temp_es5.js'], - dest: `${paths.staging.stagingPath}/${paths.src.javascript}` - }, - { - // jquery ui npm package does not provide minified scripts - buildType: 'release', - cwd: `${paths.staging.stagingPath}/${paths.src.javascript}/libs`, - src: ['jquery/jqueryui-amd*min/**/*.js'], - dest: `${paths.staging.stagingPath}/${paths.src.javascript}/libs` - } - ], - options: { - compress: { - warnings: false - }, - mangle: { - // Disable mangling requirejs config to avoid optimization errors - reserved: ['require'] - }, - output: { - max_line_len: 32000, - ascii_only: false, - beautify: false, - quote_style: 0, - comments: 'some' - }, - ie8: false - } - }), - - svgMin: paths => ({ - fileList: [ - { - cwd: `${paths.staging.themes}`, - src: ['**/*.svg'], - dest: `${paths.staging.themes}` - } - ], - options: { - plugins: [ - { removeXMLNS: false }, - { removeViewBox: false }, - { removeUselessStrokeAndFill: false }, - { convertStyleToAttrs: false }, - { removeEmptyAttrs: true }, - { - removeAttrs: { - attrs: ['xmlnsX'] - } - } - ] - } - }), - - svgSprite: { - options: { - shape: { - spacing: { // Add padding - padding: 2, // 0 would sometimes have nearby sprites bleeding in (see "layout") - box: 'content' // I was hoping this would exclude the padding but doesn't, so have to include the padding in the background-position - } - } - } - }, - - copySrcToStaging: paths => ({ - fileList: [ - { - buildType: 'release', - cwd: paths.src.common, - src: [ - '**', - `!${paths.src.javascript}/**/*.js`, - `${paths.src.javascript}/main.js`, - `${paths.src.javascript}/libs/**`, - `!${paths.src.javascript}/libs/**/*debug*`, - `!${paths.src.javascript}/libs/**/*debug*/**`, - `!${paths.src.javascript}/main-release-paths.json`, - `!${paths.staging.themes}/**`, - `!${paths.src.javascript}/${paths.composites}/**`, - `!${paths.src.typescript}/${paths.composites}/**`, - '!cordova.js' - ], - dest: paths.staging.stagingPath - }, - { - buildType: 'dev', - cwd: paths.src.common, - src: [ - '**', - `!${paths.src.javascript}/${paths.composites}/**`, - `!${paths.src.typescript}/${paths.composites}/**`, - `!${paths.src.javascript}/main-release-paths.json`, - `!${paths.staging.themes}/**`, - ], - dest: paths.staging.stagingPath - }, - { - cwd: paths.src.platformSpecific, - src: ['**'], - dest: paths.staging.stagingPath - }, - { - buildType: 'dev', - cwd: `${paths.src.common}/${paths.src.themes}`, - src: ['**', '!**/*.scss'], - dest: paths.staging.themes - }, - { - buildType: 'release', - cwd: `${paths.src.common}/${paths.src.themes}`, - src: ['**', '!**/*.scss', '!**.map'], - dest: paths.staging.themes - }, - { - cwd: `${paths.components}`, - src: ['**'], - dest: `${paths.staging.stagingPath}/${paths.src.javascript}/${paths.composites}` - }, - ], - }), - - copyCustomLibsToStaging: { - fileList: [] - }, - - requireJs: paths => ({ - baseUrl: `${paths.staging.stagingPath}/${paths.src.javascript}`, - name: 'bundle-temp', - optimize: 'none', - out: `${paths.staging.stagingPath}/${paths.src.javascript}/bundle.js` - }), - requireJsEs5: paths => ({ - baseUrl: `${paths.staging.stagingPath}/${paths.src.javascript}`, - name: 'bundle-temp_es5', - optimize: 'none', - out: `${paths.staging.stagingPath}/${paths.src.javascript}/bundle_es5.js` - }), - requireJsComponent: { - optimize: 'none', - separateCSS: false, - buildCSS: false - }, - - sass: paths => ({ - fileList: [ - { - cwd(context) { - return `${paths.src.common}/${paths.src.themes}/${context.theme.name}/${context.theme.platform}`; - }, - src: ['**/*.scss', '!**/_*.scss'], - dest(context) { - return `${paths.staging.themes}/${context.theme.name}/${context.theme.platform}`; - } - }, - { - cwd: `${paths.src.common}/${paths.src.javascript}/${paths.composites}`, - src: ['**/*.scss', '!**/_*.scss'], - dest: `${paths.staging.stagingPath}/${paths.src.javascript}/${paths.composites}` - }, - { - cwd: `${paths.src.common}/${paths.src.typescript}/${paths.composites}`, - src: ['**/*.scss', '!**/_*.scss'], - dest: `${paths.staging.stagingPath}/${paths.src.typescript}/${paths.composites}` - }, - { - cwd: `${paths.components}`, - src: ['**/*.scss', '!**/_*.scss'], - dest: `${paths.staging.stagingPath}/${paths.src.javascript}/${paths.composites}` - } - ], - options: { - precision: 10 - } - }), - - pcss: paths => ({ - fileList: [ - { - cwd(context) { - return `${paths.src.common}/${paths.src.themes}/${context.theme.name}/${context.theme.platform}`; - }, - src: ['**/*.scss', '!**/_*.scss', '!**/*.css'], - dest(context) { - return `${paths.staging.themes}/${context.theme.name}/${context.theme.platform}`; - } - }, - { - cwd: `${paths.src.common}/${paths.src.javascript}/${paths.composites}`, - src: ['**/*.scss', '!**/_*.scss'], - dest: `${paths.staging.stagingPath}/${paths.src.javascript}/${paths.composites}` - }, - { - cwd: `${paths.components}`, - src: ['**/*.scss', '!**/_*.scss'], - dest: `${paths.staging.stagingPath}/${paths.src.javascript}/${paths.composites}` - } - ], - options: { - sourceMap: false, - includePaths: [ - `node_modules/@oracle/oraclejet/dist/pcss/oj/v${util.getJETVersion()}/` - ], - precision: 5 - } - }), - - altasass: paths => ({ - fileList: [ - { - cwd(context) { - return `${context.theme.directory}`; - }, - src: ['**/*.scss', '!**/_*.scss'], - dest(context) { - return `${paths.staging.themes}/${context.theme.name}/${context.theme.platform}`; - }, - rename: (dest, file) => path.join(dest, file.replace('oj-', '')) - } - ], - options: { - precision: 10 - } - }), - - injectTheme: { - startTag: '', - endTag: '' - } - }, - - /* Serve Config */ - serve: { - defaultHybridPlatform: 'browser', - // Serve API overall default options - options: { - livereload: true, - build: true, - port: 8000, - livereloadPort: 35729, - }, - - // Sub task connect default options - connect: paths => ({ - options: { - hostname: '*', - port: 8000, - livereload: true, - base: paths.staging.web, - open: true - } - }), - - // Sub task watch default options - watch: paths => ({ - sourceFiles: - { - files: [ - `${paths.src.common}/${paths.src.styles}/!(libs)/**/*.css`, - `${paths.src.common}/${paths.src.javascript}/!(libs)/**/*.js`, - `${paths.src.common}/${paths.src.javascript}/!(libs)/**/*.json`, - `${paths.src.common}/${paths.src.javascript}/!(libs)/**/*.css`, - `${paths.src.common}/${paths.src.javascript}/{,*/}*.js`, - `${paths.src.common}/${paths.src.typescript}/!(libs)/**/*.ts`, - `${paths.src.common}/${paths.src.typescript}/!(libs)/**/*.json`, - `${paths.src.common}/${paths.src.typescript}/!(libs)/**/*.css`, - `${paths.src.common}/${paths.src.typescript}/{,*/}*.ts`, - `${paths.src.common}/${paths.src.styles}/{,*/}*.css`, - `${paths.src.common}/**/*.html`, - ], - options: - { - livereload: true, - spawn: false, - } - }, - - sass: { - files: [ - `${paths.src.common}/${paths.src.themes}/**/*`, - `${paths.components}/**/*.scss`, - `${paths.src.common}/${paths.src.javascript}/${paths.composites}/**/*.scss`, - ], - options: { - livereload: true, - spawn: false - }, - commands: ['compileSass'] - }, - - themes: { - files: [ - `${paths.staging.themes}/**/*` - ], - options: { - livereload: true, - spawn: false - }, - commands: ['copyThemes'] - }, - }), - }, - - /* Platform paths */ - platforms: (paths) => { - let androidRoot = `${paths.staging.hybrid}/platforms/android/assets/www/`; - const android700Path = `${paths.staging.hybrid}/platforms/android/app/src/main/assets/www/`; - androidRoot = fs.existsSync(androidRoot) ? androidRoot : android700Path; - return { - android: { - root: `${androidRoot}`, - }, - browser: { - root: `${paths.staging.hybrid}/platforms/browser/www/`, - }, - ios: { - root: `${paths.staging.hybrid}/platforms/ios/www/`, - }, - windows: { - root: `${paths.staging.hybrid}/platforms/windows/www/`, - } - }; - } -}; +'use strict'; + +const path = require('path'); +const fs = require('fs'); +const util = require('./util'); + +module.exports = { + build: { + + stagingPath: paths => paths.staging.stagingPath, + + injectPaths: paths => ({ + startTag: '// injector:mainReleasePaths', + endTag: '// endinjector', + mainJs: `${paths.staging.stagingPath}/${paths.src.javascript}/main.js`, + destMainJs: `${paths.staging.stagingPath}/${paths.src.javascript}/bundle-temp.js`, + destMainJsEs5: `${paths.staging.stagingPath}/${paths.src.javascript}/bundle-temp_es5.js`, + }), + + // + // The first block directive copies all .js from src dir, (excluding main.js + // and also excluding the jet-composites/ directory). + // We exclude the jet-composites/ dir because the component + // version naming is not identical under the src/ and web/ path. + // + terser: paths => ({ + fileList: [ + { + cwd: `${paths.src.common}/${paths.src.javascript}`, + src: ['**/*.js', '!main.js', `!${paths.composites}/**/*.js`], + dest: `${paths.staging.stagingPath}/${paths.src.javascript}` + }, + { + cwd: `${paths.staging.stagingPath}/${paths.src.typescript}`, + src: ['**/*.js', `!${paths.composites}/**/*.js`], + dest: `${paths.staging.stagingPath}/${paths.src.javascript}` + }, + { + cwd: `${paths.staging.stagingPath}/${paths.src.javascript}`, + src: ['bundle-temp.js', 'bundle-temp_es5.js'], + dest: `${paths.staging.stagingPath}/${paths.src.javascript}` + }, + { + // jquery ui npm package does not provide minified scripts + buildType: 'release', + cwd: `${paths.staging.stagingPath}/${paths.src.javascript}/libs`, + src: ['jquery/jqueryui-amd*min/**/*.js'], + dest: `${paths.staging.stagingPath}/${paths.src.javascript}/libs` + } + ], + options: { + compress: { + warnings: false + }, + mangle: { + // Disable mangling requirejs config to avoid optimization errors + reserved: ['require'] + }, + output: { + max_line_len: 32000, + ascii_only: false, + beautify: false, + quote_style: 0, + comments: 'some' + }, + ie8: false + } + }), + + svgMin: paths => ({ + fileList: [ + { + cwd: `${paths.staging.themes}`, + src: ['**/*.svg'], + dest: `${paths.staging.themes}` + } + ], + options: { + plugins: [ + { removeXMLNS: false }, + { removeViewBox: false }, + { removeUselessStrokeAndFill: false }, + { convertStyleToAttrs: false }, + { removeEmptyAttrs: true }, + { + removeAttrs: { + attrs: ['xmlnsX'] + } + } + ] + } + }), + + svgSprite: { + options: { + shape: { + spacing: { // Add padding + padding: 2, // 0 would sometimes have nearby sprites bleeding in (see "layout") + box: 'content' // I was hoping this would exclude the padding but doesn't, so have to include the padding in the background-position + } + } + } + }, + + copySrcToStaging: paths => ({ + fileList: [ + { + buildType: 'release', + cwd: paths.src.common, + src: [ + '**', + `!${paths.src.javascript}/**/*.js`, + `${paths.src.javascript}/main.js`, + `${paths.src.javascript}/libs/**`, + `!${paths.src.javascript}/libs/**/*debug*`, + `!${paths.src.javascript}/libs/**/*debug*/**`, + `!${paths.src.javascript}/main-release-paths.json`, + `!${paths.staging.themes}/**`, + `!${paths.src.javascript}/${paths.composites}/**`, + `!${paths.src.typescript}/${paths.composites}/**`, + '!cordova.js' + ], + dest: paths.staging.stagingPath + }, + { + buildType: 'dev', + cwd: paths.src.common, + src: [ + '**', + `!${paths.src.javascript}/${paths.composites}/**`, + `!${paths.src.typescript}/${paths.composites}/**`, + `!${paths.src.javascript}/main-release-paths.json`, + `!${paths.staging.themes}/**`, + ], + dest: paths.staging.stagingPath + }, + { + cwd: paths.src.platformSpecific, + src: ['**'], + dest: paths.staging.stagingPath + }, + { + buildType: 'dev', + cwd: `${paths.src.common}/${paths.src.themes}`, + src: ['**', '!**/*.scss'], + dest: paths.staging.themes + }, + { + buildType: 'release', + cwd: `${paths.src.common}/${paths.src.themes}`, + src: ['**', '!**/*.scss', '!**.map'], + dest: paths.staging.themes + }, + { + cwd: `${paths.components}`, + src: ['**'], + dest: `${paths.staging.stagingPath}/${paths.src.javascript}/${paths.composites}` + }, + ], + }), + + copyCustomLibsToStaging: { + fileList: [] + }, + + requireJs: paths => ({ + baseUrl: `${paths.staging.stagingPath}/${paths.src.javascript}`, + name: 'bundle-temp', + optimize: 'none', + out: `${paths.staging.stagingPath}/${paths.src.javascript}/bundle.js` + }), + requireJsEs5: paths => ({ + baseUrl: `${paths.staging.stagingPath}/${paths.src.javascript}`, + name: 'bundle-temp_es5', + optimize: 'none', + out: `${paths.staging.stagingPath}/${paths.src.javascript}/bundle_es5.js` + }), + requireJsComponent: { + optimize: 'none', + separateCSS: false, + buildCSS: false + }, + + sass: paths => ({ + fileList: [ + { + cwd(context) { + return `${paths.src.common}/${paths.src.themes}/${context.theme.name}/${context.theme.platform}`; + }, + src: ['**/*.scss', '!**/_*.scss'], + dest(context) { + return `${paths.staging.themes}/${context.theme.name}/${context.theme.platform}`; + } + }, + { + cwd: `${paths.src.common}/${paths.src.javascript}/${paths.composites}`, + src: ['**/*.scss', '!**/_*.scss'], + dest: `${paths.staging.stagingPath}/${paths.src.javascript}/${paths.composites}` + }, + { + cwd: `${paths.src.common}/${paths.src.typescript}/${paths.composites}`, + src: ['**/*.scss', '!**/_*.scss'], + dest: `${paths.staging.stagingPath}/${paths.src.typescript}/${paths.composites}` + }, + { + cwd: `${paths.components}`, + src: ['**/*.scss', '!**/_*.scss'], + dest: `${paths.staging.stagingPath}/${paths.src.javascript}/${paths.composites}` + } + ], + options: { + precision: 10 + } + }), + + pcss: paths => ({ + fileList: [ + { + cwd(context) { + return `${paths.src.common}/${paths.src.themes}/${context.theme.name}/${context.theme.platform}`; + }, + src: ['**/*.scss', '!**/_*.scss', '!**/*.css'], + dest(context) { + return `${paths.staging.themes}/${context.theme.name}/${context.theme.platform}`; + } + }, + { + cwd: `${paths.src.common}/${paths.src.javascript}/${paths.composites}`, + src: ['**/*.scss', '!**/_*.scss'], + dest: `${paths.staging.stagingPath}/${paths.src.javascript}/${paths.composites}` + }, + { + cwd: `${paths.components}`, + src: ['**/*.scss', '!**/_*.scss'], + dest: `${paths.staging.stagingPath}/${paths.src.javascript}/${paths.composites}` + } + ], + options: { + sourceMap: false, + includePaths: [ + `node_modules/@oracle/oraclejet/dist/pcss/oj/v${util.getJETVersion()}/` + ], + precision: 5 + } + }), + + altasass: paths => ({ + fileList: [ + { + cwd(context) { + return `${context.theme.directory}`; + }, + src: ['**/*.scss', '!**/_*.scss'], + dest(context) { + return `${paths.staging.themes}/${context.theme.name}/${context.theme.platform}`; + }, + rename: (dest, file) => path.join(dest, file.replace('oj-', '')) + } + ], + options: { + precision: 10 + } + }), + + injectTheme: { + startTag: '', + endTag: '' + } + }, + + /* Serve Config */ + serve: { + defaultHybridPlatform: 'browser', + // Serve API overall default options + options: { + livereload: true, + build: true, + port: 8000, + livereloadPort: 35729, + }, + + // Sub task connect default options + connect: paths => ({ + options: { + hostname: '*', + port: 8000, + livereload: true, + base: paths.staging.web, + open: true + } + }), + + // Sub task watch default options + watch: paths => ({ + sourceFiles: + { + files: [ + `${paths.src.common}/${paths.src.styles}/!(libs)/**/*.css`, + `${paths.src.common}/${paths.src.javascript}/!(libs)/**/*.js`, + `${paths.src.common}/${paths.src.javascript}/!(libs)/**/*.json`, + `${paths.src.common}/${paths.src.javascript}/!(libs)/**/*.css`, + `${paths.src.common}/${paths.src.javascript}/{,*/}*.js`, + `${paths.src.common}/${paths.src.typescript}/!(libs)/**/*.ts`, + `${paths.src.common}/${paths.src.typescript}/!(libs)/**/*.json`, + `${paths.src.common}/${paths.src.typescript}/!(libs)/**/*.css`, + `${paths.src.common}/${paths.src.typescript}/{,*/}*.ts`, + `${paths.src.common}/${paths.src.styles}/{,*/}*.css`, + `${paths.src.common}/**/*.html`, + ], + options: + { + livereload: true, + spawn: false, + } + }, + + sass: { + files: [ + `${paths.src.common}/${paths.src.themes}/**/*`, + `${paths.components}/**/*.scss`, + `${paths.src.common}/${paths.src.javascript}/${paths.composites}/**/*.scss`, + ], + options: { + livereload: true, + spawn: false + }, + commands: ['compileSass'] + }, + + themes: { + files: [ + `${paths.staging.themes}/**/*` + ], + options: { + livereload: true, + spawn: false + }, + commands: ['copyThemes'] + }, + }), + }, + + /* Platform paths */ + platforms: (paths) => { + let androidRoot = `${paths.staging.hybrid}/platforms/android/assets/www/`; + const android700Path = `${paths.staging.hybrid}/platforms/android/app/src/main/assets/www/`; + androidRoot = fs.existsSync(androidRoot) ? androidRoot : android700Path; + return { + android: { + root: `${androidRoot}`, + }, + browser: { + root: `${paths.staging.hybrid}/platforms/browser/www/`, + }, + ios: { + root: `${paths.staging.hybrid}/platforms/ios/www/`, + }, + windows: { + root: `${paths.staging.hybrid}/platforms/windows/www/`, + } + }; + } +}; diff --git a/lib/rjsConfigGenerator.js b/lib/rjsConfigGenerator.js index 82eaced..2458eac 100644 --- a/lib/rjsConfigGenerator.js +++ b/lib/rjsConfigGenerator.js @@ -2,398 +2,415 @@ Copyright (c) 2015, 2020, Oracle and/or its affiliates. The Universal Permissive License (UPL), Version 1.0 */ -'use strict'; - -const path = require('path'); -const util = require('./util'); -const CONSTANTS = require('./constants'); -const config = require('./config'); - -function _getPathMappingObj(buildType, masterJson, requirejs, es5) { - const obj = {}; - const useCdn = masterJson.use; - Object.keys(masterJson.libs).forEach((lib) => { - const libPath = _getLibPath(buildType, masterJson.libs[lib], useCdn, masterJson.cdns, - lib, requirejs, es5); - if (libPath) obj[lib] = libPath; - }); - - // fix bug for require css broken link to css-builder.js - let lp = 'libs/require-css/css-builder'; - obj['css-builder'] = path.join(lp, '..', path.basename(lp, path.extname(lp))); - lp = 'libs/require-css/normalize'; - obj.normalize = path.join(lp, '..', path.basename(lp, path.extname(lp))); - if (!requirejs) { - obj['css-builder'] = `'${obj['css-builder']}'`; - obj.normalize = `'${obj.normalize}'`; - } - return obj; -} - -function _getLibPath(buildType, libObj, useCdn, cdnUrls, libName, requirejs, es5) { - // if user defines cdn path and set use to "cdn" in path_mapping.json - // prefer to use cdn path over local path - const buildTypeEs5 = `${buildType}_es5`; - const buildTypeLibObj = (es5 && buildType === 'release' && libObj[buildTypeEs5]) ? buildTypeEs5 : buildType; - if (_isCdnPath(libObj, useCdn, cdnUrls, buildType, libName)) { - // if the lib's cdn reference points to a bundles-config - if (_isCdnBundle(libObj, cdnUrls) && !requirejs) { - return null; - } - - const prefix = typeof cdnUrls[libObj.cdn] === 'object' - ? cdnUrls[libObj.cdn].prefix : cdnUrls[libObj.cdn]; - - const suffix = libObj[buildTypeLibObj].pathSuffix ? libObj[buildTypeLibObj].pathSuffix : '\''; - return `'${prefix}/${libObj[buildType].cdnPath}${suffix}`; - } - - let libPath = _processVersionToken(libName, libObj[buildTypeLibObj].path); - if (path.extname(libPath) === '.js') { - libPath = path.join(libPath, '..', path.basename(libPath, path.extname(libPath))); - } - - libPath = requirejs ? `${libPath}` : `'${libPath}`; - let suffix = libObj[buildTypeLibObj].pathSuffix ? libObj[buildTypeLibObj].pathSuffix : '\''; - if (requirejs && suffix.substring(suffix.length - 1) === "'") { - // remove it - suffix = suffix.substring(0, suffix.length - 1); - } - - libPath += suffix; - - return libPath; -} - -function _isCdnPath(libObj, useCdn, cdnUrls, buildType, libName) { - const pluginLibs = ['text', 'css', 'normalize', 'css-builder', 'ojL10n']; - const pluginLib = (buildType === 'release' && pluginLibs.indexOf(libName) > -1); - return (useCdn === 'cdn' - && !pluginLib - && libObj.cdn !== undefined - && cdnUrls[libObj.cdn] !== undefined - && libObj[buildType].cdnPath !== undefined); -} - -function _isCdnBundle(libObj, cdnUrls) { - const cdnName = (libObj.cdn === '3rdParty') ? 'jet' : libObj.cdn; - return (typeof cdnUrls[cdnName] === 'object' && cdnUrls[cdnName].config && cdnUrls[cdnName].config.length > 0); -} - -function _processVersionToken(libName, libPath) { - const versions = util.getLibVersionsObj(); - return Object.keys(versions).indexOf(libName) !== -1 - ? libPath.replace(CONSTANTS.PATH_MAPPING_VERSION_TOKEN, versions[libName]) : libPath; -} - - -function _getRJsConfig(buildType, masterJson, oldConfig, es5) { - // Update the requirejs optimizer config to skip bundling any cdn resouces - const newConfig = oldConfig; - const useCdn = masterJson.use; - Object.keys(masterJson.libs).forEach((lib) => { - if (_isCdnPath(masterJson.libs[lib], useCdn, masterJson.cdns, buildType, lib)) { - if (newConfig.paths === undefined) { - newConfig.paths = {}; - } - newConfig.paths[lib] = 'empty:'; - } - }); - // bug fix for require-css broken link to css-build.js - if (config.exclude === undefined) { - newConfig.exclude = []; - } - newConfig.exclude.push('css-builder'); - newConfig.exclude.push('normalize'); - if (es5) { - newConfig.exclude.push('corejs'); - newConfig.exclude.push('regenerator-runtime'); - } - - return newConfig; -} - -/** - * ## _getCcaRJsConfig - * @private - * @param {String} buildType - * @param {Object} masterJson - * @param {Object} config - * @returns {Object} - */ -function _getCcaRJsConfig(buildType, masterJson, oldConfig) { - // Update the requirejs optimizer config to skip bundling any minified cca components - const newConfig = oldConfig; - const dependenciesObj = util.readJsonAndReturnObject(`./${CONSTANTS.ORACLE_JET_CONFIG_JSON}`).dependencies; - - // Update build config with reference components - const componentList = util.getDirectories(`./${CONSTANTS.JET_COMPONENTS_DIRECTORY}`); - componentList.forEach((component) => { - const componentDirPath = `./${CONSTANTS.JET_COMPONENTS_DIRECTORY}/${component}/${CONSTANTS.JET_COMPONENT_JSON}`; - const componentJson = util.readJsonAndReturnObject(`${componentDirPath}`); - if (componentJson.type === 'reference') { - // Should cdn be used? && is paths.cdn property defined? - if (masterJson.use === 'cdn' && componentJson.cdn) { - // Is either release or debug url available? - if (componentJson.cdn.min || componentJson.cdn.debug) { - newConfig.paths[(componentJson.paths && componentJson.paths.name) || component] = 'empty:'; - } - } - } - }); - - // bug fix for require-css broken link to css-build.js - if (newConfig.exclude === undefined) { - newConfig.exclude = []; - } - newConfig.exclude.push('css-builder'); - newConfig.exclude.push('normalize'); - - if (!dependenciesObj) return newConfig; - Object.keys(dependenciesObj).forEach((dependency) => { - const version = _isPack(dependenciesObj[dependency]) ? - dependenciesObj[dependency].version : dependenciesObj[dependency]; - if (buildType === 'release' && _isMinified(dependency, version)) newConfig.paths[dependency] = 'empty:'; - }); - return newConfig; -} - -function _constructComponentPath(retObj, npmPackageName) { - let finalPath = ''; - if (!retObj.npmPckgInitFileRelativePath) return finalPath; - if (retObj.npm) { - // Get only the file name - const npmPckgInitFileNameArray = retObj.npmPckgInitFileRelativePath.split('/'); - let npmPckgInitFileName = npmPckgInitFileNameArray[npmPckgInitFileNameArray.length - 1]; - npmPckgInitFileName = npmPckgInitFileName.replace('.js', ''); - finalPath = `libs/${npmPackageName}/${npmPckgInitFileName}`; - } else { - finalPath = retObj.npmPckgInitFileRelativePath; - } - return finalPath; -} - -/** - * ## _getCcaPathMapping - * @private - * @param {String} buildType - * @returns {Object} - */ -function _getCcaPathMapping(buildType, requirejs) { - const pathMappingObj = {}; - const dependenciesObj = util.readJsonAndReturnObject(`./${CONSTANTS.ORACLE_JET_CONFIG_JSON}`).components; - - if (!dependenciesObj) return pathMappingObj; - - Object.keys(dependenciesObj).forEach((dependency) => { - let dependencyPath = `${CONSTANTS.JET_COMPOSITE_DIRECTORY}/${dependency}`; - const dependencyComponentJsonPath = `./${CONSTANTS.JET_COMPONENTS_DIRECTORY}/${dependency}/${CONSTANTS.JET_COMPONENT_JSON}`; - const dependencyComponentJson = util.readJsonAndReturnObject(dependencyComponentJsonPath); - if (dependencyComponentJson.type === 'reference') { - const npmPackageName = `${dependencyComponentJson.package}`; - const retObj = util.getNpmPckgInitFileRelativePath(dependencyComponentJson, buildType); - const finalPath = _constructComponentPath(retObj, npmPackageName); - // - // For reference components, the pathMappingObject property is set to: - // (a) paths.name (if it exists), otherwise (b) the package name. - // - pathMappingObj[(dependencyComponentJson.paths && dependencyComponentJson.paths.name) || - npmPackageName] = requirejs ? finalPath : `'${finalPath}'`; // eslint-disable-line - } else { - const version = _getValidVersion(dependencyComponentJson.version); - dependencyPath += `/${version}`; - if (buildType === 'release' && _isMinified(dependency, version)) { - dependencyPath += '/min'; - } - pathMappingObj[dependency] = requirejs ? dependencyPath : `'${dependencyPath}'`; - } - }); - return pathMappingObj; -} - -/** - * ## _getReferencePathMapping - * @private - * @param {Object} dependency - * @param {Boolean} requirejs - * @returns {Object} - * - * Return a pathMappingObj that contains all reference components. - * The approach used to discover the reference components is to traverse - * the JET_COMPONENTS_DIRECTORY. - * This approach ensures that all reference components are discovered. - * - * For example, the oj-sample-calendar component will pull in two reference components, - * oj-ref-calendar and oj-ref-moment. - * These two reference components will be returned in the pathMappingObj and - * subsequently injected into the main.js pathMapping. - * - * "fullcalendar":"libs/fullcalendar/dist", - * "moment":"libs/moment/moment.min" - * -*/ -function _getReferencePathMapping(buildType, requirejs) { - const pathMappingObj = {}; - const componentList = util.getDirectories(`./${CONSTANTS.JET_COMPONENTS_DIRECTORY}`); - componentList.forEach((component) => { - const componentDirPath = `./${CONSTANTS.JET_COMPONENTS_DIRECTORY}/${component}/${CONSTANTS.JET_COMPONENT_JSON}`; - const componentJson = util.readJsonAndReturnObject(`${componentDirPath}`); - if (componentJson.type === 'reference') { - const npmPathOrPackageName = - (componentJson.paths && componentJson.paths.name) || componentJson.package; - const retObj = util.getNpmPckgInitFileRelativePath(componentJson, buildType); - const finalPath = _constructComponentPath(retObj, npmPathOrPackageName); - pathMappingObj[npmPathOrPackageName] = requirejs ? finalPath : `'${finalPath}'`; - } - }); - return pathMappingObj; -} - -function _getValidVersion(version) { - return !isNaN(version.charAt(0)) ? version : version.substring(1); -} - -/** - * ## _getLocalCcaPathMapping - * @private - * @returns {Object} - */ -function _getLocalCcaPathMapping(buildType, requirejs, scriptsFolder) { - const pathMappingObj = {}; - const ccaVersionObj = config('componentVersionObj') || {}; - const basePath = path.join( - config('paths').src.common, - scriptsFolder, - config('paths').composites - ); - const components = _getLocalComponentArray(scriptsFolder); - components.forEach((componentDir) => { - const componentPath = path.join(componentDir, 'component.json'); - const componentJson = util.readJsonAndReturnObject(path.join(basePath, componentPath)); - const version = Object.prototype.hasOwnProperty.call(componentJson, 'version') ? - componentJson.version : '1.0.0'; - ccaVersionObj[componentJson.name] = version; - - if (!Object.prototype.hasOwnProperty.call(componentJson, 'pack')) { - pathMappingObj[componentJson.name] = path.join(config('paths').composites, componentPath, '..', version); - pathMappingObj[componentJson.name] = requirejs ? pathMappingObj[componentJson.name] : `'${pathMappingObj[componentJson.name]}'`; - } else if (!Object.prototype.hasOwnProperty.call(pathMappingObj, componentJson.pack)) { - // - // Note: this may be a legacy code path. - // This conditional path is never followed, - // even when testing the oj-input-url exchange component, - // which has a "pack" property in a child componentJson. - // - // This condition would only followed if there is a "pack" PROPERTY in the top-level - // componentJson, e.g., when componentJson contains { ..., "pack": "somepackname", ...} - // And the common case for packs sets "type" property to "pack": { ..., "type": "pack", ...} - // - // When we test the code path of a component that has a "pack" attribute, we find that - // this condition is not followed. Below are the details of this test. - // The oj-input-url component has (oj-ext/input-url/component.json). - // "pack": "oj-ext" - // However the top level component.json (oj-ext/component.json) has - // "type": "pack" - // But since this code block examines the top-level componentJson for the "pack" property, - // this code block is never followed. - // - pathMappingObj[componentJson.pack] = path.join(config('paths').composites, componentPath, '..', '..', version); - pathMappingObj[componentJson.pack] = requirejs ? pathMappingObj[componentJson.pack] : `'${pathMappingObj[componentJson.pack]}'`; - } - }); - config('componentVersionObj', ccaVersionObj); - return pathMappingObj; -} - -function _getLocalComponentArray(scriptsFolder) { - const basePath = path.join( - config('paths').src.common, - scriptsFolder, - config('paths').composites - ); - const localCca = []; - if (util.fsExistsSync(basePath)) { - const dirList = util.getDirectories(basePath); - dirList.forEach((dir) => { - const componentPath = path.join(basePath, dir, 'component.json'); - if (util.fsExistsSync(componentPath)) { - const componentObj = util.readJsonAndReturnObject(componentPath); - if (Object.prototype.hasOwnProperty.call(componentObj, 'name') && componentObj.name === dir) localCca.push(dir); - } - }); - } - - return localCca; -} - -/** - * ## _isPack - * @private - * @param {Object} dependency - * @returns {Boolean} - */ -function _isPack(dependency) { - return Object.prototype.hasOwnProperty.call(dependency, 'components'); -} - -/** - * ## _isMinified - * @public - * @param {Object} dependency - * @returns {Boolean} - */ -function _isMinified(dependency, version) { - // check jet_components and the src/js/composites directories - const exchangePath = path.join(CONSTANTS.JET_COMPONENTS_DIRECTORY, dependency, version, 'min'); - const srcPath = path.join(config('paths').src.common, config('paths').src.javascript, - config('paths').composites, dependency, version, 'min'); - return (util.fsExistsSync(exchangePath) || util.fsExistsSync(srcPath)); -} - -module.exports = { - getPathsMapping: function _getPathsMapping(context, requirejs, es5) { - const masterJson = util.readPathMappingJson(); - const buildType = context.buildType === 'release' ? 'release' : 'debug'; - const pathMappingObj = - Object.assign( - {}, - _getPathMappingObj(buildType, masterJson, requirejs, es5), - _getCcaPathMapping(buildType, requirejs), - _getReferencePathMapping(buildType, requirejs), - _getLocalCcaPathMapping(buildType, requirejs, config('paths').src.javascript), - _getLocalCcaPathMapping(buildType, requirejs, config('paths').src.typescript) - ); - return pathMappingObj; - }, - - getMasterPathsMapping: function _getMasterPathsMapping(context) { - const masterJson = util.readPathMappingJson(); - const buildType = context.buildType === 'release' ? 'release' : 'debug'; - const pathMappingObj = _getPathMappingObj(buildType, masterJson, true, false); - // prepend the relative directory position for a component. - Object.keys(pathMappingObj).forEach((lib) => { - pathMappingObj[lib] = path.join('../../../../', pathMappingObj[lib]); - }); - return pathMappingObj; - }, - - getMasterPathsMappingSingleton: function _getMasterPathsMappingSingleton(context) { - const masterJson = util.readPathMappingJson(); - const buildType = context.buildType === 'release' ? 'release' : 'debug'; - const pathMappingObj = _getPathMappingObj(buildType, masterJson, true, false); - // prepend the relative directory position for a component. - Object.keys(pathMappingObj).forEach((lib) => { - pathMappingObj[lib] = path.join('../../../', pathMappingObj[lib]); - }); - return pathMappingObj; - }, - - updateRJsOptimizerConfig: function _updateRJsOptimizer(context, es5) { - const masterJson = util.readPathMappingJson(); - const rConfig = es5 ? context.opts.requireJsEs5 : context.opts.requireJs; - - const buildType = context.buildType === 'release' ? 'release' : 'debug'; - const rjsConfig = _getRJsConfig(buildType, masterJson, rConfig, es5); - return _getCcaRJsConfig(buildType, masterJson, rjsConfig); - } -}; +'use strict'; + +const path = require('path'); +const util = require('./util'); +const CONSTANTS = require('./constants'); +const config = require('./config'); + +function _getPathMappingObj(buildType, masterJson, requirejs, es5) { + const obj = {}; + const useCdn = masterJson.use; + Object.keys(masterJson.libs).forEach((lib) => { + const libPath = _getLibPath(buildType, masterJson.libs[lib], useCdn, masterJson.cdns, + lib, requirejs, es5); + if (libPath) obj[lib] = libPath; + }); + + // fix bug for require css broken link to css-builder.js + let lp = 'libs/require-css/css-builder'; + obj['css-builder'] = path.join(lp, '..', path.basename(lp, path.extname(lp))); + lp = 'libs/require-css/normalize'; + obj.normalize = path.join(lp, '..', path.basename(lp, path.extname(lp))); + if (!requirejs) { + obj['css-builder'] = `'${obj['css-builder']}'`; + obj.normalize = `'${obj.normalize}'`; + } + return obj; +} + +function _getLibPath(buildType, libObj, useCdn, cdnUrls, libName, requirejs, es5) { + // if user defines cdn path and set use to "cdn" in path_mapping.json + // prefer to use cdn path over local path + const buildTypeEs5 = `${buildType}_es5`; + const buildTypeLibObj = (es5 && buildType === 'release' && libObj[buildTypeEs5]) ? buildTypeEs5 : buildType; + if (_isCdnPath(libObj, useCdn, cdnUrls, buildType, libName)) { + // if the lib's cdn reference points to a bundles-config + if (_isCdnBundle(libObj, cdnUrls) && !requirejs) { + return null; + } + + const prefix = typeof cdnUrls[libObj.cdn] === 'object' + ? cdnUrls[libObj.cdn].prefix : cdnUrls[libObj.cdn]; + + const suffix = libObj[buildTypeLibObj].pathSuffix ? libObj[buildTypeLibObj].pathSuffix : '\''; + return `'${prefix}/${libObj[buildType].cdnPath}${suffix}`; + } + + let libPath = _processVersionToken(libName, libObj[buildTypeLibObj].path); + if (path.extname(libPath) === '.js') { + libPath = path.join(libPath, '..', path.basename(libPath, path.extname(libPath))); + } + + libPath = requirejs ? `${libPath}` : `'${libPath}`; + let suffix = libObj[buildTypeLibObj].pathSuffix ? libObj[buildTypeLibObj].pathSuffix : '\''; + if (requirejs && suffix.substring(suffix.length - 1) === "'") { + // remove it + suffix = suffix.substring(0, suffix.length - 1); + } + + libPath += suffix; + + return libPath; +} + +function _isCdnPath(libObj, useCdn, cdnUrls, buildType, libName) { + const pluginLibs = ['text', 'css', 'normalize', 'css-builder', 'ojL10n']; + const pluginLib = (buildType === 'release' && pluginLibs.indexOf(libName) > -1); + return (useCdn === 'cdn' + && !pluginLib + && libObj.cdn !== undefined + && cdnUrls[libObj.cdn] !== undefined + && libObj[buildType].cdnPath !== undefined); +} + +function _isCdnBundle(libObj, cdnUrls) { + const cdnName = (libObj.cdn === '3rdParty') ? 'jet' : libObj.cdn; + return (typeof cdnUrls[cdnName] === 'object' && cdnUrls[cdnName].config && cdnUrls[cdnName].config.length > 0); +} + +function _processVersionToken(libName, libPath) { + const versions = util.getLibVersionsObj(); + return Object.keys(versions).indexOf(libName) !== -1 + ? libPath.replace(CONSTANTS.PATH_MAPPING_VERSION_TOKEN, versions[libName]) : libPath; +} + + +function _getRJsConfig(buildType, masterJson, oldConfig, es5) { + // Update the requirejs optimizer config to skip bundling any cdn resouces + const newConfig = oldConfig; + const useCdn = masterJson.use; + Object.keys(masterJson.libs).forEach((lib) => { + if (_isCdnPath(masterJson.libs[lib], useCdn, masterJson.cdns, buildType, lib)) { + if (newConfig.paths === undefined) { + newConfig.paths = {}; + } + newConfig.paths[lib] = 'empty:'; + } + }); + // bug fix for require-css broken link to css-build.js + if (config.exclude === undefined) { + newConfig.exclude = []; + } + newConfig.exclude.push('css-builder'); + newConfig.exclude.push('normalize'); + if (es5) { + newConfig.exclude.push('corejs'); + newConfig.exclude.push('regenerator-runtime'); + } + + return newConfig; +} + +/** + * ## _getCcaRJsConfig + * @private + * @param {String} buildType + * @param {Object} masterJson + * @param {Object} config + * @returns {Object} + */ +function _getCcaRJsConfig(buildType, masterJson, oldConfig) { + // Update the requirejs optimizer config to skip bundling any minified cca components + const newConfig = oldConfig; + const dependenciesObj = util.readJsonAndReturnObject(`./${CONSTANTS.ORACLE_JET_CONFIG_JSON}`).dependencies; + + // Update build config with reference components + const componentList = util.getDirectories(`./${CONSTANTS.JET_COMPONENTS_DIRECTORY}`); + componentList.forEach((component) => { + const componentDirPath = `./${CONSTANTS.JET_COMPONENTS_DIRECTORY}/${component}/${CONSTANTS.JET_COMPONENT_JSON}`; + const componentJson = util.readJsonAndReturnObject(`${componentDirPath}`); + if (componentJson.type === 'reference') { + // Should cdn be used? && is paths.cdn property defined? + if (masterJson.use === 'cdn' && componentJson.cdn) { + // Is either release or debug url available? + if (componentJson.cdn.min || componentJson.cdn.debug) { + newConfig.paths[(componentJson.paths && componentJson.paths.name) || component] = 'empty:'; + } + } + } + }); + + // bug fix for require-css broken link to css-build.js + if (newConfig.exclude === undefined) { + newConfig.exclude = []; + } + newConfig.exclude.push('css-builder'); + newConfig.exclude.push('normalize'); + + if (!dependenciesObj) return newConfig; + Object.keys(dependenciesObj).forEach((dependency) => { + const version = _isPack(dependenciesObj[dependency]) ? + dependenciesObj[dependency].version : dependenciesObj[dependency]; + if (buildType === 'release' && _isMinified(dependency, version)) newConfig.paths[dependency] = 'empty:'; + }); + return newConfig; +} + +function _constructComponentPath(retObj, npmPackageName) { + let finalPath = ''; + if (!retObj.npmPckgInitFileRelativePath) return finalPath; + if (retObj.npm) { + // Get only the file name + const npmPckgInitFileNameArray = retObj.npmPckgInitFileRelativePath.split('/'); + let npmPckgInitFileName = npmPckgInitFileNameArray[npmPckgInitFileNameArray.length - 1]; + npmPckgInitFileName = npmPckgInitFileName.replace('.js', ''); + finalPath = `libs/${npmPackageName}/${npmPckgInitFileName}`; + } else { + finalPath = retObj.npmPckgInitFileRelativePath; + } + return finalPath; +} + + +/** + * ## _getReferencePathInternal + * @private + * @param {String} buildType + * @param {Boolean} requirejs + * @param {Object} dependencyComponentJson + * @returns {Object} + * + * Assign the proper reference paths, returning a pathMappingObj. + * For reference components, the pathMappingObject property is set to: + * (a) paths.name (if it exists), otherwise (b) the package name. + */ +function _getReferencePathInternal(buildType, requirejs, dependencyComponentJson) { + const pathMappingObj = {}; + const npmPackageName = dependencyComponentJson.package; + const npmPathName = (dependencyComponentJson.paths && dependencyComponentJson.paths.name) || + npmPackageName; + const retObj = util.getNpmPckgInitFileRelativePath(dependencyComponentJson, buildType); + const finalPath = _constructComponentPath(retObj, npmPackageName); + pathMappingObj[npmPathName] = requirejs ? finalPath : `'${finalPath}'`; // eslint-disable-line + return pathMappingObj; +} + +/** + * ## _getCcaPathMapping + * @private + * @param {String} buildType + * @returns {Object} + */ +function _getCcaPathMapping(buildType, requirejs) { + let pathMappingObj = {}; + const dependenciesObj = util.readJsonAndReturnObject(`./${CONSTANTS.ORACLE_JET_CONFIG_JSON}`).components; + + if (!dependenciesObj) return pathMappingObj; + + Object.keys(dependenciesObj).forEach((dependency) => { + let dependencyPath = `${CONSTANTS.JET_COMPOSITE_DIRECTORY}/${dependency}`; + const dependencyComponentJsonPath = `./${CONSTANTS.JET_COMPONENTS_DIRECTORY}/${dependency}/${CONSTANTS.JET_COMPONENT_JSON}`; + const dependencyComponentJson = util.readJsonAndReturnObject(dependencyComponentJsonPath); + if (dependencyComponentJson.type === 'reference') { + pathMappingObj = _getReferencePathInternal(buildType, requirejs, dependencyComponentJson); + } else { + const version = _getValidVersion(dependencyComponentJson.version); + dependencyPath += `/${version}`; + if (buildType === 'release' && _isMinified(dependency, version)) { + dependencyPath += '/min'; + } + pathMappingObj[dependency] = requirejs ? dependencyPath : `'${dependencyPath}'`; + } + }); + return pathMappingObj; +} + +/** + * ## _getReferencePathMapping + * @private + * @param {Object} dependency + * @param {Boolean} requirejs + * @returns {Object} + * + * Return a pathMappingObj that contains all reference components. + * The approach used to discover the reference components is to traverse + * the JET_COMPONENTS_DIRECTORY. + * This approach ensures that all reference components are discovered. + * + * For example, the oj-sample-calendar component will pull in two reference components, + * oj-ref-calendar and oj-ref-moment. + * These two reference components will be returned in the pathMappingObj and + * subsequently injected into the main.js pathMapping. + * + * "fullcalendar":"libs/fullcalendar/dist", + * "moment":"libs/moment/moment.min" + * +*/ +function _getReferencePathMapping(buildType, requirejs) { + const pathMappingObj = {}; + const componentList = util.getDirectories(`./${CONSTANTS.JET_COMPONENTS_DIRECTORY}`); + componentList.forEach((component) => { + const componentDirPath = `./${CONSTANTS.JET_COMPONENTS_DIRECTORY}/${component}/${CONSTANTS.JET_COMPONENT_JSON}`; + const componentJson = util.readJsonAndReturnObject(`${componentDirPath}`); + if (componentJson.type === 'reference') { + const npmPackageName = componentJson.package; + // For reference components, the pathMappingObject property is set to: + // (a) paths.name (if it exists), otherwise (b) the package name. + const npmPathName = (componentJson.paths && componentJson.paths.name) || npmPackageName; + const retObj = util.getNpmPckgInitFileRelativePath(componentJson, buildType); + const finalPath = _constructComponentPath(retObj, npmPackageName); + pathMappingObj[npmPathName] = requirejs ? finalPath : `'${finalPath}'`; + } + }); + return pathMappingObj; +} + +function _getValidVersion(version) { + return !isNaN(version.charAt(0)) ? version : version.substring(1); +} + +/** + * ## _getLocalCcaPathMapping + * @private + * @returns {Object} + */ +function _getLocalCcaPathMapping(buildType, requirejs, scriptsFolder) { + const pathMappingObj = {}; + const ccaVersionObj = config('componentVersionObj') || {}; + const basePath = path.join( + config('paths').src.common, + scriptsFolder, + config('paths').composites + ); + const components = _getLocalComponentArray(scriptsFolder); + components.forEach((componentDir) => { + const componentPath = path.join(componentDir, 'component.json'); + const componentJson = util.readJsonAndReturnObject(path.join(basePath, componentPath)); + const version = Object.prototype.hasOwnProperty.call(componentJson, 'version') ? + componentJson.version : '1.0.0'; + ccaVersionObj[componentJson.name] = version; + // + // (We only add singleton components and the 'top-level' pack (type: 'pack')) + // + // The following are NOT added: + // - members of a pack (will have a pack property, e.b. pack: packName) + // - reference components (type: reference) + // - resource components (type: resource) + // + if (!Object.prototype.hasOwnProperty.call(componentJson, 'pack') && + !(Object.prototype.hasOwnProperty.call(componentJson, 'type') && + ((componentJson.type === 'reference' || componentJson.type === 'resource')))) { + pathMappingObj[componentJson.name] = path.join(config('paths').composites, componentPath, '..', version); + // target minified directory for release builds. + if (buildType === 'release') { + pathMappingObj[componentJson.name] = path.join(pathMappingObj[componentJson.name], 'min'); + } + pathMappingObj[componentJson.name] = requirejs ? pathMappingObj[componentJson.name] : `'${pathMappingObj[componentJson.name]}'`; + } + }); + config('componentVersionObj', ccaVersionObj); + return pathMappingObj; +} + +function _getLocalComponentArray(scriptsFolder) { + const basePath = path.join( + config('paths').src.common, + scriptsFolder, + config('paths').composites + ); + const localCca = []; + if (util.fsExistsSync(basePath)) { + const dirList = util.getDirectories(basePath); + dirList.forEach((dir) => { + const componentPath = path.join(basePath, dir, 'component.json'); + if (util.fsExistsSync(componentPath)) { + const componentObj = util.readJsonAndReturnObject(componentPath); + if (Object.prototype.hasOwnProperty.call(componentObj, 'name') && componentObj.name === dir) localCca.push(dir); + } + }); + } + + return localCca; +} + +/** + * ## _isPack + * @private + * @param {Object} dependency + * @returns {Boolean} + */ +function _isPack(dependency) { + return Object.prototype.hasOwnProperty.call(dependency, 'components'); +} + +/** + * ## _isMinified + * @public + * @param {Object} dependency + * @returns {Boolean} + */ +function _isMinified(dependency, version) { + // check jet_components and the src/js/composites directories + const exchangePath = path.join(CONSTANTS.JET_COMPONENTS_DIRECTORY, dependency, version, 'min'); + const srcPath = path.join(config('paths').src.common, config('paths').src.javascript, + config('paths').composites, dependency, version, 'min'); + return (util.fsExistsSync(exchangePath) || util.fsExistsSync(srcPath)); +} + +module.exports = { + getPathsMapping: function _getPathsMapping(context, requirejs, es5) { + const masterJson = util.readPathMappingJson(); + const buildType = context.buildType === 'release' ? 'release' : 'debug'; + const pathMappingObj = + Object.assign( + {}, + _getPathMappingObj(buildType, masterJson, requirejs, es5), + _getCcaPathMapping(buildType, requirejs), + _getReferencePathMapping(buildType, requirejs), + _getLocalCcaPathMapping(buildType, requirejs, config('paths').src.javascript), + _getLocalCcaPathMapping(buildType, requirejs, config('paths').src.typescript) + ); + return pathMappingObj; + }, + + getMasterPathsMapping: function _getMasterPathsMapping(context) { + const masterJson = util.readPathMappingJson(); + const buildType = context.buildType === 'release' ? 'release' : 'debug'; + const pathMappingObj = _getPathMappingObj(buildType, masterJson, true, false); + // prepend the relative directory position for a component. + Object.keys(pathMappingObj).forEach((lib) => { + pathMappingObj[lib] = path.join('../../../../', pathMappingObj[lib]); + }); + return pathMappingObj; + }, + + getMasterPathsMappingSingleton: function _getMasterPathsMappingSingleton(context) { + const masterJson = util.readPathMappingJson(); + const buildType = context.buildType === 'release' ? 'release' : 'debug'; + const pathMappingObj = _getPathMappingObj(buildType, masterJson, true, false); + // prepend the relative directory position for a component. + Object.keys(pathMappingObj).forEach((lib) => { + pathMappingObj[lib] = path.join('../../../', pathMappingObj[lib]); + }); + return pathMappingObj; + }, + + getReferencePathMappingExternal: function _getReferencePathMappingExternal(buildType, requirejs) { + return _getReferencePathMapping(buildType, requirejs); + }, + + getReferencePath: function _getReferencePath(buildType, requirejs, dependencyComponentJson) { + return _getReferencePathInternal(buildType, requirejs, dependencyComponentJson); + }, + + updateRJsOptimizerConfig: function _updateRJsOptimizer(context, es5) { + const masterJson = util.readPathMappingJson(); + const rConfig = es5 ? context.opts.requireJsEs5 : context.opts.requireJs; + + const buildType = context.buildType === 'release' ? 'release' : 'debug'; + const rjsConfig = _getRJsConfig(buildType, masterJson, rConfig, es5); + return _getCcaRJsConfig(buildType, masterJson, rjsConfig); + } +}; diff --git a/lib/serveWebFileChangeHandler.js b/lib/serveWebFileChangeHandler.js index 4eb9385..0158895 100644 --- a/lib/serveWebFileChangeHandler.js +++ b/lib/serveWebFileChangeHandler.js @@ -2,188 +2,191 @@ Copyright (c) 2015, 2020, Oracle and/or its affiliates. The Universal Permissive License (UPL), Version 1.0 */ -'use strict'; - -/** - * # Dependencies - */ - -/* 3rd party */ -const fs = require('fs-extra'); - -/* Oracle */ -const buildCommon = require('./buildCommon'); -const config = require('./config'); -const util = require('./util'); -const path = require('path'); -const CONSTANTS = require('./constants'); - -/** - * # serveWeb file change procedure - * - * @public - * @param {string} filePath - Path to the file - * @param {object} buildContext - Build configurations - * @returns {Promise} - */ - -module.exports = function (filePath, buildContext) { - return new Promise((resolve) => { - const pathComponents = util.getPathComponents(filePath); - const defaultDest = path.join( - pathComponents.beg, - config('paths').staging.web, - pathComponents.end - ); - let buildPromise = Promise.resolve(); - let customDest; - if (_isFileOverridden(pathComponents)) { - console.log(`Overridden file not changed: ${filePath}`); - return; - } - /* Copies file over for the watch events */ - if (_isIndexHtml(filePath)) { - fs.copySync(filePath, defaultDest); - buildPromise = buildCommon.injectTheme(buildContext) - .then(buildCommon.injectLocalhostCspRule) - .then(buildCommon.injectCdnBundleScript) - .catch((err) => { - console.log(err); - }); - } else if (_isMainJs(filePath)) { - fs.copySync(filePath, defaultDest); - buildPromise = buildCommon.injectPaths(buildContext) - .catch((err) => { - console.log(err); - }); - } else if (util.isPathCCA(pathComponents.end)) { - let component = util.getCCANameFromPath(pathComponents.end); - let version = config('componentVersionObj')[component]; - // If the simple name lookup fails, then we check to see if we have a jetpack component. - if (version === undefined) { - component = util.getJetpackCompNameFromConfigObj(config('componentVersionObj'), pathComponents.end); - if (component !== null) { - version = config('componentVersionObj')[component]; - } - } - const basePathArray = pathComponents.end.split(path.sep); - let basePath = ''; - const startIndex = component ? basePathArray.indexOf(component) + 1 : - basePathArray.indexOf(CONSTANTS.JET_COMPOSITES_DIRECTORY) + 2; - for (let i = startIndex; i < basePathArray.length; i++) { - basePath = path.join(basePath, basePathArray[i]); - } - const isTypescriptComponent = util.isTypescriptComponent({ component }); - customDest = path.join( - pathComponents.beg, - config('paths').staging.web, - isTypescriptComponent ? config('paths').src.typescript : config('paths').src.javascript, - config('paths').composites, - component, - version, - basePath - ); - fs.copySync(filePath, customDest); - if (isTypescriptComponent) { - buildPromise = buildCommon.compileComponentTypescript({ - context: { - ...buildContext, - serving: true - }, - component, - version - }); - } - } else if (util.isTypescriptFile(pathComponents)) { - fs.copySync(filePath, defaultDest); - buildPromise = buildCommon.typescript({ ...buildContext, serving: true }); - } else if (_isUnderTsFolder(pathComponents.end)) { - customDest = path.join( - pathComponents.beg, - config('paths').staging.web, - _replaceTsWithJs(pathComponents.end) - ); - fs.copySync(filePath, customDest); - } else { - fs.copySync(filePath, defaultDest); - } - buildPromise.then(() => resolve()); - }); -}; - -/** - * ## _isIndexHtml - * - * @private - * @param {string} filePath - * @returns {boolean} - */ -function _isIndexHtml(filePath) { - return path.basename(filePath) === 'index.html'; -} - -/** - * ## _isMainJs - * - * @private - * @param {string} filePath - * @returns {boolean} - */ -function _isMainJs(filePath) { - return path.basename(filePath) === 'main.js'; -} - -/** - * ## _isUnderTsFolder - * - * @private - * @param {string} filePath - * @returns {boolean} - */ -function _isUnderTsFolder(filePath) { - return filePath.startsWith(_getTsFolderToken()); -} - -/** - * ## _getTsFolderToken - * - * @private - * @returns {boolean} - */ -function _getTsFolderToken() { - return `${path.sep}${config('paths').src.typescript}${path.sep}`; -} - -/** - * ## _replaceTsWithJs - * - * @private - * @returns {boolean} - */ -function _replaceTsWithJs(filePath) { - return path.join( - 'js', - filePath.slice(_getTsFolderToken().length) - ); -} - -/** - * # _isFileOverridden - * Checks if the source file modified under livereload is potentially overridden - * in the src-web directory in which case the change should not be propagated - * to the served content. - * - * @private - * @param {object} pathComponents - file path specification - * @returns {boolean} - */ -function _isFileOverridden(pathComponents) { - const srcDir = pathComponents.mid; - - if (srcDir === config('paths').src.web) { - return false; - } - const filePath = pathComponents.beg + config('paths').src.web + pathComponents.end; - - return util.fsExistsSync(filePath); -} +'use strict'; + +/** + * # Dependencies + */ + +/* 3rd party */ +const fs = require('fs-extra'); + +/* Oracle */ +const buildCommon = require('./buildCommon'); +const config = require('./config'); +const util = require('./util'); +const path = require('path'); +const CONSTANTS = require('./constants'); + +/** + * # serveWeb file change procedure + * + * @public + * @param {string} filePath - Path to the file + * @param {object} buildContext - Build configurations + * @returns {Promise} + */ + +module.exports = function (filePath, buildContext) { + return new Promise((resolve) => { + const pathComponents = util.getPathComponents(filePath); + const defaultDest = path.join( + pathComponents.beg, + config('paths').staging.web, + pathComponents.end + ); + let buildPromise = Promise.resolve(); + let customDest; + if (_isFileOverridden(pathComponents)) { + console.log(`Overridden file not changed: ${filePath}`); + return; + } + /* Copies file over for the watch events */ + if (_isIndexHtml(filePath)) { + fs.copySync(filePath, defaultDest); + buildPromise = buildCommon.injectTheme(buildContext) + .then(buildCommon.injectLocalhostCspRule) + .then(buildCommon.injectCdnBundleScript) + .catch((err) => { + console.log(err); + }); + } else if (_isMainJs(filePath)) { + fs.copySync(filePath, defaultDest); + buildPromise = buildCommon.injectPaths(buildContext) + .catch((err) => { + console.log(err); + }); + } else if (util.isPathCCA(pathComponents.end)) { + let component = util.getCCANameFromPath(pathComponents.end); + let version = config('componentVersionObj')[component]; + // If the simple name lookup fails, then we check to see if we have a jetpack component. + if (version === undefined) { + component = util.getJetpackCompNameFromConfigObj(config('componentVersionObj'), pathComponents.end); + if (component !== null) { + version = config('componentVersionObj')[component]; + } + } + const basePathArray = pathComponents.end.split(path.sep); + let basePath = ''; + const startIndex = component ? basePathArray.indexOf(component) + 1 : + basePathArray.indexOf(CONSTANTS.JET_COMPOSITES_DIRECTORY) + 2; + for (let i = startIndex; i < basePathArray.length; i++) { + basePath = path.join(basePath, basePathArray[i]); + } + const isTypescriptComponent = util.isTypescriptComponent({ component }); + customDest = path.join( + pathComponents.beg, + config('paths').staging.web, + isTypescriptComponent ? config('paths').src.typescript : config('paths').src.javascript, + config('paths').composites, + component, + version, + basePath + ); + fs.copySync(filePath, customDest); + if (isTypescriptComponent) { + buildPromise = buildCommon.compileComponentTypescript({ + context: { + ...buildContext, + serving: true + }, + component, + version + }); + } + } else if (util.isTypescriptFile(pathComponents)) { + fs.copySync(filePath, defaultDest); + buildPromise = buildCommon.typescript({ ...buildContext, serving: true }); + } else if (_isUnderTsFolder(pathComponents.end)) { + // copy to web/ts to prevent override during post-typescript copy + fs.copySync(filePath, defaultDest); + customDest = path.join( + pathComponents.beg, + config('paths').staging.web, + _replaceTsWithJs(pathComponents.end) + ); + // copy to web/js since post-typescript copy not run + fs.copySync(filePath, customDest); + } else { + fs.copySync(filePath, defaultDest); + } + buildPromise.then(() => resolve()); + }); +}; + +/** + * ## _isIndexHtml + * + * @private + * @param {string} filePath + * @returns {boolean} + */ +function _isIndexHtml(filePath) { + return path.basename(filePath) === 'index.html'; +} + +/** + * ## _isMainJs + * + * @private + * @param {string} filePath + * @returns {boolean} + */ +function _isMainJs(filePath) { + return path.basename(filePath) === 'main.js'; +} + +/** + * ## _isUnderTsFolder + * + * @private + * @param {string} filePath + * @returns {boolean} + */ +function _isUnderTsFolder(filePath) { + return filePath.startsWith(_getTsFolderToken()); +} + +/** + * ## _getTsFolderToken + * + * @private + * @returns {boolean} + */ +function _getTsFolderToken() { + return `${path.sep}${config('paths').src.typescript}${path.sep}`; +} + +/** + * ## _replaceTsWithJs + * + * @private + * @returns {boolean} + */ +function _replaceTsWithJs(filePath) { + return path.join( + 'js', + filePath.slice(_getTsFolderToken().length) + ); +} + +/** + * # _isFileOverridden + * Checks if the source file modified under livereload is potentially overridden + * in the src-web directory in which case the change should not be propagated + * to the served content. + * + * @private + * @param {object} pathComponents - file path specification + * @returns {boolean} + */ +function _isFileOverridden(pathComponents) { + const srcDir = pathComponents.mid; + + if (srcDir === config('paths').src.web) { + return false; + } + const filePath = pathComponents.beg + config('paths').src.web + pathComponents.end; + + return util.fsExistsSync(filePath); +} diff --git a/lib/templates/pack/component.json b/lib/templates/pack/component.json index 1e7fa72..2a12916 100644 --- a/lib/templates/pack/component.json +++ b/lib/templates/pack/component.json @@ -1,7 +1,7 @@ { "name": "@pack@", "version": "1.0.0", - "jetVersion": "8.1.0", + "jetVersion": "8.2.0", "type": "pack", "displayName": "A user friendly, translatable name of the pack.", "description": "A translatable high-level description for the pack.", diff --git a/package.json b/package.json index 9bdc23e..8a53dda 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oracle/oraclejet-tooling", - "version": "8.1.0", + "version": "8.2.0", "license": "UPL-1.0", "description": "Programmatic API to build and serve Oracle JET web and mobile applications", "keywords": [ @@ -37,6 +37,6 @@ "form-data": "^2.3.2" }, "engines": { - "node": ">=8.0.0" + "node": ">=10.0.0" } }