build(docs): build JSON Schema docs

Automatically build documentation for JSON Schema.

This is only built when running with `--vitepress`,
as it currently produces loads of markdown files, which I feel like
we shouldn't be committing.

This currently manually uses some internal `jsonschema2md` functions
so that we can manually control the Markdown output.
This commit is contained in:
Alois Klink
2022-12-22 01:55:55 +00:00
parent 52a1243da5
commit 0230722d36
3 changed files with 243 additions and 4 deletions

View File

@@ -74,6 +74,7 @@
"web-worker": "^1.2.0"
},
"devDependencies": {
"@adobe/jsonschema2md": "^7.1.4",
"@types/cytoscape": "^3.19.9",
"@types/d3": "^7.4.0",
"@types/d3-sankey": "^0.12.1",
@@ -109,6 +110,7 @@
"typedoc-plugin-markdown": "^3.15.2",
"typescript": "^5.0.4",
"unist-util-flatmap": "^1.0.0",
"unist-util-visit": "^4.1.2",
"vitepress": "^1.0.0-alpha.72",
"vitepress-plugin-search": "^1.0.4-alpha.20"
},

View File

@@ -34,7 +34,7 @@ import { readFileSync, writeFileSync, mkdirSync, existsSync, rmSync, rmdirSync }
import { exec } from 'child_process';
import { globby } from 'globby';
import { JSDOM } from 'jsdom';
import type { Code, Root } from 'mdast';
import type { Code, ListItem, Root, Text } from 'mdast';
import { posix, dirname, relative, join } from 'path';
import prettier from 'prettier';
import { remark } from 'remark';
@@ -44,6 +44,7 @@ import chokidar from 'chokidar';
import mm from 'micromatch';
// @ts-ignore No typescript declaration file
import flatmap from 'unist-util-flatmap';
import { visit } from 'unist-util-visit';
const MERMAID_MAJOR_VERSION = (
JSON.parse(readFileSync('../mermaid/package.json', 'utf8')).version as string
@@ -150,6 +151,7 @@ const copyTransformedContents = (filename: string, doCopy = false, transformedCo
}
filesTransformed.add(fileInFinalDocDir);
if (doCopy) {
writeFileSync(fileInFinalDocDir, newBuffer);
}
@@ -321,6 +323,93 @@ const transformMarkdown = (file: string) => {
copyTransformedContents(file, !verifyOnly, formatted);
};
import { load, JSON_SCHEMA } from 'js-yaml';
// @ts-ignore: we're importing internal jsonschema2md functions
import { default as schemaLoader } from '@adobe/jsonschema2md/lib/schemaProxy.js';
// @ts-ignore: we're importing internal jsonschema2md functions
import { default as traverseSchemas } from '@adobe/jsonschema2md/lib/traverseSchema.js';
// @ts-ignore: we're importing internal jsonschema2md functions
import { default as buildMarkdownFromSchema } from '@adobe/jsonschema2md/lib/markdownBuilder.js';
// @ts-ignore: we're importing internal jsonschema2md functions
import { default as jsonSchemaReadmeBuilder } from '@adobe/jsonschema2md/lib/readmeBuilder.js';
/**
* Transforms the given JSON Schema into Markdown documentation
*/
async function transormJsonSchema(file: string) {
const yamlContents = readSyncedUTF8file(file);
const jsonSchema = load(yamlContents, {
filename: file,
// 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,
});
// write .schema.json files
const jsonFileName = file
.replace('.schema.yaml', '.schema.json')
.replace('src/schemas/', 'src/docs/schemas/');
copyTransformedContents(jsonFileName, !verifyOnly, JSON.stringify(jsonSchema, undefined, 2));
const schemas = traverseSchemas([schemaLoader()(file, jsonSchema)]);
// ignore output of this function
// for some reason, without calling this function, we get some broken links
// this is probably a bug in @adobe/jsonschema2md
jsonSchemaReadmeBuilder({ readme: true })(schemas);
// write Markdown files
const markdownFiles = buildMarkdownFromSchema({
header: true,
// links,
includeProperties: ['tsType'], // Custom TypeScript type
exampleFormat: 'json',
// skipProperties,
})(schemas);
for (const [name, markdownAst] of Object.entries(markdownFiles)) {
/*
* Converts list entries of shape '- tsType: () => Partial<FontConfig>'
* into '- tsType: `() => Partial<FontConfig>`' (e.g. escaping with back-ticks),
* as otherwise VitePress doesn't like the <FontConfig> bit.
*/
visit(markdownAst as Root, 'listItem', (listEntry: ListItem) => {
let listText: Text;
const blockItem = listEntry.children[0];
if (blockItem.type === 'paragraph' && blockItem.children[0].type === 'text') {
listText = blockItem.children[0];
} // @ts-expect-error: MD AST output from @adobe/jsonschema2md is technically wrong
else if (blockItem.type === 'text') {
listText = blockItem;
} else {
return; // skip
}
if (listText.value.startsWith('tsType: ')) {
listText.value = listText.value.replace(/tsType: (.*)/g, 'tsType: `$1`');
}
});
const transformed = remark()
.use(remarkGfm)
.use(remarkFrontmatter, ['yaml']) // support YAML front-matter in Markdown
.use(transformMarkdownAst, {
// mermaid project specific plugin
originalFilename: file,
addAutogeneratedWarning: !noHeader,
removeYAML: !noHeader,
})
.stringify(markdownAst as Root);
const formatted = prettier.format(transformed, {
parser: 'markdown',
...prettierConfig,
});
const newFileName = join('src', 'docs', 'config', 'schema-docs', `${name}.md`);
copyTransformedContents(newFileName, !verifyOnly, formatted);
}
}
/**
* Transform an HTML file and write the transformed file to the directory for published
* documentation
@@ -388,6 +477,14 @@ const main = async () => {
const sourceDirGlob = posix.join('.', SOURCE_DOCS_DIR, '**');
const action = verifyOnly ? 'Verifying' : 'Transforming';
if (vitepress) {
console.log(`${action} 1 .schema.yaml file`);
await transormJsonSchema('src/schemas/config.schema.yaml');
} else {
// skip because this creates so many Markdown files that it lags git
console.log('Skipping 1 .schema.yaml file');
}
const mdFileGlobs = getGlobs([posix.join(sourceDirGlob, '*.md')]);
const mdFiles = await getFilesFromGlobs(mdFileGlobs);
console.log(`${action} ${mdFiles.length} markdown files...`);