Skip to content

Commit b77cd15

Browse files
committed
Add docs api
1 parent a0099a7 commit b77cd15

File tree

6 files changed

+217
-0
lines changed

6 files changed

+217
-0
lines changed

.editorconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# editorconfig.org
2+
root = true
3+
4+
[*]
5+
indent_size = 2
6+
indent_style = space
7+
end_of_line = lf
8+
charset = utf-8
9+
trim_trailing_whitespace = true
10+
insert_final_newline = true
11+
12+
[*.md]
13+
trim_trailing_whitespace = false

.eslintrc.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = {
2+
'extends': 'standard',
3+
'installedESLint': true,
4+
'plugins': [
5+
'standard',
6+
'promise'
7+
]
8+
}

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# dependencies
2+
yarn.lock
3+
node_modules
4+
5+
# logs
6+
npm-debug.log

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Nuxt.js Documentation
2+
3+
> This is where the documentation is stored and served as an API
4+
5+
## Developing
6+
7+
:warning: You must at least use `node >= 7` to start the server.
8+
9+
Start a dev server on `localhost:4000`
10+
11+
```bash
12+
npm install
13+
npm run dev
14+
```

api.js

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
const fs = require('fs')
2+
const crypto = require('crypto')
3+
const os = require('os')
4+
const git = require('simple-git')()
5+
const uuid = require('uuid/v4')
6+
const micro = require('micro')
7+
const pify = require('pify')
8+
const rimraf = pify(require('rimraf'))
9+
const glob = pify(require('glob'))
10+
const marked = require('marked')
11+
const highlightjs = require('highlight.js')
12+
const fm = require('front-matter')
13+
const { resolve } = require('path')
14+
const readFile = pify(fs.readFile)
15+
const gitClone = pify(git.clone.bind(git))
16+
const send = micro.send
17+
const json = micro.json
18+
19+
// Use highlight.js for code blocks
20+
const renderer = new marked.Renderer()
21+
renderer.code = (code, language) => {
22+
const validLang = !!(language && highlightjs.getLanguage(language))
23+
const highlighted = validLang ? highlightjs.highlight(language, code).value : code
24+
return `<pre><code class="hljs ${language}">${highlighted}</code></pre>`
25+
}
26+
marked.setOptions({ renderer })
27+
28+
// Fetch doc and menu files
29+
let docFiles = []
30+
let _CACHE_DOC_FILES_ = {}
31+
let _CACHE_MENU_ = {}
32+
async function getFiles () {
33+
_CACHE_DOC_FILES_ = {}
34+
docFiles = await glob('*/**/*.md', {
35+
ignore: 'node_modules/**/*',
36+
nodir: true
37+
})
38+
_CACHE_MENU_ = {}
39+
let filePaths = await glob('*/**/menu.json', {
40+
ignore: 'node_modules/**/*',
41+
nodir: true
42+
})
43+
filePaths.forEach((path) => {
44+
let cache = _CACHE_MENU_
45+
let keys = path.split('/').slice(0, -1)
46+
keys.forEach((key, i) => {
47+
if ((i + 1) === keys.length) {
48+
cache[key] = require(resolve(__dirname, path))
49+
return
50+
}
51+
cache[key] = cache[key] || {}
52+
cache = cache[key]
53+
})
54+
})
55+
}
56+
// Get doc file and sent back it's attributes and html body
57+
async function getDocFile (path) {
58+
path = resolve(__dirname, path)
59+
if (process.env.NODE_ENV !== 'production' && _CACHE_DOC_FILES_[path]) {
60+
return _CACHE_DOC_FILES_[path]
61+
}
62+
let file = await readFile(path, 'utf-8')
63+
// transform markdown to html
64+
file = fm(file)
65+
_CACHE_DOC_FILES_[path] = {
66+
attrs: file.attributes,
67+
body: marked(file.body)
68+
}
69+
return _CACHE_DOC_FILES_[path]
70+
}
71+
72+
// Refresh documentation files (pull from Github)
73+
async function pullDocFiles ({ req, res }) {
74+
const body = await json(req)
75+
console.log(body)
76+
// Only for production
77+
if (!process.env.GH_HOOK_SECRET || !req.headers['x-hub-signature']) {
78+
return send(res, 501)
79+
}
80+
// Check if X-Hub-Signature matches our secret
81+
let hmac = crypto.createHmac('sha1', process.env.GH_HOOK_SECRET)
82+
hmac.update(JSON.stringify(body))
83+
let signature = 'sha1=' + hmac.digest('hex')
84+
if (req.headers['x-hub-signature'] !== signature) {
85+
return send(res, 403)
86+
}
87+
// Accept only push hook events
88+
if (req.headers['x-github-event'] === 'ping') {
89+
return send(res, 200, 'OK')
90+
}
91+
// Only push event authorized
92+
if (req.headers['x-github-event'] !== 'push') {
93+
return send(res, 501)
94+
}
95+
const clonePath = resolve(os.tmpdir(), uuid())
96+
await gitClone('https://github.com/nuxt/docs.git', clonePath)
97+
console.log('Cloned', clonePath)
98+
await getFiles()
99+
await rimraf(clonePath)
100+
send(res, 200, 'OK')
101+
}
102+
103+
// Server handle request method
104+
const server = micro(async function (req, res) {
105+
// If github hook
106+
if (req.method === 'POST' && req.url === '/hook') {
107+
return await pullDocFiles({ req, res })
108+
}
109+
if (req.url === '/menu') {
110+
return send(res, 200, _CACHE_MENU_)
111+
}
112+
// remove first /
113+
let path = req.url.slice(1)
114+
// Check if path exists
115+
const docFile = docFiles.find((f) => f === path)
116+
if (!docFile) {
117+
return send(res, 404, 'File not found')
118+
}
119+
// Send back doc content
120+
send(res, 200, await getDocFile(path))
121+
})
122+
123+
getFiles()
124+
.then(() => {
125+
const port = process.env.PORT || 4000
126+
server.listen(port)
127+
console.log(`Server listening on localhost:${port}`)
128+
})

package.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"name": "nuxt-docs",
3+
"version": "1.0.0",
4+
"description": "Nuxt.js documentation files",
5+
"scripts": {
6+
"dev": "nodemon --harmony api.js",
7+
"lint": "eslint *.js",
8+
"start": "node --harmony api.js",
9+
"deploy": "now --env GH_HOOK_SECRET=@docs-api-hook-secret --env NODE_ENV=production --alias docs.api.nuxtjs.org",
10+
"precommit": "npm run lint"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "git+https://github.com/nuxt/docs.git"
15+
},
16+
"keywords": [
17+
"nuxt",
18+
"nuxt.js",
19+
"vue",
20+
"micro"
21+
],
22+
"author": "Chopin brothers (@Atinux & @alexchopin)",
23+
"license": "MIT",
24+
"bugs": {
25+
"url": "https://github.com/nuxt/docs/issues"
26+
},
27+
"homepage": "https://github.com/nuxt/docs#readme",
28+
"dependencies": {
29+
"front-matter": "^2.1.1",
30+
"glob": "^7.1.1",
31+
"highlight.js": "^9.9.0",
32+
"marked": "^0.3.6",
33+
"micro": "^6.1.0",
34+
"pify": "^2.3.0",
35+
"request": "^2.79.0",
36+
"request-promise-native": "^1.0.3",
37+
"rimraf": "^2.5.4",
38+
"simple-git": "^1.65.0",
39+
"uuid": "^3.0.1"
40+
},
41+
"devDependencies": {
42+
"eslint": "^3.12.2",
43+
"eslint-config-standard": "^6.2.1",
44+
"eslint-plugin-promise": "^3.4.0",
45+
"eslint-plugin-standard": "^2.0.1",
46+
"nodemon": "^1.11.0"
47+
}
48+
}

0 commit comments

Comments
 (0)