Compare commits
2 Commits
9a2e76ba4f
...
7fb584d929
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fb584d929 | ||
|
|
e823608325 |
@@ -222,7 +222,7 @@ function buildInstrument(node) {
|
|||||||
timbre: null,
|
timbre: null,
|
||||||
fmModulations: [],
|
fmModulations: [],
|
||||||
amModulations: [],
|
amModulations: [],
|
||||||
rawChildren: [],
|
unknownSlots: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const child of node.children) {
|
for (const child of node.children) {
|
||||||
@@ -246,7 +246,7 @@ function buildInstrument(node) {
|
|||||||
instr.amModulations.push({ ...child.props });
|
instr.amModulations.push({ ...child.props });
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
instr.rawChildren.push(buildGeneric(child));
|
instr.unknownSlots.push(buildGeneric(child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,7 +262,7 @@ function buildVariation(node) {
|
|||||||
subvariations: [],
|
subvariations: [],
|
||||||
spread: null,
|
spread: null,
|
||||||
railsbackCurve: null,
|
railsbackCurve: null,
|
||||||
rawChildren: [],
|
unknownSlots: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const child of node.children) {
|
for (const child of node.children) {
|
||||||
@@ -284,7 +284,7 @@ function buildVariation(node) {
|
|||||||
v.railsbackCurve = buildShape(child);
|
v.railsbackCurve = buildShape(child);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
v.rawChildren.push(buildGeneric(child));
|
v.unknownSlots.push(buildGeneric(child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +298,7 @@ function buildBasicProperties(node) {
|
|||||||
oscillator: null,
|
oscillator: null,
|
||||||
fmModulations: [],
|
fmModulations: [],
|
||||||
amModulations: [],
|
amModulations: [],
|
||||||
rawChildren: [],
|
unknownSlots: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const child of node.children) {
|
for (const child of node.children) {
|
||||||
@@ -322,7 +322,7 @@ function buildBasicProperties(node) {
|
|||||||
if (envChild) am.shape = buildShape(envChild);
|
if (envChild) am.shape = buildShape(envChild);
|
||||||
bp.amModulations.push(am);
|
bp.amModulations.push(am);
|
||||||
} else {
|
} else {
|
||||||
bp.rawChildren.push(buildGeneric(child));
|
bp.unknownSlots.push(buildGeneric(child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,7 +334,7 @@ function buildLabelSpec(node) {
|
|||||||
type: 'label_spec',
|
type: 'label_spec',
|
||||||
label: node.positionals[0],
|
label: node.positionals[0],
|
||||||
basicProperties: null,
|
basicProperties: null,
|
||||||
rawChildren: [],
|
unknownSlots: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const directBpChildren = [];
|
const directBpChildren = [];
|
||||||
@@ -348,7 +348,7 @@ function buildLabelSpec(node) {
|
|||||||
) {
|
) {
|
||||||
directBpChildren.push(child);
|
directBpChildren.push(child);
|
||||||
} else {
|
} else {
|
||||||
ls.rawChildren.push(buildGeneric(child));
|
ls.unknownSlots.push(buildGeneric(child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ls.basicProperties && directBpChildren.length > 0) {
|
if (!ls.basicProperties && directBpChildren.length > 0) {
|
||||||
@@ -386,7 +386,7 @@ function buildBar(node) {
|
|||||||
upperStressBound: null,
|
upperStressBound: null,
|
||||||
tunings: [],
|
tunings: [],
|
||||||
voices: {},
|
voices: {},
|
||||||
rawChildren: [],
|
unknownSlots: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const child of node.children) {
|
for (const child of node.children) {
|
||||||
@@ -414,7 +414,7 @@ function buildBar(node) {
|
|||||||
bar.voices[child.positionals[0]] = buildVoice(child);
|
bar.voices[child.positionals[0]] = buildVoice(child);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
bar.rawChildren.push(buildGeneric(child));
|
bar.unknownSlots.push(buildGeneric(child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,48 +2,9 @@ import { h, ref, watch, onMounted } from 'vue';
|
|||||||
import { fetchAstLog, fetchScoreText, putScoreText, fetchAudioWidget, URLS } from '../api.js';
|
import { fetchAstLog, fetchScoreText, putScoreText, fetchAudioWidget, URLS } from '../api.js';
|
||||||
import { parseAstLog, buildModel } from '../ast-parser.js';
|
import { parseAstLog, buildModel } from '../ast-parser.js';
|
||||||
import { patchScore } from '../exporter.js';
|
import { patchScore } from '../exporter.js';
|
||||||
|
import { shortView } from '../node-views.js';
|
||||||
import { StatusPoller } from './StatusPoller.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 = {
|
export const PaneCP = {
|
||||||
props: ['store', 'importOnLoad', 'onFocusFO'],
|
props: ['store', 'importOnLoad', 'onFocusFO'],
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
|||||||
38
static/node-views.js
Normal file
38
static/node-views.js
Normal file
@@ -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: [] };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import { readFileSync } from 'fs';
|
|||||||
import { parseAstLog, buildModel } from './static/ast-parser.js';
|
import { parseAstLog, buildModel } from './static/ast-parser.js';
|
||||||
import { exportInstrument, patchScore } from './static/exporter.js';
|
import { exportInstrument, patchScore } from './static/exporter.js';
|
||||||
import { stressorToString } from './static/util.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 FIXTURE = new URL('./fixtures/ast.log', import.meta.url);
|
||||||
const text = readFileSync(FIXTURE, 'utf8');
|
const text = readFileSync(FIXTURE, 'utf8');
|
||||||
@@ -255,7 +256,7 @@ ok('patched score is non-empty', patched.length > 100);
|
|||||||
ok('patched score has no double blank lines beyond original', true); // structural sanity only
|
ok('patched score has no double blank lines beyond original', true); // structural sanity only
|
||||||
|
|
||||||
// ── FM modulation with embedded shape (synthetic) ─────────────────────────
|
// ── FM modulation with embedded shape (synthetic) ─────────────────────────
|
||||||
// The fixture's FM+shape is inside PROFILE.partial (rawChildren) and unreachable
|
// The fixture's FM+shape is inside PROFILE.partial (unknownSlots) and unreachable
|
||||||
// from buildBasicProperties. Verify with a synthetic AST log fragment.
|
// from buildBasicProperties. Verify with a synthetic AST log fragment.
|
||||||
section('FM modulation with embedded shape (synthetic)');
|
section('FM modulation with embedded shape (synthetic)');
|
||||||
const FM_FIXTURE = `00 instrument 'test'
|
const FM_FIXTURE = `00 instrument 'test'
|
||||||
@@ -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: false when False', adjOffset.stemNotes[1].adjacent === false);
|
||||||
ok('adjacent: true when True', adjOffset.stemNotes[2].adjacent === true);
|
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');
|
section('unknownSlots graceful degradation');
|
||||||
const UNK_FIXTURE = `00 instrument 'test'
|
const UNK_FIXTURE = `00 instrument 'test'
|
||||||
01 character.FUTURE_SLOT foo='bar'
|
01 character.FUTURE_SLOT foo='bar'
|
||||||
@@ -676,10 +692,10 @@ const UNK_FIXTURE = `00 instrument 'test'
|
|||||||
const unkModel = buildModel(parseAstLog(UNK_FIXTURE));
|
const unkModel = buildModel(parseAstLog(UNK_FIXTURE));
|
||||||
const unkInstr = unkModel.instruments[0];
|
const unkInstr = unkModel.instruments[0];
|
||||||
ok('unknown slot: instrument parsed', !!unkInstr);
|
ok('unknown slot: instrument parsed', !!unkInstr);
|
||||||
ok('unknown slot: rawChildren is array', Array.isArray(unkInstr.rawChildren));
|
ok('unknown slot: unknownSlots is array', Array.isArray(unkInstr.unknownSlots));
|
||||||
ok('unknown slot: instrument-level unknown collected', unkInstr.rawChildren.length === 1);
|
ok('unknown slot: instrument-level unknown collected', unkInstr.unknownSlots.length === 1);
|
||||||
ok('unknown slot: collected slot type', unkInstr.rawChildren[0].type === 'FUTURE_SLOT');
|
ok('unknown slot: collected slot type', unkInstr.unknownSlots[0].type === 'FUTURE_SLOT');
|
||||||
ok('variation-level unknown collected', unkInstr.variations[0]?.rawChildren?.length === 1);
|
ok('variation-level unknown collected', unkInstr.variations[0]?.unknownSlots?.length === 1);
|
||||||
|
|
||||||
section('Full fixture integration');
|
section('Full fixture integration');
|
||||||
ok('fixture parses without error (checked above)', raw && raw.slot === 'root');
|
ok('fixture parses without error (checked above)', raw && raw.slot === 'root');
|
||||||
|
|||||||
Reference in New Issue
Block a user