Add /api/
This commit is contained in:
parent
8538b34755
commit
63ac3c83e5
6 changed files with 255 additions and 5 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
node_modules
|
||||
.vitepress/dist
|
||||
api
|
||||
components
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
lang: "en-US",
|
||||
title: 'Profectus',
|
||||
description: 'A game engine that grows with you.',
|
||||
head: [
|
||||
['link', { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Roboto+Mono:ital@0;1' }],
|
||||
['link', { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,600;1,400' }],
|
||||
['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' }],
|
||||
['link', { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicon-32x32.png' }],
|
||||
['link', { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/favicon-16x16.png' }],
|
||||
|
@ -71,7 +72,7 @@ module.exports = {
|
|||
|
||||
function generateAPISidebar() {
|
||||
const modules = fs.readdirSync("./api/modules").map(file => file.substr(0, file.length - 3));
|
||||
const folders = {};
|
||||
const moduleFolders = {};
|
||||
modules.forEach(file => {
|
||||
// Split by _, but not break_eternity
|
||||
const pieces = file.replace("break_eternity", "break~eternity").split(/_/).map(piece => piece === "break~eternity" ? "break_eternity" : piece);
|
||||
|
@ -82,9 +83,60 @@ function generateAPISidebar() {
|
|||
acc[curr] = { text: camelToTitle(curr), children: [] };
|
||||
}
|
||||
return acc[curr].children;
|
||||
}, folders).push(lineItem);
|
||||
}, moduleFolders).push(lineItem);
|
||||
});
|
||||
const sidebar = processFolders(moduleFolders);
|
||||
|
||||
const componentFolders = [];
|
||||
walk("./api/components", componentFolders);
|
||||
sidebar.unshift({
|
||||
text: "Components",
|
||||
children: componentFolders
|
||||
});
|
||||
|
||||
walk("./api/features", sidebar.find(item => item.text === "Features").children);
|
||||
|
||||
sort(sidebar);
|
||||
|
||||
return sidebar;
|
||||
}
|
||||
|
||||
function sort(sidebar) {
|
||||
sidebar.filter(sidebar => !!sidebar.children).forEach(item => sort(item.children));
|
||||
sidebar.sort((a, b) => {
|
||||
if (a.children && !b.children) {
|
||||
return -1;
|
||||
} else if (!a.children && b.children) {
|
||||
return 1;
|
||||
} else if (a.text > b.text) {
|
||||
return 1;
|
||||
} else if (a.text < b.text) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function walk(dir, sidebar) {
|
||||
const files = fs.readdirSync(dir);
|
||||
files.forEach(file => {
|
||||
const resolvedFile = path.join(dir, file);
|
||||
const stat = fs.statSync(resolvedFile);
|
||||
if (stat.isDirectory()) {
|
||||
let folder = sidebar.find(item => item.text === camelToTitle(file));
|
||||
if (!folder) {
|
||||
folder = {
|
||||
text: camelToTitle(file),
|
||||
children: []
|
||||
};
|
||||
sidebar.push(folder);
|
||||
}
|
||||
walk(resolvedFile, folder.children);
|
||||
} else {
|
||||
sidebar.push({ text: camelToTitle(file.substr(0, file.length - 3)), link: resolvedFile.substr(0, resolvedFile.length - 3) + ".html" });
|
||||
}
|
||||
});
|
||||
return processFolders(folders);
|
||||
}
|
||||
|
||||
function camelToTitle(camel) {
|
||||
|
|
|
@ -22,3 +22,18 @@ tr:nth-child(2n) {
|
|||
font-size: 0.9rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
p.sidebar-link-item {
|
||||
color: var(--c-text-lighter);
|
||||
}
|
||||
|
||||
pre {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
border-radius: 3px;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-family: var(--code-font-family);
|
||||
font-size: 0.85em;
|
||||
color: var(--c-text-light);
|
||||
background-color: var(--code-inline-bg-color);
|
||||
}
|
||||
|
|
32
copyComponents.js
Normal file
32
copyComponents.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
function walk(dir, dest) {
|
||||
fs.readdir(dir, (err, list) => {
|
||||
list.forEach(file => {
|
||||
const resolvedFile = path.resolve(dir, file);
|
||||
fs.stat(resolvedFile, (err, stat) => {
|
||||
if (stat.isDirectory()) {
|
||||
walk(resolvedFile, path.resolve(dest, file));
|
||||
} else {
|
||||
const stream = fs.createReadStream(resolvedFile);
|
||||
let lineCount = 0;
|
||||
stream.on("data", buffer => {
|
||||
let idx = -1;
|
||||
lineCount--; // Because the loop will run once for idx=-1
|
||||
do {
|
||||
idx = buffer.indexOf(10, idx + 1);
|
||||
lineCount++;
|
||||
} while (idx !== -1);
|
||||
if (lineCount > 4) {
|
||||
stream.destroy();
|
||||
fs.mkdirSync(dest, { recursive: true });
|
||||
fs.copyFileSync(resolvedFile, path.resolve(dest, file));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
walk("./components", "./api");
|
149
docgen.config.js
Normal file
149
docgen.config.js
Normal file
|
@ -0,0 +1,149 @@
|
|||
const path = require('path')
|
||||
const mdclean = require('vue-docgen-cli/lib/templates/utils').mdclean
|
||||
|
||||
module.exports = {
|
||||
componentsRoot: 'profectus/src', // the folder where CLI will start searching for components.
|
||||
components: '**/[A-Z]*.vue', // the glob to define what files should be documented as components (relative to componentRoot)
|
||||
outDir: 'components', // folder to save components docs in (relative to the current working directry)
|
||||
apiOptions: {
|
||||
jsx: true // tell vue-docgen-api that your components are using JSX to avoid conflicts with TypeScript <type> syntax
|
||||
},
|
||||
getDestFile: (file, config) =>
|
||||
path.join(config.outDir, file).replace(/\.vue$/, 'Component.md'), // specify the name of the output md file
|
||||
templates: {
|
||||
// global component template wrapping all others see #templates
|
||||
component,
|
||||
events: (events, opt) => displayUsedCols("Events", eventCols, eventShouldDisplayCol, eventGetDisplay, events, opt),
|
||||
methods: require('vue-docgen-cli/lib/templates/methods').default,
|
||||
props: (props, opt) => displayUsedCols("Props", propCols, propShouldDisplayCol, propGetDisplay, props, opt),
|
||||
slots: (slots, opt) => displayUsedCols("Slots", slotCols, slotShouldDisplayCol, slotGetDisplay, slots, opt),
|
||||
// static template to display as a tag if component is functional
|
||||
functionalTag: '**functional**'
|
||||
}
|
||||
}
|
||||
|
||||
function component(renderedUsage, // props, events, methods and slots documentation rendered
|
||||
doc, // the object returned by vue-docgen-api
|
||||
config, // the local config, useful to know the context
|
||||
fileName, // the name of the current file in the doc (to explain how to import it)
|
||||
requiresMd, // a list of all the documentation files
|
||||
// attached to the component documented. It includes documentation of subcomponents
|
||||
{ isSubComponent, hasSubComponents }) {
|
||||
const { displayName, description, docsBlocks } = doc
|
||||
return `
|
||||
# Component: ${displayName}
|
||||
|
||||
${description ? '> ' + description : ''}
|
||||
|
||||
${renderedUsage.props}
|
||||
${renderedUsage.methods}
|
||||
${renderedUsage.events}
|
||||
${renderedUsage.slots}
|
||||
${docsBlocks?.length ? '---\n' + docsBlocks.join('\n---\n') : ''}
|
||||
`
|
||||
}
|
||||
|
||||
const eventCols = ["Name", "Description", "Properties"];
|
||||
const eventShouldDisplayCol = {
|
||||
[eventCols[0]]: event => event.name,
|
||||
[eventCols[1]]: event => event.description,
|
||||
[eventCols[2]]: event => event.properties?.length
|
||||
}
|
||||
const eventGetDisplay = {
|
||||
[eventCols[0]]: event => `<pre>${clean(event.name)}</pre>`,
|
||||
[eventCols[1]]: event => clean(event.description || ""),
|
||||
[eventCols[2]]: event => {
|
||||
if (!event.properties) return "";
|
||||
return event.properties.map(property => {
|
||||
const { name, description, type } = property
|
||||
if (!type) {
|
||||
return ''
|
||||
}
|
||||
return `**${name}** <pre>${clean(type.names.length ? type.names.join(', ') : '')}</pre> - ${description}`
|
||||
}).join('<br/>')
|
||||
}
|
||||
}
|
||||
|
||||
const propCols = ["Name", "Types", "Description", "Values", "Default"];
|
||||
const propShouldDisplayCol = {
|
||||
[propCols[0]]: pr => pr.name,
|
||||
[propCols[1]]: pr => pr.type?.name,
|
||||
[propCols[2]]: pr => pr.description || pr.tags,
|
||||
[propCols[3]]: pr => pr.values,
|
||||
[propCols[4]]: pr => pr.defaultValue
|
||||
}
|
||||
const propGetDisplay = {
|
||||
[propCols[0]]: pr => `<pre>${clean(pr.name)}</pre>` + (pr.required ? "*" : ""),
|
||||
[propCols[1]]: pr => {
|
||||
let n = pr.type?.name ?? ''
|
||||
if (n === "union") n = pr.type?.elements.map(el => el.name).join(' | ')
|
||||
if (n === "Array") n = (pr.type?.elements.length > 1 ? "(" : "") + pr.type?.elements.map(el => el.name).join(' | ') + (pr.type?.elements.length > 1 ? ")" : "") + "[]"
|
||||
return n ? '<pre>' + clean(n) + '</pre>' : ''
|
||||
},
|
||||
[propCols[2]]: pr => clean((pr.description ?? '') + renderTags(pr.tags)),
|
||||
[propCols[3]]: pr => clean(pr.values?.map(pv => `\`${pv}\``).join(', ') ?? '-'),
|
||||
[propCols[4]]: pr => clean(pr.defaultValue?.value ?? '')
|
||||
}
|
||||
|
||||
const slotCols = ["Name", "Description", "Bindings"];
|
||||
const slotShouldDisplayCol = {
|
||||
[slotCols[0]]: slot => slot.name,
|
||||
[slotCols[1]]: slot => slot.description,
|
||||
[slotCols[2]]: slot => slot.bindings?.length
|
||||
}
|
||||
const slotGetDisplay = {
|
||||
[slotCols[0]]: slot => `<pre>${clean(slot.name)}</pre>`,
|
||||
[slotCols[1]]: slot => clean(slot.description || ""),
|
||||
[slotCols[2]]: slot => {
|
||||
if (!slot.bindings) return "";
|
||||
return slot.bindings.map(binding => {
|
||||
const { name, description, type } = binding
|
||||
if (!type) {
|
||||
return ''
|
||||
}
|
||||
return `**${name}** <pre>${
|
||||
type.name === 'union' && type.elements
|
||||
? type.elements.map(({ name: insideName }) => insideName).join(', ')
|
||||
: type.name
|
||||
}</pre> - ${description}`
|
||||
}).join('<br/>')
|
||||
}
|
||||
}
|
||||
|
||||
function displayUsedCols(title, cols, shouldDisplayCol, getDisplay, rows, opt) {
|
||||
cols = cols.filter(col => rows.some(shouldDisplayCol[col]));
|
||||
if (!cols) return "";
|
||||
|
||||
let output = `\n${opt.isSubComponent || opt.hasSubComponents ? '#' : ''}## ${title}\n|`;
|
||||
cols.forEach(col => (output += ` ${col} |`));
|
||||
output += `\n|`;
|
||||
cols.forEach(col => (output += ' :-- |'));
|
||||
output += '\n';
|
||||
|
||||
rows.forEach(row => {
|
||||
output += "|";
|
||||
cols.forEach(col => (output += ` ${getDisplay[col](row)} |`));
|
||||
output += "\n";
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function isTag(v) {
|
||||
return !!(v).content
|
||||
}
|
||||
|
||||
function renderTags(tags) {
|
||||
if (!tags) {
|
||||
return ''
|
||||
}
|
||||
return Object.entries(tags)
|
||||
.map(([tag, values]) => {
|
||||
return values.map(v => `<br/>\`@${tag}\` ${isTag(v) ? v.content : v.description}`).join('')
|
||||
})
|
||||
.join('')
|
||||
}
|
||||
|
||||
function clean(str) {
|
||||
return mdclean(str).replace(/<br\/>/g, '_br/_').replace(/>/g, '\\>').replace(/_br\/_/g, '<br/>')
|
||||
}
|
|
@ -7,7 +7,8 @@
|
|||
"serve": "vitepress serve",
|
||||
"dev": "vitepress dev",
|
||||
"build": "vitepress build",
|
||||
"typedoc": "cd profectus && vue-typedoc --logLevel Verbose --plugin typedoc-plugin-markdown --hideBreadcrumbs --hideInPageTOC --entryDocument index.md --plugin typedoc-plugin-rename-defaults --plugin typedoc-plugin-mdn-links"
|
||||
"typedoc": "cd profectus && vue-typedoc --logLevel Verbose --plugin typedoc-plugin-markdown --hideBreadcrumbs --hideInPageTOC --entryDocument index.md --plugin typedoc-plugin-rename-defaults --plugin typedoc-plugin-mdn-links",
|
||||
"docgen": "vue-docgen -c docgen.config.js && node copyComponents.js"
|
||||
},
|
||||
"repository": "git+https://github.com/profectus-engine/profectus-docs.git",
|
||||
"author": "thepaperpilot",
|
||||
|
|
Loading…
Reference in a new issue