Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip: Issue/openapi #10

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions classes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
[
{
"name": "MongodbCollectionRecordStorageBllImpl",
"documentation": "",
"type": "typeof MongodbCollectionRecordStorageBllImpl",
"constructors": [
{
"parameters": [
{
"name": "options",
"documentation": "",
"type": "{ dbClient?: MongoClient; }"
}
],
"returnType": "MongodbCollectionRecordStorageBllImpl",
"documentation": ""
}
]
},
{
"name": "MongodbCollectionRecordQueryBllImpl",
"documentation": "",
"type": "typeof MongodbCollectionRecordQueryBllImpl",
"constructors": [
{
"parameters": [
{
"name": "options",
"documentation": "",
"type": "{ dbClient?: MongoClient; }"
}
],
"returnType": "MongodbCollectionRecordQueryBllImpl",
"documentation": ""
}
]
},
{
"name": "RecordBllImpl",
"documentation": "",
"type": "typeof RecordBllImpl",
"constructors": [
{
"parameters": [
{
"name": "options",
"documentation": "",
"type": "{ recordStorageBll?: RecordStorageBll; recordQueryBll?: RecordQueryBll<any, any>; }"
}
],
"returnType": "RecordBllImpl",
"documentation": ""
}
]
},
{
"name": "RecordAuthBll",
"documentation": "",
"type": "typeof RecordAuthBll",
"constructors": [
{
"parameters": [],
"returnType": "RecordAuthBll",
"documentation": ""
}
]
},
{
"name": "RecordAPI",
"documentation": "Function2 2023423i",
"type": "typeof RecordAPI",
"constructors": [
{
"parameters": [
{
"name": "options",
"documentation": "",
"type": "{ recordBll?: RecordStorageBll & RecordQueryBll<any, any>; }"
}
],
"returnType": "RecordAPI",
"documentation": ""
}
]
}
]
5 changes: 5 additions & 0 deletions docs/api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,11 @@ paths:
summary: Query Record in JSON Array Mode
tags:
- Record API
params:
- name: xxx
in: path
- name: yyy
in: header
requestBody:
content:
application/json:
Expand Down
10 changes: 6 additions & 4 deletions src/api/doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as path from 'path'
import * as yaml from 'js-yaml'
import * as config from 'config'
import { before, controller, get } from '../http-server/decorator'
import { generateOpenApiDoc } from '../http-server/openapi'
import * as createHttpError from 'http-errors'

let openapi: any
Expand All @@ -19,9 +20,10 @@ let openapi: any
export class VersionAPI {
@get('/')
async doc() {
if (!openapi) {
openapi = yaml.load(fs.readFileSync(path.resolve(__dirname, '../../docs/api.yml'), {encoding: 'utf-8'}))
}
return openapi
// if (!openapi) {
// openapi = yaml.load(fs.readFileSync(path.resolve(__dirname, '../../docs/api.yml'), {encoding: 'utf-8'}))
// }
// return openapi
return generateOpenApiDoc()
}
}
18 changes: 17 additions & 1 deletion src/api/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export function resultMW(): MiddlewareFn {
}
}

/** Function2 2023423i
* @summary ggg
* @description ggghhh
*/
@controller('/api/record')
@before(async (ctx) => {
let token = ctx.get('authorization') as string || ''
Expand Down Expand Up @@ -159,12 +163,21 @@ export class RecordAPI {
return records
}

/**
* @summary abc create record api
* @description bcd balala
* @response
* schema:
* type: object
* properties:
* result:
*/
@post('/create')
@validator({
type: 'object',
required: ['spaceId', 'entityId'],
properties: {
id: { type: 'string' },
id: { type: 'string', summary: 'xxx', description: 'yyy' },
spaceId: { type: 'string' },
entityId: { type: 'string' },
cf: { type: 'object' },
Expand All @@ -183,6 +196,9 @@ export class RecordAPI {
return record
}

/**
* @description bcc l999
*/
@post('/update')
@validator({
type: 'object',
Expand Down
11 changes: 11 additions & 0 deletions src/api/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ try {
})
export class VersionAPI {
@get('/')
@skipLogger()
async version() {
return version
}
@get('/')
@skipLogger()
async version() {
return version
}
@get('/')
@skipLogger()
async version() {
return version
}
Expand Down
2 changes: 1 addition & 1 deletion src/http-server/decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ interface RouteMeta {
propertyName: string
}

const controllerMap = new Map<ControllerConstructor, ControllerMeta>()
export const controllerMap = new Map<ControllerConstructor, ControllerMeta>()
// const controllers: ControllerMeta[] = []

export function controller(prefix = '/') {
Expand Down
107 changes: 107 additions & 0 deletions src/http-server/jsdoc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import * as ts from "typescript"
import * as fs from "fs"

interface DocEntry {
name?: string
fileName?: string
documentation?: string
type?: string
constructors?: DocEntry[]
parameters?: DocEntry[]
returnType?: string
}

/** Generate documentation for all classes in a set of .ts files */
function generateDocumentation(
fileNames: string[],
options: ts.CompilerOptions
): void {
// Build a program using the set of root file names in fileNames
const program = ts.createProgram(fileNames, options)

// Get the checker, we will use it to find more about classes
const checker = program.getTypeChecker()
const output: DocEntry[] = []

// Visit every sourceFile in the program
for (const sourceFile of program.getSourceFiles()) {
if (!sourceFile.isDeclarationFile) {
// Walk the tree to search for classes
ts.forEachChild(sourceFile, visit)
}
}

// // print out the doc
fs.writeFileSync("classes.json", JSON.stringify(output, undefined, 4))

return

/** visit nodes finding exported classes */
function visit(node: ts.Node) {
// Only consider exported nodes
if (!isNodeExported(node)) {
return
}

if (ts.isClassDeclaration(node) && node.name) {
// This is a top level class, get its symbol
const symbol = checker.getSymbolAtLocation(node.name)
if (symbol) {
output.push(serializeClass(symbol))
}
// No need to walk any further, class expressions/inner declarations
// cannot be exported
} else if (ts.isModuleDeclaration(node)) {
// This is a namespace, visit its children
ts.forEachChild(node, visit)
}
}

/** Serialize a symbol into a json object */
function serializeSymbol(symbol: ts.Symbol): DocEntry {
return {
name: symbol.getName(),
documentation: ts.displayPartsToString(symbol.getDocumentationComment(checker)),
type: checker.typeToString(
checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration!)
)
}
}

/** Serialize a class symbol information */
function serializeClass(symbol: ts.Symbol) {
const details = serializeSymbol(symbol)

// Get the construct signatures
const constructorType = checker.getTypeOfSymbolAtLocation(
symbol,
symbol.valueDeclaration!
)
details.constructors = constructorType
.getConstructSignatures()
.map(serializeSignature)
return details
}

/** Serialize a signature (call or construct) */
function serializeSignature(signature: ts.Signature) {
return {
parameters: signature.parameters.map(serializeSymbol),
returnType: checker.typeToString(signature.getReturnType()),
documentation: ts.displayPartsToString(signature.getDocumentationComment(checker))
}
}

/** True if this is visible outside this file, false otherwise */
function isNodeExported(node: ts.Node): boolean {
return (
(ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export) !== 0 ||
(!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile)
)
}
}

generateDocumentation(process.argv.slice(2), {
target: ts.ScriptTarget.ES5,
module: ts.ModuleKind.CommonJS
})
Loading