chore: scripts for decks
This commit is contained in:
parent
c0a31e4813
commit
378aa1e064
3 changed files with 74 additions and 32 deletions
|
|
@ -27,6 +27,15 @@ def manifest [] {
|
|||
^nickel export --format json $f | from json
|
||||
}
|
||||
|
||||
# The deck→artifact keys, from lib/variants.mjs — the one authority on the rule. This file used to
|
||||
# mirror it by hand ("the variant key mirrors lib/project.mjs"), and a mirror is a copy that drifts:
|
||||
# a THIRD copy in site/justfile never learned that a bilingual deck is one source per language, and
|
||||
# gated an asset dir that does not exist. Ask, do not re-derive.
|
||||
def variants [] {
|
||||
let script = [(outreach) "scripts" "decks" "lib" "variants.mjs"] | path join
|
||||
^node $script | from json
|
||||
}
|
||||
|
||||
# ONE dist PER DECK. `slidev build` builds a single entry, so a shared dist/ means the second
|
||||
# deck silently captures the FIRST one's slides — the projection would be wrong and nothing
|
||||
# would say so. The deck's own build dir is what makes this a pipeline instead of a one-off.
|
||||
|
|
@ -66,14 +75,9 @@ def ensure-build [id: string, source: string, --force] {
|
|||
|
||||
def main [--dry-run, --force] {
|
||||
# One build per SOURCE, not per deck: a bilingual deck is two sources, and sharing a build is
|
||||
# how an English URL ends up serving Spanish slides. The variant key mirrors lib/project.mjs.
|
||||
for d in (manifest).decks {
|
||||
let sources = ($d.pages | each {|p| $p.source? | default $d.source } | uniq)
|
||||
for src in $sources {
|
||||
let langs = ($d.pages | where {|p| ($p.source? | default $d.source) == $src } | get lang)
|
||||
let key = if ($sources | length) == 1 { $d.id } else { $"($d.id)-($langs | str join '-')" }
|
||||
ensure-build $key $src --force=$force
|
||||
}
|
||||
# how an English URL ends up serving Spanish slides.
|
||||
for v in (variants) {
|
||||
ensure-build $v.key $v.source --force=$force
|
||||
}
|
||||
let flags = if $dry_run { ["--dry-run"] } else { [] }
|
||||
let script = [(outreach) "scripts" "decks" "lib" "project.mjs"] | path join
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
// site/public/images/decks/<id>/fonts/* woff2, latin + latin-ext
|
||||
// site/content/resources/<lang>/decks/<id>.md body replaced, FRONTMATTER PRESERVED
|
||||
import { readFile, writeFile, mkdir } from 'node:fs/promises'
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import vm from 'node:vm'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { capture } from './capture.mjs'
|
||||
|
|
@ -17,14 +16,13 @@ import { projectAssets } from './project-assets.mjs'
|
|||
import { fetchFonts } from './fetch-fonts.mjs'
|
||||
import { buildBody } from './build-body.mjs'
|
||||
import { readAnchors } from './anchors.mjs'
|
||||
import { OUTREACH, distDir, publicBase, publicDir, contentFile } from './paths.mjs'
|
||||
import { readManifest, variants } from './variants.mjs'
|
||||
import { distDir, publicBase, publicDir, contentFile } from './paths.mjs'
|
||||
|
||||
const DRY = process.argv.includes('--dry-run')
|
||||
const apply = !DRY
|
||||
|
||||
const manifest = JSON.parse(
|
||||
execFileSync('nickel', ['export', '--format', 'json', join(OUTREACH, 'scripts/decks/decks.ncl')], { encoding: 'utf8' })
|
||||
)
|
||||
const manifest = readManifest()
|
||||
const { boundary_allow: ALLOW, slide: { width: W, height: H }, i18n: I18N, category: CATEGORY } = manifest
|
||||
|
||||
// The generated body is fenced. Anything outside the markers is the author's and is left
|
||||
|
|
@ -40,25 +38,6 @@ function replaceBody(existing, generated) {
|
|||
|
||||
const report = []
|
||||
|
||||
// A deck may have one source per language. Group its pages by the source they actually come
|
||||
// from: each distinct source is its own build, its own capture and its own asset dir. Sharing a
|
||||
// capture across two sources is how an English URL ends up serving Spanish slides.
|
||||
function variants(deck) {
|
||||
const by = new Map()
|
||||
for (const p of deck.pages) {
|
||||
const source = p.source ?? deck.source
|
||||
if (!by.has(source)) by.set(source, [])
|
||||
by.get(source).push(p)
|
||||
}
|
||||
// One source → the deck's own id. Several → one asset dir per source, keyed by its languages,
|
||||
// because the CSS, the fonts and the images of two different decks are two different things.
|
||||
return [...by.entries()].map(([source, pages]) => ({
|
||||
source,
|
||||
pages,
|
||||
key: by.size === 1 ? deck.id : `${deck.id}-${pages.map(p => p.lang).join('-')}`,
|
||||
}))
|
||||
}
|
||||
|
||||
for (const deck of manifest.decks) {
|
||||
for (const variant of variants(deck)) {
|
||||
const { key: id, pages } = variant
|
||||
|
|
|
|||
59
scripts/decks/lib/variants.mjs
Normal file
59
scripts/decks/lib/variants.mjs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// The deck → artifact key rule, in ONE place, because it has already drifted once.
|
||||
//
|
||||
// A bilingual deck is TWO sources (decks.ncl: `pages[].source` overrides the deck's), and each
|
||||
// source is its own build, its own capture and its own asset dir — sharing them is how an English
|
||||
// URL ends up serving Spanish slides. So the artifact is keyed by the VARIANT (`ai-infra-es`),
|
||||
// not by the deck (`ai-infra`), whose bare dir holds only thumbnails.
|
||||
//
|
||||
// That rule was re-derived in three places: here (project.mjs), gen-deck-pages.nu, and the
|
||||
// justfile's `jq -r '.decks[].id'`. The third never learned the split. It kept handing `ai-infra`
|
||||
// to the artifact gate, which ENOENT'd on a deck.css that was never written there — and PASSED on
|
||||
// ontoref-ontologia-reflexion, whose PRE-SPLIT bundle was still lying on disk. A green gate over a
|
||||
// file no page loads is worse than the crash: the crash is the only reason anyone looked.
|
||||
//
|
||||
// A rule copied is a rule that drifts. Every consumer asks this module now; nobody re-derives it.
|
||||
//
|
||||
// Usage: node lib/variants.mjs → JSON [{ deck, key, source, langs }]
|
||||
// node lib/variants.mjs --ids → one artifact key per line
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { join } from 'node:path'
|
||||
import { OUTREACH } from './paths.mjs'
|
||||
|
||||
export function readManifest() {
|
||||
return JSON.parse(execFileSync(
|
||||
'nickel', ['export', '--format', 'json', join(OUTREACH, 'scripts/decks/decks.ncl')],
|
||||
{ encoding: 'utf8' },
|
||||
))
|
||||
}
|
||||
|
||||
// Group a deck's pages by the source they actually come from: each distinct source is its own
|
||||
// build, capture and asset dir. One source → the deck's own id (nothing to disambiguate).
|
||||
// Several → one key per source, named by its languages, because the CSS, the fonts and the images
|
||||
// of two different sources are two different decks' worth of artifact.
|
||||
export function variants(deck) {
|
||||
const by = new Map()
|
||||
for (const p of deck.pages) {
|
||||
const source = p.source ?? deck.source
|
||||
if (!by.has(source)) by.set(source, [])
|
||||
by.get(source).push(p)
|
||||
}
|
||||
return [...by.entries()].map(([source, pages]) => ({
|
||||
source,
|
||||
pages,
|
||||
key: by.size === 1 ? deck.id : `${deck.id}-${pages.map(p => p.lang).join('-')}`,
|
||||
}))
|
||||
}
|
||||
|
||||
export function allVariants(manifest = readManifest()) {
|
||||
return manifest.decks.flatMap(d => variants(d).map(v => ({
|
||||
deck: d.id, key: v.key, source: v.source, langs: v.pages.map(p => p.lang),
|
||||
})))
|
||||
}
|
||||
|
||||
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
||||
const all = allVariants()
|
||||
console.log(process.argv.includes('--ids')
|
||||
? all.map(v => v.key).join('\n')
|
||||
: JSON.stringify(all, null, 2))
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue