This commit is contained in:
2026-11-05 09:57:11 -05:00
parent d34388bf2c
commit 89e392cc2e
81 changed files with 12410 additions and 1135 deletions
+6 -6
View File
@@ -8,7 +8,7 @@ import { safePath } from './files.mjs';
const ROOT = fileURLToPath(new URL('../', import.meta.url));
const CATALOGUE = path.join(ROOT, 'mods/hearth/botany.lua');
const OUTPUT = path.join(ROOT, 'mods/hearth/wiki_articles.lua');
export const LIMITS = Object.freeze({ species: 80, batch: 10, concurrency: 2,
export const LIMITS = Object.freeze({ species: 100, batch: 10, concurrency: 2,
responseBytes: 2 * 1024 * 1024, catalogueBytes: 128 * 1024,
characters: 8000, requestMs: 15000, totalMs: 90000, redirects: 2 });
export const USER_AGENT = 'LastHearthSpeciesBundle/1.0 (offline educational game references; explicit manual maintenance)';
@@ -30,7 +30,7 @@ function latinName(value) {
return value;
}
function validateCatalogue(records) {
requireValue(Array.isArray(records) && records.length > 0 && records.length <= LIMITS.species, 'Catalogue scope must be 1..80.');
requireValue(Array.isArray(records) && records.length > 0 && records.length <= LIMITS.species, 'Catalogue scope must be 1..100.');
const ids = new Set(), names = new Set();
for (const r of records) {
requireValue(r && typeof r.id === 'string' && /^[a-z][a-z_]{0,39}$/.test(r.id) &&
@@ -51,7 +51,7 @@ export function parseCatalogue(source) {
requireValue(m, 'Unsupported catalogue literal.');
return { id: m[1], latin: m[2] };
});
requireValue(records.length === LIMITS.species, 'Expected exactly 80 botany catalogue rows.');
requireValue(records.length === LIMITS.species, 'Expected exactly 100 botany catalogue rows.');
return validateCatalogue(records);
}
@@ -312,7 +312,7 @@ export async function main(args = process.argv.slice(2)) {
requireValue(args.length === 1 && ['--refresh', '--check', '--help'].includes(args[0]),
'Usage: node scripts/wiki-species.mjs --refresh | --check | --help (no URLs/output paths accepted)');
if (args[0] === '--help') {
console.log('--refresh: query all 80 species; replace the fixed Lua cache with verified intros or explicit missing-page notes after full validation.\n--check: verify fixed offline cache/catalogue without network.');
console.log('--refresh: query all 100 species; replace the fixed Lua cache with verified intros or explicit missing-page notes after full validation.\n--check: verify fixed offline cache/catalogue without network.');
return;
}
const records = await readCatalogue();
@@ -336,7 +336,7 @@ export async function main(args = process.argv.slice(2)) {
e.history_url === `${ORIGIN}/w/index.php?title=${wikiTitle(e.title)}&action=history` &&
e.attribution === `Wikipedia contributors, "${e.title}"` && Array.from(e.text).length <= LIMITS.characters, 'Invalid cached attribution/excerpt.');
}
console.log(`Verified ${entries.length}/80 species: ${entries.filter(e => e.kind === 'wikipedia_intro').length} Wikipedia introductions, ${entries.filter(e => e.kind === 'original_notes').length} original availability notes; network requests: 0.`);
console.log(`Verified ${entries.length}/${LIMITS.species} species: ${entries.filter(e => e.kind === 'wikipedia_intro').length} Wikipedia introductions, ${entries.filter(e => e.kind === 'original_notes').length} original availability notes; network requests: 0.`);
return;
}
const entries = await fetchEntries(records);
@@ -347,7 +347,7 @@ export async function main(args = process.argv.slice(2)) {
await safePath(OUTPUT);
const handle = await fs.open(OUTPUT, constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | (constants.O_NOFOLLOW || 0), 0o644);
try { await handle.writeFile(source, 'utf8'); } finally { await handle.close(); }
console.log(`Cached ${entries.length}/80 species: ${entries.filter(e => e.kind === 'wikipedia_intro').length} Wikipedia introductions, ${entries.filter(e => e.kind === 'original_notes').length} original availability notes (${entries.filter(e => e.truncated).length} shortened); ${Math.ceil(records.length / LIMITS.batch)} API batches, concurrency <=2.`);
console.log(`Cached ${entries.length}/${LIMITS.species} species: ${entries.filter(e => e.kind === 'wikipedia_intro').length} Wikipedia introductions, ${entries.filter(e => e.kind === 'original_notes').length} original availability notes (${entries.filter(e => e.truncated).length} shortened); ${Math.ceil(records.length / LIMITS.batch)} API batches, concurrency <=2.`);
}
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {