Repository navigation
Public API for renderers: placed markers, the template decision, helpers (#26) - #90
Merged
Merged
Conversation
…ers (#26) ValidationResult.is_template and .placed_markers hand back the two decisions validate_document makes together (§15.1, §5.7, §15.3). Each PlacedMarker says where the marker is (section, block, fragment, offset, the list item it marks) and what applies (identifier, condition), with its line. is_template, is_drafting_note, the lexer and the fragment helpers are exported from legaldown; the condition helpers from legaldown.validator. The README states what the public API is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012pWb8FGHgaM3ZWbzsPiKsk
_placed_markers read a list's fragments once per marker, quadratic in a long list. PlacedMarker says which field of its block holds it (text, or a lifted ref's or term's suffix), and takes keyword arguments only. is_drafting_note is exported from legaldown.validator too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012pWb8FGHgaM3ZWbzsPiKsk
…ering block_fragments and list_fragments return Fragment and ListFragment named tuples, which unpack as before. is_drafting_note is True only for a quote block. PlacedMarker.field is a Literal; its docs and the README say items are numbered in pre-order and that identifiers and conditions are as written. Tests cover two lists in one section and a lifted term. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012pWb8FGHgaM3ZWbzsPiKsk
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Closes #26.
legaldown-render never re-derives a LegalDown rule, so it takes the validator's decisions from private modules. All of those imports sit in its
validator_bridge.py, and they are why it pinslegaldown-validator<0.3. Two of them are already broken against currentmain:_frontmatter_fieldsas 2-tuples; Diagnostics name their file and line (§16.9, #27) #85 made them 3-tuples.This PR makes what it needs public, so it can pin
>=0.3,<0.4.The two decisions, on
ValidationResultis_template: boolis the template decisionvalidate_documentalready makes (§15.1).placed_markers: list[PlacedMarker]holds every body marker that applies (§5.7, §15.3), in document order. It is filled from the markers the validator already found.PlacedMarkeris frozen and keyword-only. Its fields:section,block,fragmentfragmentofblock_fragments(block)offsettext[offset:offset+len(source)] == source. This replaces the renderer's first-line search.sourceidentifier#idthat applies:""for an include-only paragraph, whose#idis ignored (§12.2)conditionwhen=conditionfieldLiteral["text", "suffix"], wheresuffixis for a lifted{{ref:}}or{{term:}}itemlist_fragmentsnumbers them: an item comes before the items nested in it, and empty items count. An item can hold several fragments, so the fragment index alone cannot give this.include_onlylineNonefor a document built in code or changed since it was parsed.A fragment holds at most one placed marker. A section's own marker stays
Section.identifier/condition.Identifiers and conditions are returned as written. An invalid one is still reported as a diagnostic, so callers should check
result.is_validfirst.Public helpers
From
legaldown:is_template(document), with a clean one-argument signature. The internal form is_is_template.is_drafting_note(block), true only for a quote block.lex,Lexed,is_escaped.block_fragmentsandlist_fragments. They now return the named tuplesFragment(text, anchor)andListFragment(text, anchor, items), which unpack exactly as before.list_items.PlacedMarker.From
legaldown.validator:is_template,is_drafting_note,PlacedMarker.parse_condition,Condition,condition_problem,exclusive,Presence,ALWAYS.is_valid_iso_date,is_valid_money_amount,is_positive_numeric,IDENTIFIER_RE,KNOWN_CURRENCIES.With these, every private import in the renderer's
validator_bridge.pyandresolve/resolver.pyhas a public replacement:_frontmatter_fieldsandtext_fragmentsfed only its copy of the template formula, whichis_templatereplaces.find_markersandFoundMarkerare replaced byplaced_markers.Quote.start, which the validator'sQuotedoesn't have, is replaced byis_drafting_note.HTML_COMMENT_REis needed only for the first-line search, whichoffsetreplaces.Versioning (README, Python API)
The public API is what
legaldownandlegaldown.validatorexport in their__all__. Changes to it are listed in each GitHub release's notes. Before 1.0, a minor release may change it and a patch release does not. Other modules are internal. #34 tracks the constants that PactTrack still imports from them.The README also gains rows for the two result fields and a table of the helpers.
Verification
Tests: the full suite passes (1922 passed, 40 skipped) and ruff is clean. The new
tests/test_public_api.pycovers:itemnumbering), and two lists in one section;suffixfield after a lifted{{ref:}}and after a lifted{{term:}};is_templateandis_drafting_noteon their own, including a paragraph that is not a drafting note;Parity over the spec corpus: over every
.lgdin the LegalDown repository:is_templatematches;placed_markersequals the validator's own placed findings;That covers 30 markers, 20 of them in list items, and 24 templates.
Plan review:
itemwas added, because the fragment index alone does not locate a list-item marker.is_drafting_notereplacesQuote/block_quotes.legaldown.validator.Three code reviews:
_placed_markersis fixed, with a regression test: 2,000 marked items took 8.2 s and now take 0.17 s.PlacedMarkerbecame keyword-only and gainedfield.is_drafting_noteno longer accepts a paragraph that opens with[!DRAFTING].fieldfor a lifted term) are now caught by tests.itemandoffsetmatched.Follow-up (not in this PR)
legaldown-render needs to switch to this API after 0.3 is released:
validator_bridge.py;result.placed_markers, including their offsets andfield, andresult.is_template;legaldownandlegaldown.validator;>=0.3,<0.4.It also has to adapt to the 0.3 model: list items hold
ListItemblocks, walked recursively and keyed byPlacedMarker.item, and paragraph text holds\n. The version bump to 0.3.0 comes with the release.🤖 Generated with Claude Code
https://claude.ai/code/session_012pWb8FGHgaM3ZWbzsPiKsk