Repository navigation
Make every docs example parse, and add a test that keeps it that way - #29
Merged
Merged
Conversation
39 of the 148 live <notation> examples in docs/content did not parse.
NotationBlock.updatePreview renders nothing when load() reports errors, so
those were blank boxes on the site with the reason only in the browser
console. Five more parsed but contained ___, which lexes as an ordinary
identifier and renders as visible text where a silent space was meant.
The examples were written against a syntax the parser does not implement.
Rather than guess at the grammar changes, this rewrites them onto what works
today and files issue 27 with the impact analysis for each construct, to be
evaluated once the site renders.
Rewrites, applied inside <notation> bodies and never to a line starting with
>, which is a raw markdown embedding:
| and || removed. beatviews.ts already draws a bar line at the end of
each bar and a double line at the end of the avartanam, from
the cycle, so these characters were redundant with what gets
drawn anyway.
___ and _ one comma per underscore, which keeps the duration the example
was written with at the cost of showing the commas.
M#, GM#P quoted, so the text renders as written. Sharps are excluded
from IdentChar and carry no meaning to the layout engine either
way.
\accidentals, \noTala
removed. Neither command exists, and both threw out of load()
rather than reporting an error, see issue 28.
Four examples using the paren gamaka syntax, ((S R G) kampitam) and (R~G),
are rewritten with the ~ operators that exist. Those are the ones whose
meaning changed, since the two notations are not equivalent. Four more in
reference/embellishments had the operator in a position the grammar does not
allow, since every embellishment attaches to the literal that follows it.
Prose that described the removed constructs is corrected rather than left
claiming things that do not work.
The Comments section of the syntax reference was the one feature on that page
shown as a dead code block while its fourteen neighbours were live examples.
It is live now, as are the two example pages whose "Using Comments" sections
used \line() titles instead of comments.
docs/tests/examples.spec.ts asserts both properties for every example and
runs in CI with the rest of the suite.
CodeQL flagged the replace as js/incomplete-multi-character-sanitization, high severity: a single pass over `<!--[\s\S]*?-->` leaves a dangling `<!--` behind when a comment never closes, so the result can still contain the opener it was meant to remove. It is also wrong for that case. An unterminated comment swallows the rest of the document in a browser, and the regex version kept every example after it in the test set. Walking the string handles both, and four assertions cover the edges the corpus does not currently contain.
This was referenced Sep 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes
Every live
<notation>example on the docs site parses now. 39 of 148 did not, andNotationBlock.updatePreview()renders nothing whenload()reports errors, so those were blank boxes with the reason only in the browser console. Five more parsed but contained___, which lexes as an ordinary identifier and renders as visible text where a silent space was meant.docs/tests/examples.spec.tsasserts both properties for every example and runs in CI with the rest of the suite.Prerequisite knowledge
Reviewer's guide
A restaurant that prints a menu before the kitchen can cook the dishes ends up with two problems, and only one of them is about food. The docs here describe a notation language in some detail, and the parser implements a smaller one. Bar separators, silent spaces, sharps, free-time sections and a paren-based gamaka syntax all appear in the examples and none of them exist in the grammar. So a quarter of the menu arrived as an empty plate, silently, because the renderer draws nothing when a parse fails. The fix is not to teach the kitchen five new dishes in an afternoon, since nobody has decided what those dishes should be. It is to reprint the menu with what the kitchen actually cooks, write down the five missing recipes somewhere they can be argued about properly, and put a checker on the pass so a dish that cannot be cooked never reaches a table again.
Read in this order:
<!-- -->regions and template bodies, which is what the browser sees.stripCommentswalks the string rather than running one regex replace, for reasons in the decision log.\line()titles instead of comments.How it works
The bulk of the rewrite was scripted, applied inside
<notation>bodies only, and never to a line starting with>, which is aSINGLE_LINE_RAW_STRINGwhere everything after the>is markdown passed through. An earlier version of the script missed that and turned> ### Pallaviinto> "###" Pallavi, which is how the exclusion got there.|and||beatviews.ts:139already draws a line at the end of each bar and a double line at the end of the avartanam, from the cycle___,_M#,GM#P"M#","GM#P"\accidentals(...)\noTala((S R G) kampitam)[~ S R G][S R] ~:- [G M][S R] [~:- G M]Decision log
\line("Pallavi")in Kalyani without itsM#is a different raga. A quoted literal renders the same text, so the examples still read correctly even though the engine treats it as an opaque label.(R~G)in the old notation means one note ornamented toward another;[~ R G]is a group of two notes with kampitam on the first. They are not the same thing. Both note names survive and the example renders, which is the best available option until issue 27 is settled.complex-gamakaswere left alone because they sit inside an<!-- -->block and never reach the browser. The test strips commented regions for the same reason.docs/tests/next to the existingplayground-patterns.spec.tsrather than insrc/tests/, since it tests the docs rather than the library._row in the syntax reference table, marked "not implemented yet", rather than deleting it. It documents the intended language, and issue 17 is open against it.stripCommentsscans the string instead of calling.replace(/<!--[\s\S]*?-->/g, ""). CodeQL flagged the replace asjs/incomplete-multi-character-sanitization, high severity, and it was right that the result can still contain<!--. It was also wrong for that input in a way that mattered here: an unterminated comment swallows the rest of the document in a browser, and the regex version kept every example after it in the test set. Four assertions cover the edges, since the corpus has no unterminated comment today.Risk / blast radius
describe.eachover the examples, so a failure names the file and the example id.>are passed through as markdown and were deliberately excluded from every rule, but<notation>bodies mix the two freely and a rule leaking into one of those lines is the failure mode that would not show up as a test failure.git diff docs/content | grep '^[+-]' | grep '^\s*[+-]>'comes back empty.Before / after
The Comments section of the syntax reference, which is the change most worth looking at:
A representative example body:
\line("Pallavi with Mridangam") - Sw: S R G M , P D N S. , ___ ___ , ___ ___ | - \line("Mridangam: ta ka dhi mi , ta ka jha nu , ___ ___ , ___ ___") + // mridangam: ta ka dhi mi , ta ka jha nu + Sw: S R G M , P D N S. , , , , , , , , , , , , , ,Out of scope
NotationBlock.updatePreviewwith a try/catch. A renderer should not trust a parser not to throw, but the parser is where that bug is, and it is in issue 28.docs/static/visual-tests/, which are a separate fixture set and all parse today.js/html-constructed-from-inputalerts CodeQL has open againstNotationBlock.ts. They predate this branch, which is why the check was green before. Filed as issue 30, along with the unescaped source listing on line 89 that the alerts do not cover.