We will use ajvMetadata to demonstrate how to get Modélico to generate complex JSON schemas. This is also an example of a schema with circular references.
The Shape in the inner types can be either a Diamond or a Circle. Let's look at their definitions:
constShapeType=M.Enum.fromArray(['CIRCLE','DIAMOND'])// We are going to use this metadata in several places, so by reusing it, we// not only save unnecessary processing, but our generated JSON schema will// also be more compact.constgreaterThanZero=number({ exclusiveMinimum:0})constreviver= (k, v) => {if (k !=='') {return v }switch (v.type) {caseShapeType.CIRCLE().toJSON():returnnewCircle(v)caseShapeType.DIAMOND().toJSON():returnnewDiamond(v)default:throwTypeError('Unsupported or missing shape type in the Shape reviver.') }}classShapeextendsM.Base {toJSON () {constfields=M.fields(this)let type// the generated JSON must contain runtime type information for Modélico// to be able to revive it laterswitch (this[M.symbols.typeSymbol]()) {case Circle: type =ShapeType.CIRCLE()breakcase Diamond: type =ShapeType.DIAMOND()breakdefault:throwTypeError('Unsupported Shape in the toJSON method.') }returnObject.freeze(Object.assign({type}, fields)) }staticinnerTypes () {returnObject.freeze({// notice the self-reference here and how the subclasses are// going to extend Shape's inner types relatedShape:maybe(_(Shape)) }) }staticmetadata () {// We are going to use meta so that M.getSchema can give us a more// robust JSON schema. If you don't need that, you could return the// baseMetadata directly.constbaseMetadata=Object.assign({},base(Shape), {reviver})returnmeta(baseMetadata, {}, {}, () => ({ anyOf: [ Circle, Diamond ].map(x =>M.getSchema(base(x),false)) })) }}
Now remember how we have been using ajvMetadata and even enhanced the Shape metadata to account for its subtypes. This is going to allow us to get a very detailed schema that would not be easy to write by hand.
Note: definitions are sequentially named to avoid collisions. In the example below, the definition numbers have gaps because some of them got reserved in case they'd be reused. Short sub-schemas (less than 2 keys and not arrays) are always inlined.