Commit b4d79c28 authored by Jarrod's avatar Jarrod 💬

Initial commit

parents
Pipeline #3168 failed with stages
in 0 seconds
# @nahanil/sails-actiondoc
Generate API docs for your Sails application
Adds the route `/_apidoc` to your application in `development` mode.
\ No newline at end of file
const pkg = require('../package.json')
const getDoc = require('../lib/get-doc')
const ejs = require('ejs')
const fs = require('fs')
const path = require('path')
module.exports = function (req, res, next) {
if (sails.config.environment !== 'development' && sails.config.environment !== 'docker-dev') {
return next()
}
const doc = getDoc()
fs.readFile(path.resolve(__dirname, '../tpl/apidoc.ejs'), 'utf8', (err, file) => {
if (err) {
sails.log.error('Failed to load API doc template', err.stack)
return res.status(500).send('Failed to load api doc template')
}
const html = ejs.render(file, {
apidoc: {
version: pkg.version || 0
},
endpoints: doc,
locals: {
...res.locals
}
})
return res.send(html)
})
}
\ No newline at end of file
/**
* api-doc hook
*
* @description :: A hook definition. Extends Sails by adding shadow routes, implicit actions, and/or initialization logic.
* @docs :: https://sailsjs.com/docs/concepts/extending-sails/hooks
*/
module.exports = function defineApiDocHook(sails) {
return {
/**
* Runs when this Sails app loads/lifts.
*/
initialize: async function() {
sails.log.info('Initializing custom hook (`api-doc`)');
},
routes: {
before: {
'GET /_apidoc': require('./handler/html-doc')
// 'GET /apidoc-html': require('./handler/html-doc')
}
}
}
}
module.exports = function () {
var endpointsByMethodName = {}
var extraEndpointsOnlyForTestsByMethodName = {}
var packages = {}
_.each(sails.config.routes, (target) => {
// If the route target is an array, then only consider
// the very last sub-target in the array.
if (_.isArray(target)) {
target = _.last(target)
}
// Skip redirects
// (Note that, by doing this, we also skip traditional shorthand
// -- that's ok though.)
if (_.isString(target)) {
return
}
// Skip routes whose target doesn't contain `action` for any
// other miscellaneous reason.
if (!target.action) {
return
}
// Just about everything else gets a Cloud SDK method.
// We determine its name using the bare action name.
var bareActionName = target.action.replace(/\//g, '-')
var methodName = target.name || _.camelCase(bareActionName)
var expandedAddress = sails.getRouteFor(target)
// Skip routes that just serve views.
// (but still generate them for use in tests, for convenience)
if (target.view || (bareActionName.match(/^view-/))) {
extraEndpointsOnlyForTestsByMethodName[methodName] = {
verb: (expandedAddress.method || 'get').toUpperCase(),
url: expandedAddress.url
}
return
}
endpointsByMethodName[methodName] = {
verb: (expandedAddress.method || 'get').toUpperCase(),
url: expandedAddress.url,
package: target.package
}
// If this is an actions2 action, then determine appropriate serial usage.
// (deduced the same way as helpers)
// > If there is no such action for some reason, then don't compile a
// > method for this one.
var requestable = sails.getActions()[target.action]
if (!requestable) {
sails.log.warn('Skipping unrecognized action: `' + target.action + '`')
return
}
var def = requestable.toJSON && requestable.toJSON()
if (def && def.fn) {
endpointsByMethodName[methodName].name = def.friendlyName
endpointsByMethodName[methodName].description = def.description
endpointsByMethodName[methodName].cache = target.cache
endpointsByMethodName[methodName].protocol = target.isSocket ? 'socket' : 'http'
if (def.args !== undefined) {
endpointsByMethodName[methodName].args = def.args
} else {
endpointsByMethodName[methodName].args = _.reduce(def.inputs, (args, inputDef, inputCodeName) => {
args.push(inputCodeName)
return args
}, [])
}
endpointsByMethodName[methodName].inputs = def.inputs
endpointsByMethodName[methodName].exits = _.omit(def.exits, ['success', 'error'])
}
// endpoints.push(endpointsByMethodName[methodName])
const e = endpointsByMethodName[methodName]
e.methodName = methodName
if (!e.package) { e.package = 'default' }
if (!(e.package in packages)) {
packages[e.package] = []
}
packages[e.package].push(e)
}) // ∞
// return endpointsByMethodName
// return endpoints
return packages
}
\ No newline at end of file
{
"name": "@nahanil/sails-actiondoc",
"version": "0.1.0",
"description": "",
"main": "index.js",
"directories": {
"lib": "lib"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"sails": {
"isHook": true,
"hookName": "actiondoc"
},
"author": "Jarrod Linahan <jarrod@linahan.id.au>",
"license": "ISC"
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>API Doc</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css">
<style type="text/css">
.card {
margin-bottom: 15px;
}
.card-title {
padding: 10px 15px;
cursor: pointer;
}
.card-content {
display: none;
}
.title-url {
padding: 5px 0;
opacity: 0.7;
}
.footer {
padding: 15px;
}
</style>
</head>
<body>
<div id="app">
<section class="hero is-dark">
<div class="hero-body">
<div class="container">
<h1 class="title">
API Doc
</h1>
<!-- <h2 class="subtitle">...</h2> -->
</div>
</div>
</section>
<main class="container">
<section id="" class="section">
<div class="columns">
<aside class="menu column is-2">
<p class="menu-label">
Packages
</p>
<ul class="menu-list">
<% for (const group of Object.keys(endpoints)) { %>
<li><a href="#<%= group %>"><%= group %></a></li>
<% } %>
</ul>
</aside>
<section class="column is-10 content">
<% for (const group of Object.keys(endpoints)) { %>
<h3 id="<%= group %>">Package: <%= group %></h3>
<hr>
<% endpoints[group] && endpoints[group].forEach((e) => { %>
<div class="card">
<div class="card-title">
<div class="media">
<div class="media-content">
<p class="title is-5"><%= e.name %></p>
<p class="subtitle title-url is-6"><%= `${e.verb} ${e.url}` %></p>
</div>
</div>
</div>
<div class="card-content">
<strong><%= e.protocol %></strong>
<p><%= e.description %></p>
<% if (!_.isEmpty(e.inputs)) { %>
<h4>Inputs</h4>
<table>
<% Object.keys(e.inputs).forEach((input) =>{ %>
<tr>
<th><%= input %></th>
<td><%= JSON.stringify(e.inputs[input]) %></td>
</tr>
<% }) %>
</table>
<% } %>
<% if (!_.isEmpty(e.exits)) { %>
<h4>Exits</h4>
<table>
<% Object.keys(e.exits).forEach((exit) =>{ %>
<tr>
<th><%= exit %></th>
<td><%= JSON.stringify(e.exits[exit]) %></td>
</tr>
<% }) %>
</table>
<% } %>
<h4>Example</h4>
<pre>$sdk.<%= e.methodName %>()
.then(({ data }) => {
// console.log('Received response:', data)
})
.catch((err) => {
// Handle errors
})</pre>
<!-- <pre><%= JSON.stringify(e, null, 4) %></pre> -->
</div>
</div>
<% }) %>
<% } %>
</section>
</div>
</section>
</main>
<div class="footer">
Sails APIDoc v <%= apidoc.version %>
</div>
</div>
<script
src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
<script type="text/javascript">
$('.card-title').on('click', function(e) {
e.preventDefault();
var $el = $(this);
$el.closest('.card').find('.card-content').toggle()
})
</script>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment