refactor: remove route generation

Fixes #21
This commit is contained in:
Karl-Philipp Wulfert
2019-01-08 14:44:15 +01:00
parent 6d11c9b915
commit 75ceeb4500
3 changed files with 0 additions and 317 deletions

View File

@@ -1,83 +0,0 @@
/*
* Copyright (C) 2018 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {execSync} from 'child_process';
import * as commander from 'commander';
import {existsSync, mkdirSync, readFileSync, writeFileSync} from 'fs';
import {resolve} from 'path';
import {ProjectReflection} from 'typedoc';
import {gatherRouteInformation, generateDocumentationForRoute, logger, rimrafPromisifed} from './common';
import {NodesWithMetaInformation} from './types';
commander.version(JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json')).toString()).version);
commander
.command('routes <mdPath>')
.action(async (relativeMdPath) => {
if (!existsSync(resolve('tmp'))) {
// create tmp directory
mkdirSync(resolve('tmp'));
}
const command = resolve('node_modules', '.bin', 'typedoc');
const jsonPath = resolve('tmp', 'out.json');
const mdPath = resolve(relativeMdPath);
logger.info(`Using Typedoc from ${command}.`);
const result = execSync(`${command} --includeDeclarations --excludeExternals --mode modules --json ${jsonPath}`);
result.toString().split('\n').forEach((line) => {
if (line.length > 0) {
logger.info(line);
}
});
const jsonContent: ProjectReflection = JSON.parse(readFileSync(jsonPath).toString());
const nodes: NodesWithMetaInformation = {};
jsonContent.children.forEach((module: any) => {
if (Array.isArray(module.children) && module.children.length > 0) {
module.children.forEach((node: any) => {
nodes[node.name] = {
module: module.name.substring(1, module.name.length - 1),
type: node.kindString,
};
});
}
});
const routes = await gatherRouteInformation(jsonContent);
let output: string = '# Routes\n\n';
routes.forEach((routeWithMetaInformation) => {
output += generateDocumentationForRoute(routeWithMetaInformation, nodes);
});
writeFileSync(mdPath, output);
logger.ok(`Route documentation written to ${mdPath}.`);
// remove temporary files
await rimrafPromisifed(resolve('tmp'));
});
commander.parse(process.argv);
if (commander.args.length < 2) {
commander.outputHelp();
process.exit(1);
}

View File

@@ -1,168 +0,0 @@
/*
* Copyright (C) 2018 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Logger} from '@openstapps/logger';
import {asyncPool} from 'async-pool-native/dist/async-pool';
import humanizeString = require('humanize-string');
import * as rimraf from 'rimraf';
import {ProjectReflection} from 'typedoc';
import {promisify} from 'util';
import {NodesWithMetaInformation, NodeWithMetaInformation, RouteWithMetaInformation} from './types';
/**
* Initialized logger
*/
export const logger = new Logger();
/**
* Promisified rimraf
*/
export const rimrafPromisifed = promisify(rimraf);
/**
* Gather relevant information of routes
*
* This gathers the information for all routes that implement the abstract class SCAbstractRoute.
* Furthermore it instantiates every route and adds it to the information.
*
* @param reflection Contents of the JSON representation which Typedoc generates
*/
export async function gatherRouteInformation(reflection: ProjectReflection): Promise<RouteWithMetaInformation[]> {
const routes: RouteWithMetaInformation[] = [];
await asyncPool(2, reflection.children, async (module: any) => {
if (Array.isArray(module.children) && module.children.length > 0) {
await asyncPool(2, module.children, (async (node: any) => {
if (Array.isArray(node.extendedTypes) && node.extendedTypes.length > 0) {
if (node.extendedTypes.some((extendedType: any) => {
return extendedType.name === 'SCAbstractRoute';
})) {
logger.info(`Found ${node.name} in ${module.originalName}.`);
const importedModule = await import(module.originalName);
const route = new importedModule[node.name]();
routes.push({description: node.comment, name: node.name, route});
}
}
}));
}
});
return routes;
}
/**
* Get a linked name for a node
*
* @param name Name of the node
* @param node Node itself
* @param humanize Whether to humanize the name or not
*/
export function getLinkedNameForNode(name: string, node: NodeWithMetaInformation, humanize: boolean = false): string {
let printableName = name;
if (humanize) {
printableName = humanizeString(name.substr(2));
}
let link = `[${printableName}]`;
link += `(${getLinkForNode(name, node)})`;
return link;
}
/**
* Get link for a node
*
* @param name Name of the node
* @param node Node itself
*/
export function getLinkForNode(name: string, node: NodeWithMetaInformation): string {
let link = 'https://openstapps.gitlab.io/core/';
const module = node.module.toLowerCase().split('/').join('_');
if (node.type === 'Type alias') {
link += 'modules/';
link += `_${module}_`;
link += `.html#${name.toLowerCase()}`;
return link;
}
let type = 'classes';
if (node.type !== 'Class') {
type = `${node.type.toLowerCase()}s`;
}
link += `${type}/`;
link += `_${module}_`;
link += `.${name.toLowerCase()}.html`;
return link;
}
/**
* Generate documentation snippet for one route
*
* @param routeWithInfo A route instance with its meta information
* @param nodes
*/
export function generateDocumentationForRoute(routeWithInfo: RouteWithMetaInformation,
nodes: NodesWithMetaInformation): string {
let output = '';
const route = routeWithInfo.route;
output += `## \`${route.method} ${route.urlFragment}\``;
output += ` ${getLinkedNameForNode(routeWithInfo.name, nodes[routeWithInfo.name], true)}\n\n`;
if (typeof routeWithInfo.description.shortText === 'string') {
output += `**${routeWithInfo.description.shortText}**\n\n`;
}
if (typeof routeWithInfo.description.text === 'string') {
output += `${routeWithInfo.description.text.replace('\n', '<br>')}\n\n`;
}
output += `### Definition
| parameter | value |
| --- | --- |
| request | ${getLinkedNameForNode(route.requestBodyName, nodes[route.requestBodyName])} |
| response | ${getLinkedNameForNode(route.responseBodyName, nodes[route.responseBodyName])} |
| success code | ${route.statusCodeSuccess} |
| errors | ${route.errorNames.map((errorName) => {
return getLinkedNameForNode(errorName, nodes[errorName]);
}).join('<br>')} |
`;
if (typeof route.obligatoryParameters === 'object' && Object.keys(route.obligatoryParameters).length > 0) {
let parameterTable = '<table><tr><th>parameter</th><th>type</th></tr>';
Object.keys(route.obligatoryParameters).forEach((parameter) => {
let type = route.obligatoryParameters![parameter];
if (typeof nodes[type] !== 'undefined') {
type = getLinkedNameForNode(type, nodes[type]);
}
parameterTable += `<tr><td>${parameter}</td><td>${type}</td></tr>`;
});
parameterTable += '</table>';
output += `| obligatory parameters | ${parameterTable} |`;
}
output += '\n\n';
return output;
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright (C) 2018 StApps
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SCAbstractRoute} from './core/Route';
/**
* A route instance with its relevant meta information
*/
export interface RouteWithMetaInformation {
/**
* Description of the route
*/
description: {
/**
* Short text of the description - title
*/
shortText?: string;
/**
* Text of the description
*/
text?: string;
};
/**
* Name of the route
*/
name: string;
/**
* Instance of the route
*/
route: SCAbstractRoute;
}
/**
* A node with its relevant meta information
*/
export interface NodeWithMetaInformation {
/**
* Module the node belongs to
*/
module: string;
/**
* Type of the node
*/
type: string;
}
/**
* A map of nodes indexed by their name
*/
export interface NodesWithMetaInformation {
/**
* Index signature
*/
[k: string]: NodeWithMetaInformation;
}