diff --git a/.github/workflows/packages_lint.yml b/.github/workflows/packages_lint.yml new file mode 100644 index 0000000..c306f5f --- /dev/null +++ b/.github/workflows/packages_lint.yml @@ -0,0 +1,52 @@ +name: Packages lint +on: + push: + branches: [ main ] + pull_request: + +jobs: + Packages: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v3 + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Node.js modules cache + uses: actions/cache@v3 + id: modules-cache + with: + path: ${{ github.workspace }}/node_modules + key: ${{ runner.os }}-${{ matrix.node-version }}-modules-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.node-version }}-modules + - name: Install Node.js packages + if: ${{ steps.modules-cache.outputs.cache-hit != 'true' }} + run: npm install + - name: Build + run: npm run build:packages-lib + - name: Git modified files + if: ${{ success() }} + run: | + echo 'GIT_MODIFIED<> $GITHUB_ENV + git ls-files -m >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + - name: Lint + if: ${{ success() }} + uses: actions/github-script@v7 + with: + script: | + const action = require(`${process.env.GITHUB_WORKSPACE}/scripts/actions.fileDiffs.js`) + const options = { + rexp: /(packages\.js|packagesLicenses\.txt)$/, + message: "Update packages lib with '$ npm run build:packages-lib'" + }; + const { resultsArray, resultsString } = action(process.env.GIT_MODIFIED, options) + if (resultsArray.length) { + core.setFailed(resultsString) + } diff --git a/DOCS.md b/DOCS.md index 1714c89..051b7c2 100644 --- a/DOCS.md +++ b/DOCS.md @@ -229,47 +229,65 @@ const aPackage = packages.[PACKAGE_NAME]; **Heads up** - Packages is kept separated from `weldable` functions due to ES module loading. Certain packages do but others don't provide modules which can cause issues with tooling, such as `Jest`. +- Every package has 2 exported aspects, the `required` package and a `require.resolve` - We do not provide package use documentation. For package use review associated package. - All packages retain their respective license. It is your responsibility to use said packages accordingly. > The `weldable` lib bundles a [`txt` resource](./lib/packagesLicenses.txt) containing available license materials. -| PACKAGES | EXPOSED NAME | -|------------------------------|----------------------| -| @babel/core | babelCore | -| @tsconfig/create-react-app | N/A | -| @tsconfig/node18 | N/A | -| @tsconfig/node20 | N/A | -| @tsconfig/react-native | N/A | -| @tsconfig/recommended | N/A | -| @tsconfig/strictest | N/A | -| babel-loader | babelLoader | -| copy-webpack-plugin | CopyWebpackPlugin | -| css-loader | cssLoader | -| css-minimizer-webpack-plugin | CssMinimizerWebpackPlugin | -| dotenv | dotenv | -| dotenv-expand | dotenvExpand | -| dotenv-webpack | dotenvWebpack | -| eslint-webpack-plugin | EslintWebpackPlugin | -| html-replace-webpack-plugin | htmlReplaceWebpackPlugin | -| html-webpack-plugin | HtmlWebpackPlugin | -| less | less | -| less-loader | lessLoader | -| mini-css-extract-plugin | MiniCssExtractPlugin | -| mini-svg-data-uri | miniSvgDataUri | -| rimraf | rimraf | -| sass | sass | -| sass-loader | sassLoader | -| style-loader | styleLoader | -| terser-webpack-plugin | TerserWebpackPlugin | -| ts-loader | tsLoader | -| tslib | tslib | -| typescript | typescript | -| webpack | webpack | -| webpack-bundle-analyzer | webpackBundleAnalyzer | -| webpack-cli | WebpackCli | -| webpack-dev-server | WebpackDevServer | -| webpack-merge | webpackMerge | +| PACKAGES | EXPOSED NAME | +|------------------------------|-------------------------------------------------------------| +| @babel/core | babelCore, babelCoreResolve | +| @tsconfig/create-react-app | N/A | +| @tsconfig/node18 | N/A | +| @tsconfig/node20 | N/A | +| @tsconfig/react-native | N/A | +| @tsconfig/recommended | N/A | +| @tsconfig/strictest | N/A | +| babel-loader | babelLoader, babelLoaderResolve | +| copy-webpack-plugin | CopyWebpackPlugin, CopyWebpackPluginResolve | +| css-loader | cssLoader, cssLoaderResolve | +| css-minimizer-webpack-plugin | CssMinimizerWebpackPlugin, CssMinimizerWebpackPluginResolve | +| dotenv | dotenv, dotenvResolve | +| dotenv-expand | dotenvExpand, dotenvExpandResolve | +| dotenv-webpack | dotenvWebpack, dotenvWebpackResolve | +| eslint-webpack-plugin | EslintWebpackPlugin, EslintWebpackPluginResolve | +| html-replace-webpack-plugin | htmlReplaceWebpackPlugin, htmlReplaceWebpackPluginResolve | +| html-webpack-plugin | HtmlWebpackPlugin, HtmlWebpackPluginResolve | +| less | less, lessResolve | +| less-loader | lessLoader, lessLoaderResolve | +| mini-css-extract-plugin | MiniCssExtractPlugin, MiniCssExtractPluginResolve | +| mini-svg-data-uri | miniSvgDataUri, miniSvgDataUriResolve | +| rimraf | rimraf, rimrafResolve | +| sass | sass, sassResolve | +| sass-loader | sassLoader, sassLoaderResolve | +| style-loader | styleLoader, styleLoaderResolve | +| terser-webpack-plugin | TerserWebpackPlugin, TerserWebpackPluginResolve | +| ts-loader | tsLoader, tsLoaderResolve | +| tslib | tslib, tslibResolve | +| typescript | typescript, typescriptResolve | +| webpack | webpack, webpackResolve | +| webpack-bundle-analyzer | webpackBundleAnalyzer, webpackBundleAnalyzerResolve | +| webpack-cli | WebpackCli, WebpackCliResolve | +| webpack-dev-server | WebpackDevServer, WebpackDevServerResolve | +| webpack-merge | webpackMerge, webpackMergeResolve | + +An example webpack config rules loader using the provided `require.resolve`... +``` +const { cssLoaderResolve, MiniCssExtractPlugin, sassLoaderResolve } = require('weldable/lib/packages'); + +module.exports = ({ SRC_DIR } = {}) => ({ + module: { + rules: [ + { + test: /\.(sa|sc)ss$/i, + use: [MiniCssExtractPlugin.loader, cssLoaderResolve, sassLoaderResolve] + } + ] + } +}); +``` + #### Exposed weldable functions diff --git a/README.md b/README.md index cea6dc0..cde8939 100644 --- a/README.md +++ b/README.md @@ -86,20 +86,24 @@ A development start, and production build, using your own webpack configurations ``` #### Basic lib use -The `lib` aspect of `weldable` is exported as CommonJS and is intended to be run as part of a build process. +The `lib` aspect of `weldable` is exported as CommonJS and is intended to be run as part of your build process without the need to install many additional packages. -CommonJS... +Two primary things are exposed through `weldable`... +- packages, such as `webpack-merge` +- and `weldable` "helper" functions + +Example packages use... ``` -const { packages } = require('weldable'); +const packages = require('weldable/lib/packages'); const aPackage = packages.[PACKAGE_NAME]; ``` -ES Module... +Example helper function use... ``` -import { packages } from 'weldable'; +const { dotenv } = require('weldable'); -const aPackage = packages.[PACKAGE_NAME]; +const dotenvFunc = dotenv.[FUNC]; ``` A listing of exposed packages and weldable functions can be found under our [DOCS](./DOCS.md) or diff --git a/lib/packages.js b/lib/packages.js index 34184c5..dd8d73d 100644 --- a/lib/packages.js +++ b/lib/packages.js @@ -1,86 +1,173 @@ +const babelCoreResolve = require.resolve('@babel/core'); +exports.babelCoreResolve = babelCoreResolve; + const babelCore = require('@babel/core'); exports.babelCore = babelCore; +const babelLoaderResolve = require.resolve('babel-loader'); +exports.babelLoaderResolve = babelLoaderResolve; + const babelLoader = require('babel-loader'); exports.babelLoader = babelLoader; +const copyWebpackPluginResolve = require.resolve('copy-webpack-plugin'); +exports.copyWebpackPluginResolve = copyWebpackPluginResolve; + const CopyWebpackPlugin = require('copy-webpack-plugin'); exports.CopyWebpackPlugin = CopyWebpackPlugin; +const cssLoaderResolve = require.resolve('css-loader'); +exports.cssLoaderResolve = cssLoaderResolve; + const cssLoader = require('css-loader'); exports.cssLoader = cssLoader; +const cssMinimizerWebpackPluginResolve = require.resolve('css-minimizer-webpack-plugin'); +exports.cssMinimizerWebpackPluginResolve = cssMinimizerWebpackPluginResolve; + const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin'); exports.CssMinimizerWebpackPlugin = CssMinimizerWebpackPlugin; +const dotenvResolve = require.resolve('dotenv'); +exports.dotenvResolve = dotenvResolve; + const dotenv = require('dotenv'); exports.dotenv = dotenv; +const dotenvExpandResolve = require.resolve('dotenv-expand'); +exports.dotenvExpandResolve = dotenvExpandResolve; + const dotenvExpand = require('dotenv-expand'); exports.dotenvExpand = dotenvExpand; +const dotenvWebpackResolve = require.resolve('dotenv-webpack'); +exports.dotenvWebpackResolve = dotenvWebpackResolve; + const dotenvWebpack = require('dotenv-webpack'); exports.dotenvWebpack = dotenvWebpack; +const eslintWebpackPluginResolve = require.resolve('eslint-webpack-plugin'); +exports.eslintWebpackPluginResolve = eslintWebpackPluginResolve; + const EslintWebpackPlugin = require('eslint-webpack-plugin'); exports.EslintWebpackPlugin = EslintWebpackPlugin; +const htmlReplaceWebpackPluginResolve = require.resolve('html-replace-webpack-plugin'); +exports.htmlReplaceWebpackPluginResolve = htmlReplaceWebpackPluginResolve; + const htmlReplaceWebpackPlugin = require('html-replace-webpack-plugin'); exports.htmlReplaceWebpackPlugin = htmlReplaceWebpackPlugin; +const htmlWebpackPluginResolve = require.resolve('html-webpack-plugin'); +exports.htmlWebpackPluginResolve = htmlWebpackPluginResolve; + const HtmlWebpackPlugin = require('html-webpack-plugin'); exports.HtmlWebpackPlugin = HtmlWebpackPlugin; +const lessResolve = require.resolve('less'); +exports.lessResolve = lessResolve; + const less = require('less'); exports.less = less; +const lessLoaderResolve = require.resolve('less-loader'); +exports.lessLoaderResolve = lessLoaderResolve; + const lessLoader = require('less-loader'); exports.lessLoader = lessLoader; +const miniCssExtractPluginResolve = require.resolve('mini-css-extract-plugin'); +exports.miniCssExtractPluginResolve = miniCssExtractPluginResolve; + const MiniCssExtractPlugin = require('mini-css-extract-plugin'); exports.MiniCssExtractPlugin = MiniCssExtractPlugin; +const miniSvgDataUriResolve = require.resolve('mini-svg-data-uri'); +exports.miniSvgDataUriResolve = miniSvgDataUriResolve; + const miniSvgDataUri = require('mini-svg-data-uri'); exports.miniSvgDataUri = miniSvgDataUri; +const rimrafResolve = require.resolve('rimraf'); +exports.rimrafResolve = rimrafResolve; + const rimraf = require('rimraf'); exports.rimraf = rimraf; +const sassResolve = require.resolve('sass'); +exports.sassResolve = sassResolve; + const sass = require('sass'); exports.sass = sass; +const sassLoaderResolve = require.resolve('sass-loader'); +exports.sassLoaderResolve = sassLoaderResolve; + const sassLoader = require('sass-loader'); exports.sassLoader = sassLoader; +const styleLoaderResolve = require.resolve('style-loader'); +exports.styleLoaderResolve = styleLoaderResolve; + const styleLoader = require('style-loader'); exports.styleLoader = styleLoader; +const terserWebpackPluginResolve = require.resolve('terser-webpack-plugin'); +exports.terserWebpackPluginResolve = terserWebpackPluginResolve; + const TerserWebpackPlugin = require('terser-webpack-plugin'); exports.TerserWebpackPlugin = TerserWebpackPlugin; +const tsLoaderResolve = require.resolve('ts-loader'); +exports.tsLoaderResolve = tsLoaderResolve; + const tsLoader = require('ts-loader'); exports.tsLoader = tsLoader; +const tslibResolve = require.resolve('tslib'); +exports.tslibResolve = tslibResolve; + const tslib = require('tslib'); exports.tslib = tslib; +const typescriptResolve = require.resolve('typescript'); +exports.typescriptResolve = typescriptResolve; + const typescript = require('typescript'); exports.typescript = typescript; +const webpackResolve = require.resolve('webpack'); +exports.webpackResolve = webpackResolve; + const webpack = require('webpack'); exports.webpack = webpack; +const webpackBundleAnalyzerResolve = require.resolve('webpack-bundle-analyzer'); +exports.webpackBundleAnalyzerResolve = webpackBundleAnalyzerResolve; + const webpackBundleAnalyzer = require('webpack-bundle-analyzer'); exports.webpackBundleAnalyzer = webpackBundleAnalyzer; +const webpackCliResolve = require.resolve('webpack-cli'); +exports.webpackCliResolve = webpackCliResolve; + const WebpackCli = require('webpack-cli'); exports.WebpackCli = WebpackCli; +const webpackDevServerResolve = require.resolve('webpack-dev-server'); +exports.webpackDevServerResolve = webpackDevServerResolve; + const WebpackDevServer = require('webpack-dev-server'); exports.WebpackDevServer = WebpackDevServer; +const webpackMergeResolve = require.resolve('webpack-merge'); +exports.webpackMergeResolve = webpackMergeResolve; + const webpackMerge = require('webpack-merge'); exports.webpackMerge = webpackMerge; +const yargsResolve = require.resolve('yargs'); +exports.yargsResolve = yargsResolve; + const yargs = require('yargs'); exports.yargs = yargs; diff --git a/lib/packagesLicenses.txt b/lib/packagesLicenses.txt index 3560bd8..fcaf73c 100644 --- a/lib/packagesLicenses.txt +++ b/lib/packagesLicenses.txt @@ -2120,6 +2120,38 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- + +web license: + +Copyright 2023, the Dart project authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google LLC nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + -------------------------------------------------------------------------------- yaml license: diff --git a/scripts/actions.fileDiffs.js b/scripts/actions.fileDiffs.js new file mode 100644 index 0000000..98e5cb1 --- /dev/null +++ b/scripts/actions.fileDiffs.js @@ -0,0 +1,45 @@ +/** + * Breakout individual files for filtering. + * + * @param {string} files + * @param {object} options + * @param {string|*} options.rexp + * @param {string} options.message + * @returns {Array} + */ +const filterFiles = (files, { rexp, message = '' } = {}) => + files + .trim() + .split(/\n/g) + .filter(file => { + const updatedFile = file.trim(); + + if (rexp) { + const updatedExp = (typeof rexp === 'string' && new RegExp(rexp)) || rexp; + return updatedFile.length > 0 && updatedExp.test(updatedFile); + } + + return updatedFile.length > 0; + }) + .map(file => `File > ${file} > is modified.${(message && ` ${message}`) || ''}`); + +/** + * If modified files exist, throw an error. + * + * @param {string} files + * @param {object} options + * @param {string|*} options.rexp + * @param {string} options.message + * @returns {{resultsArray: Array, resultsString: string}} + */ +module.exports = (files, options) => { + const lintResults = { resultsArray: [], resultsString: '' }; + + if (files) { + const parsedResults = filterFiles(files, options); + lintResults.resultsArray = parsedResults; + lintResults.resultsString = JSON.stringify(parsedResults, null, 2); + } + + return lintResults; +}; diff --git a/scripts/generatePackagesLib.js b/scripts/generatePackagesLib.js index 8c5c868..3c6717a 100644 --- a/scripts/generatePackagesLib.js +++ b/scripts/generatePackagesLib.js @@ -69,33 +69,41 @@ const createPackagesExport = async () => { const defaultOrValue = value?.default || value || undefined; const updatedKey = _camelCase(key); + const updatedResolve = _camelCase(`${key}_Resolve`); + const keyDefaults = { + key, + license, + resolve: updatedResolve + }; + if (defaultOrValue) { if (typeof defaultOrValue === 'object') { - updatedPackages[updatedKey] = { - key, - license - }; + updatedPackages[updatedKey] = keyDefaults; } else { const isPossiblyClassButWhoReallyCares = /^class/i.test(defaultOrValue.toString()); - updatedPackages[(isPossiblyClassButWhoReallyCares && _upperFirst(updatedKey)) || updatedKey] = { - key, - license - }; + updatedPackages[(isPossiblyClassButWhoReallyCares && _upperFirst(updatedKey)) || updatedKey] = keyDefaults; } } else { - consoleMessage.info(`No exported value or default found, skipping package: ${updatedKey}`); + consoleMessage.info(`No exported value or default found, skipping package require: ${updatedKey}`); } } }); // Create package js file const str = []; - Object.entries(updatedPackages).forEach(([key, { key: value }]) => { - str.push(`const ${key} = require('${value}');\nexports.${key} = ${key};`); + Object.entries(updatedPackages).forEach(([key, { key: value, resolve }]) => { + str.push( + `const ${resolve} = require.resolve('${value}');`, + `exports.${resolve} = ${resolve};`, + '', + `const ${key} = require('${value}');`, + `exports.${key} = ${key};`, + '' + ); }); - createFile(str.join('\n\n') + '\n', { + createFile(str.join('\n'), { dir: path.join(__dirname, '..', 'lib'), filename: 'packages.js' });