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.
This commit is contained in:
Alois Klink 2022-12-22 01:19:02 +00:00
parent 58b43976ff
commit 52a1243da5
7 changed files with 217 additions and 2116 deletions

View File

@ -2,6 +2,7 @@ import { build, InlineConfig, type PluginOption } from 'vite';
import { resolve } from 'path';
import { fileURLToPath } from 'url';
import jisonPlugin from './jisonPlugin.js';
import jsonSchemaPlugin from './jsonSchemaPlugin.js';
import { readFileSync } from 'fs';
import typescript from '@rollup/plugin-typescript';
import { visualizer } from 'rollup-plugin-visualizer';
@ -121,6 +122,7 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
},
plugins: [
jisonPlugin(),
jsonSchemaPlugin(), // handles `.schema.yaml` files
// @ts-expect-error According to the type definitions, rollup plugins are incompatible with vite
typescript({ compilerOptions: { declaration: false } }),
istanbul({

150
.vite/jsonSchemaPlugin.ts Normal file
View File

@ -0,0 +1,150 @@
import { load, JSON_SCHEMA } from 'js-yaml';
import assert from 'node:assert';
import Ajv2019, { type JSONSchemaType } from 'ajv/dist/2019.js';
import { PluginOption } from 'vite';
import type { MermaidConfig, BaseDiagramConfig } from '../packages/mermaid/src/config.type.js';
/**
* 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',
'quadrantChart',
'requirement',
'mindmap',
'timeline',
'gitGraph',
'c4',
'sankey',
] as const;
/**
* 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)) {
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.
*/
export default function jsonSchemaPlugin(): PluginOption {
return {
name: 'json-schema-plugin',
transform(src: string, id: string) {
const idAsUrl = new URL(id, 'file:///');
if (!idAsUrl.pathname.endsWith('schema.yaml')) {
return;
}
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
};
}
},
};
}

View File

@ -14,7 +14,7 @@
#### Defined in
[defaultConfig.ts:2300](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2300)
[defaultConfig.ts:266](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L266)
---
@ -22,35 +22,12 @@
`Const` **default**: `Partial`<`MermaidConfig`>
**Configuration methods in Mermaid version 8.6.0 have been updated, to learn more\[[click
here](8.6.0_docs.md)].**
Default mermaid configuration options.
## **What follows are config instructions for older versions**
These are the default options which can be overridden with the initialization call like so:
**Example 1:**
```js
mermaid.initialize({ flowchart: { htmlLabels: false } });
```
**Example 2:**
```html
<script>
const config = {
startOnLoad: true,
flowchart: { useMaxWidth: true, htmlLabels: true, curve: 'cardinal' },
securityLevel: 'loose',
};
mermaid.initialize(config);
</script>
```
A summary of all options and their defaults is found [here](#mermaidapi-configuration-defaults).
A description of each option follows below.
Please see the Mermaid config JSON Schema for the default JSON values.
Non-JSON JS default values are listed in this file, e.g. functions, or
`undefined` (explicitly set so that `configKeys` finds them).
#### Defined in
[defaultConfig.ts:33](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L33)
[defaultConfig.ts:16](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L16)

View File

@ -81,6 +81,7 @@
"@vitest/coverage-v8": "^0.32.2",
"@vitest/spy": "^0.32.2",
"@vitest/ui": "^0.32.2",
"ajv": "^8.12.0",
"concurrently": "^8.0.1",
"cors": "^2.8.5",
"coveralls": "^3.1.1",

File diff suppressed because it is too large Load Diff

View File

@ -71,6 +71,9 @@ importers:
'@vitest/ui':
specifier: ^0.32.2
version: 0.32.2(vitest@0.32.2)
ajv:
specifier: ^8.12.0
version: 8.12.0
concurrently:
specifier: ^8.0.1
version: 8.0.1
@ -663,13 +666,13 @@ packages:
resolution: {integrity: sha512-qe8Nmh9rYI/HIspLSTwtbMFPj6dISG6+dJnOguTlPNXtCvS2uezdxscVBb7/3DrmNbQK49TDqpkSQ1chbRGdpQ==}
dev: true
/@apideck/better-ajv-errors@0.3.6(ajv@8.11.0):
/@apideck/better-ajv-errors@0.3.6(ajv@8.12.0):
resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==}
engines: {node: '>=10'}
peerDependencies:
ajv: '>=8'
dependencies:
ajv: 8.11.0
ajv: 8.12.0
json-schema: 0.4.0
jsonpointer: 5.0.1
leven: 3.1.0
@ -2258,7 +2261,7 @@ packages:
engines: {node: '>=v14'}
dependencies:
'@commitlint/types': 17.4.4
ajv: 8.11.0
ajv: 8.12.0
dev: true
/@commitlint/ensure@17.4.4:
@ -5799,7 +5802,7 @@ packages:
indent-string: 5.0.0
dev: true
/ajv-formats@2.1.1(ajv@8.11.0):
/ajv-formats@2.1.1(ajv@8.12.0):
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
ajv: ^8.0.0
@ -5807,7 +5810,7 @@ packages:
ajv:
optional: true
dependencies:
ajv: 8.11.0
ajv: 8.12.0
dev: true
/ajv-keywords@3.5.2(ajv@6.12.6):
@ -5818,12 +5821,12 @@ packages:
ajv: 6.12.6
dev: true
/ajv-keywords@5.1.0(ajv@8.11.0):
/ajv-keywords@5.1.0(ajv@8.12.0):
resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==}
peerDependencies:
ajv: ^8.8.2
dependencies:
ajv: 8.11.0
ajv: 8.12.0
fast-deep-equal: 3.1.3
dev: true
@ -5836,8 +5839,8 @@ packages:
uri-js: 4.4.1
dev: true
/ajv@8.11.0:
resolution: {integrity: sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==}
/ajv@8.12.0:
resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
dependencies:
fast-deep-equal: 3.1.3
json-schema-traverse: 1.0.0
@ -11063,7 +11066,7 @@ packages:
/light-my-request@4.12.0:
resolution: {integrity: sha512-0y+9VIfJEsPVzK5ArSIJ8Dkxp8QMP7/aCuxCUtG/tr9a2NoOf/snATE/OUc05XUplJCEnRh6gTkH7xh9POt1DQ==}
dependencies:
ajv: 8.11.0
ajv: 8.12.0
cookie: 0.5.0
process-warning: 1.0.0
set-cookie-parser: 2.6.0
@ -13514,9 +13517,9 @@ packages:
engines: {node: '>= 12.13.0'}
dependencies:
'@types/json-schema': 7.0.11
ajv: 8.11.0
ajv-formats: 2.1.1(ajv@8.11.0)
ajv-keywords: 5.1.0(ajv@8.11.0)
ajv: 8.12.0
ajv-formats: 2.1.1(ajv@8.12.0)
ajv-keywords: 5.1.0(ajv@8.12.0)
dev: true
/search-insights@2.6.0:
@ -15924,7 +15927,7 @@ packages:
resolution: {integrity: sha512-CttE7WCYW9sZC+nUYhQg3WzzGPr4IHmrPnjKiu3AMXsiNQKx+l4hHl63WTrnicLmKEKHScWDH8xsGBdrYgtBzg==}
engines: {node: '>=16.0.0'}
dependencies:
'@apideck/better-ajv-errors': 0.3.6(ajv@8.11.0)
'@apideck/better-ajv-errors': 0.3.6(ajv@8.12.0)
'@babel/core': 7.12.3
'@babel/preset-env': 7.20.2(@babel/core@7.12.3)
'@babel/runtime': 7.21.0
@ -15932,7 +15935,7 @@ packages:
'@rollup/plugin-node-resolve': 11.2.1(rollup@2.79.1)
'@rollup/plugin-replace': 2.4.2(rollup@2.79.1)
'@surma/rollup-plugin-off-main-thread': 2.2.3
ajv: 8.11.0
ajv: 8.12.0
common-tags: 1.8.2
fast-json-stable-stringify: 2.1.0
fs-extra: 9.1.0

View File

@ -1,4 +1,5 @@
import jison from './.vite/jisonPlugin.js';
import jsonSchemaPlugin from './.vite/jsonSchemaPlugin.js';
import typescript from '@rollup/plugin-typescript';
import { defineConfig } from 'vitest/config';
@ -8,6 +9,7 @@ export default defineConfig({
},
plugins: [
jison(),
jsonSchemaPlugin(), // handles .schema.yaml JSON Schema files
// @ts-expect-error According to the type definitions, rollup plugins are incompatible with vite
typescript({ compilerOptions: { declaration: false } }),
],