Articles: key by label across subtypes, scope per property, FO toggle widget
A single article label (e.g. 'f') may emit on multiple `articles.<subtype>`
lines — `defaults` today, `overwrites` planned — with disjoint property
sets that apply at different stages. Model now merges those emissions:
{ name: 'f', properties: [{ name, value, scope: 'defaults'|'overwrites' }] }
Per-label entries in the AR pane show a property-count breakdown
(`f (1 defaults, 2 overwrites)`). The Article FO pane lists each property
with a `(O-) default` / `(-O) overwrite` toggle — click flips the scope
and marks the score dirty. ASCII glyph mimics a physical switch position
so the active scope is visible at a glance.
Fixture tests cover both the existing single-subtype shape and a synthetic
two-subtype merge (177 assertions total).
This commit is contained in:
@@ -48,9 +48,24 @@ ok('stageVoices parsed', model.stageVoices.length === 3);
|
||||
ok('stageVoices[0] is "pi"', model.stageVoices[0].name === 'pi');
|
||||
ok('stageVoices[0].direction', model.stageVoices[0].direction === '1|1');
|
||||
ok('articles array non-empty', model.articles.length > 0);
|
||||
ok('articles[0].subtype defaults', model.articles[0].subtype === 'defaults');
|
||||
ok('articles[0].name "f"', model.articles[0].name === 'f');
|
||||
ok('articles[0].props.add_stress', model.articles[0].props.add_stress === 3);
|
||||
ok('articles[0].properties[]', Array.isArray(model.articles[0].properties));
|
||||
const fProp = model.articles[0].properties.find(p => p.name === 'add_stress');
|
||||
ok('articles[0] add_stress prop', fProp && fProp.value === 3 && fProp.scope === 'defaults');
|
||||
|
||||
// Merge across subtypes: same label, different subtypes → one entry, multi-scope props
|
||||
const MERGE_FIXTURE = `01 articles.defaults 'g' add_stress=2
|
||||
01 articles.overwrites 'g' pitch_bend=0.05
|
||||
`;
|
||||
const mergeRoot = parseAstLog('00 tuning base=\'x\'\n' + MERGE_FIXTURE);
|
||||
const mergeModel = buildModel(mergeRoot);
|
||||
ok('merge: single entry per label', mergeModel.articles.length === 1);
|
||||
ok('merge: label "g"', mergeModel.articles[0].name === 'g');
|
||||
ok('merge: 2 properties', mergeModel.articles[0].properties.length === 2);
|
||||
const gDef = mergeModel.articles[0].properties.find(p => p.scope === 'defaults');
|
||||
const gOver = mergeModel.articles[0].properties.find(p => p.scope === 'overwrites');
|
||||
ok('merge: default scope present', gDef && gDef.name === 'add_stress' && gDef.value === 2);
|
||||
ok('merge: overwrite scope present', gOver && gOver.name === 'pitch_bend' && gOver.value === 0.05);
|
||||
|
||||
// ── Bar IDs ────────────────────────────────────────────────────────────────
|
||||
// Bar IDs are opaque auto-increment strings; only the raw id string matters.
|
||||
|
||||
Reference in New Issue
Block a user