all2md.linter.rules
Built-in rule implementations. Importing the all2md.linter.rules package
triggers each rule module to register itself with the global
all2md.linter.rule_registry.
Structural document rules (STR001-STR008).
These check high-level document shape: does it have a title, are heading levels consistent, are headings empty or orphaned, are sections too short, is the document empty, is block-level nesting excessive?
- class all2md.linter.rules.structure.MissingTitleRule
Bases:
LintRuleSTR001: Flag documents that lack a top-level (H1) heading.
- code: str = 'STR001'
- name: str = 'missing-title'
- category: str = 'structure'
- description: str = 'Every document should have a top-level (H1) heading.'
- check(ctx: LintContext) list[Violation]
Return a single violation if the document has no H1 heading.
- class all2md.linter.rules.structure.MultipleH1Rule
Bases:
LintRuleSTR002: Flag documents that contain more than one H1 heading.
- code: str = 'STR002'
- name: str = 'multiple-h1'
- category: str = 'structure'
- description: str = 'A document should have exactly one H1 heading.'
- check(ctx: LintContext) list[Violation]
Return a violation per extra H1 (skipping the first one).
- class all2md.linter.rules.structure.HeadingHierarchyRule
Bases:
LintRuleSTR003: Flag heading-level skips (for example, H1 followed directly by H3).
- code: str = 'STR003'
- name: str = 'heading-hierarchy'
- category: str = 'structure'
- description: str = 'Heading levels must not skip (e.g., H1 followed by H3).'
- check(ctx: LintContext) list[Violation]
Return a violation for every heading that skips a level.
- class all2md.linter.rules.structure.EmptyHeadingRule
Bases:
LintRuleSTR004: Flag headings that contain no text.
- code: str = 'STR004'
- name: str = 'empty-heading'
- category: str = 'structure'
- description: str = 'Headings must contain text.'
- check(ctx: LintContext) list[Violation]
Return a violation for each empty heading.
- class all2md.linter.rules.structure.OrphanHeadingRule
Bases:
LintRuleSTR005: Flag a heading that ends the document with no content after it.
- code: str = 'STR005'
- name: str = 'orphan-heading'
- category: str = 'structure'
- description: str = 'A heading at the end of the document with no content after it is likely a mistake.'
- check(ctx: LintContext) list[Violation]
Return a violation if the last child of the document is a heading.
- class all2md.linter.rules.structure.ShortSectionRule
Bases:
LintRuleSTR006: Flag headings whose section contains fewer than N words of content.
A “section” is the run of top-level children between this heading and the next heading at the same-or-higher level (matching how readers perceive a section). The default threshold is 10 words; override via
[tool.all2md.lint.rules]STR006.min_words.- code: str = 'STR006'
- name: str = 'short-section'
- category: str = 'structure'
- description: str = 'Sections should have enough content to justify their heading.'
- check(ctx: LintContext) list[Violation]
Return a violation for each heading whose section is too short.
- class all2md.linter.rules.structure.EmptyDocumentRule
Bases:
LintRuleSTR007: Flag documents whose children list is empty.
- code: str = 'STR007'
- name: str = 'empty-document'
- category: str = 'structure'
- description: str = 'A document should contain at least one block.'
- check(ctx: LintContext) list[Violation]
Return a single violation if
ctx.document.childrenis empty.
- class all2md.linter.rules.structure.ExcessiveNestingRule
Bases:
LintRuleSTR008: Flag block-level nesting deeper than N levels.
“Block-level nesting” counts only
BlockQuoteandListItemon the path from the document root to the deepest descendant. Default threshold is 4; override viaSTR008.max_depth.- code: str = 'STR008'
- name: str = 'excessive-nesting'
- category: str = 'structure'
- description: str = 'Block-level nesting (blockquotes, list items) should not be excessively deep.'
- check(ctx: LintContext) list[Violation]
Return a violation per nested container exceeding
max_depth.
Heading content rules (HDG001-HDG007).
Checks the text of each heading: punctuation, length, duplication, capitalization consistency, emphasis-wrapped headings, sentence-shaped headings, and URLs in heading text.
- class all2md.linter.rules.headings.HeadingTrailingPunctuationRule
Bases:
LintRuleHDG001: Flag headings that end with sentence-style punctuation.
- code: str = 'HDG001'
- name: str = 'heading-trailing-punctuation'
- category: str = 'headings'
- description: str = 'Headings should not end with sentence-ending punctuation.'
- check(ctx: LintContext) list[Violation]
Return a violation for each heading ending in ‘.’, ‘,’, ‘;’, or ‘:’.
- class all2md.linter.rules.headings.HeadingLengthRule
Bases:
LintRuleHDG002: Flag headings longer than a configurable character limit (default 80).
- code: str = 'HDG002'
- name: str = 'heading-length'
- category: str = 'headings'
- description: str = 'Headings should not exceed a configurable maximum length.'
- check(ctx: LintContext) list[Violation]
Return a violation for each heading exceeding
max_length.
- class all2md.linter.rules.headings.DuplicateHeadingsRule
Bases:
LintRuleHDG003: Flag same-level headings with identical (case-insensitive) text.
- code: str = 'HDG003'
- name: str = 'duplicate-headings'
- category: str = 'headings'
- description: str = 'Headings at the same level should not have duplicate text.'
- check(ctx: LintContext) list[Violation]
Return a violation for each duplicate occurrence after the first.
- class all2md.linter.rules.headings.HeadingCapitalizationRule
Bases:
LintRuleHDG004: Flag headings at the same level that diverge from the dominant capitalization style.
- code: str = 'HDG004'
- name: str = 'heading-capitalization'
- category: str = 'headings'
- description: str = 'Headings at the same level should share a capitalization style.'
- check(ctx: LintContext) list[Violation]
Return a violation for each heading whose style doesn’t match the majority at its level.
- class all2md.linter.rules.headings.HeadingEmphasisRule
Bases:
LintRuleHDG005: Flag headings whose content is a single Strong or Emphasis node.
- code: str = 'HDG005'
- name: str = 'heading-emphasis'
- category: str = 'headings'
- description: str = 'Headings should not be wrapped entirely in emphasis or strong markup.'
- check(ctx: LintContext) list[Violation]
Return a violation for each heading wrapped entirely in emphasis.
- class all2md.linter.rules.headings.HeadingAsSentenceRule
Bases:
LintRuleHDG006: Flag headings that read like a full sentence.
A heading is sentence-shaped if it both (a) has more words than the configured threshold (default 12), and (b) ends with a sentence-final punctuation mark (
.,!,?). Either alone is unreliable — short imperative headings sometimes end with!, and long noun phrases without punctuation are perfectly valid headings.- code: str = 'HDG006'
- name: str = 'heading-as-sentence'
- category: str = 'headings'
- description: str = 'Headings should not read like full sentences.'
- check(ctx: LintContext) list[Violation]
Return a violation for each heading that looks like a sentence.
- class all2md.linter.rules.headings.HeadingUrlRule
Bases:
LintRuleHDG007: Flag headings whose text contains a URL.
- code: str = 'HDG007'
- name: str = 'heading-url'
- category: str = 'headings'
- description: str = 'Headings should not contain raw URLs.'
- check(ctx: LintContext) list[Violation]
Return a violation for each heading whose plain text contains a URL.
Link rules (LNK001-LNK007).
Checks link structure (empty text, missing URLs), duplicated URLs, bare URLs
in plain text, low-quality link labels like “click here”, insecure http://
links, and links whose text is the raw URL.
- class all2md.linter.rules.links.EmptyLinkTextRule
Bases:
LintRuleLNK001: Flag links whose visible text is empty.
- code: str = 'LNK001'
- name: str = 'empty-link-text'
- category: str = 'links'
- description: str = 'Links must have visible text describing their destination.'
- check(ctx: LintContext) list[Violation]
Return a violation for each link with empty text.
- class all2md.linter.rules.links.MissingUrlRule
Bases:
LintRuleLNK002: Flag links with empty or whitespace-only URLs.
- code: str = 'LNK002'
- name: str = 'missing-url'
- category: str = 'links'
- description: str = 'Links must have a non-empty URL.'
- check(ctx: LintContext) list[Violation]
Return a violation for each link with a blank URL.
- class all2md.linter.rules.links.DuplicateUrlsRule
Bases:
LintRuleLNK003: Flag URLs linked from more than one place in the document.
- code: str = 'LNK003'
- name: str = 'duplicate-urls'
- category: str = 'links'
- description: str = 'The same URL should typically only be linked once.'
- check(ctx: LintContext) list[Violation]
Return a violation for each repeated link to the same URL.
- class all2md.linter.rules.links.BareUrlRule
Bases:
LintRuleLNK004: Flag raw URLs that appear in prose instead of being wrapped in a Link.
- code: str = 'LNK004'
- name: str = 'bare-url'
- category: str = 'links'
- description: str = 'Raw URLs should be wrapped in link syntax.'
- check(ctx: LintContext) list[Violation]
Return a violation for each unwrapped URL found in Text content.
- class all2md.linter.rules.links.LinkTextQualityRule
Bases:
LintRuleLNK005: Flag links whose text is a low-quality filler phrase like ‘click here’.
- code: str = 'LNK005'
- name: str = 'link-text-quality'
- category: str = 'links'
- description: str = "Link text should describe the destination, not use generic phrases like 'click here'."
- check(ctx: LintContext) list[Violation]
Return a violation for each link whose text is in the generic-phrases list.
- class all2md.linter.rules.links.InsecureLinkRule
Bases:
LintRuleLNK006: Flag links that use
http://instead ofhttps://.No auto-fix in v2.0 — blindly upgrading to HTTPS can break a fraction of legitimate hosts. The lint output points the user at the link; they decide whether to upgrade.
- code: str = 'LNK006'
- name: str = 'insecure-link'
- category: str = 'links'
- description: str = 'Links should use HTTPS where possible.'
- check(ctx: LintContext) list[Violation]
Return a violation for each
http://Link URL.
- class all2md.linter.rules.links.LinkTextIsUrlRule
Bases:
LintRuleLNK007: Flag links whose visible text equals the URL itself.
Distinct from
BareUrlRule(LNK004): LNK004 catches raw URLs in prose that aren’t wrapped in link syntax at all; LNK007 catches links of the form[https://x](https://x)where the markup is correct but the visible text adds nothing.- code: str = 'LNK007'
- name: str = 'link-text-is-url'
- category: str = 'links'
- description: str = 'Link text should describe the destination, not duplicate the URL.'
- check(ctx: LintContext) list[Violation]
Return a violation for each link whose text equals its URL.
Typography rules (TYP001-TYP008).
Low-level text hygiene: trailing spaces, multiple spaces, straight quotes, double-hyphens that should be em-dashes, inconsistent list marker styles (adjacent sibling lists with mismatched ordered/unordered types), ellipsis character, space-before-punctuation, and consecutive punctuation.
Most TYP rules carry a SAFE auto-fix that mutates Text.content
in place — see all2md.linter.fixes.
- class all2md.linter.rules.typography.TrailingSpacesRule
Bases:
LintRuleTYP001: Flag Text nodes that end with whitespace when they’re the last child of their parent.
- code: str = 'TYP001'
- name: str = 'trailing-spaces'
- category: str = 'typography'
- description: str = 'Text should not end with trailing whitespace.'
- check(ctx: LintContext) list[Violation]
Return a violation for each trailing-whitespace Text at the end of a container.
- class all2md.linter.rules.typography.MultipleSpacesRule
Bases:
LintRuleTYP002: Flag Text nodes containing runs of consecutive spaces.
- code: str = 'TYP002'
- name: str = 'multiple-spaces'
- category: str = 'typography'
- description: str = 'Text should not contain multiple consecutive spaces.'
- check(ctx: LintContext) list[Violation]
Return a violation for each Text containing two or more consecutive spaces.
- class all2md.linter.rules.typography.StraightQuotesRule
Bases:
LintRuleTYP003: Flag Text that uses straight ASCII quotes around a word.
- code: str = 'TYP003'
- name: str = 'straight-quotes'
- category: str = 'typography'
- description: str = 'Prefer curly quotes (“”‘’) over straight quotes.'
- check(ctx: LintContext) list[Violation]
Return a violation for each Text containing quoted words using straight quotes.
- class all2md.linter.rules.typography.DoubleHyphensRule
Bases:
LintRuleTYP004: Flag Text containing
--that should be an em-dash.- code: str = 'TYP004'
- name: str = 'double-hyphens'
- category: str = 'typography'
- description: str = 'Prefer em-dashes (—) over double hyphens.'
- check(ctx: LintContext) list[Violation]
Return a violation for each Text containing a double-hyphen sequence.
- class all2md.linter.rules.typography.MixedListMarkersRule
Bases:
LintRuleTYP005: Flag adjacent sibling lists that disagree on ordered vs unordered style.
- code: str = 'TYP005'
- name: str = 'mixed-list-markers'
- category: str = 'typography'
- description: str = 'Adjacent sibling lists should share the same ordered/unordered style.'
- check(ctx: LintContext) list[Violation]
Return a violation for each list immediately following a sibling list of the opposite kind.
- class all2md.linter.rules.typography.EllipsisCharacterRule
Bases:
LintRuleTYP006: Flag Text containing
...instead of the ellipsis character.- code: str = 'TYP006'
- name: str = 'ellipsis-character'
- category: str = 'typography'
- description: str = 'Prefer the ellipsis character (…) over three periods.'
- check(ctx: LintContext) list[Violation]
Return a violation for each Text containing
...(but not....).
- class all2md.linter.rules.typography.SpaceBeforePunctuationRule
Bases:
LintRuleTYP007: Flag Text containing whitespace immediately before sentence punctuation.
- code: str = 'TYP007'
- name: str = 'space-before-punctuation'
- category: str = 'typography'
- description: str = 'Punctuation should not be preceded by whitespace.'
- check(ctx: LintContext) list[Violation]
Return a violation for each Text where
,.;:!?is preceded by a space.
- class all2md.linter.rules.typography.ConsecutivePunctuationRule
Bases:
LintRuleTYP008: Flag Text containing repeated punctuation like
,,or!!.Detects only
,,!, and?repeats.../...overlap with TYP006 (ellipsis) and are intentionally excluded — TYP006 already covers them. Repeats are not auto-fixed because the right replacement (collapse to one character vs. ellipsis vs. interrobang?!) is reader judgement.- code: str = 'TYP008'
- name: str = 'consecutive-punctuation'
- category: str = 'typography'
- description: str = "Punctuation should not be repeated (',,', '!!', '??', etc.)."
- check(ctx: LintContext) list[Violation]
Return a violation for each Text containing a repeated punctuation mark.