Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

Commit

Permalink
docs: auto-generate configuration api (#349)
Browse files Browse the repository at this point in the history
Co-authored-by: Pooya Parsa <[email protected]>
  • Loading branch information
danielroe and pi0 authored Aug 11, 2021
1 parent 91c6ef5 commit 052edd2
Show file tree
Hide file tree
Showing 21 changed files with 876 additions and 403 deletions.
2 changes: 2 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
5.config
schema
16 changes: 16 additions & 0 deletions docs/build.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { resolve } from 'path'
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
entries: [
{
input: resolve(__dirname, '../packages/kit/src/config/schema/index'),
outDir: 'schema',
name: 'config',
builder: 'untyped',
defaults: {
rootDir: '/project/'
}
}
]
})
5 changes: 5 additions & 0 deletions docs/content/3.server/2.api.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
navigation:
title: API
---

# API Routes

Nuxt will automatically read in any files in the `~/server/api` directory to create API endpoints.
Expand Down
1 change: 0 additions & 1 deletion docs/content/5.config/reference.md

This file was deleted.

1 change: 1 addition & 0 deletions docs/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default withDocus({
* Has to specify rootDir as we use nuxt-extend
*/
rootDir: __dirname,

/**
* Modules
*/
Expand Down
16 changes: 13 additions & 3 deletions docs/package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
{
"private": true,
"name": "docs",
"scripts": {
"dev": "nuxt dev",
"build": "nuxt generate --force-build"
"dev": "yarn gendocs && nuxt dev",
"build": "yarn gendocs && nuxt generate --force-build",
"gendocs": "unbuild && jiti ./scripts/gen-docs.ts"
},
"devDependencies": {
"@docus/app": "^1.0.38",
"@docus/github": "^1.0.3",
"@docus/social-image": "^1.0.2",
"@docus/theme": "^1.0.7",
"@docus/twitter": "^1.0.3",
"@nuxt/typescript-build": "^2.1.0"
"@nuxt/typescript-build": "^2.1.0",
"fs-extra": "^10.0.0",
"jiti": "^1.11.0",
"mkdirp": "^1.0.4",
"rimraf": "^3.0.2",
"scule": "^0.2.1",
"unbuild": "^0.4.0",
"untyped": "^0.2.7",
"upath": "^2.0.1"
}
}
150 changes: 150 additions & 0 deletions docs/scripts/gen-docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { rm, writeFile } from 'fs/promises'
import mkdirp from 'mkdirp'
import type { Schema } from 'untyped'
import { join, resolve } from 'upath'
import { kebabCase, upperFirst } from 'scule'

export async function main () {
const rootDir = resolve(__dirname, '..')
const configDir = resolve(rootDir, 'content/5.config')
await generateDocs({ outDir: configDir })
}

function generateMarkdown (schema: Schema, title: string, level: string, parentVersions: string[] = []) {
const lines: string[] = []

// Skip private
if (schema.tags?.includes('@private')) {
return []
}

// Versions
const versions = (schema.tags || []).map(t => t.match(/@version (\d+)/)?.[1]).filter(Boolean)
if (!versions.length) {
// Inherit from parent if not specified
versions.push(...parentVersions)
}
if (!versions.includes('3')) {
return []
}

// Render heading
lines.push(`${level} ${title}`, '')

// Render meta info
if (schema.type !== 'object' || !schema.properties) {
// Type and default
lines.push(`- **Type**: \`${schema.type}\``)
lines.push(`- **Version**: ${versions.join(', ')}`)
if ('default' in schema) {
lines.push('- **Default**', ...formatValue(schema.default))
}
lines.push('')
}

// Render title
if (schema.title) {
lines.push('> ' + schema.title, '')
}

// Render description
if (schema.description) {
lines.push(schema.description, '')
}

// Render @ tags
if (schema.tags) {
lines.push(...schema.tags.map(renderTag).flat())
}

// Render properties
if (schema.type === 'object') {
const keys = Object.keys(schema.properties || {}).sort()
for (const key of keys) {
const val = schema.properties[key] as Schema
const propLines = generateMarkdown(val, `\`${key}\``, level + '#', versions)
if (propLines.length) {
lines.push('', ...propLines)
}
}
}

return lines
}

const TAG_REGEX = /^@([\d\w]+)[\s\n]/i

const TagAlertType = {
note: 'note',
warning: 'warning',
deprecated: 'deprecated'
}

const InternalTypes = new Set([
'version',
'deprecated'
])

function formatValue (val) {
return ['```json', JSON.stringify(val, null, 2), '```']
}

function renderTag (tag: string) {
const type = tag.match(TAG_REGEX)?.[1]
if (!type) {
return [`<!-- ${tag} -->`]
}
if (InternalTypes.has(type)) {
return []
}
tag = tag.replace(`@${type}`, `**${upperFirst(type)}**:`)
if (TagAlertType[type]) {
return [`::alert{type="${TagAlertType[type]}"}`, tag, '::', '']
}
return tag
}

async function generateDocs ({ outDir }) {
// Prepare content directory
const start = Date.now()
console.log('Generating docs to ' + outDir)
await rm(outDir, { recursive: true }).catch(() => {})
await mkdirp(outDir)

const rootSchema = require('../schema/config.schema.json') as Schema

const keys = Object.keys(rootSchema.properties).sort()
let ctor = 1

// Generate a separate file for each section
for (const key of keys) {
const schema = rootSchema.properties[key]

const lines = generateMarkdown(schema, key, '#')

// Skip empty sections
if (lines.length < 3) {
continue
}

// Add frontmatter meta
const attributes = Object.entries({
title: key,
description: schema.title
}).map(([key, val]) => `${key}: "${val}"`)

lines.unshift('---', ...attributes, '---')

await writeFile(join(outDir, `${ctor++}.${kebabCase(key)}.md`), lines.join('\n'))
}

const frontmatter = ['---', 'navigation:', ' collapse: true', '---']
await writeFile(join(outDir, 'index.md'), frontmatter.join('\n'))

console.log(`Generate done in ${(Date.now() - start) / 1000} seconds!`)
}

main().catch((err) => {
console.error(err)
process.exit(1)
})
16 changes: 16 additions & 0 deletions docs/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"esModuleInterop": true,
"skipLibCheck": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Node",
"strict": false,
"allowJs": true,
"noUnusedLocals": true,
"resolveJsonModule": true,
"types": [
"node"
]
}
}
Loading

0 comments on commit 052edd2

Please sign in to comment.