From 3e5b978c4755f40f41b8cade14e7688099031c43 Mon Sep 17 00:00:00 2001 From: Derek Lewis Date: Wed, 12 Aug 2026 02:34:40 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=E2=9C=A8=EF=BC=9Alint?= =?UTF-8?q?=20filenames=20for=20kebab-case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revives the intent of the original branch: filenames should be predictable, and under `collections/` a filename is a published URL. Reports rather than renames, which is where this departs from the earlier attempt. A rename has to be accompanied by updating every import, include and link that points at the old name, and no formatter can do that -- an autofix here would silently change URLs. Names a tool dictates are out of scope: anything under a dot-directory, and the shouted metadata names (`README.md`, `AUTHORS`, `LICENSE/`). `_data/eleventyDataSchema.mjs` is exempt outright, since Eleventy takes the global data key from the filename. Assisted-by: Claude-Code:claude-opus-5 --- build/tasks/verify/verify-filenames.mts | 73 +++++++++++++++++++++++++ package-scripts.yml | 1 + 2 files changed, 74 insertions(+) create mode 100644 build/tasks/verify/verify-filenames.mts diff --git a/build/tasks/verify/verify-filenames.mts b/build/tasks/verify/verify-filenames.mts new file mode 100644 index 000000000..6c1677f0f --- /dev/null +++ b/build/tasks/verify/verify-filenames.mts @@ -0,0 +1,73 @@ +/** + * @file Verify filenames adhere to the project naming convention. + * @author The OpenINF Authors & Friends + * @license MIT OR Apache-2.0 OR BlueOak-1.0.0 + * @module {type ES6Module} build/tasks/verify/verify-filenames + */ + +import { glob } from '@openinf/portal/build/utils'; + +/** + * Lowercase words joined by hyphens. A leading underscore is Eleventy's and + * Sass's marking for something that is not itself output -- `_layouts/`, + * `_custom.scss` -- and is left alone. + */ +const KEBAB_CASE = /^_?[a-z0-9]+(?:-[a-z0-9]+)*$/; + +/** + * The shouted names convention reserves for metadata that sits beside the + * work rather than being part of it: `README.md`, `AUTHORS`, `LICENSE/`, and + * the licence identifiers inside it, such as `CC-BY-SA-4.0.txt`. + */ +const METADATA_CASE = /^[A-Z][A-Z0-9_-]*$/; + +/** + * Names a tool dictates and we do not get to choose. Anything under a + * dot-directory is exempt wholesale, on the same reasoning. + */ +const EXEMPT = new Set([ + // Eleventy takes the global data key from the filename, so kebab-casing + // this one would quietly unhook the front matter validator. + '_data/eleventyDataSchema.mjs', +]); + +const files = await glob(['**/*', '!_site/', '!node_modules/']); + +// A directory is only ever seen here as part of some file's path, and the +// same directory is part of many, so each is judged once. +const checked = new Set(); +const offenders: string[] = []; + +for (const file of files) { + const segments = file.split('/'); + + // `.github/ISSUE_TEMPLATE/`, `.vscode/settings.json`: whatever reads these + // decides what they are called. + if (segments.some((segment) => segment.startsWith('.'))) continue; + + for (const [index, segment] of segments.entries()) { + const path = segments.slice(0, index + 1).join('/'); + + if (checked.has(path) || EXEMPT.has(path)) continue; + + checked.add(path); + + // Extensions are not part of the name, and there may be several of them + // (`vnu-jar.d.ts`, `main.min.css`). Directories have none to shed. + const isFile = index === segments.length - 1; + const name = isFile ? (segment.split('.')[0] ?? segment) : segment; + + if (!(KEBAB_CASE.test(name) || METADATA_CASE.test(name))) { + offenders.push(path); + } + } +} + +if (offenders.length > 0) { + console.error( + `Not in kebab-case:\n${offenders.map((path) => ` ${path}`).join('\n')}\n\n` + + 'Renaming a file changes what links to it, and under `collections/` it ' + + 'changes a published URL, so this task reports rather than fixes.' + ); + process.exitCode = 1; +} diff --git a/package-scripts.yml b/package-scripts.yml index b7003c256..73d79d1ff 100644 --- a/package-scripts.yml +++ b/package-scripts.yml @@ -12,6 +12,7 @@ scripts: scss: node build/tasks/verify/verify-scss.mts dockerfile: node build/tasks/verify/verify-dockerfile.mts fileModes: node build/tasks/verify/verify-file-modes.mts + filenames: node build/tasks/verify/verify-filenames.mts htmlValidForVNU: node build/tasks/verify/verify-html-valid-for-vnu.mts js: node build/tasks/verify/verify-js.mts json: node build/tasks/verify/verify-json.mts From 6f44f515689881055912b8c8be0864653e63ade5 Mon Sep 17 00:00:00 2001 From: Derek Lewis Date: Wed, 12 Aug 2026 02:34:40 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=E2=99=BB=EF=B8=8F?= =?UTF-8?q?=EF=BC=9Akebab-case=20two=20asset=20names?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nothing references either file, so this is a rename and no more. Assisted-by: Claude-Code:claude-opus-5 --- .../img/sublime-theme/{flower_of_life.svg => flower-of-life.svg} | 0 _assets/img/sublime-theme/{prism_outro.svg => prism-outro.svg} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename _assets/img/sublime-theme/{flower_of_life.svg => flower-of-life.svg} (100%) rename _assets/img/sublime-theme/{prism_outro.svg => prism-outro.svg} (100%) diff --git a/_assets/img/sublime-theme/flower_of_life.svg b/_assets/img/sublime-theme/flower-of-life.svg similarity index 100% rename from _assets/img/sublime-theme/flower_of_life.svg rename to _assets/img/sublime-theme/flower-of-life.svg diff --git a/_assets/img/sublime-theme/prism_outro.svg b/_assets/img/sublime-theme/prism-outro.svg similarity index 100% rename from _assets/img/sublime-theme/prism_outro.svg rename to _assets/img/sublime-theme/prism-outro.svg