179 lines
8.6 KiB
TypeScript
179 lines
8.6 KiB
TypeScript
#!/usr/bin/env bun
|
|
|
|
/**
|
|
* ensure-category-subcategory-intros — writes placeholder `_intro.md` files
|
|
* for every category and subcategory that lacks one. Existing files are never
|
|
* overwritten.
|
|
*
|
|
* Usage: bun scripts/ensure-category-subcategory-intros.ts
|
|
*/
|
|
|
|
import { existsSync, readdirSync, writeFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { CONFIG } from "./lib/config.js";
|
|
import { isDirectorySafe } from "./lib/doc-tree.js";
|
|
|
|
const ROOT = CONFIG.paths.root;
|
|
const PACKAGES_ROOT = join(ROOT, CONFIG.paths.packagesRoot);
|
|
|
|
const CATEGORY_INTROS: Record<string, string> = {
|
|
"api-stack":
|
|
"# `api-stack`\n\nAPI infrastructure, plugin framework, and HTTP orchestration layer for the Suaveplan monorepo.",
|
|
commerce:
|
|
"# `commerce`\n\nBooking engines, contact management, payment plugins, and commerce primitives.",
|
|
communication:
|
|
"# `communication`\n\nEmail delivery, messaging channels, and webhook clients.",
|
|
devtools:
|
|
"# `devtools`\n\nDeveloper tooling, documentation generators, Docker helpers, and build utilities.",
|
|
foundation:
|
|
"# `foundation`\n\nFoundational primitives — types, errors, configuration, data structures, and cross-cutting utilities.",
|
|
gaming: "# `gaming`\n\nGame engines, entity-component systems, and simulation libraries.",
|
|
geospatial:
|
|
"# `geospatial`\n\nGeospatial data, mapping, planetary coordinates, and logistics utilities.",
|
|
identity:
|
|
"# `identity`\n\nAuthentication, authorization, identity resolution, and credential management.",
|
|
localization:
|
|
"# `localization`\n\nInternationalization, localization, locale detection, and translation infrastructure.",
|
|
media: "# `media`\n\nAudio, video, image, and font processing libraries.",
|
|
money: "# `money`\n\nPayments, currencies, cryptocurrency, and financial primitives.",
|
|
networking:
|
|
"# `networking`\n\nDistributed networking, event buses, drive mesh, and network discovery.",
|
|
observability:
|
|
"# `observability`\n\nMonitoring, logging, health checks, audit trails, and analytics.",
|
|
persistence:
|
|
"# `persistence`\n\nCaching, database adapters, search engines, and storage abstractions.",
|
|
"security-stack":
|
|
"# `security-stack`\n\nCryptography, vaults, security utilities, and threat-detection primitives.",
|
|
testkit:
|
|
"# `testkit`\n\nTesting frameworks, A/B testing, and quality-assurance utilities.",
|
|
threejs:
|
|
"# `threejs`\n\nThree.js and React Three Fiber integrations.",
|
|
ui: "# `ui`\n\nReact components, forms, and user-interface primitives.",
|
|
};
|
|
|
|
const SUBCATEGORY_INTROS: Record<string, string> = {
|
|
api: "API orchestration, plugin lifecycle, routing, workers, and tenant resolution.",
|
|
audio: "Audio processing, playback, analysis, and effect plugins.",
|
|
"audio-fx": "Real-time audio effects and DSP plugins.",
|
|
"audio-ir": "Impulse-response capture, loading, and room-acoustic plugins.",
|
|
auth: "Authentication providers, JWT, WebAuthn, OAuth, and session resolution.",
|
|
barcode: "1-D barcode generation and parsing.",
|
|
bitpacker:
|
|
"Bit-level binary packing, schemas, compression, and streaming codecs.",
|
|
booking:
|
|
"Universal booking engine with availability, conflict detection, and pricing.",
|
|
cache: "Caching abstractions, memory caches, and Redis backends.",
|
|
contacts:
|
|
"Contact and group management with deduplication and import/export.",
|
|
core: "Core foundation — types, errors, configuration, schema registry, and utilities.",
|
|
crypto: "Cryptographic primitives, ciphers, hashes, curves, and key management.",
|
|
data: "Data manipulation, masking, deduplication, diffing, and byte utilities.",
|
|
database: "Database adapters, migrations, seeding, and SQLite support.",
|
|
datetime: "Timezone-aware date/time utilities, calendars, and recurrence.",
|
|
docker: "Docker helpers and GPU runtime configuration.",
|
|
docs: "Documentation utilities, SVG compression, PDF handling, and sitemap generation.",
|
|
drive: "Virtual filesystem, mesh networking, and chunk-addressed storage plugins.",
|
|
emails:
|
|
"Email delivery, DMARC parsing, templates, campaigns, and suppression lists.",
|
|
env: "Type-safe environment variable loading and validation.",
|
|
error: "Foundation error substrate, code registries, and wire formats.",
|
|
etl: "Extract-Transform-Load pipeline engine with typed stages.",
|
|
events: "Typed event bus, event sourcing, metrics, and transport bridges.",
|
|
"feature-flags": "Feature-flag evaluation engine with percentage and attribute targeting.",
|
|
finance:
|
|
"Currency conversion, cryptocurrency utilities, and exchange-rate providers.",
|
|
flow: "Finite state machines, CRDTs, idempotency, and CBOR serialization.",
|
|
fonts: "Font packing, compression, subsetting, and conversion tools.",
|
|
games: "Game controllers, entity-component systems, and game-server logic.",
|
|
geo: "Geospatial coordinates, planetary data, and solar-system modelling.",
|
|
i18n: "Internationalization core, backends, detectors, and locale resolution.",
|
|
image: "Image compression, colour conversion, EXIF handling, and optimisation.",
|
|
logistics: "Port data and logistics primitives.",
|
|
messaging:
|
|
"Messaging adapters — Discord, Slack, Telegram, SMS, iMessage, and notifications.",
|
|
midi: "MIDI message parsing, control surfaces, and hardware integration.",
|
|
migration: "Schema migration runners and ledger tracking.",
|
|
monitor: "Logging, health checks, audit logging, and analytics instrumentation.",
|
|
network:
|
|
"Mesh networking, WebSocket transports, bootstrap, and discovery protocols.",
|
|
payment:
|
|
"Payment intent lifecycle, provider adapters, and fraud detection.",
|
|
ports: "Maritime port and logistics data.",
|
|
random: "Pseudo-random generators, noise functions, and deterministic sequences.",
|
|
r3f: "React Three Fiber networking and scene components.",
|
|
search: "Full-text search, BM25, fuzzy matching, and faceted search.",
|
|
security: "Have-I-Been-Pwned checks, JWS, licensing, and OTP utilities.",
|
|
storage: "Storage abstractions, browser backends, S3, CDN, and URI routing.",
|
|
testing: "Testing runners, DOM helpers, E2E harnesses, and A/B testing.",
|
|
timing: "Cron, stopwatches, throttling, debouncing, and scheduling.",
|
|
tooling: "CLI frameworks, installers, and build tooling.",
|
|
"webhook-client": "Webhook delivery client with retry logic and HMAC verification.",
|
|
video: "Video encoding, decoding, and thumbnail generation.",
|
|
voice: "Voice synthesis, speech-to-text, and provider adapters.",
|
|
forms: "Form builders, validation, and React form components.",
|
|
react: "React hooks and components for audio, auth, and UI surfaces.",
|
|
};
|
|
|
|
function ensureIntro(path: string, content: string): boolean {
|
|
if (existsSync(path)) return false;
|
|
writeFileSync(path, content + "\n");
|
|
return true;
|
|
}
|
|
|
|
function main(): void {
|
|
if (!isDirectorySafe(PACKAGES_ROOT)) {
|
|
console.error(`Packages root not found: ${PACKAGES_ROOT}`);
|
|
process.exit(2);
|
|
}
|
|
|
|
let created = 0;
|
|
let skipped = 0;
|
|
|
|
const catEntries = readdirSync(PACKAGES_ROOT, { withFileTypes: true });
|
|
|
|
for (const cat of catEntries) {
|
|
if (!cat.isDirectory() || cat.name.startsWith(".")) continue;
|
|
const categoryDir = join(PACKAGES_ROOT, cat.name);
|
|
|
|
// Category intro
|
|
const catIntro = CATEGORY_INTROS[cat.name];
|
|
if (catIntro) {
|
|
const didCreate = ensureIntro(
|
|
join(categoryDir, "_intro.md"),
|
|
catIntro
|
|
);
|
|
didCreate ? created++ : skipped++;
|
|
}
|
|
|
|
const subEntries = readdirSync(categoryDir, { withFileTypes: true });
|
|
for (const sub of subEntries) {
|
|
if (!sub.isDirectory() || sub.name.startsWith(".")) continue;
|
|
const subDir = join(categoryDir, sub.name);
|
|
|
|
// Check if this subcategory actually contains packages
|
|
const pkgEntries = readdirSync(subDir, { withFileTypes: true });
|
|
const hasPackages = pkgEntries.some(
|
|
(e) =>
|
|
e.isDirectory() &&
|
|
!e.name.startsWith(".") &&
|
|
existsSync(join(subDir, e.name, "package.json"))
|
|
);
|
|
if (!hasPackages) continue;
|
|
|
|
const subIntro = SUBCATEGORY_INTROS[sub.name];
|
|
if (subIntro) {
|
|
const didCreate = ensureIntro(
|
|
join(subDir, "_intro.md"),
|
|
subIntro
|
|
);
|
|
didCreate ? created++ : skipped++;
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(`Created: ${created}`);
|
|
console.log(`Skipped (already exist): ${skipped}`);
|
|
}
|
|
|
|
main();
|