Skip to content

writeChartFile: re-quote extraChartSongFields per .chart spec types - #89

Open
elicwhite wants to merge 1 commit into
skip-default-keys-in-ini-writerfrom
quote-extra-song-fields
Open

writeChartFile: re-quote extraChartSongFields per .chart spec types#89
elicwhite wants to merge 1 commit into
skip-default-keys-in-ini-writerfrom
quote-extra-song-fields

Conversation

@elicwhite

Copy link
Copy Markdown
Owner

Stacked on top of #87 and the writer stack below it. Standalone of the stack, the change is ~30 lines.

Summary

The chart parser strips enclosing quotes from [Song] values on read (chart-parser.ts's chartSongMetaRegex = /^(.+?) = "?(.*?)"?$/), so metadata.extraChartSongFields always holds bare strings. The writer was emitting them verbatim — which produces MusicStream = song.ogg (unquoted). Moonscraper rejects that shape and silently fails to load audio, so any chart edited and re-saved via writeChartFile came back broken.

Changes

writeChartFile re-applies quoting on emit per the .chart spec's field-type table at Format-Overview.md (lines 78-85, 143-199):

  • Player2 — the spec's lone bare string field — stays bare via a small allowlist.
  • Numeric / decimal / boolean primitives stay bare via a value-shape regex (/^(?:-?\d+(?:\.\d+)?|true|false)$/).
  • Everything else gets quoted. Erring toward quoting matches the spec (every string and file path field is quoted) and mirrors what readers (Moonscraper, scan-chart) tolerate.

The parser is untouched, so the extraChartSongFields shape stays "always bare" — callers don't have to think about quoting.

Why these rules

Verified across a 62,697-chart corpus (Encore + remaining-charts dumps). For every well-known string-typed [Song] key, ≥99.97% of occurrences are quoted; outlier counts are 3-5 per key (sloppy authoring, not a real divergence). Stream filenames specifically are quoted 100% of the time. The only de-facto boolean field in the corpus, OriginalArtist, appears as OriginalArtist = false in 171/171 charts that use it — covered by the boolean branch of the value-shape regex.

Test plan

  • 4 new tests in round-trip-unrecognized-extras.test.ts:
    • MusicStream emits with quotes Moonscraper expects (pins on-disk text).
    • Player2 emits unquoted (bare-string field per spec).
    • Numeric-typed legacy fields (HoPo, PreviewEnd) emit unquoted.
    • Unknown keys: string-shaped → quoted, primitive-shaped → bare.
  • All 425 tests pass.

The parser strips enclosing quotes from `[Song]` values on read, so
`extraChartSongFields` always holds bare strings. Emitting them verbatim
produced `MusicStream = song.ogg` (unquoted) — Moonscraper rejects that
shape and fails to load the audio.

Re-apply quoting on write per the spec's field-type table:
- `Player2` (the lone `bare string` field) stays bare.
- Numeric and boolean primitives stay bare via value-shape check.
- Everything else gets quoted.

The default-quote-strings rule is verified across a 62K-chart corpus:
every `string` / `file path` field is quoted ≥99.97% of the time, and
the only de-facto boolean field (`OriginalArtist = false`) appears
unquoted in 171/171 occurrences.
@elicwhite
elicwhite changed the base branch from master to skip-default-keys-in-ini-writer April 28, 2026 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant