-
Notifications
You must be signed in to change notification settings - Fork 238
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement Eleventy-based build system (#3917)
Re-implements the Ant/XSLT-based build system, with no changes to source HTML files. See PR for full list of fixes and a few behavioral changes, and 11ty/README.md for running instructions.
- Loading branch information
1 parent
ba81e62
commit f8efc41
Showing
48 changed files
with
5,156 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
*.* | ||
11ty/ | ||
acknowledgements/ | ||
conformance-challenges/ | ||
guidelines/ | ||
lib/ | ||
requirements/ | ||
script/ | ||
wcag20/ | ||
# working-examples is directly copied; it should not be processed as templates | ||
working-examples/ | ||
xslt/ | ||
|
||
# These files under understanding don't end up in output in the old build | ||
understanding/*/accessibility-support-documenting.html | ||
understanding/*/identify-changes.html | ||
understanding/*/interruptions-minimum.html | ||
understanding/*/seizures.html | ||
|
||
# Ignore templates used for creating new documents | ||
**/*-template.html | ||
|
||
# HTML files under img will be passthrough-copied | ||
**/img/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
20 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.* | ||
!*.ts | ||
!*.11tydata.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"printWidth": 100, | ||
"trailingComma": "es5" | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Eleventy Infrastructure for WCAG Techniques and Understanding | ||
|
||
This subdirectory contains ES Modules re-implementing pieces of the | ||
XSLT-based build process using Eleventy. | ||
|
||
## Usage | ||
|
||
Make sure you have Node.js installed. This has primarily been tested with v20, | ||
the current LTS at time of writing. | ||
|
||
If you use [fnm](https://github.com/Schniz/fnm) or [nvm](https://github.com/nvm-sh/nvm) to manage multiple Node.js versions, | ||
you can switch to the recommended version by typing `fnm use` or `nvm use` | ||
(with no additional arguments) while in the repository directory. | ||
|
||
Otherwise, you can download an installer from [nodejs.org](https://nodejs.org/). | ||
|
||
First, run `npm i` in the root directory of the repository to install dependencies. | ||
|
||
Common tasks: | ||
|
||
- `npm run build` runs a one-time build | ||
- `npm start` runs a local server with hot-reloading to preview changes as you make them: | ||
- http://localhost:8080/techniques | ||
- http://localhost:8080/understanding | ||
|
||
Maintenance tasks (for working with Eleventy config and supporting files under this subdirectory): | ||
|
||
- `npm run check` checks for TypeScript errors | ||
- `npm run fmt` formats all TypeScript files | ||
|
||
## Environment Variables | ||
|
||
### `WCAG_CVSDIR` | ||
|
||
**Usage context:** `publish-w3c` script only | ||
|
||
Indicates top-level path of W3C CVS checkout, for WAI site updates (via `publish-w3c` script). | ||
|
||
**Default:** `../../../w3ccvs` (same as in Ant/XSLT build process) | ||
|
||
### `WCAG_VERSION` | ||
|
||
**Usage context:** `publish-w3c` script only; | ||
this should currently not be changed, pending future improvements to `21` support. | ||
|
||
Indicates WCAG version being built, in `XY` format (i.e. no `.`) | ||
|
||
**Default:** `22` | ||
|
||
### `WCAG_MODE` | ||
|
||
**Usage context:** should not need to be used manually except in specific testing scenarios | ||
|
||
Influences base URLs for links to guidelines, techniques, and understanding pages. | ||
Typically set by specific npm scripts or CI processes. | ||
|
||
Possible values: | ||
|
||
- Unset **(default)** - Sets base URLs appropriate for local testing | ||
- `editors` - Sets base URLs appropriate for `gh-pages` publishing; used by deploy action | ||
- `publication` - Sets base URLs appropriate for WAI site publishing; used by `publish-w3c` script | ||
|
||
## Other points of interest | ||
|
||
- The main configuration can be found in top-level `eleventy.config.ts` | ||
- Build commands are defined in top-level `package.json` under `scripts`, | ||
and can be run via `npm run <name>` | ||
- If you see files named `*.11tydata.js`, these contribute data to the Eleventy build | ||
(see Template and Directory Data files under | ||
[Sources of Data](https://www.11ty.dev/docs/data/#sources-of-data)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { load, type CheerioOptions } from "cheerio"; | ||
import { readFileSync } from "fs"; | ||
import { readFile } from "fs/promises"; | ||
import { dirname, resolve } from "path"; | ||
|
||
export { load } from "cheerio"; | ||
|
||
/** Convenience function that combines readFile and load. */ | ||
export const loadFromFile = async ( | ||
inputPath: string, | ||
options?: CheerioOptions | null, | ||
isDocument?: boolean | ||
) => load(await readFile(inputPath, "utf8"), options, isDocument); | ||
|
||
/** | ||
* Retrieves content for a data-include, either from _includes, | ||
* or relative to the input file. | ||
* Operates synchronously for simplicity of use within Cheerio callbacks. | ||
* | ||
* @param includePath A data-include attribute value | ||
* @param inputPath Path (relative to repo root) to file containing the directive | ||
* @returns | ||
*/ | ||
function readInclude(includePath: string, inputPath: string) { | ||
const relativePath = resolve(dirname(inputPath), includePath); | ||
if (includePath.startsWith("..")) return readFileSync(relativePath, "utf8"); | ||
|
||
try { | ||
// Prioritize any match under _includes (e.g. over local toc.html built via XSLT) | ||
return readFileSync(resolve("_includes", includePath), "utf8"); | ||
} catch (error) { | ||
return readFileSync(relativePath, "utf8"); | ||
} | ||
} | ||
|
||
/** | ||
* Resolves data-include directives in the given file, a la flatten-document.xslt. | ||
* This is a lower-level version for use in Eleventy configuration; | ||
* you'd probably rather use flattenDomFromFile in other cases. | ||
* | ||
* @param content String containing HTML to process | ||
* @param inputPath Path (relative to repo root) to file containing the HTML | ||
* (needed for data-include resolution) | ||
* @returns Cheerio instance containing "flattened" DOM | ||
*/ | ||
export function flattenDom(content: string, inputPath: string) { | ||
const $ = load(content); | ||
|
||
$("body [data-include]").each((_, el) => { | ||
const replacement = readInclude(el.attribs["data-include"], inputPath); | ||
// Replace entire element or children, depending on data-include-replace | ||
if (el.attribs["data-include-replace"]) $(el).replaceWith(replacement); | ||
else $(el).removeAttr("data-include").html(replacement); | ||
}); | ||
|
||
return $; | ||
} | ||
|
||
/** | ||
* Convenience version of flattenDom that requires only inputPath to be passed. | ||
* @see flattenDom | ||
*/ | ||
export const flattenDomFromFile = async (inputPath: string) => | ||
flattenDom(await readFile(inputPath, "utf8"), inputPath); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** @fileoverview Common functions used by multiple parts of the build process */ | ||
|
||
import type { Guideline, Principle, SuccessCriterion } from "./guidelines"; | ||
|
||
/** Generates an ID for heading permalinks. Equivalent to wcag:generate-id in base.xslt. */ | ||
export function generateId(title: string) { | ||
if (title === "Parsing (Obsolete and removed)") return "parsing"; | ||
return title | ||
.replace(/\s+/g, "-") | ||
.replace(/[,\():]+/g, "") | ||
.toLowerCase(); | ||
} | ||
|
||
/** Given a string "xy", returns "x.y" */ | ||
export const resolveDecimalVersion = (version: `${number}`) => version.split("").join("."); | ||
|
||
/** Sort function for ordering WCAG principle/guideline/SC numbers ascending */ | ||
export function wcagSort( | ||
a: Principle | Guideline | SuccessCriterion, | ||
b: Principle | Guideline | SuccessCriterion | ||
) { | ||
const aParts = a.num.split(".").map((n) => +n); | ||
const bParts = b.num.split(".").map((n) => +n); | ||
|
||
for (let i = 0; i < 3; i++) { | ||
if (aParts[i] > bParts[i] || (aParts[i] && !bParts[i])) return 1; | ||
if (aParts[i] < bParts[i] || (bParts[i] && !aParts[i])) return -1; | ||
} | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** @fileoverview script to copy already-built output to CVS subfolders */ | ||
|
||
import { copyFile, unlink } from "fs/promises"; | ||
import { glob } from "glob"; | ||
import { mkdirp } from "mkdirp"; | ||
|
||
import { dirname, join } from "path"; | ||
|
||
const outputBase = "_site"; | ||
const cvsBase = process.env.WCAG_CVSDIR || "../../../w3ccvs"; | ||
const wcagVersion = process.env.WCAG_VERSION || "22"; | ||
const wcagBase = `${cvsBase}/WWW/WAI/WCAG${wcagVersion}`; | ||
|
||
// Map (git) sources to (CVS) destinations, since some don't match case-sensitively | ||
const dirs = { | ||
techniques: "Techniques", | ||
understanding: "Understanding", | ||
"working-examples": "working-examples", | ||
}; | ||
|
||
for (const [srcDir, destDir] of Object.entries(dirs)) { | ||
const cleanPaths = await glob(`**`, { | ||
cwd: join(wcagBase, destDir), | ||
ignore: ["**/CVS/**"], | ||
nodir: true, | ||
}); | ||
|
||
for (const path of cleanPaths) await unlink(join(wcagBase, destDir, path)); | ||
|
||
const indexPaths = await glob(`**/index.html`, { cwd: join(outputBase, srcDir) }); | ||
const nonIndexPaths = await glob(`**`, { | ||
cwd: join(outputBase, srcDir), | ||
ignore: ["**/index.html"], | ||
nodir: true, | ||
}); | ||
|
||
for (const path of indexPaths) { | ||
const srcPath = join(outputBase, srcDir, path); | ||
const destPath = join(wcagBase, destDir, path.replace(/index\.html$/, "Overview.html")); | ||
await mkdirp(dirname(destPath)); | ||
await copyFile(srcPath, destPath); | ||
} | ||
|
||
for (const path of nonIndexPaths) { | ||
const srcPath = join(outputBase, srcDir, path); | ||
const destPath = join(wcagBase, destDir, path); | ||
await mkdirp(dirname(destPath)); | ||
await copyFile(srcPath, destPath); | ||
} | ||
} |
Oops, something went wrong.