Validating a bundle
Parsing tells you a model is well formed. It cannot tell you that the schema it points at was actually published, or that a relationship names a model that exists. Those are the failures a consumer meets as a broken integration rather than as a parse error, so they get their own pass.
import { assembleBundle, validateBundle, hasErrors } from "@openhi/ours";
const bundle = assembleBundle({ ontology, models, vocabularies, schemas });const issues = validateBundle(bundle);
for (const issue of issues) { console.error(`${issue.level} ${issue.resource} ${issue.message}`);}if (hasErrors(issues)) process.exit(1);interface ValidationIssue { readonly level: "error" | "warning"; /** The URL of the resource the issue is about. */ readonly resource: string; readonly message: string;}Errors and warnings
Section titled “Errors and warnings”An error is something that will break a consumer. A relationship pointing
at a model that is not in the ontology leaves them with a dead link; a $ref
that does not resolve makes the schema uncompilable. Do not publish with any.
A warning is something worth knowing. A model with no mapsTo is valid,
and is also invisible to the integration OURS exists to enable. An ontology can
be published with warnings, and sometimes should be, but each one is a question
worth having an answer to.
hasErrors is the predicate to gate a publish on. It ignores warnings.
What is checked
Section titled “What is checked”Models
Section titled “Models”| Level | Condition |
|---|---|
| error | Two models share an id. |
| error | schema names a schema that is not in the bundle. |
| error | A relationship.target names no model in the bundle, by name or by id. |
| warning | The model publishes no schema. |
| warning | The model publishes no mapsTo alignment. |
Relationships are checked once every model is known, so a model may reference one that appears later in the bundle. Order in the document does not decide whether a forward reference is an error.
Vocabularies
Section titled “Vocabularies”| Level | Condition |
|---|---|
| error | Two vocabularies share an id. |
| warning | The vocabulary has neither codes nor a mapsTo alignment. |
An empty mapsTo counts as none. The field being present says only that
somebody typed it.
Schemas
Section titled “Schemas”| Level | Condition |
|---|---|
| error | A $ref does not resolve to a schema in the bundle. |
References resolve against the $id in scope where they were written, not
against the document they happen to sit in, and both the bundle’s documents and
every $id embedded inside them count as targets. A pointer beginning with #
is the schema’s own business and is left alone.
Schemas covers the resolution rules and why they matter.
Options
Section titled “Options”validateBundle(bundle, { warnOnMissingMapsTo: false });| Option | Default | |
|---|---|---|
warnOnMissingMapsTo |
true |
Warn about models that publish no alignment. Turn it off for an ontology that is deliberately all your own. |
Running it in CI
Section titled “Running it in CI”The check that matters is the one against the files you are about to serve, not against the objects in memory that produced them. Read the built files back:
import { assembleBundle, validateBundle, hasErrors } from "@openhi/ours";
const read = (path: string) => Bun.file(path).json();
const bundle = assembleBundle({ ontology: await read("public/ontology.json"), models: [await read("public/models.json")], vocabularies: [await read("public/vocabularies.json")], schemas: await Promise.all( [...new Bun.Glob("public/schemas/**/*.json").scanSync(".")].map(read), ),});
const issues = validateBundle(bundle);for (const issue of issues) { console.error(`${issue.level} ${issue.resource} ${issue.message}`);}if (hasErrors(issues)) process.exit(1);assembleBundle throws rather than reporting an issue for the problems that
make a bundle impossible to build at all: a duplicate url, a JSON Schema with
no $id, or a schema whose $id collides with one derived from a vocabulary.
Let those throw. They are bugs in the generator, not conditions to report on.