Skip to content

Commit 2f1affc

Browse files
Merge pull request #9 from chris-c-thomas/fix/formatting
Fix file formatting with Prettier
2 parents a9ed346 + 25e1db3 commit 2f1affc

16 files changed

Lines changed: 203 additions & 113 deletions

File tree

packages/cli/src/commands/convert.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ interface ConvertCommandOptions {
3636
}
3737

3838
/** Build the shared convert options from CLI flags. */
39-
function buildConvertOptions(inputPath: string, outputPath: string, options: ConvertCommandOptions) {
39+
function buildConvertOptions(
40+
inputPath: string,
41+
outputPath: string,
42+
options: ConvertCommandOptions,
43+
) {
4044
const hasSelectiveFlags =
4145
options.includeEditorialNotes || options.includeStatutoryNotes || options.includeAmendments;
4246
const includeNotes = hasSelectiveFlags ? false : options.includeNotes;
@@ -159,11 +163,7 @@ export const convertCommand = new Command("convert")
159163
.argument("[input]", "Path to a USC XML file")
160164
.option("-o, --output <dir>", "Output directory", "./output")
161165
.option("--titles <spec>", "Title(s) to convert (e.g. 1, 1-5, 1,3,8, 1-5,8,11)")
162-
.option(
163-
"-i, --input-dir <dir>",
164-
"Directory containing USC XML files",
165-
"./downloads/usc/xml",
166-
)
166+
.option("-i, --input-dir <dir>", "Directory containing USC XML files", "./downloads/usc/xml")
167167
.option(
168168
"-g, --granularity <level>",
169169
'Output granularity: "section" (one file per section) or "chapter" (sections inline)',
@@ -186,9 +186,7 @@ export const convertCommand = new Command("convert")
186186
.action(async (input: string | undefined, options: ConvertCommandOptions) => {
187187
// Validate: must specify <input> or --titles
188188
if (!input && !options.titles) {
189-
console.error(
190-
error("Specify an input file or --titles <spec> (e.g. --titles 1-5,8,11)"),
191-
);
189+
console.error(error("Specify an input file or --titles <spec> (e.g. --titles 1-5,8,11)"));
192190
process.exit(1);
193191
}
194192

packages/cli/src/commands/download.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@ export const downloadCommand = new Command("download")
5555
const outputDir = resolve(options.output);
5656
const titleCount = titles ? titles.length : 54;
5757
const label =
58-
titleCount === 1
59-
? `Downloading Title ${titles?.[0]}`
60-
: `Downloading ${titleCount} titles`;
58+
titleCount === 1 ? `Downloading Title ${titles?.[0]}` : `Downloading ${titleCount} titles`;
6159

6260
const spinner = createSpinner(`${label}...`);
6361
spinner.start();
@@ -110,8 +108,7 @@ export const downloadCommand = new Command("download")
110108
// Footer
111109
const titleWord = result.files.length === 1 ? "title" : "titles";
112110
const summary = `Downloaded ${result.files.length} ${titleWord} (${formatBytes(totalBytes)}) in ${formatDuration(elapsed)}`;
113-
const failSuffix =
114-
result.errors.length > 0 ? ` (${result.errors.length} failed)` : "";
111+
const failSuffix = result.errors.length > 0 ? ` (${result.errors.length} failed)` : "";
115112
console.log(` ${success(summary + failSuffix)}`);
116113
console.log("");
117114
} catch (err) {

packages/cli/src/ui.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,7 @@ function visualLength(s: string): number {
5252
* Compute column widths that fill the terminal.
5353
* Expands `flexCol` to absorb remaining space.
5454
*/
55-
function fillWidths(
56-
columns: string[][],
57-
colCount: number,
58-
flexCol: number,
59-
): number[] | undefined {
55+
function fillWidths(columns: string[][], colCount: number, flexCol: number): number[] | undefined {
6056
const termWidth = process.stdout.columns || 80;
6157
// Compute natural width per column (max visual length across all rows)
6258
const natural = Array.from<number>({ length: colCount }).fill(0);

packages/core/src/ast/builder.test.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ function parseAndCollect(xml: string, emitAt: ASTBuilderOptions["emitAt"] = "sec
3030
}
3131

3232
/** Helper: parse a fixture file and collect emitted sections */
33-
async function parseFileAndCollect(filename: string, emitAt: ASTBuilderOptions["emitAt"] = "section") {
33+
async function parseFileAndCollect(
34+
filename: string,
35+
emitAt: ASTBuilderOptions["emitAt"] = "section",
36+
) {
3437
const emitted: Array<{ node: LevelNode; context: EmitContext }> = [];
3538

3639
const builder = new ASTBuilder({
@@ -103,14 +106,17 @@ describe("ASTBuilder", () => {
103106
const section = emitted[0]!.node;
104107

105108
// Find the content node
106-
const contentNode = section.children.find((c) => c.type === "content") as ContentNode | undefined;
109+
const contentNode = section.children.find((c) => c.type === "content") as
110+
| ContentNode
111+
| undefined;
107112
expect(contentNode).toBeDefined();
108113
expect(contentNode!.variant).toBe("content");
109114
expect(contentNode!.children.length).toBeGreaterThan(0);
110115

111116
// Check that there is text
112117
const hasText = contentNode!.children.some(
113-
(c) => c.type === "inline" && c.inlineType === "text" && c.text && c.text.includes("county"),
118+
(c) =>
119+
c.type === "inline" && c.inlineType === "text" && c.text && c.text.includes("county"),
114120
);
115121
expect(hasText).toBe(true);
116122
});
@@ -119,7 +125,9 @@ describe("ASTBuilder", () => {
119125
const { emitted } = await parseFileAndCollect("simple-section.xml");
120126
const section = emitted[0]!.node;
121127

122-
const sourceCredit = section.children.find((c) => c.type === "sourceCredit") as SourceCreditNode | undefined;
128+
const sourceCredit = section.children.find((c) => c.type === "sourceCredit") as
129+
| SourceCreditNode
130+
| undefined;
123131
expect(sourceCredit).toBeDefined();
124132
expect(sourceCredit!.children.length).toBeGreaterThan(0);
125133
});
@@ -175,7 +183,10 @@ describe("ASTBuilder", () => {
175183
parser.on("closeElement", (name) => builder.onCloseElement(name));
176184
parser.on("text", (text) => builder.onText(text));
177185

178-
const stream = createReadStream(resolve(FIXTURES_DIR, "section-with-subsections.xml"), "utf-8");
186+
const stream = createReadStream(
187+
resolve(FIXTURES_DIR, "section-with-subsections.xml"),
188+
"utf-8",
189+
);
179190
await parser.parseStream(stream);
180191

181192
expect(onEmit).toHaveBeenCalledTimes(1);

packages/core/src/ast/builder.ts

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,16 @@ const INLINE_TYPE_MAP: Readonly<Record<string, InlineType>> = {
5656
*/
5757
interface StackFrame {
5858
/** What kind of frame this is */
59-
kind: "level" | "content" | "inline" | "note" | "sourceCredit" | "notesContainer" | "quotedContent" | "meta" | "ignore";
59+
kind:
60+
| "level"
61+
| "content"
62+
| "inline"
63+
| "note"
64+
| "sourceCredit"
65+
| "notesContainer"
66+
| "quotedContent"
67+
| "meta"
68+
| "ignore";
6069
/** The AST node being constructed (null for meta/ignore frames) */
6170
node: ASTNode | null;
6271
/** The XML element name that opened this frame */
@@ -151,8 +160,14 @@ export class ASTBuilder {
151160

152161
if (name === "xhtml:table") {
153162
this.tableCollector = {
154-
headers: [], rows: [], currentRow: [], cellText: "",
155-
inHead: false, inCell: false, isComplex: false, cellDepth: 0,
163+
headers: [],
164+
rows: [],
165+
currentRow: [],
166+
cellText: "",
167+
inHead: false,
168+
inCell: false,
169+
isComplex: false,
170+
cellDepth: 0,
156171
};
157172
return;
158173
}
@@ -163,8 +178,14 @@ export class ASTBuilder {
163178

164179
if (name === "layout") {
165180
this.layoutCollector = {
166-
headers: [], rows: [], currentRow: [], cellText: "",
167-
inHead: false, inCell: false, isComplex: false, cellDepth: 0,
181+
headers: [],
182+
rows: [],
183+
currentRow: [],
184+
cellText: "",
185+
inHead: false,
186+
inCell: false,
187+
isComplex: false,
188+
cellDepth: 0,
168189
};
169190
return;
170191
}
@@ -207,7 +228,12 @@ export class ASTBuilder {
207228
return;
208229
}
209230

210-
if (name === "note" || name === "statutoryNote" || name === "editorialNote" || name === "changeNote") {
231+
if (
232+
name === "note" ||
233+
name === "statutoryNote" ||
234+
name === "editorialNote" ||
235+
name === "changeNote"
236+
) {
211237
this.openNote(name, attrs);
212238
return;
213239
}
@@ -349,7 +375,12 @@ export class ASTBuilder {
349375
}
350376

351377
// Handle note close
352-
if (name === "note" || name === "statutoryNote" || name === "editorialNote" || name === "changeNote") {
378+
if (
379+
name === "note" ||
380+
name === "statutoryNote" ||
381+
name === "editorialNote" ||
382+
name === "changeNote"
383+
) {
353384
this.closeNote();
354385
return;
355386
}
@@ -455,7 +486,11 @@ export class ASTBuilder {
455486
const trimmed = text.trim();
456487
if (trimmed) {
457488
const textNode: InlineNode = { type: "inline", inlineType: "text", text };
458-
const contentNode: ContentNode = { type: "content", variant: "content", children: [textNode] };
489+
const contentNode: ContentNode = {
490+
type: "content",
491+
variant: "content",
492+
children: [textNode],
493+
};
459494
const parent = frame.node;
460495
if (parent && "children" in parent && Array.isArray(parent.children)) {
461496
(parent.children as ASTNode[]).push(contentNode);
@@ -469,7 +504,11 @@ export class ASTBuilder {
469504
const trimmed = text.trim();
470505
if (trimmed) {
471506
const textNode: InlineNode = { type: "inline", inlineType: "text", text };
472-
const contentNode: ContentNode = { type: "content", variant: "content", children: [textNode] };
507+
const contentNode: ContentNode = {
508+
type: "content",
509+
variant: "content",
510+
children: [textNode],
511+
};
473512
(frame.node as LevelNode).children.push(contentNode);
474513
}
475514
return;
@@ -741,7 +780,12 @@ export class ASTBuilder {
741780
// Add as inline "quoted" node if parent is content/inline,
742781
// or as block node if parent is note/level
743782
const parentFrame = this.peekFrame();
744-
if (parentFrame && (parentFrame.kind === "content" || parentFrame.kind === "inline" || parentFrame.kind === "sourceCredit")) {
783+
if (
784+
parentFrame &&
785+
(parentFrame.kind === "content" ||
786+
parentFrame.kind === "inline" ||
787+
parentFrame.kind === "sourceCredit")
788+
) {
745789
// Flatten to inline quoted text
746790
const qNode: InlineNode = {
747791
type: "inline",
@@ -766,7 +810,11 @@ export class ASTBuilder {
766810
const levelFrame = this.findParentFrame("level");
767811

768812
// Heading inside a note takes priority
769-
if (name === "heading" && noteFrame && (!levelFrame || this.stack.indexOf(noteFrame) > this.stack.indexOf(levelFrame))) {
813+
if (
814+
name === "heading" &&
815+
noteFrame &&
816+
(!levelFrame || this.stack.indexOf(noteFrame) > this.stack.indexOf(levelFrame))
817+
) {
770818
(noteFrame.node as NoteNode).heading = text;
771819
return;
772820
}
@@ -783,7 +831,9 @@ export class ASTBuilder {
783831
}
784832

785833
// Update ancestor entry if this is a big level
786-
const ancestor = this.ancestors.find((a) => a.levelType === levelNode.levelType && a.identifier === levelNode.identifier);
834+
const ancestor = this.ancestors.find(
835+
(a) => a.levelType === levelNode.levelType && a.identifier === levelNode.identifier,
836+
);
787837
if (ancestor) {
788838
if (name === "num") {
789839
ancestor.numValue = levelNode.numValue;
@@ -812,10 +862,18 @@ export class ASTBuilder {
812862
}
813863
children.push(textNode);
814864
}
815-
} else if (parentFrame.kind === "note" || parentFrame.kind === "level" || parentFrame.kind === "quotedContent") {
865+
} else if (
866+
parentFrame.kind === "note" ||
867+
parentFrame.kind === "level" ||
868+
parentFrame.kind === "quotedContent"
869+
) {
816870
// Wrap in a ContentNode
817871
const textNode: InlineNode = { type: "inline", inlineType: "text", text };
818-
const contentNode: ContentNode = { type: "content", variant: "content", children: [textNode] };
872+
const contentNode: ContentNode = {
873+
type: "content",
874+
variant: "content",
875+
children: [textNode],
876+
};
819877
const parent = parentFrame.node;
820878
if (parent && "children" in parent && Array.isArray(parent.children)) {
821879
(parent.children as ASTNode[]).push(contentNode);

packages/core/src/ast/types.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,18 @@ describe("AST types", () => {
149149

150150
it("creates valid AncestorInfo", () => {
151151
const ancestors: AncestorInfo[] = [
152-
{ levelType: "title", numValue: "1", heading: "GENERAL PROVISIONS", identifier: "/us/usc/t1" },
153-
{ levelType: "chapter", numValue: "1", heading: "RULES OF CONSTRUCTION", identifier: "/us/usc/t1/ch1" },
152+
{
153+
levelType: "title",
154+
numValue: "1",
155+
heading: "GENERAL PROVISIONS",
156+
identifier: "/us/usc/t1",
157+
},
158+
{
159+
levelType: "chapter",
160+
numValue: "1",
161+
heading: "RULES OF CONSTRUCTION",
162+
identifier: "/us/usc/t1/ch1",
163+
},
154164
];
155165
expect(ancestors).toHaveLength(2);
156166
expect(ancestors[0]!.levelType).toBe("title");

packages/core/src/ast/types.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,17 @@ export interface ContentNode extends BaseNode {
114114
}
115115

116116
/** Discriminator for inline node types */
117-
export type InlineType = "text" | "bold" | "italic" | "ref" | "date" | "term" | "quoted" | "sup" | "sub" | "footnoteRef";
117+
export type InlineType =
118+
| "text"
119+
| "bold"
120+
| "italic"
121+
| "ref"
122+
| "date"
123+
| "term"
124+
| "quoted"
125+
| "sup"
126+
| "sub"
127+
| "footnoteRef";
118128

119129
/** Inline text or formatting */
120130
export interface InlineNode extends BaseNode {

packages/core/src/index.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,7 @@ export {
2020
} from "./xml/namespace.js";
2121

2222
// AST types
23-
export {
24-
LEVEL_TYPES,
25-
BIG_LEVELS,
26-
SMALL_LEVELS,
27-
} from "./ast/types.js";
23+
export { LEVEL_TYPES, BIG_LEVELS, SMALL_LEVELS } from "./ast/types.js";
2824
export type {
2925
LevelType,
3026
LevelNode,
@@ -56,4 +52,3 @@ export type { RenderOptions, NotesFilter } from "./markdown/renderer.js";
5652
export { generateFrontmatter, FORMAT_VERSION, GENERATOR } from "./markdown/frontmatter.js";
5753
export { createLinkResolver, parseIdentifier } from "./markdown/links.js";
5854
export type { LinkResolver, ParsedIdentifier } from "./markdown/links.js";
59-

packages/core/src/markdown/frontmatter.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { FrontmatterData } from "../ast/types.js";
66
/** Minimal valid frontmatter data */
77
const MINIMAL_DATA: FrontmatterData = {
88
identifier: "/us/usc/t1/s1",
9-
title: '1 USC § 1 - Words denoting number, gender, and so forth',
9+
title: "1 USC § 1 - Words denoting number, gender, and so forth",
1010
title_number: 1,
1111
title_name: "General Provisions",
1212
section_number: "1",

0 commit comments

Comments
 (0)