Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 7x 7x 7x 7x 7x 7x | // SPDX-FileCopyrightText: 2024-2026 Hack23 AB
// SPDX-License-Identifier: Apache-2.0
/**
* @module Aggregator/ArticleGenerator
* @description Barrel + thin CLI entry point for the article generator.
*
* The library was split (Refactor 7/8) into focused sub-modules under
* `./generator/` so the public API is importable without CLI
* side-effects:
*
* - `./generator/cli.ts` — `parseCliArgs`, `CliOptions`
* - `./generator/slug.ts` — slug + default-description helpers
* - `./generator/discovery.ts` — `discoverAnalysisRuns`, grouping
* - `./generator/reader-guide-insertion.ts`— Reader guide splice helper
* - `./generator/render-one.ts` — `generateArticle(...)` single-run
* - `./generator/render-batch.ts` — `generateAllArticles(opts)`
*
* This file remains the compiled CLI entry — `npm run generate-article`
* resolves to `scripts/aggregator/article-generator.js`. The
* `process.exit`, `console.log`, and `process.argv` side-effects live
* inside the `isMain` block below so that programmatic importers
* (production aggregator code, the test suite, downstream curators)
* see only the pure barrel exports.
*
* **Always-14-languages-always-HTML contract**: every CLI invocation
* renders every supported language to HTML. The legacy `--lang` /
* `--language` / `--markdown-only` flags have been removed. The
* programmatic `generateArticle()` API still accepts `langs` and
* `markdownOnly` for tests that need to scope a render for speed.
*/
import path from 'path';
import { pathToFileURL } from 'url';
// CLI parsing
export { parseCliArgs, type CliOptions } from './generator/cli.js';
// Slug + default description
export {
buildArticleSlug,
sanitizeRunSuffix,
extractDefaultDescription,
} from './generator/slug.js';
// Discovery + grouping
export {
discoverAnalysisRuns,
groupRunsForCollision,
type DiscoveredRun,
} from './generator/discovery.js';
// Reader guide insertion
export { insertReaderGuideAfterExecutiveBrief } from './generator/reader-guide-insertion.js';
// Progressive disclosure reading-time helpers
export {
estimateReadingMinutes,
buildLayerReadingTimes,
splitBodyIntoDisclosureLayers,
} from './progressive-disclosure.js';
// Single-run + batch orchestrators
export { generateArticle, type GenerateResult } from './generator/render-one.js';
export { generateAllArticles } from './generator/render-batch.js';
import { parseCliArgs } from './generator/cli.js';
import { generateArticle } from './generator/render-one.js';
import { generateAllArticles } from './generator/render-batch.js';
/**
* Main entry when invoked as a script. Uses `process.argv.slice(2)` and the
* current working directory as repo root unless overridden by `REPO_ROOT`.
*
* @param argv - Argument list (defaults to `process.argv.slice(2)`)
*/
export async function main(argv: readonly string[] = process.argv.slice(2)): Promise<void> {
const repoRoot = process.env.REPO_ROOT ? path.resolve(process.env.REPO_ROOT) : process.cwd();
const opts = parseCliArgs(argv, repoRoot);
if (opts.all) {
const results = generateAllArticles(opts);
let totalFiles = 0;
let totalArtifacts = 0;
for (const r of results) {
totalFiles += r.writtenFiles.length;
totalArtifacts += r.aggregated.includedArtifacts.length;
process.stdout.write(
` [${r.aggregated.date}/${r.aggregated.articleType}] ${r.writtenFiles.length} file(s) · ${r.aggregated.includedArtifacts.length} artifact(s) · gate ${r.aggregated.gateResult}\n`
);
}
process.stdout.write(
`Generated ${totalFiles} file(s) across ${results.length} run(s) from ${totalArtifacts} total artifact(s)\n`
);
return;
}
const result = generateArticle(opts);
process.stdout.write(
`Generated ${result.writtenFiles.length} file(s) from ${result.aggregated.includedArtifacts.length} artifact(s) — gate: ${result.aggregated.gateResult}\n`
);
for (const f of result.writtenFiles) process.stdout.write(` ${f}\n`);
}
// Only run when invoked directly, not when imported by tests.
const isMain = (() => {
const entry = process.argv[1];
Iif (!entry) return false;
try {
return import.meta.url === pathToFileURL(entry).href;
} catch {
return false;
}
})();
Iif (isMain) {
main().catch((err: unknown) => {
const msg = err instanceof Error ? err.message : String(err);
process.stderr.write(`generate-article: ${msg}\n`);
process.exit(1);
});
}
|