Files
openstapps/src/common.ts
2019-02-26 16:52:11 +01:00

185 lines
4.8 KiB
TypeScript

/*
* Copyright (C) 2018-2019 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 {existsSync, mkdir, PathLike, readFile, unlink, writeFile} from 'fs';
import * as glob from 'glob';
import {Schema as JSONSchema, ValidationError} from 'jsonschema';
import {platform} from 'os';
import {join, sep} from 'path';
import {Definition} from 'ts-json-schema-generator';
import {Application, ProjectReflection} from 'typedoc';
import {promisify} from 'util';
export const logger = new Logger();
export const globPromisified = promisify(glob);
export const mkdirPromisified = promisify(mkdir);
export const readFilePromisified = promisify(readFile);
export const writeFilePromisified = promisify(writeFile);
export const unlinkPromisified = promisify(unlink);
/**
* 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: {
errorNames: Error[];
method: string;
obligatoryParameters: {
[k: string]: string;
}
requestBodyName: string;
responseBodyName: string;
statusCodeSuccess: number;
urlFragment: string;
};
}
/**
* 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;
}
/**
* A schema with definitions
*/
interface SchemaWithDefinitions extends JSONSchema {
definitions: { [name: string]: Definition };
}
/**
* An expectable error
*/
export type ExpectableValidationError = ValidationError & { expected: boolean };
/**
* A map of files and their expectable validation errors
*/
export interface ExpectableValidationErrors {
[fileName: string]: ExpectableValidationError[];
}
/**
* Get a project reflection from a path
*
* @param srcPath Path to get reflection from
*/
export function getProjectReflection(srcPath: PathLike): ProjectReflection {
logger.info(`Generating project reflection for ${srcPath.toString()}.`);
const tsconfigPath = getTsconfigPath(srcPath.toString());
// initialize new Typedoc application
const app = new Application({
excludeExternals: true,
includeDeclarations: true,
module: 'commonjs',
tsconfig: join(tsconfigPath, 'tsconfig.json'),
});
let inputFilePath = srcPath;
if (inputFilePath === tsconfigPath) {
inputFilePath = join(tsconfigPath, 'src');
}
// get input files
const inputFiles = app.expandInputFiles([inputFilePath.toString()]);
// get project reflection from input files
const result = app.convert(inputFiles);
if (typeof result === 'undefined') {
throw new Error('Project reflection could not be generated.');
}
return result;
}
/**
* Check if a schema has definitions
*
* @param schema Schema to check
*/
export function isSchemaWithDefinitions(schema: JSONSchema): schema is SchemaWithDefinitions {
return typeof schema.definitions !== 'undefined';
}
/**
* Get path that contains a tsconfig.json
*
* @param startPath Path from where to start searching "upwards"
*/
export function getTsconfigPath(startPath: string): string {
let tsconfigPath = startPath;
// see https://stackoverflow.com/questions/9652043/identifying-the-file-system-root-with-node-js
const root = (platform() === 'win32') ? process.cwd().split(sep)[0] : '/';
// repeat until a tsconfig.json is found
while (!existsSync(join(tsconfigPath, 'tsconfig.json'))) {
if (tsconfigPath === root) {
throw new Error(`Reached file system root ${root} while searching for 'tsconfig.json' in ${startPath}!`);
}
// pop last directory
const tsconfigPathParts = tsconfigPath.split(sep);
tsconfigPathParts.pop();
tsconfigPath = tsconfigPathParts.join(sep);
}
logger.info(`Using 'tsconfig.json' from ${tsconfigPath}.`);
return tsconfigPath;
}