mirror of
https://github.com/twbs/bootstrap.git
synced 2025-08-17 02:54:01 +02:00
Try a new approach
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -40,3 +40,6 @@ Thumbs.db
|
||||
# Folders to ignore
|
||||
/js/coverage/
|
||||
/node_modules/
|
||||
|
||||
# Ignore generated diff files
|
||||
# /site/static/docs/5.3/assets/json/diffs
|
||||
|
74
build/diff.mjs
Normal file
74
build/diff.mjs
Normal file
@@ -0,0 +1,74 @@
|
||||
// import * as path from 'path';
|
||||
import * as fs from 'fs/promises';
|
||||
import * as diff from 'fast-array-diff';
|
||||
// import { argv } from 'node:process';
|
||||
import { getCssClasses } from './getCssClasses.mjs';
|
||||
|
||||
// TODO: not run this script all the time
|
||||
// TODO: retrieve the lists of Bootstrap versions (with GitHub API)
|
||||
const versions = ["4.6.2", "5.0.0", "5.1.3"]
|
||||
const currentVersion = "5.3.0"
|
||||
const currentShortVersion = "5.3"
|
||||
|
||||
const currentVersionClasses = await getCssClasses('dist/css/bootstrap.css')
|
||||
|
||||
for (const version of versions) {
|
||||
const bootstrapCssPath = `https://cdn.jsdelivr.net/npm/bootstrap@${version}/dist/css/bootstrap.css`
|
||||
|
||||
const versionClasses = await getCssClasses(bootstrapCssPath)
|
||||
|
||||
const outputJSONContent = diff.diff(
|
||||
versionClasses.classes,
|
||||
currentVersionClasses.classes
|
||||
)
|
||||
|
||||
outputJSONContent['same'] = diff.same(
|
||||
versionClasses.classes,
|
||||
currentVersionClasses.classes
|
||||
)
|
||||
|
||||
const outputFileDir = `./site/static/docs/${currentShortVersion}/assets/json/diffs/`
|
||||
await fs.mkdir(outputFileDir, { recursive: true })
|
||||
|
||||
const outputFilePath = `${outputFileDir}/bootstrap-from-${version}-to-${currentVersion}.diff.json`
|
||||
await fs.writeFile(outputFilePath, JSON.stringify(outputJSONContent))
|
||||
}
|
||||
|
||||
/*
|
||||
try {
|
||||
const args = argv.slice(2);
|
||||
|
||||
// TODO: check the size of args: must be 2
|
||||
const fromPath = args[0]
|
||||
const toPath = args[1]
|
||||
|
||||
const from = await fs.readFile(fromPath, 'utf8');
|
||||
const to = await fs.readFile(toPath, 'utf8');
|
||||
|
||||
const fromClasses = JSON.parse(from)["classes"];
|
||||
const toClasses = JSON.parse(to)["classes"];
|
||||
|
||||
const outputJSONContent = diff.diff(
|
||||
fromClasses,
|
||||
toClasses
|
||||
)
|
||||
|
||||
outputJSONContent['same'] = diff.same(
|
||||
fromClasses,
|
||||
toClasses
|
||||
)
|
||||
|
||||
// TODO: add "from"/"to" keys?
|
||||
|
||||
const outputFilePath = args[2] ?? `from_${path.parse(fromPath).name}_to_${path.parse(toPath).name}.diff.json`
|
||||
await fs.writeFile(outputFilePath, JSON.stringify(outputJSONContent))
|
||||
}
|
||||
catch(error) {
|
||||
// console.log(error)
|
||||
console.log(`Usage: node diff.mjs <fromPath> <toPath> <outputPath>
|
||||
- fromPath: JSON file
|
||||
- toPath: JSON file
|
||||
- outputPath: JSON file (optional). Default value will be 'from_<fromPath>_to_<toPath>.diff.json'
|
||||
`)
|
||||
}
|
||||
*/
|
@@ -1,89 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*!
|
||||
* Script to update our glossary semi-automatically based on bootstrap.css.
|
||||
* Copyright 2017-2022 The Bootstrap Authors
|
||||
* Copyright 2017-2022 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const fs = require('fs')
|
||||
|
||||
fs.readFile('../dist/css/bootstrap.css', 'utf8', (error, data) => {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
|
||||
// TODO: bootstrap.css should be stripped of its comments to avoid having .map and other elements in the array
|
||||
|
||||
// TODO: previous re was /\.[a-zA-Z]([0-9a-zA-Z]*-)*[0-9a-zA-Z]*/gi, optimized
|
||||
const re = /\.[a-z]([\da-z]*-)*[\da-z]*/gi
|
||||
|
||||
const matches = [...data.matchAll(re)]
|
||||
|
||||
// Array.from will build an array with just the matching strings
|
||||
// .sort() will sort those matching strings in the array
|
||||
// Array.from(new Set(...)) will remove the duplicate entries
|
||||
const results = Array.from(new Set(Array.from(matches, m => m[0]).sort()))
|
||||
|
||||
let newContent = ''
|
||||
|
||||
for (const result of results) {
|
||||
newContent += result + ':\r\n'
|
||||
}
|
||||
|
||||
// Create a temp file containing all classes names as keys and empty values
|
||||
fs.writeFile('../site/static/docs/5.3/assets/data/glossary.data.temp', newContent, error => {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
})
|
||||
|
||||
// Compare what's inside our glossary.data and the temp glossary to:
|
||||
// - remove in glossary.data what doesn't exist anymore
|
||||
// - add the keys in glossary.data that should be completed with the corresponding links manually
|
||||
fs.readFile('../site/static/docs/5.3/assets/data/glossary.data', 'utf8', (error, data) => {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
|
||||
const newContentSplit = newContent.split('\r\n')
|
||||
const finalContentArray = []
|
||||
|
||||
// Find all elements that are already in our glossary
|
||||
// Remove elements that are not in the temp glossary
|
||||
for (const d of data.split('\r\n')) {
|
||||
const found = newContentSplit.find(elt => elt.split(':')[0] === d.split(':')[0])
|
||||
if (found) {
|
||||
// finalContent += d + '\r\n'
|
||||
finalContentArray.push(d + '\r\n')
|
||||
}
|
||||
}
|
||||
|
||||
// Add elements that are new in the temp glossary
|
||||
for (const d of newContentSplit) {
|
||||
// Avoid adding empty lines
|
||||
if (d) {
|
||||
const found = data.split('\r\n').find(elt => elt.split(':')[0] === d.split(':')[0])
|
||||
if (!found) {
|
||||
// finalContent += d + '\r\n'
|
||||
finalContentArray.push(d + '\r\n')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFile('../site/static/docs/5.3/assets/data/glossary.data', finalContentArray.sort().join(''), { flag: 'w' }, error => {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
})
|
||||
|
||||
fs.unlink('../site/static/docs/5.3/assets/data/glossary.data.temp', error => {
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
9
build/getCssClasses.mjs
Normal file
9
build/getCssClasses.mjs
Normal file
@@ -0,0 +1,9 @@
|
||||
import listSelectors from 'list-selectors';
|
||||
|
||||
export async function getCssClasses(filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
listSelectors(filePath, { include: ['classes'] }, (result) => {
|
||||
resolve(result);
|
||||
});
|
||||
})
|
||||
}
|
22
build/glossary.mjs
Normal file
22
build/glossary.mjs
Normal file
@@ -0,0 +1,22 @@
|
||||
import * as path from 'path';
|
||||
import { argv } from 'node:process';
|
||||
import * as fs from 'fs/promises';
|
||||
import { getCssClasses } from './getCssClasses.mjs';
|
||||
|
||||
try {
|
||||
const args = argv.slice(2);
|
||||
|
||||
const fileClasses = await getCssClasses(args[0]);
|
||||
|
||||
const outputFilePath = args[1] ?? `${path.parse(args[0]).name}.json`
|
||||
|
||||
await fs.writeFile(outputFilePath, JSON.stringify(fileClasses))
|
||||
}
|
||||
catch (error) {
|
||||
// console.log(error)
|
||||
// TODO: inputPath could be an HTTP link
|
||||
console.log(`Usage: node glossary.mjs <inputPath> <outputPath>
|
||||
- inputPath: CSS file to parse
|
||||
- outputPath: JSON file (optional). Default value is: <inputPath>.json
|
||||
`)
|
||||
}
|
1269
package-lock.json
generated
1269
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -82,6 +82,7 @@
|
||||
"docs-serve": "hugo server --port 9001 --disableFastRender --printUnusedTemplates",
|
||||
"docs-serve-only": "npx sirv-cli _site --port 9001",
|
||||
"lockfile-lint": "lockfile-lint --allowed-hosts npm --allowed-schemes https: --empty-hostname false --type npm --path package-lock.json",
|
||||
"predocs-build": "node build/diff.mjs",
|
||||
"update-deps": "ncu -u -x globby,karma-browserstack-launcher,karma-rollup-preprocessor,terser && echo Manually update site/assets/js/vendor",
|
||||
"release": "npm-run-all dist release-sri docs-build release-zip*",
|
||||
"release-sri": "node build/generate-sri.js",
|
||||
@@ -121,6 +122,7 @@
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-markdown": "^3.0.0",
|
||||
"eslint-plugin-unicorn": "^46.0.0",
|
||||
"fast-array-diff": "^1.1.0",
|
||||
"find-unused-sass-variables": "^4.0.6",
|
||||
"globby": "^11.1.0",
|
||||
"hammer-simulator": "0.0.1",
|
||||
@@ -137,6 +139,7 @@
|
||||
"karma-jasmine": "^5.1.0",
|
||||
"karma-jasmine-html-reporter": "^2.0.0",
|
||||
"karma-rollup-preprocessor": "7.0.7",
|
||||
"list-selectors": "^2.0.1",
|
||||
"lockfile-lint": "^4.10.1",
|
||||
"nodemon": "^2.0.21",
|
||||
"npm-run-all": "^4.1.5",
|
||||
|
60
site/content/docs/5.3/diff.md
Normal file
60
site/content/docs/5.3/diff.md
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
layout: docs
|
||||
title: Diff
|
||||
description: Compare HTML classes from different Bootstrap versions
|
||||
group: diff
|
||||
aliases: "/diff/"
|
||||
---
|
||||
|
||||
<script type="module">
|
||||
// TODO: Use https://gohugo.io/functions/safejs/
|
||||
|
||||
const file = await fetch('/docs/5.3/assets/json/diffs/bootstrap-from-4.6.2-to-5.3.0.diff.json');
|
||||
const text = await file.text();
|
||||
|
||||
function getElements(divId, dataArray) {
|
||||
const listContainer = document.getElementById(divId);
|
||||
const listElement = document.createElement('ul');
|
||||
for (const item of dataArray) {
|
||||
const listItem = document.createElement('li');
|
||||
listItem.textContent = item;
|
||||
listElement.appendChild(listItem);
|
||||
}
|
||||
listContainer.appendChild(listElement);
|
||||
}
|
||||
|
||||
getElements('removedElements', JSON.parse(text).removed);
|
||||
getElements('addedElements', JSON.parse(text).added);
|
||||
</script>
|
||||
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="fromVersions" class="form-label">From</label>
|
||||
<select class="form-select" aria-label="Default select example" id="fromVersions">
|
||||
<option selected>Open this select menu</option>
|
||||
<option value="1">v4.6.2</option>
|
||||
<option value="2">v5.0.0</option>
|
||||
<option value="3">v5.1.3</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="toVersions" class="form-label">To</label>
|
||||
<select class="form-select" aria-label="Default select example" id="toVersions">
|
||||
<option selected>Open this select menu</option>
|
||||
<option value="2">v5.0.0</option>
|
||||
<option value="3">v5.1.3</option>
|
||||
<option value="3">v5.1.3</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
|
||||
# Deprecated classes
|
||||
|
||||
<div id="removedElements">
|
||||
</div>
|
||||
|
||||
# New classes
|
||||
|
||||
<div id="addedElements">
|
||||
</div>
|
@@ -10,21 +10,14 @@ toc: true
|
||||
## Glossary
|
||||
|
||||
{{< tables.inline >}}
|
||||
{{ $file := split (readFile (path.Join "site/static/docs" .Site.Params.docs_version "assets/data/glossary.data")) "\n" }}
|
||||
<table class="table">
|
||||
<tbody>
|
||||
{{- range $file }}
|
||||
{{ $class := split . ":" }}
|
||||
{{ range $.Site.Data.bootstrap.classes }}
|
||||
<tr>
|
||||
<td>
|
||||
{{ if gt (len (string (index $class 1))) 1 }}
|
||||
<a href="/docs/{{ $.Site.Params.docs_version }}/{{ (index $class 1) }}">{{ index $class 0 }}</a>
|
||||
{{ else }}
|
||||
<span>{{ index $class 0 }}</span>
|
||||
{{ end }}
|
||||
</td>
|
||||
<td>{{ . }}</td>
|
||||
</tr>
|
||||
{{- end -}}
|
||||
{{ end }}
|
||||
</ul>
|
||||
</tbody>
|
||||
</table>
|
||||
{{< /tables.inline >}}
|
||||
|
1
site/data/bootstrap.json
Normal file
1
site/data/bootstrap.json
Normal file
File diff suppressed because one or more lines are too long
@@ -158,3 +158,4 @@
|
||||
|
||||
- title: Glossary
|
||||
- title: Migration
|
||||
- title: Diff
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user