From 22daa00afb1a5d628e0267fba0f062c4f8fb5613 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 15 Sep 2023 13:37:20 +0200 Subject: Adding upstream version 5.3.2+dfsg. Signed-off-by: Daniel Baumann --- .cspell.json | 1 + .eslintrc.json | 2 +- .github/workflows/browserstack.yml | 2 +- .github/workflows/bundlewatch.yml | 2 +- .github/workflows/calibreapp-image-actions.yml | 8 +- .github/workflows/codeql.yml | 2 +- .github/workflows/cspell.yml | 4 +- .github/workflows/css.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/js.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/node-sass.yml | 2 +- README.md | 12 +- build/banner.js | 15 - build/banner.mjs | 20 + build/build-plugins.js | 103 - build/build-plugins.mjs | 105 + build/change-version.js | 101 - build/change-version.mjs | 113 + build/generate-sri.js | 63 - build/generate-sri.mjs | 64 + build/postcss.config.js | 19 - build/postcss.config.mjs | 17 + build/rollup.config.js | 57 - build/rollup.config.mjs | 59 + build/vnu-jar.js | 61 - build/vnu-jar.mjs | 59 + build/zip-examples.js | 98 - build/zip-examples.mjs | 101 + hugo.yml | 26 +- js/src/base-component.js | 2 +- js/src/dom/selector-engine.js | 4 +- js/src/tab.js | 2 +- js/tests/unit/dom/selector-engine.spec.js | 12 + package-lock.json | 2740 +++++++++++--------- package.js | 2 +- package.json | 64 +- scss/_buttons.scss | 2 +- scss/_reboot.scss | 1 + scss/_root.scss | 3 + scss/_utilities.scss | 6 +- scss/_variables-dark.scss | 2 + scss/_variables.scss | 28 +- scss/forms/_form-check.scss | 1 + scss/mixins/_banner.scss | 2 +- scss/mixins/_grid.scss | 2 +- site/assets/scss/_navbar.scss | 2 +- site/assets/scss/_scrolling.scss | 3 + site/assets/scss/_sidebar.scss | 2 +- site/content/docs/5.3/components/popovers.md | 2 +- .../docs/5.3/examples/dashboard-rtl/index.html | 6 +- .../content/docs/5.3/examples/dashboard/index.html | 6 +- .../5.3/examples/features/unsplash-photo-1.jpg | Bin 10451 -> 10433 bytes .../5.3/examples/features/unsplash-photo-2.jpg | Bin 113018 -> 113000 bytes .../5.3/examples/features/unsplash-photo-3.jpg | Bin 40607 -> 40589 bytes .../docs/5.3/examples/heroes/bootstrap-docs.png | Bin 371399 -> 369569 bytes .../docs/5.3/examples/starter-template/index.html | 2 +- site/content/docs/5.3/getting-started/download.md | 18 + .../docs/5.3/getting-started/introduction.md | 13 +- .../content/docs/5.3/getting-started/javascript.md | 3 +- site/content/docs/5.3/layout/gutters.md | 2 +- site/content/docs/5.3/migration.md | 71 +- site/data/docs-versions.yml | 2 +- site/layouts/_default/examples.html | 5 + .../5.3/assets/brand/bootstrap-logo-shadow.png | Bin 48625 -> 46142 bytes .../static/docs/5.3/assets/img/bootstrap-icons.png | Bin 40798 -> 40444 bytes .../5.3/assets/img/bootstrap-themes-collage@2x.png | Bin 244640 -> 244028 bytes .../docs/5.3/assets/img/examples/album@2x.png | Bin 25026 -> 24917 bytes .../docs/5.3/assets/img/examples/badges@2x.png | Bin 14798 -> 14236 bytes .../docs/5.3/assets/img/examples/buttons.png | Bin 4545 -> 4495 bytes .../docs/5.3/assets/img/examples/buttons@2x.png | Bin 9994 -> 9832 bytes .../docs/5.3/assets/img/examples/carousel-rtl.png | Bin 10344 -> 10264 bytes .../5.3/assets/img/examples/carousel-rtl@2x.png | Bin 24460 -> 24421 bytes .../docs/5.3/assets/img/examples/carousel.png | Bin 13219 -> 13178 bytes .../docs/5.3/assets/img/examples/carousel@2x.png | Bin 31320 -> 31276 bytes .../5.3/assets/img/examples/dashboard-rtl@2x.png | Bin 19399 -> 19368 bytes .../docs/5.3/assets/img/examples/headers.png | Bin 5196 -> 5182 bytes .../docs/5.3/assets/img/examples/headers@2x.png | Bin 12639 -> 12566 bytes .../docs/5.3/assets/img/examples/list-groups.png | Bin 7134 -> 7116 bytes .../docs/5.3/assets/img/examples/masonry.png | Bin 15253 -> 15238 bytes .../docs/5.3/assets/img/examples/masonry@2x.png | Bin 37705 -> 37623 bytes .../docs/5.3/assets/img/examples/navbar-bottom.png | Bin 4819 -> 4754 bytes .../5.3/assets/img/examples/navbar-bottom@2x.png | Bin 11666 -> 11603 bytes .../5.3/assets/img/examples/navbars-offcanvas.png | Bin 6850 -> 6821 bytes .../assets/img/examples/navbars-offcanvas@2x.png | Bin 16965 -> 16919 bytes .../5.3/assets/img/examples/offcanvas-navbar.png | Bin 9691 -> 9674 bytes .../assets/img/examples/offcanvas-navbar@2x.png | Bin 23975 -> 23928 bytes .../assets/img/examples/sticky-footer-navbar.png | Bin 6966 -> 6895 bytes .../img/examples/sticky-footer-navbar@2x.png | Bin 15744 -> 15725 bytes .../5.3/assets/img/favicons/apple-touch-icon.png | Bin 7650 -> 7489 bytes .../5.3/assets/img/guides/parcel-dev-server.png | Bin 13933 -> 13694 bytes .../docs/5.3/assets/img/guides/vite-dev-server.png | Bin 13584 -> 13266 bytes .../5.3/assets/img/guides/webpack-dev-server.png | Bin 14197 -> 14001 bytes 93 files changed, 2214 insertions(+), 1920 deletions(-) delete mode 100644 build/banner.js create mode 100644 build/banner.mjs delete mode 100644 build/build-plugins.js create mode 100644 build/build-plugins.mjs delete mode 100644 build/change-version.js create mode 100644 build/change-version.mjs delete mode 100644 build/generate-sri.js create mode 100644 build/generate-sri.mjs delete mode 100644 build/postcss.config.js create mode 100644 build/postcss.config.mjs delete mode 100644 build/rollup.config.js create mode 100644 build/rollup.config.mjs delete mode 100644 build/vnu-jar.js create mode 100644 build/vnu-jar.mjs delete mode 100644 build/zip-examples.js create mode 100644 build/zip-examples.mjs diff --git a/.cspell.json b/.cspell.json index e477ef8..484af2a 100644 --- a/.cspell.json +++ b/.cspell.json @@ -40,6 +40,7 @@ "dropright", "dropstart", "dropup", + "dgst", "errorf", "favicon", "favicons", diff --git a/.eslintrc.json b/.eslintrc.json index 055acc7..6c9c24d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -108,7 +108,7 @@ "node": true }, "parserOptions": { - "sourceType": "script" + "sourceType": "module" }, "rules": { "no-console": "off", diff --git a/.github/workflows/browserstack.yml b/.github/workflows/browserstack.yml index e545d62..8d8cb1c 100644 --- a/.github/workflows/browserstack.yml +++ b/.github/workflows/browserstack.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/bundlewatch.yml b/.github/workflows/bundlewatch.yml index c02a37e..7f58b24 100644 --- a/.github/workflows/bundlewatch.yml +++ b/.github/workflows/bundlewatch.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/calibreapp-image-actions.yml b/.github/workflows/calibreapp-image-actions.yml index 21df1f6..f4aeb87 100644 --- a/.github/workflows/calibreapp-image-actions.yml +++ b/.github/workflows/calibreapp-image-actions.yml @@ -8,15 +8,21 @@ on: - '**.png' - '**.webp' +permissions: + contents: read + jobs: build: # Only run on Pull Requests within the same repository, and not from forks. if: github.event.pull_request.head.repo.full_name == github.repository name: calibreapp/image-actions runs-on: ubuntu-latest + permissions: + # allow calibreapp/image-actions to update PRs + pull-requests: write steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b1780ee..6d5f778 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/cspell.yml b/.github/workflows/cspell.yml index 11788e3..3e7902e 100644 --- a/.github/workflows/cspell.yml +++ b/.github/workflows/cspell.yml @@ -23,12 +23,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Run cspell - uses: streetsidesoftware/cspell-action@v2 + uses: streetsidesoftware/cspell-action@v3 with: config: ".cspell.json" files: "**/*.md" diff --git a/.github/workflows/css.yml b/.github/workflows/css.yml index 66112a9..d859c45 100644 --- a/.github/workflows/css.yml +++ b/.github/workflows/css.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 2a684f6..278b099 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml index 805b1b7..e123e98 100644 --- a/.github/workflows/js.yml +++ b/.github/workflows/js.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fd62b41..7c88ddc 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/node-sass.yml b/.github/workflows/node-sass.yml index c558e44..51ea6bf 100644 --- a/.github/workflows/node-sass.yml +++ b/.github/workflows/node-sass.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/README.md b/README.md index c08d4cb..9826293 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,11 @@ Our default branch is for development of our Bootstrap 5 release. Head to the [` Several quick start options are available: -- [Download the latest release](https://github.com/twbs/bootstrap/archive/v5.3.1.zip) +- [Download the latest release](https://github.com/twbs/bootstrap/archive/v5.3.2.zip) - Clone the repo: `git clone https://github.com/twbs/bootstrap.git` -- Install with [npm](https://www.npmjs.com/): `npm install bootstrap@v5.3.1` -- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@v5.3.1` -- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:5.3.1` +- Install with [npm](https://www.npmjs.com/): `npm install bootstrap@v5.3.2` +- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@v5.3.2` +- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:5.3.2` - Install with [NuGet](https://www.nuget.org/): CSS: `Install-Package bootstrap` Sass: `Install-Package bootstrap.sass` Read the [Getting started page](https://getbootstrap.com/docs/5.3/getting-started/introduction/) for information on the framework contents, templates, examples, and more. @@ -69,7 +69,6 @@ Read the [Getting started page](https://getbootstrap.com/docs/5.3/getting-starte [![CSS Brotli size](https://img.badgesize.io/twbs/bootstrap/main/dist/css/bootstrap.min.css?compression=brotli&label=CSS%20Brotli%20size)](https://github.com/twbs/bootstrap/blob/main/dist/css/bootstrap.min.css) [![JS gzip size](https://img.badgesize.io/twbs/bootstrap/main/dist/js/bootstrap.min.js?compression=gzip&label=JS%20gzip%20size)](https://github.com/twbs/bootstrap/blob/main/dist/js/bootstrap.min.js) [![JS Brotli size](https://img.badgesize.io/twbs/bootstrap/main/dist/js/bootstrap.min.js?compression=brotli&label=JS%20Brotli%20size)](https://github.com/twbs/bootstrap/blob/main/dist/js/bootstrap.min.js) -[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=SkxZcStBeExEdVJqQ2hWYnlWckpkNmNEY213SFp6WHFETWk2bGFuY3pCbz0tLXhqbHJsVlZhQnRBdEpod3NLSDMzaHc9PQ==--3d0b75245708616eb93113221beece33e680b229)](https://www.browserstack.com/automate/public-build/SkxZcStBeExEdVJqQ2hWYnlWckpkNmNEY213SFp6WHFETWk2bGFuY3pCbz0tLXhqbHJsVlZhQnRBdEpod3NLSDMzaHc9PQ==--3d0b75245708616eb93113221beece33e680b229) [![Backers on Open Collective](https://img.shields.io/opencollective/backers/bootstrap?logo=opencollective&logoColor=fff)](#backers) [![Sponsors on Open Collective](https://img.shields.io/opencollective/sponsors/bootstrap?logo=opencollective&logoColor=fff)](#sponsors) @@ -177,7 +176,8 @@ Get updates on Bootstrap's development and chat with the project maintainers and - Follow [@getbootstrap on Twitter](https://twitter.com/getbootstrap). - Read and subscribe to [The Official Bootstrap Blog](https://blog.getbootstrap.com/). -- Ask and explore [our GitHub Discussions](https://github.com/twbs/bootstrap/discussions). +- Ask questions and explore [our GitHub Discussions](https://github.com/twbs/bootstrap/discussions). +- Discuss, ask questions, and more on [the community Discord](https://discord.gg/bZUvakRU3M) or [Bootstrap subreddit](https://reddit.com/r/bootstrap). - Chat with fellow Bootstrappers in IRC. On the `irc.libera.chat` server, in the `#bootstrap` channel. - Implementation help may be found at Stack Overflow (tagged [`bootstrap-5`](https://stackoverflow.com/questions/tagged/bootstrap-5)). - Developers should use the keyword `bootstrap` on packages which modify or add to the functionality of Bootstrap when distributing through [npm](https://www.npmjs.com/browse/keyword/bootstrap) or similar delivery mechanisms for maximum discoverability. diff --git a/build/banner.js b/build/banner.js deleted file mode 100644 index a022f1c..0000000 --- a/build/banner.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict' - -const pkg = require('../package.json') - -const year = new Date().getFullYear() - -function getBanner(pluginFilename) { - return `/*! - * Bootstrap${pluginFilename ? ` ${pluginFilename}` : ''} v${pkg.version} (${pkg.homepage}) - * Copyright 2011-${year} ${pkg.author} - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */` -} - -module.exports = getBanner diff --git a/build/banner.mjs b/build/banner.mjs new file mode 100644 index 0000000..3fea93c --- /dev/null +++ b/build/banner.mjs @@ -0,0 +1,20 @@ +import fs from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +const pkgJson = path.join(__dirname, '../package.json') +const pkg = JSON.parse(await fs.readFile(pkgJson, 'utf8')) + +const year = new Date().getFullYear() + +function getBanner(pluginFilename) { + return `/*! + * Bootstrap${pluginFilename ? ` ${pluginFilename}` : ''} v${pkg.version} (${pkg.homepage}) + * Copyright 2011-${year} ${pkg.author} + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */` +} + +export default getBanner diff --git a/build/build-plugins.js b/build/build-plugins.js deleted file mode 100644 index b2833a3..0000000 --- a/build/build-plugins.js +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env node - -/*! - * Script to build our plugins to use them separately. - * Copyright 2020-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ - -'use strict' - -const path = require('node:path') -const rollup = require('rollup') -const globby = require('globby') -const { babel } = require('@rollup/plugin-babel') -const banner = require('./banner.js') - -const sourcePath = path.resolve(__dirname, '../js/src/').replace(/\\/g, '/') -const jsFiles = globby.sync(`${sourcePath}/**/*.js`) - -// Array which holds the resolved plugins -const resolvedPlugins = [] - -// Trims the "js" extension and uppercases => first letter, hyphens, backslashes & slashes -const filenameToEntity = filename => filename.replace('.js', '') - .replace(/(?:^|-|\/|\\)[a-z]/g, str => str.slice(-1).toUpperCase()) - -for (const file of jsFiles) { - resolvedPlugins.push({ - src: file, - dist: file.replace('src', 'dist'), - fileName: path.basename(file), - className: filenameToEntity(path.basename(file)) - // safeClassName: filenameToEntity(path.relative(sourcePath, file)) - }) -} - -const build = async plugin => { - const globals = {} - - const bundle = await rollup.rollup({ - input: plugin.src, - plugins: [ - babel({ - // Only transpile our source code - exclude: 'node_modules/**', - // Include the helpers in each file, at most one copy of each - babelHelpers: 'bundled' - }) - ], - external(source) { - // Pattern to identify local files - const pattern = /^(\.{1,2})\// - - // It's not a local file, e.g a Node.js package - if (!pattern.test(source)) { - globals[source] = source - return true - } - - const usedPlugin = resolvedPlugins.find(plugin => { - return plugin.src.includes(source.replace(pattern, '')) - }) - - if (!usedPlugin) { - throw new Error(`Source ${source} is not mapped!`) - } - - // We can change `Index` with `UtilIndex` etc if we use - // `safeClassName` instead of `className` everywhere - globals[path.normalize(usedPlugin.src)] = usedPlugin.className - return true - } - }) - - await bundle.write({ - banner: banner(plugin.fileName), - format: 'umd', - name: plugin.className, - sourcemap: true, - globals, - generatedCode: 'es2015', - file: plugin.dist - }) - - console.log(`Built ${plugin.className}`) -} - -(async () => { - try { - const basename = path.basename(__filename) - const timeLabel = `[${basename}] finished` - - console.log('Building individual plugins...') - console.time(timeLabel) - - await Promise.all(Object.values(resolvedPlugins).map(plugin => build(plugin))) - - console.timeEnd(timeLabel) - } catch (error) { - console.error(error) - process.exit(1) - } -})() diff --git a/build/build-plugins.mjs b/build/build-plugins.mjs new file mode 100644 index 0000000..77e6307 --- /dev/null +++ b/build/build-plugins.mjs @@ -0,0 +1,105 @@ +#!/usr/bin/env node + +/*! + * Script to build our plugins to use them separately. + * Copyright 2020-2023 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ + +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { babel } from '@rollup/plugin-babel' +import globby from 'globby' +import { rollup } from 'rollup' +import banner from './banner.mjs' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +const sourcePath = path.resolve(__dirname, '../js/src/').replace(/\\/g, '/') +const jsFiles = globby.sync(`${sourcePath}/**/*.js`) + +// Array which holds the resolved plugins +const resolvedPlugins = [] + +// Trims the "js" extension and uppercases => first letter, hyphens, backslashes & slashes +const filenameToEntity = filename => filename.replace('.js', '') + .replace(/(?:^|-|\/|\\)[a-z]/g, str => str.slice(-1).toUpperCase()) + +for (const file of jsFiles) { + resolvedPlugins.push({ + src: file, + dist: file.replace('src', 'dist'), + fileName: path.basename(file), + className: filenameToEntity(path.basename(file)) + // safeClassName: filenameToEntity(path.relative(sourcePath, file)) + }) +} + +const build = async plugin => { + const globals = {} + + const bundle = await rollup({ + input: plugin.src, + plugins: [ + babel({ + // Only transpile our source code + exclude: 'node_modules/**', + // Include the helpers in each file, at most one copy of each + babelHelpers: 'bundled' + }) + ], + external(source) { + // Pattern to identify local files + const pattern = /^(\.{1,2})\// + + // It's not a local file, e.g a Node.js package + if (!pattern.test(source)) { + globals[source] = source + return true + } + + const usedPlugin = resolvedPlugins.find(plugin => { + return plugin.src.includes(source.replace(pattern, '')) + }) + + if (!usedPlugin) { + throw new Error(`Source ${source} is not mapped!`) + } + + // We can change `Index` with `UtilIndex` etc if we use + // `safeClassName` instead of `className` everywhere + globals[path.normalize(usedPlugin.src)] = usedPlugin.className + return true + } + }) + + await bundle.write({ + banner: banner(plugin.fileName), + format: 'umd', + name: plugin.className, + sourcemap: true, + globals, + generatedCode: 'es2015', + file: plugin.dist + }) + + console.log(`Built ${plugin.className}`) +} + +(async () => { + try { + const basename = path.basename(__filename) + const timeLabel = `[${basename}] finished` + + console.log('Building individual plugins...') + console.time(timeLabel) + + await Promise.all(Object.values(resolvedPlugins).map(plugin => build(plugin))) + + console.timeEnd(timeLabel) + } catch (error) { + console.error(error) + process.exit(1) + } +})() diff --git a/build/change-version.js b/build/change-version.js deleted file mode 100644 index 9685df5..0000000 --- a/build/change-version.js +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env node - -/*! - * Script to update version number references in the project. - * Copyright 2017-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ - -'use strict' - -const fs = require('node:fs').promises -const path = require('node:path') -const globby = require('globby') - -const VERBOSE = process.argv.includes('--verbose') -const DRY_RUN = process.argv.includes('--dry') || process.argv.includes('--dry-run') - -// These are the filetypes we only care about replacing the version -const GLOB = [ - '**/*.{css,html,js,json,md,scss,txt,yml}' -] -const GLOBBY_OPTIONS = { - cwd: path.join(__dirname, '..'), - gitignore: true -} - -// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37 -function regExpQuote(string) { - return string.replace(/[$()*+-.?[\\\]^{|}]/g, '\\$&') -} - -function regExpQuoteReplacement(string) { - return string.replace(/\$/g, '$$') -} - -async function replaceRecursively(file, oldVersion, newVersion) { - const originalString = await fs.readFile(file, 'utf8') - const newString = originalString - .replace( - new RegExp(regExpQuote(oldVersion), 'g'), - regExpQuoteReplacement(newVersion) - ) - // Also replace the version used by the rubygem, - // which is using periods (`.`) instead of hyphens (`-`) - .replace( - new RegExp(regExpQuote(oldVersion.replace(/-/g, '.')), 'g'), - regExpQuoteReplacement(newVersion.replace(/-/g, '.')) - ) - - // No need to move any further if the strings are identical - if (originalString === newString) { - return - } - - if (VERBOSE) { - console.log(`FILE: ${file}`) - } - - if (DRY_RUN) { - return - } - - await fs.writeFile(file, newString, 'utf8') -} - -function showUsage(args) { - console.error('USAGE: change-version old_version new_version [--verbose] [--dry[-run]]') - console.error('Got arguments:', args) - process.exit(1) -} - -async function main(args) { - let [oldVersion, newVersion] = args - - if (!oldVersion || !newVersion) { - showUsage(args) - } - - // Strip any leading `v` from arguments because - // otherwise we will end up with duplicate `v`s - [oldVersion, newVersion] = [oldVersion, newVersion].map(arg => { - return arg.startsWith('v') ? arg.slice(1) : arg - }) - - if (oldVersion === newVersion) { - showUsage(args) - } - - try { - const files = await globby(GLOB, GLOBBY_OPTIONS) - - await Promise.all( - files.map(file => replaceRecursively(file, oldVersion, newVersion)) - ) - } catch (error) { - console.error(error) - process.exit(1) - } -} - -main(process.argv.slice(2)) diff --git a/build/change-version.mjs b/build/change-version.mjs new file mode 100644 index 0000000..3c1e706 --- /dev/null +++ b/build/change-version.mjs @@ -0,0 +1,113 @@ +#!/usr/bin/env node + +/*! + * Script to update version number references in the project. + * Copyright 2017-2023 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ + +import { execFile } from 'node:child_process' +import fs from 'node:fs/promises' +import process from 'node:process' + +const VERBOSE = process.argv.includes('--verbose') +const DRY_RUN = process.argv.includes('--dry') || process.argv.includes('--dry-run') + +// These are the files we only care about replacing the version +const FILES = [ + 'README.md', + 'hugo.yml', + 'js/src/base-component.js', + 'package.js', + 'scss/mixins/_banner.scss', + 'site/data/docs-versions.yml' +] + +// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37 +function regExpQuote(string) { + return string.replace(/[$()*+-.?[\\\]^{|}]/g, '\\$&') +} + +function regExpQuoteReplacement(string) { + return string.replace(/\$/g, '$$') +} + +async function replaceRecursively(file, oldVersion, newVersion) { + const originalString = await fs.readFile(file, 'utf8') + const newString = originalString + .replace( + new RegExp(regExpQuote(oldVersion), 'g'), + regExpQuoteReplacement(newVersion) + ) + // Also replace the version used by the rubygem, + // which is using periods (`.`) instead of hyphens (`-`) + .replace( + new RegExp(regExpQuote(oldVersion.replace(/-/g, '.')), 'g'), + regExpQuoteReplacement(newVersion.replace(/-/g, '.')) + ) + + // No need to move any further if the strings are identical + if (originalString === newString) { + return + } + + if (VERBOSE) { + console.log(`Found ${oldVersion} in ${file}`) + } + + if (DRY_RUN) { + return + } + + await fs.writeFile(file, newString, 'utf8') +} + +function bumpNpmVersion(newVersion) { + if (DRY_RUN) { + return + } + + execFile('npm', ['version', newVersion, '--no-git-tag'], { shell: true }, error => { + if (error) { + console.error(error) + process.exit(1) + } + }) +} + +function showUsage(args) { + console.error('USAGE: change-version old_version new_version [--verbose] [--dry[-run]]') + console.error('Got arguments:', args) + process.exit(1) +} + +async function main(args) { + let [oldVersion, newVersion] = args + + if (!oldVersion || !newVersion) { + showUsage(args) + } + + // Strip any leading `v` from arguments because + // otherwise we will end up with duplicate `v`s + [oldVersion, newVersion] = [oldVersion, newVersion].map(arg => { + return arg.startsWith('v') ? arg.slice(1) : arg + }) + + if (oldVersion === newVersion) { + showUsage(args) + } + + bumpNpmVersion(newVersion) + + try { + await Promise.all( + FILES.map(file => replaceRecursively(file, oldVersion, newVersion)) + ) + } catch (error) { + console.error(error) + process.exit(1) + } +} + +main(process.argv.slice(2)) diff --git a/build/generate-sri.js b/build/generate-sri.js deleted file mode 100644 index 2e22924..0000000 --- a/build/generate-sri.js +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env node - -/*! - * Script to generate SRI hashes for use in our docs. - * Remember to use the same vendor files as the CDN ones, - * otherwise the hashes won't match! - * - * Copyright 2017-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ - -'use strict' - -const crypto = require('node:crypto') -const fs = require('node:fs') -const path = require('node:path') -const sh = require('shelljs') - -sh.config.fatal = true - -const configFile = path.join(__dirname, '../hugo.yml') - -// Array of objects which holds the files to generate SRI hashes for. -// `file` is the path from the root folder -// `configPropertyName` is the hugo.yml variable's name of the file -const files = [ - { - file: 'dist/css/bootstrap.min.css', - configPropertyName: 'css_hash' - }, - { - file: 'dist/css/bootstrap.rtl.min.css', - configPropertyName: 'css_rtl_hash' - }, - { - file: 'dist/js/bootstrap.min.js', - configPropertyName: 'js_hash' - }, - { - file: 'dist/js/bootstrap.bundle.min.js', - configPropertyName: 'js_bundle_hash' - }, - { - file: 'node_modules/@popperjs/core/dist/umd/popper.min.js', - configPropertyName: 'popper_hash' - } -] - -for (const { file, configPropertyName } of files) { - fs.readFile(file, 'utf8', (error, data) => { - if (error) { - throw error - } - - const algo = 'sha384' - const hash = crypto.createHash(algo).update(data, 'utf8').digest('base64') - const integrity = `${algo}-${hash}` - - console.log(`${configPropertyName}: ${integrity}`) - - sh.sed('-i', new RegExp(`^(\\s+${configPropertyName}:\\s+["'])\\S*(["'])`), `$1${integrity}$2`, configFile) - }) -} diff --git a/build/generate-sri.mjs b/build/generate-sri.mjs new file mode 100644 index 0000000..e2b1554 --- /dev/null +++ b/build/generate-sri.mjs @@ -0,0 +1,64 @@ +#!/usr/bin/env node + +/*! + * Script to generate SRI hashes for use in our docs. + * Remember to use the same vendor files as the CDN ones, + * otherwise the hashes won't match! + * + * Copyright 2017-2023 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ + +import crypto from 'node:crypto' +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import sh from 'shelljs' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +sh.config.fatal = true + +const configFile = path.join(__dirname, '../hugo.yml') + +// Array of objects which holds the files to generate SRI hashes for. +// `file` is the path from the root folder +// `configPropertyName` is the hugo.yml variable's name of the file +const files = [ + { + file: 'dist/css/bootstrap.min.css', + configPropertyName: 'css_hash' + }, + { + file: 'dist/css/bootstrap.rtl.min.css', + configPropertyName: 'css_rtl_hash' + }, + { + file: 'dist/js/bootstrap.min.js', + configPropertyName: 'js_hash' + }, + { + file: 'dist/js/bootstrap.bundle.min.js', + configPropertyName: 'js_bundle_hash' + }, + { + file: 'node_modules/@popperjs/core/dist/umd/popper.min.js', + configPropertyName: 'popper_hash' + } +] + +for (const { file, configPropertyName } of files) { + fs.readFile(file, 'utf8', (error, data) => { + if (error) { + throw error + } + + const algorithm = 'sha384' + const hash = crypto.createHash(algorithm).update(data, 'utf8').digest('base64') + const integrity = `${algorithm}-${hash}` + + console.log(`${configPropertyName}: ${integrity}`) + + sh.sed('-i', new RegExp(`^(\\s+${configPropertyName}:\\s+["'])\\S*(["'])`), `$1${integrity}$2`, configFile) + }) +} diff --git a/build/postcss.config.js b/build/postcss.config.js deleted file mode 100644 index 7f8186d..0000000 --- a/build/postcss.config.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict' - -const mapConfig = { - inline: false, - annotation: true, - sourcesContent: true -} - -module.exports = context => { - return { - map: context.file.dirname.includes('examples') ? false : mapConfig, - plugins: { - autoprefixer: { - cascade: false - }, - rtlcss: context.env === 'RTL' - } - } -} diff --git a/build/postcss.config.mjs b/build/postcss.config.mjs new file mode 100644 index 0000000..7717cfc --- /dev/null +++ b/build/postcss.config.mjs @@ -0,0 +1,17 @@ +const mapConfig = { + inline: false, + annotation: true, + sourcesContent: true +} + +export default context => { + return { + map: context.file.dirname.includes('examples') ? false : mapConfig, + plugins: { + autoprefixer: { + cascade: false + }, + rtlcss: context.env === 'RTL' + } + } +} diff --git a/build/rollup.config.js b/build/rollup.config.js deleted file mode 100644 index f01918e..0000000 --- a/build/rollup.config.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict' - -const path = require('node:path') -const { babel } = require('@rollup/plugin-babel') -const { nodeResolve } = require('@rollup/plugin-node-resolve') -const replace = require('@rollup/plugin-replace') -const banner = require('./banner.js') - -const BUNDLE = process.env.BUNDLE === 'true' -const ESM = process.env.ESM === 'true' - -let fileDestination = `bootstrap${ESM ? '.esm' : ''}` -const external = ['@popperjs/core'] -const plugins = [ - babel({ - // Only transpile our source code - exclude: 'node_modules/**', - // Include the helpers in the bundle, at most one copy of each - babelHelpers: 'bundled' - }) -] -const globals = { - '@popperjs/core': 'Popper' -} - -if (BUNDLE) { - fileDestination += '.bundle' - // Remove last entry in external array to bundle Popper - external.pop() - delete globals['@popperjs/core'] - plugins.push( - replace({ - 'process.env.NODE_ENV': '"production"', - preventAssignment: true - }), - nodeResolve() - ) -} - -const rollupConfig = { - input: path.resolve(__dirname, `../js/index.${ESM ? 'esm' : 'umd'}.js`), - output: { - banner: banner(), - file: path.resolve(__dirname, `../dist/js/${fileDestination}.js`), - format: ESM ? 'esm' : 'umd', - globals, - generatedCode: 'es2015' - }, - external, - plugins -} - -if (!ESM) { - rollupConfig.output.name = 'bootstrap' -} - -module.exports = rollupConfig diff --git a/build/rollup.config.mjs b/build/rollup.config.mjs new file mode 100644 index 0000000..dd6c7d1 --- /dev/null +++ b/build/rollup.config.mjs @@ -0,0 +1,59 @@ +import path from 'node:path' +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import { babel } from '@rollup/plugin-babel' +import { nodeResolve } from '@rollup/plugin-node-resolve' +import replace from '@rollup/plugin-replace' +import banner from './banner.mjs' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +const BUNDLE = process.env.BUNDLE === 'true' +const ESM = process.env.ESM === 'true' + +let destinationFile = `bootstrap${ESM ? '.esm' : ''}` +const external = ['@popperjs/core'] +const plugins = [ + babel({ + // Only transpile our source code + exclude: 'node_modules/**', + // Include the helpers in the bundle, at most one copy of each + babelHelpers: 'bundled' + }) +] +const globals = { + '@popperjs/core': 'Popper' +} + +if (BUNDLE) { + destinationFile += '.bundle' + // Remove last entry in external array to bundle Popper + external.pop() + delete globals['@popperjs/core'] + plugins.push( + replace({ + 'process.env.NODE_ENV': '"production"', + preventAssignment: true + }), + nodeResolve() + ) +} + +const rollupConfig = { + input: path.resolve(__dirname, `../js/index.${ESM ? 'esm' : 'umd'}.js`), + output: { + banner: banner(), + file: path.resolve(__dirname, `../dist/js/${destinationFile}.js`), + format: ESM ? 'esm' : 'umd', + globals, + generatedCode: 'es2015' + }, + external, + plugins +} + +if (!ESM) { + rollupConfig.output.name = 'bootstrap' +} + +export default rollupConfig diff --git a/build/vnu-jar.js b/build/vnu-jar.js deleted file mode 100644 index 22956cb..0000000 --- a/build/vnu-jar.js +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env node - -/*! - * Script to run vnu-jar if Java is available. - * Copyright 2017-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ - -'use strict' - -const { execFile, spawn } = require('node:child_process') -const vnu = require('vnu-jar') - -execFile('java', ['-version'], (error, stdout, stderr) => { - if (error) { - console.error('Skipping vnu-jar test; Java is probably missing.') - console.error(error) - return - } - - console.log('Running vnu-jar validation...') - - const is32bitJava = !/64-Bit/.test(stderr) - - // vnu-jar accepts multiple ignores joined with a `|`. - // Also note that the ignores are string regular expressions. - const ignores = [ - // "autocomplete" is included in