mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 05:23:40 +00:00
OpenAPI: CLI support configuration files
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
---
|
||||
'@fuma-docs/openapi': minor
|
||||
---
|
||||
|
||||
**Support generating docs for OpenAPI schema**
|
||||
|
||||
In `openapi.config.js`:
|
||||
|
||||
```js
|
||||
/**
|
||||
* @type {import("@fuma-docs/openapi").Config}
|
||||
*/
|
||||
module.exports = {
|
||||
input: ['./petstore.yaml'],
|
||||
output: './content/docs',
|
||||
per: 'tag',
|
||||
render: (title, description) => {
|
||||
return {
|
||||
frontmatter: [
|
||||
'---',
|
||||
`title: ${title}`,
|
||||
`description: ${description}`,
|
||||
'toc: false',
|
||||
'---',
|
||||
].join('\n'),
|
||||
};
|
||||
},
|
||||
};
|
||||
```
|
||||
@@ -14,7 +14,6 @@ node_modules
|
||||
# outputs
|
||||
.turbo
|
||||
.next
|
||||
out
|
||||
dist
|
||||
.contentlayer
|
||||
.eslintcache
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
"---Guide---",
|
||||
"index",
|
||||
"...",
|
||||
"---API---",
|
||||
"...api",
|
||||
"---Components---",
|
||||
"...components",
|
||||
"---Blocks---",
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { resolve, join } from 'node:path';
|
||||
import { generateTags } from '@fuma-docs/openapi';
|
||||
|
||||
const folder = resolve('./content/docs/ui/api');
|
||||
|
||||
generateTags('./petstore.yaml', {
|
||||
render(title, description) {
|
||||
return {
|
||||
frontmatter: [
|
||||
'---',
|
||||
`title: ${title}`,
|
||||
`description: ${description}`,
|
||||
'toc: false',
|
||||
'---',
|
||||
].join('\n'),
|
||||
};
|
||||
},
|
||||
}).then((tags) => {
|
||||
tags.forEach(({ tag, content }) => {
|
||||
writeFileSync(join(folder, `${tag.toLowerCase()}.mdx`), content);
|
||||
console.log(`Generated page for ${tag}`);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @type {import("@fuma-docs/openapi").Config}
|
||||
*/
|
||||
module.exports = {
|
||||
input: ['./petstore.yaml'],
|
||||
output: './content/docs/headless',
|
||||
per: 'tag',
|
||||
render: (title, description) => {
|
||||
return {
|
||||
frontmatter: [
|
||||
'---',
|
||||
`title: ${title}`,
|
||||
`description: ${description}`,
|
||||
'toc: false',
|
||||
'---',
|
||||
].join('\n'),
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
"scripts": {
|
||||
"build": "pnpm build:openapi && next build && pnpm build:index",
|
||||
"build:index": "node ./update-index.mjs",
|
||||
"build:openapi": "node ./generate-docs.mjs",
|
||||
"build:openapi": "fuma-docs-openapi",
|
||||
"build:shaders": "glslx shaders/rain.glsl --output=shaders/rain.min.js --format=js --renaming=internal-only",
|
||||
"dev": "next dev",
|
||||
"lint": "next lint",
|
||||
|
||||
@@ -1,11 +1,102 @@
|
||||
#!/usr/bin/env node
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { generate } from './generate';
|
||||
import { writeFileSync, mkdirSync } from 'node:fs';
|
||||
import { dirname, join, parse, resolve } from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import type { GenerateOptions } from './generate';
|
||||
import { generate, generateTags } from './generate';
|
||||
|
||||
const path = process.argv[2];
|
||||
const output = process.argv[3];
|
||||
async function main(): Promise<void> {
|
||||
const configName = process.argv[2];
|
||||
const {
|
||||
input,
|
||||
output,
|
||||
name: nameFn,
|
||||
per = 'file',
|
||||
render,
|
||||
} = await readConfig(configName);
|
||||
const outputDir = resolve(output);
|
||||
|
||||
void generate(path).then((res) => {
|
||||
writeFileSync(output, res);
|
||||
console.log(`Generated: ${res.length} characters`);
|
||||
});
|
||||
const options = {
|
||||
render,
|
||||
};
|
||||
|
||||
await Promise.all(
|
||||
input.map(async (file) => {
|
||||
const path = resolve(file);
|
||||
let filename = parse(path).name;
|
||||
filename = nameFn?.('file', filename) ?? filename;
|
||||
|
||||
if (per === 'file') {
|
||||
const outPath = join(outputDir, `${filename}.mdx`);
|
||||
|
||||
const result = await generate(path, options);
|
||||
write(outPath, result);
|
||||
console.log(`Generated: ${outPath}`);
|
||||
} else {
|
||||
const results = await generateTags(path, options);
|
||||
|
||||
results.forEach((result) => {
|
||||
let tagName = result.tag;
|
||||
tagName =
|
||||
nameFn?.('tag', tagName) ??
|
||||
tagName.toLowerCase().replace(/\s+/g, '-');
|
||||
|
||||
const outPath = join(outputDir, `${filename}/${tagName}.mdx`);
|
||||
|
||||
write(outPath, result.content);
|
||||
console.log(`Generated: ${outPath}`);
|
||||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function write(path: string, content: string): void {
|
||||
mkdirSync(dirname(path), { recursive: true });
|
||||
writeFileSync(path, content);
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
/**
|
||||
* Schema files
|
||||
*/
|
||||
input: string[];
|
||||
|
||||
/**
|
||||
* Output directory
|
||||
*/
|
||||
output: string;
|
||||
|
||||
/**
|
||||
* tag: Generate a page for each tag
|
||||
*
|
||||
* file: Generate a page for each schema
|
||||
*
|
||||
* @defaultValue tag
|
||||
*/
|
||||
per?: 'tag' | 'file';
|
||||
|
||||
/**
|
||||
* Specify name for output file
|
||||
*/
|
||||
name?: (type: 'file' | 'tag', name: string) => string;
|
||||
|
||||
/**
|
||||
* Modify output file
|
||||
*/
|
||||
render?: NonNullable<GenerateOptions['render']>;
|
||||
}
|
||||
|
||||
async function readConfig(name = 'openapi.config.js'): Promise<Config> {
|
||||
const path = resolve(process.cwd(), name);
|
||||
const result = (await import(pathToFileURL(path).toString())) as {
|
||||
default: Config;
|
||||
};
|
||||
|
||||
if (typeof result.default !== 'object')
|
||||
throw new Error('Invalid configuration');
|
||||
|
||||
return result.default;
|
||||
}
|
||||
|
||||
void main();
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './generate';
|
||||
export * from './types';
|
||||
export type { Config } from './bin';
|
||||
|
||||
@@ -8,12 +8,13 @@ describe('Generate documents', () => {
|
||||
fileURLToPath(new URL('./fixtures/petstore.yaml', import.meta.url)),
|
||||
);
|
||||
|
||||
for (const tag of tags) {
|
||||
// eslint-disable-next-line no-await-in-loop -- Ignore
|
||||
await expect(tag.content).toMatchFileSnapshot(
|
||||
`./test/petstore-out/${tag.tag}.mdx`,
|
||||
);
|
||||
}
|
||||
await Promise.all(
|
||||
tags.map(async (tag) =>
|
||||
expect(tag.content).toMatchFileSnapshot(
|
||||
`./out/petstore/${tag.tag}.mdx`,
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('Pet Store', async () => {
|
||||
@@ -21,11 +22,10 @@ describe('Generate documents', () => {
|
||||
fileURLToPath(new URL('./fixtures/museum.yaml', import.meta.url)),
|
||||
);
|
||||
|
||||
for (const tag of tags) {
|
||||
// eslint-disable-next-line no-await-in-loop -- Ignore
|
||||
await expect(tag.content).toMatchFileSnapshot(
|
||||
`./test/museum-out/${tag.tag}.mdx`,
|
||||
);
|
||||
}
|
||||
await Promise.all(
|
||||
tags.map(async (tag) =>
|
||||
expect(tag.content).toMatchFileSnapshot(`./out/museum/${tag.tag}.mdx`),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user