Releases: vale-cli/vale
Release list
v3.19.0
MDX: JSX children are now linted
Vale now reads a JSX element's children as the Markdown they are — matching MDX's own grammar, where only tags, attributes, and {...} expressions are JavaScript. The prose inside wrapping components like <Steps>, <Tabs>, or <Aside> is linted at its exact source position, as is the text of inline elements (<abbr>HTML</abbr> — "HTML" is read as part of its sentence). For documentation built on component-heavy frameworks like Astro Starlight, this can mean a quarter of your prose is now covered.
Children carry the element's name as a class scope, the same way MyST and Quarto directives work — so a rule can target one component's content (scope: text.class.Aside), and a component whose content shouldn't be linted can be excluded by name:
IgnoredClasses = RawOutputThat's also the escape hatch if you preferred the old skip-everything behavior. Attribute values, expressions, self-closing elements, and elements opened and closed on a single standalone line are still treated as code.
Changelog
- 405a7da fix: strip a comment's delimiters, not its prose's (#1151)
- 7766415 feat(code): add Elixir comment and doc-attribute extraction (#1151)
- 055db43 feat: let a sequence token ask for repeated occurrences (#899)
- 9ba5dea feat: lint a JSX element's children as the Markdown they are (#1155)
- 8702043 fix: lint a block title as written, without its generated label (#1152)
- d0e65f4 docs: update contributing for native MDX and Typst
v3.18.0
v3.18.0 is the largest expansion of Vale's format support since v3.0.0.
MDX is now parsed natively — mdx2vast is no longer required. This release also adds support for four new markup formats: Typst (through the new typst2vast program), Quarto, MyST, and QDoc. R Markdown now works out of the box, and comment extraction now covers Lua, PHP, Haskell, R, Perl, and SCSS.
Beyond formats, there's a new meta scope for a document's machine-readable content, a --plain-progress flag, and per-package logging for vale sync in CI — plus a long list of fixes that make alert positions and scoping more accurate across every format.
✨ Sponsor Spotlight
Special thanks to Promptless — Vale's newest sponsor and the latest to receive a Spotlight page. Promptless suggests doc updates when your product changes; you review, edit, and ship.
Changelog
- 6c382ec fix: stop element-scoped rules from matching sentence fragments (#1150)
- 9b9594d fix: don't treat a word before a code span as inline markup (#1147)
- 2b159ab fix: stop corrupting suggestions containing 'PIPE'
- 390dda6 fix: compile glob patterns once at construction (#1145)
- fcf0740 fix(ls-metrics): prevent panic on empty directory (#1144)
- dd09d42 fix(core): resolve Lang and Transform in section order, not map order (#1143)
- 85ee608 fix(dita): report dita's own error output instead of just the exit status (#1141)
- fd8c2e0 refactor: satisfy revive's empty-block
- 2f65b83 fix: close display math on any line ending with
$$(#1148) - e587329 fix(lint): treat an HTML comment as a text boundary outside inline elements (#1140)
- 4691bd3 docs: add new spotlight
- 37cb109 feat: add
--plain-progress - 12fbbd7 feat: log each package when sync isn't writing to a terminal
- 9a1a16c fix: mark a QDoc image that has no alt text, and publish inline ones
- c154ac2 Keep the extracted text one line per source line (#1135)
- 8fe9804 refactor: CLI clean up and subcommand help
- ae6d749 feat: add
vale test - e5a0286 fix: read a shebang as a POSIX path
- eec2f59 fix: read a .qdocinc as the include it is, and keep meta out of prose
- 7618d04 fix: only hand the Docutils source to a Python interpreter
- b596b0d fix: stop a string run's helper processes the way a file run does
- f3f3402 fix: keep
vale offworking when QDoc prose is escaped - 54efd3b fix: escape QDoc markup
- 5666297 fix: treat a snippet marker inside a QDoc comment as markup
- c2d1a55 feat: add a meta scope for a document's machine-readable content
- 33e4012 fix: close QDoc's code blocks on the right command, and scope its divs
- 5ae4867 fix: read only
/*!as QDoc, and cover commands - e60b5bc fix: keep a rule's level in the section that set it
- c1e2fa0 fix: honor IgnoredScopes when a markup format is mapped onto source
- 85c1343 fix: place a match inside a block that inline markup rewrote
- b47ccb0 fix: don't mask an autolink's URL twice
- 65f5687 fix: skip
$…$inline math - b3bade4 fix: lint a tight list item's own text as its own block
- 4a6b7cf Don't lint a shebang as a comment (#1134)
- 77179c0 fix: report spans against the file's actual bytes
- 7f429e3 test: pin issue 1007's frontmatter and blockquote scenarios
- b049e35 feat: support the .scss extension
- b678b8d test: add QML case
- e82432d feat: extract Lua, PHP, Haskell, R, and Perl comments with tree-sitter
- 0e2f8bf eat: support QML sources via qml = qdoc
- cc710aa fix: treat only block comments as QDoc documentation
- bd1f33a ci: install typst2vast, drop mdx2vast
- 9708be6 feat: support Typst
- 15115bf fix: place a rewritten block by its longest word, not its last
- 5c91639 fix: skip a repeated match's prior occurrences by count, not by masking
- db8c83c feat: support QDoc
- fca7b79 feat: support Quarto
- 286fc59 feat: parse MDX natively, dropping mdx2vast
- fedaf20 feat: support MyST
- eec788d fix: read the character actually beside a match for inline code
- 590278e feat: lint R Markdown out of the box
- 4d8e228 fix: strip tab indentation from block comments (#1131)
- 02fb654 fix: switch on what every term of a chained scope needs
- f011cb0 fix: keep 'scope: paragraph' out of headings, tables, lists, and blockquotes
v3.17.1
Changelog
- bc78bf3 tests: add case for block change
- d078f4c perf: spend fewer cores on startup and more on large blocks
- 1dd53ff perf: hoist a lookaround shared by every swap key
- c8a19c9 perf: skip compiling rules the config can never run
- 70aa68f fix: give each Org file its own HTML writer
- 44e5572 chore: bump regexp2
- 124ed7c feat: build for Windows on ARM
- a335cfa refactor: Warn on unrecognized core options
- 529d382 fix: pin the comment fixtures to LF
- fd1a319 docs: stop pinning a version in the security policy
- 20505a3 test: replace the Cucumber suite with YAML-driven Go tests
- 4503ee7 fix: resolve the default config during a dry run
- d947f20 perf: size the converter pools to the run, not the host
- 72a1502 Update SECURITY.md
- 6d08e80 docs: fix old links
- fdd1844 fix: bound and validate rule-embedded scripts
v3.17.0
Building on the dependency updates from the previous release, v3.17.0 brings the most significant performance improvements since v3.0.0.
It also brings support for inline scopes and style-level severity changes.
If you use MDX, make sure to update mdx2vast to v0.5.0 to see the performance gains.
✨ Sponsor Spotlight
Special thanks to Mintlify for becoming Vale's latest sponsor and the first to receive a Spotlight page!
Changelog
- 989be25 docs: add sponsor
- ff6de4d fix: stop sharing per-file scope state across goroutines
- 5d413a0 fix: name the spelling a vocab term wants, not its pattern
- 5f071ef perf: reuse one Docutils interpreter instead of one per file
- 4fd0ba6 perf: reuse one mdx2vast process instead of one per file
- d65b54c perf: keep Asciidoctor running instead of restarting it per file
- eea7ac3 perf: stop scanning the whole document to place each alert
- d6308d2 docs: update contributing
- dccf897 perf: run one search per block instead of one per line
- 769943c fix: stop narrowing paragraph to a scope nothing carries
- 67f6502 fix: read block-comment decoration as decoration, not markup
- c937d0c perf: stop deduplicating rule runs per text
- 3bf1bb9 perf: read literals through a pattern's lookarounds
- c795e3e perf: read literals through a pattern's lookarounds
- 1bbfca0 perf: decide a rule's scope once per block scope
- 38849c4 build: use regexp2 v2.5.4
- bf80cba perf: compile the capitalization word pattern once
- 000a253 perf: only map runs to the source when something will ask
- d59f600 docs: write an actual security policy
- 3a8a295 fix: place inline fragments where they actually are
- 8d4b2d0 fix: close extracted files properly
- b6b4ae4 fix: bound COMPOUNDMIN and COMPOUNDRULE
- 8b961fb feat: support inline scopes
- b828088 feat: allow scoping by class
- 0dc010c test: add cases for new package-level settings
- 473c6c1 feat: allow a setting to be given for a whole style
- 9c1aee1 fix: honour a sequence rule's declared scope
- ff1b04b perf: run each rule once per distinct text
- 59ba324 perf: run each rule once per distinct text
- 21743d1 perf: locate spelling alerts by offset
- e29df0e perf: stop searching once a usable match is found
- 5cab109 perf: skip rules whose tokens cannot match
- d92fed0 perf: Split selectors once instead of on every comparison
- 391e3c0 fix: stop section styles leaking across globs
v3.16.0
This release includes a major update to prose, Vale's underlying NLP library, that brings significant performance improvements across the board.
Changelog
- 4e6335d spell: use strings.Cut for the continuation split
- bf76e1e spell: follow affix continuation classes
- 37b242a docs: update README link
- f439d0f perf: pre-compile Tengo
- 5ea9564 perf: stop repeating work in the per-block hot path
- a165f8d fix: match sequence patterns against whole tokens
- be96fa9 feat: add
matchCasefor alert reporting - e55d29c perf: index line starts instead of counting newlines per alert
- fd183ac perf: slice matches out by offset instead of converting to runes
- 3a29bc0 perf: place alerts by offset instead of searching for their text
- 9bd0cf9 feat: match universal POS tags in sequence
- ab05648 fix: locate sequence matches by position, not by searching
- 6e87b3e chore: drop our regexp2 fork
- f7d2f10 chore: move NLP to the new prose/v3 library
v3.15.2
Tip
Try Vale CMS: the hosted authoring layer for Vale. Build and maintain your style guide in the browser -- config, rules, vocabularies, dictionaries, filters, views, and templates -- with the real Vale engine linting live before you ship changes back to your repository.
Changelog
- 94e2076 test: cover style-local action script lookup
- f34c494 fix: allow action scripts to be found inside the style directory (#1121)
- ab0ad9e test: add AsciiDoc source-position regression (#1113)
- 778a44f fix: preserve AsciiDoc heading scopes with anchors and xrefs
- 378f704 fix: preserve source whitespace around inline markup (#1111, #1119)
- 24e9634 fix: parse condition-less affix rules; floor compound segment length (#776)
- e5c4672 fix: guard against negative span in AddAlert (#808)
- f1cbd5f feat: recognize affix-flag compound words (#848)
- 1cde8bf fix: position scope:raw matches by byte offset, not search (#869)
- d27f93a feat: skip display math (
$$…$$ ) when linting Markdown (#878) - 08107df fix: position repeated tokens correctly in assignLoc (#892)
- 23af9bd fix: handle broken symlinks gracefully during walks (#919, #968)
- 4729abb fix: name the offending path in symlink-resolution errors (#968)
- 42048e0 fix: don't rename a local package's .vale.ini during sync (#991)
- f887695 fix: locate punctuation-only matches within their block (#994)
- e200b60 fix: surface a concise MDX parse error instead of a Node trace (#995)
- ecdec34 feat: re-case regex vocab terms in Vale.Terms output (#997)
- f19f7bd fix: honor inline vale off/on spans (#1001)
- 4c69948 fix: locate quote-normalized matches in smart-quote source (#1003)
- af6b537 fix: don't abort dictionary search on a failed readlink (#1014)
- 09a81d0 fix: make missing-Vocab error show the searched paths (#1015)
- 480061b fix: allow array document roots in Views (#1017)
- 5089175 fix: don't leak line comments into a following block comment (#1020)
- edf327b fix: keep words apart across skipped inline scopes (#1052)
v3.15.1
v3.15.0
Vocabularies now support multi-word entries — phrases that are valid as a unit but whose individual words shouldn't be accepted on their own.
Previously, an accept.txt entry like mea culpa couldn't work: spell-checking splits text into single words, so mea and culpa were each checked (and flagged) separately. Your only option was accepting each word individually — which also silently allowed them everywhere else.
Now you can add the phrase directly:
mea culpa
mea culpais accepted as a phrase- a stray
meaorculpaon its own is still flagged
Changelog
- 948bd96 feat: support presence checks in conditional rules
- 4d281c3 fix: render occurrence count as a number
- 3b43f73 fix: preserve relative indentation in code-comment markup (#1028)
- 32cd425 fix: don't pad dashes adjacent to inline markup (#1029)
- fa67a3e feat: accept multi-word phrases in the vocabulary (#1035)
- 072ac4f fix: don't treat substitution replacements as regexes (#1038)
- d372163 fix: don't pad inline content adjacent to brackets (#1056)
- 2680b53 fix: don't apply word Vocab to nonword existence rules (#1058)
- 8558c4f fix: handle Danish-style hunspell dictionaries (#1065)
- 0da27dd fix: ignore generated TOC and section numbers in AsciiDoc (#1101)
- a686cae fix: don't require a python executable to lint reStructuredText (#1102)
- 813e6c8 fix: prevent crash when masking read-only context (#1099)
- c1533d1 fix: create configured StylesPath during sync (#1105) (#1106)
v3.14.2
Changelog
- 810868b chore: drop yaml v2
- 20fcb4d fix: move to gopkg.in/yaml.v3
- cdf6f9e Bugfix/path expansion (#1096)
- 3b9c8bf chore(deps): upgrade github.com/olekukonko/tablewriter from v0.0.5 to v1.1.4 (#1092)
- e251662 fix: add FLAG num support for agglutinative languages (#1090)
- 831ded9 chore: update clone path
- 806283c chore(deps): bump github.com/tomwright/dasel/v3 from 3.3.1 to 3.3.2 (#1088)
v3.14.1
Changelog
- 41f3b22 fix: correctly ignore
classvalues in HTML