Skip to content

Commit

Permalink
build: use vite to get default mermaid config
Browse files Browse the repository at this point in the history
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
aloisklink committed Feb 20, 2023
1 parent 98f22ea commit 81b7d74
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 1,901 deletions.
5 changes: 3 additions & 2 deletions .vite/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { visualizer } from 'rollup-plugin-visualizer';
import type { TemplateType } from 'rollup-plugin-visualizer/dist/plugin/template-types.js';
Expand Down Expand Up @@ -108,9 +109,9 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
},
},
resolve: {
extensions: ['.jison', '.js', '.ts', '.json'],
extensions: ['.jison', '.js', '.ts', '.json', '.schema.yaml'],
},
plugins: [jisonPlugin(), ...visualizerOptions(packageName, core)],
plugins: [jisonPlugin(), jsonSchemaPlugin(), ...visualizerOptions(packageName, core)],
};

if (watch && config.build) {
Expand Down
152 changes: 152 additions & 0 deletions .vite/jsonSchemaPlugin.ts
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
};
}
}
},
};
}
35 changes: 6 additions & 29 deletions docs/config/setup/modules/defaultConfig.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,43 +14,20 @@

#### Defined in

[defaultConfig.ts:2084](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L2084)
[defaultConfig.ts:260](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L260)

---

### default

`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)
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"@vitest/coverage-c8": "^0.28.4",
"@vitest/spy": "^0.28.4",
"@vitest/ui": "^0.28.4",
"ajv": "^8.12.0",
"concurrently": "^7.5.0",
"coveralls": "^3.1.1",
"cypress": "^12.0.0",
Expand Down
Loading

0 comments on commit 81b7d74

Please sign in to comment.