Validation

validate(ensemble, { meshes }) returns problems and never throws. The two consumers want different things from the same call: an editor shows everything and keeps working, while a generator must decide whether to emit.

A bare string[] forces the generator to either reject on cosmetic warnings or parse prose to tell them apart — and it will parse prose. So a problem is structured:

import { validate } from 'tosijs-3d-ensemble'

const problems = validate(ensemble, { meshes: new Set(library.getNames()) })
const fatal = problems.filter((p) => p.severity === 'error')

path is a JSON Pointer into the ensemble, which is what lets the editor put a message on the field rather than in a list at the bottom of the screen.

Two checks worth more than the rest