normik 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- normik-0.1.0/.gitignore +50 -0
- normik-0.1.0/LICENSE +21 -0
- normik-0.1.0/Makefile +25 -0
- normik-0.1.0/PKG-INFO +140 -0
- normik-0.1.0/README.md +115 -0
- normik-0.1.0/docs/contributing.md +328 -0
- normik-0.1.0/docs/index.md +57 -0
- normik-0.1.0/docs/installation.md +37 -0
- normik-0.1.0/docs/integrations.md +79 -0
- normik-0.1.0/docs/profiles.md +84 -0
- normik-0.1.0/docs/rules/G732-4-elements-order.md +79 -0
- normik-0.1.0/docs/rules/G732-4-required-element-missing.md +77 -0
- normik-0.1.0/docs/rules/G732-5.3.2-abstract-volume-info.md +63 -0
- normik-0.1.0/docs/rules/G732-5.3.2.1-keywords-count.md +61 -0
- normik-0.1.0/docs/rules/G732-5.5.2-terms-opening.md +59 -0
- normik-0.1.0/docs/rules/G732-5.6.1-abbreviations-opening.md +59 -0
- normik-0.1.0/docs/rules/G732-6.12.1-abstract-volume-inline.md +67 -0
- normik-0.1.0/docs/rules/G732-6.12.2-keywords-final-dot.md +49 -0
- normik-0.1.0/docs/rules/G732-6.12.2-keywords-uppercase.md +50 -0
- normik-0.1.0/docs/rules/G732-6.14-terms-dash.md +63 -0
- normik-0.1.0/docs/rules/G732-6.15-abbreviations-dash.md +59 -0
- normik-0.1.0/docs/rules/G732-6.16-bibitem-uncited.md +56 -0
- normik-0.1.0/docs/rules/G732-6.16-bibliography-order.md +58 -0
- normik-0.1.0/docs/rules/G732-6.16-bibtex-order-unverifiable.md +57 -0
- normik-0.1.0/docs/rules/G732-6.17.2-appendix-no-reference.md +65 -0
- normik-0.1.0/docs/rules/G732-6.17.3-appendix-page-break.md +64 -0
- normik-0.1.0/docs/rules/G732-6.17.4-appendix-letter.md +56 -0
- normik-0.1.0/docs/rules/G732-6.17.4-appendix-sequence.md +56 -0
- normik-0.1.0/docs/rules/G732-6.17.6-appendix-numbering.md +67 -0
- normik-0.1.0/docs/rules/G732-6.2.1-structural-heading-case.md +58 -0
- normik-0.1.0/docs/rules/G732-6.2.1-structural-heading-numbered.md +62 -0
- normik-0.1.0/docs/rules/G732-6.2.2-heading-empty.md +58 -0
- normik-0.1.0/docs/rules/G732-6.2.3-heading-dot.md +57 -0
- normik-0.1.0/docs/rules/G732-6.2.4-heading-hyphenation.md +48 -0
- normik-0.1.0/docs/rules/G732-6.4.1-manual-section-number.md +62 -0
- normik-0.1.0/docs/rules/G732-6.4.5-heading-depth.md +69 -0
- normik-0.1.0/docs/rules/G732-6.4.6-enumeration-letters.md +61 -0
- normik-0.1.0/docs/rules/G732-6.5.1-figure-no-reference.md +72 -0
- normik-0.1.0/docs/rules/G732-6.5.1-reference-word.md +50 -0
- normik-0.1.0/docs/rules/G732-6.5.4-numbering-scheme-mixed.md +80 -0
- normik-0.1.0/docs/rules/G732-6.5.5-appendix-numbering.md +73 -0
- normik-0.1.0/docs/rules/G732-6.5.7-caption-dot.md +94 -0
- normik-0.1.0/docs/rules/G732-6.5.7-caption-manual-number.md +76 -0
- normik-0.1.0/docs/rules/G732-6.5.7-caption-position.md +65 -0
- normik-0.1.0/docs/rules/G732-6.5.8-caption-capital.md +73 -0
- normik-0.1.0/docs/rules/G732-6.5.8-caption-hyphenation.md +60 -0
- normik-0.1.0/docs/rules/G732-6.6.2-reference-word.md +46 -0
- normik-0.1.0/docs/rules/G732-6.6.2-table-no-reference.md +78 -0
- normik-0.1.0/docs/rules/G732-6.6.3-caption-capital.md +56 -0
- normik-0.1.0/docs/rules/G732-6.6.3-caption-dot.md +63 -0
- normik-0.1.0/docs/rules/G732-6.6.3-caption-manual-number.md +72 -0
- normik-0.1.0/docs/rules/G732-6.6.3-caption-position.md +64 -0
- normik-0.1.0/docs/rules/G732-6.6.4-appendix-numbering.md +81 -0
- normik-0.1.0/docs/rules/G732-6.7.2-note-capital.md +59 -0
- normik-0.1.0/docs/rules/G732-6.7.3-note-dash.md +57 -0
- normik-0.1.0/docs/rules/G732-6.7.4-footnote-space.md +48 -0
- normik-0.1.0/docs/rules/G732-6.8.1-blank-line-around.md +66 -0
- normik-0.1.0/docs/rules/G732-6.8.2-where-colon.md +59 -0
- normik-0.1.0/docs/rules/G732-6.8.3-formula-no-reference.md +72 -0
- normik-0.1.0/docs/rules/G732-6.8.4-formula-reference-format.md +51 -0
- normik-0.1.0/docs/rules/G732-6.8.5-appendix-numbering.md +75 -0
- normik-0.1.0/docs/rules/G732-6.9.1-cite-unresolved.md +56 -0
- normik-0.1.0/docs/rules/NK-STYLE-dash.md +61 -0
- normik-0.1.0/docs/rules/NK-STYLE-initials-nbsp.md +56 -0
- normik-0.1.0/docs/rules/NK-STYLE-particle-nbsp.md +52 -0
- normik-0.1.0/docs/rules/NK-STYLE-preposition-nbsp.md +76 -0
- normik-0.1.0/docs/rules/NK-STYLE-quotes.md +51 -0
- normik-0.1.0/docs/rules/NK-STYLE-reference-nbsp.md +54 -0
- normik-0.1.0/docs/rules/NK-STYLE-unit-nbsp.md +55 -0
- normik-0.1.0/docs/rules/SUMMARY.md +64 -0
- normik-0.1.0/docs/rules/index.md +73 -0
- normik-0.1.0/docs/usage.md +236 -0
- normik-0.1.0/profiles/example-university.toml +35 -0
- normik-0.1.0/properdocs.yml +79 -0
- normik-0.1.0/pyproject.toml +100 -0
- normik-0.1.0/src/nk/__init__.py +3 -0
- normik-0.1.0/src/nk/cli.py +331 -0
- normik-0.1.0/src/nk/core/__init__.py +1 -0
- normik-0.1.0/src/nk/core/baseline.py +94 -0
- normik-0.1.0/src/nk/core/diagnostics.py +44 -0
- normik-0.1.0/src/nk/core/document.py +219 -0
- normik-0.1.0/src/nk/core/finding.py +97 -0
- normik-0.1.0/src/nk/core/fixer.py +135 -0
- normik-0.1.0/src/nk/core/numbering.py +82 -0
- normik-0.1.0/src/nk/core/position.py +50 -0
- normik-0.1.0/src/nk/core/profile.py +197 -0
- normik-0.1.0/src/nk/core/registry.py +91 -0
- normik-0.1.0/src/nk/core/rule.py +225 -0
- normik-0.1.0/src/nk/core/runner.py +197 -0
- normik-0.1.0/src/nk/core/suppressions.py +51 -0
- normik-0.1.0/src/nk/parse/__init__.py +1 -0
- normik-0.1.0/src/nk/parse/issues.py +60 -0
- normik-0.1.0/src/nk/parse/numbering.py +194 -0
- normik-0.1.0/src/nk/parse/structure.py +336 -0
- normik-0.1.0/src/nk/parse/suppressions.py +48 -0
- normik-0.1.0/src/nk/parse/tex.py +236 -0
- normik-0.1.0/src/nk/profiles/__init__.py +1 -0
- normik-0.1.0/src/nk/profiles/base.toml +17 -0
- normik-0.1.0/src/nk/py.typed +0 -0
- normik-0.1.0/src/nk/report/__init__.py +1 -0
- normik-0.1.0/src/nk/report/agent.py +78 -0
- normik-0.1.0/src/nk/report/common.py +57 -0
- normik-0.1.0/src/nk/report/examples.py +69 -0
- normik-0.1.0/src/nk/report/human.py +81 -0
- normik-0.1.0/src/nk/report/json.py +55 -0
- normik-0.1.0/src/nk/report/rules_docs.py +213 -0
- normik-0.1.0/src/nk/rules/__init__.py +14 -0
- normik-0.1.0/src/nk/rules/_shared.py +324 -0
- normik-0.1.0/src/nk/rules/_text.py +46 -0
- normik-0.1.0/src/nk/rules/elements/__init__.py +1 -0
- normik-0.1.0/src/nk/rules/elements/appendix_figure_numbering.py +46 -0
- normik-0.1.0/src/nk/rules/elements/appendix_formula_numbering.py +46 -0
- normik-0.1.0/src/nk/rules/elements/appendix_table_numbering.py +46 -0
- normik-0.1.0/src/nk/rules/elements/bibliography_bibtex.py +48 -0
- normik-0.1.0/src/nk/rules/elements/bibliography_cite_unresolved.py +66 -0
- normik-0.1.0/src/nk/rules/elements/bibliography_order.py +69 -0
- normik-0.1.0/src/nk/rules/elements/bibliography_uncited.py +47 -0
- normik-0.1.0/src/nk/rules/elements/figure_caption_capital.py +50 -0
- normik-0.1.0/src/nk/rules/elements/figure_caption_dot.py +44 -0
- normik-0.1.0/src/nk/rules/elements/figure_caption_hyphenation.py +50 -0
- normik-0.1.0/src/nk/rules/elements/figure_caption_manual_number.py +55 -0
- normik-0.1.0/src/nk/rules/elements/figure_caption_position.py +45 -0
- normik-0.1.0/src/nk/rules/elements/figure_reference.py +54 -0
- normik-0.1.0/src/nk/rules/elements/figure_reference_word.py +44 -0
- normik-0.1.0/src/nk/rules/elements/footnote_space.py +53 -0
- normik-0.1.0/src/nk/rules/elements/formula_blank_lines.py +62 -0
- normik-0.1.0/src/nk/rules/elements/formula_reference.py +51 -0
- normik-0.1.0/src/nk/rules/elements/formula_reference_format.py +59 -0
- normik-0.1.0/src/nk/rules/elements/formula_where_colon.py +46 -0
- normik-0.1.0/src/nk/rules/elements/note_capital.py +50 -0
- normik-0.1.0/src/nk/rules/elements/note_dash.py +68 -0
- normik-0.1.0/src/nk/rules/elements/numbering_scheme_mixed.py +48 -0
- normik-0.1.0/src/nk/rules/elements/table_caption_capital.py +49 -0
- normik-0.1.0/src/nk/rules/elements/table_caption_dot.py +42 -0
- normik-0.1.0/src/nk/rules/elements/table_caption_manual_number.py +53 -0
- normik-0.1.0/src/nk/rules/elements/table_caption_position.py +43 -0
- normik-0.1.0/src/nk/rules/elements/table_reference.py +52 -0
- normik-0.1.0/src/nk/rules/elements/table_reference_word.py +41 -0
- normik-0.1.0/src/nk/rules/layout/__init__.py +1 -0
- normik-0.1.0/src/nk/rules/layout/enumeration_letters.py +55 -0
- normik-0.1.0/src/nk/rules/layout/heading_depth.py +49 -0
- normik-0.1.0/src/nk/rules/layout/heading_dot.py +47 -0
- normik-0.1.0/src/nk/rules/layout/heading_empty.py +47 -0
- normik-0.1.0/src/nk/rules/layout/heading_hyphenation.py +51 -0
- normik-0.1.0/src/nk/rules/layout/manual_section_number.py +71 -0
- normik-0.1.0/src/nk/rules/layout/structural_heading_case.py +52 -0
- normik-0.1.0/src/nk/rules/layout/structural_heading_numbered.py +49 -0
- normik-0.1.0/src/nk/rules/structure/__init__.py +1 -0
- normik-0.1.0/src/nk/rules/structure/abbreviations_opening.py +55 -0
- normik-0.1.0/src/nk/rules/structure/abstract_volume_info.py +53 -0
- normik-0.1.0/src/nk/rules/structure/abstract_volume_inline.py +91 -0
- normik-0.1.0/src/nk/rules/structure/appendix_internal_numbering.py +54 -0
- normik-0.1.0/src/nk/rules/structure/appendix_letter.py +52 -0
- normik-0.1.0/src/nk/rules/structure/appendix_page_break.py +59 -0
- normik-0.1.0/src/nk/rules/structure/appendix_reference.py +67 -0
- normik-0.1.0/src/nk/rules/structure/appendix_sequence.py +66 -0
- normik-0.1.0/src/nk/rules/structure/elements_order.py +56 -0
- normik-0.1.0/src/nk/rules/structure/keywords_count.py +57 -0
- normik-0.1.0/src/nk/rules/structure/keywords_final_dot.py +38 -0
- normik-0.1.0/src/nk/rules/structure/keywords_uppercase.py +43 -0
- normik-0.1.0/src/nk/rules/structure/required_elements.py +66 -0
- normik-0.1.0/src/nk/rules/structure/terms_opening.py +54 -0
- normik-0.1.0/src/nk/rules/typography/__init__.py +6 -0
- normik-0.1.0/src/nk/rules/typography/abbreviations_dash.py +55 -0
- normik-0.1.0/src/nk/rules/typography/initials_nbsp.py +81 -0
- normik-0.1.0/src/nk/rules/typography/particle_nbsp.py +56 -0
- normik-0.1.0/src/nk/rules/typography/preposition_nbsp.py +79 -0
- normik-0.1.0/src/nk/rules/typography/reference_nbsp.py +53 -0
- normik-0.1.0/src/nk/rules/typography/terms_dash.py +55 -0
- normik-0.1.0/src/nk/rules/typography/text_dash.py +83 -0
- normik-0.1.0/src/nk/rules/typography/text_quotes.py +64 -0
- normik-0.1.0/src/nk/rules/typography/unit_nbsp.py +69 -0
- normik-0.1.0/tests/conftest.py +30 -0
- normik-0.1.0/tests/fixtures/G732-4-elements-order/bad.tex +11 -0
- normik-0.1.0/tests/fixtures/G732-4-elements-order/good.tex +21 -0
- normik-0.1.0/tests/fixtures/G732-4-required-element-missing/bad.tex +9 -0
- normik-0.1.0/tests/fixtures/G732-4-required-element-missing/good.tex +20 -0
- normik-0.1.0/tests/fixtures/G732-5.3.2-abstract-volume-info/bad.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-5.3.2-abstract-volume-info/good.tex +9 -0
- normik-0.1.0/tests/fixtures/G732-5.3.2.1-keywords-count/bad.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-5.3.2.1-keywords-count/good.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-5.5.2-terms-opening/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-5.5.2-terms-opening/good.tex +8 -0
- normik-0.1.0/tests/fixtures/G732-5.6.1-abbreviations-opening/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-5.6.1-abbreviations-opening/good.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-6.12.1-abstract-volume-inline/bad.tex +11 -0
- normik-0.1.0/tests/fixtures/G732-6.12.1-abstract-volume-inline/good.tex +11 -0
- normik-0.1.0/tests/fixtures/G732-6.12.2-keywords-final-dot/bad.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-6.12.2-keywords-final-dot/good.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-6.12.2-keywords-uppercase/bad.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-6.12.2-keywords-uppercase/good.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-6.14-terms-dash/bad.tex +8 -0
- normik-0.1.0/tests/fixtures/G732-6.14-terms-dash/good.tex +12 -0
- normik-0.1.0/tests/fixtures/G732-6.15-abbreviations-dash/bad.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-6.15-abbreviations-dash/good.tex +9 -0
- normik-0.1.0/tests/fixtures/G732-6.16-bibitem-uncited/bad.tex +6 -0
- normik-0.1.0/tests/fixtures/G732-6.16-bibitem-uncited/good.tex +6 -0
- normik-0.1.0/tests/fixtures/G732-6.16-bibliography-order/bad.tex +6 -0
- normik-0.1.0/tests/fixtures/G732-6.16-bibliography-order/good.tex +6 -0
- normik-0.1.0/tests/fixtures/G732-6.16-bibtex-order-unverifiable/bad.tex +4 -0
- normik-0.1.0/tests/fixtures/G732-6.16-bibtex-order-unverifiable/good.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.17.2-appendix-no-reference/bad.tex +9 -0
- normik-0.1.0/tests/fixtures/G732-6.17.2-appendix-no-reference/good.tex +9 -0
- normik-0.1.0/tests/fixtures/G732-6.17.3-appendix-page-break/bad.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-6.17.3-appendix-page-break/good.tex +13 -0
- normik-0.1.0/tests/fixtures/G732-6.17.4-appendix-letter/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.17.4-appendix-letter/good.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.17.4-appendix-sequence/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.17.4-appendix-sequence/good.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.17.6-appendix-numbering/bad.tex +8 -0
- normik-0.1.0/tests/fixtures/G732-6.17.6-appendix-numbering/good.tex +13 -0
- normik-0.1.0/tests/fixtures/G732-6.2.1-structural-heading-case/bad.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-6.2.1-structural-heading-case/good.tex +9 -0
- normik-0.1.0/tests/fixtures/G732-6.2.1-structural-heading-numbered/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.2.1-structural-heading-numbered/good.tex +11 -0
- normik-0.1.0/tests/fixtures/G732-6.2.2-heading-empty/bad.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-6.2.2-heading-empty/good.tex +9 -0
- normik-0.1.0/tests/fixtures/G732-6.2.3-heading-dot/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.2.3-heading-dot/good.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-6.2.4-heading-hyphenation/bad.tex +1 -0
- normik-0.1.0/tests/fixtures/G732-6.2.4-heading-hyphenation/good.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-6.4.1-manual-section-number/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.4.1-manual-section-number/good.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-6.4.5-heading-depth/bad.tex +9 -0
- normik-0.1.0/tests/fixtures/G732-6.4.5-heading-depth/good.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-6.4.6-enumeration-letters/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.4.6-enumeration-letters/good.tex +10 -0
- normik-0.1.0/tests/fixtures/G732-6.5.1-figure-no-reference/bad.tex +12 -0
- normik-0.1.0/tests/fixtures/G732-6.5.1-figure-no-reference/good.tex +14 -0
- normik-0.1.0/tests/fixtures/G732-6.5.1-reference-word/bad.tex +2 -0
- normik-0.1.0/tests/fixtures/G732-6.5.1-reference-word/good.tex +4 -0
- normik-0.1.0/tests/fixtures/G732-6.5.4-numbering-scheme-mixed/bad.tex +17 -0
- normik-0.1.0/tests/fixtures/G732-6.5.4-numbering-scheme-mixed/good.tex +19 -0
- normik-0.1.0/tests/fixtures/G732-6.5.5-appendix-numbering/bad.tex +13 -0
- normik-0.1.0/tests/fixtures/G732-6.5.5-appendix-numbering/good.tex +15 -0
- normik-0.1.0/tests/fixtures/G732-6.5.7-caption-dot/bad.tex +17 -0
- normik-0.1.0/tests/fixtures/G732-6.5.7-caption-dot/good.tex +33 -0
- normik-0.1.0/tests/fixtures/G732-6.5.7-caption-manual-number/bad.tex +17 -0
- normik-0.1.0/tests/fixtures/G732-6.5.7-caption-manual-number/good.tex +13 -0
- normik-0.1.0/tests/fixtures/G732-6.5.7-caption-position/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.5.7-caption-position/good.tex +15 -0
- normik-0.1.0/tests/fixtures/G732-6.5.8-caption-capital/bad.tex +11 -0
- normik-0.1.0/tests/fixtures/G732-6.5.8-caption-capital/good.tex +19 -0
- normik-0.1.0/tests/fixtures/G732-6.5.8-caption-hyphenation/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.5.8-caption-hyphenation/good.tex +13 -0
- normik-0.1.0/tests/fixtures/G732-6.6.2-reference-word/bad.tex +2 -0
- normik-0.1.0/tests/fixtures/G732-6.6.2-reference-word/good.tex +2 -0
- normik-0.1.0/tests/fixtures/G732-6.6.2-table-no-reference/bad.tex +16 -0
- normik-0.1.0/tests/fixtures/G732-6.6.2-table-no-reference/good.tex +18 -0
- normik-0.1.0/tests/fixtures/G732-6.6.3-caption-capital/bad.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-6.6.3-caption-capital/good.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-6.6.3-caption-dot/bad.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-6.6.3-caption-dot/good.tex +14 -0
- normik-0.1.0/tests/fixtures/G732-6.6.3-caption-manual-number/bad.tex +13 -0
- normik-0.1.0/tests/fixtures/G732-6.6.3-caption-manual-number/good.tex +15 -0
- normik-0.1.0/tests/fixtures/G732-6.6.3-caption-position/bad.tex +7 -0
- normik-0.1.0/tests/fixtures/G732-6.6.3-caption-position/good.tex +14 -0
- normik-0.1.0/tests/fixtures/G732-6.6.4-appendix-numbering/bad.tex +17 -0
- normik-0.1.0/tests/fixtures/G732-6.6.4-appendix-numbering/good.tex +19 -0
- normik-0.1.0/tests/fixtures/G732-6.7.2-note-capital/bad.tex +8 -0
- normik-0.1.0/tests/fixtures/G732-6.7.2-note-capital/good.tex +8 -0
- normik-0.1.0/tests/fixtures/G732-6.7.3-note-dash/bad.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-6.7.3-note-dash/good.tex +8 -0
- normik-0.1.0/tests/fixtures/G732-6.7.4-footnote-space/bad.tex +1 -0
- normik-0.1.0/tests/fixtures/G732-6.7.4-footnote-space/good.tex +3 -0
- normik-0.1.0/tests/fixtures/G732-6.8.1-blank-line-around/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.8.1-blank-line-around/good.tex +15 -0
- normik-0.1.0/tests/fixtures/G732-6.8.2-where-colon/bad.tex +8 -0
- normik-0.1.0/tests/fixtures/G732-6.8.2-where-colon/good.tex +8 -0
- normik-0.1.0/tests/fixtures/G732-6.8.3-formula-no-reference/bad.tex +12 -0
- normik-0.1.0/tests/fixtures/G732-6.8.3-formula-no-reference/good.tex +16 -0
- normik-0.1.0/tests/fixtures/G732-6.8.4-formula-reference-format/bad.tex +2 -0
- normik-0.1.0/tests/fixtures/G732-6.8.4-formula-reference-format/good.tex +4 -0
- normik-0.1.0/tests/fixtures/G732-6.8.5-appendix-numbering/bad.tex +11 -0
- normik-0.1.0/tests/fixtures/G732-6.8.5-appendix-numbering/good.tex +19 -0
- normik-0.1.0/tests/fixtures/G732-6.9.1-cite-unresolved/bad.tex +5 -0
- normik-0.1.0/tests/fixtures/G732-6.9.1-cite-unresolved/good.tex +6 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-dash/bad.tex +1 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-dash/good.tex +15 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-initials-nbsp/bad.tex +1 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-initials-nbsp/good.tex +9 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-particle-nbsp/bad.tex +2 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-particle-nbsp/good.tex +6 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-preposition-nbsp/bad.tex +2 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-preposition-nbsp/good.tex +13 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-quotes/bad.tex +1 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-quotes/good.tex +5 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-reference-nbsp/bad.tex +4 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-reference-nbsp/good.tex +6 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-unit-nbsp/bad.tex +2 -0
- normik-0.1.0/tests/fixtures/NK-STYLE-unit-nbsp/good.tex +6 -0
- normik-0.1.0/tests/support.py +77 -0
- normik-0.1.0/tests/test_baseline.py +115 -0
- normik-0.1.0/tests/test_cli.py +309 -0
- normik-0.1.0/tests/test_docs.py +75 -0
- normik-0.1.0/tests/test_document.py +56 -0
- normik-0.1.0/tests/test_finding.py +54 -0
- normik-0.1.0/tests/test_fixer.py +139 -0
- normik-0.1.0/tests/test_numbering.py +118 -0
- normik-0.1.0/tests/test_parse/test_structure.py +150 -0
- normik-0.1.0/tests/test_parse/test_tex.py +140 -0
- normik-0.1.0/tests/test_profile.py +184 -0
- normik-0.1.0/tests/test_registry.py +126 -0
- normik-0.1.0/tests/test_report/conftest.py +31 -0
- normik-0.1.0/tests/test_report/helpers.py +33 -0
- normik-0.1.0/tests/test_report/test_agent.py +86 -0
- normik-0.1.0/tests/test_report/test_human.py +50 -0
- normik-0.1.0/tests/test_report/test_json.py +86 -0
- normik-0.1.0/tests/test_rule.py +170 -0
- normik-0.1.0/tests/test_rules.py +107 -0
- normik-0.1.0/tests/test_runner.py +277 -0
- normik-0.1.0/tests/test_suppressions.py +102 -0
- normik-0.1.0/uv.lock +736 -0
normik-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Virtual environments
|
|
7
|
+
.venv/
|
|
8
|
+
.env
|
|
9
|
+
.env.staging
|
|
10
|
+
.env.prod
|
|
11
|
+
|
|
12
|
+
# IDE
|
|
13
|
+
.vscode/
|
|
14
|
+
.idea/
|
|
15
|
+
|
|
16
|
+
# Python tooling
|
|
17
|
+
.poetry/
|
|
18
|
+
.mypy_cache/
|
|
19
|
+
.pytype/
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.coverage
|
|
22
|
+
htmlcov/
|
|
23
|
+
|
|
24
|
+
# Собранный сайт документации
|
|
25
|
+
site/
|
|
26
|
+
|
|
27
|
+
# Build
|
|
28
|
+
build/
|
|
29
|
+
dist/
|
|
30
|
+
*.egg-info/
|
|
31
|
+
|
|
32
|
+
# OS
|
|
33
|
+
.DS_Store
|
|
34
|
+
|
|
35
|
+
# Docker
|
|
36
|
+
*.log
|
|
37
|
+
|
|
38
|
+
# Local overrides
|
|
39
|
+
*.local.*
|
|
40
|
+
local/
|
|
41
|
+
|
|
42
|
+
# Claude
|
|
43
|
+
.claude/worktrees/
|
|
44
|
+
.claude/agent-memory/
|
|
45
|
+
|
|
46
|
+
# Ruff
|
|
47
|
+
.ruff_cache/
|
|
48
|
+
|
|
49
|
+
# Кэш сборки документации
|
|
50
|
+
.cache/
|
normik-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arkadii Artamonov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
normik-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
.PHONY: lint format test check docs docs-serve
|
|
2
|
+
|
|
3
|
+
package ?= src tests
|
|
4
|
+
|
|
5
|
+
lint:
|
|
6
|
+
uv run ruff check $(package)
|
|
7
|
+
uv run ruff format --check $(package)
|
|
8
|
+
uv run ty check $(package)
|
|
9
|
+
|
|
10
|
+
format:
|
|
11
|
+
uv run ruff check --fix $(package)
|
|
12
|
+
uv run ruff format $(package)
|
|
13
|
+
|
|
14
|
+
test:
|
|
15
|
+
uv run pytest
|
|
16
|
+
|
|
17
|
+
check: lint test
|
|
18
|
+
|
|
19
|
+
docs:
|
|
20
|
+
uv run nk rules docs
|
|
21
|
+
uv run --group docs properdocs build --strict
|
|
22
|
+
|
|
23
|
+
docs-serve:
|
|
24
|
+
uv run nk rules docs
|
|
25
|
+
uv run --group docs properdocs serve
|
normik-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: normik
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Проверка работ на соответствие ГОСТ
|
|
5
|
+
Project-URL: Homepage, https://trum-ok.github.io/normik/
|
|
6
|
+
Project-URL: Documentation, https://trum-ok.github.io/normik/
|
|
7
|
+
Project-URL: Repository, https://github.com/Trum-ok/normik
|
|
8
|
+
Project-URL: Issues, https://github.com/Trum-ok/normik/issues
|
|
9
|
+
Author-email: Arkadii Artamonov <artamarkan@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: gost,latex,linter,гост,нир
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Education
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Natural Language :: Russian
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Text Processing :: Markup :: LaTeX
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.13.4
|
|
22
|
+
Requires-Dist: rich>=14.0.0
|
|
23
|
+
Requires-Dist: typer>=0.20.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# normik
|
|
27
|
+
|
|
28
|
+
[](https://github.com/Trum-ok/normik/actions/workflows/ci.yaml)
|
|
29
|
+
|
|
30
|
+
`nk` — линтер оформления отчёта о НИР по ГОСТ 7.32-2017 для исходников LaTeX.
|
|
31
|
+
|
|
32
|
+
**Документация: <https://trum-ok.github.io/normik/>**
|
|
33
|
+
|
|
34
|
+
Принимает `.tex` и выдаёт список нарушений с указанием пункта стандарта, файла
|
|
35
|
+
и строки.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
uv run nk check report.tex
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
report.tex
|
|
43
|
+
1:17 warning G732-6.5.1-reference-word
|
|
44
|
+
Нарушение: В ссылке на иллюстрацию использовано сокращение «рис.».
|
|
45
|
+
Требуется: При ссылке пишут слово «рисунок» полностью и его номер.
|
|
46
|
+
Исправить: Заменить «рис.» на «рисунок» в нужном падеже.
|
|
47
|
+
> 1 | Как показано на рис.~\ref{fig:speed}, зависимость линейная.
|
|
48
|
+
2 |
|
|
49
|
+
3 | \begin{figure}[h]
|
|
50
|
+
|
|
51
|
+
5:5 error G732-6.5.7-caption-dot
|
|
52
|
+
Нарушение: Наименование рисунка заканчивается точкой.
|
|
53
|
+
Требуется: Наименование рисунка приводят с прописной буквы без точки в конце.
|
|
54
|
+
Исправить: \caption{Зависимость скорости от нагрузки}
|
|
55
|
+
3 | \begin{figure}[h]
|
|
56
|
+
4 | \includegraphics{plot.png}
|
|
57
|
+
> 5 | \caption{Зависимость скорости от нагрузки.}
|
|
58
|
+
6 | \label{fig:speed}
|
|
59
|
+
7 | \end{figure}
|
|
60
|
+
|
|
61
|
+
Итого: 1 error, 1 warning, 0 info.
|
|
62
|
+
Машинный вывод: --format json, вывод для агента: --format agent
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Установка
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
uv sync
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Примеры запуска
|
|
72
|
+
|
|
73
|
+
Проверить весь каталог с исходниками:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
uv run nk check chapters
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Получить вывод, который можно скопировать в Claude Code без пояснений:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
uv run nk check chapters --format agent
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Проверить по профилю кафедры, показывая только ошибки:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uv run nk check report.tex --profile profiles/example-university.toml --severity error
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Починить то, что чинится механически — сначала посмотреть, потом применить:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
uv run nk check chapters --diff
|
|
95
|
+
uv run nk check chapters --fix
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Включить линтер на готовой работе: зафиксировать текущие нарушения снимком
|
|
99
|
+
и дальше видеть только новые:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
uv run nk check chapters --write-baseline .nk-baseline.json
|
|
103
|
+
uv run nk check chapters --baseline .nk-baseline.json
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Команды
|
|
107
|
+
|
|
108
|
+
| Команда | Назначение |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `nk check PATH...` | проверить исходники |
|
|
111
|
+
| `nk rules list` | перечень правил |
|
|
112
|
+
| `nk rules show RULE_ID` | подробности по правилу |
|
|
113
|
+
| `nk rules docs` | пересобрать страницы правил в `docs/rules/` |
|
|
114
|
+
| `nk profile show` | итоговый набор правил после применения профиля |
|
|
115
|
+
|
|
116
|
+
Ключи `check`, коды возврата и форматы вывода — на странице
|
|
117
|
+
[Использование](https://trum-ok.github.io/normik/usage/).
|
|
118
|
+
|
|
119
|
+
## Документация
|
|
120
|
+
|
|
121
|
+
| Страница | О чём |
|
|
122
|
+
|---|---|
|
|
123
|
+
| [Использование](https://trum-ok.github.io/normik/usage/) | команды, ключи, форматы вывода, автоисправление, подавления, снимок |
|
|
124
|
+
| [Профили](https://trum-ok.github.io/normik/profiles/) | подстройка набора правил под кафедру |
|
|
125
|
+
| [Правила](https://trum-ok.github.io/normik/rules/) | страница на каждое правило: почему, пример, настройка |
|
|
126
|
+
| [Интеграции](https://trum-ok.github.io/normik/integrations/) | CI, хук, передача вывода агенту |
|
|
127
|
+
| [Как добавить правило](https://trum-ok.github.io/normik/contributing/) | руководство для соавторов |
|
|
128
|
+
|
|
129
|
+
Исходники документации — в каталоге
|
|
130
|
+
[`docs/`](https://github.com/Trum-ok/normik/tree/master/docs); каталог
|
|
131
|
+
[`docs/rules/`](https://github.com/Trum-ok/normik/tree/master/docs/rules)
|
|
132
|
+
генерируется командой `uv run nk rules docs` и руками не редактируется.
|
|
133
|
+
|
|
134
|
+
## Разработка
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
make check # ruff, ty, pytest
|
|
138
|
+
make docs # перегенерировать правила и собрать сайт
|
|
139
|
+
make docs-serve # локальный просмотр на http://127.0.0.1:8000
|
|
140
|
+
```
|
normik-0.1.0/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# normik
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Trum-ok/normik/actions/workflows/ci.yaml)
|
|
4
|
+
|
|
5
|
+
`nk` — линтер оформления отчёта о НИР по ГОСТ 7.32-2017 для исходников LaTeX.
|
|
6
|
+
|
|
7
|
+
**Документация: <https://trum-ok.github.io/normik/>**
|
|
8
|
+
|
|
9
|
+
Принимает `.tex` и выдаёт список нарушений с указанием пункта стандарта, файла
|
|
10
|
+
и строки.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
uv run nk check report.tex
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
report.tex
|
|
18
|
+
1:17 warning G732-6.5.1-reference-word
|
|
19
|
+
Нарушение: В ссылке на иллюстрацию использовано сокращение «рис.».
|
|
20
|
+
Требуется: При ссылке пишут слово «рисунок» полностью и его номер.
|
|
21
|
+
Исправить: Заменить «рис.» на «рисунок» в нужном падеже.
|
|
22
|
+
> 1 | Как показано на рис.~\ref{fig:speed}, зависимость линейная.
|
|
23
|
+
2 |
|
|
24
|
+
3 | \begin{figure}[h]
|
|
25
|
+
|
|
26
|
+
5:5 error G732-6.5.7-caption-dot
|
|
27
|
+
Нарушение: Наименование рисунка заканчивается точкой.
|
|
28
|
+
Требуется: Наименование рисунка приводят с прописной буквы без точки в конце.
|
|
29
|
+
Исправить: \caption{Зависимость скорости от нагрузки}
|
|
30
|
+
3 | \begin{figure}[h]
|
|
31
|
+
4 | \includegraphics{plot.png}
|
|
32
|
+
> 5 | \caption{Зависимость скорости от нагрузки.}
|
|
33
|
+
6 | \label{fig:speed}
|
|
34
|
+
7 | \end{figure}
|
|
35
|
+
|
|
36
|
+
Итого: 1 error, 1 warning, 0 info.
|
|
37
|
+
Машинный вывод: --format json, вывод для агента: --format agent
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Установка
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
uv sync
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Примеры запуска
|
|
47
|
+
|
|
48
|
+
Проверить весь каталог с исходниками:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uv run nk check chapters
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Получить вывод, который можно скопировать в Claude Code без пояснений:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
uv run nk check chapters --format agent
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Проверить по профилю кафедры, показывая только ошибки:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv run nk check report.tex --profile profiles/example-university.toml --severity error
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Починить то, что чинится механически — сначала посмотреть, потом применить:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv run nk check chapters --diff
|
|
70
|
+
uv run nk check chapters --fix
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Включить линтер на готовой работе: зафиксировать текущие нарушения снимком
|
|
74
|
+
и дальше видеть только новые:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uv run nk check chapters --write-baseline .nk-baseline.json
|
|
78
|
+
uv run nk check chapters --baseline .nk-baseline.json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Команды
|
|
82
|
+
|
|
83
|
+
| Команда | Назначение |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `nk check PATH...` | проверить исходники |
|
|
86
|
+
| `nk rules list` | перечень правил |
|
|
87
|
+
| `nk rules show RULE_ID` | подробности по правилу |
|
|
88
|
+
| `nk rules docs` | пересобрать страницы правил в `docs/rules/` |
|
|
89
|
+
| `nk profile show` | итоговый набор правил после применения профиля |
|
|
90
|
+
|
|
91
|
+
Ключи `check`, коды возврата и форматы вывода — на странице
|
|
92
|
+
[Использование](https://trum-ok.github.io/normik/usage/).
|
|
93
|
+
|
|
94
|
+
## Документация
|
|
95
|
+
|
|
96
|
+
| Страница | О чём |
|
|
97
|
+
|---|---|
|
|
98
|
+
| [Использование](https://trum-ok.github.io/normik/usage/) | команды, ключи, форматы вывода, автоисправление, подавления, снимок |
|
|
99
|
+
| [Профили](https://trum-ok.github.io/normik/profiles/) | подстройка набора правил под кафедру |
|
|
100
|
+
| [Правила](https://trum-ok.github.io/normik/rules/) | страница на каждое правило: почему, пример, настройка |
|
|
101
|
+
| [Интеграции](https://trum-ok.github.io/normik/integrations/) | CI, хук, передача вывода агенту |
|
|
102
|
+
| [Как добавить правило](https://trum-ok.github.io/normik/contributing/) | руководство для соавторов |
|
|
103
|
+
|
|
104
|
+
Исходники документации — в каталоге
|
|
105
|
+
[`docs/`](https://github.com/Trum-ok/normik/tree/master/docs); каталог
|
|
106
|
+
[`docs/rules/`](https://github.com/Trum-ok/normik/tree/master/docs/rules)
|
|
107
|
+
генерируется командой `uv run nk rules docs` и руками не редактируется.
|
|
108
|
+
|
|
109
|
+
## Разработка
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
make check # ruff, ty, pytest
|
|
113
|
+
make docs # перегенерировать правила и собрать сайт
|
|
114
|
+
make docs-serve # локальный просмотр на http://127.0.0.1:8000
|
|
115
|
+
```
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
# Как добавить правило
|
|
2
|
+
|
|
3
|
+
Добавление правила — это один новый файл в `src/nk/rules/` и один каталог
|
|
4
|
+
в `tests/fixtures/`. Ничего больше править не нужно: реестр находит правило
|
|
5
|
+
по декоратору, тесты — по имени каталога.
|
|
6
|
+
|
|
7
|
+
## Рецепт
|
|
8
|
+
|
|
9
|
+
1. Найти пункт ГОСТ 7.32-2017, который проверяете, и выписать его номер.
|
|
10
|
+
2. Придумать идентификатор: `G732-<пункт>-<мнемоника>`, например
|
|
11
|
+
`G732-6.5.7-caption-dot`. Мнемоника нужна потому, что на один пункт
|
|
12
|
+
приходится несколько независимых проверок.
|
|
13
|
+
3. Создать файл в подпапке по разделу стандарта:
|
|
14
|
+
- `rules/structure/` — разделы 4 и 5: состав и требования к структурным элементам;
|
|
15
|
+
- `rules/layout/` — подразделы 6.2 и 6.4: построение отчёта и нумерация рубрик;
|
|
16
|
+
- `rules/elements/` — подразделы 6.5–6.9, 6.12, 6.16, 6.17: иллюстрации,
|
|
17
|
+
таблицы, формулы, ссылки, реферат, источники, приложения.
|
|
18
|
+
4. Создать `tests/fixtures/<id>/bad.tex` и `tests/fixtures/<id>/good.tex`.
|
|
19
|
+
5. Написать докстринг правила — из него собирается страница документации.
|
|
20
|
+
6. Прогнать `make check` и `uv run nk rules docs`.
|
|
21
|
+
|
|
22
|
+
## Полный пример
|
|
23
|
+
|
|
24
|
+
`src/nk/rules/elements/figure_caption_dot.py`:
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
"""Точка в конце наименования рисунка."""
|
|
28
|
+
|
|
29
|
+
from collections.abc import Iterable
|
|
30
|
+
|
|
31
|
+
from nk.core.document import Document
|
|
32
|
+
from nk.core.finding import Finding, Severity
|
|
33
|
+
from nk.core.rule import rule
|
|
34
|
+
from nk.rules._shared import FIGURE_ENVIRONMENTS, caption_text, captions, one_line
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@rule(
|
|
38
|
+
id="G732-6.5.7-caption-dot",
|
|
39
|
+
clause="6.5.7",
|
|
40
|
+
severity=Severity.ERROR,
|
|
41
|
+
title="Наименование рисунка заканчивается точкой",
|
|
42
|
+
)
|
|
43
|
+
def figure_caption_dot(doc: Document) -> Iterable[Finding]:
|
|
44
|
+
r"""Проверяет наименование рисунка на точку в конце. Точка внутри
|
|
45
|
+
наименования нарушением не является.
|
|
46
|
+
|
|
47
|
+
## Почему это нарушение
|
|
48
|
+
|
|
49
|
+
Наименование рисунка приводят с прописной буквы без точки в конце.
|
|
50
|
+
|
|
51
|
+
## Как исправить
|
|
52
|
+
|
|
53
|
+
Убрать точку в конце `\caption`.
|
|
54
|
+
"""
|
|
55
|
+
for environment in doc.structure.find_environments(*FIGURE_ENVIRONMENTS):
|
|
56
|
+
for command in captions(environment):
|
|
57
|
+
text = caption_text(command)
|
|
58
|
+
if not text.endswith("."):
|
|
59
|
+
continue
|
|
60
|
+
yield figure_caption_dot.finding(
|
|
61
|
+
doc,
|
|
62
|
+
command.span,
|
|
63
|
+
message="Наименование рисунка заканчивается точкой.",
|
|
64
|
+
requirement="Наименование рисунка приводят с прописной буквы без точки в конце.",
|
|
65
|
+
suggestion=f"\\{command.name}{{{one_line(text[:-1])}}}",
|
|
66
|
+
col=command.col,
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Разбор по частям:
|
|
71
|
+
|
|
72
|
+
- **Декоратор** объявляет метаданные один раз. `id`, `clause`, `severity` и `title`
|
|
73
|
+
больше нигде повторять не нужно.
|
|
74
|
+
- **Докстринг** — источник страницы правила в документации, см.
|
|
75
|
+
[ниже](#описание-правила).
|
|
76
|
+
- **Сигнатура** фиксирована протоколом `Rule` и проверяется `ty`: правило принимает
|
|
77
|
+
`Document` и возвращает `Iterable[Finding]`.
|
|
78
|
+
- **Правило — чистая функция.** Никакого ввода-вывода, никакого состояния между
|
|
79
|
+
вызовами, никакого чтения файлов помимо того, что уже в `Document`.
|
|
80
|
+
- **`figure_caption_dot.finding(...)`** — обращение правила к самому себе по имени.
|
|
81
|
+
Оно разрешается в момент вызова, когда декоратор уже отработал. Метод сам
|
|
82
|
+
проставляет `rule_id`, `clause`, `severity` с учётом профиля, `excerpt` и `context`.
|
|
83
|
+
- **Позиция.** Первым позиционным аргументом идёт `Line` или `Span`; `col`
|
|
84
|
+
указывается отдельно, если известна колонка.
|
|
85
|
+
|
|
86
|
+
## Что видит правило
|
|
87
|
+
|
|
88
|
+
`Document` хранит два представления одного исходника.
|
|
89
|
+
|
|
90
|
+
**Построчное** — для проверок, где важен текст строки:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
for line in doc.iter_lines():
|
|
94
|
+
line.raw # исходная строка
|
|
95
|
+
line.stripped # без комментария (% с учётом экранированного \%)
|
|
96
|
+
line.lineno # номер строки, с единицы
|
|
97
|
+
line.path # файл, а не файл-агрегатор
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Структурное** — для проверок, где важна вложенность:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
doc.structure.find_environments("figure", "table") # окружения по именам
|
|
104
|
+
doc.structure.find_commands("caption", "label") # команды по именам
|
|
105
|
+
doc.structure.enclosing(path, lineno) # самое внутреннее окружение
|
|
106
|
+
environment.children # вложенные окружения
|
|
107
|
+
environment.commands # команды непосредственно внутри
|
|
108
|
+
environment.all_commands() # включая вложенные окружения
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Готовые помощники — в `src/nk/rules/_shared.py`: наборы имён окружений, извлечение
|
|
112
|
+
текста подписи, метки и ссылки, наименования структурных элементов. Прежде чем
|
|
113
|
+
писать свой разбор, посмотрите, нет ли там нужного.
|
|
114
|
+
|
|
115
|
+
## Описание правила
|
|
116
|
+
|
|
117
|
+
Докстринг функции правила — источник его страницы в документации. Он пишется
|
|
118
|
+
на Markdown и попадает на страницу как есть, поэтому заголовки в нём — второго
|
|
119
|
+
уровня.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
def figure_caption_dot(doc: Document) -> Iterable[Finding]:
|
|
123
|
+
"""Проверяет наименование рисунка на точку в конце. Точка внутри
|
|
124
|
+
наименования нарушением не является.
|
|
125
|
+
|
|
126
|
+
## Почему это нарушение
|
|
127
|
+
|
|
128
|
+
Наименование рисунка приводят с прописной буквы без точки в конце: оно
|
|
129
|
+
образует с номером единую подпись, а не предложение.
|
|
130
|
+
|
|
131
|
+
## Как исправить
|
|
132
|
+
|
|
133
|
+
Убрать точку в конце `\caption`.
|
|
134
|
+
"""
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- **Первый абзац** — что правило ищет и чего не трогает. Сюда же выносятся
|
|
138
|
+
известные ограничения: случаи, в которых по исходникам решить нельзя.
|
|
139
|
+
- **«Почему это нарушение»** — смысл требования своими словами. Не «так
|
|
140
|
+
написано в стандарте», а что ломается, если сделать иначе.
|
|
141
|
+
- **«Как исправить»** — что сделать в исходнике.
|
|
142
|
+
|
|
143
|
+
Если в докстринге есть обратная косая — а она есть, как только появляется
|
|
144
|
+
пример LaTeX, — объявляйте его сырым: `r"""`.
|
|
145
|
+
|
|
146
|
+
Пример нарушения и правильного оформления на страницу подставляются из фикстур
|
|
147
|
+
правила, писать их отдельно не нужно. Показывается файл целиком; если он
|
|
148
|
+
длинный, покажите его часть, обрамив её метками:
|
|
149
|
+
|
|
150
|
+
```latex
|
|
151
|
+
% DOC-BEGIN
|
|
152
|
+
\begin{figure}
|
|
153
|
+
\includegraphics{img/setup.png}
|
|
154
|
+
\caption{Схема экспериментальной установки}
|
|
155
|
+
\end{figure}
|
|
156
|
+
% DOC-END
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Правка для `--fix`
|
|
160
|
+
|
|
161
|
+
Если исправление однозначно, правило может объявить машинную правку — тогда
|
|
162
|
+
`nk check --fix` применит её сам. Частый случай: `suggestion` и есть готовая
|
|
163
|
+
замена, тогда достаточно указать заменяемый регион:
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
yield figure_caption_dot.finding(
|
|
167
|
+
doc,
|
|
168
|
+
command.span,
|
|
169
|
+
message="Наименование рисунка заканчивается точкой.",
|
|
170
|
+
requirement="Наименование рисунка приводят с прописной буквы без точки в конце.",
|
|
171
|
+
suggestion=f"\\{command.name}{{{one_line(text[:-1])}}}",
|
|
172
|
+
col=command.col,
|
|
173
|
+
fix=command.region, # заменить команду целиком текстом suggestion
|
|
174
|
+
)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`command.region` — точные границы команды вместе с аргументами, включая
|
|
178
|
+
многострочные. Правило с правками объявляется с `fixable=True`; тест сверяет
|
|
179
|
+
объявление с действительностью, поэтому соврать не получится.
|
|
180
|
+
|
|
181
|
+
Когда заменяемый текст отличается от подсказки — например подсказка говорит
|
|
182
|
+
«убрать двоеточие», а заменить нужно один символ на пустую строку, — передаётся
|
|
183
|
+
готовый `Fix`:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
fix=Fix(Region.in_line(line.path, line.lineno, colon, colon + 1), "")
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Точный кусок исходника под регионом даёт `doc.slice(region)` — им удобно строить
|
|
190
|
+
замену «то же самое, но без чего-то»:
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
fix=Fix(command.region, doc.slice(command.region).replace("\\-", ""))
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Правку объявляют, только когда замена однозначна.** «Перенести подпись ниже
|
|
197
|
+
рисунка», «добавить ссылку в текст», «заменить «рис.» на «рисунок»» правками не
|
|
198
|
+
являются: в первых двух нужно решение о структуре, в третьем — согласование
|
|
199
|
+
падежа. Такие правила ограничиваются `suggestion`.
|
|
200
|
+
|
|
201
|
+
Тест на фикстурах проверяет правки сам: применяет их к `bad.tex` в несколько
|
|
202
|
+
проходов и требует, чтобы находки с правками исчезли и новых не появилось.
|
|
203
|
+
|
|
204
|
+
## Требования к тексту находки
|
|
205
|
+
|
|
206
|
+
Это самая частая точка деградации, поэтому требование проверяется на ревью.
|
|
207
|
+
Находка должна быть самодостаточна: по ней нарушение исправляется руками или
|
|
208
|
+
передачей вывода `--format agent` в Claude Code, без дополнительных пояснений.
|
|
209
|
+
Читающий не обязан открывать ГОСТ или `docs/RULES.md`.
|
|
210
|
+
|
|
211
|
+
- **`message`** — что не так, одной фразой, про конкретное место.
|
|
212
|
+
Плохо: `Нарушение п. 6.5.7`. Хорошо: `Наименование рисунка заканчивается точкой.`
|
|
213
|
+
- **`requirement`** — что требуется, **своими словами**. Цитировать стандарт нельзя:
|
|
214
|
+
ГОСТ 7.32-2017 не является общественным достоянием, и его текста в репозитории нет.
|
|
215
|
+
Плохо: `См. п. 6.5.7`. Хорошо: `Наименование рисунка приводят с прописной буквы
|
|
216
|
+
без точки в конце.`
|
|
217
|
+
- **`suggestion`** — конкретное действие или готовый фрагмент на замену.
|
|
218
|
+
Плохо: `Исправьте оформление`. Хорошо: `\caption{Схема экспериментальной установки}`.
|
|
219
|
+
|
|
220
|
+
`suggestion` обязателен. Если исправление принципиально неоднозначно, объявите
|
|
221
|
+
правило с `allow_missing_suggestion=True` — тест это проверяет.
|
|
222
|
+
|
|
223
|
+
## Фикстуры
|
|
224
|
+
|
|
225
|
+
`bad.tex` — файл с нарушениями. Каждая строка, где правило обязано сработать,
|
|
226
|
+
помечается комментарием `% EXPECT`:
|
|
227
|
+
|
|
228
|
+
```latex
|
|
229
|
+
\begin{figure}
|
|
230
|
+
\includegraphics{img/setup.png}
|
|
231
|
+
\caption{Схема экспериментальной установки.} % EXPECT
|
|
232
|
+
\end{figure}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Сопоставление строгое в обе стороны: множество строк с находками должно совпадать
|
|
236
|
+
с множеством помеченных строк. Лишняя находка и пропущенная пометка одинаково
|
|
237
|
+
роняют тест.
|
|
238
|
+
|
|
239
|
+
Если конструкция занимает несколько строк, пометка ставится на ту строку, куда
|
|
240
|
+
указывает находка, — то есть на начало команды:
|
|
241
|
+
|
|
242
|
+
```latex
|
|
243
|
+
\caption{Зависимость погрешности от числа % EXPECT
|
|
244
|
+
измерений.}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Комментарий вырезается парсером и на разбор не влияет.
|
|
248
|
+
|
|
249
|
+
`good.tex` — файл, на котором правило не должно сработать ни разу. Это не формальность:
|
|
250
|
+
именно сюда складываются пограничные случаи, на которых легко получить ложное
|
|
251
|
+
срабатывание. Хороший `good.tex` содержит конструкции, похожие на нарушение, но
|
|
252
|
+
нарушением не являющиеся — точку внутри наименования, подпись таблицы там, где
|
|
253
|
+
правило проверяет рисунки, многозначное число в начале заголовка.
|
|
254
|
+
|
|
255
|
+
Оба файла обязаны разбираться парсером без замечаний.
|
|
256
|
+
|
|
257
|
+
## Параметры
|
|
258
|
+
|
|
259
|
+
Если у правила есть порог, который кафедра захочет изменить, объявите его
|
|
260
|
+
параметром со значением по умолчанию:
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
@rule(
|
|
264
|
+
id="G732-5.3.2.1-keywords-count",
|
|
265
|
+
clause="5.3.2.1",
|
|
266
|
+
severity=Severity.ERROR,
|
|
267
|
+
title="Число ключевых слов вне допустимого диапазона",
|
|
268
|
+
params={"keywords_min": 5, "keywords_max": 15},
|
|
269
|
+
)
|
|
270
|
+
def keywords_count(doc: Document) -> Iterable[Finding]:
|
|
271
|
+
params = keywords_count.params(doc)
|
|
272
|
+
lower = int(params["keywords_min"])
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Профиль переопределяет параметр так:
|
|
276
|
+
|
|
277
|
+
```toml
|
|
278
|
+
[rules."G732-5.3.2.1-keywords-count".params]
|
|
279
|
+
keywords_max = 20
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Проверки
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
make check
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Прогоняет `ruff check`, `ruff format --check`, `ty check` и `pytest`. Всё должно
|
|
289
|
+
проходить полностью. Отдельно:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
make lint
|
|
293
|
+
make test
|
|
294
|
+
make format
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Что проверяет тест автоматически
|
|
298
|
+
|
|
299
|
+
- правило сработало на `bad.tex` ровно на помеченных строках;
|
|
300
|
+
- правило не сработало на `good.tex` ни разу;
|
|
301
|
+
- у каждой находки непустые `message`, `requirement` и `context`;
|
|
302
|
+
- `clause` находки совпадает с объявленным в декораторе;
|
|
303
|
+
- `suggestion` есть, если правило не объявлено с `allow_missing_suggestion=True`;
|
|
304
|
+
- у каждого правила есть каталог фикстур, у каждого каталога — правило.
|
|
305
|
+
|
|
306
|
+
Последние два пункта не дают репозиторию расползтись, поэтому обойти их нельзя.
|
|
307
|
+
|
|
308
|
+
## После добавления правила
|
|
309
|
+
|
|
310
|
+
Перегенерируйте страницы документации:
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
uv run nk rules docs
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Каталог `docs/rules/` руками не редактируется: он собирается из реестра, а тест
|
|
317
|
+
проверяет, что записанное на диске совпадает со сгенерированным.
|
|
318
|
+
|
|
319
|
+
## Чего в правилах не делаем
|
|
320
|
+
|
|
321
|
+
- Не вызываем LLM: инструмент детерминирован.
|
|
322
|
+
- Не читаем PDF: источник данных — только исходники `.tex`. Проверки, требующие
|
|
323
|
+
скомпилированного документа (поля, гарнитуры, кегль, колонцифры), в область
|
|
324
|
+
видимости не входят.
|
|
325
|
+
- Не цитируем ГОСТ 7.32-2017 ни в коде, ни в тестах, ни в документации.
|
|
326
|
+
Допустимы только номера пунктов и собственные краткие формулировки.
|
|
327
|
+
- Не правим файлы отчёта наугад. Правка объявляется только там, где замена
|
|
328
|
+
однозначна; во всех остальных случаях правило ограничивается `suggestion`.
|