Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/content-json-schema-defs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ export const CONTENT_DEFS: Record<string, JsonSchema> = {
ContentListMembership: {
type: 'object',
properties: {
numId: { type: 'string' },
numId: { type: 'string' }, // optional in the Zod source -- depth-only list membership (OOXML drawing paragraphs) carries no numbering identity
level: { type: 'integer', minimum: 0, maximum: MAX_SAFE_INTEGER },
},
required: ['numId', 'level'],
required: ['level'],
additionalProperties: false,
},
ContentRun: {
Expand Down
27 changes: 27 additions & 0 deletions src/content.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,33 @@ describe('ContentParagraphSchema headingLevel', () => {
});
});

describe('ContentListMembership numId', () => {
it('parses a level-only membership, the shape a format with depth but no numbering identity produces (OOXML drawing paragraphs carry only a:pPr/@lvl)', () => {
const parsed = ContentParagraphSchema.parse({
kind: 'paragraph',
runs: [{ text: 'Bullet text' }],
list: { level: 1 },
});
expect(parsed.list).toEqual({ level: 1 });
});

it('still parses a numId+level membership, the shape a format with a shared numbering definition produces (docx w:numId, ODF minted identity)', () => {
const parsed = ContentParagraphSchema.parse({
kind: 'paragraph',
runs: [{ text: 'Item one' }],
list: { numId: '1', level: 0 },
});
expect(parsed.list).toEqual({ numId: '1', level: 0 });
});

it('keeps level required, so a membership without one does not parse', () => {
expect(ContentParagraphSchema.safeParse({ kind: 'paragraph', runs: [], list: { numId: '1' } }).success).toBe(
false,
);
expect(ContentParagraphSchema.safeParse({ kind: 'paragraph', runs: [], list: {} }).success).toBe(false);
});
});

describe('clampHeadingLevel', () => {
it('leaves a level already within 1-6 untouched', () => {
expect(clampHeadingLevel(1)).toBe(1);
Expand Down
2 changes: 1 addition & 1 deletion src/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const ContentRunSchema = z.object({
export type ContentRun = z.infer<typeof ContentRunSchema>;

export const ContentListMembershipSchema = z.object({
numId: z.string(), // w:numId
numId: z.string().optional(), // identifies a shared numbering definition when the source format has one -- docx's w:numId, ODF's minted structural identity -- and is absent when the format carries only a depth (OOXML drawing paragraphs' a:pPr/@lvl), where fabricating one would invent numbering identity the source never had
level: z.number().int().nonnegative(), // w:ilvl
});
export type ContentListMembership = z.infer<typeof ContentListMembershipSchema>;
Expand Down
Loading