-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
build: use vite to get default mermaid config
Adds a vitepress JsonSchema plugin that automatically loads the Mermaid Config JSON Schema from a .schema.yaml file and gets the default values from it.
- Loading branch information
1 parent
98f22ea
commit 81b7d74
Showing
7 changed files
with
212 additions
and
1,901 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
import { load, JSON_SCHEMA } from 'js-yaml'; | ||
import assert from 'node:assert'; | ||
import Ajv2019, { type JSONSchemaType, type AnySchema } from 'ajv/dist/2019.js'; | ||
import { PluginOption } from 'vite'; | ||
|
||
// TODO, can we import these somehow? | ||
type MermaidConfig = any; | ||
type BaseDiagramConfig = any; | ||
|
||
/** | ||
* All of the keys in the mermaid config that have a mermaid diagram config. | ||
*/ | ||
const MERMAID_CONFIG_DIAGRAM_KEYS = [ | ||
'flowchart', | ||
'sequence', | ||
'gantt', | ||
'journey', | ||
'class', | ||
'state', | ||
'er', | ||
'pie', | ||
'requirement', | ||
'mindmap', | ||
'gitGraph', | ||
'timeline', | ||
'c4', | ||
]; | ||
|
||
/** | ||
* Generate default values from the JSON Schema. | ||
* | ||
* AJV does not support nested default values yet (or default values with $ref), | ||
* so we need to manually find them (this may be fixed in ajv v9). | ||
* | ||
* @param mermaidConfigSchema - The Mermaid JSON Schema to use. | ||
* @returns The default mermaid config object. | ||
*/ | ||
function generateDefaults(mermaidConfigSchema: JSONSchemaType<MermaidConfig>) { | ||
const ajv = new Ajv2019({ | ||
useDefaults: true, | ||
allowUnionTypes: true, | ||
strict: true, | ||
}); | ||
|
||
ajv.addKeyword({ | ||
keyword: 'meta:enum', // used by jsonschema2md | ||
errors: false, | ||
}); | ||
ajv.addKeyword({ | ||
keyword: 'tsType', // used by json-schema-to-typescript | ||
errors: false, | ||
}); | ||
|
||
// ajv currently doesn't support nested default values, see https://github.com/ajv-validator/ajv/issues/1718 | ||
// (may be fixed in v9) so we need to manually use sub-schemas | ||
const mermaidDefaultConfig = {}; | ||
|
||
assert.ok(mermaidConfigSchema.$defs); | ||
const baseDiagramConfig = mermaidConfigSchema.$defs.BaseDiagramConfig; | ||
|
||
for (const key of MERMAID_CONFIG_DIAGRAM_KEYS) { | ||
const subSchemaRef = mermaidConfigSchema.properties[key].$ref; | ||
const [root, defs, defName] = subSchemaRef.split('/'); | ||
assert.strictEqual(root, '#'); | ||
assert.strictEqual(defs, '$defs'); | ||
const subSchema = { | ||
$schema: mermaidConfigSchema.$schema, | ||
$defs: mermaidConfigSchema.$defs, | ||
...mermaidConfigSchema.$defs[defName], | ||
} as JSONSchemaType<BaseDiagramConfig>; | ||
|
||
const validate = ajv.compile(subSchema); | ||
|
||
mermaidDefaultConfig[key] = {}; | ||
|
||
for (const required of subSchema.required ?? []) { | ||
if (subSchema.properties[required] === undefined && baseDiagramConfig.properties[required]) { | ||
mermaidDefaultConfig[key][required] = baseDiagramConfig.properties[required].default; | ||
} | ||
} | ||
if (!validate(mermaidDefaultConfig[key])) { | ||
throw new Error( | ||
`schema for subconfig ${key} does not have valid defaults! Errors were ${JSON.stringify( | ||
validate.errors, | ||
undefined, | ||
2 | ||
)}` | ||
); | ||
} | ||
} | ||
|
||
const validate = ajv.compile(mermaidConfigSchema); | ||
|
||
if (validate(mermaidDefaultConfig)) { | ||
// console.log('Mermaid config defaults match the schema'); | ||
} else { | ||
throw new Error( | ||
`Mermaid config JSON Schema does not have valid defaults! Errors were ${JSON.stringify( | ||
validate.errors, | ||
undefined, | ||
2 | ||
)}` | ||
); | ||
} | ||
|
||
return mermaidDefaultConfig; | ||
} | ||
|
||
/** | ||
* Vite plugin that handles JSON Schemas saved as a `.schema.yaml` file. | ||
* | ||
* Use `my-example.schema.yaml?only-defaults=true` to only load the default values. | ||
* | ||
* @returns {PluginOption} | ||
*/ | ||
export default function jsonSchemaPlugin() { | ||
return { | ||
name: 'json-schema-plugin', | ||
transform(src: string, id: string) { | ||
const idAsUrl = new URL(id, 'file:///'); | ||
|
||
if (idAsUrl.pathname.endsWith('schema.yaml')) { | ||
if (idAsUrl.searchParams.get('only-defaults')) { | ||
const jsonSchema = load(src, { | ||
filename: idAsUrl.pathname, | ||
// only allow JSON types in our YAML doc (will probably be default in YAML 1.3) | ||
// e.g. `true` will be parsed a boolean `true`, `True` will be parsed as string `"True"`. | ||
schema: JSON_SCHEMA, | ||
}) as JSONSchemaType<MermaidConfig>; | ||
return { | ||
code: `export default ${JSON.stringify(generateDefaults(jsonSchema), undefined, 2)};`, | ||
map: null, // no source map | ||
}; | ||
} else { | ||
return { | ||
code: `export default ${JSON.stringify( | ||
load(src, { | ||
filename: idAsUrl.pathname, | ||
// only allow JSON types in our YAML doc (will probably be default in YAML 1.3) | ||
// e.g. `true` will be parsed a boolean `true`, `True` will be parsed as string `"True"`. | ||
schema: JSON_SCHEMA, | ||
}), | ||
undefined, | ||
2 | ||
)};`, | ||
map: null, // provide source map if available | ||
}; | ||
} | ||
} | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.