@lexbuild/usc 1.0.6 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,7 +23,7 @@ import { convertTitle } from "@lexbuild/usc";
23
23
  const result = await convertTitle({
24
24
  input: "./downloads/usc/xml/usc01.xml",
25
25
  output: "./output",
26
- granularity: "section",
26
+ granularity: "section", // or "chapter" or "title"
27
27
  linkStyle: "plaintext",
28
28
  includeSourceCredits: true,
29
29
  includeNotes: true,
@@ -91,20 +91,13 @@ console.log(`Release point: ${result.releasePoint}`);
91
91
 
92
92
  ## Output
93
93
 
94
- Each title produces a directory tree of Markdown files with YAML frontmatter and JSON metadata indexes:
94
+ Each title produces Markdown files with YAML frontmatter. The output structure depends on the granularity setting:
95
95
 
96
- ```
97
- output/usc/title-01/
98
- README.md
99
- _meta.json
100
- chapter-01/
101
- _meta.json
102
- section-1.md
103
- section-2.md
104
- chapter-02/
105
- _meta.json
106
- section-101.md
107
- ```
96
+ | Granularity | Output | Metadata |
97
+ |---|---|---|
98
+ | `section` (default) | `title-NN/chapter-NN/section-N.md` | `_meta.json` per chapter + title, `README.md` per title |
99
+ | `chapter` | `title-NN/chapter-NN.md` | `_meta.json` per title, `README.md` per title |
100
+ | `title` | `title-NN.md` | Enriched frontmatter only (no sidecar files) |
108
101
 
109
102
  See the [output format specification](https://github.com/chris-c-thomas/lexbuild/blob/main/docs/output-format.md) for details.
110
103
 
package/dist/index.d.ts CHANGED
@@ -10,8 +10,8 @@ interface ConvertOptions {
10
10
  input: string;
11
11
  /** Output directory root */
12
12
  output: string;
13
- /** Output granularity: "section" (one file per section) or "chapter" (sections inline) */
14
- granularity: "section" | "chapter";
13
+ /** Output granularity: "section" (one file per section), "chapter" (sections inline), or "title" (entire title) */
14
+ granularity: "section" | "chapter" | "title";
15
15
  /** How to render cross-references */
16
16
  linkStyle: "relative" | "canonical" | "plaintext";
17
17
  /** Include source credits in output */
package/dist/index.js CHANGED
@@ -8,10 +8,12 @@ import {
8
8
  ASTBuilder,
9
9
  renderDocument,
10
10
  renderSection,
11
+ renderNode,
11
12
  generateFrontmatter,
12
13
  createLinkResolver,
13
14
  FORMAT_VERSION,
14
- GENERATOR
15
+ GENERATOR,
16
+ BIG_LEVELS
15
17
  } from "@lexbuild/core";
16
18
  var DEFAULTS = {
17
19
  granularity: "section",
@@ -27,8 +29,9 @@ async function convertTitle(options) {
27
29
  const opts = { ...DEFAULTS, ...options };
28
30
  const files = [];
29
31
  let peakMemory = process.memoryUsage.rss();
32
+ let titleLevelTokenEstimate;
30
33
  const collected = [];
31
- const emitAt = opts.granularity === "chapter" ? "chapter" : "section";
34
+ const emitAt = opts.granularity === "title" ? "title" : opts.granularity === "chapter" ? "chapter" : "section";
32
35
  const builder = new ASTBuilder({
33
36
  emitAt,
34
37
  onEmit: (node, context) => {
@@ -46,7 +49,9 @@ async function convertTitle(options) {
46
49
  const meta = builder.getDocumentMeta();
47
50
  if (opts.dryRun) {
48
51
  for (const { node, context } of collected) {
49
- if (opts.granularity === "chapter") {
52
+ if (opts.granularity === "title") {
53
+ collectSectionMetasFromTree(node, context, sectionMetas);
54
+ } else if (opts.granularity === "chapter") {
50
55
  for (const child of node.children) {
51
56
  if (child.type === "level" && child.levelType === "section") {
52
57
  sectionMetas.push(buildSectionMetaDryRun(child, node, context));
@@ -58,6 +63,17 @@ async function convertTitle(options) {
58
63
  }
59
64
  }
60
65
  }
66
+ } else if (opts.granularity === "title") {
67
+ let titleTokenEstimate = 0;
68
+ for (const { node, context } of collected) {
69
+ const result = await writeWholeTitle(node, context, opts);
70
+ files.push(result.filePath);
71
+ titleTokenEstimate += result.totalTokenEstimate;
72
+ for (const m of result.sectionMetas) {
73
+ sectionMetas.push(m);
74
+ }
75
+ }
76
+ titleLevelTokenEstimate = titleTokenEstimate;
61
77
  } else if (opts.granularity === "chapter") {
62
78
  for (const { node, context } of collected) {
63
79
  const result = await writeChapter(node, context, opts);
@@ -104,15 +120,15 @@ async function convertTitle(options) {
104
120
  }
105
121
  }
106
122
  const firstCollected = collected[0];
107
- const titleHeading = firstCollected ? findAncestor(firstCollected.context.ancestors, "title")?.heading?.trim() : void 0;
123
+ const titleHeading = firstCollected ? opts.granularity === "title" ? firstCollected.node.heading?.trim() : findAncestor(firstCollected.context.ancestors, "title")?.heading?.trim() : void 0;
108
124
  if (!opts.dryRun) {
109
125
  await writeMetaFiles(sectionMetas, meta, opts, titleHeading);
110
126
  }
111
127
  peakMemory = Math.max(peakMemory, process.memoryUsage.rss());
112
- const chapterIds = new Set(sectionMetas.map((s) => s.chapterIdentifier));
113
- const totalTokens = sectionMetas.reduce((sum, s) => sum + Math.ceil(s.contentLength / 4), 0);
128
+ const chapterIds = new Set(sectionMetas.map((s) => s.chapterIdentifier).filter(Boolean));
129
+ const totalTokens = titleLevelTokenEstimate ?? sectionMetas.reduce((sum, s) => sum + Math.ceil(s.contentLength / 4), 0);
114
130
  return {
115
- sectionsWritten: opts.dryRun ? sectionMetas.length : files.length,
131
+ sectionsWritten: opts.dryRun || opts.granularity === "title" || opts.granularity === "chapter" ? sectionMetas.length : files.length,
116
132
  files,
117
133
  titleNumber: meta.docNumber ?? "unknown",
118
134
  titleName: titleHeading ?? meta.dcTitle ?? "Unknown Title",
@@ -161,6 +177,7 @@ async function writeSection(node, context, options, linkResolver, dupSuffix) {
161
177
  }
162
178
  async function writeMetaFiles(sectionMetas, docMeta, options, titleHeading) {
163
179
  if (sectionMetas.length === 0) return;
180
+ if (options.granularity === "title") return;
164
181
  const docNum = docMeta.docNumber ?? "0";
165
182
  const titleDirName = buildTitleDirFromDocNumber(docNum);
166
183
  const titleDir = join(options.output, "usc", titleDirName);
@@ -333,6 +350,115 @@ async function writeChapter(chapterNode, context, options) {
333
350
  await writeFile(filePath, markdown, "utf-8");
334
351
  return { filePath, sectionMetas };
335
352
  }
353
+ async function writeWholeTitle(titleNode, context, options) {
354
+ const meta = context.documentMeta;
355
+ const docNum = meta.docNumber ?? titleNode.numValue ?? "0";
356
+ const titleNum = docNum.replace(/a$/i, "");
357
+ const titleName = titleNode.heading?.trim() ?? meta.dcTitle ?? "";
358
+ const currency = parseCurrency(meta.docPublicationName ?? "");
359
+ const lastUpdated = parseDate(meta.created ?? "");
360
+ const notesFilter = buildNotesFilter(options);
361
+ const renderOpts = {
362
+ headingOffset: 0,
363
+ linkStyle: options.linkStyle,
364
+ notesFilter
365
+ };
366
+ const sectionMetas = [];
367
+ const bodyParts = renderTitleChildren(titleNode, 2, options, renderOpts, sectionMetas, titleNum);
368
+ const bodyMarkdownParts = [];
369
+ const numDisplay = titleNode.num ?? "";
370
+ const headingText = titleNode.heading ? ` ${titleNode.heading}` : "";
371
+ bodyMarkdownParts.push(`# ${numDisplay}${headingText}`);
372
+ bodyMarkdownParts.push(...bodyParts);
373
+ const bodyMarkdown = bodyMarkdownParts.join("\n");
374
+ const fmData = {
375
+ identifier: titleNode.identifier ?? meta.identifier ?? `/us/usc/t${titleNum}`,
376
+ title: `Title ${titleNum} \u2014 ${titleName}`,
377
+ title_number: parseIntSafe(titleNum),
378
+ title_name: titleName,
379
+ positive_law: meta.positivelaw ?? false,
380
+ currency,
381
+ last_updated: lastUpdated,
382
+ chapter_count: new Set(sectionMetas.map((s) => s.chapterIdentifier).filter(Boolean)).size,
383
+ section_count: sectionMetas.length,
384
+ total_token_estimate: Math.ceil(bodyMarkdown.length / 4)
385
+ };
386
+ const markdown = generateFrontmatter(fmData) + "\n\n" + bodyMarkdown + "\n";
387
+ const titleFile = `${buildTitleDirFromDocNumber(docNum)}.md`;
388
+ const filePath = join(options.output, "usc", titleFile);
389
+ await mkdir(dirname(filePath), { recursive: true });
390
+ await writeFile(filePath, markdown, "utf-8");
391
+ const totalTokenEstimate = Math.ceil(bodyMarkdown.length / 4);
392
+ return { filePath, sectionMetas, totalTokenEstimate };
393
+ }
394
+ function renderTitleChildren(node, headingLevel, options, renderOpts, sectionMetas, titleNum, currentChapter) {
395
+ const parts = [];
396
+ for (const child of node.children) {
397
+ if (child.type === "level" && child.levelType === "section") {
398
+ const sectionOpts = {
399
+ ...renderOpts,
400
+ headingOffset: Math.min(headingLevel - 1, 5)
401
+ };
402
+ const sectionNode = options.includeSourceCredits ? child : stripSourceCredits(child);
403
+ const sectionMd = renderSection(sectionNode, sectionOpts);
404
+ parts.push("");
405
+ parts.push(sectionMd);
406
+ const sectionNum = child.numValue ?? "0";
407
+ const hasNotes = child.children.some((c) => c.type === "notesContainer" || c.type === "note");
408
+ sectionMetas.push({
409
+ identifier: child.identifier ?? `/us/usc/t${titleNum}/s${sectionNum}`,
410
+ number: sectionNum,
411
+ name: child.heading?.trim() ?? "",
412
+ fileName: `section-${sectionNum}.md`,
413
+ relativeFile: `section-${sectionNum}.md`,
414
+ contentLength: sectionMd.length,
415
+ hasNotes,
416
+ status: child.status ?? "current",
417
+ chapterIdentifier: currentChapter?.identifier ?? "",
418
+ chapterNumber: currentChapter?.numValue ?? "0",
419
+ chapterName: currentChapter?.heading?.trim() ?? ""
420
+ });
421
+ } else if (child.type === "level" && BIG_LEVELS.has(child.levelType)) {
422
+ const numDisplay = child.num ?? "";
423
+ const heading = child.heading ? ` ${child.heading}` : "";
424
+ parts.push("");
425
+ if (headingLevel <= 5) {
426
+ const prefix = "#".repeat(headingLevel);
427
+ parts.push(`${prefix} ${numDisplay}${heading}`);
428
+ } else {
429
+ parts.push(`**${numDisplay}${heading}**`);
430
+ }
431
+ const nextChapter = child.levelType === "chapter" ? child : currentChapter;
432
+ const childParts = renderTitleChildren(
433
+ child,
434
+ headingLevel + 1,
435
+ options,
436
+ renderOpts,
437
+ sectionMetas,
438
+ titleNum,
439
+ nextChapter
440
+ );
441
+ parts.push(...childParts);
442
+ } else {
443
+ const rendered = renderNode(child, renderOpts);
444
+ if (rendered) {
445
+ parts.push("");
446
+ parts.push(rendered);
447
+ }
448
+ }
449
+ }
450
+ return parts;
451
+ }
452
+ function collectSectionMetasFromTree(node, context, sectionMetas, currentChapter) {
453
+ for (const child of node.children) {
454
+ if (child.type === "level" && child.levelType === "section") {
455
+ sectionMetas.push(buildSectionMetaDryRun(child, currentChapter ?? null, context));
456
+ } else if (child.type === "level" && BIG_LEVELS.has(child.levelType)) {
457
+ const nextChapter = child.levelType === "chapter" ? child : currentChapter;
458
+ collectSectionMetasFromTree(child, context, sectionMetas, nextChapter);
459
+ }
460
+ }
461
+ }
336
462
  function buildOutputPath(context, sectionNum, outputRoot, dupSuffix) {
337
463
  const titleDir = buildTitleDir(context);
338
464
  const chapterDir = buildChapterDir(context);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/converter.ts","../src/downloader.ts"],"sourcesContent":["/**\n * USC Converter — orchestrates the full conversion pipeline for a single USC XML file.\n *\n * Creates a ReadStream → SAX Parser → AST Builder (emit at section) →\n * Markdown Renderer + Frontmatter → File Writer.\n */\n\nimport { createReadStream } from \"node:fs\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { basename } from \"node:path\";\nimport {\n XMLParser,\n ASTBuilder,\n renderDocument,\n renderSection,\n generateFrontmatter,\n createLinkResolver,\n FORMAT_VERSION,\n GENERATOR,\n} from \"@lexbuild/core\";\nimport type {\n LevelNode,\n EmitContext,\n FrontmatterData,\n RenderOptions,\n NotesFilter,\n AncestorInfo,\n LinkResolver,\n} from \"@lexbuild/core\";\n\n/** Options for converting a USC XML file */\nexport interface ConvertOptions {\n /** Path to the input XML file */\n input: string;\n /** Output directory root */\n output: string;\n /** Output granularity: \"section\" (one file per section) or \"chapter\" (sections inline) */\n granularity: \"section\" | \"chapter\";\n /** How to render cross-references */\n linkStyle: \"relative\" | \"canonical\" | \"plaintext\";\n /** Include source credits in output */\n includeSourceCredits: boolean;\n /** Include notes in output. True = all notes (default). False = no notes. */\n includeNotes: boolean;\n /** Include editorial notes only (when includeNotes is false) */\n includeEditorialNotes: boolean;\n /** Include statutory notes only (when includeNotes is false) */\n includeStatutoryNotes: boolean;\n /** Include amendment history notes only (when includeNotes is false) */\n includeAmendments: boolean;\n /** Dry-run mode: parse and report structure without writing files */\n dryRun: boolean;\n}\n\n/** Result of a conversion */\nexport interface ConvertResult {\n /** Number of sections written (or that would be written in dry-run) */\n sectionsWritten: number;\n /** Output paths of all written files (empty in dry-run) */\n files: string[];\n /** Title number extracted from metadata */\n titleNumber: string;\n /** Title name extracted from metadata */\n titleName: string;\n /** Whether this was a dry run */\n dryRun: boolean;\n /** Chapter count */\n chapterCount: number;\n /** Estimated total tokens */\n totalTokenEstimate: number;\n /** Peak resident set size in bytes during conversion */\n peakMemoryBytes: number;\n}\n\n/** Default convert options */\nconst DEFAULTS: Omit<ConvertOptions, \"input\" | \"output\"> = {\n granularity: \"section\",\n linkStyle: \"plaintext\",\n includeSourceCredits: true,\n includeNotes: true,\n includeEditorialNotes: false,\n includeStatutoryNotes: false,\n includeAmendments: false,\n dryRun: false,\n};\n\n/** Metadata collected for a written section (used to build _meta.json) */\ninterface SectionMeta {\n identifier: string;\n number: string;\n name: string;\n /** Filename only (e.g., \"section-3598.md\" or \"section-3598-2.md\" for duplicates) */\n fileName: string;\n /** File path relative to the title directory (e.g., \"chapter-01/section-1.md\") */\n relativeFile: string;\n /** Content length in characters (for token estimation) */\n contentLength: number;\n hasNotes: boolean;\n status: string;\n /** Chapter identifier this section belongs to */\n chapterIdentifier: string;\n chapterNumber: string;\n chapterName: string;\n}\n\n/** A collected section ready to be written */\ninterface CollectedSection {\n node: LevelNode;\n context: EmitContext;\n}\n\n/**\n * Convert a single USC XML file to section-level Markdown files.\n */\nexport async function convertTitle(options: ConvertOptions): Promise<ConvertResult> {\n const opts = { ...DEFAULTS, ...options };\n const files: string[] = [];\n let peakMemory = process.memoryUsage.rss();\n\n // Collect emitted nodes during parsing (synchronous), write after parsing completes\n const collected: CollectedSection[] = [];\n\n // Set up the AST builder — emit level depends on granularity\n const emitAt = opts.granularity === \"chapter\" ? (\"chapter\" as const) : (\"section\" as const);\n const builder = new ASTBuilder({\n emitAt,\n onEmit: (node, context) => {\n collected.push({ node, context });\n },\n });\n\n // Set up the XML parser\n const parser = new XMLParser();\n parser.on(\"openElement\", (name, attrs) => builder.onOpenElement(name, attrs));\n parser.on(\"closeElement\", (name) => builder.onCloseElement(name));\n parser.on(\"text\", (text) => builder.onText(text));\n\n // Parse the XML file\n const stream = createReadStream(opts.input, \"utf-8\");\n await parser.parseStream(stream);\n peakMemory = Math.max(peakMemory, process.memoryUsage.rss());\n\n const sectionMetas: SectionMeta[] = [];\n const meta = builder.getDocumentMeta();\n\n if (opts.dryRun) {\n // Dry-run: collect metadata without writing files\n for (const { node, context } of collected) {\n if (opts.granularity === \"chapter\") {\n // Extract section metadata from chapter children\n for (const child of node.children) {\n if (child.type === \"level\" && child.levelType === \"section\") {\n sectionMetas.push(buildSectionMetaDryRun(child, node, context));\n }\n }\n } else {\n if (node.numValue) {\n sectionMetas.push(buildSectionMetaDryRun(node, null, context));\n }\n }\n }\n } else if (opts.granularity === \"chapter\") {\n // Chapter-level: each emitted node is a chapter containing sections\n for (const { node, context } of collected) {\n const result = await writeChapter(node, context, opts);\n if (result) {\n files.push(result.filePath);\n for (const m of result.sectionMetas) {\n sectionMetas.push(m);\n }\n }\n }\n } else {\n // Section-level with relative links: need two-pass for link resolver\n // Track duplicate section numbers per chapter to disambiguate filenames\n const sectionCounts = new Map<string, number>();\n const suffixes: (string | undefined)[] = [];\n for (const { node, context } of collected) {\n const sectionNum = node.numValue;\n if (!sectionNum) {\n suffixes.push(undefined);\n continue;\n }\n const chapterDir = buildChapterDir(context) ?? \"__root__\";\n const key = `${chapterDir}/${sectionNum}`;\n const count = (sectionCounts.get(key) ?? 0) + 1;\n sectionCounts.set(key, count);\n suffixes.push(count > 1 ? `-${count}` : undefined);\n }\n\n const linkResolver = createLinkResolver();\n for (const [i, { node, context }] of collected.entries()) {\n const sectionNum = node.numValue;\n if (sectionNum && node.identifier) {\n const filePath = buildOutputPath(context, sectionNum, opts.output, suffixes[i]);\n // For duplicates, register with the XML element @id to disambiguate\n const regId = suffixes[i] ? `${node.identifier}#${suffixes[i]}` : node.identifier;\n linkResolver.register(regId, filePath);\n // Always register the first occurrence under the canonical identifier\n if (!suffixes[i]) {\n linkResolver.register(node.identifier, filePath);\n }\n }\n }\n\n for (const [i, { node, context }] of collected.entries()) {\n const result = await writeSection(node, context, opts, linkResolver, suffixes[i]);\n if (result) {\n files.push(result.filePath);\n sectionMetas.push(result.meta);\n }\n }\n }\n\n // Extract the title heading from the first collected section's ancestors\n const firstCollected = collected[0];\n const titleHeading = firstCollected\n ? findAncestor(firstCollected.context.ancestors, \"title\")?.heading?.trim()\n : undefined;\n\n // Generate _meta.json and README.md files (skip in dry-run)\n if (!opts.dryRun) {\n await writeMetaFiles(sectionMetas, meta, opts, titleHeading);\n }\n\n // Final memory sample\n peakMemory = Math.max(peakMemory, process.memoryUsage.rss());\n\n // Compute stats\n const chapterIds = new Set(sectionMetas.map((s) => s.chapterIdentifier));\n const totalTokens = sectionMetas.reduce((sum, s) => sum + Math.ceil(s.contentLength / 4), 0);\n\n return {\n sectionsWritten: opts.dryRun ? sectionMetas.length : files.length,\n files,\n titleNumber: meta.docNumber ?? \"unknown\",\n titleName: titleHeading ?? meta.dcTitle ?? \"Unknown Title\",\n dryRun: opts.dryRun,\n chapterCount: chapterIds.size,\n totalTokenEstimate: totalTokens,\n peakMemoryBytes: peakMemory,\n };\n}\n\n/** Result of writing a single section */\ninterface WriteSectionResult {\n filePath: string;\n meta: SectionMeta;\n}\n\n/**\n * Write a single section to disk.\n * Returns the file path and metadata, or null if the section was skipped.\n */\nasync function writeSection(\n node: LevelNode,\n context: EmitContext,\n options: ConvertOptions,\n linkResolver?: LinkResolver | undefined,\n /** Disambiguation suffix for duplicate section numbers (e.g., \"-2\") */\n dupSuffix?: string | undefined,\n): Promise<WriteSectionResult | null> {\n const sectionNum = node.numValue;\n if (!sectionNum) return null;\n\n // Build the output file path (with optional duplicate suffix)\n const filePath = buildOutputPath(context, sectionNum, options.output, dupSuffix);\n\n // Build frontmatter data\n const frontmatter = buildFrontmatter(node, context);\n\n // Build notes filter\n const notesFilter = buildNotesFilter(options);\n\n // Build render options with link resolver for relative links\n const renderOpts: RenderOptions = {\n headingOffset: 0,\n linkStyle: options.linkStyle,\n resolveLink: linkResolver\n ? (identifier: string) => linkResolver.resolve(identifier, filePath)\n : undefined,\n notesFilter,\n };\n\n // Optionally strip source credits\n const sectionNode = options.includeSourceCredits ? node : stripSourceCredits(node);\n\n // Render the document\n const markdown = renderDocument(sectionNode, frontmatter, renderOpts);\n\n // Ensure the directory exists and write the file\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, markdown, \"utf-8\");\n\n // Collect metadata\n const titleNum = findAncestor(context.ancestors, \"title\")?.numValue ?? \"0\";\n const chapterAncestor = findAncestor(context.ancestors, \"chapter\");\n const chapterDir = chapterAncestor?.numValue ? `chapter-${padTwo(chapterAncestor.numValue)}` : \"\";\n const sectionFileName = `section-${sectionNum}${dupSuffix ?? \"\"}.md`;\n const relativeFile = chapterDir ? `${chapterDir}/${sectionFileName}` : sectionFileName;\n\n const hasNotes = node.children.some((c) => c.type === \"notesContainer\" || c.type === \"note\");\n\n const sectionMeta: SectionMeta = {\n identifier: node.identifier ?? `/us/usc/t${titleNum}/s${sectionNum}`,\n number: sectionNum,\n name: node.heading?.trim() ?? \"\",\n fileName: sectionFileName,\n relativeFile,\n contentLength: markdown.length,\n hasNotes,\n status: node.status ?? \"current\",\n chapterIdentifier: chapterAncestor?.identifier ?? \"\",\n chapterNumber: chapterAncestor?.numValue ?? \"0\",\n chapterName: chapterAncestor?.heading?.trim() ?? \"\",\n };\n\n return { filePath, meta: sectionMeta };\n}\n\n/**\n * Build the output file path for a section.\n *\n * Format: {output}/usc/title-{NN}/chapter-{NN}/section-{N}.md\n */\n/**\n * Generate _meta.json files at title and chapter levels.\n */\nasync function writeMetaFiles(\n sectionMetas: SectionMeta[],\n docMeta: {\n dcTitle?: string | undefined;\n docNumber?: string | undefined;\n positivelaw?: boolean | undefined;\n docPublicationName?: string | undefined;\n created?: string | undefined;\n identifier?: string | undefined;\n },\n options: ConvertOptions,\n titleHeading?: string | undefined,\n): Promise<void> {\n if (sectionMetas.length === 0) return;\n\n const docNum = docMeta.docNumber ?? \"0\";\n const titleDirName = buildTitleDirFromDocNumber(docNum);\n const titleDir = join(options.output, \"usc\", titleDirName);\n const currency = parseCurrency(docMeta.docPublicationName ?? \"\");\n\n // Group sections by chapter\n const chapterMap = new Map<string, SectionMeta[]>();\n for (const sm of sectionMetas) {\n const key = sm.chapterIdentifier || \"__no_chapter__\";\n let arr = chapterMap.get(key);\n if (!arr) {\n arr = [];\n chapterMap.set(key, arr);\n }\n arr.push(sm);\n }\n\n // Write chapter-level _meta.json files\n const chapterEntries: Array<{\n identifier: string;\n number: number;\n name: string;\n directory: string;\n sections: Array<{\n identifier: string;\n number: string;\n name: string;\n file: string;\n token_estimate: number;\n has_notes: boolean;\n status: string;\n }>;\n }> = [];\n\n for (const [chapterId, chapterSections] of chapterMap) {\n if (chapterId === \"__no_chapter__\") continue;\n\n const first = chapterSections[0];\n if (!first) continue;\n\n const chapterDir = `chapter-${padTwo(first.chapterNumber)}`;\n\n const sections = chapterSections.map((sm) => ({\n identifier: sm.identifier,\n number: sm.number,\n name: sm.name,\n file: sm.fileName,\n token_estimate: Math.ceil(sm.contentLength / 4),\n has_notes: sm.hasNotes,\n status: sm.status,\n }));\n\n const chapterMeta = {\n format_version: FORMAT_VERSION,\n identifier: chapterId,\n chapter_number: parseIntSafe(first.chapterNumber),\n chapter_name: first.chapterName,\n title_number: parseIntSafe(docNum),\n section_count: sections.length,\n sections,\n };\n\n const chapterMetaPath = join(titleDir, chapterDir, \"_meta.json\");\n await mkdir(dirname(chapterMetaPath), { recursive: true });\n await writeFile(chapterMetaPath, JSON.stringify(chapterMeta, null, 2) + \"\\n\", \"utf-8\");\n\n chapterEntries.push({\n identifier: chapterId,\n number: parseIntSafe(first.chapterNumber),\n name: first.chapterName,\n directory: chapterDir,\n sections,\n });\n }\n\n // Write title-level _meta.json\n const totalTokens = sectionMetas.reduce((sum, sm) => sum + Math.ceil(sm.contentLength / 4), 0);\n\n const titleMeta = {\n format_version: FORMAT_VERSION,\n generator: GENERATOR,\n generated_at: new Date().toISOString(),\n identifier: docMeta.identifier ?? `/us/usc/t${docNum}`,\n title_number: parseIntSafe(docNum),\n title_name: titleHeading ?? docMeta.dcTitle ?? \"\",\n positive_law: docMeta.positivelaw ?? false,\n currency,\n source_xml: basename(options.input),\n granularity: options.granularity,\n stats: {\n chapter_count: chapterEntries.length,\n section_count: sectionMetas.length,\n total_files: sectionMetas.length,\n total_tokens_estimate: totalTokens,\n },\n chapters: chapterEntries,\n };\n\n const titleMetaPath = join(titleDir, \"_meta.json\");\n await mkdir(dirname(titleMetaPath), { recursive: true });\n await writeFile(titleMetaPath, JSON.stringify(titleMeta, null, 2) + \"\\n\", \"utf-8\");\n\n // Write title-level README.md\n const readmePath = join(titleDir, \"README.md\");\n const readme = generateTitleReadme(titleMeta);\n await writeFile(readmePath, readme, \"utf-8\");\n}\n\n/**\n * Generate a human-readable README.md for a title output directory.\n */\nfunction generateTitleReadme(meta: {\n title_number: number;\n title_name: string;\n positive_law: boolean;\n currency: string;\n granularity: string;\n stats: {\n chapter_count: number;\n section_count: number;\n total_tokens_estimate: number;\n };\n chapters: Array<{\n number: number;\n name: string;\n directory: string;\n sections: Array<{\n number: string;\n name: string;\n file: string;\n status: string;\n }>;\n }>;\n}): string {\n const lines: string[] = [];\n\n lines.push(`# Title ${meta.title_number} — ${meta.title_name}`);\n lines.push(\"\");\n lines.push(`| | |`);\n lines.push(`| --- | --- |`);\n lines.push(`| **Positive Law** | ${meta.positive_law ? \"Yes\" : \"No\"} |`);\n lines.push(`| **Currency** | ${meta.currency || \"unknown\"} |`);\n lines.push(`| **Chapters** | ${meta.stats.chapter_count} |`);\n lines.push(`| **Sections** | ${meta.stats.section_count.toLocaleString()} |`);\n lines.push(`| **Est. Tokens** | ${meta.stats.total_tokens_estimate.toLocaleString()} |`);\n lines.push(`| **Granularity** | ${meta.granularity} |`);\n lines.push(\"\");\n\n // Chapter listing\n lines.push(\"## Chapters\");\n lines.push(\"\");\n\n for (const ch of meta.chapters) {\n const sectionCount = ch.sections.length;\n lines.push(`### Chapter ${ch.number} — ${ch.name}`);\n lines.push(\"\");\n lines.push(\n `${sectionCount} section${sectionCount !== 1 ? \"s\" : \"\"} · [${ch.directory}/](${ch.directory}/)`,\n );\n lines.push(\"\");\n }\n\n // Footer\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(`Generated by [lexbuild](https://github.com/chris-c-thomas/lexbuild)`);\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/** Result of writing a chapter file */\ninterface WriteChapterResult {\n filePath: string;\n sectionMetas: SectionMeta[];\n}\n\n/**\n * Write a chapter-level file (all sections inlined).\n * The emitted node is a chapter LevelNode whose children include section LevelNodes.\n */\nasync function writeChapter(\n chapterNode: LevelNode,\n context: EmitContext,\n options: ConvertOptions,\n): Promise<WriteChapterResult | null> {\n const chapterNum = chapterNode.numValue;\n if (!chapterNum) return null;\n\n const titleNum = findAncestor(context.ancestors, \"title\")?.numValue ?? \"0\";\n const titleDir = `title-${padTwo(titleNum)}`;\n const chapterFile = `chapter-${padTwo(chapterNum)}.md`;\n const filePath = join(options.output, \"usc\", titleDir, chapterFile);\n\n // Build chapter-level frontmatter\n const titleAncestor = findAncestor(context.ancestors, \"title\");\n const meta = context.documentMeta;\n const chapterName = chapterNode.heading?.trim() ?? \"\";\n const titleName = titleAncestor?.heading?.trim() ?? meta.dcTitle ?? \"\";\n const currency = parseCurrency(meta.docPublicationName ?? \"\");\n const lastUpdated = parseDate(meta.created ?? \"\");\n\n const fmData: FrontmatterData = {\n identifier: chapterNode.identifier ?? `/us/usc/t${titleNum}/ch${chapterNum}`,\n title: `${titleNum} USC Chapter ${chapterNum} - ${chapterName}`,\n title_number: parseIntSafe(titleNum),\n title_name: titleName,\n section_number: chapterNum,\n section_name: chapterName,\n chapter_number: parseIntSafe(chapterNum),\n chapter_name: chapterName,\n positive_law: meta.positivelaw ?? false,\n currency,\n last_updated: lastUpdated,\n };\n\n const notesFilter = buildNotesFilter(options);\n const renderOpts: RenderOptions = {\n headingOffset: 0,\n linkStyle: options.linkStyle,\n notesFilter,\n };\n\n // Build the chapter Markdown: heading + each section rendered with H2\n const parts: string[] = [];\n parts.push(generateFrontmatter(fmData));\n parts.push(\"\");\n parts.push(`# Chapter ${chapterNum} — ${chapterName}`);\n\n // Collect section metas and render each section\n const sectionMetas: SectionMeta[] = [];\n\n for (const child of chapterNode.children) {\n if (child.type === \"level\" && child.levelType === \"section\") {\n const sectionOpts: RenderOptions = { ...renderOpts, headingOffset: 1 };\n const sectionNode = options.includeSourceCredits ? child : stripSourceCredits(child);\n const sectionMd = renderSection(sectionNode, sectionOpts);\n parts.push(\"\");\n parts.push(sectionMd);\n\n // Collect section metadata\n const sectionNum = child.numValue ?? \"0\";\n const hasNotes = child.children.some((c) => c.type === \"notesContainer\" || c.type === \"note\");\n sectionMetas.push({\n identifier: child.identifier ?? `/us/usc/t${titleNum}/s${sectionNum}`,\n number: sectionNum,\n name: child.heading?.trim() ?? \"\",\n fileName: `section-${sectionNum}.md`,\n relativeFile: chapterFile,\n contentLength: sectionMd.length,\n hasNotes,\n status: child.status ?? \"current\",\n chapterIdentifier: chapterNode.identifier ?? \"\",\n chapterNumber: chapterNum,\n chapterName,\n });\n }\n }\n\n const markdown = parts.join(\"\\n\") + \"\\n\";\n\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, markdown, \"utf-8\");\n\n return { filePath, sectionMetas };\n}\n\nfunction buildOutputPath(\n context: EmitContext,\n sectionNum: string,\n outputRoot: string,\n /** Disambiguation suffix for duplicate section numbers (e.g., \"-2\") */\n dupSuffix?: string | undefined,\n): string {\n const titleDir = buildTitleDir(context);\n const chapterDir = buildChapterDir(context);\n const sectionFile = `section-${sectionNum}${dupSuffix ?? \"\"}.md`;\n\n if (chapterDir) {\n return join(outputRoot, \"usc\", titleDir, chapterDir, sectionFile);\n }\n\n return join(outputRoot, \"usc\", titleDir, sectionFile);\n}\n\n/**\n * Build the title directory name from context.\n * Handles appendix titles: docNumber \"5a\" → \"title-05-appendix\"\n */\nfunction buildTitleDir(context: EmitContext): string {\n // Check for appendix via docNumber (e.g., \"5a\", \"11a\")\n const docNum = context.documentMeta.docNumber ?? \"\";\n const appendixMatch = /^(\\d+)a$/i.exec(docNum);\n if (appendixMatch?.[1]) {\n return `title-${padTwo(appendixMatch[1])}-appendix`;\n }\n\n // Check for appendix ancestor\n const appendixAncestor = findAncestor(context.ancestors, \"appendix\");\n if (appendixAncestor) {\n const num = appendixAncestor.numValue ?? docNum;\n const numericPart = /^(\\d+)/.exec(num);\n if (numericPart?.[1]) {\n return `title-${padTwo(numericPart[1])}-appendix`;\n }\n }\n\n // Normal title\n const titleNum = findAncestor(context.ancestors, \"title\")?.numValue ?? \"00\";\n return `title-${padTwo(titleNum)}`;\n}\n\n/**\n * Build the chapter directory name from context.\n * Handles chapter equivalents: compiledAct, reorganizationPlan.\n */\nfunction buildChapterDir(context: EmitContext): string | undefined {\n // Standard chapter\n const chapterNum = findAncestor(context.ancestors, \"chapter\")?.numValue;\n if (chapterNum) return `chapter-${padTwo(chapterNum)}`;\n\n // Compiled act as chapter equivalent\n const compiledAct = findAncestor(context.ancestors, \"compiledAct\");\n if (compiledAct) {\n const heading = compiledAct.heading?.trim() ?? \"\";\n // Use a slug of the heading as directory name\n const slug = heading\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 50);\n return slug || \"compiled-act\";\n }\n\n // Reorganization plan as chapter equivalent\n const reorgPlan = findAncestor(context.ancestors, \"reorganizationPlan\");\n if (reorgPlan) {\n const heading = reorgPlan.heading?.trim() ?? \"\";\n const slug = heading\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 50);\n return slug || \"reorganization-plan\";\n }\n\n // Reorganization plans container\n const reorgPlans = findAncestor(context.ancestors, \"reorganizationPlans\");\n if (reorgPlans) {\n return \"reorganization-plans\";\n }\n\n return undefined;\n}\n\n/**\n * Build FrontmatterData from the emitted section node and context.\n */\nfunction buildFrontmatter(node: LevelNode, context: EmitContext): FrontmatterData {\n const meta = context.documentMeta;\n const titleAncestor =\n findAncestor(context.ancestors, \"title\") ?? findAncestor(context.ancestors, \"appendix\");\n const chapterAncestor =\n findAncestor(context.ancestors, \"chapter\") ??\n findAncestor(context.ancestors, \"compiledAct\") ??\n findAncestor(context.ancestors, \"reorganizationPlan\");\n const subchapterAncestor = findAncestor(context.ancestors, \"subchapter\");\n const partAncestor = findAncestor(context.ancestors, \"part\");\n\n const docNum = meta.docNumber ?? titleAncestor?.numValue ?? \"0\";\n const titleNum = parseIntSafe(docNum.replace(/a$/i, \"\"));\n const sectionNum = node.numValue ?? \"0\";\n const sectionName = node.heading?.trim() ?? \"\";\n const titleName = titleAncestor?.heading?.trim() ?? meta.dcTitle ?? \"\";\n\n // Build the human-readable title: \"1 USC § 1 - Section Name\"\n const displayTitle = `${titleNum} USC § ${sectionNum} - ${sectionName}`;\n\n // Extract source credit text from the section's children\n const sourceCredit = extractSourceCreditText(node);\n\n // Parse currency from docPublicationName (e.g., \"Online@119-73not60\" → \"119-73\")\n const currency = parseCurrency(meta.docPublicationName ?? \"\");\n\n // Parse last_updated from created timestamp\n const lastUpdated = parseDate(meta.created ?? \"\");\n\n const fm: FrontmatterData = {\n identifier: node.identifier ?? `/us/usc/t${titleNum}/s${sectionNum}`,\n title: displayTitle,\n title_number: titleNum,\n title_name: titleName,\n section_number: sectionNum,\n section_name: sectionName,\n positive_law: meta.positivelaw ?? false,\n currency,\n last_updated: lastUpdated,\n };\n\n if (chapterAncestor?.numValue) {\n fm.chapter_number = parseIntSafe(chapterAncestor.numValue);\n }\n if (chapterAncestor?.heading) {\n fm.chapter_name = chapterAncestor.heading.trim();\n }\n if (subchapterAncestor?.numValue) {\n fm.subchapter_number = subchapterAncestor.numValue;\n }\n if (subchapterAncestor?.heading) {\n fm.subchapter_name = subchapterAncestor.heading.trim();\n }\n if (partAncestor?.numValue) {\n fm.part_number = partAncestor.numValue;\n }\n if (partAncestor?.heading) {\n fm.part_name = partAncestor.heading.trim();\n }\n if (sourceCredit) {\n fm.source_credit = sourceCredit;\n }\n if (node.status) {\n fm.status = node.status;\n }\n\n return fm;\n}\n\n// ---------------------------------------------------------------------------\n// Utility functions\n// ---------------------------------------------------------------------------\n\n/**\n * Find an ancestor by level type.\n */\n/**\n * Build a NotesFilter from convert options.\n * Returns undefined if all notes should be included (default).\n */\n/**\n * Build SectionMeta from AST node without rendering (for dry-run mode).\n */\nfunction buildSectionMetaDryRun(\n sectionNode: LevelNode,\n chapterNode: LevelNode | null,\n context: EmitContext,\n): SectionMeta {\n const titleNum = findAncestor(context.ancestors, \"title\")?.numValue ?? \"0\";\n const chapterAncestor = chapterNode\n ? {\n numValue: chapterNode.numValue,\n heading: chapterNode.heading,\n identifier: chapterNode.identifier,\n }\n : findAncestor(context.ancestors, \"chapter\");\n const sectionNum = sectionNode.numValue ?? \"0\";\n const chapterNum = chapterAncestor?.numValue ?? \"0\";\n const chapterDir = chapterNum !== \"0\" ? `chapter-${padTwo(chapterNum)}` : \"\";\n\n const hasNotes = sectionNode.children.some(\n (c) => c.type === \"notesContainer\" || c.type === \"note\",\n );\n\n // Rough content length estimate from AST text nodes\n let contentLength = 0;\n const walk = (node: {\n children?: readonly { text?: string | undefined; children?: readonly unknown[] }[] | undefined;\n text?: string | undefined;\n }): void => {\n if (node.text) contentLength += node.text.length;\n if (node.children) {\n for (const child of node.children) {\n walk(child as typeof node);\n }\n }\n };\n walk(sectionNode as unknown as Parameters<typeof walk>[0]);\n\n const sectionFileName = `section-${sectionNum}.md`;\n return {\n identifier: sectionNode.identifier ?? `/us/usc/t${titleNum}/s${sectionNum}`,\n number: sectionNum,\n name: sectionNode.heading?.trim() ?? \"\",\n fileName: sectionFileName,\n relativeFile: chapterDir ? `${chapterDir}/${sectionFileName}` : sectionFileName,\n contentLength,\n hasNotes,\n status: sectionNode.status ?? \"current\",\n chapterIdentifier: chapterAncestor?.identifier ?? \"\",\n chapterNumber: chapterNum,\n chapterName: chapterAncestor?.heading?.trim() ?? \"\",\n };\n}\n\nfunction buildNotesFilter(options: ConvertOptions): NotesFilter | undefined {\n // Default: include all notes\n if (options.includeNotes) return undefined;\n\n // No notes at all\n if (\n !options.includeEditorialNotes &&\n !options.includeStatutoryNotes &&\n !options.includeAmendments\n ) {\n return { editorial: false, statutory: false, amendments: false };\n }\n\n // Selective inclusion\n return {\n editorial: options.includeEditorialNotes,\n statutory: options.includeStatutoryNotes,\n amendments: options.includeAmendments,\n };\n}\n\nfunction findAncestor(\n ancestors: readonly AncestorInfo[],\n levelType: string,\n): AncestorInfo | undefined {\n return ancestors.find((a) => a.levelType === levelType);\n}\n\n/**\n * Zero-pad a number string to 2 digits.\n */\n/**\n * Build title directory name from docNumber.\n * \"5\" → \"title-05\", \"5a\" → \"title-05-appendix\"\n */\nfunction buildTitleDirFromDocNumber(docNum: string): string {\n const appendixMatch = /^(\\d+)a$/i.exec(docNum);\n if (appendixMatch?.[1]) {\n return `title-${padTwo(appendixMatch[1])}-appendix`;\n }\n return `title-${padTwo(docNum)}`;\n}\n\nfunction padTwo(num: string): string {\n const n = parseInt(num, 10);\n if (isNaN(n)) return num;\n return n.toString().padStart(2, \"0\");\n}\n\n/**\n * Parse an integer safely, returning 0 if invalid.\n */\nfunction parseIntSafe(s: string): number {\n const n = parseInt(s, 10);\n return isNaN(n) ? 0 : n;\n}\n\n/**\n * Extract source credit plain text from a section node's children.\n */\nfunction extractSourceCreditText(node: LevelNode): string | undefined {\n for (const child of node.children) {\n if (child.type === \"sourceCredit\") {\n return child.children.map((inline) => inlineToText(inline)).join(\"\");\n }\n }\n return undefined;\n}\n\n/**\n * Recursively extract plain text from an InlineNode.\n */\nfunction inlineToText(node: {\n readonly type: \"inline\";\n text?: string | undefined;\n children?: readonly { readonly type: \"inline\"; text?: string | undefined }[] | undefined;\n}): string {\n if (node.text) return node.text;\n if (node.children) {\n return node.children.map((c) => c.text ?? \"\").join(\"\");\n }\n return \"\";\n}\n\n/**\n * Parse currency/release point from docPublicationName.\n * Example: \"Online@119-73not60\" → \"119-73\"\n */\nfunction parseCurrency(pubName: string): string {\n // Try to extract the release point pattern (e.g., \"119-73\")\n const match = /(\\d+-\\d+)/.exec(pubName);\n if (match?.[1]) return match[1];\n return pubName || \"unknown\";\n}\n\n/**\n * Parse a date string to ISO date format (YYYY-MM-DD).\n */\nfunction parseDate(dateStr: string): string {\n if (!dateStr) return \"unknown\";\n // Handle ISO timestamp: \"2025-12-03T10:11:39\" → \"2025-12-03\"\n const datePart = dateStr.split(\"T\")[0];\n return datePart ?? dateStr;\n}\n\n/**\n * Create a copy of a section node with source credit children removed.\n */\nfunction stripSourceCredits(node: LevelNode): LevelNode {\n return {\n ...node,\n children: node.children.filter((c) => c.type !== \"sourceCredit\"),\n };\n}\n","/**\n * OLRC U.S. Code XML downloader.\n *\n * Downloads USC title XML zip files from the Office of the Law Revision Counsel\n * and extracts them to a local directory.\n */\n\nimport { createWriteStream } from \"node:fs\";\nimport { mkdir, stat, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable } from \"node:stream\";\nimport { open as yauzlOpen } from \"yauzl\";\nimport type { ZipFile, Entry } from \"yauzl\";\n\n// ---------------------------------------------------------------------------\n// Release point configuration\n// ---------------------------------------------------------------------------\n\n/**\n * Current OLRC release point.\n *\n * Update this value when OLRC publishes a new release point.\n * The release point appears in download URLs and identifies which\n * public laws are incorporated. Format: \"{congress}-{law}[not{excluded}]\"\n *\n * Check https://uscode.house.gov/download/download.shtml for the latest.\n */\nexport const CURRENT_RELEASE_POINT = \"119-73not60\";\n\n/** OLRC base URL for release point downloads */\nconst OLRC_BASE_URL = \"https://uscode.house.gov/download/releasepoints/us/pl\";\n\n/** Valid USC title numbers (1-54) */\nexport const USC_TITLE_NUMBERS = Array.from({ length: 54 }, (_, i) => i + 1);\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Check whether a list of title numbers covers all 54 USC titles.\n *\n * Handles arbitrary ordering and duplicates.\n */\nexport function isAllTitles(titles: number[]): boolean {\n const unique = new Set(titles);\n return unique.size === 54 && USC_TITLE_NUMBERS.every((n) => unique.has(n));\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** Options for downloading USC XML files */\nexport interface DownloadOptions {\n /** Directory to save downloaded XML files */\n outputDir: string;\n /** Specific title numbers to download, or undefined for all */\n titles?: number[] | undefined;\n /** Release point override (default: CURRENT_RELEASE_POINT) */\n releasePoint?: string | undefined;\n}\n\n/** Result of a download operation */\nexport interface DownloadResult {\n /** Release point used */\n releasePoint: string;\n /** Files successfully downloaded and extracted */\n files: DownloadedFile[];\n /** Titles that failed to download */\n errors: DownloadError[];\n}\n\n/** A successfully downloaded file */\nexport interface DownloadedFile {\n /** Title number */\n titleNumber: number;\n /** Path to the extracted XML file */\n filePath: string;\n /** Size in bytes */\n size: number;\n}\n\n/** A failed download */\nexport interface DownloadError {\n /** Title number */\n titleNumber: number;\n /** Error message */\n message: string;\n}\n\n/**\n * Download USC title XML files from OLRC.\n *\n * When all 54 titles are requested, uses the bulk `uscAll` zip for a single\n * HTTP round-trip instead of 54 individual requests. Falls back to per-title\n * downloads if the bulk download fails.\n */\nexport async function downloadTitles(options: DownloadOptions): Promise<DownloadResult> {\n const releasePoint = options.releasePoint ?? CURRENT_RELEASE_POINT;\n const titles = options.titles ?? USC_TITLE_NUMBERS;\n\n await mkdir(options.outputDir, { recursive: true });\n\n // Use bulk zip when all 54 titles are requested\n if (options.titles === undefined || isAllTitles(titles)) {\n try {\n const files = await downloadAndExtractAllTitles(releasePoint, options.outputDir);\n return { releasePoint, files, errors: [] };\n } catch {\n // Fall back to per-title downloads\n }\n }\n\n const files: DownloadedFile[] = [];\n const errors: DownloadError[] = [];\n\n for (const titleNum of titles) {\n try {\n const file = await downloadAndExtractTitle(titleNum, releasePoint, options.outputDir);\n files.push(file);\n } catch (err) {\n errors.push({\n titleNumber: titleNum,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n return { releasePoint, files, errors };\n}\n\n// ---------------------------------------------------------------------------\n// URL construction\n// ---------------------------------------------------------------------------\n\n/**\n * Build the download URL for a single title's XML zip.\n *\n * Format: {base}/pl/{releasePointPath}/xml_usc{NN}@{releasePoint}.zip\n *\n * The release point path splits the release point into directory segments.\n * For \"119-73not60\", the path is \"119/73not60\".\n */\nexport function buildDownloadUrl(titleNumber: number, releasePoint: string): string {\n const paddedTitle = titleNumber.toString().padStart(2, \"0\");\n const rpPath = releasePointToPath(releasePoint);\n return `${OLRC_BASE_URL}/${rpPath}/xml_usc${paddedTitle}@${releasePoint}.zip`;\n}\n\n/**\n * Build the download URL for all titles in a single zip.\n */\nexport function buildAllTitlesUrl(releasePoint: string): string {\n const rpPath = releasePointToPath(releasePoint);\n return `${OLRC_BASE_URL}/${rpPath}/xml_uscAll@${releasePoint}.zip`;\n}\n\n/**\n * Convert a release point string to a URL path segment.\n * \"119-73not60\" → \"119/73not60\"\n * \"119-43\" → \"119/43\"\n */\nexport function releasePointToPath(releasePoint: string): string {\n // Split on the first hyphen only\n const dashIndex = releasePoint.indexOf(\"-\");\n if (dashIndex === -1) return releasePoint;\n return `${releasePoint.slice(0, dashIndex)}/${releasePoint.slice(dashIndex + 1)}`;\n}\n\n// ---------------------------------------------------------------------------\n// Download and extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Download a single title's zip and extract the XML file.\n */\nasync function downloadAndExtractTitle(\n titleNumber: number,\n releasePoint: string,\n outputDir: string,\n): Promise<DownloadedFile> {\n const url = buildDownloadUrl(titleNumber, releasePoint);\n const paddedTitle = titleNumber.toString().padStart(2, \"0\");\n const zipPath = join(outputDir, `usc${paddedTitle}.zip`);\n const xmlFileName = `usc${paddedTitle}.xml`;\n const xmlPath = join(outputDir, xmlFileName);\n\n // Download the zip file\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText} for ${url}`);\n }\n\n if (!response.body) {\n throw new Error(`No response body for ${url}`);\n }\n\n // Write zip to disk\n const fileStream = createWriteStream(zipPath);\n // ReadableStream type mismatch between DOM and Node — cast to `never` to bridge\n await pipeline(Readable.fromWeb(response.body as never), fileStream);\n\n // Extract XML from zip\n await extractXmlFromZip(zipPath, xmlFileName, xmlPath);\n\n // Clean up zip file\n await unlink(zipPath);\n\n // Get file size\n const fileStat = await stat(xmlPath);\n\n return {\n titleNumber,\n filePath: xmlPath,\n size: fileStat.size,\n };\n}\n\n/**\n * Extract a specific XML file from a zip archive.\n */\nfunction extractXmlFromZip(\n zipPath: string,\n targetFileName: string,\n outputPath: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n yauzlOpen(zipPath, { lazyEntries: true }, (err, zipFile) => {\n if (err) {\n reject(new Error(`Failed to open zip: ${err.message}`));\n return;\n }\n if (!zipFile) {\n reject(new Error(\"Failed to open zip: no zipFile returned\"));\n return;\n }\n\n let found = false;\n\n zipFile.on(\"entry\", (entry: Entry) => {\n // Look for the target XML file (might be at root or in a subdirectory)\n const fileName = entry.fileName.split(\"/\").pop() ?? entry.fileName;\n if (fileName === targetFileName || entry.fileName.endsWith(`.xml`)) {\n found = true;\n extractEntry(zipFile, entry, outputPath)\n .then(() => {\n zipFile.close();\n resolve();\n })\n .catch((extractErr) => {\n zipFile.close();\n reject(extractErr);\n });\n } else {\n zipFile.readEntry();\n }\n });\n\n zipFile.on(\"end\", () => {\n if (!found) {\n reject(new Error(`${targetFileName} not found in zip`));\n }\n });\n\n zipFile.on(\"error\", (zipErr: Error) => {\n reject(new Error(`Zip error: ${zipErr.message}`));\n });\n\n zipFile.readEntry();\n });\n });\n}\n\n/**\n * Extract a single zip entry to a file.\n */\nfunction extractEntry(zipFile: ZipFile, entry: Entry, outputPath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n zipFile.openReadStream(entry, (err, readStream) => {\n if (err) {\n reject(new Error(`Failed to read zip entry: ${err.message}`));\n return;\n }\n if (!readStream) {\n reject(new Error(\"No read stream for zip entry\"));\n return;\n }\n\n const writeStream = createWriteStream(outputPath);\n readStream.pipe(writeStream);\n\n writeStream.on(\"finish\", () => resolve());\n writeStream.on(\"error\", (writeErr) => reject(new Error(`Write error: ${writeErr.message}`)));\n readStream.on(\"error\", (readErr) => reject(new Error(`Read error: ${readErr.message}`)));\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Bulk download (all titles in one zip)\n// ---------------------------------------------------------------------------\n\n/** Regex matching USC XML filenames like usc01.xml, usc54.xml */\nconst USC_XML_RE = /^(?:.*\\/)?usc(\\d{2})\\.xml$/;\n\n/**\n * Extract all `usc{NN}.xml` files from a bulk zip archive.\n *\n * Returns an array of `{ titleNumber, filePath }` for each extracted file.\n */\nfunction extractAllXmlFromZip(\n zipPath: string,\n outputDir: string,\n): Promise<{ titleNumber: number; filePath: string }[]> {\n return new Promise((resolve, reject) => {\n yauzlOpen(zipPath, { lazyEntries: true }, (err, zipFile) => {\n if (err) {\n reject(new Error(`Failed to open zip: ${err.message}`));\n return;\n }\n if (!zipFile) {\n reject(new Error(\"Failed to open zip: no zipFile returned\"));\n return;\n }\n\n const extracted: { titleNumber: number; filePath: string }[] = [];\n let pending = 0;\n let ended = false;\n\n const maybeResolve = (): void => {\n if (ended && pending === 0) {\n resolve(extracted);\n }\n };\n\n zipFile.on(\"entry\", (entry: Entry) => {\n const match = USC_XML_RE.exec(entry.fileName);\n if (match) {\n const titleNum = parseInt(match[1] ?? \"0\", 10);\n const outPath = join(outputDir, `usc${match[1] ?? \"00\"}.xml`);\n pending++;\n\n extractEntry(zipFile, entry, outPath)\n .then(() => {\n extracted.push({ titleNumber: titleNum, filePath: outPath });\n pending--;\n // Continue reading entries after extraction completes\n zipFile.readEntry();\n maybeResolve();\n })\n .catch((extractErr) => {\n zipFile.close();\n reject(extractErr);\n });\n } else {\n zipFile.readEntry();\n }\n });\n\n zipFile.on(\"end\", () => {\n ended = true;\n maybeResolve();\n });\n\n zipFile.on(\"error\", (zipErr: Error) => {\n reject(new Error(`Zip error: ${zipErr.message}`));\n });\n\n zipFile.readEntry();\n });\n });\n}\n\n/**\n * Download the bulk all-titles zip and extract every `usc{NN}.xml` file.\n */\nasync function downloadAndExtractAllTitles(\n releasePoint: string,\n outputDir: string,\n): Promise<DownloadedFile[]> {\n const url = buildAllTitlesUrl(releasePoint);\n const zipPath = join(outputDir, \"uscAll.zip\");\n\n // Download the zip file\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText} for ${url}`);\n }\n\n if (!response.body) {\n throw new Error(`No response body for ${url}`);\n }\n\n // Write zip to disk\n const fileStream = createWriteStream(zipPath);\n await pipeline(Readable.fromWeb(response.body as never), fileStream);\n\n // Extract all XML files from zip\n const extracted = await extractAllXmlFromZip(zipPath, outputDir);\n\n // Clean up zip file\n await unlink(zipPath);\n\n // Stat each extracted file and build results\n const files: DownloadedFile[] = [];\n for (const { titleNumber, filePath } of extracted) {\n const fileStat = await stat(filePath);\n files.push({ titleNumber, filePath, size: fileStat.size });\n }\n\n // Sort by title number for consistent ordering\n files.sort((a, b) => a.titleNumber - b.titleNumber);\n\n return files;\n}\n"],"mappings":"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","names":["mkdir","join","files"]}
1
+ {"version":3,"sources":["../src/converter.ts","../src/downloader.ts"],"sourcesContent":["/**\n * USC Converter — orchestrates the full conversion pipeline for a single USC XML file.\n *\n * Creates a ReadStream → SAX Parser → AST Builder (emit at section) →\n * Markdown Renderer + Frontmatter → File Writer.\n */\n\nimport { createReadStream } from \"node:fs\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { basename } from \"node:path\";\nimport {\n XMLParser,\n ASTBuilder,\n renderDocument,\n renderSection,\n renderNode,\n generateFrontmatter,\n createLinkResolver,\n FORMAT_VERSION,\n GENERATOR,\n BIG_LEVELS,\n} from \"@lexbuild/core\";\nimport type {\n LevelNode,\n ASTNode,\n EmitContext,\n FrontmatterData,\n RenderOptions,\n NotesFilter,\n AncestorInfo,\n LinkResolver,\n} from \"@lexbuild/core\";\n\n/** Options for converting a USC XML file */\nexport interface ConvertOptions {\n /** Path to the input XML file */\n input: string;\n /** Output directory root */\n output: string;\n /** Output granularity: \"section\" (one file per section), \"chapter\" (sections inline), or \"title\" (entire title) */\n granularity: \"section\" | \"chapter\" | \"title\";\n /** How to render cross-references */\n linkStyle: \"relative\" | \"canonical\" | \"plaintext\";\n /** Include source credits in output */\n includeSourceCredits: boolean;\n /** Include notes in output. True = all notes (default). False = no notes. */\n includeNotes: boolean;\n /** Include editorial notes only (when includeNotes is false) */\n includeEditorialNotes: boolean;\n /** Include statutory notes only (when includeNotes is false) */\n includeStatutoryNotes: boolean;\n /** Include amendment history notes only (when includeNotes is false) */\n includeAmendments: boolean;\n /** Dry-run mode: parse and report structure without writing files */\n dryRun: boolean;\n}\n\n/** Result of a conversion */\nexport interface ConvertResult {\n /** Number of sections written (or that would be written in dry-run) */\n sectionsWritten: number;\n /** Output paths of all written files (empty in dry-run) */\n files: string[];\n /** Title number extracted from metadata */\n titleNumber: string;\n /** Title name extracted from metadata */\n titleName: string;\n /** Whether this was a dry run */\n dryRun: boolean;\n /** Chapter count */\n chapterCount: number;\n /** Estimated total tokens */\n totalTokenEstimate: number;\n /** Peak resident set size in bytes during conversion */\n peakMemoryBytes: number;\n}\n\n/** Default convert options */\nconst DEFAULTS: Omit<ConvertOptions, \"input\" | \"output\"> = {\n granularity: \"section\",\n linkStyle: \"plaintext\",\n includeSourceCredits: true,\n includeNotes: true,\n includeEditorialNotes: false,\n includeStatutoryNotes: false,\n includeAmendments: false,\n dryRun: false,\n};\n\n/** Metadata collected for a written section (used to build _meta.json) */\ninterface SectionMeta {\n identifier: string;\n number: string;\n name: string;\n /** Filename only (e.g., \"section-3598.md\" or \"section-3598-2.md\" for duplicates) */\n fileName: string;\n /** File path relative to the title directory (e.g., \"chapter-01/section-1.md\") */\n relativeFile: string;\n /** Content length in characters (for token estimation) */\n contentLength: number;\n hasNotes: boolean;\n status: string;\n /** Chapter identifier this section belongs to */\n chapterIdentifier: string;\n chapterNumber: string;\n chapterName: string;\n}\n\n/** A collected section ready to be written */\ninterface CollectedSection {\n node: LevelNode;\n context: EmitContext;\n}\n\n/**\n * Convert a single USC XML file to section-level Markdown files.\n */\nexport async function convertTitle(options: ConvertOptions): Promise<ConvertResult> {\n const opts = { ...DEFAULTS, ...options };\n const files: string[] = [];\n let peakMemory = process.memoryUsage.rss();\n let titleLevelTokenEstimate: number | undefined;\n\n // Collect emitted nodes during parsing (synchronous), write after parsing completes\n const collected: CollectedSection[] = [];\n\n // Set up the AST builder — emit level depends on granularity\n const emitAt =\n opts.granularity === \"title\"\n ? (\"title\" as const)\n : opts.granularity === \"chapter\"\n ? (\"chapter\" as const)\n : (\"section\" as const);\n const builder = new ASTBuilder({\n emitAt,\n onEmit: (node, context) => {\n collected.push({ node, context });\n },\n });\n\n // Set up the XML parser\n const parser = new XMLParser();\n parser.on(\"openElement\", (name, attrs) => builder.onOpenElement(name, attrs));\n parser.on(\"closeElement\", (name) => builder.onCloseElement(name));\n parser.on(\"text\", (text) => builder.onText(text));\n\n // Parse the XML file\n const stream = createReadStream(opts.input, \"utf-8\");\n await parser.parseStream(stream);\n peakMemory = Math.max(peakMemory, process.memoryUsage.rss());\n\n const sectionMetas: SectionMeta[] = [];\n const meta = builder.getDocumentMeta();\n\n if (opts.dryRun) {\n // Dry-run: collect metadata without writing files\n for (const { node, context } of collected) {\n if (opts.granularity === \"title\") {\n // Walk title tree → chapters → sections\n collectSectionMetasFromTree(node, context, sectionMetas);\n } else if (opts.granularity === \"chapter\") {\n // Extract section metadata from chapter children\n for (const child of node.children) {\n if (child.type === \"level\" && child.levelType === \"section\") {\n sectionMetas.push(buildSectionMetaDryRun(child, node, context));\n }\n }\n } else {\n if (node.numValue) {\n sectionMetas.push(buildSectionMetaDryRun(node, null, context));\n }\n }\n }\n } else if (opts.granularity === \"title\") {\n // Title-level: each emitted node is an entire title\n let titleTokenEstimate = 0;\n for (const { node, context } of collected) {\n const result = await writeWholeTitle(node, context, opts);\n files.push(result.filePath);\n titleTokenEstimate += result.totalTokenEstimate;\n for (const m of result.sectionMetas) {\n sectionMetas.push(m);\n }\n }\n // Store the accurate title-level estimate for use in ConvertResult\n titleLevelTokenEstimate = titleTokenEstimate;\n } else if (opts.granularity === \"chapter\") {\n // Chapter-level: each emitted node is a chapter containing sections\n for (const { node, context } of collected) {\n const result = await writeChapter(node, context, opts);\n if (result) {\n files.push(result.filePath);\n for (const m of result.sectionMetas) {\n sectionMetas.push(m);\n }\n }\n }\n } else {\n // Section-level with relative links: need two-pass for link resolver\n // Track duplicate section numbers per chapter to disambiguate filenames\n const sectionCounts = new Map<string, number>();\n const suffixes: (string | undefined)[] = [];\n for (const { node, context } of collected) {\n const sectionNum = node.numValue;\n if (!sectionNum) {\n suffixes.push(undefined);\n continue;\n }\n const chapterDir = buildChapterDir(context) ?? \"__root__\";\n const key = `${chapterDir}/${sectionNum}`;\n const count = (sectionCounts.get(key) ?? 0) + 1;\n sectionCounts.set(key, count);\n suffixes.push(count > 1 ? `-${count}` : undefined);\n }\n\n const linkResolver = createLinkResolver();\n for (const [i, { node, context }] of collected.entries()) {\n const sectionNum = node.numValue;\n if (sectionNum && node.identifier) {\n const filePath = buildOutputPath(context, sectionNum, opts.output, suffixes[i]);\n // For duplicates, register with the XML element @id to disambiguate\n const regId = suffixes[i] ? `${node.identifier}#${suffixes[i]}` : node.identifier;\n linkResolver.register(regId, filePath);\n // Always register the first occurrence under the canonical identifier\n if (!suffixes[i]) {\n linkResolver.register(node.identifier, filePath);\n }\n }\n }\n\n for (const [i, { node, context }] of collected.entries()) {\n const result = await writeSection(node, context, opts, linkResolver, suffixes[i]);\n if (result) {\n files.push(result.filePath);\n sectionMetas.push(result.meta);\n }\n }\n }\n\n // Extract the title heading from the first collected node\n const firstCollected = collected[0];\n const titleHeading = firstCollected\n ? opts.granularity === \"title\"\n ? firstCollected.node.heading?.trim()\n : findAncestor(firstCollected.context.ancestors, \"title\")?.heading?.trim()\n : undefined;\n\n // Generate _meta.json and README.md files (skip in dry-run)\n if (!opts.dryRun) {\n await writeMetaFiles(sectionMetas, meta, opts, titleHeading);\n }\n\n // Final memory sample\n peakMemory = Math.max(peakMemory, process.memoryUsage.rss());\n\n // Compute stats\n const chapterIds = new Set(sectionMetas.map((s) => s.chapterIdentifier).filter(Boolean));\n // For title granularity, use the accurate estimate from the full rendered body\n // (includes structural headings); for other modes, sum per-section content lengths\n const totalTokens =\n titleLevelTokenEstimate ??\n sectionMetas.reduce((sum, s) => sum + Math.ceil(s.contentLength / 4), 0);\n\n return {\n sectionsWritten:\n opts.dryRun || opts.granularity === \"title\" || opts.granularity === \"chapter\"\n ? sectionMetas.length\n : files.length,\n files,\n titleNumber: meta.docNumber ?? \"unknown\",\n titleName: titleHeading ?? meta.dcTitle ?? \"Unknown Title\",\n dryRun: opts.dryRun,\n chapterCount: chapterIds.size,\n totalTokenEstimate: totalTokens,\n peakMemoryBytes: peakMemory,\n };\n}\n\n/** Result of writing a single section */\ninterface WriteSectionResult {\n filePath: string;\n meta: SectionMeta;\n}\n\n/**\n * Write a single section to disk.\n * Returns the file path and metadata, or null if the section was skipped.\n */\nasync function writeSection(\n node: LevelNode,\n context: EmitContext,\n options: ConvertOptions,\n linkResolver?: LinkResolver | undefined,\n /** Disambiguation suffix for duplicate section numbers (e.g., \"-2\") */\n dupSuffix?: string | undefined,\n): Promise<WriteSectionResult | null> {\n const sectionNum = node.numValue;\n if (!sectionNum) return null;\n\n // Build the output file path (with optional duplicate suffix)\n const filePath = buildOutputPath(context, sectionNum, options.output, dupSuffix);\n\n // Build frontmatter data\n const frontmatter = buildFrontmatter(node, context);\n\n // Build notes filter\n const notesFilter = buildNotesFilter(options);\n\n // Build render options with link resolver for relative links\n const renderOpts: RenderOptions = {\n headingOffset: 0,\n linkStyle: options.linkStyle,\n resolveLink: linkResolver\n ? (identifier: string) => linkResolver.resolve(identifier, filePath)\n : undefined,\n notesFilter,\n };\n\n // Optionally strip source credits\n const sectionNode = options.includeSourceCredits ? node : stripSourceCredits(node);\n\n // Render the document\n const markdown = renderDocument(sectionNode, frontmatter, renderOpts);\n\n // Ensure the directory exists and write the file\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, markdown, \"utf-8\");\n\n // Collect metadata\n const titleNum = findAncestor(context.ancestors, \"title\")?.numValue ?? \"0\";\n const chapterAncestor = findAncestor(context.ancestors, \"chapter\");\n const chapterDir = chapterAncestor?.numValue ? `chapter-${padTwo(chapterAncestor.numValue)}` : \"\";\n const sectionFileName = `section-${sectionNum}${dupSuffix ?? \"\"}.md`;\n const relativeFile = chapterDir ? `${chapterDir}/${sectionFileName}` : sectionFileName;\n\n const hasNotes = node.children.some((c) => c.type === \"notesContainer\" || c.type === \"note\");\n\n const sectionMeta: SectionMeta = {\n identifier: node.identifier ?? `/us/usc/t${titleNum}/s${sectionNum}`,\n number: sectionNum,\n name: node.heading?.trim() ?? \"\",\n fileName: sectionFileName,\n relativeFile,\n contentLength: markdown.length,\n hasNotes,\n status: node.status ?? \"current\",\n chapterIdentifier: chapterAncestor?.identifier ?? \"\",\n chapterNumber: chapterAncestor?.numValue ?? \"0\",\n chapterName: chapterAncestor?.heading?.trim() ?? \"\",\n };\n\n return { filePath, meta: sectionMeta };\n}\n\n/**\n * Generate _meta.json files at title and chapter levels.\n */\nasync function writeMetaFiles(\n sectionMetas: SectionMeta[],\n docMeta: {\n dcTitle?: string | undefined;\n docNumber?: string | undefined;\n positivelaw?: boolean | undefined;\n docPublicationName?: string | undefined;\n created?: string | undefined;\n identifier?: string | undefined;\n },\n options: ConvertOptions,\n titleHeading?: string | undefined,\n): Promise<void> {\n if (sectionMetas.length === 0) return;\n if (options.granularity === \"title\") return;\n\n const docNum = docMeta.docNumber ?? \"0\";\n const titleDirName = buildTitleDirFromDocNumber(docNum);\n const titleDir = join(options.output, \"usc\", titleDirName);\n const currency = parseCurrency(docMeta.docPublicationName ?? \"\");\n\n // Group sections by chapter\n const chapterMap = new Map<string, SectionMeta[]>();\n for (const sm of sectionMetas) {\n const key = sm.chapterIdentifier || \"__no_chapter__\";\n let arr = chapterMap.get(key);\n if (!arr) {\n arr = [];\n chapterMap.set(key, arr);\n }\n arr.push(sm);\n }\n\n // Write chapter-level _meta.json files\n const chapterEntries: Array<{\n identifier: string;\n number: number;\n name: string;\n directory: string;\n sections: Array<{\n identifier: string;\n number: string;\n name: string;\n file: string;\n token_estimate: number;\n has_notes: boolean;\n status: string;\n }>;\n }> = [];\n\n for (const [chapterId, chapterSections] of chapterMap) {\n if (chapterId === \"__no_chapter__\") continue;\n\n const first = chapterSections[0];\n if (!first) continue;\n\n const chapterDir = `chapter-${padTwo(first.chapterNumber)}`;\n\n const sections = chapterSections.map((sm) => ({\n identifier: sm.identifier,\n number: sm.number,\n name: sm.name,\n file: sm.fileName,\n token_estimate: Math.ceil(sm.contentLength / 4),\n has_notes: sm.hasNotes,\n status: sm.status,\n }));\n\n const chapterMeta = {\n format_version: FORMAT_VERSION,\n identifier: chapterId,\n chapter_number: parseIntSafe(first.chapterNumber),\n chapter_name: first.chapterName,\n title_number: parseIntSafe(docNum),\n section_count: sections.length,\n sections,\n };\n\n const chapterMetaPath = join(titleDir, chapterDir, \"_meta.json\");\n await mkdir(dirname(chapterMetaPath), { recursive: true });\n await writeFile(chapterMetaPath, JSON.stringify(chapterMeta, null, 2) + \"\\n\", \"utf-8\");\n\n chapterEntries.push({\n identifier: chapterId,\n number: parseIntSafe(first.chapterNumber),\n name: first.chapterName,\n directory: chapterDir,\n sections,\n });\n }\n\n // Write title-level _meta.json\n const totalTokens = sectionMetas.reduce((sum, sm) => sum + Math.ceil(sm.contentLength / 4), 0);\n\n const titleMeta = {\n format_version: FORMAT_VERSION,\n generator: GENERATOR,\n generated_at: new Date().toISOString(),\n identifier: docMeta.identifier ?? `/us/usc/t${docNum}`,\n title_number: parseIntSafe(docNum),\n title_name: titleHeading ?? docMeta.dcTitle ?? \"\",\n positive_law: docMeta.positivelaw ?? false,\n currency,\n source_xml: basename(options.input),\n granularity: options.granularity,\n stats: {\n chapter_count: chapterEntries.length,\n section_count: sectionMetas.length,\n total_files: sectionMetas.length,\n total_tokens_estimate: totalTokens,\n },\n chapters: chapterEntries,\n };\n\n const titleMetaPath = join(titleDir, \"_meta.json\");\n await mkdir(dirname(titleMetaPath), { recursive: true });\n await writeFile(titleMetaPath, JSON.stringify(titleMeta, null, 2) + \"\\n\", \"utf-8\");\n\n // Write title-level README.md\n const readmePath = join(titleDir, \"README.md\");\n const readme = generateTitleReadme(titleMeta);\n await writeFile(readmePath, readme, \"utf-8\");\n}\n\n/**\n * Generate a human-readable README.md for a title output directory.\n */\nfunction generateTitleReadme(meta: {\n title_number: number;\n title_name: string;\n positive_law: boolean;\n currency: string;\n granularity: string;\n stats: {\n chapter_count: number;\n section_count: number;\n total_tokens_estimate: number;\n };\n chapters: Array<{\n number: number;\n name: string;\n directory: string;\n sections: Array<{\n number: string;\n name: string;\n file: string;\n status: string;\n }>;\n }>;\n}): string {\n const lines: string[] = [];\n\n lines.push(`# Title ${meta.title_number} — ${meta.title_name}`);\n lines.push(\"\");\n lines.push(`| | |`);\n lines.push(`| --- | --- |`);\n lines.push(`| **Positive Law** | ${meta.positive_law ? \"Yes\" : \"No\"} |`);\n lines.push(`| **Currency** | ${meta.currency || \"unknown\"} |`);\n lines.push(`| **Chapters** | ${meta.stats.chapter_count} |`);\n lines.push(`| **Sections** | ${meta.stats.section_count.toLocaleString()} |`);\n lines.push(`| **Est. Tokens** | ${meta.stats.total_tokens_estimate.toLocaleString()} |`);\n lines.push(`| **Granularity** | ${meta.granularity} |`);\n lines.push(\"\");\n\n // Chapter listing\n lines.push(\"## Chapters\");\n lines.push(\"\");\n\n for (const ch of meta.chapters) {\n const sectionCount = ch.sections.length;\n lines.push(`### Chapter ${ch.number} — ${ch.name}`);\n lines.push(\"\");\n lines.push(\n `${sectionCount} section${sectionCount !== 1 ? \"s\" : \"\"} · [${ch.directory}/](${ch.directory}/)`,\n );\n lines.push(\"\");\n }\n\n // Footer\n lines.push(\"---\");\n lines.push(\"\");\n lines.push(`Generated by [lexbuild](https://github.com/chris-c-thomas/lexbuild)`);\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/** Result of writing a chapter file */\ninterface WriteChapterResult {\n filePath: string;\n sectionMetas: SectionMeta[];\n}\n\n/**\n * Write a chapter-level file (all sections inlined).\n * The emitted node is a chapter LevelNode whose children include section LevelNodes.\n */\nasync function writeChapter(\n chapterNode: LevelNode,\n context: EmitContext,\n options: ConvertOptions,\n): Promise<WriteChapterResult | null> {\n const chapterNum = chapterNode.numValue;\n if (!chapterNum) return null;\n\n const titleNum = findAncestor(context.ancestors, \"title\")?.numValue ?? \"0\";\n const titleDir = `title-${padTwo(titleNum)}`;\n const chapterFile = `chapter-${padTwo(chapterNum)}.md`;\n const filePath = join(options.output, \"usc\", titleDir, chapterFile);\n\n // Build chapter-level frontmatter\n const titleAncestor = findAncestor(context.ancestors, \"title\");\n const meta = context.documentMeta;\n const chapterName = chapterNode.heading?.trim() ?? \"\";\n const titleName = titleAncestor?.heading?.trim() ?? meta.dcTitle ?? \"\";\n const currency = parseCurrency(meta.docPublicationName ?? \"\");\n const lastUpdated = parseDate(meta.created ?? \"\");\n\n const fmData: FrontmatterData = {\n identifier: chapterNode.identifier ?? `/us/usc/t${titleNum}/ch${chapterNum}`,\n title: `${titleNum} USC Chapter ${chapterNum} - ${chapterName}`,\n title_number: parseIntSafe(titleNum),\n title_name: titleName,\n section_number: chapterNum,\n section_name: chapterName,\n chapter_number: parseIntSafe(chapterNum),\n chapter_name: chapterName,\n positive_law: meta.positivelaw ?? false,\n currency,\n last_updated: lastUpdated,\n };\n\n const notesFilter = buildNotesFilter(options);\n const renderOpts: RenderOptions = {\n headingOffset: 0,\n linkStyle: options.linkStyle,\n notesFilter,\n };\n\n // Build the chapter Markdown: heading + each section rendered with H2\n const parts: string[] = [];\n parts.push(generateFrontmatter(fmData));\n parts.push(\"\");\n parts.push(`# Chapter ${chapterNum} — ${chapterName}`);\n\n // Collect section metas and render each section\n const sectionMetas: SectionMeta[] = [];\n\n for (const child of chapterNode.children) {\n if (child.type === \"level\" && child.levelType === \"section\") {\n const sectionOpts: RenderOptions = { ...renderOpts, headingOffset: 1 };\n const sectionNode = options.includeSourceCredits ? child : stripSourceCredits(child);\n const sectionMd = renderSection(sectionNode, sectionOpts);\n parts.push(\"\");\n parts.push(sectionMd);\n\n // Collect section metadata\n const sectionNum = child.numValue ?? \"0\";\n const hasNotes = child.children.some((c) => c.type === \"notesContainer\" || c.type === \"note\");\n sectionMetas.push({\n identifier: child.identifier ?? `/us/usc/t${titleNum}/s${sectionNum}`,\n number: sectionNum,\n name: child.heading?.trim() ?? \"\",\n fileName: `section-${sectionNum}.md`,\n relativeFile: chapterFile,\n contentLength: sectionMd.length,\n hasNotes,\n status: child.status ?? \"current\",\n chapterIdentifier: chapterNode.identifier ?? \"\",\n chapterNumber: chapterNum,\n chapterName,\n });\n }\n }\n\n const markdown = parts.join(\"\\n\") + \"\\n\";\n\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, markdown, \"utf-8\");\n\n return { filePath, sectionMetas };\n}\n\n/** Result of writing a title-level file */\ninterface WriteTitleResult {\n filePath: string;\n sectionMetas: SectionMeta[];\n /** Token estimate based on full rendered body (including structural headings) */\n totalTokenEstimate: number;\n}\n\n/**\n * Write a title-level file (entire title as a single Markdown document).\n * The emitted node is the title LevelNode with all children.\n */\nasync function writeWholeTitle(\n titleNode: LevelNode,\n context: EmitContext,\n options: ConvertOptions,\n): Promise<WriteTitleResult> {\n const meta = context.documentMeta;\n const docNum = meta.docNumber ?? titleNode.numValue ?? \"0\";\n const titleNum = docNum.replace(/a$/i, \"\");\n const titleName = titleNode.heading?.trim() ?? meta.dcTitle ?? \"\";\n const currency = parseCurrency(meta.docPublicationName ?? \"\");\n const lastUpdated = parseDate(meta.created ?? \"\");\n\n const notesFilter = buildNotesFilter(options);\n const renderOpts: RenderOptions = {\n headingOffset: 0,\n linkStyle: options.linkStyle,\n notesFilter,\n };\n\n // Render title children recursively, collecting section metas\n const sectionMetas: SectionMeta[] = [];\n const bodyParts = renderTitleChildren(titleNode, 2, options, renderOpts, sectionMetas, titleNum);\n\n // Build the title Markdown body first so we can measure its total length\n const bodyMarkdownParts: string[] = [];\n const numDisplay = titleNode.num ?? \"\";\n const headingText = titleNode.heading ? ` ${titleNode.heading}` : \"\";\n bodyMarkdownParts.push(`# ${numDisplay}${headingText}`);\n bodyMarkdownParts.push(...bodyParts);\n const bodyMarkdown = bodyMarkdownParts.join(\"\\n\");\n\n // Build enriched frontmatter for title-level output\n // Use full body length (not just section content) for accurate token estimate\n const fmData: FrontmatterData = {\n identifier: titleNode.identifier ?? meta.identifier ?? `/us/usc/t${titleNum}`,\n title: `Title ${titleNum} — ${titleName}`,\n title_number: parseIntSafe(titleNum),\n title_name: titleName,\n positive_law: meta.positivelaw ?? false,\n currency,\n last_updated: lastUpdated,\n chapter_count: new Set(sectionMetas.map((s) => s.chapterIdentifier).filter(Boolean)).size,\n section_count: sectionMetas.length,\n total_token_estimate: Math.ceil(bodyMarkdown.length / 4),\n };\n\n // Assemble final Markdown: frontmatter + body\n const markdown = generateFrontmatter(fmData) + \"\\n\\n\" + bodyMarkdown + \"\\n\";\n\n // Output path: output/usc/title-NN.md (or title-NN-appendix.md for appendix titles)\n const titleFile = `${buildTitleDirFromDocNumber(docNum)}.md`;\n const filePath = join(options.output, \"usc\", titleFile);\n\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, markdown, \"utf-8\");\n\n const totalTokenEstimate = Math.ceil(bodyMarkdown.length / 4);\n return { filePath, sectionMetas, totalTokenEstimate };\n}\n\n/**\n * Recursively render children of a big-level node for title-level output.\n * Returns an array of Markdown parts (each preceded by blank line).\n * Collects SectionMeta for each section encountered.\n */\nfunction renderTitleChildren(\n node: LevelNode,\n headingLevel: number,\n options: ConvertOptions,\n renderOpts: RenderOptions,\n sectionMetas: SectionMeta[],\n titleNum: string,\n currentChapter?: LevelNode | undefined,\n): string[] {\n const parts: string[] = [];\n\n for (const child of node.children) {\n if (child.type === \"level\" && child.levelType === \"section\") {\n // Render section at current heading level\n // renderSection adds 1 to headingOffset, so subtract 1 to land at headingLevel\n const sectionOpts: RenderOptions = {\n ...renderOpts,\n headingOffset: Math.min(headingLevel - 1, 5),\n };\n const sectionNode = options.includeSourceCredits ? child : stripSourceCredits(child);\n const sectionMd = renderSection(sectionNode, sectionOpts);\n parts.push(\"\");\n parts.push(sectionMd);\n\n // Collect section metadata\n const sectionNum = child.numValue ?? \"0\";\n const hasNotes = child.children.some((c) => c.type === \"notesContainer\" || c.type === \"note\");\n sectionMetas.push({\n identifier: child.identifier ?? `/us/usc/t${titleNum}/s${sectionNum}`,\n number: sectionNum,\n name: child.heading?.trim() ?? \"\",\n fileName: `section-${sectionNum}.md`,\n relativeFile: `section-${sectionNum}.md`,\n contentLength: sectionMd.length,\n hasNotes,\n status: child.status ?? \"current\",\n chapterIdentifier: currentChapter?.identifier ?? \"\",\n chapterNumber: currentChapter?.numValue ?? \"0\",\n chapterName: currentChapter?.heading?.trim() ?? \"\",\n });\n } else if (child.type === \"level\" && BIG_LEVELS.has(child.levelType)) {\n // Big-level child: emit heading, then recurse\n // Structural headings cap at H5; H6 is reserved for sections.\n // Beyond H5, fall back to bold text so sections remain visually distinct.\n const numDisplay = child.num ?? \"\";\n const heading = child.heading ? ` ${child.heading}` : \"\";\n parts.push(\"\");\n if (headingLevel <= 5) {\n const prefix = \"#\".repeat(headingLevel);\n parts.push(`${prefix} ${numDisplay}${heading}`);\n } else {\n parts.push(`**${numDisplay}${heading}**`);\n }\n\n // Track the chapter ancestor for section metadata\n const nextChapter = child.levelType === \"chapter\" ? child : currentChapter;\n\n const childParts = renderTitleChildren(\n child,\n headingLevel + 1,\n options,\n renderOpts,\n sectionMetas,\n titleNum,\n nextChapter,\n );\n parts.push(...childParts);\n } else {\n // Content, notes, toc, etc. — render inline\n const rendered = renderNode(child as ASTNode, renderOpts);\n if (rendered) {\n parts.push(\"\");\n parts.push(rendered);\n }\n }\n }\n\n return parts;\n}\n\n/**\n * Recursively walk a title-level AST tree and collect SectionMeta for dry-run.\n */\nfunction collectSectionMetasFromTree(\n node: LevelNode,\n context: EmitContext,\n sectionMetas: SectionMeta[],\n currentChapter?: LevelNode | undefined,\n): void {\n for (const child of node.children) {\n if (child.type === \"level\" && child.levelType === \"section\") {\n sectionMetas.push(buildSectionMetaDryRun(child, currentChapter ?? null, context));\n } else if (child.type === \"level\" && BIG_LEVELS.has(child.levelType)) {\n const nextChapter = child.levelType === \"chapter\" ? child : currentChapter;\n collectSectionMetasFromTree(child, context, sectionMetas, nextChapter);\n }\n }\n}\n\nfunction buildOutputPath(\n context: EmitContext,\n sectionNum: string,\n outputRoot: string,\n /** Disambiguation suffix for duplicate section numbers (e.g., \"-2\") */\n dupSuffix?: string | undefined,\n): string {\n const titleDir = buildTitleDir(context);\n const chapterDir = buildChapterDir(context);\n const sectionFile = `section-${sectionNum}${dupSuffix ?? \"\"}.md`;\n\n if (chapterDir) {\n return join(outputRoot, \"usc\", titleDir, chapterDir, sectionFile);\n }\n\n return join(outputRoot, \"usc\", titleDir, sectionFile);\n}\n\n/**\n * Build the title directory name from context.\n * Handles appendix titles: docNumber \"5a\" → \"title-05-appendix\"\n */\nfunction buildTitleDir(context: EmitContext): string {\n // Check for appendix via docNumber (e.g., \"5a\", \"11a\")\n const docNum = context.documentMeta.docNumber ?? \"\";\n const appendixMatch = /^(\\d+)a$/i.exec(docNum);\n if (appendixMatch?.[1]) {\n return `title-${padTwo(appendixMatch[1])}-appendix`;\n }\n\n // Check for appendix ancestor\n const appendixAncestor = findAncestor(context.ancestors, \"appendix\");\n if (appendixAncestor) {\n const num = appendixAncestor.numValue ?? docNum;\n const numericPart = /^(\\d+)/.exec(num);\n if (numericPart?.[1]) {\n return `title-${padTwo(numericPart[1])}-appendix`;\n }\n }\n\n // Normal title\n const titleNum = findAncestor(context.ancestors, \"title\")?.numValue ?? \"00\";\n return `title-${padTwo(titleNum)}`;\n}\n\n/**\n * Build the chapter directory name from context.\n * Handles chapter equivalents: compiledAct, reorganizationPlan.\n */\nfunction buildChapterDir(context: EmitContext): string | undefined {\n // Standard chapter\n const chapterNum = findAncestor(context.ancestors, \"chapter\")?.numValue;\n if (chapterNum) return `chapter-${padTwo(chapterNum)}`;\n\n // Compiled act as chapter equivalent\n const compiledAct = findAncestor(context.ancestors, \"compiledAct\");\n if (compiledAct) {\n const heading = compiledAct.heading?.trim() ?? \"\";\n // Use a slug of the heading as directory name\n const slug = heading\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 50);\n return slug || \"compiled-act\";\n }\n\n // Reorganization plan as chapter equivalent\n const reorgPlan = findAncestor(context.ancestors, \"reorganizationPlan\");\n if (reorgPlan) {\n const heading = reorgPlan.heading?.trim() ?? \"\";\n const slug = heading\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, 50);\n return slug || \"reorganization-plan\";\n }\n\n // Reorganization plans container\n const reorgPlans = findAncestor(context.ancestors, \"reorganizationPlans\");\n if (reorgPlans) {\n return \"reorganization-plans\";\n }\n\n return undefined;\n}\n\n/**\n * Build FrontmatterData from the emitted section node and context.\n */\nfunction buildFrontmatter(node: LevelNode, context: EmitContext): FrontmatterData {\n const meta = context.documentMeta;\n const titleAncestor =\n findAncestor(context.ancestors, \"title\") ?? findAncestor(context.ancestors, \"appendix\");\n const chapterAncestor =\n findAncestor(context.ancestors, \"chapter\") ??\n findAncestor(context.ancestors, \"compiledAct\") ??\n findAncestor(context.ancestors, \"reorganizationPlan\");\n const subchapterAncestor = findAncestor(context.ancestors, \"subchapter\");\n const partAncestor = findAncestor(context.ancestors, \"part\");\n\n const docNum = meta.docNumber ?? titleAncestor?.numValue ?? \"0\";\n const titleNum = parseIntSafe(docNum.replace(/a$/i, \"\"));\n const sectionNum = node.numValue ?? \"0\";\n const sectionName = node.heading?.trim() ?? \"\";\n const titleName = titleAncestor?.heading?.trim() ?? meta.dcTitle ?? \"\";\n\n // Build the human-readable title: \"1 USC § 1 - Section Name\"\n const displayTitle = `${titleNum} USC § ${sectionNum} - ${sectionName}`;\n\n // Extract source credit text from the section's children\n const sourceCredit = extractSourceCreditText(node);\n\n // Parse currency from docPublicationName (e.g., \"Online@119-73not60\" → \"119-73\")\n const currency = parseCurrency(meta.docPublicationName ?? \"\");\n\n // Parse last_updated from created timestamp\n const lastUpdated = parseDate(meta.created ?? \"\");\n\n const fm: FrontmatterData = {\n identifier: node.identifier ?? `/us/usc/t${titleNum}/s${sectionNum}`,\n title: displayTitle,\n title_number: titleNum,\n title_name: titleName,\n section_number: sectionNum,\n section_name: sectionName,\n positive_law: meta.positivelaw ?? false,\n currency,\n last_updated: lastUpdated,\n };\n\n if (chapterAncestor?.numValue) {\n fm.chapter_number = parseIntSafe(chapterAncestor.numValue);\n }\n if (chapterAncestor?.heading) {\n fm.chapter_name = chapterAncestor.heading.trim();\n }\n if (subchapterAncestor?.numValue) {\n fm.subchapter_number = subchapterAncestor.numValue;\n }\n if (subchapterAncestor?.heading) {\n fm.subchapter_name = subchapterAncestor.heading.trim();\n }\n if (partAncestor?.numValue) {\n fm.part_number = partAncestor.numValue;\n }\n if (partAncestor?.heading) {\n fm.part_name = partAncestor.heading.trim();\n }\n if (sourceCredit) {\n fm.source_credit = sourceCredit;\n }\n if (node.status) {\n fm.status = node.status;\n }\n\n return fm;\n}\n\n// ---------------------------------------------------------------------------\n// Utility functions\n// ---------------------------------------------------------------------------\n\n/**\n * Build SectionMeta from AST node without rendering (for dry-run mode).\n */\nfunction buildSectionMetaDryRun(\n sectionNode: LevelNode,\n chapterNode: LevelNode | null,\n context: EmitContext,\n): SectionMeta {\n const titleNum = findAncestor(context.ancestors, \"title\")?.numValue ?? \"0\";\n const chapterAncestor = chapterNode\n ? {\n numValue: chapterNode.numValue,\n heading: chapterNode.heading,\n identifier: chapterNode.identifier,\n }\n : findAncestor(context.ancestors, \"chapter\");\n const sectionNum = sectionNode.numValue ?? \"0\";\n const chapterNum = chapterAncestor?.numValue ?? \"0\";\n const chapterDir = chapterNum !== \"0\" ? `chapter-${padTwo(chapterNum)}` : \"\";\n\n const hasNotes = sectionNode.children.some(\n (c) => c.type === \"notesContainer\" || c.type === \"note\",\n );\n\n // Rough content length estimate from AST text nodes\n let contentLength = 0;\n const walk = (node: {\n children?: readonly { text?: string | undefined; children?: readonly unknown[] }[] | undefined;\n text?: string | undefined;\n }): void => {\n if (node.text) contentLength += node.text.length;\n if (node.children) {\n for (const child of node.children) {\n walk(child as typeof node);\n }\n }\n };\n walk(sectionNode as unknown as Parameters<typeof walk>[0]);\n\n const sectionFileName = `section-${sectionNum}.md`;\n return {\n identifier: sectionNode.identifier ?? `/us/usc/t${titleNum}/s${sectionNum}`,\n number: sectionNum,\n name: sectionNode.heading?.trim() ?? \"\",\n fileName: sectionFileName,\n relativeFile: chapterDir ? `${chapterDir}/${sectionFileName}` : sectionFileName,\n contentLength,\n hasNotes,\n status: sectionNode.status ?? \"current\",\n chapterIdentifier: chapterAncestor?.identifier ?? \"\",\n chapterNumber: chapterNum,\n chapterName: chapterAncestor?.heading?.trim() ?? \"\",\n };\n}\n\nfunction buildNotesFilter(options: ConvertOptions): NotesFilter | undefined {\n // Default: include all notes\n if (options.includeNotes) return undefined;\n\n // No notes at all\n if (\n !options.includeEditorialNotes &&\n !options.includeStatutoryNotes &&\n !options.includeAmendments\n ) {\n return { editorial: false, statutory: false, amendments: false };\n }\n\n // Selective inclusion\n return {\n editorial: options.includeEditorialNotes,\n statutory: options.includeStatutoryNotes,\n amendments: options.includeAmendments,\n };\n}\n\nfunction findAncestor(\n ancestors: readonly AncestorInfo[],\n levelType: string,\n): AncestorInfo | undefined {\n return ancestors.find((a) => a.levelType === levelType);\n}\n\n/**\n * Build title directory name from docNumber.\n * \"5\" → \"title-05\", \"5a\" → \"title-05-appendix\"\n */\nfunction buildTitleDirFromDocNumber(docNum: string): string {\n const appendixMatch = /^(\\d+)a$/i.exec(docNum);\n if (appendixMatch?.[1]) {\n return `title-${padTwo(appendixMatch[1])}-appendix`;\n }\n return `title-${padTwo(docNum)}`;\n}\n\nfunction padTwo(num: string): string {\n const n = parseInt(num, 10);\n if (isNaN(n)) return num;\n return n.toString().padStart(2, \"0\");\n}\n\n/**\n * Parse an integer safely, returning 0 if invalid.\n */\nfunction parseIntSafe(s: string): number {\n const n = parseInt(s, 10);\n return isNaN(n) ? 0 : n;\n}\n\n/**\n * Extract source credit plain text from a section node's children.\n */\nfunction extractSourceCreditText(node: LevelNode): string | undefined {\n for (const child of node.children) {\n if (child.type === \"sourceCredit\") {\n return child.children.map((inline) => inlineToText(inline)).join(\"\");\n }\n }\n return undefined;\n}\n\n/**\n * Recursively extract plain text from an InlineNode.\n */\nfunction inlineToText(node: {\n readonly type: \"inline\";\n text?: string | undefined;\n children?: readonly { readonly type: \"inline\"; text?: string | undefined }[] | undefined;\n}): string {\n if (node.text) return node.text;\n if (node.children) {\n return node.children.map((c) => c.text ?? \"\").join(\"\");\n }\n return \"\";\n}\n\n/**\n * Parse currency/release point from docPublicationName.\n * Example: \"Online@119-73not60\" → \"119-73\"\n */\nfunction parseCurrency(pubName: string): string {\n // Try to extract the release point pattern (e.g., \"119-73\")\n const match = /(\\d+-\\d+)/.exec(pubName);\n if (match?.[1]) return match[1];\n return pubName || \"unknown\";\n}\n\n/**\n * Parse a date string to ISO date format (YYYY-MM-DD).\n */\nfunction parseDate(dateStr: string): string {\n if (!dateStr) return \"unknown\";\n // Handle ISO timestamp: \"2025-12-03T10:11:39\" → \"2025-12-03\"\n const datePart = dateStr.split(\"T\")[0];\n return datePart ?? dateStr;\n}\n\n/**\n * Create a copy of a section node with source credit children removed.\n */\nfunction stripSourceCredits(node: LevelNode): LevelNode {\n return {\n ...node,\n children: node.children.filter((c) => c.type !== \"sourceCredit\"),\n };\n}\n","/**\n * OLRC U.S. Code XML downloader.\n *\n * Downloads USC title XML zip files from the Office of the Law Revision Counsel\n * and extracts them to a local directory.\n */\n\nimport { createWriteStream } from \"node:fs\";\nimport { mkdir, stat, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable } from \"node:stream\";\nimport { open as yauzlOpen } from \"yauzl\";\nimport type { ZipFile, Entry } from \"yauzl\";\n\n// ---------------------------------------------------------------------------\n// Release point configuration\n// ---------------------------------------------------------------------------\n\n/**\n * Current OLRC release point.\n *\n * Update this value when OLRC publishes a new release point.\n * The release point appears in download URLs and identifies which\n * public laws are incorporated. Format: \"{congress}-{law}[not{excluded}]\"\n *\n * Check https://uscode.house.gov/download/download.shtml for the latest.\n */\nexport const CURRENT_RELEASE_POINT = \"119-73not60\";\n\n/** OLRC base URL for release point downloads */\nconst OLRC_BASE_URL = \"https://uscode.house.gov/download/releasepoints/us/pl\";\n\n/** Valid USC title numbers (1-54) */\nexport const USC_TITLE_NUMBERS = Array.from({ length: 54 }, (_, i) => i + 1);\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Check whether a list of title numbers covers all 54 USC titles.\n *\n * Handles arbitrary ordering and duplicates.\n */\nexport function isAllTitles(titles: number[]): boolean {\n const unique = new Set(titles);\n return unique.size === 54 && USC_TITLE_NUMBERS.every((n) => unique.has(n));\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** Options for downloading USC XML files */\nexport interface DownloadOptions {\n /** Directory to save downloaded XML files */\n outputDir: string;\n /** Specific title numbers to download, or undefined for all */\n titles?: number[] | undefined;\n /** Release point override (default: CURRENT_RELEASE_POINT) */\n releasePoint?: string | undefined;\n}\n\n/** Result of a download operation */\nexport interface DownloadResult {\n /** Release point used */\n releasePoint: string;\n /** Files successfully downloaded and extracted */\n files: DownloadedFile[];\n /** Titles that failed to download */\n errors: DownloadError[];\n}\n\n/** A successfully downloaded file */\nexport interface DownloadedFile {\n /** Title number */\n titleNumber: number;\n /** Path to the extracted XML file */\n filePath: string;\n /** Size in bytes */\n size: number;\n}\n\n/** A failed download */\nexport interface DownloadError {\n /** Title number */\n titleNumber: number;\n /** Error message */\n message: string;\n}\n\n/**\n * Download USC title XML files from OLRC.\n *\n * When all 54 titles are requested, uses the bulk `uscAll` zip for a single\n * HTTP round-trip instead of 54 individual requests. Falls back to per-title\n * downloads if the bulk download fails.\n */\nexport async function downloadTitles(options: DownloadOptions): Promise<DownloadResult> {\n const releasePoint = options.releasePoint ?? CURRENT_RELEASE_POINT;\n const titles = options.titles ?? USC_TITLE_NUMBERS;\n\n await mkdir(options.outputDir, { recursive: true });\n\n // Use bulk zip when all 54 titles are requested\n if (options.titles === undefined || isAllTitles(titles)) {\n try {\n const files = await downloadAndExtractAllTitles(releasePoint, options.outputDir);\n return { releasePoint, files, errors: [] };\n } catch {\n // Fall back to per-title downloads\n }\n }\n\n const files: DownloadedFile[] = [];\n const errors: DownloadError[] = [];\n\n for (const titleNum of titles) {\n try {\n const file = await downloadAndExtractTitle(titleNum, releasePoint, options.outputDir);\n files.push(file);\n } catch (err) {\n errors.push({\n titleNumber: titleNum,\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n return { releasePoint, files, errors };\n}\n\n// ---------------------------------------------------------------------------\n// URL construction\n// ---------------------------------------------------------------------------\n\n/**\n * Build the download URL for a single title's XML zip.\n *\n * Format: {base}/pl/{releasePointPath}/xml_usc{NN}@{releasePoint}.zip\n *\n * The release point path splits the release point into directory segments.\n * For \"119-73not60\", the path is \"119/73not60\".\n */\nexport function buildDownloadUrl(titleNumber: number, releasePoint: string): string {\n const paddedTitle = titleNumber.toString().padStart(2, \"0\");\n const rpPath = releasePointToPath(releasePoint);\n return `${OLRC_BASE_URL}/${rpPath}/xml_usc${paddedTitle}@${releasePoint}.zip`;\n}\n\n/**\n * Build the download URL for all titles in a single zip.\n */\nexport function buildAllTitlesUrl(releasePoint: string): string {\n const rpPath = releasePointToPath(releasePoint);\n return `${OLRC_BASE_URL}/${rpPath}/xml_uscAll@${releasePoint}.zip`;\n}\n\n/**\n * Convert a release point string to a URL path segment.\n * \"119-73not60\" → \"119/73not60\"\n * \"119-43\" → \"119/43\"\n */\nexport function releasePointToPath(releasePoint: string): string {\n // Split on the first hyphen only\n const dashIndex = releasePoint.indexOf(\"-\");\n if (dashIndex === -1) return releasePoint;\n return `${releasePoint.slice(0, dashIndex)}/${releasePoint.slice(dashIndex + 1)}`;\n}\n\n// ---------------------------------------------------------------------------\n// Download and extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Download a single title's zip and extract the XML file.\n */\nasync function downloadAndExtractTitle(\n titleNumber: number,\n releasePoint: string,\n outputDir: string,\n): Promise<DownloadedFile> {\n const url = buildDownloadUrl(titleNumber, releasePoint);\n const paddedTitle = titleNumber.toString().padStart(2, \"0\");\n const zipPath = join(outputDir, `usc${paddedTitle}.zip`);\n const xmlFileName = `usc${paddedTitle}.xml`;\n const xmlPath = join(outputDir, xmlFileName);\n\n // Download the zip file\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText} for ${url}`);\n }\n\n if (!response.body) {\n throw new Error(`No response body for ${url}`);\n }\n\n // Write zip to disk\n const fileStream = createWriteStream(zipPath);\n // ReadableStream type mismatch between DOM and Node — cast to `never` to bridge\n await pipeline(Readable.fromWeb(response.body as never), fileStream);\n\n // Extract XML from zip\n await extractXmlFromZip(zipPath, xmlFileName, xmlPath);\n\n // Clean up zip file\n await unlink(zipPath);\n\n // Get file size\n const fileStat = await stat(xmlPath);\n\n return {\n titleNumber,\n filePath: xmlPath,\n size: fileStat.size,\n };\n}\n\n/**\n * Extract a specific XML file from a zip archive.\n */\nfunction extractXmlFromZip(\n zipPath: string,\n targetFileName: string,\n outputPath: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n yauzlOpen(zipPath, { lazyEntries: true }, (err, zipFile) => {\n if (err) {\n reject(new Error(`Failed to open zip: ${err.message}`));\n return;\n }\n if (!zipFile) {\n reject(new Error(\"Failed to open zip: no zipFile returned\"));\n return;\n }\n\n let found = false;\n\n zipFile.on(\"entry\", (entry: Entry) => {\n // Look for the target XML file (might be at root or in a subdirectory)\n const fileName = entry.fileName.split(\"/\").pop() ?? entry.fileName;\n if (fileName === targetFileName || entry.fileName.endsWith(`.xml`)) {\n found = true;\n extractEntry(zipFile, entry, outputPath)\n .then(() => {\n zipFile.close();\n resolve();\n })\n .catch((extractErr) => {\n zipFile.close();\n reject(extractErr);\n });\n } else {\n zipFile.readEntry();\n }\n });\n\n zipFile.on(\"end\", () => {\n if (!found) {\n reject(new Error(`${targetFileName} not found in zip`));\n }\n });\n\n zipFile.on(\"error\", (zipErr: Error) => {\n reject(new Error(`Zip error: ${zipErr.message}`));\n });\n\n zipFile.readEntry();\n });\n });\n}\n\n/**\n * Extract a single zip entry to a file.\n */\nfunction extractEntry(zipFile: ZipFile, entry: Entry, outputPath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n zipFile.openReadStream(entry, (err, readStream) => {\n if (err) {\n reject(new Error(`Failed to read zip entry: ${err.message}`));\n return;\n }\n if (!readStream) {\n reject(new Error(\"No read stream for zip entry\"));\n return;\n }\n\n const writeStream = createWriteStream(outputPath);\n readStream.pipe(writeStream);\n\n writeStream.on(\"finish\", () => resolve());\n writeStream.on(\"error\", (writeErr) => reject(new Error(`Write error: ${writeErr.message}`)));\n readStream.on(\"error\", (readErr) => reject(new Error(`Read error: ${readErr.message}`)));\n });\n });\n}\n\n// ---------------------------------------------------------------------------\n// Bulk download (all titles in one zip)\n// ---------------------------------------------------------------------------\n\n/** Regex matching USC XML filenames like usc01.xml, usc54.xml */\nconst USC_XML_RE = /^(?:.*\\/)?usc(\\d{2})\\.xml$/;\n\n/**\n * Extract all `usc{NN}.xml` files from a bulk zip archive.\n *\n * Returns an array of `{ titleNumber, filePath }` for each extracted file.\n */\nfunction extractAllXmlFromZip(\n zipPath: string,\n outputDir: string,\n): Promise<{ titleNumber: number; filePath: string }[]> {\n return new Promise((resolve, reject) => {\n yauzlOpen(zipPath, { lazyEntries: true }, (err, zipFile) => {\n if (err) {\n reject(new Error(`Failed to open zip: ${err.message}`));\n return;\n }\n if (!zipFile) {\n reject(new Error(\"Failed to open zip: no zipFile returned\"));\n return;\n }\n\n const extracted: { titleNumber: number; filePath: string }[] = [];\n let pending = 0;\n let ended = false;\n\n const maybeResolve = (): void => {\n if (ended && pending === 0) {\n resolve(extracted);\n }\n };\n\n zipFile.on(\"entry\", (entry: Entry) => {\n const match = USC_XML_RE.exec(entry.fileName);\n if (match) {\n const titleNum = parseInt(match[1] ?? \"0\", 10);\n const outPath = join(outputDir, `usc${match[1] ?? \"00\"}.xml`);\n pending++;\n\n extractEntry(zipFile, entry, outPath)\n .then(() => {\n extracted.push({ titleNumber: titleNum, filePath: outPath });\n pending--;\n // Continue reading entries after extraction completes\n zipFile.readEntry();\n maybeResolve();\n })\n .catch((extractErr) => {\n zipFile.close();\n reject(extractErr);\n });\n } else {\n zipFile.readEntry();\n }\n });\n\n zipFile.on(\"end\", () => {\n ended = true;\n maybeResolve();\n });\n\n zipFile.on(\"error\", (zipErr: Error) => {\n reject(new Error(`Zip error: ${zipErr.message}`));\n });\n\n zipFile.readEntry();\n });\n });\n}\n\n/**\n * Download the bulk all-titles zip and extract every `usc{NN}.xml` file.\n */\nasync function downloadAndExtractAllTitles(\n releasePoint: string,\n outputDir: string,\n): Promise<DownloadedFile[]> {\n const url = buildAllTitlesUrl(releasePoint);\n const zipPath = join(outputDir, \"uscAll.zip\");\n\n // Download the zip file\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText} for ${url}`);\n }\n\n if (!response.body) {\n throw new Error(`No response body for ${url}`);\n }\n\n // Write zip to disk\n const fileStream = createWriteStream(zipPath);\n await pipeline(Readable.fromWeb(response.body as never), fileStream);\n\n // Extract all XML files from zip\n const extracted = await extractAllXmlFromZip(zipPath, outputDir);\n\n // Clean up zip file\n await unlink(zipPath);\n\n // Stat each extracted file and build results\n const files: DownloadedFile[] = [];\n for (const { titleNumber, filePath } of extracted) {\n const fileStat = await stat(filePath);\n files.push({ titleNumber, filePath, size: fileStat.size });\n }\n\n // Sort by title number for consistent ordering\n files.sort((a, b) => a.titleNumber - b.titleNumber);\n\n return files;\n}\n"],"mappings":"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","names":["mkdir","join","files"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lexbuild/usc",
3
- "version": "1.0.6",
3
+ "version": "1.1.1",
4
4
  "description": "Federal U.S. Code specific element handlers and downloader for LexBuild",
5
5
  "author": "Chris Thomas",
6
6
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  ],
44
44
  "dependencies": {
45
45
  "yauzl": "^3.2.0",
46
- "@lexbuild/core": "1.0.6"
46
+ "@lexbuild/core": "1.1.1"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/node": "^25.3.2",