diff --git a/static/components/PaneCP.js b/static/components/PaneCP.js index 8a6432c..6e16d1c 100644 --- a/static/components/PaneCP.js +++ b/static/components/PaneCP.js @@ -2,48 +2,9 @@ import { h, ref, watch, onMounted } from 'vue'; import { fetchAstLog, fetchScoreText, putScoreText, fetchAudioWidget, URLS } from '../api.js'; import { parseAstLog, buildModel } from '../ast-parser.js'; import { patchScore } from '../exporter.js'; +import { shortView } from '../node-views.js'; import { StatusPoller } from './StatusPoller.js'; -// Short label + identifying meta for each node type. -function shortView(node) { - if (!node) return { typeTag: '?', label: '?', meta: [] }; - switch (node.type) { - case 'score': - return { - typeTag: 'score', - label: node.info?.title ?? '(untitled)', - meta: node.info?.composer ? [{ key: 'composer', value: node.info.composer }] : [], - }; - case 'instrument': - return { typeTag: 'instrument', label: node.name, meta: [] }; - case 'variation': { - const dep = node.dependsOn; - const label = dep == null ? '(root variation)' - : isNaN(Number(dep)) ? `ATTR: ${dep}` - : String(dep); - return { typeTag: 'variation', label, meta: [] }; - } - case 'label_spec': - return { typeTag: 'label', label: node.label ?? '(no label)', meta: [] }; - case 'bar': - return { typeTag: 'bar', label: node.id, meta: [] }; - case 'voice': - return { typeTag: 'voice', label: node.name, meta: [] }; - case 'offset': - return { typeTag: 'tick', label: String(node.tick ?? '?'), meta: [] }; - case 'motif': - return { typeTag: 'motif', label: node.label, meta: node.isStatic ? [{ key: 'static', value: '✓' }] : [] }; - case 'stem_note': - return { typeTag: 'stem_note', label: String(node.pitch), meta: [] }; - case 'article': { - const n = node.properties?.length ?? 0; - return { typeTag: 'article', label: node.name, meta: n ? [{ key: 'props', value: n }] : [] }; - } - default: - return { typeTag: node.type, label: node.type, meta: [] }; - } -} - export const PaneCP = { props: ['store', 'importOnLoad', 'onFocusFO'], setup(props) { diff --git a/static/node-views.js b/static/node-views.js new file mode 100644 index 0000000..89bf12e --- /dev/null +++ b/static/node-views.js @@ -0,0 +1,38 @@ +export function shortView(node) { + if (!node) return { typeTag: '?', label: '?', meta: [] }; + switch (node.type) { + case 'score': + return { + typeTag: 'score', + label: node.info?.title ?? '(untitled)', + meta: node.info?.composer ? [{ key: 'composer', value: node.info.composer }] : [], + }; + case 'instrument': + return { typeTag: 'instrument', label: node.name, meta: [] }; + case 'variation': { + const dep = node.dependsOn; + const label = dep == null ? '(root variation)' + : isNaN(Number(dep)) ? `ATTR: ${dep}` + : String(dep); + return { typeTag: 'variation', label, meta: [] }; + } + case 'label_spec': + return { typeTag: 'label', label: node.label ?? '(no label)', meta: [] }; + case 'bar': + return { typeTag: 'bar', label: node.id, meta: [] }; + case 'voice': + return { typeTag: 'voice', label: node.name, meta: [] }; + case 'offset': + return { typeTag: 'tick', label: String(node.tick ?? '?'), meta: [] }; + case 'motif': + return { typeTag: 'motif', label: node.label, meta: node.isStatic ? [{ key: 'static', value: '✓' }] : [] }; + case 'stem_note': + return { typeTag: 'stem_note', label: String(node.pitch), meta: [] }; + case 'article': { + const n = node.properties?.length ?? 0; + return { typeTag: 'article', label: node.name, meta: n ? [{ key: 'props', value: n }] : [] }; + } + default: + return { typeTag: node.type, label: node.type, meta: [] }; + } +} diff --git a/test-parser.mjs b/test-parser.mjs index 9b35550..5fd31fd 100644 --- a/test-parser.mjs +++ b/test-parser.mjs @@ -6,6 +6,7 @@ import { readFileSync } from 'fs'; import { parseAstLog, buildModel } from './static/ast-parser.js'; import { exportInstrument, patchScore } from './static/exporter.js'; import { stressorToString } from './static/util.js'; +import { shortView } from './static/node-views.js'; const FIXTURE = new URL('./fixtures/ast.log', import.meta.url); const text = readFileSync(FIXTURE, 'utf8'); @@ -667,6 +668,21 @@ ok('adjacent: null when absent', adjOffset.stemNotes[0].adjacent === null); ok('adjacent: false when False', adjOffset.stemNotes[1].adjacent === false); ok('adjacent: true when True', adjOffset.stemNotes[2].adjacent === true); +section('shortView'); +ok('shortView null → ?', shortView(null).typeTag === '?'); +ok('shortView score', shortView(model).typeTag === 'score'); +ok('shortView score label', shortView(model).label === model.info?.title); +ok('shortView score meta', shortView(model).meta.some(m => m.key === 'composer')); +ok('shortView instrument', shortView(model.instruments[0]).typeTag === 'instrument'); +ok('shortView instrument label',shortView(model.instruments[0]).label === model.instruments[0].name); +ok('shortView bar', shortView(model.bars[0]).typeTag === 'bar'); +ok('shortView bar label', shortView(model.bars[0]).label === model.bars[0].id); +ok('shortView article', shortView(model.articles[0]).typeTag === 'article'); +const svV = model.instruments[0]?.variations[0]; +if (svV) { + ok('shortView variation root', shortView(svV).label === '(root variation)' || shortView(svV).label.startsWith('ATTR')); +} + section('unknownSlots graceful degradation'); const UNK_FIXTURE = `00 instrument 'test' 01 character.FUTURE_SLOT foo='bar'