From b6f7f93f3a46a82b2c20ef3a6b573759c6c3fdf7 Mon Sep 17 00:00:00 2001 From: Ben Moroze Date: Thu, 12 Jan 2023 13:59:05 -0500 Subject: [PATCH] Release 14.0.0 --- CONTRIBUTING.md | 2 +- LICENSE | 2 +- README.md | 6 +- RELEASENOTES.md | 2 +- config/eslintcustom.js | 2 +- hooks/jetAfterPrepare.js | 2 +- hooks/jetInjector.js | 2 +- lib/add.js | 2 +- lib/addjsdoc.js | 28 + lib/addpcss.js | 2 +- lib/addpwa.js | 155 ++-- lib/addsass.js | 2 +- lib/addtypescript.js | 7 +- lib/addwebpack.js | 103 ++- lib/build.js | 2 +- lib/buildCommon.js | 541 ++++++------- lib/buildCommon/compileTypescript.js | 785 ++++++++++++------- lib/buildCommon/copyLocalComponent.js | 44 +- lib/buildCommon/generateComponentsCache.js | 50 +- lib/buildCommon/minifyComponent.js | 57 +- lib/buildCommon/optimizeComponent.js | 80 +- lib/buildCommon/restoreLocalComponentJson.js | 38 +- lib/buildCommon/stripLocalComponentJson.js | 2 +- lib/buildCommon/webpack.js | 2 +- lib/buildComponent.js | 66 +- lib/buildHybrid.js | 70 +- lib/buildWeb.js | 57 +- lib/clean.js | 2 +- lib/config.js | 4 +- lib/configure.js | 2 +- lib/constants.js | 15 +- lib/create.js | 6 +- lib/defaultconfig.js | 2 +- lib/hookRunner.js | 2 +- lib/indexHtmlInjector.js | 30 +- lib/injectorUtil.js | 2 +- lib/list.js | 2 +- lib/mainJsInjector.js | 34 +- lib/npmCopy.js | 6 +- lib/package.js | 2 +- lib/parser/dom-parser.js | 2 +- lib/parser/dom.js | 2 +- lib/parser/sax.js | 2 +- lib/pcss.js | 2 +- lib/publish.js | 2 +- lib/remove.js | 2 +- lib/rjsConfigGenerator.js | 25 +- lib/sass.js | 2 +- lib/scopes/component.js | 26 +- lib/scopes/exchange.js | 27 +- lib/scopes/pack.js | 61 +- lib/search.js | 2 +- lib/serve.js | 2 +- lib/serve/connect.js | 2 +- lib/serve/watch.js | 11 +- lib/serveHybrid.js | 2 +- lib/serveHybridFileChangeHandler.js | 2 +- lib/serveWeb.js | 2 +- lib/serveWebFileChangeHandler.js | 2 +- lib/strip.js | 2 +- lib/svg.js | 2 +- lib/templates/pack/component.json | 2 +- lib/templates/typescript/tsconfig.json | 6 +- lib/templates/webpack/ojet.config.js | 2 +- lib/util.js | 90 ++- lib/utils.exchange.js | 6 +- lib/validations.js | 3 +- lib/webpack/build.js | 9 +- lib/webpack/custom-tsc/index.js | 2 +- lib/webpack/serve.js | 2 +- lib/webpack/setup.js | 66 +- lib/webpack/utils.js | 163 ++-- lib/webpack/webpack.common.js | 123 +-- lib/webpack/webpack.development.js | 31 +- lib/webpack/webpack.production.js | 72 +- oraclejet-tooling.js | 3 +- package.json | 2 +- test/config.js | 2 +- test/hook.js | 15 +- test/util.js | 2 +- 80 files changed, 1787 insertions(+), 1216 deletions(-) create mode 100644 lib/addjsdoc.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9ad4d94..dc51f8c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to oraclejet-tooling -*Copyright (c) 2014, 2022 Oracle and/or its affiliates +*Copyright (c) 2014, 2023 Oracle and/or its affiliates Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/* diff --git a/LICENSE b/LICENSE index 182cd16..7a44d23 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ # oraclejet-tooling -Copyright (c) 2022 Oracle and/or its affiliates. +Copyright (c) 2023 Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/README.md b/README.md index 18200e5..e629baa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# @oracle/oraclejet-tooling 13.1.0 +# @oracle/oraclejet-tooling 14.0.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=jet1310&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=jet1400&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 @@ -14,5 +14,5 @@ Oracle JET is an open source project. Pull Requests are currently not being acc for details. ## [License](https://github.com/oracle/oraclejet-tooling/blob/master/LICENSE) -Copyright (c) 2022 Oracle and/or its affiliates and released under the +Copyright (c) 2023 Oracle and/or its affiliates and released under the [Universal Permissive License (UPL)](https://oss.oracle.com/licenses/upl/), Version 1.0 \ No newline at end of file diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 79638ed..dc40033 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,6 +1,6 @@ ## Release Notes for oraclejet-tooling ## -### 13.1.0 +### 14.0.0 ### 11.0.0 * oraclejet-tooling now requires node 12.21 or later diff --git a/config/eslintcustom.js b/config/eslintcustom.js index 29a2579..c20fc24 100644 --- a/config/eslintcustom.js +++ b/config/eslintcustom.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/hooks/jetAfterPrepare.js b/hooks/jetAfterPrepare.js index cc79342..dfcbc4f 100644 --- a/hooks/jetAfterPrepare.js +++ b/hooks/jetAfterPrepare.js @@ -1,6 +1,6 @@ #!/usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/hooks/jetInjector.js b/hooks/jetInjector.js index babdde4..1cf8e81 100644 --- a/hooks/jetInjector.js +++ b/hooks/jetInjector.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/add.js b/lib/add.js index b5739f9..3ee485d 100644 --- a/lib/add.js +++ b/lib/add.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/addjsdoc.js b/lib/addjsdoc.js new file mode 100644 index 0000000..44780ad --- /dev/null +++ b/lib/addjsdoc.js @@ -0,0 +1,28 @@ +#! /usr/bin/env node +/** + Copyright (c) 2015, 2023, Oracle and/or its affiliates. + Licensed under The Universal Permissive License (UPL), Version 1.0 + as shown at https://oss.oracle.com/licenses/upl/ + +*/ + +'use strict'; + +/** + * ## Dependencies + */ +const util = require('./util'); + +/** + * # 'addJsdoc' + * + * @public + * @param {Object} options + * @returns {Promise} + */ +module.exports = function (options) { + util.log('Installing jsdoc'); + const installer = util.getInstallerCommand({ options }); + + return util.spawn(installer.installer, [installer.verbs.install, 'jsdoc@3.5.5', '--save-dev=true', '--save-exact']); +}; diff --git a/lib/addpcss.js b/lib/addpcss.js index f404746..1fb0f09 100644 --- a/lib/addpcss.js +++ b/lib/addpcss.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/addpwa.js b/lib/addpwa.js index 5bb36d0..667d870 100644 --- a/lib/addpwa.js +++ b/lib/addpwa.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -24,82 +24,79 @@ const CONSTANTS = require('./constants'); */ module.exports = function () { - return new Promise((resolve) => { - // eslint-disable-next-line global-require - const appName = path.basename(process.cwd()); - const appNameRegex = new RegExp('@AppName@', 'g'); - const pathToApp = path.join('src'); - const pathToIndexHtml = path.join(pathToApp, 'index.html'); - const pathToServiceWorkerTemplates = path.join(util.getToolingPath(), - CONSTANTS.PATH_TO_PWA_TEMPLATES); - // 1. read index.html - const indexHtmlString = fs.readFileSync( - pathToIndexHtml, - { encoding: 'utf-8' } - ); - // 2. read sw.txt, replace app name token and resources to cache - // according to the app's architecture, and then write to app as js file - let swJsString; - if (util.isVDOMApplication()) { - swJsString = fs.readFileSync( - path.join(pathToServiceWorkerTemplates, 'sw.txt'), - { encoding: 'utf-8' }); - const vdomResourcesToCache = `[ - 'index.js', - 'index.html', - 'bundle.js', - 'manifest.json', - 'components/', - 'libs/', - 'styles/' - ]`; - const mvvmResourcesToCache = "['index.html', 'manifest.json', 'js/', 'css/']"; - swJsString = swJsString.replace(mvvmResourcesToCache, vdomResourcesToCache); - } else { - swJsString = fs.readFileSync( - path.join(pathToServiceWorkerTemplates, 'sw.txt'), - { encoding: 'utf-8' }); - } - const pathToAppSw = path.join(pathToApp, 'sw.js'); - if (fs.pathExistsSync(pathToAppSw)) { - fs.renameSync(pathToAppSw, path.join(pathToApp, 'sw_old.js')); - } - fs.outputFileSync( - pathToAppSw, - swJsString.replace(appNameRegex, appName) - ); - // 3. read manifest.json, replace app name token, write to app - const manifestJsonString = fs.readFileSync( - path.join(pathToServiceWorkerTemplates, 'manifest.json'), - { encoding: 'utf-8' } - ); - const pathToAppManifest = path.join(pathToApp, 'manifest.json'); - if (fs.pathExistsSync(pathToAppManifest)) { - fs.renameSync(pathToAppManifest, path.join(pathToApp, 'manifest_old.json')); - } - fs.outputFileSync( - path.join(pathToApp, 'manifest.json'), - manifestJsonString.replace(appNameRegex, appName) - ); - // 4. copy swInit.txt and add it to end of body tag index.html, add - // to end of header tag in index.html and update - const swInitString = fs.readFileSync( - path.join(pathToServiceWorkerTemplates, 'swInit.txt'), - { encoding: 'utf-8' } - ); - fs.outputFileSync( - pathToIndexHtml, - indexHtmlString.replace( - new RegExp('', 'g'), - '\n' - ).replace( - new RegExp('', 'g'), - `${swInitString.replace(appNameRegex, appName)}\n` - ) - ); - // Copy over swinit.js - fs.copyFileSync(path.join(pathToServiceWorkerTemplates, 'swinit._js'), - path.join(pathToApp, 'swinit.js')); - resolve(); - }); + const appName = path.basename(process.cwd()); + const appNameRegex = new RegExp('@AppName@', 'g'); + const pathToApp = path.join('src'); + const pathToIndexHtml = path.join(pathToApp, 'index.html'); + const pathToServiceWorkerTemplates = path.join(util.getToolingPath(), + CONSTANTS.PATH_TO_PWA_TEMPLATES); + // 1. read index.html + const indexHtmlString = fs.readFileSync( + pathToIndexHtml, + { encoding: 'utf-8' } + ); + // 2. read sw.txt, replace app name token and resources to cache + // according to the app's architecture, and then write to app as js file + let swJsString; + if (util.isVDOMApplication()) { + swJsString = fs.readFileSync( + path.join(pathToServiceWorkerTemplates, 'sw.txt'), + { encoding: 'utf-8' }); + const vdomResourcesToCache = `[ + 'index.js', + 'index.html', + 'bundle.js', + 'manifest.json', + 'components/', + 'libs/', + 'styles/' + ]`; + const mvvmResourcesToCache = "['index.html', 'manifest.json', 'js/', 'css/']"; + swJsString = swJsString.replace(mvvmResourcesToCache, vdomResourcesToCache); + } else { + swJsString = fs.readFileSync( + path.join(pathToServiceWorkerTemplates, 'sw.txt'), + { encoding: 'utf-8' }); + } + const pathToAppSw = path.join(pathToApp, 'sw.js'); + if (fs.pathExistsSync(pathToAppSw)) { + fs.renameSync(pathToAppSw, path.join(pathToApp, 'sw_old.js')); + } + fs.outputFileSync( + pathToAppSw, + swJsString.replace(appNameRegex, appName) + ); + // 3. read manifest.json, replace app name token, write to app + const manifestJsonString = fs.readFileSync( + path.join(pathToServiceWorkerTemplates, 'manifest.json'), + { encoding: 'utf-8' } + ); + const pathToAppManifest = path.join(pathToApp, 'manifest.json'); + if (fs.pathExistsSync(pathToAppManifest)) { + fs.renameSync(pathToAppManifest, path.join(pathToApp, 'manifest_old.json')); + } + fs.outputFileSync( + path.join(pathToApp, 'manifest.json'), + manifestJsonString.replace(appNameRegex, appName) + ); + // 4. copy swInit.txt and add it to end of body tag index.html, add + // to end of header tag in index.html and update + const swInitString = fs.readFileSync( + path.join(pathToServiceWorkerTemplates, 'swInit.txt'), + { encoding: 'utf-8' } + ); + fs.outputFileSync( + pathToIndexHtml, + indexHtmlString.replace( + new RegExp('', 'g'), + '\n' + ).replace( + new RegExp('', 'g'), + `${swInitString.replace(appNameRegex, appName)}\n` + ) + ); + // Copy over swinit.js + fs.copyFileSync(path.join(pathToServiceWorkerTemplates, 'swinit._js'), + path.join(pathToApp, 'swinit.js')); + return Promise.resolve(); }; diff --git a/lib/addsass.js b/lib/addsass.js index 08f9341..7efbab2 100644 --- a/lib/addsass.js +++ b/lib/addsass.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/addtypescript.js b/lib/addtypescript.js index a73bb83..efdc9e1 100644 --- a/lib/addtypescript.js +++ b/lib/addtypescript.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -16,6 +16,7 @@ const util = require('./util'); const fs = require('fs-extra'); const path = require('path'); const CONSTANTS = require('./constants'); +const config = require('./config'); /** * ## Helpers @@ -34,8 +35,10 @@ const CONSTANTS = require('./constants'); function installTypescipt(options) { util.log('Installing Typescript'); const installer = util.getInstallerCommand({ options }); + config.loadOraclejetConfig(); + const typescriptLibraries = config.data.typescriptLibraries; - const command = `${installer.installer} ${installer.verbs.install} typescript@${CONSTANTS.TYPESCRIPT_VERSION} yargs-parser@~13.1.2 --save-dev --save-exact`; + const command = `${installer.installer} ${installer.verbs.install} ${typescriptLibraries} --save-dev --save-exact`; return util.exec(command); } diff --git a/lib/addwebpack.js b/lib/addwebpack.js index 6d91c24..09f4684 100644 --- a/lib/addwebpack.js +++ b/lib/addwebpack.js @@ -1,63 +1,50 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ */ -const path = require('path'); -const CONSTANTS = require('./constants'); -const util = require('./util'); - -/** - * ## injectOjetConfig - * - * Inject default ojet.config file into the application - * - * @private - * @returns {Promise} - */ -function injectOJetConfig() { - return util.injectFileIntoApplication({ - name: CONSTANTS.OJET_CONFIG, - src: path.join(util.getToolingPath(), CONSTANTS.PATH_TO_OJET_CONFIG_TEMPLATE), - dest: CONSTANTS.OJET_CONFIG - }); -} - -/** - * Install webpack and required loaders from NPM - * @param {Object} options - * @returns - */ -function installWebpack(options) { - util.log('Installing webpack and required dependencies'); - const installer = util.getInstallerCommand({ options }); - - const command = ` - ${installer.installer} ${installer.verbs.install} - webpack@${CONSTANTS.WEBPACK_VERSION} - @types/node@18.8.3 - webpack-dev-server - style-loader - css-loader - ts-loader - raw-loader - noop-loader - html-webpack-plugin - html-replace-webpack-plugin - copy-webpack-plugin - @prefresh/webpack - @prefresh/babel-plugin - webpack-merge - compression-webpack-plugin - mini-css-extract-plugin - --save-dev --save-exact - `.replace(/\n/g, '').replace(/\s+/g, ' '); - return util.exec(command); -} - -module.exports = function (options) { - return installWebpack(options) - .then(injectOJetConfig) - .catch(util.log.error); -}; +const path = require('path'); +const CONSTANTS = require('./constants'); +const util = require('./util'); +const config = require('./config'); + +/** + * ## injectOjetConfig + * + * Inject default ojet.config file into the application + * + * @private + * @returns {Promise} + */ +function injectOJetConfig() { + return util.injectFileIntoApplication({ + name: CONSTANTS.OJET_CONFIG, + src: path.join(util.getToolingPath(), CONSTANTS.PATH_TO_OJET_CONFIG_TEMPLATE), + dest: CONSTANTS.OJET_CONFIG + }); +} + +/** + * Install webpack and required loaders from NPM + * @param {Object} options + * @returns + */ +function installWebpack(options) { + util.log('Installing webpack and required dependencies'); + const installer = util.getInstallerCommand({ options }); + config.loadOraclejetConfig(); + const webpackLibraries = config.data.webpackLibraries; + + const command = ` + ${installer.installer} ${installer.verbs.install} ${webpackLibraries} + --save-dev --save-exact + `.replace(/\n/g, '').replace(/\s+/g, ' '); + return util.exec(command); +} + +module.exports = function (options) { + return installWebpack(options) + .then(injectOJetConfig) + .catch(util.log.error); +}; diff --git a/lib/build.js b/lib/build.js index e3a4d34..a2065db 100644 --- a/lib/build.js +++ b/lib/build.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/buildCommon.js b/lib/buildCommon.js index 50964c0..0c14045 100644 --- a/lib/buildCommon.js +++ b/lib/buildCommon.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -31,22 +31,20 @@ const { const webpack = require('./buildCommon/webpack'); function _copyFileToStaging(fileList) { - return new Promise((resolve, reject) => { - try { - for (let i = 0; i < fileList.length; i++) { - const destDir = fileList[i].dest; - const srcDir = fileList[i].src; - if (_isSvgFile(srcDir)) { - fs.copySync(srcDir, destDir, { overwrite: false, errorOnExist: false }); - } else { - fs.copySync(srcDir, destDir, { overwrite: true }); - } + try { + for (let i = 0; i < fileList.length; i++) { + const destDir = fileList[i].dest; + const srcDir = fileList[i].src; + if (_isSvgFile(srcDir)) { + fs.copySync(srcDir, destDir, { overwrite: false, errorOnExist: false }); + } else { + fs.copySync(srcDir, destDir, { overwrite: true }); } - resolve(); - } catch (error) { - reject(error); } - }); + return Promise.resolve(); + } catch (error) { + return Promise.reject(error); + } } function _isSvgFile(fileName) { @@ -126,45 +124,47 @@ function _copyDefaultResourcesToStaging(theme, stagingPath, themeName) { } function _copyExchangeComponentsToStaging({ context, componentsSource }) { - return new Promise((resolve) => { + try { if (util.isObjectEmpty(componentsSource)) { // No component source present, continue... - resolve(); - } else { - const componentDirectories = util.getDirectories(componentsSource.cwd); - if (componentDirectories.length) { - componentDirectories.forEach((component) => { - const configPaths = util.getConfiguredPaths(); - const componentDirPath = path.resolve(configPaths.exchangeComponents, component); - const componentJsonPath = path.join( - componentDirPath, CONSTANTS.JET_COMPONENT_JSON); - if (fs.existsSync(componentJsonPath)) { - const componentJson = util.readJsonAndReturnObject(componentJsonPath); - if (!util.hasProperty(componentJson, 'version')) { - util.log.error(`Missing property 'version' in '${component}' component's/pack's definition file.`); - } - if (!util.isLocalComponent({ component })) { - const destPath = util.generatePathToComponentRoot({ - context, - component, - root: context.opts.stagingPath, - scripts: configPaths.src.javascript - }); - fs.copySync(componentDirPath, destPath); - } - resolve(); - } else { - // Folder is missing component.json, log warning and skip. - util.log.warning(`Missing the definition file '${CONSTANTS.JET_COMPONENT_JSON}' for component / pack '${component}'.`); - resolve(); + return Promise.resolve(context); + } + const componentDirectories = util.getDirectories(componentsSource.cwd); + if (componentDirectories.length) { + componentDirectories.forEach((component) => { + const configPaths = util.getConfiguredPaths(); + const componentDirPath = path.resolve(configPaths.exchangeComponents, component); + const componentJsonPath = path.join( + componentDirPath, CONSTANTS.JET_COMPONENT_JSON); + if (fs.existsSync(componentJsonPath)) { + const componentJson = util.readJsonAndReturnObject(componentJsonPath); + if (!util.hasProperty(componentJson, 'version')) { + util.log.error(`Missing property 'version' in '${component}' component's/pack's definition file.`); } - }); - } else { - // No components added from the Exchange, continue... - resolve(); - } + if (!util.isLocalComponent({ component })) { + const destPath = util.generatePathToComponentRoot({ + context, + component, + root: context.opts.stagingPath, + scripts: configPaths.src.javascript + }); + fs.copySync(componentDirPath, destPath); + } + return Promise.resolve(); + } + // Folder is missing component.json, log warning and skip. + util.log.warning(`Missing the definition file '${CONSTANTS.JET_COMPONENT_JSON}' for component / pack '${component}'.`); + return Promise.resolve(context); + }); + } else { + // No components added from the Exchange, continue... + return Promise.resolve(context); } - }).catch(error => util.log.error(error)); + return Promise.resolve(context); + } catch (error) { + util.log.error(error); + return Promise.reject(error); + } } function _copyFilesExcludeScss(srcBase, destBase) { @@ -258,55 +258,49 @@ function _copyThemesToStaging(context) { const stdest = _getThemeDestPath(stable, stgPath, ext, livereload, platform, opts.destination); fs.copySync(stsrc, stdest); } - return new Promise((resolve, reject) => { - // copy to themes - if ((theme.name !== CONSTANTS.DEFAULT_THEME || theme.name !== CONSTANTS.DEFAULT_PCSS_THEME || - theme.name !== CONSTANTS.DEFAULT_STABLE_THEME) - && !livereload) { - _copySrcResourcesToThemes(theme); - if (opts.theme.cssGeneratedType === 'add-on' || config('defaultTheme') === CONSTANTS.DEFAULT_PCSS_THEME || - config('defaultTheme') === CONSTANTS.DEFAULT_STABLE_THEME) { - if (config('defaultTheme') === CONSTANTS.DEFAULT_STABLE_THEME) { - _copySrcResourcesToThemes(stable); - } else { - _copySrcResourcesToThemes(rwood); - } - } - if (!util.getInstalledCssPackage()) { - if (config('defaultTheme') === CONSTANTS.DEFAULT_PCSS_THEME) { - _copyDefaultResourcesToStaging(rwood, stgPath, CONSTANTS.DEFAULT_PCSS_THEME); - } else { - // copy alta resources link imageDir, fontsDir, commonImageDir - _copyDefaultResourcesToStaging(theme, stgPath, CONSTANTS.DEFAULT_THEME); - } + // copy to themes + if ((theme.name !== CONSTANTS.DEFAULT_THEME || theme.name !== CONSTANTS.DEFAULT_PCSS_THEME || + theme.name !== CONSTANTS.DEFAULT_STABLE_THEME) + && !livereload) { + _copySrcResourcesToThemes(theme); + if (opts.theme.cssGeneratedType === 'add-on' || config('defaultTheme') === CONSTANTS.DEFAULT_PCSS_THEME || + config('defaultTheme') === CONSTANTS.DEFAULT_STABLE_THEME) { + if (config('defaultTheme') === CONSTANTS.DEFAULT_STABLE_THEME) { + _copySrcResourcesToThemes(stable); } else { - // copy redwood resources link imageDir, fontsDir, commonImageDir - _copyDefaultResourcesToStaging(theme, stgPath, CONSTANTS.DEFAULT_PCSS_THEME); - _copyDefaultResourcesToStaging(theme, stgPath, CONSTANTS.DEFAULT_STABLE_THEME); + _copySrcResourcesToThemes(rwood); } } - _copyMultiThemesSrcResourcesToThemes(opts.themes); - - // copy to staging - // copy theme/platform to staging - fs.copySync(src, dest); - // Copy preact theme if present - if (fs.existsSync(preactSrc)) { - fs.copySync(preactSrc, preactDest); - if (buildType === 'release') { - // Preact images need to be a peer of the code bundle.js - fs.copySync(path.join(preactSrc, 'images'), path.join(stgPath, 'images')); + if (!util.getInstalledCssPackage()) { + if (config('defaultTheme') === CONSTANTS.DEFAULT_PCSS_THEME) { + _copyDefaultResourcesToStaging(rwood, stgPath, CONSTANTS.DEFAULT_PCSS_THEME); + } else { + // copy alta resources link imageDir, fontsDir, commonImageDir + _copyDefaultResourcesToStaging(theme, stgPath, CONSTANTS.DEFAULT_THEME); } + } else { + // copy redwood resources link imageDir, fontsDir, commonImageDir + _copyDefaultResourcesToStaging(theme, stgPath, CONSTANTS.DEFAULT_PCSS_THEME); + _copyDefaultResourcesToStaging(theme, stgPath, CONSTANTS.DEFAULT_STABLE_THEME); + } + } + _copyMultiThemesSrcResourcesToThemes(opts.themes); + + // copy to staging + // copy theme/platform to staging + fs.copySync(src, dest); + // Copy preact theme if present + if (fs.existsSync(preactSrc)) { + fs.copySync(preactSrc, preactDest); + if (buildType === 'release') { + // Preact images need to be a peer of the code bundle.js + fs.copySync(path.join(preactSrc, 'images'), path.join(stgPath, 'images')); } + } - // copy additional resources staged-themes/theme/common - _copyThemeCommonToStaging(theme, stgPath) - .then(_copyMultiThemesToStaging(opts, stgPath, livereload)) - .then(() => { - resolve(context); - }) - .catch(err => reject(err)); - }); + // copy additional resources staged-themes/theme/common + return _copyThemeCommonToStaging(theme, stgPath) + .then(_copyMultiThemesToStaging(opts, stgPath, livereload)); } // only runs when platform is windows, fixing locale Bug 26871715 @@ -355,17 +349,15 @@ function _requireJsInvoker(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 - resolve(context); - } catch (error) { - reject(error); - } - }); + 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 + return Promise.resolve(context); + } catch (error) { + return Promise.reject(error); + } } module.exports = { @@ -389,16 +381,11 @@ module.exports = { }, copySingleCca: function _copySingleCca(context, componentJson, componentName) { - return new Promise((resolve, reject) => { - try { - copyLocalComponent({ context, componentName, componentJson }) - .then(() => { - resolve(context); - }); - } catch (error) { - reject(error); - } - }); + try { + return copyLocalComponent({ context, componentName, componentJson }); + } catch (error) { + return Promise.reject(error); + } }, clean: function _clean(context) { @@ -467,75 +454,63 @@ module.exports = { injectPaths: function _injectMainPaths(context) { util.log('Running injection tasks.'); - return new Promise((resolve, reject) => { - mainJsInjector.injectPaths(context) - .then(() => { - util.log('Task main.js paths injection finished.'); - resolve(context); - }) - .catch(err => reject(err)); - }); + return mainJsInjector.injectPaths(context) + .then(() => { + util.log('Task main.js paths injection finished.'); + return Promise.resolve(context); + }) + .catch(err => Promise.reject(err)); }, injectTs: function _injectTs(context) { util.log('Running typescript injection tasks.'); - return new Promise((resolve, reject) => { - mainJsInjector.injectTs(context) - .then(() => { - util.log('Task typescript injection finished.'); - resolve(context); - }) - .catch(err => reject(err)); - }); + return mainJsInjector.injectTs(context) + .then(() => { + util.log('Task typescript injection finished.'); + return Promise.resolve(context); + }) + .catch(err => Promise.reject(err)); }, injectLocalhostCspRule: function _injectLocalhostCspRule(context) { util.log('Running localhost csp rule injection task.'); - return new Promise((resolve, reject) => { - indexHtmlInjector.injectLocalhostCspRule(context) - .then(() => { - util.log('Task index.html localhost csp rule injection finished.'); - resolve(context); - }) - .catch(err => reject(err)); - }); + return indexHtmlInjector.injectLocalhostCspRule(context) + .then(() => { + util.log('Task index.html localhost csp rule injection finished.'); + return Promise.resolve(context); + }) + .catch(err => Promise.reject(err)); }, injectScripts: function _injectScripts(context) { - return new Promise((resolve, reject) => { - indexHtmlInjector.injectScripts(context) - .then(() => { - util.log('Task index.html script injection finished'); - resolve(context); - }) - .catch(reject); - }); + return indexHtmlInjector.injectScripts(context) + .then(() => { + util.log('Task index.html script injection finished'); + return Promise.resolve(context); + }) + .catch(err => Promise.reject(err)); }, injectTheme: function _injectTheme(context) { util.log('Running theme injection task.'); - return new Promise((resolve, reject) => { - indexHtmlInjector.injectThemePath(context) - .then(() => { - util.log('Task index.html theme path injection finished.'); - resolve(context); - }) - .catch(err => reject(err)); - }); + return indexHtmlInjector.injectThemePath(context) + .then(() => { + util.log('Task index.html theme path injection finished.'); + return Promise.resolve(context); + }) + .catch(err => Promise.reject(err)); }, copyThemes: function _copyThemes(context) { util.log('Running theme copy task.'); - return new Promise((resolve, reject) => { - _copyThemesToStaging(context) - .then(() => { - util.log('Theme copy task finished.'); - resolve(context); - }) - .catch(err => reject(err)); - }); + return _copyThemesToStaging(context) + .then(() => { + util.log('Theme copy task finished.'); + return Promise.resolve(context); + }) + .catch(err => Promise.reject(err)); }, terser: function _terser(context) { @@ -545,19 +520,17 @@ module.exports = { const platform = context.platform; const terserConfig = opts.terser; const minify = opts.optimize !== 'none'; - return new Promise((resolve, reject) => { - util.minifyFiles({ - files: util.getFileList(buildType, terserConfig.fileList, platform), - options: terserConfig.options, - generateSourceMaps: false, - minify + return util.minifyFiles({ + files: util.getFileList(buildType, terserConfig.fileList, platform), + options: terserConfig.options, + generateSourceMaps: false, + minify + }) + .then(() => { + util.log('Task terser finished.'); + return Promise.resolve(context); }) - .then(() => { - util.log('Task terser finished.'); - resolve(context); - }) - .catch(err => reject(err)); - }); + .catch(err => Promise.reject(err)); }, requireJs: function _requireJs(context) { @@ -621,24 +594,22 @@ module.exports = { }, cleanTemp: function _cleanTemp(context) { - return new Promise((resolve) => { - util.log('Cleaning temporary files.'); - const opts = context.opts; - const configPaths = util.getConfiguredPaths(); - const bundleTemp = path.join( - opts.stagingPath, - configPaths.src.javascript, - path.basename(opts.injectPaths.destMainJs) - ); - const mainJs = path.join(opts.stagingPath, configPaths.src.javascript, 'main.js'); - const filesToDelete = [bundleTemp]; - if (!bundleTemp.endsWith('main-temp.js')) { - filesToDelete.push(mainJs); - } - filesToDelete.forEach(filePath => fs.existsSync(filePath) && fs.removeSync(filePath)); - util.log('Task cleaning temporary files finished.'); - resolve(context); - }); + util.log('Cleaning temporary files.'); + const opts = context.opts; + const configPaths = util.getConfiguredPaths(); + const bundleTemp = path.join( + opts.stagingPath, + configPaths.src.javascript, + path.basename(opts.injectPaths.destMainJs) + ); + const mainJs = path.join(opts.stagingPath, configPaths.src.javascript, 'main.js'); + const filesToDelete = [bundleTemp]; + if (!bundleTemp.endsWith('main-temp.js')) { + filesToDelete.push(mainJs); + } + filesToDelete.forEach(filePath => fs.existsSync(filePath) && fs.removeSync(filePath)); + util.log('Task cleaning temporary files finished.'); + return Promise.resolve(context); }, spriteSvg: function _spriteSvg(context) { @@ -654,13 +625,11 @@ module.exports = { }, fixWindowsLocale: function _fixWindowsLocale(context) { - return new Promise((resolve) => { - const platform = context.platform; - if (platform === 'windows') { - _renameNlsDirs(); - } - resolve(context); - }); + const platform = context.platform; + if (platform === 'windows') { + _renameNlsDirs(); + } + return Promise.resolve(context); }, copyLocalVComponents: function _copyLocalVComponents(context) { @@ -702,45 +671,43 @@ module.exports = { }, copyLocalResourceComponents: function _copyLocalResourceComponents(context) { - return new Promise((resolve) => { - // copy none web components in // - // these will typically be none-custom element vcomponents - const configPaths = util.getConfiguredPaths(); - const componentsSrcPath = path.join( - configPaths.src.common, + // copy none web components in // + // these will typically be none-custom element vcomponents + const configPaths = util.getConfiguredPaths(); + const componentsSrcPath = path.join( + configPaths.src.common, + configPaths.src.typescript, + configPaths.components + ); + if (util.fsExistsSync(componentsSrcPath)) { + const componentsDestPath = path.join( + context.opts.stagingPath, configPaths.src.typescript, configPaths.components ); - if (util.fsExistsSync(componentsSrcPath)) { - const componentsDestPath = path.join( - context.opts.stagingPath, - configPaths.src.typescript, - configPaths.components - ); - const paths = []; - util.readDirSync(componentsSrcPath, { withFileTypes: true }) - .forEach((dirent) => { - const dirEntName = dirent.name; - // only copy files or none web component folders, web components are - // copied / staged via a different task - if (dirent.isFile() || - (dirent.isDirectory() && !util.isWebComponent({ component: dirEntName })) - ) { - paths.push([ - path.join(componentsSrcPath, dirEntName), - path.join(componentsDestPath, dirEntName) - ]); - } - }); - if (paths.length) { - paths.forEach(([src, dest]) => { - fs.copySync(src, dest); - }); - util.log('Copied local resource components'); - } + const paths = []; + util.readDirSync(componentsSrcPath, { withFileTypes: true }) + .forEach((dirent) => { + const dirEntName = dirent.name; + // only copy files or none web component folders, web components are + // copied / staged via a different task + if (dirent.isFile() || + (dirent.isDirectory() && !util.isWebComponent({ component: dirEntName })) + ) { + paths.push([ + path.join(componentsSrcPath, dirEntName), + path.join(componentsDestPath, dirEntName) + ]); + } + }); + if (paths.length) { + paths.forEach(([src, dest]) => { + fs.copySync(src, dest); + }); + util.log('Copied local resource components'); } - resolve(context); - }); + } + return Promise.resolve(context); }, minifyLocalVComponents: function _minifyLocalVComponents(context) { @@ -835,67 +802,65 @@ module.exports = { // } copyReferenceCca(context) { - return new Promise((resolve) => { - util.log('Copy reference components to staging directory.'); - const configPaths = util.getConfiguredPaths(); - const componentList = util.getDirectories(`./${configPaths.exchangeComponents}`); - componentList.forEach((component) => { - const componentDirPath = `./${configPaths.exchangeComponents}/${component}/${CONSTANTS.JET_COMPONENT_JSON}`; - const componentJson = util.readJsonAndReturnObject(`${componentDirPath}`); - if (componentJson.type === CONSTANTS.COMPONENT_TYPE.REFERENCE) { - const npmPckgName = componentJson.package; - const retObj = util.getNpmPckgInitFileRelativePath(componentJson, context.buildType); - const npmPckgInitFileRelativePath = retObj.npmPckgInitFileRelativePath; - + util.log('Copy reference components to staging directory.'); + const configPaths = util.getConfiguredPaths(); + const componentList = util.getDirectories(`./${configPaths.exchangeComponents}`); + componentList.forEach((component) => { + const componentDirPath = `./${configPaths.exchangeComponents}/${component}/${CONSTANTS.JET_COMPONENT_JSON}`; + const componentJson = util.readJsonAndReturnObject(`${componentDirPath}`); + if (componentJson.type === CONSTANTS.COMPONENT_TYPE.REFERENCE) { + const npmPckgName = componentJson.package; + const retObj = util.getNpmPckgInitFileRelativePath(componentJson, context.buildType); + const npmPckgInitFileRelativePath = retObj.npmPckgInitFileRelativePath; + + // + // Select the the minimized path (if defined). + // Otherwise select the debug path. + // Example path from component.json: + // + // "paths": { + // "npm": { + // "min": "dist/showdown.min", + // "debug": "dist/showdown" + // } + // } + // + + // Copy is only necessary for npm paths. + // (no copy is necessary for cdn paths). + if (npmPckgInitFileRelativePath !== undefined && retObj.npm) { + // Extract out the filename portion of the path. + const npmPckgInitFileNameArray = npmPckgInitFileRelativePath.split('/'); + const npmPckgInitFileName = npmPckgInitFileNameArray[npmPckgInitFileNameArray.length - 1]; // eslint-disable-line max-len + const npmPckgSrcPath = `./${CONSTANTS.NODE_MODULES_DIRECTORY}/${npmPckgName}/${npmPckgInitFileRelativePath}`; // eslint-disable-line max-len // - // Select the the minimized path (if defined). - // Otherwise select the debug path. - // Example path from component.json: + // Construct the npm path (node_modules) to the component file. + // E.g: + // ./node_modules/showdown/dist/showdown + // Then copy this file to + // /web/js/libs/showdown/showdown.js // - // "paths": { - // "npm": { - // "min": "dist/showdown.min", - // "debug": "dist/showdown" - // } - // } + // Note - the component.json npm path does not necessarily have the .js extension, + // so we handle this if necessary. // - // Copy is only necessary for npm paths. - // (no copy is necessary for cdn paths). - if (npmPckgInitFileRelativePath !== undefined && retObj.npm) { - // Extract out the filename portion of the path. - const npmPckgInitFileNameArray = npmPckgInitFileRelativePath.split('/'); - const npmPckgInitFileName = npmPckgInitFileNameArray[npmPckgInitFileNameArray.length - 1]; // eslint-disable-line max-len - const npmPckgSrcPath = `./${CONSTANTS.NODE_MODULES_DIRECTORY}/${npmPckgName}/${npmPckgInitFileRelativePath}`; // eslint-disable-line max-len - // - // Construct the npm path (node_modules) to the component file. - // E.g: - // ./node_modules/showdown/dist/showdown - // Then copy this file to - // /web/js/libs/showdown/showdown.js - // - // Note - the component.json npm path does not necessarily have the .js extension, - // so we handle this if necessary. - // - - const destBasePath = path.join(config('paths').staging.stagingPath, config('paths').src.javascript, 'libs'); - // - // If npmPckgSrcPath is a directory (containing multiple files), - // then we need to copy the entire directory. - // - const destNpmpckgDirPath = `${destBasePath}/${npmPckgName}/${npmPckgInitFileName}`; - - if (util.fsExistsSync(npmPckgSrcPath)) { - fs.copySync(npmPckgSrcPath, destNpmpckgDirPath); - } else if (util.fsExistsSync(npmPckgSrcPath.concat('.js'))) { - fs.copySync(npmPckgSrcPath.concat('.js'), destNpmpckgDirPath.concat('.js')); - } + const destBasePath = path.join(config('paths').staging.stagingPath, config('paths').src.javascript, 'libs'); + // + // If npmPckgSrcPath is a directory (containing multiple files), + // then we need to copy the entire directory. + // + const destNpmpckgDirPath = `${destBasePath}/${npmPckgName}/${npmPckgInitFileName}`; + + if (util.fsExistsSync(npmPckgSrcPath)) { + fs.copySync(npmPckgSrcPath, destNpmpckgDirPath); + } else if (util.fsExistsSync(npmPckgSrcPath.concat('.js'))) { + fs.copySync(npmPckgSrcPath.concat('.js'), destNpmpckgDirPath.concat('.js')); } } - }); - util.log('Copy finished.'); - resolve(context); + } }); + util.log('Copy finished.'); + return Promise.resolve(context); }, diff --git a/lib/buildCommon/compileTypescript.js b/lib/buildCommon/compileTypescript.js index 46504a9..7c75395 100644 --- a/lib/buildCommon/compileTypescript.js +++ b/lib/buildCommon/compileTypescript.js @@ -1,10 +1,11 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ */ const fs = require('fs-extra'); +const { exec } = require('child_process'); const glob = require('glob'); const path = require('path'); const CONSTANTS = require('../constants'); @@ -124,6 +125,8 @@ function _compileComponentTypescript({ // run before_component_typescript hook () => hookRunner('before_component_typescript', context), // compile component typescript + () => _renameIndexFileInMonoPack({ context }), + // compile component typescript () => _runTypescriptCompilation({ context, pack, component }), // copy runtime resources to /js () => _runIfTypescriptCompilationSucceeded( @@ -160,6 +163,12 @@ function _compileComponentTypescript({ 'after_component_typescript', context ), + // generate API documentation if vcomponent + () => _runIfTypescriptCompilationSucceeded( + context, + _generateApiDocumentation, + { context } + ), // resolve with context () => _logTypescriptCompliationResult(context, `Compile ${componentName} typescript`) ]; @@ -223,6 +232,8 @@ function compileApplicationTypescript(context) { () => _setupTypescriptCompilation(context), // run before_app_typescript hook () => hookRunner('before_app_typescript', context), + // rename the index files in vcomponents in mono-packs + () => _renameIndexFileInMonoPack({ context }), // compile app typescript () => _runTypescriptCompilation({ context }), // copy runtime sources to /js @@ -262,6 +273,56 @@ function compileApplicationTypescript(context) { return util.runPromisesInSeries(promiseFunctions); } +/** + * ## _renameIndexFileInMonoPack + * + * renames the vcomponent index.ts file in a mono-pack to .ts, + * and copies it to the mono-pack root level: + * + * @private + * @param {object} context - build context + */ +function _renameIndexFileInMonoPack({ context }) { + const compositeComponents = context.opts.component ? [context.opts.component] : + util.getLocalCompositeComponents(); + compositeComponents.forEach((compositeComponent) => { + const componentJson = util.getComponentJson({ component: compositeComponent }); + if (componentJson.type && componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { + const vComponentsInMonoPack = util.getVComponentsInJETPack({ pack: compositeComponent }); + vComponentsInMonoPack.forEach((vComponent) => { + const pathToComponentInTsFolder = path.join( + context.opts.stagingPath, + 'ts', + context.paths.components, + compositeComponent, + context.opts[CONSTANTS.OMIT_COMPONENT_VERSION_FLAG] ? `${vComponent}` : + path.join(componentJson.version, vComponent) + ); + const pathToComponentWithoutTsFolder = path.join( + context.opts.stagingPath, + context.paths.components, + compositeComponent, + context.opts[CONSTANTS.OMIT_COMPONENT_VERSION_FLAG] ? `${vComponent}` : + path.join(componentJson.version, vComponent) + ); + const pathToComponentsInWeb = fs.existsSync(pathToComponentInTsFolder) ? + pathToComponentInTsFolder : pathToComponentWithoutTsFolder; + const pathToStubFile = `${pathToComponentsInWeb}.ts`; + const indexFile = path.join(pathToComponentsInWeb, 'index.ts'); + if (!fs.existsSync(pathToStubFile) && fs.existsSync(indexFile)) { + const indexFileContent = fs.readFileSync(indexFile, { encoding: 'utf-8' }); + fs.writeFileSync( + pathToStubFile, + indexFileContent.replace(`"./${vComponent}"`, `"./${vComponent}/${vComponent}"`) + ); + fs.removeSync(indexFile); + } + }); + } + }); + return Promise.resolve(context); +} + /** * ## _setupTypescriptCompilation * @@ -272,43 +333,54 @@ function compileApplicationTypescript(context) { * @param {object} context - build context */ function _setupTypescriptCompilation(context) { - return new Promise((resolve) => { - const configPaths = util.getConfiguredPaths(); - const tsconfigJson = util.readJsonAndReturnObject(CONSTANTS.TSCONFIG); - const typescriptOptions = context.opts.typescript; - const typescriptOptionsTsconfig = typescriptOptions.tsconfigJson; - // setup tsconfig.json - // eslint-disable-next-line no-param-reassign - tsconfigJson.include = typescriptOptionsTsconfig.include; - // eslint-disable-next-line no-param-reassign - tsconfigJson.exclude = typescriptOptionsTsconfig.exclude; - // eslint-disable-next-line no-param-reassign - tsconfigJson.compilerOptions.sourceMap = context.buildType === 'dev'; - // eslint-disable-next-line no-param-reassign - tsconfigJson.compilerOptions.paths = { - [`${configPaths.components}/*`]: [util.pathJoin( - '.', - context.opts.stagingPath, - configPaths.src.typescript, - configPaths.components, - '*' - )], - ...util.pointTypescriptPathMappingsToStaging({ - context, - pathMappings: tsconfigJson.compilerOptions.paths - }), - ...util.getLocalComponentPathMappings({ context }), - ...util.getExchangeComponentPathMappings({ context }) - }; + const configPaths = util.getConfiguredPaths(); + const tsconfigJson = util.readJsonAndReturnObject(CONSTANTS.TSCONFIG); + const typescriptOptions = context.opts.typescript; + const typescriptOptionsTsconfig = typescriptOptions.tsconfigJson; + // setup tsconfig.json + // eslint-disable-next-line no-param-reassign + tsconfigJson.include = typescriptOptionsTsconfig.include; + // eslint-disable-next-line no-param-reassign + tsconfigJson.exclude = typescriptOptionsTsconfig.exclude; + // eslint-disable-next-line no-param-reassign + tsconfigJson.compilerOptions.sourceMap = context.buildType === 'dev'; + // eslint-disable-next-line no-param-reassign + tsconfigJson.compilerOptions.paths = { + [`${configPaths.components}/*`]: [util.pathJoin( + '.', + context.opts.stagingPath, + configPaths.src.typescript, + configPaths.components, + '*' + )], + ...util.pointTypescriptPathMappingsToStaging({ + context, + pathMappings: tsconfigJson.compilerOptions.paths + }), + ...util.getLocalComponentPathMappings({ context }), + ...util.getExchangeComponentPathMappings({ context }) + }; + if (typescriptOptionsTsconfig.compilerOptions.rootDir) { // eslint-disable-next-line no-param-reassign tsconfigJson.compilerOptions.rootDir = typescriptOptionsTsconfig.compilerOptions.rootDir; + } + if (typescriptOptionsTsconfig.compilerOptions.outDir) { // eslint-disable-next-line no-param-reassign tsconfigJson.compilerOptions.outDir = typescriptOptionsTsconfig.compilerOptions.outDir; - // setup typescript options for hook + } + if (typescriptOptionsTsconfig.compilerOptions.strict) { // eslint-disable-next-line no-param-reassign - context.opts.typescript = { ...typescriptOptions, tsconfigJson }; - resolve(context); - }); + tsconfigJson.compilerOptions.strict = typescriptOptionsTsconfig.compilerOptions.strict; + } + if (typescriptOptionsTsconfig.compilerOptions.removeComments) { + // eslint-disable-next-line no-param-reassign + tsconfigJson.compilerOptions.removeComments = + typescriptOptionsTsconfig.compilerOptions.removeComments; + } + // setup typescript options for hook + // eslint-disable-next-line no-param-reassign + context.opts.typescript = { ...typescriptOptions, tsconfigJson }; + return Promise.resolve(context); } /** @@ -416,44 +488,42 @@ function _runTypescriptCompilation({ context, pack, component }) { * @returns {Promise} promise that resolves with build context */ function _copyTypescriptComponentFilesToJSFolder({ context, pack, component }) { - return new Promise((resolve) => { - const configPaths = util.getConfiguredPaths(); - const stagingPath = context.opts.stagingPath; - const typescriptFolder = configPaths.src.typescript; - const javascriptFolder = configPaths.src.javascript; - const componentName = pack ? `${pack}-${component}` : component; - const componentSrc = util.generatePathToComponentRoot({ - context, - pack, - component, - root: stagingPath, - scripts: typescriptFolder - }); - const componentDest = util.generatePathToComponentRoot({ - context, - pack, - component, - root: stagingPath, - scripts: javascriptFolder + const configPaths = util.getConfiguredPaths(); + const stagingPath = context.opts.stagingPath; + const typescriptFolder = configPaths.src.typescript; + const javascriptFolder = configPaths.src.javascript; + const componentName = pack ? `${pack}-${component}` : component; + const componentSrc = util.generatePathToComponentRoot({ + context, + pack, + component, + root: stagingPath, + scripts: typescriptFolder + }); + const componentDest = util.generatePathToComponentRoot({ + context, + pack, + component, + root: stagingPath, + scripts: javascriptFolder + }); + if (componentSrc !== componentDest) { + const files = glob.sync('**', { + cwd: componentSrc, + nodir: true, + ignore: ['**/*.ts', '**/*.tsx'] }); - if (componentSrc !== componentDest) { - const files = glob.sync('**', { - cwd: componentSrc, - nodir: true, - ignore: ['**/*.ts', '**/*.tsx'] + if (files.length) { + files.forEach((file) => { + fs.copySync( + path.join(componentSrc, file), + path.join(componentDest, file) + ); }); - if (files.length) { - files.forEach((file) => { - fs.copySync( - path.join(componentSrc, file), - path.join(componentDest, file) - ); - }); - util.log(`Copied ${componentName} runtime resources from ${componentSrc} to ${componentDest}`); - } + util.log(`Copied ${componentName} runtime resources from ${componentSrc} to ${componentDest}`); } - resolve(context); - }); + } + return Promise.resolve(context); } /** @@ -468,37 +538,35 @@ function _copyTypescriptComponentFilesToJSFolder({ context, pack, component }) { * @returns {Promise} promise that resolves with build context */ function _copyTypescriptApplicationFilesToJSFolder({ context }) { - return new Promise((resolve) => { - const configPaths = util.getConfiguredPaths(); - const stagingPath = context.opts.stagingPath; - const typescriptFolder = configPaths.src.typescript; - const javascriptFolder = configPaths.src.javascript; - const applicationSrc = path.join( - stagingPath, - typescriptFolder - ); - const applicationDest = path.join( - stagingPath, - javascriptFolder - ); - if (applicationSrc !== applicationDest) { - const files = glob.sync('**/*', { - cwd: applicationSrc, - nodir: true, - ignore: ['**/*.ts', '**/*.tsx', '**/components_dt/**'] + const configPaths = util.getConfiguredPaths(); + const stagingPath = context.opts.stagingPath; + const typescriptFolder = configPaths.src.typescript; + const javascriptFolder = configPaths.src.javascript; + const applicationSrc = path.join( + stagingPath, + typescriptFolder + ); + const applicationDest = path.join( + stagingPath, + javascriptFolder + ); + if (applicationSrc !== applicationDest) { + const files = glob.sync('**/*', { + cwd: applicationSrc, + nodir: true, + ignore: ['**/*.ts', '**/*.tsx', '**/components_dt/**'] + }); + if (files.length) { + files.forEach((file) => { + fs.copySync( + path.join(applicationSrc, file), + path.join(applicationDest, file) + ); }); - if (files.length) { - files.forEach((file) => { - fs.copySync( - path.join(applicationSrc, file), - path.join(applicationDest, file) - ); - }); - util.log(`Copied runtime resources from /${typescriptFolder} to /${javascriptFolder}`); - } + util.log(`Copied runtime resources from /${typescriptFolder} to /${javascriptFolder}`); } - resolve(context); - }); + } + return Promise.resolve(context); } /** @@ -514,107 +582,222 @@ function _copyTypescriptApplicationFilesToJSFolder({ context }) { * @returns {Promise} promise that resolves with build context */ function _copyVComponentComponentJsonToJs({ context }) { - return new Promise((resolve) => { - const configPaths = util.getConfiguredPaths(); - const componentsDtBaseSrcPath = util.pathJoin( - context.opts.stagingPath, - configPaths.src.typescript, - CONSTANTS.COMPONENTS_DT, - ); - if (fs.existsSync(componentsDtBaseSrcPath)) { - const { pack, component } = context.opts.typescript; - let files = []; - if (component) { - if (context.serving && util.isVComponent({ pack, component })) { - // changed component during "ojet serve", is a singleton or pack vcomponent - const componentJsonPath = path.join(componentsDtBaseSrcPath, `${pack ? `${pack}-` : ''}${component}.json`); - if (util.fsExistsSync(componentJsonPath)) { - files.push(componentJsonPath); - } else { - util.log.warning(`${componentJsonPath} does not exist`); - } - } else if (!context.serving) { - // running "ojet build component" which builds a singleton or pack component - if (util.isJETPack({ pack: component })) { - // is a pack, check if it contains vcomponents - util.getVComponentsInJETPack({ pack: component }).forEach((vcomponent) => { - const componentJsonPath = path.join(componentsDtBaseSrcPath, `${component}-${vcomponent}.json`); - if (util.fsExistsSync(componentJsonPath)) { - files.push(componentJsonPath); - } else { - util.log.error(`${componentJsonPath} does not exist`); - } - }); - } else if (util.isVComponent({ component })) { - // is a singleton vcomponent - const componentJsonPath = path.join(componentsDtBaseSrcPath, `${component}.json`); + const configPaths = util.getConfiguredPaths(); + const componentsDtBaseSrcPath = util.pathJoin( + context.opts.stagingPath, + configPaths.src.typescript, + CONSTANTS.COMPONENTS_DT, + ); + if (fs.existsSync(componentsDtBaseSrcPath)) { + const { pack, component } = context.opts.typescript; + let files = []; + if (component) { + if (context.serving && util.isVComponent({ pack, component })) { + // changed component during "ojet serve", is a singleton or pack vcomponent + const componentJsonPath = path.join(componentsDtBaseSrcPath, `${pack ? `${pack}-` : ''}${component}.json`); + if (util.fsExistsSync(componentJsonPath)) { + files.push(componentJsonPath); + } else { + util.log.warning(`${componentJsonPath} does not exist`); + } + } else if (!context.serving) { + // running "ojet build component" which builds a singleton or pack component + if (util.isJETPack({ pack: component })) { + // is a pack, check if it contains vcomponents + util.getVComponentsInJETPack({ pack: component }).forEach((vcomponent) => { + const componentJsonPath = path.join(componentsDtBaseSrcPath, `${component}-${vcomponent}.json`); if (util.fsExistsSync(componentJsonPath)) { files.push(componentJsonPath); } else { util.log.error(`${componentJsonPath} does not exist`); } + }); + } else if (util.isVComponent({ component })) { + // is a singleton vcomponent + const componentJsonPath = path.join(componentsDtBaseSrcPath, `${component}.json`); + if (util.fsExistsSync(componentJsonPath)) { + files.push(componentJsonPath); + } else { + util.log.error(`${componentJsonPath} does not exist`); } } - } else { - // get all *.json files in components_dt - files = glob.sync(path.join(componentsDtBaseSrcPath, '*.json')); } - files.forEach((filepath) => { - let componentJson = util.readJsonAndReturnObject(filepath); - const componentsCache = util.getComponentsCache(); - // VDOM architecture supports components where the component.json is not needed. - // For example, we can have src/components/app.tsx which contains a custom element - // vcomponent used to define the HTML of the app. Because it is a custom element vcomponent, - // the compiler will create a *.json file for it in components_dt - // but we don't care about it. We verify this - // by checking the cache which contains entries for all "valid" components - // Due to change in component json generation by custom-tsc, if the simple - // componentJson.name isn't found in the cache, then try the custom element - // tag name (componentJson.pack-componentJson.name) - const fullComponentName = (componentsCache[componentJson.name] || !componentJson.pack) ? - componentJson.name : `${componentJson.pack}-${componentJson.name}`; + } else { + // get all *.json files in components_dt + files = glob.sync(path.join(componentsDtBaseSrcPath, '*.json')); + } + files.forEach((filepath) => { + let componentJson = util.readJsonAndReturnObject(filepath); + const componentsCache = util.getComponentsCache(); + // VDOM architecture supports components where the component.json is not needed. + // For example, we can have src/components/app.tsx which contains a custom element + // vcomponent used to define the HTML of the app. Because it is a custom element vcomponent, + // the compiler will create a *.json file for it in components_dt + // but we don't care about it. We verify this + // by checking the cache which contains entries for all "valid" components + // Due to change in component json generation by custom-tsc, if the simple + // componentJson.name isn't found in the cache, then try the custom element + // tag name (componentJson.pack-componentJson.name) + const fullComponentName = (componentsCache[componentJson.name] || !componentJson.pack) ? + componentJson.name : `${componentJson.pack}-${componentJson.name}`; - if (componentsCache[fullComponentName]) { - // Update component's component.json in cache + if (componentsCache[fullComponentName]) { + // Update component's component.json in cache. Note that the order of the spread + // operator changes depending on the type of the pack the component is part of. + // For the mono-packs, there is an added implementation for JET-48251 that ensures + // that the emitted metadata from the custom_tsc is corrected in case the annotated + // ojmetadata properties values in the .tsx have incorrect values. + // Therefore, the corrected info in componentJson with the same keys in it as in the cache + // should take precedence in updating the componentCache. Otherwise, for non-mono-packs, + // the data already in the cache should be the one referred to. + const packName = componentsCache[fullComponentName].componentJson.pack; + if (packName && + componentsCache[packName].componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { componentsCache[fullComponentName].componentJson = { + ...componentsCache[fullComponentName].componentJson, ...componentJson, - ...componentsCache[fullComponentName].componentJson }; - componentJson = componentsCache[fullComponentName].componentJson; - const componentJsonDestPath = path.join( - util.generatePathToComponentRoot({ - context, - pack: componentJson.pack, - component: componentJson.name, - root: context.opts.stagingPath, - scripts: configPaths.src.javascript - }), - CONSTANTS.JET_COMPONENT_JSON - ); - // TODO: in next major release, stop writing component.json since - // it will be written after runAllComponentHooks - util.writeObjectAsJsonFile(componentJsonDestPath, componentJson); - util.log(`Copied ${filepath} to ${componentJsonDestPath}`); + } else { + componentsCache[fullComponentName].componentJson = { + ...componentJson, + ...componentsCache[fullComponentName].componentJson, + }; } + componentJson = componentsCache[fullComponentName].componentJson; + const componentJsonDestPath = path.join( + util.generatePathToComponentRoot({ + context, + pack: componentJson.pack, + component: componentJson.name, + root: context.opts.stagingPath, + scripts: configPaths.src.javascript + }), + CONSTANTS.JET_COMPONENT_JSON + ); + // TODO: in next major release, stop writing component.json since + // it will be written after runAllComponentHooks + util.writeObjectAsJsonFile(componentJsonDestPath, componentJson); + util.log(`Copied ${filepath} to ${componentJsonDestPath}`); + } + }); + } + return Promise.resolve(context); +} + +/** + * ## _generateApiDocumentation + * + * Generates the vcomponent API docs + * + * @private + * @param {object} options.context build context + * @returns {Promise} promise that resolves with build context + */ +function _generateApiDocumentation({ context }) { + // eslint-disable-next-line consistent-return + return new Promise((resolve, reject) => { + let isVComponent; + let componentName; + let vComponentsInPack = []; + const { component, pack } = context.opts.typescript; + if (component && !pack) { + // It might be the case that the passed component is a pack + // or stand-alone component. Therefore, we need to check if + // it's a pack with vcomponents or just a stand-alone vcomponent + componentName = component; + isVComponent = util.isVComponent({ component }); + if (util.isJETPack({ pack: component })) { + vComponentsInPack = util.getVComponentsInJETPack({ pack: component }); + } + } else if (component && pack) { + // In this case, we have a component in a pack. Just retrieve + // vcomponents in the pack to generate the docs for. + componentName = pack; + vComponentsInPack = util.getVComponentsInJETPack({ pack }); + } + // The APIs should be generated for vcomponents only: + if (util.hasJsdocInstalled() && (isVComponent || vComponentsInPack !== 0)) { + if (isVComponent && vComponentsInPack.length === 0) { + console.log(`Generating API docs for vcomponent ${component}.`); + } else if (vComponentsInPack !== 0) { + vComponentsInPack.forEach((vcomponent) => { + console.log(`Generating API docs for vcomponent ${vcomponent} in ${pack}.`); + }); + } + const { command, templatesFolder } = _getExecCallParameters(context, componentName); + exec(command, { cwd: templatesFolder }, (error) => { + if (error) { + console.error(`Unexpected error happened while generating the API Doc: ${error}`); + return reject(error); + } + return resolve(context); }); + } else { + // eslint-disable-next-line consistent-return + return resolve(context); } - resolve(context); }); } +/** + * ## __getExecCallParameters + * + * Generates the parameters for jsdoc execution call + * + * @private + * @param {string} component + * @param {object} context + * @returns {Object} containing path to config file and destination folder + */ +function _getExecCallParameters(context, component) { + const srcPath = path.resolve(util.getComponentPath({ context, component, built: true })); + const templatesFolder = path.resolve(util.getOraclejetPath(), CONSTANTS.PATH_TO_JSDOC); + // Ensure that the destination folder is docs: + const { pathToConfigFile, destPath } = _modifyConfigFileInStaging(srcPath, templatesFolder); + const jsdocFile = path.join(process.cwd(), CONSTANTS.NODE_MODULES_DIRECTORY, 'jsdoc', 'jsdoc.js'); + const params = `"docletSource=${srcPath}&destination=${destPath}"`; + const command = `node ${jsdocFile} -c ${pathToConfigFile} -q ${params}`; + return { command, templatesFolder }; +} + +/** + * ## _modifyConfigFileInStaging + * + * Ensure that the destination folder for the generated APIs is docs + * + * @private + * @param {string} srcPath + * @returns {Object} containing path to config file and destination folder + */ +function _modifyConfigFileInStaging(srcPath, templatesFolder) { + let destPath; + let pathToConfigFile; + try { + // Read the config file copied to staging: + pathToConfigFile = path.join(templatesFolder, CONSTANTS.JSDOC_CONFIG_JSON); + const configFileContent = fs.readJSONSync(pathToConfigFile); + // Modify the config json to ensure the destination folder for generated files is docs: + configFileContent.opts.destination = './docs'; + fs.writeJSONSync(pathToConfigFile, configFileContent, { encoding: 'utf-8' }); + // Create docs path in staging: + destPath = path.join(srcPath, 'docs'); + } catch (error) { + util.log.error(`Modifying config file staging failed with error: ${error}`); + } + return { pathToConfigFile, destPath }; +} + function _deleteVComponentComponentsDt({ context }) { - return new Promise((resolve) => { - const configPaths = util.getConfiguredPaths(); - const pathToComponentsDt = util.pathJoin( - context.opts.stagingPath, - configPaths.src.typescript, - CONSTANTS.COMPONENTS_DT, - ); - if (fs.existsSync(pathToComponentsDt)) { - fs.removeSync(pathToComponentsDt); - } - resolve(context); - }); + const configPaths = util.getConfiguredPaths(); + const pathToComponentsDt = util.pathJoin( + context.opts.stagingPath, + configPaths.src.typescript, + CONSTANTS.COMPONENTS_DT, + ); + if (fs.existsSync(pathToComponentsDt)) { + fs.removeSync(pathToComponentsDt); + } + return Promise.resolve(context); } /** @@ -628,74 +811,82 @@ function _deleteVComponentComponentsDt({ context }) { * @returns {Promise} promise that resolves with build context */ function _organizeComponentsTypeDefinitions({ context }) { - return new Promise((resolve) => { - // only organize type definition files if declaration option - // set to true - const typescriptOptions = context.opts.typescript; - if (typescriptOptions.tsconfigJson.compilerOptions.declaration) { - const componentsCache = util.getComponentsCache(); - const { pack, component } = typescriptOptions; - if (pack && component) { - // only organize pack component's type definitions - const componentCache = componentsCache[`${pack}-${component}`]; - if (componentCache && - (componentCache.isTypescriptComponent || componentCache.isVComponent)) { - _organizePackComponentTypeDefinitions({ context, pack, component }); - } - } else if (component) { - // component can either be a singleton or a pack - const componentCache = componentsCache[component]; - if (componentCache && componentCache.componentJson.type === 'pack') { - // component is pack (build initiated by ojet build component ) - Object.keys(componentsCache) - .filter((fullComponentName) => { - const hasPackPrefix = fullComponentName.startsWith(component); - return hasPackPrefix && fullComponentName !== component; - }).forEach((fullComponentName) => { - const { - isTypescriptComponent, - isVComponent, - componentJson - } = componentsCache[fullComponentName]; - if (isTypescriptComponent || isVComponent) { - _organizePackComponentTypeDefinitions({ - context, - pack: componentJson.pack, - component: componentJson.name - }); - } - }); - } else if (componentCache && - componentCache.componentJson.type !== 'pack' && - (componentCache.isTypescriptComponent || componentCache.isVComponent)) { - // component is a singleton - _organizeSingletonComponentTypeDefinitions({ context, component }); - } - } else { - // organize the type definitions of all components - Object.keys(componentsCache).forEach((fullComponentName) => { - const componentCache = componentsCache[fullComponentName]; - if (componentCache && - (componentCache.isTypescriptComponent || componentCache.isVComponent)) { - const { componentJson } = componentCache; - if (componentJson.pack) { + // only organize type definition files if declaration option + // set to true + const typescriptOptions = context.opts.typescript; + if (typescriptOptions.tsconfigJson.compilerOptions.declaration) { + const componentsCache = util.getComponentsCache(); + const { pack, component } = typescriptOptions; + if (pack && component) { + // only organize pack component's type definitions + const componentCache = componentsCache[`${pack}-${component}`]; + if (componentCache && + (componentCache.isTypescriptComponent || componentCache.isVComponent)) { + _organizePackComponentTypeDefinitions({ context, pack, component }); + } + } else if (component) { + // component can either be a singleton or a pack + const componentCache = componentsCache[component]; + if (componentCache && (componentCache.componentJson.type === 'pack' || + componentCache.componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK)) { + // component is pack (build initiated by ojet build component ) + Object.keys(componentsCache) + .filter((fullComponentName) => { + const hasPackPrefix = fullComponentName.startsWith(component); + return hasPackPrefix && fullComponentName !== component; + }).forEach((fullComponentName) => { + const { + isTypescriptComponent, + isVComponent, + componentJson + } = componentsCache[fullComponentName]; + if (isTypescriptComponent || isVComponent) { _organizePackComponentTypeDefinitions({ context, pack: componentJson.pack, component: componentJson.name }); - } else if (componentJson.type !== 'pack') { - _organizeSingletonComponentTypeDefinitions({ - context, - component: componentJson.name - }); } - } - }); + }); + } else if (componentCache && + componentCache.componentJson.type !== 'pack' && + componentCache.componentJson.type !== CONSTANTS.PACK_TYPE.MONO_PACK && + (componentCache.isTypescriptComponent || componentCache.isVComponent)) { + // component is a singleton + _organizeSingletonComponentTypeDefinitions({ context, component }); } + } else { + // organize the type definitions of all components + Object.keys(componentsCache).forEach((fullComponentName) => { + const componentCache = componentsCache[fullComponentName]; + if (componentCache && + (componentCache.isTypescriptComponent || componentCache.isVComponent)) { + const { componentJson } = componentCache; + if (componentJson.pack) { + _organizePackComponentTypeDefinitions({ + context, + pack: componentJson.pack, + component: componentJson.name + }); + } else if (componentJson.type !== 'pack' && componentJson.type !== CONSTANTS.PACK_TYPE.MONO_PACK) { + _organizeSingletonComponentTypeDefinitions({ + context, + component: componentJson.name + }); + } + } + }); } - resolve(context); - }); + // Go through the packs' root level and move any d.ts files of non-component pack's + // content to the types folder. + Object.keys(componentsCache).forEach((fullComponentName) => { + const componentJson = componentsCache[fullComponentName].componentJson; + if (componentJson && (componentJson.type === 'pack' || componentJson.type === 'mono-pack')) { + _organizePackNonComponentTypeDefinitions({ context, pack: componentJson.name }); + } + }); + } + return Promise.resolve(context); } /** @@ -737,6 +928,62 @@ function _organizePackComponentTypeDefinitions({ context, pack, component }) { } } +/** + * ## _organizePackNonComponentTypeDefinitions + * + * Organizes type definitions of non-component pack's + * content since we now also allow processing of pack's fo- + * lders which are not components. For normal packs, the + * folders could be extension and/or utils while for + * mono-packs any other needed by the pack or stub files. + * + * @private + * @param {object} options.context + * @param {string} options.pack + */ +function _organizePackNonComponentTypeDefinitions({ context, pack }) { + const configPaths = util.getConfiguredPaths(); + const builtPackPath = util.generatePathToComponentRoot({ + context, + component: pack, + root: context.opts.stagingPath, + scripts: configPaths.src.javascript + }); + const componentTypesFolder = path.join(builtPackPath, 'types'); + if (fs.existsSync(componentTypesFolder)) { + glob.sync( + path.join(builtPackPath, '**/*.d.ts'), + { ignore: ['**/types/**', '**/min/**'] } + ).forEach((filePath) => { + // copy *.d.ts files to types folder + if (util.fsExistsSync(path.join( + componentTypesFolder, + path.relative(builtPackPath, filePath) + ))) { + // already exists in types folder, delete + fs.removeSync(filePath); + } else { + // not in types folder, move into + fs.moveSync(filePath, path.join( + componentTypesFolder, + path.relative(builtPackPath, filePath) + )); + } + }); + } else { + glob.sync( + path.join(builtPackPath, '**/*.d.ts'), + { ignore: ['**/min/**'] } + ).forEach((filePath) => { + // copy *.d.ts files to types folder + fs.moveSync(filePath, path.join( + componentTypesFolder, + path.relative(builtPackPath, filePath) + )); + }); + } +} + /** * ## _organizeSingletonComponentTypeDefinitions * @@ -879,38 +1126,36 @@ function cleanTypescript(context) { if (util.shouldNotRunTypescriptTasks(context)) { return Promise.resolve(context); } - return new Promise((resolve) => { - util.log('Cleaning Typescript staging directory'); - const configPaths = util.getConfiguredPaths(); - const stagingPath = path.normalize(context.opts.stagingPath); - const typescriptStagingPath = path.join(stagingPath, configPaths.src.typescript); - const javascriptStagingPath = path.join(stagingPath, configPaths.src.javascript); - let filePaths; - if (stagingPath !== typescriptStagingPath) { - filePaths = [ - // add / - typescriptStagingPath, - // add *.d.ts files in / - ...glob.sync( - `${javascriptStagingPath}/**/*.d.ts`, - { ignore: ['libs/**', '**/types/**'] } - ) - ]; - } else { - // add *.ts files in - filePaths = glob.sync( - `${stagingPath}/**/*.{ts,tsx}`, + util.log('Cleaning Typescript staging directory'); + const configPaths = util.getConfiguredPaths(); + const stagingPath = path.normalize(context.opts.stagingPath); + const typescriptStagingPath = path.join(stagingPath, configPaths.src.typescript); + const javascriptStagingPath = path.join(stagingPath, configPaths.src.javascript); + let filePaths; + if (stagingPath !== typescriptStagingPath) { + filePaths = [ + // add / + typescriptStagingPath, + // add *.d.ts files in / + ...glob.sync( + `${javascriptStagingPath}/**/*.d.ts`, { ignore: ['libs/**', '**/types/**'] } - ); - } - if (filePaths.length) { - filePaths.forEach((filePath) => { - fs.removeSync(filePath); - }); - util.log('Cleaning Typescript staging directory finished'); - } - resolve(context); - }); + ) + ]; + } else { + // add *.ts files in + filePaths = glob.sync( + `${stagingPath}/**/*.{ts,tsx}`, + { ignore: ['libs/**', '**/types/**'] } + ); + } + if (filePaths.length) { + filePaths.forEach((filePath) => { + fs.removeSync(filePath); + }); + util.log('Cleaning Typescript staging directory finished'); + } + return Promise.resolve(context); } module.exports = { diff --git a/lib/buildCommon/copyLocalComponent.js b/lib/buildCommon/copyLocalComponent.js index 4d4b855..f479d8e 100644 --- a/lib/buildCommon/copyLocalComponent.js +++ b/lib/buildCommon/copyLocalComponent.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -10,6 +10,8 @@ const util = require('../util'); const fs = require('fs-extra'); const CONSTANTS = require('../constants'); +const _ = {}; +_.union = require('lodash.union'); /** * ## copyLocalComponent * @@ -41,8 +43,18 @@ function copyLocalComponent({ context, componentName, componentJson }) { context.opts[CONSTANTS.OMIT_COMPONENT_VERSION_FLAG] ? '' : componentJson.version ); if (util.isJETPack({ componentJson })) { - // only copy top-level jet pack files e.g component.json - util.getFiles(srcPath).forEach((fileInPath) => { + // Only copy top-level jet pack files (e.g component.json) and the extension and + // utils folders. However, it is legitimate that the packaged folder structure for + // the mono-pack zip file contains extra folders as not all of the modules exposed + // by the mono-pack are necessarily within composite components or resource compo- + // nents. Therefore, do not filter directories in mono-packs when copying its con- + // tents. + const pathContentArray = _.union( + util.getFiles(srcPath), + componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK ? fs.readdirSync(srcPath) : + fs.readdirSync(srcPath).filter(item => item === 'extension' || item === 'utils') + ); + pathContentArray.forEach((fileInPath) => { fs.copySync( path.join(srcPath, fileInPath), path.join(destPath, fileInPath), @@ -51,8 +63,20 @@ function copyLocalComponent({ context, componentName, componentJson }) { }); const packName = componentName; const componentsCache = util.getComponentsCache(); - if (util.hasProperty(componentsCache[packName].componentJson, 'dependencies')) { - Object.keys(componentsCache[packName].componentJson.dependencies).forEach((packMemberName) => { // eslint-disable-line max-len + const packComponentJson = componentsCache[packName].componentJson; + if (util.hasProperty(packComponentJson, 'dependencies')) { + let packMemberNameList; + // In mono-pack, we do not add entries in the dependencies for + // components in the same pack. However, since the entries are + // used below to retrieve the componentCache for the respective + // component, then we need to generate the pack member list: + if (packComponentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { + packMemberNameList = _.union(util.getMonoPackMemberNameList(packComponentJson), + Object.keys(packComponentJson.dependencies)); + } else { + packMemberNameList = Object.keys(packComponentJson.dependencies); + } + packMemberNameList.forEach((packMemberName) => { // eslint-disable-line max-len if (packMemberName.startsWith(packName)) { const componentCache = componentsCache[packMemberName]; if (!componentCache) { @@ -74,7 +98,13 @@ function copyLocalComponent({ context, componentName, componentJson }) { }).stage() ); } else { - util.log.error(`Missing pack prefix for component ${packMemberName} in ${packName}`); + // eslint-disable-next-line no-lonely-if + if (componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { + // Do not do anything. It is possible that other pack + // prefix can be in the mono-pack dependencies object. + } else { + util.log.error(`Missing pack prefix for component ${packMemberName} in ${packName}`); + } } }); } @@ -150,7 +180,7 @@ class PackComponentJsonValidator extends ComponentJsonValidator { if (componentJson.pack !== packName) { util.log.error(`${packName} does not match the 'pack' field of ${componentName}'s component.json.`); } - if (packName && componentJson.type === 'pack') { + if (packName && (componentJson.type === 'pack' || componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK)) { util.log.error(`A pack within a pack is not supported (pack ${packName}, component ${componentJson.name})`); } } diff --git a/lib/buildCommon/generateComponentsCache.js b/lib/buildCommon/generateComponentsCache.js index f915e4d..7eccfb9 100644 --- a/lib/buildCommon/generateComponentsCache.js +++ b/lib/buildCommon/generateComponentsCache.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -65,15 +65,22 @@ function generateComponentsCache({ context }) { componentJson, componentPath }); - if (type === 'pack') { + if (type === 'pack' || type === CONSTANTS.PACK_TYPE.MONO_PACK) { const packName = componentName; const hasDependenciesToken = util.hasDependenciesToken(componentJson); if (hasDependenciesToken) { componentJson.dependencies = {}; } - getComponentsInDirectory({ - directory: path.join(componentBasePath, packName) - }).forEach((componentInPack) => { + // eslint-disable-next-line max-len + const componentsInPack = getComponentsInDirectory({ directory: path.join(componentBasePath, packName) }); + const monoPackDependencies = []; + // We need the what would be mono-pack dependencies in the form + // for components in the mono-pack. We use this info to promote depencies in the components + // from the mono-pack whose pack is not mono-pack: + componentsInPack.forEach((componentInPack) => { + monoPackDependencies.push(`${packName}-${componentInPack}`); + }); + componentsInPack.forEach((componentInPack) => { const componentInPackPath = path.join(componentBasePath, packName, componentInPack); const componentInPackComponentJson = util.getComponentJson({ context, @@ -81,7 +88,8 @@ function generateComponentsCache({ context }) { pack: packName }); const { name: componentInPackName } = componentInPackComponentJson; - if (componentInPackComponentJson.type === 'pack') { + if (componentInPackComponentJson.type === 'pack' || + componentInPackComponentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { util.log.error(`Cannot have a component of type "pack" within a pack: ${packName}/${componentInPackName} `); } const fullComponentName = `${packName}-${componentInPackName}`; @@ -99,7 +107,12 @@ function generateComponentsCache({ context }) { if (util.hasMissingProperty(componentInPackComponentJson, 'pack')) { componentInPackComponentJson.pack = packName; } - if (hasDependenciesToken) { + // eslint-disable-next-line max-len + if (type === CONSTANTS.PACK_TYPE.MONO_PACK) { + // eslint-disable-next-line max-len + promoteDependencyInMonoPack(monoPackDependencies, componentInPackComponentJson, packCompJson); + } + if (hasDependenciesToken && type !== CONSTANTS.PACK_TYPE.MONO_PACK) { packCompJson.dependencies[fullComponentName] = componentInPackComponentJson.version; } componentsCache[fullComponentName] = generateComponentCache({ @@ -264,4 +277,27 @@ function isLocalComponent({ componentPath }) { return componentPath.startsWith(configPaths.src.common); } +/** + * ## promoteDependencyInMonoPack + * This will ensure that only the dependencies which are not + * of the components from the same mono-pack are included in + * the mono-pack dependencies object. + * @param {Array} monoPackDependencies + * @param {object} componentJson + * @param {object} packComponentJson + * + */ +function promoteDependencyInMonoPack(monoPackDependencies, componentJson, packComponentJson) { + const componentDependencies = componentJson.dependencies; + const dependenciesNames = new Set(monoPackDependencies); + // eslint-disable-next-line max-len + const dependenciesArray = componentDependencies ? Object.getOwnPropertyNames(componentDependencies) : []; + dependenciesArray.forEach((dependency) => { + if (!dependenciesNames.has(dependency) && packComponentJson.dependencies) { + // eslint-disable-next-line no-param-reassign + packComponentJson.dependencies[dependency] = componentDependencies[dependency]; + } + }); +} + module.exports = generateComponentsCache; diff --git a/lib/buildCommon/minifyComponent.js b/lib/buildCommon/minifyComponent.js index 7bc0d66..aa82bd5 100644 --- a/lib/buildCommon/minifyComponent.js +++ b/lib/buildCommon/minifyComponent.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -9,6 +9,9 @@ const util = require('../util'); const optimizeComponent = require('./optimizeComponent'); const CONSTANTS = require('../constants'); +const _ = {}; +_.union = require('lodash.union'); + class ComponentMinifier { /** * @@ -46,7 +49,8 @@ class ComponentMinifier { .forEach((dependency) => { const dependencyComponentCache = componentsCache[dependency]; if (dependencyComponentCache) { - if (dependencyComponentCache.componentJson.type === 'pack') { + if (dependencyComponentCache.componentJson.type === 'pack' || + dependencyComponentCache.componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { util.log.error(`Cannot have a dependency on a pack (${dependency}).`); } if ( @@ -142,10 +146,36 @@ class PackComponentMinifier extends ComponentMinifier { } generateRjsOptions() { const { baseUrl, componentJson, destPath } = this; + let outputPath; + let namePath; + // With loaderless components, the minimized component js and map files should be under the + // root of the min folder: destpath is of the format web/..//../min/. + // However, users can decide to select the output file to which the minified version will be + // emitted to. This could be done by adding the path segments in the ojmetadata main property, + // ending up in the component.json' main attribute. Possible main attribute values are + // main: /; + // //loader; + // //; + if (componentJson.main) { + if (componentJson.main === `${componentJson.pack}/${componentJson.name}`) { + outputPath = `${destPath}.js`; + namePath = `${componentJson.pack}/${componentJson.name}/${componentJson.name}`; + } else if (componentJson.main === `${componentJson.pack}/${componentJson.name}/loader`) { + outputPath = path.join(destPath, 'loader.js'); + namePath = `${componentJson.pack}/${componentJson.name}/loader`; + } else { + const pathSegments = componentJson.main.split('/'); + outputPath = path.join(destPath, `${pathSegments[2]}.js`); + namePath = `${componentJson.pack}/${componentJson.name}/${pathSegments[2]}`; + } + } else { + outputPath = path.join(destPath, 'loader.js'); + namePath = `${componentJson.pack}/${componentJson.name}/loader`; + } return { baseUrl, - name: `${componentJson.pack}/${componentJson.name}/loader`, - out: path.join(destPath, 'loader.js') + name: namePath, + out: outputPath }; } } @@ -389,7 +419,7 @@ function minifyComponent({ context, componentJson, componentName, destBase }) { context, componentJson }).generateMinificationFunction()); - } else if (componentHasType && componentType === 'pack') { + } else if (componentHasType && (componentType === 'pack' || componentType === CONSTANTS.PACK_TYPE.MONO_PACK)) { const packComponentJson = componentJson; const packVersion = context.opts[CONSTANTS.OMIT_COMPONENT_VERSION_FLAG] ? '' : packComponentJson.version; const packName = util.hasProperty(packComponentJson, 'name') && packComponentJson.name; @@ -397,7 +427,18 @@ function minifyComponent({ context, componentJson, componentName, destBase }) { util.log.error('Missing "name" property for pack.'); } if (util.hasProperty(packComponentJson, 'dependencies')) { - Object.keys(packComponentJson.dependencies).forEach((packMember) => { + let packMemberNameList; + // In mono-pack, we do not add entries in the dependencies for + // components in the same pack. However, since the entries are + // used below to retrieve the componentCache for the respective + // component, then we need to generate the pack member list: + if (packComponentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { + packMemberNameList = _.union(util.getMonoPackMemberNameList(packComponentJson), + Object.keys(packComponentJson.dependencies)); + } else { + packMemberNameList = Object.keys(packComponentJson.dependencies); + } + packMemberNameList.forEach((packMember) => { if (packMember.startsWith(packName)) { const packComponentName = packMember.substring(packName.length + 1); const packMemberComponentJson = util.readJsonAndReturnObject(path.join( @@ -426,6 +467,9 @@ function minifyComponent({ context, componentJson, componentName, destBase }) { case 'pack': util.log.error(`Cannot have a pack (${packMember}) listed as a dependency of a pack (${packName}).`); break; + case CONSTANTS.PACK_TYPE.MONO_PACK: + util.log.error(`Cannot have a mono-pack (${packMember}) listed as a dependency of a mono-pack (${packName}).`); + break; default: break; } @@ -451,4 +495,3 @@ function minifyComponent({ context, componentJson, componentName, destBase }) { } module.exports = minifyComponent; - diff --git a/lib/buildCommon/optimizeComponent.js b/lib/buildCommon/optimizeComponent.js index dc618a7..408b9bd 100644 --- a/lib/buildCommon/optimizeComponent.js +++ b/lib/buildCommon/optimizeComponent.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -70,45 +70,43 @@ function optimizeComponentSetup({ extraExcludes, extraEmpties }) { - return new Promise((resolve, reject) => { - try { - const pathMappings = pathGenerator.getMasterPathsMapping(context, true); - const rConfig = { - ...rjsOptions, - optimize: context.opts.requireJsComponent.optimize, - buildCSS: context.opts.requireJsComponent.buildCSS, - separateCSS: context.opts.requireJsComponent.separateCSS, - generateSourceMaps: context.opts.requireJsComponent.generateSourceMaps - }; - const exclude = ['css', 'ojcss', 'ojs/ojcss', 'ojL10n', 'text', 'normalize', 'ojs/normalize', 'css-builder']; - if (extraExcludes) { - extraExcludes.forEach((extraExclude) => { - pathMappings[extraExclude] = 'empty:'; - exclude.push(extraExclude); - }); - } - Object.keys(pathMappings).forEach((lib) => { - if (!exclude.includes(lib)) { - pathMappings[lib] = 'empty:'; - } + try { + const pathMappings = pathGenerator.getMasterPathsMapping(context, true); + const rConfig = { + ...rjsOptions, + optimize: context.opts.requireJsComponent.optimize, + buildCSS: context.opts.requireJsComponent.buildCSS, + separateCSS: context.opts.requireJsComponent.separateCSS, + generateSourceMaps: context.opts.requireJsComponent.generateSourceMaps + }; + const exclude = ['css', 'ojcss', 'ojs/ojcss', 'ojL10n', 'text', 'normalize', 'ojs/normalize', 'css-builder']; + if (extraExcludes) { + extraExcludes.forEach((extraExclude) => { + pathMappings[extraExclude] = 'empty:'; + exclude.push(extraExclude); }); - if (extraEmpties) { - extraEmpties.forEach((extraEmpty) => { - pathMappings[extraEmpty] = 'empty:'; - }); - } - rConfig.paths = pathMappings; - rConfig.exclude = exclude; - if (root) { - rConfig.paths[root] = '.'; + } + Object.keys(pathMappings).forEach((lib) => { + if (!exclude.includes(lib)) { + pathMappings[lib] = 'empty:'; } - // eslint-disable-next-line no-param-reassign - context.opts.componentRequireJs = rConfig; - resolve(context); - } catch (error) { - reject(error); + }); + if (extraEmpties) { + extraEmpties.forEach((extraEmpty) => { + pathMappings[extraEmpty] = 'empty:'; + }); } - }); + rConfig.paths = pathMappings; + rConfig.exclude = exclude; + if (root) { + rConfig.paths[root] = '.'; + } + // eslint-disable-next-line no-param-reassign + context.opts.componentRequireJs = rConfig; + return Promise.resolve(context); + } catch (error) { + return Promise.reject(error); + } } /** @@ -141,13 +139,19 @@ function optimizeComponentInvoker({ context, rjsOptions, tempBundleFile }) { !context.opts.componentRequireJs.out.endsWith(loaderSignature)) { minifyFile = context.opts.componentRequireJs.out; } + // If a special copyTo filename is set, copy the file before terser minifies + // it up to that location + if (context.opts.componentRequireJs.copyTo) { + fs.copyFileSync(minifyFile, context.opts.componentRequireJs.copyTo); + } util.minifyFiles({ files: [{ dest: minifyFile, src: minifyFile }], options: context.opts.terser.options, generateSourceMaps: true, minify: true }).then(() => { - if (tempBundleFile && fs.existsSync(tempBundleFile)) { + if (tempBundleFile && fs.existsSync(tempBundleFile) && + tempBundleFile !== context.opts.componentRequireJs.copyTo) { fs.removeSync(tempBundleFile); } resolve(context); diff --git a/lib/buildCommon/restoreLocalComponentJson.js b/lib/buildCommon/restoreLocalComponentJson.js index 6ec7d17..6780287 100644 --- a/lib/buildCommon/restoreLocalComponentJson.js +++ b/lib/buildCommon/restoreLocalComponentJson.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -14,26 +14,24 @@ const path = require('path'); * location after calling stripLocalComponentJson in buildWeb: */ function restoreLocalComponentJson(context) { - return new Promise((resolve) => { - const componentsCache = util.getComponentsCache(); - util.getLocalCompositeComponents().forEach((_component) => { - let pathToComponentJson; - const { componentJson, builtPath } = componentsCache[_component]; - // Retrieve the component.json contents from cache and write them in web: - if (util.isJETPack({ pack: _component, componentJson })) { - const dependenciesFromCache = Object.getOwnPropertyNames(componentJson.dependencies); - dependenciesFromCache.forEach((component) => { - const componentData = componentsCache[component]; - pathToComponentJson = path.join(componentData.builtPath, CONSTANTS.JET_COMPONENT_JSON); - fs.writeJsonSync(pathToComponentJson, componentData.componentJson); - }); - } else { - pathToComponentJson = path.join(builtPath, CONSTANTS.JET_COMPONENT_JSON); - fs.writeJsonSync(pathToComponentJson, componentJson); - } - }); - resolve(context); + const componentsCache = util.getComponentsCache(); + util.getLocalCompositeComponents().forEach((_component) => { + let pathToComponentJson; + const { componentJson, builtPath } = componentsCache[_component]; + // Retrieve the component.json contents from cache and write them in web: + if (util.isJETPack({ pack: _component, componentJson })) { + const dependenciesFromCache = Object.getOwnPropertyNames(componentJson.dependencies); + dependenciesFromCache.forEach((component) => { + const componentData = componentsCache[component]; + pathToComponentJson = path.join(componentData.builtPath, CONSTANTS.JET_COMPONENT_JSON); + fs.writeJsonSync(pathToComponentJson, componentData.componentJson); + }); + } else { + pathToComponentJson = path.join(builtPath, CONSTANTS.JET_COMPONENT_JSON); + fs.writeJsonSync(pathToComponentJson, componentJson); + } }); + return Promise.resolve(context); } module.exports = restoreLocalComponentJson; diff --git a/lib/buildCommon/stripLocalComponentJson.js b/lib/buildCommon/stripLocalComponentJson.js index 71f62ab..76d8854 100644 --- a/lib/buildCommon/stripLocalComponentJson.js +++ b/lib/buildCommon/stripLocalComponentJson.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/buildCommon/webpack.js b/lib/buildCommon/webpack.js index 59699a0..fda89ad 100644 --- a/lib/buildCommon/webpack.js +++ b/lib/buildCommon/webpack.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/buildComponent.js b/lib/buildComponent.js index c48f41b..6b2e74f 100644 --- a/lib/buildComponent.js +++ b/lib/buildComponent.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -15,37 +15,35 @@ const generateComponentsCache = require('./buildCommon/generateComponentsCache') const constants = require('./constants'); module.exports = function buildComponent(component, opts) { - return new Promise((resolve, reject) => { - // force component build to run in release mode. - const context = { platform: 'web', buildType: 'release', opts }; - const componentsCache = generateComponentsCache({ context }); - config.set('componentsCache', componentsCache); - const componentCache = componentsCache[component]; - if (!componentCache) { - util.log.error(`${component} is not a valid component name.`); - } - const { componentJson } = componentCache; - context.componentConfig = componentJson; - // Note that in order to ensure that the proper libs - // are in web/ (platform:web buildType:release) we must call copyLibs(). - buildCommon.copyLibs(context) - .then(() => buildCommon.copySingleCca(context, componentJson, component)) - .then(() => buildCommon.compileComponentTypescript({ - context, - component, - version: componentJson.version - })) - .then(() => buildCommon.minifyComponent(context, componentJson, component)) - .then(() => hookRunner('after_component_build', context)) - .then(() => { - if (!componentsCache[component].isVComponent) { - // Write cached component.json to staging location, for non vcomponents - const { builtPath } = componentsCache[component]; - const componentJsonPath = path.join(builtPath, constants.JET_COMPONENT_JSON); - util.writeObjectAsJsonFile(componentJsonPath, componentJson); - } - }) - .then(data => resolve(data)) - .catch(err => reject(err)); - }); + // force component build to run in release mode. + const context = { platform: 'web', buildType: 'release', opts }; + const componentsCache = generateComponentsCache({ context }); + config.set('componentsCache', componentsCache); + const componentCache = componentsCache[component]; + if (!componentCache) { + util.log.error(`${component} is not a valid component name.`); + } + const { componentJson } = componentCache; + context.componentConfig = componentJson; + // Note that in order to ensure that the proper libs + // are in web/ (platform:web buildType:release) we must call copyLibs(). + return buildCommon.copyLibs(context) + .then(() => buildCommon.copySingleCca(context, componentJson, component)) + .then(() => buildCommon.compileComponentTypescript({ + context, + component, + version: componentJson.version + })) + .then(() => buildCommon.minifyComponent(context, componentJson, component)) + .then(() => hookRunner('after_component_build', context)) + .then(() => { + if (!componentsCache[component].isVComponent) { + // Write cached component.json to staging location, for non vcomponents + const { builtPath } = componentsCache[component]; + const componentJsonPath = path.join(builtPath, constants.JET_COMPONENT_JSON); + util.writeObjectAsJsonFile(componentJsonPath, componentJson); + } + }) + .then(data => Promise.resolve(data)) + .catch(err => Promise.reject(err)); }; diff --git a/lib/buildHybrid.js b/lib/buildHybrid.js index eb4a26a..d957938 100644 --- a/lib/buildHybrid.js +++ b/lib/buildHybrid.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -117,28 +117,27 @@ function _runCordovaBuildTasks(context) { } function _runCommonBuildTasks(context) { - return new Promise((resolve, reject) => { - buildCommon.clean(context) - .then(data => hookRunner('before_build', data)) - .then(buildCommon.copy) - .then(buildCommon.copyLibs) - .then(buildCommon.copyReferenceCca) - .then(buildCommon.copyLocalCca) - .then(buildCommon.copyLocalVComponents) - .then(buildCommon.copyLocalResourceComponents) - .then(buildCommon.spriteSvg) - .then(buildCommon.css) - .then(buildCommon.pcss) - .then(buildCommon.injectTs) - .then(buildCommon.compileApplicationTypescript) - .then(buildCommon.copyThemes) - .then(buildCommon.injectTheme) - .then(buildCommon.injectScripts) - .then(_injectScriptTags) - .then(buildCommon.injectPaths) - .then(data => resolve(data)) - .catch(err => reject(err)); - }); + return buildCommon.clean(context) + .then(data => hookRunner('before_build', data)) + .then(buildCommon.copy) + .then(buildCommon.copyLibs) + .then(buildCommon.copyReferenceCca) + .then(buildCommon.copyLocalCca) + .then(buildCommon.copyLocalVComponents) + .then(buildCommon.copyLocalResourceComponents) + .then(buildCommon.spriteSvg) + .then(buildCommon.css) + .then(buildCommon.pcss) + .then(data => hookRunner('before_injection', data)) + .then(buildCommon.injectTs) + .then(buildCommon.compileApplicationTypescript) + .then(buildCommon.copyThemes) + .then(buildCommon.injectTheme) + .then(buildCommon.injectScripts) + .then(_injectScriptTags) + .then(buildCommon.injectPaths) + .then(data => Promise.resolve(data)) + .catch(err => Promise.reject(err)); } function _runReleaseBuildTasks(context) { @@ -161,26 +160,17 @@ function _runReleaseBuildTasks(context) { } function _runWindowsLocaleFix(context) { - return new Promise((resolve, reject) => { - buildCommon.fixWindowsLocale(context) - .then(data => resolve(data)) - .catch(err => reject(err)); - }); + return buildCommon.fixWindowsLocale(context); } module.exports = function buildHybrid(buildType, platform, opts) { const context = { buildType, platform, opts }; config.set('componentsCache', generateComponentsCache({ context })); - return new Promise((resolve, reject) => { - _runCommonBuildTasks(context) - .then(_runWindowsLocaleFix) - .then(_runReleaseBuildTasks) - .then(_runCordovaBuildTasks) - .then(buildCommon.runAllComponentHooks) - .then(data => hookRunner('after_build', data)) - .then((data) => { - resolve(data); - }) - .catch(err => reject(err)); - }); + return _runCommonBuildTasks(context) + .then(_runWindowsLocaleFix) + .then(_runReleaseBuildTasks) + .then(_runCordovaBuildTasks) + .then(buildCommon.runAllComponentHooks) + .then(data => hookRunner('after_build', data)) + .catch(err => Promise.reject(err)); }; diff --git a/lib/buildWeb.js b/lib/buildWeb.js index 2d7c9a6..a1237a3 100644 --- a/lib/buildWeb.js +++ b/lib/buildWeb.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -40,39 +40,34 @@ function _runReleaseBuildTasks(context) { } function _runCommonBuildTasks(context) { - return new Promise((resolve, reject) => { - buildCommon.clean(context) - .then(data => hookRunner('before_build', data)) - .then(buildCommon.copy) - .then(buildCommon.copyLibs) - .then(buildCommon.copyReferenceCca) - .then(buildCommon.copyLocalCca) - .then(buildCommon.copyLocalVComponents) - .then(buildCommon.copyLocalResourceComponents) - .then(buildCommon.spriteSvg) - .then(buildCommon.injectTs) - .then(buildCommon.compileApplicationTypescript) - .then(buildCommon.css) - .then(buildCommon.injectTheme) - .then(buildCommon.copyThemes) - .then(buildCommon.injectScripts) - .then(buildCommon.injectPaths) - .then(data => resolve(data)) - .catch(err => reject(err)); - }); + return buildCommon.clean(context) + .then(data => hookRunner('before_build', data)) + .then(buildCommon.copy) + .then(buildCommon.copyLibs) + .then(buildCommon.copyReferenceCca) + .then(buildCommon.copyLocalCca) + .then(buildCommon.copyLocalVComponents) + .then(buildCommon.copyLocalResourceComponents) + .then(buildCommon.spriteSvg) + .then(data => hookRunner('before_injection', data)) + .then(buildCommon.injectTs) + .then(buildCommon.compileApplicationTypescript) + .then(buildCommon.css) + .then(buildCommon.injectTheme) + .then(buildCommon.copyThemes) + .then(buildCommon.injectScripts) + .then(buildCommon.injectPaths) + .then(data => Promise.resolve(data)) + .catch(err => Promise.reject(err)); } module.exports = function buildWeb(buildType, opts) { const context = { buildType, opts, platform: 'web' }; config.set('componentsCache', generateComponentsCache({ context })); - return new Promise((resolve, reject) => { - _runCommonBuildTasks(context) - .then(_runReleaseBuildTasks) - .then(buildCommon.runAllComponentHooks) - .then(data => hookRunner('after_build', data)) - .then((data) => { - resolve(data); - }) - .catch(err => reject(err)); - }); + return _runCommonBuildTasks(context) + .then(_runReleaseBuildTasks) + .then(buildCommon.runAllComponentHooks) + .then(data => hookRunner('after_build', data)) + .then(data => Promise.resolve(data)) + .catch(err => Promise.reject(err)); }; diff --git a/lib/clean.js b/lib/clean.js index 9785266..6fce944 100644 --- a/lib/clean.js +++ b/lib/clean.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/config.js b/lib/config.js index 8000a5f..964bd07 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -93,7 +93,9 @@ function _readConfigJson() { const configJson = fs.existsSync(configPath) ? fs.readJsonSync(configPath) : {}; config.set('defaultBrowser', configJson.defaultBrowser || CONSTANTS.DEFAULT_BROWSER); config.set('sassVer', configJson.sassVer || CONSTANTS.SASS_VER); + config.set('typescriptLibraries', configJson.typescriptLibraries || CONSTANTS.TYPESCRIPT_LIBARIES); config.set('defaultTheme', configJson.defaultTheme || CONSTANTS.DEFAULT_THEME); config.set('installer', configJson.installer || CONSTANTS.DEFAULT_INSTALLER); + config.set('webpackLibraries', configJson.webpackLibraries || CONSTANTS.WEBPACK_LIBRARIES); return configJson; } diff --git a/lib/configure.js b/lib/configure.js index ca229a2..6ace558 100644 --- a/lib/configure.js +++ b/lib/configure.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/constants.js b/lib/constants.js index fbb8669..b6683dd 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -24,7 +24,7 @@ module.exports = { DEFAULT_STABLE_THEME: 'stable', DEFAULT_BROWSER: 'chrome', DEFAULT_INSTALLER: 'npm', - SASS_VER: '5.0.0', + SASS_VER: '7.0.1', COMMON_THEME_DIRECTORY: 'common', JET_COMPOSITE_DIRECTORY: 'jet-composites', JET_COMPONENTS_DIRECTORY: 'jet_components', @@ -79,6 +79,7 @@ module.exports = { REMOVE: 'remove', SEARCH: 'search', ADDTYPESCRIPT: 'addtypescript', + ADDJSDOC: 'addjsdoc', ADDPWA: 'addpwa', PACKAGE: 'package', ADDWEBPACK: 'addwebpack' @@ -104,19 +105,25 @@ module.exports = { COMPONENTS_DT: 'components_dt', PATH_TO_CUSTOM_TSC: 'dist/custom-tsc', PATH_TO_CUSTOM_TSC_TEMPLATES: 'dist/custom-tsc/templates', - TYPESCRIPT_VERSION: '4.6.4', + PATH_TO_JSDOC: 'dist/jsdoc', + JSDOC_CONFIG_JSON: 'confapidoc.json', + TYPESCRIPT_LIBARIES: 'typescript@4.8.4 yargs-parser@~13.1.2', JEST_TEST_FILE_AND_LIBS_GLOBS: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)', 'libs/**'], OMIT_COMPONENT_VERSION_FLAG: 'omit-component-version', WEBPACK_TOOLS_PATH: 'dist/webpack-tools', VDOM_ARCHITECTURE: 'vdom', DEFAULT_BUNDLE_NAME: 'bundle.js', PATH_MAPPING_PREFIX_TOKEN: '#', - WEBPACK_VERSION: '5.60.0', COMPONENT_JSON_DEPENDENCIES_TOKEN: '@dependencies@', PATH_TO_OJET_CONFIG: './ojet.config.js', + WEBPACK_LIBRARIES: 'webpack@5.60.0 @types/node@18.8.3 webpack-dev-server style-loader css-loader ts-loader raw-loader noop-loader html-webpack-plugin html-replace-webpack-plugin copy-webpack-plugin @prefresh/webpack @prefresh/babel-plugin webpack-merge compression-webpack-plugin mini-css-extract-plugin clean-webpack-plugin css-fix-url-loader zlib', COMPONENT_TYPE: { REFERENCE: 'reference', RESOURCE: 'resource' + }, + + PACK_TYPE: { + MONO_PACK: 'mono-pack', } }; diff --git a/lib/create.js b/lib/create.js index 7fdc89d..1cbaf3d 100644 --- a/lib/create.js +++ b/lib/create.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -23,10 +23,10 @@ const util = require('./util'); * @param {string} parameter * @returns {Promise} */ -module.exports = function (scope, parameter) { +module.exports = function (scope, parameter, options) { switch (scope) { case (CONSTANTS.API_SCOPES.PACK): - return pack.create(parameter); + return pack.create(parameter, options); default: util.log.error(`Please specify ojet.${CONSTANTS.API_TASKS.CREATE}() 'scope' parameter.`); return false; diff --git a/lib/defaultconfig.js b/lib/defaultconfig.js index 1605e9e..2e1ce8b 100644 --- a/lib/defaultconfig.js +++ b/lib/defaultconfig.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/hookRunner.js b/lib/hookRunner.js index 8c1fd34..105bbe9 100644 --- a/lib/hookRunner.js +++ b/lib/hookRunner.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/indexHtmlInjector.js b/lib/indexHtmlInjector.js index f608740..aa8b365 100644 --- a/lib/indexHtmlInjector.js +++ b/lib/indexHtmlInjector.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -131,7 +131,11 @@ function _getInjectSourceContent(updatePlatformFile, platform) { const document = util.readFileSync(indexHTML); const documentDom = new DOMParser().parseFromString(document, 'text/html'); - return { indexHTML, document, documentDom }; + return { + indexHTML, + document, + documentDom + }; } function _getStyleLinkBase(css, theme, buildType) { @@ -142,7 +146,9 @@ function _getStyleLinkBase(css, theme, buildType) { // CDN // Add -platform if non web and non redwood const platform = (theme.platform === 'web' || theme.name === 'redwood') ? '' : `-${theme.platform}`; - const cdnObj = { created: `${masterJson.cdns.jet.css}/${theme.name}${platform}/oj-${theme.name}${linkExt}` }; + const cdnObj = { + created: `${masterJson.cdns.jet.css}/${theme.name}${platform}/oj-${theme.name}${linkExt}` + }; if (theme.name === 'redwood' || theme.name === 'stable') { cdnObj.preact = `${masterJson.cdns.jet.csspreact}/Theme-${theme.name}/theme.css`; } @@ -305,7 +311,11 @@ function _replaceTokenWithScripts({ util.writeFileSync(contentDest, injectResult); } -function _injectCdnBundleScript({ content, contentDest, masterJson }) { +function _injectCdnBundleScript({ + content, + contentDest, + masterJson +}) { const documentDom = new DOMParser().parseFromString(content, 'text/html'); const scriptSrc = `${masterJson.cdns.jet.prefix}/${masterJson.cdns.jet.config}`; const cdnBundleElement = _createScriptElement(documentDom, scriptSrc); @@ -319,8 +329,7 @@ function _injectCdnBundleScript({ content, contentDest, masterJson }) { } } -module.exports = -{ +module.exports = { injectHybridScriptTags: (context) => { const updatePlatformFile = context.updatePlatformFile; const platform = context.platform; @@ -436,7 +445,10 @@ module.exports = const indexHtmlDestPath = util.destPath(path.join(stagingPath, 'index.html')); const indexHtmlContent = _getIndexHtml(indexHtmlDestPath); const masterJson = _isUseCdn(); - const { startTag, endTag } = opts.injectScripts; + const { + startTag, + endTag + } = opts.injectScripts; const pattern = injectorUtil.getInjectorTagsRegExp(startTag, endTag); if (pattern.test(indexHtmlContent)) { // index.html has injector:scripts token @@ -459,5 +471,7 @@ module.exports = }); } return Promise.resolve(context); - } + }, + + getStyleLinkBase: (css, theme, buildType) => _getStyleLinkBase(css, theme, buildType) }; diff --git a/lib/injectorUtil.js b/lib/injectorUtil.js index c4b113b..110305b 100644 --- a/lib/injectorUtil.js +++ b/lib/injectorUtil.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/list.js b/lib/list.js index 6851348..39d76f9 100644 --- a/lib/list.js +++ b/lib/list.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/mainJsInjector.js b/lib/mainJsInjector.js index b996928..5b6eddc 100644 --- a/lib/mainJsInjector.js +++ b/lib/mainJsInjector.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -174,7 +174,9 @@ function _writeDebugPreactImportToFile(context) { _replacePreactImport(context, buildType, config, platform, config.indexTs); fs.outputFile(config.indexTs, injectedContent, (err) => { - if (err) reject(err); + if (err) { + reject(err); + } resolve(context); }); }); @@ -202,7 +204,9 @@ function _writeRequirePathToFile(context) { _replaceReleasePath(context, buildType, config, platform, config.mainJs); fs.outputFile(destDir, injectedContent, (err) => { - if (err) reject(err); + if (err) { + reject(err); + } resolve(context); }); }); @@ -300,20 +304,16 @@ function _restorePathMapping(pathsObj) { module.exports = { injectPaths: function _injectpaths(context) { - return new Promise((resolve, reject) => { - try { - const newContext = context; - const pathsObj = pathGenerator.getPathsMapping(context, false, false); - newContext.opts.requireJs = pathGenerator.updateRJsOptimizerConfig(context); - _setMainPathMapping(newContext, pathsObj) - .then(_writeRequirePathToFile) - .then(() => { - resolve(newContext); - }); - } catch (error) { - reject(error); - } - }); + try { + const newContext = context; + const pathsObj = pathGenerator.getPathsMapping(context, false, false); + newContext.opts.requireJs = pathGenerator.updateRJsOptimizerConfig(context); + return _setMainPathMapping(newContext, pathsObj) + .then(_writeRequirePathToFile) + .then(() => Promise.resolve(newContext)); + } catch (error) { + return Promise.reject(error); + } }, injectTs: function _injectTs(context) { return new Promise((resolve, reject) => { diff --git a/lib/npmCopy.js b/lib/npmCopy.js index f69b000..2db64e2 100644 --- a/lib/npmCopy.js +++ b/lib/npmCopy.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -29,7 +29,7 @@ npmCopy.getNonMappingFileList = function (buildType, platform) { `${config('paths').staging.web}/${config('paths').src.javascript}/libs` : `${config('paths').staging.hybrid}/www/${config('paths').src.javascript}/libs`; const cssSrcPrefix = `${srcPrefix}/@oracle/oraclejet/dist/css/`; - const cssCorePackSrcPrefix = `${srcPrefix}/@oracle/oraclejet/dist/js/libs/oraclejet-preact/amd/`; + const cssCorePackSrcPrefix = `${srcPrefix}/@oracle/oraclejet-preact/amd/`; let nonMappingList = []; const versions = util.getLibVersionsObj(); if (!util.getInstalledCssPackage()) { @@ -331,7 +331,7 @@ npmCopy.getMappingLibsList = function (buildMode, platform) { const libsList = []; const masterJson = util.readPathMappingJson(); const basePath = masterJson.baseUrl; - Object.keys(masterJson.libs).forEach((lib) => { + Object.keys(masterJson.libs || {}).forEach((lib) => { const libObj = masterJson.libs[lib]; const isCdn = configGenerator.isCdnPath( libObj, diff --git a/lib/package.js b/lib/package.js index 2777dcb..2eaba8d 100644 --- a/lib/package.js +++ b/lib/package.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/parser/dom-parser.js b/lib/parser/dom-parser.js index 61a2b83..eddb148 100644 --- a/lib/parser/dom-parser.js +++ b/lib/parser/dom-parser.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/parser/dom.js b/lib/parser/dom.js index 8d6475b..274e4fa 100644 --- a/lib/parser/dom.js +++ b/lib/parser/dom.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/parser/sax.js b/lib/parser/sax.js index df8b08b..f67e6c8 100644 --- a/lib/parser/sax.js +++ b/lib/parser/sax.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/pcss.js b/lib/pcss.js index 0383c3a..3c2c0f5 100644 --- a/lib/pcss.js +++ b/lib/pcss.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/publish.js b/lib/publish.js index 112c46e..f2bf5a4 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/remove.js b/lib/remove.js index 7b0e2a2..eceab1c 100644 --- a/lib/remove.js +++ b/lib/remove.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/rjsConfigGenerator.js b/lib/rjsConfigGenerator.js index 6a25b42..a608e70 100644 --- a/lib/rjsConfigGenerator.js +++ b/lib/rjsConfigGenerator.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -275,6 +275,17 @@ function _getExchangeCcaPathMapping(context, buildType, masterJson, requirejs) { exchangeComponentPath = 'empty:'; } } + // For the case(s) when oj-c is installed as an NPM module and then added by + // the JET command 'ojet add component', the component then has two paths that + // it can be mapped to. In such a case, do not allow path overwriting. + if (exchangeComponent === 'oj-c') { + const pathMappingObject = _getPathMappingObj(buildType, masterJson, requirejs); + if (pathMappingObject[exchangeComponent] !== exchangeComponentPath) { + const errorMessage = `Cannot overwrite path ${pathMappingObject[exchangeComponent]} by the path '${exchangeComponentPath}'.`; + const toDoMessage = `Either use '${exchangeComponent}' from exchange or node_modules (delete it from the other location) before continuing.`; + util.log.error(`${errorMessage}\n${toDoMessage}`); + } + } pathMappingObj[exchangeComponent] = requirejs ? exchangeComponentPath : `'${exchangeComponentPath}'`; } }); @@ -349,14 +360,14 @@ function _getLocalCcaPathMapping(context, buildType, requirejs, scriptsFolder) { // // 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 === CONSTANTS.COMPONENT_TYPE.REFERENCE || - componentJson.type === CONSTANTS.COMPONENT_TYPE.RESOURCE)))) { - pathMappingObj[componentJson.name] = _getLocalComponentPath({ + (componentJson.type === CONSTANTS.COMPONENT_TYPE.RESOURCE))) { + const packageName = (componentJson.package ? componentJson.package : componentJson.name); + const pathName = (componentJson.paths && componentJson.paths.name) || packageName; + pathMappingObj[pathName] = _getLocalComponentPath({ context, component: componentJson.name, version @@ -366,10 +377,10 @@ function _getLocalCcaPathMapping(context, buildType, requirejs, scriptsFolder) { // Use minified directory for all components except type: demo if (!(Object.prototype.hasOwnProperty.call(componentJson, 'type') && (componentJson.type === 'demo'))) { - pathMappingObj[componentJson.name] = path.join(pathMappingObj[componentJson.name], 'min'); + pathMappingObj[pathName] = path.join(pathMappingObj[componentJson.name], 'min'); } } - pathMappingObj[componentJson.name] = requirejs ? pathMappingObj[componentJson.name] : `'${pathMappingObj[componentJson.name]}'`; + pathMappingObj[pathName] = requirejs ? pathMappingObj[pathName] : `'${pathMappingObj[pathName]}'`; } }); return pathMappingObj; diff --git a/lib/sass.js b/lib/sass.js index 8097064..fd5afb9 100644 --- a/lib/sass.js +++ b/lib/sass.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/scopes/component.js b/lib/scopes/component.js index cf87354..2f62c16 100644 --- a/lib/scopes/component.js +++ b/lib/scopes/component.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -188,7 +188,7 @@ function _applyEnvironmentChangesAddOrUpdate(solution, type, options) { fullName: comp, name: comp, version: envChanges[comp].version, - type: 'pack' + type: packComponentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK ? CONSTANTS.PACK_TYPE.MONO_PACK : 'pack' }); } else { util.log(`Pack ${comp} already installed. Skipping.`); @@ -419,7 +419,7 @@ function _unpackArchive(componentMetadata) { return new Promise((resolve, reject) => { // When updating, delete the original one if (fs.existsSync(componentDirPath)) { - if (componentMetadata.type !== 'pack') { + if (componentMetadata.type !== 'pack' && componentMetadata.type !== CONSTANTS.PACK_TYPE.MONO_PACK) { // 1. Component, just delete dir util.deleteDirSync(componentDirPath); } else { @@ -510,6 +510,11 @@ function _installReferenceComponent(obj) { util.spawn(installer.installer, [installer.verbs.install, npmPackage]) .then(() => { util.log(`Npm package '${npmPackage}' was successfully installed.`); + // Add the referenced component into the tsconfig file: + util.addComponentToTsconfigPathMapping({ + component: componentMetadata.fullName, + isLocal: false + }); resolve(componentMetadata); }) .catch((error) => { @@ -584,7 +589,7 @@ function _shufflePackComponentResources(componentMetadata) { } } } - if (type !== 'pack') { + if (type !== 'pack' && type !== CONSTANTS.PACK_TYPE.MONO_PACK) { // find all *.d.ts files in the none-pack component and move them to // /types/ if the component is in a pack and // /types if the component is a singleton @@ -701,7 +706,7 @@ component.list = function () { folderNames.forEach((folder) => { const componentJson = util.readJsonAndReturnObject(`${componentsDirPath}/${folder}/${CONSTANTS.JET_COMPONENT_JSON}`); - if (componentJson.type === 'pack') { + if (componentJson.type === 'pack' || componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { // Components that belongs to pack const packFolderNames = util.getDirectories(`${componentsDirPath}/${folder}`); @@ -771,8 +776,8 @@ component.package = function (componentNames, options) { // If pack name was used as the component name // package only pack itself (excluding its dependencies) if (!opts.pack) { - // Is it a component of a type 'pack'? - if (componentMetadata.type === 'pack' && + // Is it a component of a type 'pack' or mono-pack? + if ((componentMetadata.type === 'pack' || componentMetadata.type === CONSTANTS.PACK_TYPE.MONO_PACK) && // Pack content is already known, avoid infinite loop. Loop explanation: // Under the hood packaging of a pack calls component.package() but with a known content. !util.hasProperty(opts, '_contentToArchive') @@ -921,7 +926,7 @@ component.publish = function (componentName, options) { }); // Is it a component of a type 'pack'? - if (componentMetadata.type === 'pack' && + if ((componentMetadata.type === 'pack' || componentMetadata.type === 'pack') && // Pack content is already known, avoid infinite loop. Loop explanation: // Under the hood packaging of a pack calls component.package() but with a known content. !util.hasProperty(opts, '_contentToArchive') @@ -1056,11 +1061,12 @@ function _createArchive(componentName, context, options) { archive.directory(pathToComponentTypesFolder, 'types'); } } else { + const vComponent = util.isVComponent({ component: componentName }); archive.glob('**/*', { - cwd: componentPath + cwd: componentPath, + ignore: vComponent ? [`**/${util.getComponentJsDocsJsonFile(componentName)}`] : [] }); } - archive.finalize(); }); } diff --git a/lib/scopes/exchange.js b/lib/scopes/exchange.js index bd9f929..755efb0 100644 --- a/lib/scopes/exchange.js +++ b/lib/scopes/exchange.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -30,19 +30,18 @@ const exchange = module.exports; * @param {string} url - exchange url */ exchange.configureUrl = function (url) { - return new Promise((resolve) => { - const configObj = util.getOraclejetConfigJson(); - configObj[CONSTANTS.EXCHANGE_URL_PARAM] = url; - // Because a new url has been set, delete the 'cached' local components support flag. - delete configObj[CONSTANTS.EXCHANGE_LOCAL_COMPONENTS_SUPPORT]; - try { - util.writeFileSync(`./${CONSTANTS.ORACLE_JET_CONFIG_JSON}`, JSON.stringify(configObj, null, 2)); - util.log.success(`Exchange url set: ${url}`); - resolve(); - } catch (e) { - util.log.error(`Exchange url could not be set. ${e}`, true); - } - }); + const configObj = util.getOraclejetConfigJson(); + configObj[CONSTANTS.EXCHANGE_URL_PARAM] = url; + // Because a new url has been set, delete the 'cached' local components support flag. + delete configObj[CONSTANTS.EXCHANGE_LOCAL_COMPONENTS_SUPPORT]; + try { + util.writeFileSync(`./${CONSTANTS.ORACLE_JET_CONFIG_JSON}`, JSON.stringify(configObj, null, 2)); + util.log.success(`Exchange url set: ${url}`); + return Promise.resolve(); + } catch (e) { + util.log.error(`Exchange url could not be set. ${e}`, true); + return Promise.reject(); + } }; /** diff --git a/lib/scopes/pack.js b/lib/scopes/pack.js index aeee907..c6811f3 100644 --- a/lib/scopes/pack.js +++ b/lib/scopes/pack.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -24,7 +24,7 @@ const util = require('../util'); const generateComponentsCache = require('../buildCommon/generateComponentsCache'); // Module variables -const packDirBlacklist = ['min', 'types']; +let packDirBlacklist = ['min', 'types']; /** * # Components @@ -58,7 +58,7 @@ pack.add = function (packNames, options) { exchangeUtils.getComponentMetadata(packName) .then((metadata) => { // eslint-disable-line return new Promise((res, rej) => { - if (metadata.type === 'pack') { + if (metadata.type === 'pack' || metadata.type === CONSTANTS.PACK_TYPE.MONO_PACK) { const packDependenciesObject = metadata.component.dependencies; // Array of serialized component names to be added @[] @@ -107,8 +107,8 @@ pack.add = function (packNames, options) { * @param {string} packName * @return {Promise} */ -pack.create = function (packName) { - return new Promise((resolve) => { +pack.create = function (packName, options) { + try { util.ensureParameters(packName, CONSTANTS.API_TASKS.CREATE); const configPaths = util.getConfiguredPaths(); @@ -123,6 +123,9 @@ pack.create = function (packName) { // Check if already exists if (fs.existsSync(packDirPath)) { util.log.error(`Pack '${packName}' already exits.`); + } else if (options.type === CONSTANTS.PACK_TYPE.MONO_PACK && !util.isTypescriptApplication()) { + const errorMessage = 'Cannot create a mono-pack in a Javascript application. Please run \'ojet add typescript\' to add Typescript support to your application and then try again.'; + util.log.error(errorMessage); } else { // Make pack directory util.ensureDir(packDirPath); @@ -132,6 +135,10 @@ pack.create = function (packName) { const packComponentJson = util.readJsonAndReturnObject(packComponentJsonTemplatePath); packComponentJson.name = packName; packComponentJson.jetVersion = `^${util.getJETVersion()}`; + if (options.type === CONSTANTS.PACK_TYPE.MONO_PACK) { + packComponentJson.type = CONSTANTS.PACK_TYPE.MONO_PACK; + packComponentJson.contents = []; + } const filename = path.join(packDirPath, CONSTANTS.JET_COMPONENT_JSON); util.writeFileSync(filename, JSON.stringify(packComponentJson, null, 2)); // Add path mapping for pack in tsconfig.json if in typescript app @@ -140,11 +147,12 @@ pack.create = function (packName) { isLocal: true }); util.log.success(`Pack '${packName}' successfully created.`); - resolve(); } - }).catch((error) => { + return Promise.resolve(); + } catch (error) { util.log.error(error, true); - }); + return Promise.reject(error); + } }; /** @@ -155,7 +163,7 @@ pack.create = function (packName) { * @return {Promise} */ pack.list = function () { - return new Promise((resolve) => { + try { const configPaths = util.getConfiguredPaths(); // Read packs from the config file const packsInConfigFile = []; @@ -177,7 +185,7 @@ pack.list = function () { folderNames.forEach((folderName) => { const componentJson = util.readJsonAndReturnObject(`${componentsDirPath}/${folderName}/${CONSTANTS.JET_COMPONENT_JSON}`); - if (componentJson.type === 'pack') { + if (componentJson.type === 'pack' || componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { packsByFolder.push(folderName); } }); @@ -189,10 +197,11 @@ pack.list = function () { util.printList(packsInConfigFile, packsByFolder); util.log.success('Packs listed.'); - resolve(); - }).catch((error) => { + return Promise.resolve(); + } catch (error) { util.log.error(error, true); - }); + return Promise.reject(error); + } }; /** @@ -270,7 +279,11 @@ pack.package = function (packNames, options) { }); builtPackDirs = util.getDirectories(builtPackPath); - + // If the pack is mono-pack, do not filter the min and types folders, + // which are listed in the packDirBlacklist: + if (packComponentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { + packDirBlacklist = []; + } // Save pack directories (not components, types or min folder) builtPackDirs = builtPackDirs.filter((packDir) => { // eslint-disable-line return builtPackComponentNames.indexOf(packDir) === -1 && @@ -313,6 +326,11 @@ pack.package = function (packNames, options) { initialPromise = Promise.resolve(); } else { opts.buildType = 'release'; + // For packs, we would want to build the component, where we get + // generated docs folder. This folder need to be packaged as well. + if (packComponentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK || packComponentJson.type === 'pack') { + opts.component = packName; + } initialPromise = build('web', opts); } @@ -343,10 +361,23 @@ pack.package = function (packNames, options) { .then(() => { // Package pack if (opts.pack) { delete opts.pack; } + + // Create an array of vcomponent json files used to generate + // the components' JsDocs folder (/docs) in web. + const componentDocsJsonArray = []; + const vComponents = util.getVComponentsInJETPack({ pack: packName }); + vComponents.forEach((vComponent) => { + componentDocsJsonArray.push(util.getComponentJsDocsJsonFile(vComponent)); + }); + return component.package([packName], Object.assign(opts, { _contentToArchive: { dirs: builtPackDirs, - files: util.getFiles(builtPackPath), + // Filter all json files used to generate /docs for vcomponents in + // the pack: These artefacts are not to be packaged in the zip. + files: util.getFiles(builtPackPath).filter( + file => !componentDocsJsonArray.includes(`${file}`) + ), minFiles: util.getFiles(path.join(builtPackPath, 'min')) } })); diff --git a/lib/search.js b/lib/search.js index c099438..f350975 100644 --- a/lib/search.js +++ b/lib/search.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/serve.js b/lib/serve.js index 8b4ee4c..d5fe7c8 100644 --- a/lib/serve.js +++ b/lib/serve.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/serve/connect.js b/lib/serve/connect.js index 6de8efc..856084a 100644 --- a/lib/serve/connect.js +++ b/lib/serve/connect.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/serve/watch.js b/lib/serve/watch.js index abdc319..4a8da7f 100644 --- a/lib/serve/watch.js +++ b/lib/serve/watch.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -100,10 +100,13 @@ function _startLiveReloadServer(opts, port, context) { function _startWatchers(opts) { util.log('Watching files.'); + const intervalValue = util.getOraclejetConfigJson().watchInterval; + util.log(`Watching Interval: ${intervalValue}.`); return new Promise((resolve, reject) => { try { Object.keys(opts).forEach((watchTarget) => { - watchers[watchTarget] = _startWatcher(opts[watchTarget].files, watchTarget, opts); + // eslint-disable-next-line max-len + watchers[watchTarget] = _startWatcher(opts[watchTarget].files, watchTarget, intervalValue, opts); }); resolve(); } catch (err) { @@ -112,8 +115,8 @@ function _startWatchers(opts) { }); } -function _startWatcher(targetFiles, target, opts) { - const watcher = new Gaze(targetFiles, { interval: 1000 }); +function _startWatcher(targetFiles, target, intervalValue, opts) { + const watcher = new Gaze(targetFiles, { interval: intervalValue }); watcher.on('ready', () => { util.log(`Watcher: ${target} is ready.`); diff --git a/lib/serveHybrid.js b/lib/serveHybrid.js index 2c3889b..d4f62ff 100644 --- a/lib/serveHybrid.js +++ b/lib/serveHybrid.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/serveHybridFileChangeHandler.js b/lib/serveHybridFileChangeHandler.js index 4e77f37..358e423 100644 --- a/lib/serveHybridFileChangeHandler.js +++ b/lib/serveHybridFileChangeHandler.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/serveWeb.js b/lib/serveWeb.js index 796d329..04f19d0 100644 --- a/lib/serveWeb.js +++ b/lib/serveWeb.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/serveWebFileChangeHandler.js b/lib/serveWebFileChangeHandler.js index 55ec05b..bbdbf32 100644 --- a/lib/serveWebFileChangeHandler.js +++ b/lib/serveWebFileChangeHandler.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/strip.js b/lib/strip.js index 9b5d170..3a6bc0c 100644 --- a/lib/strip.js +++ b/lib/strip.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/svg.js b/lib/svg.js index 54d5598..0aeef3f 100644 --- a/lib/svg.js +++ b/lib/svg.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/templates/pack/component.json b/lib/templates/pack/component.json index 12c9f68..5a62f52 100644 --- a/lib/templates/pack/component.json +++ b/lib/templates/pack/component.json @@ -1,7 +1,7 @@ { "name": "@pack@", "version": "1.0.0", - "jetVersion": "13.1.0", + "jetVersion": "14.0.0", "type": "pack", "displayName": "A user friendly, translatable name of the pack.", "description": "A translatable high-level description for the pack.", diff --git a/lib/templates/typescript/tsconfig.json b/lib/templates/typescript/tsconfig.json index 5753a8f..19c3c67 100644 --- a/lib/templates/typescript/tsconfig.json +++ b/lib/templates/typescript/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "baseUrl": ".", "target": "es6", + "strict": true, "module": "amd", "moduleResolution": "node", "jsx": "react-jsx", @@ -11,14 +12,15 @@ "typeRoots": ["./node_modules/@oracle/oraclejet/dist/types", "./node_modules/@types"], "paths": { "ojs/*": ["./node_modules/@oracle/oraclejet/dist/types/*"], - "@oracle/oraclejet-preact/*": ["./node_modules/@oracle/oraclejet/dist/js/libs/oraclejet-preact/types/*"], + "@oracle/oraclejet-preact/*": ["./node_modules/@oracle/oraclejet-preact/*"], "oj-c/*": ["./node_modules/@oracle/oraclejet-core-pack/oj-c/types/*"], "preact": ["./node_modules/@oracle/oraclejet/dist/js/libs/preact"] }, "declaration": true, "noEmitOnError": true, "experimentalDecorators": true, - "skipLibCheck": true + "skipLibCheck": true, + "removeComments": true }, "include": ["./src/ts/**/*"] } \ No newline at end of file diff --git a/lib/templates/webpack/ojet.config.js b/lib/templates/webpack/ojet.config.js index d1c2a12..b7e2676 100644 --- a/lib/templates/webpack/ojet.config.js +++ b/lib/templates/webpack/ojet.config.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/util.js b/lib/util.js index 7434683..dfa8258 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -59,6 +59,22 @@ util.convertJsonToObject = (string) => { util.validateSassInstall = function () { validate.sassInstall(); }; +util.hasJsdocInstalled = function () { + const hasJsdocPackageJson = util.getModulePath( + path.join( + 'node_modules', + 'jsdoc', + 'package.json' + ), + 'jsdoc' + ); + + if (hasJsdocPackageJson) { + return true; + } + return false; +}; + /** * get the minified component path. * @private @@ -2540,13 +2556,33 @@ util.addComponentToTsconfigPathMapping = ({ component, isLocal }) => { const configPaths = util.getConfiguredPaths(); const tsconfigJsonPath = path.join('.', CONSTANTS.TSCONFIG); const tsconfigJson = util.readJsonAndReturnObject(tsconfigJsonPath); + const componentJson = util.getExchangeComponentComponentJson({ component }); const srcFolder = configPaths.src.common; const compositesFolder = configPaths.components; const typescriptFolder = configPaths.src.typescript === '.' ? '' : `${configPaths.src.typescript}/`; - const pathMapping = `${component}/*`; + let pathMapping = `${component}/*`; + let exchangeCompPath; + // Ensure that the reference components are also added to the tsconfig.json file: + if (componentJson && componentJson.type === CONSTANTS.COMPONENT_TYPE.REFERENCE) { + const pathName = (componentJson.paths && componentJson.paths.name) ? + componentJson.paths.name : componentJson.package; + const modulePath = util.getModulePath( + path.join( + CONSTANTS.NODE_MODULES_DIRECTORY, + componentJson.package + ), + componentJson.package + ); + if (modulePath !== null) { + pathMapping = `${pathName}/*`; + exchangeCompPath = `./${CONSTANTS.NODE_MODULES_DIRECTORY}/${componentJson.package}/*`; + } + } else if (util.isExchangeComponent({ component })) { + exchangeCompPath = `./${configPaths.exchangeComponents}/${component}/types/*`; + } + const typesPath = isLocal ? - `./${srcFolder}/${typescriptFolder}${compositesFolder}/${component}/*` : - `./${configPaths.exchangeComponents}/${component}/types/*`; + `./${srcFolder}/${typescriptFolder}${compositesFolder}/${component}/*` : exchangeCompPath; if (!tsconfigJson.compilerOptions.paths[pathMapping]) { tsconfigJson.compilerOptions.paths = { ...(tsconfigJson.compilerOptions.paths || {}), @@ -2613,7 +2649,7 @@ util.isJETPack = ({ pack, componentJson }) => { _componentJson = componentCache ? componentCache.componentJson : util.getComponentJson({ component: pack }); } - return util.hasProperty(_componentJson, 'type') && _componentJson.type === 'pack'; + return util.hasProperty(_componentJson, 'type') && (_componentJson.type === 'pack' || _componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK); }; /** @@ -3135,3 +3171,47 @@ util.isVDOMApplication = () => { } return false; }; + +/** + * Retrieves the array with elements in the format + * -. This info is needed + * to retrieve respective component's component + * cache for mono-packs. + * + * @returns {array} + */ +util.getMonoPackMemberNameList = (packComponentJson) => { + const contentsArray = packComponentJson.contents; + const packName = packComponentJson.name; + const packMemberNameList = []; + contentsArray.forEach((content) => { + // Do not include mono-pack content of type module. + // They are not components that should be processed + // during the building or packaging process. + if (!content.type || (content.type !== 'module')) { + packMemberNameList.push(`${packName}-${content.name}`); + } + }); + return packMemberNameList; +}; + +/** + * ## util.getComponentJsDocsJsonFile + * + * This method return the json file used to generate Js Docs + * For example, a vcomponent my-component-1-to-test-the-format + * gets transformed to MyComponent1ToTestTheFormat.json, which + * is in the used naming format for such files. + * + * @param {string} component + * @returns string + */ +util.getComponentJsDocsJsonFile = (component) => { + const jsDocJsonFile = component + .toLowerCase() + .split('-') + .map(componentName => componentName.charAt(0).toUpperCase() + componentName.slice(1)) + .join('') + .concat('.json'); + return jsDocJsonFile; +}; diff --git a/lib/utils.exchange.js b/lib/utils.exchange.js index 4026a67..3f02bf6 100644 --- a/lib/utils.exchange.js +++ b/lib/utils.exchange.js @@ -1,6 +1,6 @@ #! /usr/bin/env node /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -99,7 +99,7 @@ function _getEnvironment() { const componentJsonPath = path.join(jetCompsDir, componentDir, compJson); const componentJson = util.readJsonAndReturnObject(componentJsonPath); - if (componentJson.type === 'pack') { + if (componentJson.type === 'pack' || componentJson.type === CONSTANTS.PACK_TYPE.MONO_PACK) { environment[componentDir] = { version: componentJson.version, components: {} @@ -145,7 +145,7 @@ function _getLocalComponents() { Object.keys(componentCache) .forEach((componentFullname) => { const componentData = componentCache[componentFullname]; - if (componentData.isLocal) { + if (componentData.isLocal && !componentData.isVComponent) { const localComponent = { fullName: componentFullname }; diff --git a/lib/validations.js b/lib/validations.js index 2947438..22dcd83 100644 --- a/lib/validations.js +++ b/lib/validations.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -350,3 +350,4 @@ function _validateSassInstall() { util.log.error('Please run \'ojet add sass\' to configure your projects for SASS processing. \n OR \n Please run \'ojet add theming\' to configure your projects for PCSS processing.'); } } + diff --git a/lib/webpack/build.js b/lib/webpack/build.js index dd08dfb..4a9d735 100644 --- a/lib/webpack/build.js +++ b/lib/webpack/build.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -33,12 +33,5 @@ module.exports = (options) => { if (ojetUtils.isTypescriptApplication()) { webpackUtils.organizeTypeDefinitions(); } - }).then(() => { - // In release mode, we modify the src/index.html by directly injecting required links - // into index.html which, otherwise, would not have been injected. The temp-index.html - // in src ensures that the original file is restored before deleting the file: - if (options.buildType === 'release') { - webpackUtils.deleteTempSrcIndexHTML(); - } }); }; diff --git a/lib/webpack/custom-tsc/index.js b/lib/webpack/custom-tsc/index.js index fa68537..a32f116 100644 --- a/lib/webpack/custom-tsc/index.js +++ b/lib/webpack/custom-tsc/index.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/webpack/serve.js b/lib/webpack/serve.js index 36a7b5c..8d8b4bc 100644 --- a/lib/webpack/serve.js +++ b/lib/webpack/serve.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/lib/webpack/setup.js b/lib/webpack/setup.js index fb5d91c..298a7b9 100644 --- a/lib/webpack/setup.js +++ b/lib/webpack/setup.js @@ -1,19 +1,25 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ */ const path = require('path'); - +const fs = require('fs-extra'); const ojetUtils = require('../util'); const webpackUtils = require('./utils'); const config = require('../config'); const valid = require('../validations'); const generateComponentsCache = require('../buildCommon/generateComponentsCache'); const constants = require('../constants'); +const buildCommon = require('../buildCommon'); + +const configPaths = ojetUtils.getConfiguredPaths(); -function createContext({ options, platform }) { +function createContext({ + options, + platform +}) { config.loadOraclejetConfig(platform); const validPlatform = valid.platform(platform); const validOptions = valid.buildOptions(options, validPlatform); @@ -25,29 +31,61 @@ function createContext({ options, platform }) { }; } -module.exports = ({ options, platform }) => { - const context = createContext({ options, platform }); - config.set('componentsCache', generateComponentsCache({ context })); +module.exports = ({ + options, + platform +}) => { + const context = createContext({ + options, + platform + }); + config.set('componentsCache', generateComponentsCache({ + context + })); let webpackConfig; if (context.buildType === 'release') { - // Make a temp-index.html, copy contents to index.html later: the original is modified below. - // We need original src/index.html contents after running ojet build --release. - webpackUtils.makeTempSrcIndexHTML(); - // In the release mode, the src/index.html file is minified. Comment tags are removed. - // No comment tag, no injecting the link into web/index.html. Injecting the link tags - // right before the minification ensures that they are present in web/index.html. - webpackUtils.modifySrcIndexHTML(context); // eslint-disable-next-line global-require webpackConfig = require('./webpack.production'); } else { // eslint-disable-next-line global-require webpackConfig = require('./webpack.development'); } + + // Process theme files and copy them to staging: + buildCommon.copy(context); + buildCommon.copyLibs(context); + buildCommon.css(context); + buildCommon.copyThemes(context); + webpackUtils.copyRequiredAltaFilesToStaging(context); + + const entryFilesArray = webpackConfig.entry.main; + const masterJSON = ojetUtils.readPathMappingJson(); + const themeStyleArray = webpackUtils.getThemeStyleArray(context); + const pathToAppCSS = webpackUtils.getAppCssFilesPath(context); + // Add path to app.css or app-min.css as part of the entry files: + entryFilesArray.push(pathToAppCSS); + // Add path(s) to the chosen theme(s) as entry point as well: + if (masterJSON.use === 'cdn') { + // Add a configuration to ensure that webpack resolves CDN links if CDN is used: + webpackConfig.externalsType = 'script'; + webpackConfig.externals = { packageName: themeStyleArray }; + } else if (masterJSON.use === 'local') { + themeStyleArray.forEach((theme) => { + const pathToThemeInWeb = path.resolve(configPaths.staging.web, theme); + if (fs.existsSync(pathToThemeInWeb)) { + entryFilesArray.push(pathToThemeInWeb); + } + }); + } + const pathToOjetConfig = path.resolve(constants.PATH_TO_OJET_CONFIG); // eslint-disable-next-line global-require, import/no-dynamic-require const ojetConfig = require(pathToOjetConfig); if (ojetConfig.webpack) { - webpackConfig = ojetConfig.webpack({ context, config: webpackConfig }) || webpackConfig; + webpackConfig = ojetConfig.webpack({ + context, + config: webpackConfig + }) || webpackConfig; } return { webpack: ojetUtils.requireLocalFirst('webpack'), diff --git a/lib/webpack/utils.js b/lib/webpack/utils.js index 5eac455..5334041 100644 --- a/lib/webpack/utils.js +++ b/lib/webpack/utils.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -8,6 +8,9 @@ const path = require('path'); const glob = require('glob'); const fs = require('fs-extra'); const ojetUtils = require('../util'); +const injector = require('../indexHtmlInjector'); +const config = require('../config'); +const constants = require('../constants'); const configPaths = ojetUtils.getConfiguredPaths(); const exchangeComponentsPath = path.resolve(configPaths.exchangeComponents); @@ -17,55 +20,19 @@ const localComponentsPath = path.resolve( configPaths.components ); const oracleJetDistPath = path.join(ojetUtils.getOraclejetPath(), 'dist'); -const oracleJetPreactThemePath = path.join(oracleJetDistPath, 'js', 'libs', 'oraclejet-preact', 'amd'); const oracleJetDistCssPath = path.join(oracleJetDistPath, 'css'); const oracleJetDistJsLibsPath = path.join(oracleJetDistPath, 'js/libs'); -const pathToSrcHTML = path.resolve(configPaths.src.common, 'index.html'); -const pathToTempSrcHTML = path.resolve(configPaths.src.common, 'temp-index.html'); // eslint-disable-next-line no-useless-escape const htmlTokenPattern = /()?/g; // eslint-disable-next-line no-useless-escape const htmlEndInjectorTokenPattern = /()/g; -const htmlTokenResources = { - css: { - redwood: `./${configPaths.src.styles}/redwood/oj-redwood-min.css`, - preact: `./${configPaths.src.styles}/theme-redwood/theme.css` - }, - injector: { - theme: `./${configPaths.src.styles}/redwood/oj-redwood-min.css`, - } -}; -const htmlTokenTEmplates = { - css: '', - injector: '' -}; -const preactThemePath = htmlTokenTEmplates.css.replace('%s', htmlTokenResources.css.preact); -// eslint-disable-next-line no-unused-vars -function htmlTokenReplacementFunction(match, $1, type, file, $4, index, input) { - // those formal parameters could be: - // match: <-- css:bootstrap--> - // type: css - // file: redwood - // Then fetch css link from some resource object - // var url = resources['css']['redwood'] - - // Replace with empty string: - if (type === 'endinjector') { - return ''; - } - // Replace with empty string, too. - // We do not need this injector since webpack automatically - // injects the required file link: - if (type === 'injector' && file === 'scripts') { - return ''; - } - const url = htmlTokenResources[type][file]; - // This ensures that preact link is injected into the index.html: - const themeStyleLinks = `${htmlTokenTEmplates[type].replace('%s', url)}\n\t\t${preactThemePath}`; - // $1==='@@' <--EQ--> $4===undefined - return ($4 === undefined ? url : themeStyleLinks); -} +// eslint-disable-next-line no-useless-escape +const htmlAppCssLinkTokenPattern = /<\w+\s*\w+[^abc]+css[^abc]app.css[^abc]+css[^abc]+>/g; +/** + * ## isWebComponent + * + */ function isWebComponent(resourcePath) { let component; const normalizedResourcePath = path.normalize(resourcePath); @@ -77,38 +44,10 @@ function isWebComponent(resourcePath) { return component === undefined ? false : !!ojetUtils.getComponentsCache()[component]; } -function makeTempSrcIndexHTML() { - fs.copyFileSync(pathToSrcHTML, pathToTempSrcHTML); -} - -function deleteTempSrcIndexHTML() { - // Restore the original index.html in src before deleting temp-index.html: - fs.copyFileSync(pathToTempSrcHTML, pathToSrcHTML); - fs.removeSync(pathToTempSrcHTML); -} - -function modifySrcIndexHTML() { - let htmlContent = fs.readFileSync(pathToSrcHTML, { - encoding: 'utf8' - }); - // Same link tag will be used for replacing the matched comment tags below. - // The link is : - const redwoodMinPath = htmlTokenReplacementFunction(undefined, undefined, 'css', 'redwood', '-->', undefined); - // Replace with link to redwood-min.css: - // eslint-disable-next-line no-useless-escape - const regexCSS = /()?/g; - htmlContent = htmlContent.replace(regexCSS, redwoodMinPath); - - // Replace with link to redwood-min.css, too, if present: - // eslint-disable-next-line no-useless-escape - const regexInjector = /()?/g; - htmlContent = htmlContent.replace(regexInjector, redwoodMinPath); - - // Note: No need to delete/replace and - // with empty string: these are going to be delete by the webpack plugin anyway. - fs.writeFileSync(pathToSrcHTML, htmlContent); -} - +/** + * ## organizeTypeDefinitions + * + */ function organizeTypeDefinitions() { const tsFilesTypesFolder = path.resolve(configPaths.staging.stagingPath, 'types'); ojetUtils.ensureDir(tsFilesTypesFolder); @@ -140,6 +79,11 @@ function organizeTypeDefinitions() { } } +/** + * ## getEntryFilePath + * + * @returns {string} path to the root file + */ function getEntryFilePath() { if (ojetUtils.isVDOMApplication()) { return path.resolve(configPaths.src.common, 'index.ts'); @@ -150,6 +94,11 @@ function getEntryFilePath() { return path.resolve(configPaths.src.common, 'js', 'root.js'); } +/** + * ## getRootPath + * + * @returns {string} path to root folder + */ function getRootPath() { if (ojetUtils.isVDOMApplication()) { return path.resolve(configPaths.staging.web, @@ -163,6 +112,59 @@ function getRootPath() { configPaths.src.javascript); } +/** + * ## getThemeStyleArray + * + * @param {Object} context + * @returns {Array} array with paths to theme files + */ +function getThemeStyleArray(context) { + let themeStyleArray; + const css = config('paths').src.styles; + const theme = context.opts.theme; + const buildType = context.buildType; + const linkBase = injector.getStyleLinkBase(css, theme, buildType); + if (linkBase.default) { + themeStyleArray = theme.name === 'redwood' ? [linkBase.default, linkBase.created, linkBase.preact] : [linkBase.default, linkBase.created]; + return themeStyleArray; + } + themeStyleArray = theme.name === 'redwood' ? [linkBase.created, linkBase.preact] : [linkBase.created]; + return themeStyleArray; +} + +/** + * ## getAppCssFilesPath + * + * @param {Object} context + * @returns {string} path to the app css files + */ +function getAppCssFilesPath(context) { + const buildType = context.buildType; + const appCSSPath = path.resolve(configPaths.staging.web, `${configPaths.src.styles}`, 'app.css'); + const pathToAppCSS = buildType === 'release' && !ojetUtils.isVDOMApplication() ? + appCSSPath.replace('app.css', 'app-min.css') : appCSSPath; + return pathToAppCSS; +} + +/** + * ## copyRequiredAltaFilesToStaging + * + * @param {Object} context + */ +function copyRequiredAltaFilesToStaging(context) { + // The required folders will be 'common' and the chosen platform (web, windows, etc). + // We need the contents of these folders because we are redirecting some paths in the + // generated css file (see webpack.common under the css-fix-url loader) to the resources + // that are only found in the required folders. + const requiredFolders = ['common', context.platform]; + requiredFolders.forEach((folder) => { + const scrPath = path.resolve(configPaths.staging.themes, 'alta', folder); + let destPath = path.resolve(configPaths.staging.web, configPaths.src.styles, 'alta'); + destPath = !context.opts[constants.OMIT_COMPONENT_VERSION_FLAG] ? path.join(destPath, `${ojetUtils.getJETVersion()}`, folder) : path.join(destPath, folder); + fs.copySync(scrPath, destPath); + }); +} + module.exports = { isWebComponent, localComponentsPath, @@ -170,14 +172,13 @@ module.exports = { oracleJetDistPath, oracleJetDistCssPath, oracleJetDistJsLibsPath, - oracleJetPreactThemePath, htmlTokenPattern, htmlEndInjectorTokenPattern, - htmlTokenReplacementFunction, + htmlAppCssLinkTokenPattern, getEntryFilePath, - makeTempSrcIndexHTML, - deleteTempSrcIndexHTML, - modifySrcIndexHTML, organizeTypeDefinitions, - getRootPath + getRootPath, + getThemeStyleArray, + getAppCssFilesPath, + copyRequiredAltaFilesToStaging }; diff --git a/lib/webpack/webpack.common.js b/lib/webpack/webpack.common.js index 0f0ad1f..95e8b88 100644 --- a/lib/webpack/webpack.common.js +++ b/lib/webpack/webpack.common.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -12,29 +12,69 @@ const WebpackRequireFixupPlugin = require(path.join(webpackUtils.oracleJetDistPa const HtmlWebpackPlugin = ojetUtils.requireLocalFirst('html-webpack-plugin'); const HtmlReplaceWebpackPlugin = ojetUtils.requireLocalFirst('html-replace-webpack-plugin'); -const CopyPlugin = ojetUtils.requireLocalFirst('copy-webpack-plugin'); const webpack = ojetUtils.requireLocalFirst('webpack'); - +const entryFile = webpackUtils.getEntryFilePath(); const configPaths = ojetUtils.getConfiguredPaths(); const isTypescriptApplication = ojetUtils.isTypescriptApplication(); +const { + CleanWebpackPlugin +} = ojetUtils.requireLocalFirst('clean-webpack-plugin'); module.exports = { - entry: webpackUtils.getEntryFilePath(), + entry: { + main: [ + entryFile + ] + }, output: { path: path.resolve(configPaths.staging.web), - clean: true + clean: true, + environment: { + module: true, + dynamicImport: true, + } }, module: { rules: [{ - test: /\.(png|jpg|jpeg|svg|gif)$/i, + test: /\.(png|jpg|jpeg|svg|gif|ico)$/i, type: 'asset', + generator: { + filename: `${configPaths.src.styles}/images/[hash][ext][query]` + } }, { test: /\.css$/i, use: [ 'style-loader', - 'css-loader' - ], + 'css-loader', + { + loader: 'css-fix-url-loader', + // There is no path to images/../../redwood/images/. + // Enable webpack to resolve it as images/. + options: { + from: 'images/../../redwood/images', + to: 'images', + } + }, + { + loader: 'css-fix-url-loader', + // There is no 'images' folder under the created theme's folder. + // Redirect the path to the alta's images subfolder. + options: { + from: 'images/animated-overlay.gif', + to: `../../../alta/${ojetUtils.getJETVersion()}/common/images/animated-overlay.gif`, + } + }, + // There is no path to ../../css/redwood/images/AI-Sparkle.gif. + // Configure webpack to resolve it as ./images/AI-Sparkle.gif. + { + loader: 'css-fix-url-loader', + options: { + from: '../../css/redwood/images/AI-Sparkle.gif', + to: './images/AI-Sparkle.gif', + } + }, + ] }, { test: /\.tsx?/, @@ -56,7 +96,8 @@ module.exports = { // text! to import *.json files test: resource => (/\.json$/i.test(resource) && webpackUtils.isWebComponent(resource)), type: 'javascript/auto' - }], + } + ], }, resolve: { modules: [webpackUtils.localComponentsPath, webpackUtils.exchangeComponentsPath, 'node_modules'], @@ -64,23 +105,12 @@ module.exports = { alias: { react: 'preact/compat', 'react-dom': 'preact/compat', - ojdnd: path.join( - webpackUtils.oracleJetDistJsLibsPath, 'dnd-polyfill/dnd-polyfill-1.0.2' - ), - signals: path.resolve('./node_modules/signals/dist/signals.js'), - touchr: path.join( - webpackUtils.oracleJetDistJsLibsPath, 'touchr/touchr' - ), - 'jqueryui-amd': path.resolve('./node_modules/jquery-ui/ui'), - ojs: path.join( - webpackUtils.oracleJetDistJsLibsPath, 'oj/debug' - ), - ojtranslations: path.join( - webpackUtils.oracleJetDistJsLibsPath, 'oj/resources' - ), - '@oracle/oraclejet-preact': path.join( - webpackUtils.oracleJetDistJsLibsPath, 'oraclejet-preact/amd' - ) + ojdnd: '@oracle/oraclejet/dist/js/libs/dnd-polyfill/dnd-polyfill-1.0.2', + signals: 'signals/dist/signals.js', + touchr: '@oracle/oraclejet/dist/js/libs/touchr/touchr', + 'jqueryui-amd': '@oracle/oraclejet/dist/js/libs/jquery/jqueryui-amd-1.13.2', + ojs: '@oracle/oraclejet/dist/js/libs/oj/debug', + ojtranslations: '@oracle/oraclejet/dist/js/libs/oj/resources', }, }, resolveLoader: { @@ -97,7 +127,7 @@ module.exports = { text: 'raw-loader?esModule=false', css: 'noop-loader', ojcss: 'noop-loader', - 'ojs/ojcss': 'noop-loader' + 'ojs/ojcss': 'noop-loader', } }, plugins: [ @@ -106,40 +136,33 @@ module.exports = { }), new HtmlReplaceWebpackPlugin( [{ - pattern: webpackUtils.htmlEndInjectorTokenPattern, - replacement: webpackUtils.htmlTokenReplacementFunction + pattern: '', + replacement: '' }, { - pattern: webpackUtils.htmlTokenPattern, - replacement: webpackUtils.htmlTokenReplacementFunction + pattern: '', + replacement: '' }, { - pattern: '', + pattern: '', replacement: '' - }]), - new CopyPlugin({ - patterns: [{ - from: path.resolve(configPaths.src.common, configPaths.src.styles), - to: path.resolve(configPaths.staging.web, configPaths.src.styles), }, { - from: path.join( - webpackUtils.oracleJetDistCssPath, - 'redwood' - ), - to: path.resolve(configPaths.staging.web, configPaths.src.styles, 'redwood'), + pattern: '', + replacement: '' }, { - from: path.join( - webpackUtils.oracleJetDistCssPath, - 'common' - ), - to: path.resolve(configPaths.staging.web, configPaths.src.styles, 'common'), + pattern: '', + replacement: '' }, { - from: path.join(webpackUtils.oracleJetPreactThemePath, 'Theme-redwood'), - to: path.resolve(configPaths.staging.web, configPaths.src.styles, 'theme-redwood'), - }], + pattern: webpackUtils.htmlAppCssLinkTokenPattern, + replacement: '' + }]), + new CleanWebpackPlugin({ + cleanAfterEveryBuildPatterns: ['web/**'], + dry: true, + verbose: true, }), // This plugin sets options for the ojL10n-loader (in this case, just the locale name) new webpack.LoaderOptionsPlugin({ diff --git a/lib/webpack/webpack.development.js b/lib/webpack/webpack.development.js index dbf8d8e..47d3685 100644 --- a/lib/webpack/webpack.development.js +++ b/lib/webpack/webpack.development.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -10,24 +10,26 @@ const webpackUtils = require('./utils'); const common = require('./webpack.common.js'); const PreactRefreshPlugin = ojetUtils.requireLocalFirst('@prefresh/webpack'); -const { merge } = ojetUtils.requireLocalFirst('webpack-merge'); +const { + merge +} = ojetUtils.requireLocalFirst('webpack-merge'); const configPaths = ojetUtils.getConfiguredPaths(); module.exports = merge(common, { mode: 'development', output: { - filename: '[name].bundle.js', + filename: 'js/[name].bundle.js', + clean: true }, devServer: { - static: [ - { - directory: path.join(webpackUtils.oracleJetDistCssPath, 'redwood'), - publicPath: `/${configPaths.src.styles}/redwood`, - }, - { - directory: path.join(webpackUtils.oracleJetDistCssPath, 'common'), - publicPath: `/${configPaths.src.styles}/common`, - }, + static: [{ + directory: path.join(webpackUtils.oracleJetDistCssPath, 'redwood'), + publicPath: `/${configPaths.src.styles}/redwood`, + }, + { + directory: path.join(webpackUtils.oracleJetDistCssPath, 'common'), + publicPath: `/${configPaths.src.styles}/common`, + }, ], client: { overlay: { @@ -40,11 +42,6 @@ module.exports = merge(common, { open: true, hot: true, }, - resolve: { - alias: { - 'oj-c': '@oracle/oraclejet-core-pack/oj-c' - } - }, plugins: [ new PreactRefreshPlugin() ], diff --git a/lib/webpack/webpack.production.js b/lib/webpack/webpack.production.js index a0f7473..6bbb1a4 100644 --- a/lib/webpack/webpack.production.js +++ b/lib/webpack/webpack.production.js @@ -1,43 +1,68 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ */ const path = require('path'); -const zlib = require('zlib'); const ojetUtils = require('../util'); +const zlib = require('zlib'); const common = require('./webpack.common.js'); -const { merge } = ojetUtils.requireLocalFirst('webpack-merge'); +const { + merge +} = ojetUtils.requireLocalFirst('webpack-merge'); const webpack = ojetUtils.requireLocalFirst('webpack'); const MiniCssExtractPlugin = ojetUtils.requireLocalFirst('mini-css-extract-plugin'); const CompressionPlugin = ojetUtils.requireLocalFirst('compression-webpack-plugin'); const configPaths = ojetUtils.getConfiguredPaths(); +const { + CleanWebpackPlugin +} = ojetUtils.requireLocalFirst('clean-webpack-plugin'); module.exports = merge(common, { mode: 'production', devtool: 'source-map', output: { - filename: '[name].[fullhash].js', - chunkFilename: '[name].[fullhash].js', + filename: 'js/[name].[fullhash].js', + chunkFilename: 'js/[name].[fullhash].js', path: path.resolve(configPaths.staging.web), + clean: true + }, module: { - rules: [ - { - test: /\.css$/i, - use: [ - MiniCssExtractPlugin.loader, - 'css-loader' - ], - }, - ], - }, - resolve: { - alias: { - 'oj-c': '@oracle/oraclejet-core-pack/oj-c/min' - } + rules: [{ + test: /\.css$/i, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader', + { + loader: 'css-fix-url-loader', + // There is no path to images/../../redwood/images/. + // Enable webpack to resolve it as images/. + options: { + from: 'images/../../redwood/images', + to: 'images', + } + }, + { + loader: 'css-fix-url-loader', + // There is no 'images' folder under the created theme's folder. + // Redirect the path to the alta's images subfolder. + options: { + from: 'images/animated-overlay.gif', + to: `../../../alta/${ojetUtils.getJETVersion()}/common/images/animated-overlay.gif`, + } + }, + { + loader: 'css-fix-url-loader', + options: { + from: '../../css/redwood/images/AI-Sparkle.gif', + to: './images/AI-Sparkle.gif', + } + }, + ], + }], }, plugins: [ new CompressionPlugin({ @@ -53,7 +78,14 @@ module.exports = merge(common, { minRatio: 0.8, deleteOriginalAssets: false, }), - new MiniCssExtractPlugin(), + new MiniCssExtractPlugin({ + filename: `${configPaths.src.styles}/[name].[fullhash].css` + }), new webpack.optimize.ModuleConcatenationPlugin(), + new CleanWebpackPlugin({ + cleanAfterEveryBuildPatterns: ['web/**'], + dry: true, + verbose: true, + }) ], }); diff --git a/oraclejet-tooling.js b/oraclejet-tooling.js index 6fc648f..c7f6bd0 100644 --- a/oraclejet-tooling.js +++ b/oraclejet-tooling.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -36,6 +36,7 @@ const CONSTANTS = require('./lib/constants'); CONSTANTS.API_TASKS.REMOVE, CONSTANTS.API_TASKS.SEARCH, CONSTANTS.API_TASKS.ADDTYPESCRIPT, + CONSTANTS.API_TASKS.ADDJSDOC, CONSTANTS.API_TASKS.ADDPWA, CONSTANTS.API_TASKS.ADDWEBPACK, 'serve', diff --git a/package.json b/package.json index feb1bf9..9f198cb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oracle/oraclejet-tooling", - "version": "13.1.0", + "version": "14.0.0", "license": "UPL-1.0", "description": "Programmatic API to build and serve Oracle JET web and mobile applications", "keywords": [ diff --git a/test/config.js b/test/config.js index 40aa806..1c05932 100644 --- a/test/config.js +++ b/test/config.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ diff --git a/test/hook.js b/test/hook.js index b62c098..864c414 100644 --- a/test/hook.js +++ b/test/hook.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ @@ -10,19 +10,30 @@ const hooks = require('../lib/hookRunner'); const hookList = [ 'after_app_create', 'after_app_restore', + 'after_app_typescript', 'after_build', 'after_component_build', 'after_component_create', 'after_component_package', + 'after_component_typescript', 'after_serve', + 'after_watch', + 'before_app_typescript', 'before_build', + 'before_component_typescript', 'before_hybrid_build', + 'before_injection', + 'before_component_optimize', 'before_component_package', 'before_optimize', + 'before_release', 'before_release_build', - 'before_serve' + 'before_serve', + 'before_watch', + 'before_webpack' ]; + describe('Hooks Test', () => { before(() => { process.env.NODE_ENV = 'test'; diff --git a/test/util.js b/test/util.js index cde188d..813fc42 100644 --- a/test/util.js +++ b/test/util.js @@ -1,5 +1,5 @@ /** - Copyright (c) 2015, 2022, Oracle and/or its affiliates. + Copyright (c) 2015, 2023, Oracle and/or its affiliates. Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/