chaffjs 0.33.0 → 0.35.0
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.
- package/dist/api.d.ts +7 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js.map +1 -1
- package/dist/capitals-passage.d.ts +3 -0
- package/dist/capitals-passage.d.ts.map +1 -0
- package/dist/capitals-passage.js +26 -0
- package/dist/capitals-passage.js.map +1 -0
- package/dist/cli-text.d.ts.map +1 -1
- package/dist/cli-text.js +4 -2
- package/dist/cli-text.js.map +1 -1
- package/dist/coined-hyphen-name.d.ts +13 -0
- package/dist/coined-hyphen-name.d.ts.map +1 -0
- package/dist/coined-hyphen-name.js +21 -0
- package/dist/coined-hyphen-name.js.map +1 -0
- package/dist/commands/grade.d.ts.map +1 -1
- package/dist/commands/grade.js +66 -21
- package/dist/commands/grade.js.map +1 -1
- package/dist/company-kana-spelling.d.ts +6 -1
- package/dist/company-kana-spelling.d.ts.map +1 -1
- package/dist/company-kana-spelling.js +19 -2
- package/dist/company-kana-spelling.js.map +1 -1
- package/dist/company-name-ending.d.ts +7 -0
- package/dist/company-name-ending.d.ts.map +1 -0
- package/dist/company-name-ending.js +44 -0
- package/dist/company-name-ending.js.map +1 -0
- package/dist/company-names.d.ts +17 -4
- package/dist/company-names.d.ts.map +1 -1
- package/dist/company-names.js +49 -17
- package/dist/company-names.js.map +1 -1
- package/dist/custom/no-rewrite.d.ts +3 -0
- package/dist/custom/no-rewrite.d.ts.map +1 -0
- package/dist/custom/no-rewrite.js +3 -0
- package/dist/custom/no-rewrite.js.map +1 -0
- package/dist/custom/parse.d.ts.map +1 -1
- package/dist/custom/parse.js +14 -2
- package/dist/custom/parse.js.map +1 -1
- package/dist/detectors/acronym-context.d.ts +1 -1
- package/dist/detectors/acronym-context.d.ts.map +1 -1
- package/dist/detectors/acronym-context.js +4 -4
- package/dist/detectors/acronym-context.js.map +1 -1
- package/dist/detectors/acronym-definition.d.ts +13 -0
- package/dist/detectors/acronym-definition.d.ts.map +1 -0
- package/dist/detectors/acronym-definition.js +90 -0
- package/dist/detectors/acronym-definition.js.map +1 -0
- package/dist/detectors/acronym-lone.d.ts +13 -0
- package/dist/detectors/acronym-lone.d.ts.map +1 -0
- package/dist/detectors/acronym-lone.js +22 -0
- package/dist/detectors/acronym-lone.js.map +1 -0
- package/dist/detectors/acronym-name.d.ts +55 -0
- package/dist/detectors/acronym-name.d.ts.map +1 -0
- package/dist/detectors/acronym-name.js +75 -0
- package/dist/detectors/acronym-name.js.map +1 -0
- package/dist/detectors/age-words.d.ts +5 -0
- package/dist/detectors/age-words.d.ts.map +1 -0
- package/dist/detectors/age-words.js +8 -0
- package/dist/detectors/age-words.js.map +1 -0
- package/dist/detectors/annual-pay-mismatch.d.ts.map +1 -1
- package/dist/detectors/annual-pay-mismatch.js +2 -12
- package/dist/detectors/annual-pay-mismatch.js.map +1 -1
- package/dist/detectors/blank-structure.d.ts.map +1 -1
- package/dist/detectors/blank-structure.js +4 -3
- package/dist/detectors/blank-structure.js.map +1 -1
- package/dist/detectors/capitalised-term.d.ts +14 -2
- package/dist/detectors/capitalised-term.d.ts.map +1 -1
- package/dist/detectors/capitalised-term.js +115 -4
- package/dist/detectors/capitalised-term.js.map +1 -1
- package/dist/detectors/caps-caption.d.ts +11 -0
- package/dist/detectors/caps-caption.d.ts.map +1 -0
- package/dist/detectors/caps-caption.js +51 -0
- package/dist/detectors/caps-caption.js.map +1 -0
- package/dist/detectors/char-shape.d.ts.map +1 -1
- package/dist/detectors/char-shape.js +47 -18
- package/dist/detectors/char-shape.js.map +1 -1
- package/dist/detectors/clause-shape.d.ts +1 -1
- package/dist/detectors/clause-shape.d.ts.map +1 -1
- package/dist/detectors/clause-shape.js +9 -4
- package/dist/detectors/clause-shape.js.map +1 -1
- package/dist/detectors/closing-balance-mismatch.d.ts.map +1 -1
- package/dist/detectors/closing-balance-mismatch.js +1 -0
- package/dist/detectors/closing-balance-mismatch.js.map +1 -1
- package/dist/detectors/code-fences.d.ts +5 -0
- package/dist/detectors/code-fences.d.ts.map +1 -1
- package/dist/detectors/code-fences.js +9 -0
- package/dist/detectors/code-fences.js.map +1 -1
- package/dist/detectors/concrete-evidence.d.ts +13 -1
- package/dist/detectors/concrete-evidence.d.ts.map +1 -1
- package/dist/detectors/concrete-evidence.js +59 -0
- package/dist/detectors/concrete-evidence.js.map +1 -1
- package/dist/detectors/condition-toki.d.ts +16 -0
- package/dist/detectors/condition-toki.d.ts.map +1 -0
- package/dist/detectors/condition-toki.js +42 -0
- package/dist/detectors/condition-toki.js.map +1 -0
- package/dist/detectors/conjugated-entry.d.ts +17 -0
- package/dist/detectors/conjugated-entry.d.ts.map +1 -0
- package/dist/detectors/conjugated-entry.js +50 -0
- package/dist/detectors/conjugated-entry.js.map +1 -0
- package/dist/detectors/content-morphemes.d.ts +2 -0
- package/dist/detectors/content-morphemes.d.ts.map +1 -1
- package/dist/detectors/content-morphemes.js +1 -1
- package/dist/detectors/content-morphemes.js.map +1 -1
- package/dist/detectors/contraction-minority.d.ts +11 -0
- package/dist/detectors/contraction-minority.d.ts.map +1 -0
- package/dist/detectors/contraction-minority.js +10 -0
- package/dist/detectors/contraction-minority.js.map +1 -0
- package/dist/detectors/counter-edge.d.ts +5 -0
- package/dist/detectors/counter-edge.d.ts.map +1 -1
- package/dist/detectors/counter-edge.js +23 -0
- package/dist/detectors/counter-edge.js.map +1 -1
- package/dist/detectors/cross-facts.d.ts.map +1 -1
- package/dist/detectors/cross-facts.js +2 -1
- package/dist/detectors/cross-facts.js.map +1 -1
- package/dist/detectors/custom.d.ts.map +1 -1
- package/dist/detectors/custom.js +8 -2
- package/dist/detectors/custom.js.map +1 -1
- package/dist/detectors/date-any-year.d.ts +6 -3
- package/dist/detectors/date-any-year.d.ts.map +1 -1
- package/dist/detectors/date-any-year.js +47 -10
- package/dist/detectors/date-any-year.js.map +1 -1
- package/dist/detectors/date-heading-year.d.ts +18 -0
- package/dist/detectors/date-heading-year.d.ts.map +1 -0
- package/dist/detectors/date-heading-year.js +38 -0
- package/dist/detectors/date-heading-year.js.map +1 -0
- package/dist/detectors/date-year.d.ts +12 -2
- package/dist/detectors/date-year.d.ts.map +1 -1
- package/dist/detectors/date-year.js +31 -6
- package/dist/detectors/date-year.js.map +1 -1
- package/dist/detectors/defined-term-form.d.ts.map +1 -1
- package/dist/detectors/defined-term-form.js +26 -5
- package/dist/detectors/defined-term-form.js.map +1 -1
- package/dist/detectors/document-shape.d.ts.map +1 -1
- package/dist/detectors/document-shape.js +6 -0
- package/dist/detectors/document-shape.js.map +1 -1
- package/dist/detectors/due-date.d.ts.map +1 -1
- package/dist/detectors/due-date.js +18 -2
- package/dist/detectors/due-date.js.map +1 -1
- package/dist/detectors/en-shape.d.ts.map +1 -1
- package/dist/detectors/en-shape.js +5 -1
- package/dist/detectors/en-shape.js.map +1 -1
- package/dist/detectors/fact-consistency.d.ts.map +1 -1
- package/dist/detectors/fact-consistency.js +15 -15
- package/dist/detectors/fact-consistency.js.map +1 -1
- package/dist/detectors/form-line.d.ts +9 -0
- package/dist/detectors/form-line.d.ts.map +1 -0
- package/dist/detectors/form-line.js +36 -0
- package/dist/detectors/form-line.js.map +1 -0
- package/dist/detectors/formula-amount.d.ts.map +1 -1
- package/dist/detectors/formula-amount.js +2 -12
- package/dist/detectors/formula-amount.js.map +1 -1
- package/dist/detectors/gram-passages.d.ts +11 -0
- package/dist/detectors/gram-passages.d.ts.map +1 -0
- package/dist/detectors/gram-passages.js +26 -0
- package/dist/detectors/gram-passages.js.map +1 -0
- package/dist/detectors/heading-claim.d.ts +14 -0
- package/dist/detectors/heading-claim.d.ts.map +1 -0
- package/dist/detectors/heading-claim.js +49 -0
- package/dist/detectors/heading-claim.js.map +1 -0
- package/dist/detectors/heading-echo.d.ts.map +1 -1
- package/dist/detectors/heading-echo.js +29 -1
- package/dist/detectors/heading-echo.js.map +1 -1
- package/dist/detectors/heading-end-mark.d.ts +8 -3
- package/dist/detectors/heading-end-mark.d.ts.map +1 -1
- package/dist/detectors/heading-end-mark.js +18 -8
- package/dist/detectors/heading-end-mark.js.map +1 -1
- package/dist/detectors/heading-names.d.ts +7 -0
- package/dist/detectors/heading-names.d.ts.map +1 -0
- package/dist/detectors/heading-names.js +24 -0
- package/dist/detectors/heading-names.js.map +1 -0
- package/dist/detectors/heading-numbering.d.ts.map +1 -1
- package/dist/detectors/heading-numbering.js +7 -2
- package/dist/detectors/heading-numbering.js.map +1 -1
- package/dist/detectors/inch-mark.d.ts +10 -0
- package/dist/detectors/inch-mark.d.ts.map +1 -0
- package/dist/detectors/inch-mark.js +48 -0
- package/dist/detectors/inch-mark.js.map +1 -0
- package/dist/detectors/installment-total-mismatch.d.ts.map +1 -1
- package/dist/detectors/installment-total-mismatch.js +2 -12
- package/dist/detectors/installment-total-mismatch.js.map +1 -1
- package/dist/detectors/lexicon.d.ts +0 -1
- package/dist/detectors/lexicon.d.ts.map +1 -1
- package/dist/detectors/lexicon.js +29 -23
- package/dist/detectors/lexicon.js.map +1 -1
- package/dist/detectors/list-parallel.d.ts +5 -2
- package/dist/detectors/list-parallel.d.ts.map +1 -1
- package/dist/detectors/list-parallel.js +45 -7
- package/dist/detectors/list-parallel.js.map +1 -1
- package/dist/detectors/mark-shape.d.ts +6 -3
- package/dist/detectors/mark-shape.d.ts.map +1 -1
- package/dist/detectors/mark-shape.js +12 -6
- package/dist/detectors/mark-shape.js.map +1 -1
- package/dist/detectors/name-variant-apart.d.ts +27 -0
- package/dist/detectors/name-variant-apart.d.ts.map +1 -0
- package/dist/detectors/name-variant-apart.js +51 -0
- package/dist/detectors/name-variant-apart.js.map +1 -0
- package/dist/detectors/name-variant.d.ts.map +1 -1
- package/dist/detectors/name-variant.js +51 -17
- package/dist/detectors/name-variant.js.map +1 -1
- package/dist/detectors/number-unit.d.ts +10 -0
- package/dist/detectors/number-unit.d.ts.map +1 -1
- package/dist/detectors/number-unit.js +28 -8
- package/dist/detectors/number-unit.js.map +1 -1
- package/dist/detectors/numeral-word.d.ts +15 -0
- package/dist/detectors/numeral-word.d.ts.map +1 -0
- package/dist/detectors/numeral-word.js +26 -0
- package/dist/detectors/numeral-word.js.map +1 -0
- package/dist/detectors/organisation-run.d.ts +14 -0
- package/dist/detectors/organisation-run.d.ts.map +1 -0
- package/dist/detectors/organisation-run.js +73 -0
- package/dist/detectors/organisation-run.js.map +1 -0
- package/dist/detectors/orthographic-variant.d.ts.map +1 -1
- package/dist/detectors/orthographic-variant.js +13 -5
- package/dist/detectors/orthographic-variant.js.map +1 -1
- package/dist/detectors/orthography.d.ts.map +1 -1
- package/dist/detectors/orthography.js +16 -7
- package/dist/detectors/orthography.js.map +1 -1
- package/dist/detectors/outline-label.d.ts +14 -0
- package/dist/detectors/outline-label.d.ts.map +1 -0
- package/dist/detectors/outline-label.js +32 -0
- package/dist/detectors/outline-label.js.map +1 -0
- package/dist/detectors/page-marker.d.ts +6 -0
- package/dist/detectors/page-marker.d.ts.map +1 -0
- package/dist/detectors/page-marker.js +19 -0
- package/dist/detectors/page-marker.js.map +1 -0
- package/dist/detectors/parallel-definition.d.ts +16 -0
- package/dist/detectors/parallel-definition.d.ts.map +1 -0
- package/dist/detectors/parallel-definition.js +51 -0
- package/dist/detectors/parallel-definition.js.map +1 -0
- package/dist/detectors/per-unit-words.d.ts +7 -0
- package/dist/detectors/per-unit-words.d.ts.map +1 -0
- package/dist/detectors/per-unit-words.js +17 -0
- package/dist/detectors/per-unit-words.js.map +1 -0
- package/dist/detectors/period-multiple-mismatch.d.ts.map +1 -1
- package/dist/detectors/period-multiple-mismatch.js +2 -12
- package/dist/detectors/period-multiple-mismatch.js.map +1 -1
- package/dist/detectors/reference-number-variant.d.ts.map +1 -1
- package/dist/detectors/reference-number-variant.js +21 -3
- package/dist/detectors/reference-number-variant.js.map +1 -1
- package/dist/detectors/reference-text.d.ts.map +1 -1
- package/dist/detectors/reference-text.js +1 -0
- package/dist/detectors/reference-text.js.map +1 -1
- package/dist/detectors/registry/condition-toki.d.ts +3 -0
- package/dist/detectors/registry/condition-toki.d.ts.map +1 -0
- package/dist/detectors/registry/condition-toki.js +3 -0
- package/dist/detectors/registry/condition-toki.js.map +1 -0
- package/dist/detectors/registry/unfilled-placeholder.d.ts.map +1 -1
- package/dist/detectors/registry/unfilled-placeholder.js +2 -2
- package/dist/detectors/registry/unfilled-placeholder.js.map +1 -1
- package/dist/detectors/registry/vague-density.js +1 -1
- package/dist/detectors/registry/vague-density.js.map +1 -1
- package/dist/detectors/rent-multiple-mismatch.d.ts.map +1 -1
- package/dist/detectors/rent-multiple-mismatch.js +2 -12
- package/dist/detectors/rent-multiple-mismatch.js.map +1 -1
- package/dist/detectors/request-owner.d.ts +6 -2
- package/dist/detectors/request-owner.d.ts.map +1 -1
- package/dist/detectors/request-owner.js +57 -7
- package/dist/detectors/request-owner.js.map +1 -1
- package/dist/detectors/requirement-smell.d.ts.map +1 -1
- package/dist/detectors/requirement-smell.js +10 -2
- package/dist/detectors/requirement-smell.js.map +1 -1
- package/dist/detectors/row-sentence-amounts.d.ts.map +1 -1
- package/dist/detectors/row-sentence-amounts.js +5 -10
- package/dist/detectors/row-sentence-amounts.js.map +1 -1
- package/dist/detectors/sentence-length.d.ts.map +1 -1
- package/dist/detectors/sentence-length.js +24 -16
- package/dist/detectors/sentence-length.js.map +1 -1
- package/dist/detectors/sentence-rhythm.d.ts.map +1 -1
- package/dist/detectors/sentence-rhythm.js +6 -3
- package/dist/detectors/sentence-rhythm.js.map +1 -1
- package/dist/detectors/series-label.d.ts +2 -1
- package/dist/detectors/series-label.d.ts.map +1 -1
- package/dist/detectors/series-label.js +10 -4
- package/dist/detectors/series-label.js.map +1 -1
- package/dist/detectors/signals.d.ts +4 -0
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +95 -36
- package/dist/detectors/signals.js.map +1 -1
- package/dist/detectors/stated-amounts.d.ts +4 -0
- package/dist/detectors/stated-amounts.d.ts.map +1 -0
- package/dist/detectors/stated-amounts.js +12 -0
- package/dist/detectors/stated-amounts.js.map +1 -0
- package/dist/detectors/step-time-sum.d.ts.map +1 -1
- package/dist/detectors/step-time-sum.js +2 -1
- package/dist/detectors/step-time-sum.js.map +1 -1
- package/dist/detectors/structure-tree.d.ts.map +1 -1
- package/dist/detectors/structure-tree.js +11 -7
- package/dist/detectors/structure-tree.js.map +1 -1
- package/dist/detectors/team.d.ts.map +1 -1
- package/dist/detectors/team.js +10 -6
- package/dist/detectors/team.js.map +1 -1
- package/dist/detectors/template-sections.d.ts +14 -0
- package/dist/detectors/template-sections.d.ts.map +1 -0
- package/dist/detectors/template-sections.js +25 -0
- package/dist/detectors/template-sections.js.map +1 -0
- package/dist/detectors/time-order.d.ts.map +1 -1
- package/dist/detectors/time-order.js +17 -13
- package/dist/detectors/time-order.js.map +1 -1
- package/dist/detectors/titled-run.d.ts +22 -0
- package/dist/detectors/titled-run.d.ts.map +1 -0
- package/dist/detectors/titled-run.js +34 -0
- package/dist/detectors/titled-run.js.map +1 -0
- package/dist/detectors/unbalanced-bracket.d.ts.map +1 -1
- package/dist/detectors/unbalanced-bracket.js +4 -0
- package/dist/detectors/unbalanced-bracket.js.map +1 -1
- package/dist/detectors/undefined-term.d.ts.map +1 -1
- package/dist/detectors/undefined-term.js +8 -0
- package/dist/detectors/undefined-term.js.map +1 -1
- package/dist/detectors/unfilled-placeholder.d.ts +4 -0
- package/dist/detectors/unfilled-placeholder.d.ts.map +1 -0
- package/dist/detectors/unfilled-placeholder.js +9 -0
- package/dist/detectors/unfilled-placeholder.js.map +1 -0
- package/dist/detectors/unknown-word.d.ts +4 -1
- package/dist/detectors/unknown-word.d.ts.map +1 -1
- package/dist/detectors/unknown-word.js +18 -2
- package/dist/detectors/unknown-word.js.map +1 -1
- package/dist/detectors/use-interval.d.ts +1 -0
- package/dist/detectors/use-interval.d.ts.map +1 -1
- package/dist/detectors/use-interval.js +15 -10
- package/dist/detectors/use-interval.js.map +1 -1
- package/dist/detectors/use-maximum.d.ts.map +1 -1
- package/dist/detectors/use-maximum.js +3 -1
- package/dist/detectors/use-maximum.js.map +1 -1
- package/dist/detectors/vague-density.d.ts +5 -0
- package/dist/detectors/vague-density.d.ts.map +1 -0
- package/dist/detectors/vague-density.js +52 -0
- package/dist/detectors/vague-density.js.map +1 -0
- package/dist/extension/document-view.d.ts +2 -2
- package/dist/extension/document-view.d.ts.map +1 -1
- package/dist/extension/document-view.js +17 -8
- package/dist/extension/document-view.js.map +1 -1
- package/dist/extension/entry-genres.d.ts +5 -0
- package/dist/extension/entry-genres.d.ts.map +1 -0
- package/dist/extension/entry-genres.js +13 -0
- package/dist/extension/entry-genres.js.map +1 -0
- package/dist/extension/module-detector.d.ts.map +1 -1
- package/dist/extension/module-detector.js +4 -4
- package/dist/extension/module-detector.js.map +1 -1
- package/dist/extension/plugin-parse.d.ts +1 -1
- package/dist/extension/plugin-parse.d.ts.map +1 -1
- package/dist/extension/plugin-parse.js +24 -7
- package/dist/extension/plugin-parse.js.map +1 -1
- package/dist/extension/problem-text.d.ts.map +1 -1
- package/dist/extension/problem-text.js +2 -0
- package/dist/extension/problem-text.js.map +1 -1
- package/dist/facts/age-values.d.ts.map +1 -1
- package/dist/facts/age-values.js +20 -2
- package/dist/facts/age-values.js.map +1 -1
- package/dist/facts/column-units.d.ts +31 -0
- package/dist/facts/column-units.d.ts.map +1 -0
- package/dist/facts/column-units.js +37 -0
- package/dist/facts/column-units.js.map +1 -0
- package/dist/facts/fact-scope.d.ts +10 -1
- package/dist/facts/fact-scope.d.ts.map +1 -1
- package/dist/facts/fact-scope.js +34 -3
- package/dist/facts/fact-scope.js.map +1 -1
- package/dist/facts/fact-values.d.ts +4 -0
- package/dist/facts/fact-values.d.ts.map +1 -1
- package/dist/facts/fact-values.js +3 -1
- package/dist/facts/fact-values.js.map +1 -1
- package/dist/facts/labelled-facts.d.ts +10 -0
- package/dist/facts/labelled-facts.d.ts.map +1 -1
- package/dist/facts/labelled-facts.js +6 -1
- package/dist/facts/labelled-facts.js.map +1 -1
- package/dist/facts/per-unit.d.ts +36 -0
- package/dist/facts/per-unit.d.ts.map +1 -0
- package/dist/facts/per-unit.js +56 -0
- package/dist/facts/per-unit.js.map +1 -0
- package/dist/facts/row-sentence-amounts.d.ts +3 -12
- package/dist/facts/row-sentence-amounts.d.ts.map +1 -1
- package/dist/facts/row-sentence-amounts.js +1 -15
- package/dist/facts/row-sentence-amounts.js.map +1 -1
- package/dist/facts/table-facts.d.ts +13 -3
- package/dist/facts/table-facts.d.ts.map +1 -1
- package/dist/facts/table-facts.js +35 -13
- package/dist/facts/table-facts.js.map +1 -1
- package/dist/facts/term-values.d.ts +13 -1
- package/dist/facts/term-values.d.ts.map +1 -1
- package/dist/facts/term-values.js +71 -12
- package/dist/facts/term-values.js.map +1 -1
- package/dist/grade/baseline.d.ts +4 -2
- package/dist/grade/baseline.d.ts.map +1 -1
- package/dist/grade/baseline.js +13 -11
- package/dist/grade/baseline.js.map +1 -1
- package/dist/grade/expect-read.d.ts +16 -0
- package/dist/grade/expect-read.d.ts.map +1 -0
- package/dist/grade/expect-read.js +52 -0
- package/dist/grade/expect-read.js.map +1 -0
- package/dist/grade/expect.d.ts +50 -0
- package/dist/grade/expect.d.ts.map +1 -0
- package/dist/grade/expect.js +53 -0
- package/dist/grade/expect.js.map +1 -0
- package/dist/grade/grade-item.d.ts +1 -1
- package/dist/grade/grade-item.d.ts.map +1 -1
- package/dist/grade/grade-item.js +13 -3
- package/dist/grade/grade-item.js.map +1 -1
- package/dist/grade/item.d.ts +9 -1
- package/dist/grade/item.d.ts.map +1 -1
- package/dist/grade/item.js +32 -7
- package/dist/grade/item.js.map +1 -1
- package/dist/grade/result.d.ts +5 -0
- package/dist/grade/result.d.ts.map +1 -1
- package/dist/grade/results-read.d.ts.map +1 -1
- package/dist/grade/results-read.js +4 -2
- package/dist/grade/results-read.js.map +1 -1
- package/dist/grade/rubric-file.d.ts +23 -0
- package/dist/grade/rubric-file.d.ts.map +1 -0
- package/dist/grade/rubric-file.js +35 -0
- package/dist/grade/rubric-file.js.map +1 -0
- package/dist/grade/rubric.d.ts +2 -0
- package/dist/grade/rubric.d.ts.map +1 -1
- package/dist/grade/rubric.js +75 -47
- package/dist/grade/rubric.js.map +1 -1
- package/dist/grade/setup.d.ts +2 -1
- package/dist/grade/setup.d.ts.map +1 -1
- package/dist/grade/setup.js +2 -2
- package/dist/grade/setup.js.map +1 -1
- package/dist/grade/stamp.d.ts +2 -0
- package/dist/grade/stamp.d.ts.map +1 -1
- package/dist/grade/stamp.js +8 -2
- package/dist/grade/stamp.js.map +1 -1
- package/dist/grade/task-rubric.d.ts +16 -0
- package/dist/grade/task-rubric.d.ts.map +1 -0
- package/dist/grade/task-rubric.js +34 -0
- package/dist/grade/task-rubric.js.map +1 -0
- package/dist/grade/text.d.ts +5 -1
- package/dist/grade/text.d.ts.map +1 -1
- package/dist/grade/text.js +16 -4
- package/dist/grade/text.js.map +1 -1
- package/dist/grade-api.d.ts +9 -2
- package/dist/grade-api.d.ts.map +1 -1
- package/dist/grade-api.js +31 -15
- package/dist/grade-api.js.map +1 -1
- package/dist/heading-numbering.d.ts +5 -2
- package/dist/heading-numbering.d.ts.map +1 -1
- package/dist/heading-numbering.js +27 -6
- package/dist/heading-numbering.js.map +1 -1
- package/dist/name-char-reading.d.ts +5 -0
- package/dist/name-char-reading.d.ts.map +1 -1
- package/dist/name-char-reading.js +15 -0
- package/dist/name-char-reading.js.map +1 -1
- package/dist/name-end-letter.d.ts +24 -0
- package/dist/name-end-letter.d.ts.map +1 -0
- package/dist/name-end-letter.js +45 -0
- package/dist/name-end-letter.js.map +1 -0
- package/dist/name-given-before.d.ts +15 -0
- package/dist/name-given-before.d.ts.map +1 -0
- package/dist/name-given-before.js +30 -0
- package/dist/name-given-before.js.map +1 -0
- package/dist/name-neighbours.d.ts.map +1 -1
- package/dist/name-neighbours.js +2 -1
- package/dist/name-neighbours.js.map +1 -1
- package/dist/name-separator.d.ts +6 -0
- package/dist/name-separator.d.ts.map +1 -1
- package/dist/name-separator.js +80 -0
- package/dist/name-separator.js.map +1 -1
- package/dist/name-variants.d.ts +8 -3
- package/dist/name-variants.d.ts.map +1 -1
- package/dist/name-variants.js +40 -12
- package/dist/name-variants.js.map +1 -1
- package/dist/name-word-order.d.ts +9 -5
- package/dist/name-word-order.d.ts.map +1 -1
- package/dist/name-word-order.js +47 -15
- package/dist/name-word-order.js.map +1 -1
- package/dist/nominal-stem.d.ts +13 -0
- package/dist/nominal-stem.d.ts.map +1 -0
- package/dist/nominal-stem.js +32 -0
- package/dist/nominal-stem.js.map +1 -0
- package/dist/number-name.d.ts.map +1 -1
- package/dist/number-name.js +11 -2
- package/dist/number-name.js.map +1 -1
- package/dist/profile/cue-lines.d.ts +6 -0
- package/dist/profile/cue-lines.d.ts.map +1 -0
- package/dist/profile/cue-lines.js +13 -0
- package/dist/profile/cue-lines.js.map +1 -0
- package/dist/profile/parse.d.ts +1 -1
- package/dist/profile/parse.d.ts.map +1 -1
- package/dist/profile/parse.js +3 -2
- package/dist/profile/parse.js.map +1 -1
- package/dist/reference-numbers.d.ts +2 -0
- package/dist/reference-numbers.d.ts.map +1 -1
- package/dist/reference-numbers.js +1 -1
- package/dist/reference-numbers.js.map +1 -1
- package/dist/sentence-load.d.ts +2 -1
- package/dist/sentence-load.d.ts.map +1 -1
- package/dist/sentence-load.js +6 -2
- package/dist/sentence-load.js.map +1 -1
- package/dist/spaced-person-name.d.ts.map +1 -1
- package/dist/spaced-person-name.js +26 -1
- package/dist/spaced-person-name.js.map +1 -1
- package/dist/spacing-code.d.ts.map +1 -1
- package/dist/spacing-code.js +10 -1
- package/dist/spacing-code.js.map +1 -1
- package/dist/spacing-minority.d.ts +7 -0
- package/dist/spacing-minority.d.ts.map +1 -1
- package/dist/spacing-minority.js +14 -0
- package/dist/spacing-minority.js.map +1 -1
- package/dist/structure/cited-document-section.d.ts +7 -0
- package/dist/structure/cited-document-section.d.ts.map +1 -0
- package/dist/structure/cited-document-section.js +33 -0
- package/dist/structure/cited-document-section.js.map +1 -0
- package/dist/structure/closing-balance.d.ts +9 -0
- package/dist/structure/closing-balance.d.ts.map +1 -1
- package/dist/structure/closing-balance.js +34 -7
- package/dist/structure/closing-balance.js.map +1 -1
- package/dist/structure/definition-use.d.ts.map +1 -1
- package/dist/structure/definition-use.js +20 -1
- package/dist/structure/definition-use.js.map +1 -1
- package/dist/structure/document-context.d.ts +2 -0
- package/dist/structure/document-context.d.ts.map +1 -0
- package/dist/structure/document-context.js +42 -0
- package/dist/structure/document-context.js.map +1 -0
- package/dist/structure/fenced-lines.d.ts +7 -0
- package/dist/structure/fenced-lines.d.ts.map +1 -0
- package/dist/structure/fenced-lines.js +27 -0
- package/dist/structure/fenced-lines.js.map +1 -0
- package/dist/structure/html-text-blocks.d.ts +8 -0
- package/dist/structure/html-text-blocks.d.ts.map +1 -0
- package/dist/structure/html-text-blocks.js +47 -0
- package/dist/structure/html-text-blocks.js.map +1 -0
- package/dist/structure/issues.d.ts +1 -1
- package/dist/structure/issues.d.ts.map +1 -1
- package/dist/structure/issues.js +19 -4
- package/dist/structure/issues.js.map +1 -1
- package/dist/structure/labelled-date-order.d.ts +34 -9
- package/dist/structure/labelled-date-order.d.ts.map +1 -1
- package/dist/structure/labelled-date-order.js +60 -15
- package/dist/structure/labelled-date-order.js.map +1 -1
- package/dist/structure/labelled-order.d.ts +10 -1
- package/dist/structure/labelled-order.d.ts.map +1 -1
- package/dist/structure/labelled-order.js +18 -6
- package/dist/structure/labelled-order.js.map +1 -1
- package/dist/structure/line-amount-label.d.ts.map +1 -1
- package/dist/structure/line-amount-label.js +2 -1
- package/dist/structure/line-amount-label.js.map +1 -1
- package/dist/structure/line-amount.d.ts +0 -5
- package/dist/structure/line-amount.d.ts.map +1 -1
- package/dist/structure/line-amount.js +1 -10
- package/dist/structure/line-amount.js.map +1 -1
- package/dist/structure/list-numbering.d.ts +20 -4
- package/dist/structure/list-numbering.d.ts.map +1 -1
- package/dist/structure/list-numbering.js +65 -9
- package/dist/structure/list-numbering.js.map +1 -1
- package/dist/structure/listed-paragraph.d.ts +16 -0
- package/dist/structure/listed-paragraph.d.ts.map +1 -0
- package/dist/structure/listed-paragraph.js +37 -0
- package/dist/structure/listed-paragraph.js.map +1 -0
- package/dist/structure/numbering.d.ts +3 -2
- package/dist/structure/numbering.d.ts.map +1 -1
- package/dist/structure/numbering.js +31 -6
- package/dist/structure/numbering.js.map +1 -1
- package/dist/structure/prose-total.d.ts +8 -0
- package/dist/structure/prose-total.d.ts.map +1 -1
- package/dist/structure/prose-total.js +70 -2
- package/dist/structure/prose-total.js.map +1 -1
- package/dist/structure/reference-text.d.ts +9 -1
- package/dist/structure/reference-text.d.ts.map +1 -1
- package/dist/structure/reference-text.js +21 -3
- package/dist/structure/reference-text.js.map +1 -1
- package/dist/structure/runs.d.ts.map +1 -1
- package/dist/structure/runs.js +9 -1
- package/dist/structure/runs.js.map +1 -1
- package/dist/structure/section-names.d.ts +12 -0
- package/dist/structure/section-names.d.ts.map +1 -0
- package/dist/structure/section-names.js +26 -0
- package/dist/structure/section-names.js.map +1 -0
- package/dist/structure/signed-date-line.d.ts +15 -0
- package/dist/structure/signed-date-line.d.ts.map +1 -0
- package/dist/structure/signed-date-line.js +68 -0
- package/dist/structure/signed-date-line.js.map +1 -0
- package/dist/structure/tax.d.ts.map +1 -1
- package/dist/structure/tax.js +5 -3
- package/dist/structure/tax.js.map +1 -1
- package/dist/structure/total-line.d.ts.map +1 -1
- package/dist/structure/total-line.js +10 -6
- package/dist/structure/total-line.js.map +1 -1
- package/dist/structure/total.d.ts +2 -0
- package/dist/structure/total.d.ts.map +1 -1
- package/dist/structure/total.js +34 -3
- package/dist/structure/total.js.map +1 -1
- package/dist/structure/versioned-label.d.ts +16 -0
- package/dist/structure/versioned-label.d.ts.map +1 -0
- package/dist/structure/versioned-label.js +48 -0
- package/dist/structure/versioned-label.js.map +1 -0
- package/dist/structure/written-headings.d.ts +31 -0
- package/dist/structure/written-headings.d.ts.map +1 -0
- package/dist/structure/written-headings.js +119 -0
- package/dist/structure/written-headings.js.map +1 -0
- package/dist/structure/written-resolve.d.ts +12 -0
- package/dist/structure/written-resolve.d.ts.map +1 -0
- package/dist/structure/written-resolve.js +49 -0
- package/dist/structure/written-resolve.js.map +1 -0
- package/dist/subject-codes.d.ts +21 -0
- package/dist/subject-codes.d.ts.map +1 -0
- package/dist/subject-codes.js +79 -0
- package/dist/subject-codes.js.map +1 -0
- package/dist/unlabelled-references.d.ts +6 -2
- package/dist/unlabelled-references.d.ts.map +1 -1
- package/dist/unlabelled-references.js +11 -10
- package/dist/unlabelled-references.js.map +1 -1
- package/genres.yaml +17 -0
- package/package.json +3 -3
- package/profiles/listing.yaml +1 -1
- package/rules/all-caps-shouting.yaml +2 -2
- package/rules/closing-balance-mismatch.yaml +3 -3
- package/rules/concrete-evidence-density.yaml +2 -2
- package/rules/contraction-consistency.yaml +13 -13
- package/rules/dangling-reference.yaml +2 -2
- package/rules/date-without-year.yaml +2 -2
- package/rules/defined-name-repeated.yaml +2 -2
- package/rules/due-before-issue.yaml +9 -5
- package/rules/fact-conflict.yaml +2 -2
- package/rules/heading-echo.yaml +2 -2
- package/rules/heading-end-punctuation-mix.yaml +2 -2
- package/rules/heading-numbering-mix.yaml +2 -2
- package/rules/internal-jargon.yaml +2 -2
- package/rules/latin-spacing.yaml +4 -4
- package/rules/list-item-form-mix.yaml +1 -1
- package/rules/max-kanji-continuous.yaml +5 -3
- package/rules/max-sentence-length.yaml +3 -2
- package/rules/name-variant.yaml +5 -2
- package/rules/ngram-repetition.yaml +2 -2
- package/rules/no-lead.yaml +2 -2
- package/rules/number-without-unit.yaml +2 -2
- package/rules/numbering-gap.yaml +2 -2
- package/rules/orthographic-variant.yaml +2 -2
- package/rules/reference-number-variant.yaml +3 -3
- package/rules/reference-title-mismatch.yaml +2 -2
- package/rules/repeated-sentence-ending.yaml +3 -2
- package/rules/request-without-deadline.yaml +2 -2
- package/rules/requirement-smell.yaml +2 -2
- package/rules/sentence-rhythm.yaml +2 -2
- package/rules/title-case-consistency.yaml +2 -2
- package/rules/toki-as-condition.yaml +71 -0
- package/rules/total-mismatch.yaml +4 -4
- package/rules/unbalanced-bracket.yaml +2 -2
- package/rules/undefined-acronym.yaml +11 -2
- package/rules/undefined-term.yaml +2 -2
- package/rules/unfilled-placeholder.yaml +2 -2
- package/rules/unknown-word.yaml +2 -2
- package/rules/use-before-definition.yaml +2 -2
- package/rules/vague-word-density.yaml +2 -2
- package/src/api.ts +11 -2
- package/src/capitals-passage.ts +31 -0
- package/src/cli-text.ts +4 -2
- package/src/coined-hyphen-name.ts +27 -0
- package/src/commands/grade.ts +75 -23
- package/src/company-kana-spelling.ts +22 -2
- package/src/company-name-ending.ts +50 -0
- package/src/company-names.ts +76 -20
- package/src/custom/no-rewrite.ts +2 -0
- package/src/custom/parse.ts +18 -2
- package/src/detectors/acronym-context.ts +5 -6
- package/src/detectors/acronym-definition.ts +123 -0
- package/src/detectors/acronym-lone.ts +26 -0
- package/src/detectors/acronym-name.ts +117 -0
- package/src/detectors/age-words.ts +12 -0
- package/src/detectors/annual-pay-mismatch.ts +3 -18
- package/src/detectors/blank-structure.ts +4 -3
- package/src/detectors/capitalised-term.ts +154 -4
- package/src/detectors/caps-caption.ts +61 -0
- package/src/detectors/char-shape.ts +74 -22
- package/src/detectors/clause-shape.ts +14 -4
- package/src/detectors/closing-balance-mismatch.ts +1 -0
- package/src/detectors/code-fences.ts +10 -0
- package/src/detectors/concrete-evidence.ts +77 -1
- package/src/detectors/condition-toki.ts +60 -0
- package/src/detectors/conjugated-entry.ts +53 -0
- package/src/detectors/content-morphemes.ts +2 -1
- package/src/detectors/contraction-minority.ts +11 -0
- package/src/detectors/counter-edge.ts +23 -0
- package/src/detectors/cross-facts.ts +2 -1
- package/src/detectors/custom.ts +9 -2
- package/src/detectors/date-any-year.ts +56 -10
- package/src/detectors/date-heading-year.ts +55 -0
- package/src/detectors/date-year.ts +54 -9
- package/src/detectors/defined-term-form.ts +26 -5
- package/src/detectors/document-shape.ts +8 -0
- package/src/detectors/due-date.ts +26 -7
- package/src/detectors/en-shape.ts +5 -1
- package/src/detectors/fact-consistency.ts +16 -19
- package/src/detectors/form-line.ts +47 -0
- package/src/detectors/formula-amount.ts +2 -18
- package/src/detectors/gram-passages.ts +36 -0
- package/src/detectors/heading-claim.ts +76 -0
- package/src/detectors/heading-echo.ts +32 -1
- package/src/detectors/heading-end-mark.ts +23 -10
- package/src/detectors/heading-names.ts +31 -0
- package/src/detectors/heading-numbering.ts +7 -2
- package/src/detectors/inch-mark.ts +49 -0
- package/src/detectors/installment-total-mismatch.ts +3 -18
- package/src/detectors/lexicon.ts +32 -21
- package/src/detectors/list-parallel.ts +46 -7
- package/src/detectors/mark-shape.ts +12 -6
- package/src/detectors/name-variant-apart.ts +63 -0
- package/src/detectors/name-variant.ts +73 -18
- package/src/detectors/number-unit.ts +35 -9
- package/src/detectors/numeral-word.ts +33 -0
- package/src/detectors/organisation-run.ts +86 -0
- package/src/detectors/orthographic-variant.ts +22 -6
- package/src/detectors/orthography.ts +17 -8
- package/src/detectors/outline-label.ts +48 -0
- package/src/detectors/page-marker.ts +26 -0
- package/src/detectors/parallel-definition.ts +64 -0
- package/src/detectors/per-unit-words.ts +24 -0
- package/src/detectors/period-multiple-mismatch.ts +2 -18
- package/src/detectors/reference-number-variant.ts +27 -5
- package/src/detectors/reference-text.ts +1 -0
- package/src/detectors/registry/condition-toki.ts +4 -0
- package/src/detectors/registry/unfilled-placeholder.ts +2 -2
- package/src/detectors/registry/vague-density.ts +1 -1
- package/src/detectors/rent-multiple-mismatch.ts +2 -18
- package/src/detectors/request-owner.ts +71 -8
- package/src/detectors/requirement-smell.ts +15 -2
- package/src/detectors/row-sentence-amounts.ts +5 -20
- package/src/detectors/sentence-length.ts +14 -6
- package/src/detectors/sentence-rhythm.ts +8 -4
- package/src/detectors/series-label.ts +13 -4
- package/src/detectors/signals.ts +94 -26
- package/src/detectors/stated-amounts.ts +20 -0
- package/src/detectors/step-time-sum.ts +2 -1
- package/src/detectors/structure-tree.ts +13 -8
- package/src/detectors/team.ts +13 -7
- package/src/detectors/template-sections.ts +37 -0
- package/src/detectors/time-order.ts +6 -3
- package/src/detectors/titled-run.ts +43 -0
- package/src/detectors/unbalanced-bracket.ts +3 -0
- package/src/detectors/undefined-term.ts +8 -0
- package/src/detectors/unfilled-placeholder.ts +10 -0
- package/src/detectors/unknown-word.ts +20 -2
- package/src/detectors/use-interval.ts +8 -4
- package/src/detectors/use-maximum.ts +3 -1
- package/src/detectors/vague-density.ts +68 -0
- package/src/extension/document-view.ts +18 -9
- package/src/extension/entry-genres.ts +15 -0
- package/src/extension/module-detector.ts +9 -4
- package/src/extension/plugin-parse.ts +29 -7
- package/src/extension/problem-text.ts +4 -0
- package/src/facts/age-values.ts +24 -2
- package/src/facts/column-units.ts +67 -0
- package/src/facts/fact-scope.ts +53 -4
- package/src/facts/fact-values.ts +11 -1
- package/src/facts/labelled-facts.ts +16 -2
- package/src/facts/per-unit.ts +105 -0
- package/src/facts/row-sentence-amounts.ts +4 -26
- package/src/facts/table-facts.ts +50 -10
- package/src/facts/term-values.ts +94 -13
- package/src/grade/baseline.ts +20 -12
- package/src/grade/expect-read.ts +65 -0
- package/src/grade/expect.ts +74 -0
- package/src/grade/grade-item.ts +14 -3
- package/src/grade/item.ts +48 -8
- package/src/grade/result.ts +5 -0
- package/src/grade/results-read.ts +7 -2
- package/src/grade/rubric-file.ts +46 -0
- package/src/grade/rubric.ts +77 -47
- package/src/grade/setup.ts +3 -3
- package/src/grade/stamp.ts +10 -2
- package/src/grade/task-rubric.ts +39 -0
- package/src/grade/text.ts +27 -5
- package/src/grade-api.ts +38 -16
- package/src/heading-numbering.ts +35 -8
- package/src/name-char-reading.ts +16 -0
- package/src/name-end-letter.ts +61 -0
- package/src/name-given-before.ts +40 -0
- package/src/name-neighbours.ts +2 -1
- package/src/name-separator.ts +93 -0
- package/src/name-variants.ts +69 -18
- package/src/name-word-order.ts +62 -17
- package/src/nominal-stem.ts +36 -0
- package/src/number-name.ts +12 -3
- package/src/profile/cue-lines.ts +14 -0
- package/src/profile/parse.ts +3 -2
- package/src/reference-numbers.ts +1 -1
- package/src/sentence-load.ts +7 -2
- package/src/spaced-person-name.ts +27 -2
- package/src/spacing-code.ts +13 -2
- package/src/spacing-minority.ts +17 -0
- package/src/structure/cited-document-section.ts +42 -0
- package/src/structure/closing-balance.ts +46 -8
- package/src/structure/definition-use.ts +24 -1
- package/src/structure/document-context.ts +46 -0
- package/src/structure/fenced-lines.ts +28 -0
- package/src/structure/html-text-blocks.ts +45 -0
- package/src/structure/issues.ts +19 -4
- package/src/structure/labelled-date-order.ts +108 -21
- package/src/structure/labelled-order.ts +33 -13
- package/src/structure/line-amount-label.ts +2 -1
- package/src/structure/line-amount.ts +1 -11
- package/src/structure/list-numbering.ts +100 -11
- package/src/structure/listed-paragraph.ts +45 -0
- package/src/structure/numbering.ts +48 -19
- package/src/structure/prose-total.ts +81 -2
- package/src/structure/reference-text.ts +25 -3
- package/src/structure/runs.ts +10 -1
- package/src/structure/section-names.ts +32 -0
- package/src/structure/signed-date-line.ts +78 -0
- package/src/structure/tax.ts +6 -3
- package/src/structure/total-line.ts +12 -6
- package/src/structure/total.ts +42 -3
- package/src/structure/versioned-label.ts +52 -0
- package/src/structure/written-headings.ts +137 -0
- package/src/structure/written-resolve.ts +57 -0
- package/src/subject-codes.ts +105 -0
- package/src/unlabelled-references.ts +24 -16
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Atom } from "../compare/atom.ts";
|
|
2
|
+
import { outcomeOf, type Compared } from "../compare/outcome.ts";
|
|
3
|
+
|
|
4
|
+
// An item's known answer (`expect`): facts the output must state and facts it must not. Pure: the shape of the field,
|
|
5
|
+
// which one fact an entry states, and whether the output states it, decided as `chaff compare --distinct` decides it.
|
|
6
|
+
|
|
7
|
+
export type GradeExpect = { readonly facts: readonly string[]; readonly absent: readonly string[] };
|
|
8
|
+
|
|
9
|
+
export const EXPECT_LISTS = ["facts", "absent"] as const;
|
|
10
|
+
|
|
11
|
+
export type ExpectList = (typeof EXPECT_LISTS)[number];
|
|
12
|
+
|
|
13
|
+
const isExpectList = (key: string): key is ExpectList => EXPECT_LISTS.some((list) => list === key);
|
|
14
|
+
|
|
15
|
+
const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16
|
+
|
|
17
|
+
const isEntryList = (value: unknown): value is string[] => Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.trim() !== "");
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The field as written, or the path of its first wrong part. A key other than facts and absent is wrong, not ignored:
|
|
21
|
+
* a misspelt list would check nothing and pass every output. A missing list is an empty one.
|
|
22
|
+
*/
|
|
23
|
+
export const expectOf = (raw: unknown): { readonly expect: GradeExpect | undefined } | { readonly wrong: string } => {
|
|
24
|
+
if (raw === undefined) return { expect: undefined };
|
|
25
|
+
if (!isRecord(raw)) return { wrong: "expect" };
|
|
26
|
+
const unknown = Object.keys(raw).find((key) => !isExpectList(key));
|
|
27
|
+
if (unknown !== undefined) return { wrong: `expect.${unknown}` };
|
|
28
|
+
const wrongList = EXPECT_LISTS.find((list) => raw[list] !== undefined && !isEntryList(raw[list]));
|
|
29
|
+
if (wrongList !== undefined) return { wrong: `expect.${wrongList}` };
|
|
30
|
+
const listOf = (list: ExpectList): readonly string[] => {
|
|
31
|
+
const value = raw[list];
|
|
32
|
+
return isEntryList(value) ? value : [];
|
|
33
|
+
};
|
|
34
|
+
return { expect: { facts: listOf("facts"), absent: listOf("absent") } };
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** The one fact an entry states, or why it states none or several. */
|
|
38
|
+
export type EntryFact = { readonly fact: Atom } | { readonly unread: "no-fact" | "several-facts" };
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The fact an entry states. Several facts are one when exactly one of them is the whole entry: a quotation 「12,000円」
|
|
42
|
+
* is read as the quotation and the number inside it, and the entry means the quotation.
|
|
43
|
+
*/
|
|
44
|
+
export const factOfEntry = (entry: string, atoms: readonly Atom[]): EntryFact => {
|
|
45
|
+
const [only] = atoms;
|
|
46
|
+
if (atoms.length === 1 && only !== undefined) return { fact: only };
|
|
47
|
+
if (atoms.length === 0) return { unread: "no-fact" };
|
|
48
|
+
const whole = atoms.filter((atom) => atom.text === entry.trim());
|
|
49
|
+
const [wholeOnly] = whole;
|
|
50
|
+
return whole.length === 1 && wholeOnly !== undefined ? { fact: wholeOnly } : { unread: "several-facts" };
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** Where an entry is in the item: `expect.facts[0]`. */
|
|
54
|
+
export const entryPath = (list: ExpectList, index: number): string => `expect.${list}[${String(index)}]`;
|
|
55
|
+
|
|
56
|
+
/** One entry as read: its list, its place, its text, and its document's facts with only the entry's fact kept. */
|
|
57
|
+
export type ReadEntry = { readonly list: ExpectList; readonly index: number; readonly entry: string; readonly read: Compared };
|
|
58
|
+
|
|
59
|
+
/** An entry that states one fact, compared as compare compares two documents: the output states it at least once. */
|
|
60
|
+
export const statesFact = (entry: Compared, output: Compared): boolean => outcomeOf(entry, output, undefined, "distinct").dropped.length === 0;
|
|
61
|
+
|
|
62
|
+
/** What the output was checked against: how many entries, the facts it does not state, and the absent ones it does. */
|
|
63
|
+
export type GradeExpectResult = { readonly checked: number; readonly missing: readonly string[]; readonly present: readonly string[] };
|
|
64
|
+
|
|
65
|
+
/** Each entry against the output, by the entry's text as written in the item. */
|
|
66
|
+
export const expectAgainst = (entries: readonly ReadEntry[], output: Compared): GradeExpectResult => ({
|
|
67
|
+
checked: entries.length,
|
|
68
|
+
missing: entries.filter((entry) => entry.list === "facts" && !statesFact(entry.read, output)).map((entry) => entry.entry),
|
|
69
|
+
present: entries.filter((entry) => entry.list === "absent" && statesFact(entry.read, output)).map((entry) => entry.entry),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/** The failure reasons: `expect.missing 12,000円`, `expect.present 15,000円`. Absent when the item had no expect. */
|
|
73
|
+
export const expectFailures = (result: GradeExpectResult | undefined): string[] =>
|
|
74
|
+
result === undefined ? [] : [...result.missing.map((entry) => `expect.missing ${entry}`), ...result.present.map((entry) => `expect.present ${entry}`)];
|
package/src/grade/grade-item.ts
CHANGED
|
@@ -10,11 +10,14 @@ import { ratesOf, sizeOf, type OutputSize } from "./rates.ts";
|
|
|
10
10
|
import type { GradeCitations, GradeFacts, GradeFinding, GradeResult, GradeScore, NotRunEntry, Stamp } from "./result.ts";
|
|
11
11
|
import type { Rubric } from "./rubric.ts";
|
|
12
12
|
import { rubricVerdict } from "./rubric-verdict.ts";
|
|
13
|
+
import { rubricForTask } from "./task-rubric.ts";
|
|
13
14
|
import type { GradeSettings } from "./stamp.ts";
|
|
14
15
|
import { GRADE_TEXT } from "./text.ts";
|
|
15
16
|
import { aiScoreOfDocument } from "../ai-score/of-document.ts";
|
|
16
17
|
import { gradeAiScoreOf } from "./ai-score.ts";
|
|
17
|
-
import { defaultVerdict, type Verdict } from "./verdict.ts";
|
|
18
|
+
import { defaultVerdict, verdictOf, type Verdict } from "./verdict.ts";
|
|
19
|
+
import { expectFailures, type GradeExpectResult } from "./expect.ts";
|
|
20
|
+
import { expectOfItem } from "./expect-read.ts";
|
|
18
21
|
|
|
19
22
|
/** One run's settings, its `grade:` rubric when chaff.yaml has one, and its stamp, which every result carries. */
|
|
20
23
|
export type GradeSetup = GradeSettings & { readonly stamp: Stamp; readonly rubric?: Rubric | undefined };
|
|
@@ -34,6 +37,7 @@ type Checked = {
|
|
|
34
37
|
readonly facts: GradeFacts | null;
|
|
35
38
|
readonly cited: CitationsRead | undefined;
|
|
36
39
|
readonly contexts: ContextsRead | undefined;
|
|
40
|
+
readonly expect: GradeExpectResult | undefined;
|
|
37
41
|
};
|
|
38
42
|
|
|
39
43
|
const checkItem = async (item: GradeItem, setup: GradeSetup): Promise<Checked> => {
|
|
@@ -50,6 +54,7 @@ const checkItem = async (item: GradeItem, setup: GradeSetup): Promise<Checked> =
|
|
|
50
54
|
facts: item.reference === undefined ? null : await factsAgainst(texts, reading, allowedBy(setup.rubric)),
|
|
51
55
|
cited: item.citations === undefined ? undefined : await citationsAgainst(item, item.citations, reading, ui),
|
|
52
56
|
contexts: await contextsOf(item, check.language, reading, setup.rubric),
|
|
57
|
+
expect: await expectOfItem(item, { ...reading, language: check.language }),
|
|
53
58
|
};
|
|
54
59
|
};
|
|
55
60
|
|
|
@@ -97,12 +102,17 @@ const judge = (item: GradeItem, checked: Checked, setup: GradeSetup): { readonly
|
|
|
97
102
|
};
|
|
98
103
|
|
|
99
104
|
/** Grades one output (spec §29.3): its findings and their rates, the facts against its reference, its quotations, and pass or fail. */
|
|
100
|
-
export const gradeItem = async (item: GradeItem,
|
|
105
|
+
export const gradeItem = async (item: GradeItem, runSetup: GradeSetup): Promise<GradeResult> => {
|
|
106
|
+
const setup = item.task === undefined ? runSetup : { ...runSetup, rubric: rubricForTask(runSetup.rubric, item.task) };
|
|
101
107
|
const checked = await checkItem(item, setup);
|
|
102
|
-
const
|
|
108
|
+
const judged = judge(item, checked, setup);
|
|
109
|
+
const { score } = judged;
|
|
110
|
+
// expect is the item's own answer, so it fails the output with or without a `grade:` rubric.
|
|
111
|
+
const verdict = verdictOf([...judged.verdict.failedBecause, ...expectFailures(checked.expect)]);
|
|
103
112
|
return {
|
|
104
113
|
id: item.id,
|
|
105
114
|
...(item.variant === undefined ? {} : { variant: item.variant }),
|
|
115
|
+
...(item.task === undefined ? {} : { task: item.task }),
|
|
106
116
|
language: checked.check.language,
|
|
107
117
|
genre: checked.check.genre.genre,
|
|
108
118
|
size: checked.size,
|
|
@@ -115,6 +125,7 @@ export const gradeItem = async (item: GradeItem, setup: GradeSetup): Promise<Gra
|
|
|
115
125
|
facts: checked.facts,
|
|
116
126
|
citations: citationsOf(checked),
|
|
117
127
|
...(checked.contexts === undefined ? {} : { contexts: checked.contexts.contexts }),
|
|
128
|
+
...(checked.expect === undefined ? {} : { expect: checked.expect }),
|
|
118
129
|
...(score === undefined ? {} : { score }),
|
|
119
130
|
aiScore: gradeAiScoreOf(aiScoreOfDocument(checked.check.doc, checked.check.rules, checked.check.genre.genre)),
|
|
120
131
|
pass: verdict.pass,
|
package/src/grade/item.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// One line of `chaff grade`'s input: a model's output and what to check it against. Pure: reads text, returns items
|
|
2
2
|
// or what is wrong with them, so a harness that writes the file can be told which line to fix.
|
|
3
|
+
import { expectOf, type GradeExpect } from "./expect.ts";
|
|
3
4
|
import { resultKey } from "./result-name.ts";
|
|
4
5
|
|
|
5
6
|
export type GradeCitation = { readonly source: string; readonly address: string; readonly quote: string };
|
|
@@ -18,10 +19,14 @@ export type GradeItem = {
|
|
|
18
19
|
readonly contexts?: readonly string[] | undefined;
|
|
19
20
|
/** The prompt, model or setting that produced this output. Outputs of several variants are compared on the same ids. */
|
|
20
21
|
readonly variant?: string | undefined;
|
|
22
|
+
/** The rubric task this item is graded under (`grade.tasks.<name>`). Undefined: the top-level rubric. */
|
|
23
|
+
readonly task?: string | undefined;
|
|
24
|
+
/** Facts the output must state and facts it must not: a question's known answer. Undefined when not given. */
|
|
25
|
+
readonly expect?: GradeExpect | undefined;
|
|
21
26
|
};
|
|
22
27
|
|
|
23
28
|
/** The fields an item already has a meaning for: none of them can name a variant. */
|
|
24
|
-
export const ITEM_FIELDS: readonly string[] = ["id", "output", "reference", "sources", "citations", "contexts", "language", "genre"];
|
|
29
|
+
export const ITEM_FIELDS: readonly string[] = ["id", "output", "reference", "sources", "citations", "contexts", "language", "genre", "expect", "task"];
|
|
25
30
|
|
|
26
31
|
/** Which field names an output's variant, and whether every line must have it (the key was given on the command line). */
|
|
27
32
|
export type VariantField = { readonly key: string; readonly required: boolean };
|
|
@@ -44,13 +49,22 @@ export type ItemProblemKind =
|
|
|
44
49
|
| "which-source"
|
|
45
50
|
| "unknown-language"
|
|
46
51
|
| "unknown-genre"
|
|
52
|
+
| "not-expect"
|
|
53
|
+
| "expect-no-fact"
|
|
54
|
+
| "expect-several-facts"
|
|
55
|
+
| "unknown-task"
|
|
47
56
|
| "empty";
|
|
48
57
|
|
|
49
58
|
/** Why a line cannot be graded. `detail`: the field, the value or the parser's message; `first`: the line an id was first on. */
|
|
50
59
|
export type ItemProblem = { readonly kind: ItemProblemKind; readonly line: number; readonly detail?: string; readonly first?: number };
|
|
51
60
|
|
|
52
61
|
/** What an item may name: the languages chaff can load and the genres it knows. */
|
|
53
|
-
export type ItemVocabulary = {
|
|
62
|
+
export type ItemVocabulary = {
|
|
63
|
+
readonly isLanguage: (language: string) => boolean;
|
|
64
|
+
readonly genres: readonly string[];
|
|
65
|
+
/** The tasks the rubric defines. None given: an item naming a task is refused, as there is no rubric for it. */
|
|
66
|
+
readonly tasks?: readonly string[] | undefined;
|
|
67
|
+
};
|
|
54
68
|
|
|
55
69
|
const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
56
70
|
|
|
@@ -129,6 +143,27 @@ const variantOf = (raw: Record<string, unknown>, key: string, line: number): Par
|
|
|
129
143
|
return typeof value === "string" && value !== "" ? { value } : { problem: { kind: "not-string", line, detail: key } };
|
|
130
144
|
};
|
|
131
145
|
|
|
146
|
+
/** The item's task: a non-empty string the rubric defines, or none. Never a silent fall back to the top-level rubric. */
|
|
147
|
+
const taskOf = (raw: unknown, vocabulary: ItemVocabulary, line: number): Parsed<string | undefined> => {
|
|
148
|
+
if (raw === undefined) return { value: undefined };
|
|
149
|
+
if (typeof raw !== "string" || raw === "") return { problem: { kind: "not-string", line, detail: "task" } };
|
|
150
|
+
return (vocabulary.tasks ?? []).includes(raw) ? { value: raw } : { problem: { kind: "unknown-task", line, detail: raw } };
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/** The item's variant and task, each written only when given, checked in that order. */
|
|
154
|
+
const labelsOf = (
|
|
155
|
+
raw: Record<string, unknown>,
|
|
156
|
+
line: number,
|
|
157
|
+
vocabulary: ItemVocabulary,
|
|
158
|
+
variantKey: string,
|
|
159
|
+
): Parsed<{ readonly variant?: string; readonly task?: string }> => {
|
|
160
|
+
const variant = variantOf(raw, variantKey, line);
|
|
161
|
+
if ("problem" in variant) return variant;
|
|
162
|
+
const task = taskOf(raw["task"], vocabulary, line);
|
|
163
|
+
if ("problem" in task) return task;
|
|
164
|
+
return { value: { ...(variant.value === undefined ? {} : { variant: variant.value }), ...(task.value === undefined ? {} : { task: task.value }) } };
|
|
165
|
+
};
|
|
166
|
+
|
|
132
167
|
const itemOf = (raw: Record<string, unknown>, line: number, vocabulary: ItemVocabulary, variantKey: string): Parsed<GradeItem> => {
|
|
133
168
|
const id = raw["id"];
|
|
134
169
|
if (typeof id !== "string" || id === "") return { problem: { kind: "no-id", line } };
|
|
@@ -138,17 +173,22 @@ const itemOf = (raw: Record<string, unknown>, line: number, vocabulary: ItemVoca
|
|
|
138
173
|
if ("problem" in fields) return fields;
|
|
139
174
|
const unknown = vocabularyProblem(fields.value, vocabulary, line);
|
|
140
175
|
if (unknown !== undefined) return { problem: unknown };
|
|
141
|
-
const
|
|
142
|
-
if ("problem" in
|
|
176
|
+
const labels = labelsOf(raw, line, vocabulary, variantKey);
|
|
177
|
+
if ("problem" in labels) return labels;
|
|
143
178
|
const sources = sourcesOf(raw["sources"], line);
|
|
144
179
|
if ("problem" in sources) return sources;
|
|
145
180
|
const citations = citationsOf(raw["citations"], sources.value, line);
|
|
146
181
|
if ("problem" in citations) return citations;
|
|
147
182
|
const contexts = contextsOf(raw["contexts"], line);
|
|
148
183
|
if ("problem" in contexts) return contexts;
|
|
184
|
+
const expect = expectOf(raw["expect"]);
|
|
185
|
+
if ("wrong" in expect) return { problem: { kind: "not-expect", line, detail: expect.wrong } };
|
|
149
186
|
const passages = contexts.value === undefined ? {} : { contexts: contexts.value };
|
|
150
|
-
const
|
|
151
|
-
|
|
187
|
+
const expected = expect.expect === undefined ? {} : { expect: expect.expect };
|
|
188
|
+
const { variant, task } = labels.value;
|
|
189
|
+
const labelled = variant === undefined ? {} : { variant };
|
|
190
|
+
const tasked = task === undefined ? {} : { task };
|
|
191
|
+
return { value: { id, output, ...fields.value, sources: sources.value, citations: citations.value, ...passages, ...labelled, ...expected, ...tasked } };
|
|
152
192
|
};
|
|
153
193
|
|
|
154
194
|
/** One item from a value already parsed, as `grade()` receives it; `line` is 0 when it came from no file. */
|
|
@@ -192,7 +232,7 @@ export const parseItems = (
|
|
|
192
232
|
text: string,
|
|
193
233
|
vocabulary: ItemVocabulary,
|
|
194
234
|
variantField: VariantField = DEFAULT_VARIANT_FIELD,
|
|
195
|
-
): { readonly items: readonly GradeItem[] } | { readonly problems: readonly ItemProblem[] } => {
|
|
235
|
+
): { readonly items: readonly GradeItem[]; readonly lines: readonly number[] } | { readonly problems: readonly ItemProblem[] } => {
|
|
196
236
|
const lines = text.split(/\r?\n/u).map((body, index) => ({ body, line: index + 1 }));
|
|
197
237
|
const parsed = lines
|
|
198
238
|
.filter(({ body }) => body.trim() !== "")
|
|
@@ -204,5 +244,5 @@ export const parseItems = (
|
|
|
204
244
|
...unlabelled(read, variantField),
|
|
205
245
|
];
|
|
206
246
|
if (problems.length > 0) return { problems: problems.toSorted((left, right) => left.line - right.line) };
|
|
207
|
-
return read.length === 0 ? { problems: [{ kind: "empty", line: 0 }] } : { items: read.map((entry) => entry.item) };
|
|
247
|
+
return read.length === 0 ? { problems: [{ kind: "empty", line: 0 }] } : { items: read.map((entry) => entry.item), lines: read.map((entry) => entry.line) };
|
|
208
248
|
};
|
package/src/grade/result.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { CitationStatus } from "../structure/cite.ts";
|
|
|
3
3
|
import type { Severity } from "../plugin.ts";
|
|
4
4
|
import type { OutputSize } from "./rates.ts";
|
|
5
5
|
import type { GradeAiScore } from "./ai-score.ts";
|
|
6
|
+
import type { GradeExpectResult } from "./expect.ts";
|
|
6
7
|
|
|
7
8
|
// The shape of one line of `chaff grade --out`, and of what `grade()` returns. Spec §29.3.
|
|
8
9
|
|
|
@@ -62,6 +63,8 @@ export type GradeResult = {
|
|
|
62
63
|
readonly id: string;
|
|
63
64
|
/** The item's variant label, when it had one. */
|
|
64
65
|
readonly variant?: string | undefined;
|
|
66
|
+
/** The rubric task the output was graded under, when the item named one. */
|
|
67
|
+
readonly task?: string | undefined;
|
|
65
68
|
readonly language: string;
|
|
66
69
|
readonly genre: string;
|
|
67
70
|
readonly size: OutputSize;
|
|
@@ -74,6 +77,8 @@ export type GradeResult = {
|
|
|
74
77
|
readonly citations: GradeCitations | null;
|
|
75
78
|
/** Only when the item gave contexts, so results of items without them keep their shape. */
|
|
76
79
|
readonly contexts?: GradeContexts | undefined;
|
|
80
|
+
/** Only when the item gave expect: the entries checked, the facts not stated and the absent ones stated. */
|
|
81
|
+
readonly expect?: GradeExpectResult | undefined;
|
|
77
82
|
/** Only with a `grade:` rubric. */
|
|
78
83
|
readonly score?: GradeScore | undefined;
|
|
79
84
|
/** The AI-likeness quick score. Absent only in results written before it existed. Never part of pass or fail. */
|
|
@@ -72,8 +72,13 @@ const isRates = (value: unknown): boolean => isRecord(value) && Object.values(va
|
|
|
72
72
|
/** The id, and the variant when the output had one. */
|
|
73
73
|
const isLabel = (value: Record<string, unknown>): boolean => isString(value["id"]) && (value["variant"] === undefined || isString(value["variant"]));
|
|
74
74
|
|
|
75
|
-
/**
|
|
76
|
-
const
|
|
75
|
+
/** Absent when the item gave no expect. */
|
|
76
|
+
const isExpect = (value: unknown): boolean =>
|
|
77
|
+
value === undefined || (isRecord(value) && isNumber(value["checked"]) && isArrayOf(value["missing"], isString) && isArrayOf(value["present"], isString));
|
|
78
|
+
|
|
79
|
+
/** The parts a result carries only sometimes: contexts, expect, a rubric's score, the quick score. Each is checked when present. */
|
|
80
|
+
const hasOptionalParts = (value: Record<string, unknown>): boolean =>
|
|
81
|
+
isContexts(value["contexts"]) && isExpect(value["expect"]) && isScore(value["score"]) && isAiScore(value["aiScore"]);
|
|
77
82
|
|
|
78
83
|
/** A line `--out` writes, every field checked: a line that only looks like one would be compared as if it had been graded. */
|
|
79
84
|
export const isGradeResult = (value: unknown): value is GradeResult =>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { extname } from "node:path";
|
|
3
|
+
import { parse } from "yaml";
|
|
4
|
+
import { parseRubric, type Rubric, type RubricProblem } from "./rubric.ts";
|
|
5
|
+
|
|
6
|
+
// A rubric file given with `chaff grade --rubric <file>`: the schema of chaff.yaml's `grade:`, at the file's top level.
|
|
7
|
+
// Pure: the caller reads the file. Its paths drop the `grade.` prefix, because in the file they start at the top.
|
|
8
|
+
|
|
9
|
+
type Format = "yaml" | "json";
|
|
10
|
+
|
|
11
|
+
const FORMATS: Readonly<Record<string, Format>> = { ".yaml": "yaml", ".yml": "yaml", ".json": "json" };
|
|
12
|
+
|
|
13
|
+
export type RubricFileProblem =
|
|
14
|
+
{ readonly kind: "format" } | { readonly kind: "syntax"; readonly why: string } | { readonly kind: "rubric"; readonly problem: RubricProblem };
|
|
15
|
+
|
|
16
|
+
export type RubricFile = { readonly rubric: Rubric; readonly digest: string } | { readonly problems: readonly RubricFileProblem[] };
|
|
17
|
+
|
|
18
|
+
const formatOf = (path: string): Format | undefined => FORMATS[extname(path).toLowerCase()];
|
|
19
|
+
|
|
20
|
+
const syntaxOf = (content: string, format: Format): { readonly raw: unknown } | { readonly why: string } => {
|
|
21
|
+
try {
|
|
22
|
+
// An empty file reads as null in YAML but throws in JSON; both are an empty rubric, as a bare `grade:` is.
|
|
23
|
+
if (content.trim() === "") return { raw: null };
|
|
24
|
+
return { raw: format === "json" ? JSON.parse(content) : parse(content) };
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return { why: error instanceof Error ? error.message : String(error) };
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** `grade.rules.x` in chaff.yaml is `rules.x` in a rubric file; `grade` itself is the file's top level, the empty path. */
|
|
31
|
+
export const filePathOf = (gradePath: string): string => (gradePath === "grade" ? "" : gradePath.replace(/^grade\./u, ""));
|
|
32
|
+
|
|
33
|
+
/** The sha256 of the file's bytes as read, recorded in the stamp so runs under different rubric files are not compared silently. */
|
|
34
|
+
export const rubricFileDigest = (content: string): string => `sha256:${createHash("sha256").update(content).digest("hex")}`;
|
|
35
|
+
|
|
36
|
+
/** The rubric a file holds, or every problem with it. An empty file is an empty rubric, as a bare `grade:` is. */
|
|
37
|
+
export const parseRubricFile = (path: string, content: string): RubricFile => {
|
|
38
|
+
const format = formatOf(path);
|
|
39
|
+
if (format === undefined) return { problems: [{ kind: "format" }] };
|
|
40
|
+
const read = syntaxOf(content, format);
|
|
41
|
+
if ("why" in read) return { problems: [{ kind: "syntax", why: read.why }] };
|
|
42
|
+
const parsed = parseRubric(read.raw ?? null);
|
|
43
|
+
if ("problems" in parsed)
|
|
44
|
+
return { problems: parsed.problems.map((problem) => ({ kind: "rubric", problem: { ...problem, path: filePathOf(problem.path) } })) };
|
|
45
|
+
return { rubric: parsed.rubric ?? { rules: {} }, digest: rubricFileDigest(content) };
|
|
46
|
+
};
|
package/src/grade/rubric.ts
CHANGED
|
@@ -31,6 +31,8 @@ export type Rubric = {
|
|
|
31
31
|
readonly citations?: CitationLimits | undefined;
|
|
32
32
|
readonly contexts?: ContextLimits | undefined;
|
|
33
33
|
readonly penalty?: number | undefined;
|
|
34
|
+
/** Each task's own rubric, as written: what it does not write comes from the top level (task-rubric.ts). */
|
|
35
|
+
readonly tasks?: Readonly<Record<string, Rubric>> | undefined;
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
/** What a value under `grade:` should have been. */
|
|
@@ -78,10 +80,10 @@ const ruleLimit = (raw: unknown, path: string): Read<RuleLimit> => {
|
|
|
78
80
|
};
|
|
79
81
|
};
|
|
80
82
|
|
|
81
|
-
const rulesOf = (raw: unknown): Read<Record<string, RuleLimit>> => {
|
|
83
|
+
const rulesOf = (raw: unknown, base: string): Read<Record<string, RuleLimit>> => {
|
|
82
84
|
if (raw === undefined) return ok({});
|
|
83
|
-
if (!isRecord(raw)) return { value: {}, problems: [problem(
|
|
84
|
-
const read = Object.entries(raw).map(([id, limit]) => ({ id, read: ruleLimit(limit,
|
|
85
|
+
if (!isRecord(raw)) return { value: {}, problems: [problem(`${base}.rules`, "map", raw)] };
|
|
86
|
+
const read = Object.entries(raw).map(([id, limit]) => ({ id, read: ruleLimit(limit, `${base}.rules.${id}`) }));
|
|
85
87
|
return { value: Object.fromEntries(read.map((entry) => [entry.id, entry.read.value])), problems: read.flatMap((entry) => entry.read.problems) };
|
|
86
88
|
};
|
|
87
89
|
|
|
@@ -98,13 +100,14 @@ const kindsOf = (raw: unknown, path: string): Read<AtomKind[]> => {
|
|
|
98
100
|
return kinds.length === entries.length ? ok(kinds) : { value: kinds, problems: [problem(path, "kinds", raw)] };
|
|
99
101
|
};
|
|
100
102
|
|
|
101
|
-
const factsOf = (raw: unknown): Read<FactLimits | undefined> => {
|
|
103
|
+
const factsOf = (raw: unknown, base: string): Read<FactLimits | undefined> => {
|
|
102
104
|
if (raw === undefined) return ok(undefined);
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
const
|
|
105
|
+
const path = `${base}.facts`;
|
|
106
|
+
if (!isRecord(raw)) return { value: undefined, problems: [problem(path, "map", raw)] };
|
|
107
|
+
const dropped = optional(raw, "dropped", path, "count");
|
|
108
|
+
const added = optional(raw, "added", path, "count");
|
|
109
|
+
const allowDropped = kindsOf(raw["allow_dropped"], `${path}.allow_dropped`);
|
|
110
|
+
const allowAdded = kindsOf(raw["allow_added"], `${path}.allow_added`);
|
|
108
111
|
return {
|
|
109
112
|
value: { dropped: dropped.value, added: added.value, allowDropped: allowDropped.value, allowAdded: allowAdded.value },
|
|
110
113
|
problems: [
|
|
@@ -112,7 +115,7 @@ const factsOf = (raw: unknown): Read<FactLimits | undefined> => {
|
|
|
112
115
|
...added.problems,
|
|
113
116
|
...allowDropped.problems,
|
|
114
117
|
...allowAdded.problems,
|
|
115
|
-
...unknownKeys(raw, ["dropped", "added", "allow_dropped", "allow_added"],
|
|
118
|
+
...unknownKeys(raw, ["dropped", "added", "allow_dropped", "allow_added"], path),
|
|
116
119
|
],
|
|
117
120
|
};
|
|
118
121
|
};
|
|
@@ -125,62 +128,51 @@ const requiredOf = (raw: Record<string, unknown>, path: string): Read<boolean> =
|
|
|
125
128
|
: { value: false, problems: [problem(`${path}.required`, "boolean", required)] };
|
|
126
129
|
};
|
|
127
130
|
|
|
128
|
-
const citationsOf = (raw: unknown): Read<CitationLimits | undefined> => {
|
|
131
|
+
const citationsOf = (raw: unknown, base: string): Read<CitationLimits | undefined> => {
|
|
129
132
|
if (raw === undefined) return ok(undefined);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
+
const path = `${base}.citations`;
|
|
134
|
+
if (!isRecord(raw)) return { value: undefined, problems: [problem(path, "map", raw)] };
|
|
135
|
+
const failed = optional(raw, "failed", path, "count");
|
|
136
|
+
const required = requiredOf(raw, path);
|
|
133
137
|
return {
|
|
134
138
|
value: { failed: failed.value, required: required.value },
|
|
135
|
-
problems: [...failed.problems, ...required.problems, ...unknownKeys(raw, ["failed", "required"],
|
|
139
|
+
problems: [...failed.problems, ...required.problems, ...unknownKeys(raw, ["failed", "required"], path)],
|
|
136
140
|
};
|
|
137
141
|
};
|
|
138
142
|
|
|
139
|
-
const contextsOf = (raw: unknown): Read<ContextLimits | undefined> => {
|
|
143
|
+
const contextsOf = (raw: unknown, base: string): Read<ContextLimits | undefined> => {
|
|
140
144
|
if (raw === undefined) return ok(undefined);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
+
const path = `${base}.contexts`;
|
|
146
|
+
if (!isRecord(raw)) return { value: undefined, problems: [problem(path, "map", raw)] };
|
|
147
|
+
const unsupported = optional(raw, "unsupported", path, "count");
|
|
148
|
+
const allowUnsupported = kindsOf(raw["allow_unsupported"], `${path}.allow_unsupported`);
|
|
149
|
+
const required = requiredOf(raw, path);
|
|
145
150
|
return {
|
|
146
151
|
value: { unsupported: unsupported.value, allowUnsupported: allowUnsupported.value, required: required.value },
|
|
147
152
|
problems: [
|
|
148
153
|
...unsupported.problems,
|
|
149
154
|
...allowUnsupported.problems,
|
|
150
155
|
...required.problems,
|
|
151
|
-
...unknownKeys(raw, ["unsupported", "allow_unsupported", "required"],
|
|
156
|
+
...unknownKeys(raw, ["unsupported", "allow_unsupported", "required"], path),
|
|
152
157
|
],
|
|
153
158
|
};
|
|
154
159
|
};
|
|
155
160
|
|
|
156
|
-
|
|
161
|
+
/** The keys a task's rubric may write: every top-level key but `tasks`, so a task cannot hold tasks of its own. */
|
|
162
|
+
const TASK_KEYS: readonly string[] = ["rules", "required_sections", "facts", "citations", "contexts", "penalty"];
|
|
157
163
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
const
|
|
168
|
-
const facts = factsOf(raw["facts"]);
|
|
169
|
-
const citations = citationsOf(raw["citations"]);
|
|
170
|
-
const contexts = contextsOf(raw["contexts"]);
|
|
171
|
-
const penalty = optional(raw, "penalty", "grade", "number");
|
|
172
|
-
const problems = [
|
|
173
|
-
...rules.problems,
|
|
174
|
-
...sections.problems,
|
|
175
|
-
...facts.problems,
|
|
176
|
-
...citations.problems,
|
|
177
|
-
...contexts.problems,
|
|
178
|
-
...penalty.problems,
|
|
179
|
-
...unknownKeys(raw, RUBRIC_KEYS, "grade"),
|
|
180
|
-
];
|
|
181
|
-
if (problems.length > 0) return { problems };
|
|
164
|
+
const RUBRIC_KEYS: readonly string[] = [...TASK_KEYS, "tasks"];
|
|
165
|
+
|
|
166
|
+
/** One rubric's keys under `base` (`grade`, or `grade.tasks.<name>`); a key not among `keys` is a problem. */
|
|
167
|
+
const rubricAt = (raw: Record<string, unknown>, base: string, keys: readonly string[]): Read<Rubric> => {
|
|
168
|
+
const rules = rulesOf(raw["rules"], base);
|
|
169
|
+
const sections = wordsOf(raw["required_sections"], `${base}.required_sections`);
|
|
170
|
+
const facts = factsOf(raw["facts"], base);
|
|
171
|
+
const citations = citationsOf(raw["citations"], base);
|
|
172
|
+
const contexts = contextsOf(raw["contexts"], base);
|
|
173
|
+
const penalty = optional(raw, "penalty", base, "number");
|
|
182
174
|
return {
|
|
183
|
-
|
|
175
|
+
value: {
|
|
184
176
|
rules: rules.value,
|
|
185
177
|
requiredSections: sections.value,
|
|
186
178
|
facts: facts.value,
|
|
@@ -188,5 +180,43 @@ export const parseRubric = (raw: unknown): { readonly rubric: Rubric | undefined
|
|
|
188
180
|
contexts: contexts.value,
|
|
189
181
|
penalty: penalty.value,
|
|
190
182
|
},
|
|
183
|
+
problems: [
|
|
184
|
+
...rules.problems,
|
|
185
|
+
...sections.problems,
|
|
186
|
+
...facts.problems,
|
|
187
|
+
...citations.problems,
|
|
188
|
+
...contexts.problems,
|
|
189
|
+
...penalty.problems,
|
|
190
|
+
...unknownKeys(raw, keys, base),
|
|
191
|
+
],
|
|
191
192
|
};
|
|
192
193
|
};
|
|
194
|
+
|
|
195
|
+
/** One task's rubric. A bare `<name>:` (null) writes nothing, so the task inherits the whole top-level rubric. */
|
|
196
|
+
const taskOf = (raw: unknown, path: string): Read<Rubric> => {
|
|
197
|
+
if (raw === null) return ok({ rules: {} });
|
|
198
|
+
if (!isRecord(raw)) return { value: { rules: {} }, problems: [problem(path, "map", raw)] };
|
|
199
|
+
return rubricAt(raw, path, TASK_KEYS);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const tasksOf = (raw: unknown): Read<Record<string, Rubric> | undefined> => {
|
|
203
|
+
if (raw === undefined) return ok(undefined);
|
|
204
|
+
if (!isRecord(raw)) return { value: undefined, problems: [problem("grade.tasks", "map", raw)] };
|
|
205
|
+
const read = Object.entries(raw).map(([name, task]) => ({ name, read: taskOf(task, `grade.tasks.${name}`) }));
|
|
206
|
+
return { value: Object.fromEntries(read.map((entry) => [entry.name, entry.read.value])), problems: read.flatMap((entry) => entry.read.problems) };
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* The rubric, or every problem in it. No `grade:` key is no rubric: the default pass or fail applies (spec §29.3). A bare
|
|
211
|
+
* `grade:` (null) is an empty rubric, so writing the key alone still turns the default off, as the spec says it does.
|
|
212
|
+
*/
|
|
213
|
+
export const parseRubric = (raw: unknown): { readonly rubric: Rubric | undefined } | { readonly problems: readonly RubricProblem[] } => {
|
|
214
|
+
if (raw === undefined) return { rubric: undefined };
|
|
215
|
+
if (raw === null) return { rubric: { rules: {} } };
|
|
216
|
+
if (!isRecord(raw)) return { problems: [problem("grade", "map", raw)] };
|
|
217
|
+
const top = rubricAt(raw, "grade", RUBRIC_KEYS);
|
|
218
|
+
const tasks = tasksOf(raw["tasks"]);
|
|
219
|
+
const problems = [...top.problems, ...tasks.problems];
|
|
220
|
+
if (problems.length > 0) return { problems };
|
|
221
|
+
return { rubric: tasks.value === undefined ? top.value : { ...top.value, tasks: tasks.value } };
|
|
222
|
+
};
|
package/src/grade/setup.ts
CHANGED
|
@@ -28,16 +28,16 @@ const ruleSetOf = async (config: Config, languages: readonly string[]): Promise<
|
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
/** A run's settings, rubric and stamp. `languages`: those the items name, beyond the bundled ones. Throws when a language package cannot be loaded. */
|
|
31
|
+
/** A run's settings, rubric and stamp. `run.rubricFile`: a --rubric file's digest, when the rubric came from one. `languages`: those the items name, beyond the bundled ones. Throws when a language package cannot be loaded. */
|
|
32
32
|
export const gradeSetup = async (
|
|
33
33
|
config: Config,
|
|
34
|
-
run: { readonly experimental: boolean; readonly genre: string | undefined },
|
|
34
|
+
run: { readonly experimental: boolean; readonly genre: string | undefined; readonly rubricFile?: string | undefined },
|
|
35
35
|
languages: readonly string[],
|
|
36
36
|
rubric: Rubric | undefined,
|
|
37
37
|
): Promise<GradeSetup> => {
|
|
38
38
|
// chaff.yaml's language and its by_path languages are loaded here too, so a missing package stops the run before grading.
|
|
39
39
|
const named = [config.language, ...config.byPath.map((rule) => rule.language)].filter((language) => language !== undefined);
|
|
40
40
|
const all = [...new Set([...BUNDLED_LANGUAGES, ...named, ...languages])].toSorted(compareText);
|
|
41
|
-
const settings = { config, experimental: run.experimental, genre: run.genre };
|
|
41
|
+
const settings = { config, experimental: run.experimental, genre: run.genre, rubricFile: run.rubricFile };
|
|
42
42
|
return { ...settings, rubric, stamp: stampOf(VERSION_LINES, await ruleSetOf(config, all), settings) };
|
|
43
43
|
};
|
package/src/grade/stamp.ts
CHANGED
|
@@ -20,6 +20,15 @@ export type GradeSettings = {
|
|
|
20
20
|
readonly experimental: boolean;
|
|
21
21
|
/** --genre, which wins over chaff.yaml for every item that does not name its own. */
|
|
22
22
|
readonly genre: string | undefined;
|
|
23
|
+
/** The digest of a --rubric file, which replaces chaff.yaml's `grade:` for the run. */
|
|
24
|
+
readonly rubricFile?: string | undefined;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** The rubric a run grades by: a --rubric file by its digest, else chaff.yaml's `grade:`. */
|
|
28
|
+
const gradeOf = (settings: GradeSettings): unknown => {
|
|
29
|
+
if (settings.rubricFile !== undefined) return { file: settings.rubricFile };
|
|
30
|
+
// A bare `grade:` reads as null and is an empty rubric, which grades otherwise than no `grade:` at all.
|
|
31
|
+
return settings.config.grade === undefined ? "none" : settings.config.grade;
|
|
23
32
|
};
|
|
24
33
|
|
|
25
34
|
/** The parts of chaff.yaml that change a finding, a fact or a verdict. Paths and the AI judge do not. */
|
|
@@ -40,8 +49,7 @@ export const settingsOf = (settings: GradeSettings): Record<string, unknown> =>
|
|
|
40
49
|
requiredSections: config.requiredSections,
|
|
41
50
|
names: config.names,
|
|
42
51
|
byPath: config.byPath,
|
|
43
|
-
|
|
44
|
-
grade: config.grade === undefined ? "none" : config.grade,
|
|
52
|
+
grade: gradeOf(settings),
|
|
45
53
|
};
|
|
46
54
|
};
|
|
47
55
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Rubric } from "./rubric.ts";
|
|
2
|
+
|
|
3
|
+
// The rubric one item is graded by: the top-level rubric with its task's rubric laid over it. Pure.
|
|
4
|
+
// A key the task writes replaces the top-level key whole (`facts`, `citations`, `contexts` are not merged field by
|
|
5
|
+
// field); a key it does not write is inherited. `rules` is merged per rule id: the task's entry for an id replaces the
|
|
6
|
+
// top-level entry for that id, and every other top-level id still applies.
|
|
7
|
+
|
|
8
|
+
/** The task names a rubric defines; none without a rubric or without `tasks`. */
|
|
9
|
+
export const taskNamesOf = (rubric: Rubric | undefined): readonly string[] => Object.keys(rubric?.tasks ?? {});
|
|
10
|
+
|
|
11
|
+
/** Each rule id the rubric names and where, from the rubric's top level: `rules`, or `tasks.<name>.rules`. */
|
|
12
|
+
export const rubricRuleEntries = (rubric: Rubric | undefined): readonly { readonly path: string; readonly id: string }[] => [
|
|
13
|
+
...Object.keys(rubric?.rules ?? {}).map((id) => ({ path: "rules", id })),
|
|
14
|
+
...Object.entries(rubric?.tasks ?? {}).flatMap(([name, task]) => Object.keys(task.rules).map((id) => ({ path: `tasks.${name}.rules`, id }))),
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const overlay = (top: Rubric, task: Rubric): Rubric => ({
|
|
18
|
+
rules: { ...top.rules, ...task.rules },
|
|
19
|
+
requiredSections: task.requiredSections ?? top.requiredSections,
|
|
20
|
+
facts: task.facts ?? top.facts,
|
|
21
|
+
citations: task.citations ?? top.citations,
|
|
22
|
+
contexts: task.contexts ?? top.contexts,
|
|
23
|
+
penalty: task.penalty ?? top.penalty,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The rubric for an item of `task`. Without a task, the rubric as it is. A task the rubric does not define is refused
|
|
28
|
+
* when the items are read, so here it cannot happen; it throws rather than fall back to the top level silently.
|
|
29
|
+
*/
|
|
30
|
+
export const rubricForTask = (rubric: Rubric | undefined, task: string | undefined): Rubric | undefined => {
|
|
31
|
+
if (task === undefined) return rubric;
|
|
32
|
+
const own = rubric?.tasks?.[task];
|
|
33
|
+
if (rubric === undefined || own === undefined) throw new Error(`chaff grade: no rubric for task "${task}"`);
|
|
34
|
+
return overlay(rubric, own);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** The rule ids an output of `task` is graded by: whose rise in that output is a regression against a baseline. */
|
|
38
|
+
export const taskRuleIds = (rubric: Rubric | undefined, task: string | undefined): ReadonlySet<string> =>
|
|
39
|
+
new Set(Object.keys(rubricForTask(rubric, task)?.rules ?? {}));
|