forked from jupyter-book/mystmd
-
Notifications
You must be signed in to change notification settings - Fork 0
Book-style numbering: format, label, section-tagged TOC, auto-prefix #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
fbed3d4
Add schema for book-style numbering (PR #1, §3.5(1))
mmcky d39288c
Add formatCounter for arabic/alph/Alph/roman/Roman (PR #1, §3.5(2))
mmcky 1c3251a
Render heading cross-refs via label / fall back to title (PR #1, §3.5…
mmcky 88ffc86
Apply label rendering to file-target cross-refs (PR #1, §3.5(5))
mmcky 61f74f4
Inject per-section numbering defaults for tagged TOC subtrees (PR #1,…
mmcky ccff61a
Auto-prefix figures/equations/tables/proofs with chapter enumerator (…
mmcky 8409c8c
Test proof:* / exercise auto-prefix and render-only format override
mmcky db7ddea
Apply prettier formatting to enumerate.ts and enumerate.spec.ts
mmcky 8b476e6
Fix ESLint errors flagged by CI
mmcky ca72cbd
Address Copilot review feedback
mmcky 79c9239
Merge branch 'main' into feature/book-numbering
mmcky File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| import { describe, expect, test } from 'vitest'; | ||
| import type { PageFrontmatter } from 'myst-frontmatter'; | ||
| import { injectBookSectionDefaults } from './mdast.js'; | ||
|
|
||
| describe('injectBookSectionDefaults', () => { | ||
| test('no-op when book mode is off', () => { | ||
| const fm: PageFrontmatter = { numbering: {} }; | ||
| injectBookSectionDefaults(fm, 'chapters', false); | ||
| expect(fm.numbering).toEqual({}); | ||
| }); | ||
|
|
||
| test('no-op when section is undefined', () => { | ||
| const fm: PageFrontmatter = { numbering: { book: { enabled: true } } }; | ||
| injectBookSectionDefaults(fm, undefined, false); | ||
| expect(fm.numbering).toEqual({ book: { enabled: true } }); | ||
| }); | ||
|
|
||
| test('chapters section seeds heading_1 with the Chapter label', () => { | ||
| const fm: PageFrontmatter = { numbering: { book: { enabled: true } } }; | ||
| injectBookSectionDefaults(fm, 'chapters', false); | ||
| expect(fm.numbering?.heading_1).toEqual({ enabled: true, label: 'Chapter %s' }); | ||
| }); | ||
|
|
||
| test('first chapter gets start: 1', () => { | ||
| const fm: PageFrontmatter = { numbering: { book: { enabled: true } } }; | ||
| injectBookSectionDefaults(fm, 'chapters', true); | ||
| expect(fm.numbering?.heading_1).toEqual({ start: 1, enabled: true, label: 'Chapter %s' }); | ||
| }); | ||
|
|
||
| test('appendices section seeds Alph format + Appendix label', () => { | ||
| const fm: PageFrontmatter = { numbering: { book: { enabled: true } } }; | ||
| injectBookSectionDefaults(fm, 'appendices', false); | ||
| expect(fm.numbering?.heading_1).toEqual({ | ||
| enabled: true, | ||
| format: 'Alph', | ||
| label: 'Appendix %s', | ||
| }); | ||
| }); | ||
|
|
||
| test('first appendix gets start: 1 (counter reset on section transition)', () => { | ||
| const fm: PageFrontmatter = { numbering: { book: { enabled: true } } }; | ||
| injectBookSectionDefaults(fm, 'appendices', true); | ||
| expect(fm.numbering?.heading_1).toEqual({ | ||
| start: 1, | ||
| enabled: true, | ||
| format: 'Alph', | ||
| label: 'Appendix %s', | ||
| }); | ||
| }); | ||
|
|
||
| test('frontmatter section disables heading_1 (skip-semantic)', () => { | ||
| const fm: PageFrontmatter = { numbering: { book: { enabled: true } } }; | ||
| injectBookSectionDefaults(fm, 'frontmatter', true); | ||
| expect(fm.numbering?.heading_1?.enabled).toBe(false); | ||
| }); | ||
|
|
||
| test('backmatter section disables heading_1', () => { | ||
| const fm: PageFrontmatter = { numbering: { book: { enabled: true } } }; | ||
| injectBookSectionDefaults(fm, 'backmatter', false); | ||
| expect(fm.numbering?.heading_1?.enabled).toBe(false); | ||
| }); | ||
|
|
||
| test('numbering.chapters.label flows into heading_1', () => { | ||
| // Copilot review #2: a project setting `numbering.chapters.label` | ||
| // should reach pages in `section: chapters` instead of being | ||
| // silently ignored in favour of the hardcoded "Chapter %s". | ||
| const fm: PageFrontmatter = { | ||
| numbering: { | ||
| book: { enabled: true }, | ||
| chapters: { label: 'Module %s' }, | ||
| }, | ||
| }; | ||
| injectBookSectionDefaults(fm, 'chapters', false); | ||
| expect(fm.numbering?.heading_1?.label).toBe('Module %s'); | ||
| }); | ||
|
|
||
| test('numbering.appendices.format flows into heading_1', () => { | ||
| const fm: PageFrontmatter = { | ||
| numbering: { | ||
| book: { enabled: true }, | ||
| appendices: { format: 'roman' }, | ||
| }, | ||
| }; | ||
| injectBookSectionDefaults(fm, 'appendices', false); | ||
| // section config beats the hardcoded `Alph` default | ||
| expect(fm.numbering?.heading_1?.format).toBe('roman'); | ||
| // hardcoded label still fills in because section didn't set one | ||
| expect(fm.numbering?.heading_1?.label).toBe('Appendix %s'); | ||
| }); | ||
|
|
||
| test('page heading_1 beats section config beats hardcoded default', () => { | ||
| const fm: PageFrontmatter = { | ||
| numbering: { | ||
| book: { enabled: true }, | ||
| chapters: { label: 'Module %s', format: 'roman' }, | ||
| // page-level wins for label; format comes from section config | ||
| heading_1: { label: 'Lesson %s' }, | ||
| }, | ||
| }; | ||
| injectBookSectionDefaults(fm, 'chapters', false); | ||
| expect(fm.numbering?.heading_1?.label).toBe('Lesson %s'); // page wins | ||
| expect(fm.numbering?.heading_1?.format).toBe('roman'); // section wins over hardcoded | ||
| }); | ||
|
|
||
| test('does not clobber explicit author settings', () => { | ||
| const fm: PageFrontmatter = { | ||
| numbering: { | ||
| book: { enabled: true }, | ||
| heading_1: { label: 'Section %s', format: 'roman' }, | ||
| }, | ||
| }; | ||
| injectBookSectionDefaults(fm, 'chapters', false); | ||
| // author-set label and format are preserved | ||
| expect(fm.numbering?.heading_1?.label).toBe('Section %s'); | ||
| expect(fm.numbering?.heading_1?.format).toBe('roman'); | ||
| // enabled is filled in (the default kicks in only when unset) | ||
| expect(fm.numbering?.heading_1?.enabled).toBe(true); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.