@tremho/mist-lift 1.1.2 → 1.1.4-pre-release.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +66 -65
- package/build/QSTest/functions/IntegrationTest/integrationTest-tests/Sanity.test.js +14 -0
- package/build/QSTest/functions/IntegrationTest/integrationTest-tests/Sanity.test.js.map +1 -0
- package/build/QSTest/functions/IntegrationTest/src/local.js +33 -0
- package/build/QSTest/functions/IntegrationTest/src/local.js.map +1 -0
- package/build/QSTest/functions/IntegrationTest/src/main.js +29 -0
- package/build/QSTest/functions/IntegrationTest/src/main.js.map +1 -0
- package/build/{commands → src/commands}/actions/initQuestions.js +1 -1
- package/build/src/commands/actions/initQuestions.js.map +1 -0
- package/build/src/commands/actions/makePackageJson.js.map +1 -0
- package/build/src/commands/actions/setupPackageJson.js.map +1 -0
- package/build/{commands → src/commands}/build.js +7 -6
- package/build/src/commands/build.js.map +1 -0
- package/build/{commands → src/commands}/builtin/ApiDocMaker.js +9 -3
- package/build/src/commands/builtin/ApiDocMaker.js.map +1 -0
- package/build/src/commands/builtin/BuiltInHandler.js.map +1 -0
- package/build/src/commands/builtin/DeployBuiltInZip.js.map +1 -0
- package/build/src/commands/builtin/StageWebrootZip.js.map +1 -0
- package/build/src/commands/create.js.map +1 -0
- package/build/src/commands/deploy.js.map +1 -0
- package/build/{commands → src/commands}/doctor.js +2 -1
- package/build/src/commands/doctor.js.map +1 -0
- package/build/src/commands/help.js.map +1 -0
- package/build/src/commands/info.js.map +1 -0
- package/build/src/commands/init.js.map +1 -0
- package/build/src/commands/package.js.map +1 -0
- package/build/src/commands/publish.js.map +1 -0
- package/build/src/commands/settings.js.map +1 -0
- package/build/src/commands/start.js.map +1 -0
- package/build/src/commands/test.js.map +1 -0
- package/build/src/commands/user.js.map +1 -0
- package/build/src/expressRoutes/all.js.map +1 -0
- package/build/src/expressRoutes/api.js.map +1 -0
- package/build/src/expressRoutes/functionBinder.js.map +1 -0
- package/build/{integration-tests → src/integration-tests}/quickstart-scenario.test.js +13 -11
- package/build/src/integration-tests/quickstart-scenario.test.js.map +1 -0
- package/build/src/lib/CaseUtils.js.map +1 -0
- package/build/src/lib/DirectoryUtils.js.map +1 -0
- package/build/src/lib/LiftConfig.js.map +1 -0
- package/build/src/lib/LiftVersion.js.map +1 -0
- package/build/src/lib/Tests/fileCompare.test.js.map +1 -0
- package/build/src/lib/askQuestion.js.map +1 -0
- package/build/src/lib/executeCommand.js.map +1 -0
- package/build/src/lib/fileCompare.js.map +1 -0
- package/build/src/lib/openAPI/ApiBuildCollector.js.map +1 -0
- package/build/src/lib/openAPI/WebrootFileSupport.js.map +1 -0
- package/build/src/lib/openAPI/openApiConstruction.js.map +1 -0
- package/build/src/lib/pathResolve.js.map +1 -0
- package/build/src/lib/utils.js.map +1 -0
- package/build/{lift.js → src/lift.js} +0 -0
- package/build/src/lift.js.map +1 -0
- package/package.json +79 -75
- package/src/commands/actions/initQuestions.ts +133 -133
- package/src/commands/actions/setupPackageJson.ts +32 -32
- package/src/commands/build.ts +173 -170
- package/src/commands/builtin/ApiDocMaker.ts +106 -102
- package/src/commands/builtin/BuiltInHandler.ts +47 -47
- package/src/commands/builtin/DeployBuiltInZip.ts +25 -25
- package/src/commands/builtin/StageWebrootZip.ts +36 -36
- package/src/commands/create.ts +52 -52
- package/src/commands/deploy.ts +161 -161
- package/src/commands/doctor.ts +107 -106
- package/src/commands/help.ts +178 -178
- package/src/commands/info.ts +42 -42
- package/src/commands/init.ts +61 -61
- package/src/commands/package.ts +234 -234
- package/src/commands/publish.ts +330 -330
- package/src/commands/settings.ts +73 -73
- package/src/commands/start.ts +43 -43
- package/src/commands/test.ts +37 -37
- package/src/commands/user.ts +20 -20
- package/src/expressRoutes/all.ts +99 -99
- package/src/expressRoutes/api.ts +22 -22
- package/src/expressRoutes/functionBinder.ts +155 -155
- package/src/integration-tests/quickstart-scenario.test.ts +76 -74
- package/src/lib/CaseUtils.ts +63 -63
- package/src/lib/DirectoryUtils.ts +34 -34
- package/src/lib/LiftConfig.ts +74 -74
- package/src/lib/LiftVersion.ts +87 -87
- package/src/lib/Tests/fileCompare.test.ts +35 -35
- package/src/lib/askQuestion.ts +17 -17
- package/src/lib/executeCommand.ts +45 -45
- package/src/lib/fileCompare.ts +55 -55
- package/src/lib/openAPI/ApiBuildCollector.ts +47 -47
- package/src/lib/openAPI/WebrootFileSupport.ts +19 -19
- package/src/lib/openAPI/openApiConstruction.ts +196 -196
- package/src/lib/pathResolve.ts +26 -26
- package/src/lib/utils.ts +43 -43
- package/src/lift.ts +87 -87
- package/templateData/function-definition-template +20 -20
- package/templateData/function-local-ts +16 -16
- package/templateData/function-main-ts +16 -16
- package/templateData/function-runmain-mjs +6 -6
- package/templateData/function-test-template +11 -11
- package/templateData/swagger-ui-bundle.js +2 -2
- package/templateData/swagger-ui-standalone-preset.js +2 -2
- package/templateData/swagger-ui.css +2 -2
- package/tsconfig.json +28 -28
- package/build/commands/actions/initQuestions.js.map +0 -1
- package/build/commands/actions/makePackageJson.js.map +0 -1
- package/build/commands/actions/setupPackageJson.js.map +0 -1
- package/build/commands/build.js.map +0 -1
- package/build/commands/builtin/ApiDocMaker.js.map +0 -1
- package/build/commands/builtin/BuiltInHandler.js.map +0 -1
- package/build/commands/builtin/DeployBuiltInZip.js.map +0 -1
- package/build/commands/builtin/StageWebrootZip.js.map +0 -1
- package/build/commands/create.js.map +0 -1
- package/build/commands/deploy.js.map +0 -1
- package/build/commands/doctor.js.map +0 -1
- package/build/commands/help.js.map +0 -1
- package/build/commands/info.js.map +0 -1
- package/build/commands/init.js.map +0 -1
- package/build/commands/package.js.map +0 -1
- package/build/commands/publish.js.map +0 -1
- package/build/commands/settings.js.map +0 -1
- package/build/commands/start.js.map +0 -1
- package/build/commands/test.js.map +0 -1
- package/build/commands/user.js.map +0 -1
- package/build/expressRoutes/all.js.map +0 -1
- package/build/expressRoutes/api.js.map +0 -1
- package/build/expressRoutes/functionBinder.js.map +0 -1
- package/build/integration-tests/quickstart-scenario.test.js.map +0 -1
- package/build/lib/CaseUtils.js.map +0 -1
- package/build/lib/DirectoryUtils.js.map +0 -1
- package/build/lib/LiftConfig.js.map +0 -1
- package/build/lib/LiftVersion.js.map +0 -1
- package/build/lib/Tests/fileCompare.test.js.map +0 -1
- package/build/lib/askQuestion.js.map +0 -1
- package/build/lib/executeCommand.js.map +0 -1
- package/build/lib/fileCompare.js.map +0 -1
- package/build/lib/openAPI/ApiBuildCollector.js.map +0 -1
- package/build/lib/openAPI/WebrootFileSupport.js.map +0 -1
- package/build/lib/openAPI/openApiConstruction.js.map +0 -1
- package/build/lib/pathResolve.js.map +0 -1
- package/build/lib/utils.js.map +0 -1
- package/build/lift.js.map +0 -1
- /package/build/{commands → src/commands}/actions/makePackageJson.js +0 -0
- /package/build/{commands → src/commands}/actions/setupPackageJson.js +0 -0
- /package/build/{commands → src/commands}/builtin/BuiltInHandler.js +0 -0
- /package/build/{commands → src/commands}/builtin/DeployBuiltInZip.js +0 -0
- /package/build/{commands → src/commands}/builtin/StageWebrootZip.js +0 -0
- /package/build/{commands → src/commands}/create.js +0 -0
- /package/build/{commands → src/commands}/deploy.js +0 -0
- /package/build/{commands → src/commands}/help.js +0 -0
- /package/build/{commands → src/commands}/info.js +0 -0
- /package/build/{commands → src/commands}/init.js +0 -0
- /package/build/{commands → src/commands}/package.js +0 -0
- /package/build/{commands → src/commands}/publish.js +0 -0
- /package/build/{commands → src/commands}/settings.js +0 -0
- /package/build/{commands → src/commands}/start.js +0 -0
- /package/build/{commands → src/commands}/test.js +0 -0
- /package/build/{commands → src/commands}/user.js +0 -0
- /package/build/{expressRoutes → src/expressRoutes}/all.js +0 -0
- /package/build/{expressRoutes → src/expressRoutes}/api.js +0 -0
- /package/build/{expressRoutes → src/expressRoutes}/functionBinder.js +0 -0
- /package/build/{lib → src/lib}/CaseUtils.js +0 -0
- /package/build/{lib → src/lib}/DirectoryUtils.js +0 -0
- /package/build/{lib → src/lib}/LiftConfig.js +0 -0
- /package/build/{lib → src/lib}/LiftVersion.js +0 -0
- /package/build/{lib → src/lib}/Tests/fileCompare.test.js +0 -0
- /package/build/{lib → src/lib}/askQuestion.js +0 -0
- /package/build/{lib → src/lib}/executeCommand.js +0 -0
- /package/build/{lib → src/lib}/fileCompare.js +0 -0
- /package/build/{lib → src/lib}/openAPI/ApiBuildCollector.js +0 -0
- /package/build/{lib → src/lib}/openAPI/WebrootFileSupport.js +0 -0
- /package/build/{lib → src/lib}/openAPI/openApiConstruction.js +0 -0
- /package/build/{lib → src/lib}/pathResolve.js +0 -0
- /package/build/{lib → src/lib}/utils.js +0 -0
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Part 1 of two steps to build openApi docs.
|
|
3
|
-
* This reads values from our "definitions.json" format and creates a single array that step 2 will turn into
|
|
4
|
-
* openApi specifications.
|
|
5
|
-
*/
|
|
6
|
-
import fs from 'fs'
|
|
7
|
-
import path from 'path'
|
|
8
|
-
import { recurseDirectory } from '../DirectoryUtils'
|
|
9
|
-
import { resolvePaths } from '../pathResolve'
|
|
10
|
-
|
|
11
|
-
export function gatherFunctionDefinitions (): any[] {
|
|
12
|
-
const defs: any = []
|
|
13
|
-
try {
|
|
14
|
-
const projectPaths = resolvePaths()
|
|
15
|
-
if (!projectPaths.verified) return []
|
|
16
|
-
const funcNames: string[] = []
|
|
17
|
-
if (!fs.existsSync(projectPaths.functionPath)) return []
|
|
18
|
-
let firstDepth = 0
|
|
19
|
-
recurseDirectory(projectPaths.functionPath, (filepath, stats) => {
|
|
20
|
-
if (stats.isDirectory()) {
|
|
21
|
-
const depth = filepath.split(path.sep).length
|
|
22
|
-
if (firstDepth === 0) firstDepth = depth
|
|
23
|
-
if (firstDepth === depth) {
|
|
24
|
-
funcNames.push(path.basename(filepath))
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return false
|
|
28
|
-
})
|
|
29
|
-
if (projectPaths.functionPath.includes('functions')) {
|
|
30
|
-
for (const name of funcNames) {
|
|
31
|
-
const defPath = path.join(projectPaths.functionPath, name, 'src', 'definition.json')
|
|
32
|
-
if (fs.existsSync(defPath)) {
|
|
33
|
-
const content = fs.readFileSync(defPath).toString()
|
|
34
|
-
// const buildPath = path.join(projectPaths.buildPath, 'functions', name, 'src', 'definition.json')
|
|
35
|
-
// fs.writeFileSync(buildPath, content); // use this opportunity to copy to build folder before we use it.
|
|
36
|
-
defs.push(JSON.parse(content))
|
|
37
|
-
} else {
|
|
38
|
-
console.error(`Definition file not found at ${defPath}`)
|
|
39
|
-
return []
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
} catch (e: any) {
|
|
44
|
-
console.error('Exception in ApiBuildCollector', e)
|
|
45
|
-
}
|
|
46
|
-
return defs
|
|
47
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Part 1 of two steps to build openApi docs.
|
|
3
|
+
* This reads values from our "definitions.json" format and creates a single array that step 2 will turn into
|
|
4
|
+
* openApi specifications.
|
|
5
|
+
*/
|
|
6
|
+
import fs from 'fs'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
import { recurseDirectory } from '../DirectoryUtils'
|
|
9
|
+
import { resolvePaths } from '../pathResolve'
|
|
10
|
+
|
|
11
|
+
export function gatherFunctionDefinitions (): any[] {
|
|
12
|
+
const defs: any = []
|
|
13
|
+
try {
|
|
14
|
+
const projectPaths = resolvePaths()
|
|
15
|
+
if (!projectPaths.verified) return []
|
|
16
|
+
const funcNames: string[] = []
|
|
17
|
+
if (!fs.existsSync(projectPaths.functionPath)) return []
|
|
18
|
+
let firstDepth = 0
|
|
19
|
+
recurseDirectory(projectPaths.functionPath, (filepath, stats) => {
|
|
20
|
+
if (stats.isDirectory()) {
|
|
21
|
+
const depth = filepath.split(path.sep).length
|
|
22
|
+
if (firstDepth === 0) firstDepth = depth
|
|
23
|
+
if (firstDepth === depth) {
|
|
24
|
+
funcNames.push(path.basename(filepath))
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return false
|
|
28
|
+
})
|
|
29
|
+
if (projectPaths.functionPath.includes('functions')) {
|
|
30
|
+
for (const name of funcNames) {
|
|
31
|
+
const defPath = path.join(projectPaths.functionPath, name, 'src', 'definition.json')
|
|
32
|
+
if (fs.existsSync(defPath)) {
|
|
33
|
+
const content = fs.readFileSync(defPath).toString()
|
|
34
|
+
// const buildPath = path.join(projectPaths.buildPath, 'functions', name, 'src', 'definition.json')
|
|
35
|
+
// fs.writeFileSync(buildPath, content); // use this opportunity to copy to build folder before we use it.
|
|
36
|
+
defs.push(JSON.parse(content))
|
|
37
|
+
} else {
|
|
38
|
+
console.error(`Definition file not found at ${defPath}`)
|
|
39
|
+
return []
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} catch (e: any) {
|
|
44
|
+
console.error('Exception in ApiBuildCollector', e)
|
|
45
|
+
}
|
|
46
|
+
return defs
|
|
47
|
+
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
import * as path from 'path'
|
|
3
|
-
import { resolvePaths } from '../pathResolve'
|
|
4
|
-
import { recurseDirectory } from '../DirectoryUtils'
|
|
5
|
-
|
|
6
|
-
export function GetWebrootServePaths (): string[] {
|
|
7
|
-
const projectPaths = resolvePaths()
|
|
8
|
-
const webroot = path.join(projectPaths.basePath, 'webroot')
|
|
9
|
-
|
|
10
|
-
const list: string[] = ['']
|
|
11
|
-
recurseDirectory(webroot, (filepath, stats) => {
|
|
12
|
-
if (stats.isDirectory()) {
|
|
13
|
-
const relpath = filepath.substring(webroot.length)
|
|
14
|
-
if (!list.includes(relpath)) list.push(relpath)
|
|
15
|
-
}
|
|
16
|
-
return false
|
|
17
|
-
})
|
|
18
|
-
return list
|
|
19
|
-
}
|
|
1
|
+
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import { resolvePaths } from '../pathResolve'
|
|
4
|
+
import { recurseDirectory } from '../DirectoryUtils'
|
|
5
|
+
|
|
6
|
+
export function GetWebrootServePaths (): string[] {
|
|
7
|
+
const projectPaths = resolvePaths()
|
|
8
|
+
const webroot = path.join(projectPaths.basePath, 'webroot')
|
|
9
|
+
|
|
10
|
+
const list: string[] = ['']
|
|
11
|
+
recurseDirectory(webroot, (filepath, stats) => {
|
|
12
|
+
if (stats.isDirectory()) {
|
|
13
|
+
const relpath = filepath.substring(webroot.length)
|
|
14
|
+
if (!list.includes(relpath)) list.push(relpath)
|
|
15
|
+
}
|
|
16
|
+
return false
|
|
17
|
+
})
|
|
18
|
+
return list
|
|
19
|
+
}
|
|
@@ -1,196 +1,196 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This is part 2 of 2 -- we take our pre-built json array of definitions and apply them to openApi in this phase.
|
|
3
|
-
*/
|
|
4
|
-
import { OpenApiBuilder } from 'openapi3-ts/oas30'
|
|
5
|
-
import fs from 'fs'
|
|
6
|
-
import path from 'path'
|
|
7
|
-
import { resolvePaths } from '../pathResolve'
|
|
8
|
-
|
|
9
|
-
export async function buildOpenApi (
|
|
10
|
-
defs: any[],
|
|
11
|
-
includePrivate: boolean = false,
|
|
12
|
-
yamlFile?: string
|
|
13
|
-
): Promise<Uint8Array> {
|
|
14
|
-
const builder = new OpenApiBuilder()
|
|
15
|
-
|
|
16
|
-
const projectPaths = await resolvePaths()
|
|
17
|
-
if (!projectPaths.verified) return new Uint8Array(0) // don't continue if not valid
|
|
18
|
-
|
|
19
|
-
// Read our package.json and construct info from that
|
|
20
|
-
const pkgFile = projectPaths.packagePath
|
|
21
|
-
let pkg: any = {}
|
|
22
|
-
try { pkg = JSON.parse(fs.readFileSync(pkgFile).toString()) } catch {}
|
|
23
|
-
const title: string = pkg.name ?? ''
|
|
24
|
-
// let summary = pkg.description;
|
|
25
|
-
// let spdx: string = pkg.license ?? ''
|
|
26
|
-
// const contactName: string = pkg.author ?? ''
|
|
27
|
-
const version: string = pkg.version ?? ''
|
|
28
|
-
|
|
29
|
-
// license and version definitely come from package.json
|
|
30
|
-
// description and title might get overridden by service.info file
|
|
31
|
-
const infoFile = path.join(projectPaths.functionPath, 'apiService.info.json')
|
|
32
|
-
let svcInfo: any = {}
|
|
33
|
-
if (fs.existsSync(infoFile)) {
|
|
34
|
-
svcInfo = JSON.parse(fs.readFileSync(infoFile).toString())
|
|
35
|
-
}
|
|
36
|
-
// spdx = svcInfo.contact?.spdx ?? spdx
|
|
37
|
-
|
|
38
|
-
const info = {
|
|
39
|
-
title: svcInfo.name ?? title,
|
|
40
|
-
// summary: summary,
|
|
41
|
-
description: svcInfo.description,
|
|
42
|
-
version: svcInfo.version ?? version ?? new Date().toUTCString()
|
|
43
|
-
}
|
|
44
|
-
builder.addInfo(info)
|
|
45
|
-
|
|
46
|
-
// map our defs into openApi values
|
|
47
|
-
for (const def of defs) {
|
|
48
|
-
const pathDef = {}
|
|
49
|
-
if (def.private === true && !includePrivate) continue // skip private
|
|
50
|
-
|
|
51
|
-
const parameters = def.parameters ?? []
|
|
52
|
-
const methods = def.allowedMethods.split(',')
|
|
53
|
-
const schemas = def.schemas ?? {}
|
|
54
|
-
for (const schemaName of Object.getOwnPropertyNames(schemas)) {
|
|
55
|
-
const schema = schemas[schemaName]
|
|
56
|
-
addTypeSchema(builder, schemaName, schema)
|
|
57
|
-
}
|
|
58
|
-
for (let method of methods) {
|
|
59
|
-
method = method.trim().toLowerCase()
|
|
60
|
-
addFunctionMethod(pathDef, method, def)
|
|
61
|
-
for (const param of parameters) {
|
|
62
|
-
addParameter(pathDef, param)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
addCORSOptionMethod(pathDef)
|
|
66
|
-
builder.addPath((def.pathMap ?? '/' + (def.name as string)), pathDef)
|
|
67
|
-
|
|
68
|
-
builder.addSchema('Empty', {
|
|
69
|
-
title: 'Empty Schema',
|
|
70
|
-
type: 'object'
|
|
71
|
-
})
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const outFile = yamlFile ?? path.join(projectPaths.basePath, 'webroot', 'docs', 'apidoc.yaml')
|
|
75
|
-
|
|
76
|
-
const str2ab = (str: string): Uint8Array => {
|
|
77
|
-
const buf = new ArrayBuffer(str.length * 2) // 2 bytes for each char
|
|
78
|
-
const bufView = new Uint8Array(buf)
|
|
79
|
-
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
80
|
-
bufView[i] = str.charCodeAt(i)
|
|
81
|
-
}
|
|
82
|
-
return bufView
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const yaml = builder.getSpecAsYaml()
|
|
86
|
-
const bytes = str2ab(yaml)
|
|
87
|
-
if (!includePrivate) {
|
|
88
|
-
fs.writeFileSync(outFile, yaml)
|
|
89
|
-
}
|
|
90
|
-
return bytes
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function addTypeSchema (builder: any, schemaName: string, schema: any): void {
|
|
94
|
-
const ref: any = { title: schemaName, type: 'object', properties: {} }
|
|
95
|
-
for (const prop of Object.getOwnPropertyNames(schema)) {
|
|
96
|
-
const scType: any = schemaType('', schema[prop], false)
|
|
97
|
-
|
|
98
|
-
ref.properties[prop] = scType
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
builder.addSchema(schemaName, ref)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function addFunctionMethod (pathDef: any, method: string, def: any): void {
|
|
105
|
-
// TODO: Define a return schema and put that here
|
|
106
|
-
const retDef: any = (def.returns)['200']
|
|
107
|
-
const content: any = {}
|
|
108
|
-
const mime = retDef?.content ?? retDef?.mime ?? 'text/plain'
|
|
109
|
-
content[mime] = {}
|
|
110
|
-
|
|
111
|
-
const methData = {
|
|
112
|
-
summary: def.name,
|
|
113
|
-
description: def.description,
|
|
114
|
-
responses: {
|
|
115
|
-
200: {
|
|
116
|
-
description: retDef?.description ?? 'Success Response',
|
|
117
|
-
content
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
pathDef[method] = methData
|
|
122
|
-
}
|
|
123
|
-
function addCORSOptionMethod (pathDef: any): void {
|
|
124
|
-
if (pathDef.options === undefined) return // already assinged by definition
|
|
125
|
-
// add options for CORS
|
|
126
|
-
pathDef.options = {
|
|
127
|
-
responses: {
|
|
128
|
-
200: {
|
|
129
|
-
description: '200 response',
|
|
130
|
-
content: {
|
|
131
|
-
'application/json': {
|
|
132
|
-
schema: {
|
|
133
|
-
$ref: '#/components/schemas/Empty'
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
},
|
|
139
|
-
'x-amazon-apigateway-integration': {
|
|
140
|
-
responses: {
|
|
141
|
-
default: {
|
|
142
|
-
statusCode: '200'
|
|
143
|
-
}
|
|
144
|
-
},
|
|
145
|
-
requestTemplates: {
|
|
146
|
-
'application/json': '{"statusCode": 200}'
|
|
147
|
-
},
|
|
148
|
-
passthroughBehavior: 'when_no_match',
|
|
149
|
-
type: 'mock'
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function addParameter (pathDef: any, param: any): void {
|
|
155
|
-
if (pathDef.parameters === undefined) pathDef.parameters = []
|
|
156
|
-
const parameters = pathDef.parameters
|
|
157
|
-
const example = param.example ?? param.default ?? ''
|
|
158
|
-
const type = param.type ?? typeof example
|
|
159
|
-
const deflt = param.default ?? example
|
|
160
|
-
|
|
161
|
-
parameters.push({
|
|
162
|
-
in: param.in,
|
|
163
|
-
name: param.name,
|
|
164
|
-
description: param.description,
|
|
165
|
-
example,
|
|
166
|
-
required: param.required,
|
|
167
|
-
schema: schemaType(deflt, type, true)
|
|
168
|
-
})
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function schemaType (deflt: string, namedType: string, innerOnly: boolean): any {
|
|
172
|
-
if (typeof namedType === 'object') return namedType
|
|
173
|
-
const typeFormat = namedType.split(':')
|
|
174
|
-
let type = typeFormat[0]
|
|
175
|
-
const format = typeFormat.length > 1 ? typeFormat[1] : undefined
|
|
176
|
-
if (!(type === 'string' ||
|
|
177
|
-
type === 'number' ||
|
|
178
|
-
type === 'integer' ||
|
|
179
|
-
type === 'boolean' ||
|
|
180
|
-
type === 'int' ||
|
|
181
|
-
type === 'bool'
|
|
182
|
-
)) {
|
|
183
|
-
return innerOnly
|
|
184
|
-
? {
|
|
185
|
-
$ref: `#/components/schemas/${type}`
|
|
186
|
-
}
|
|
187
|
-
: {
|
|
188
|
-
schema: {
|
|
189
|
-
$ref: `#/components/schemas/${type}`
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
if (type === 'int') type = 'integer'
|
|
194
|
-
if (type === 'bool') type = 'boolean'
|
|
195
|
-
return innerOnly ? { type, format, example: deflt } : { schema: { type, format, example: deflt } }
|
|
196
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* This is part 2 of 2 -- we take our pre-built json array of definitions and apply them to openApi in this phase.
|
|
3
|
+
*/
|
|
4
|
+
import { OpenApiBuilder } from 'openapi3-ts/oas30'
|
|
5
|
+
import fs from 'fs'
|
|
6
|
+
import path from 'path'
|
|
7
|
+
import { resolvePaths } from '../pathResolve'
|
|
8
|
+
|
|
9
|
+
export async function buildOpenApi (
|
|
10
|
+
defs: any[],
|
|
11
|
+
includePrivate: boolean = false,
|
|
12
|
+
yamlFile?: string
|
|
13
|
+
): Promise<Uint8Array> {
|
|
14
|
+
const builder = new OpenApiBuilder()
|
|
15
|
+
|
|
16
|
+
const projectPaths = await resolvePaths()
|
|
17
|
+
if (!projectPaths.verified) return new Uint8Array(0) // don't continue if not valid
|
|
18
|
+
|
|
19
|
+
// Read our package.json and construct info from that
|
|
20
|
+
const pkgFile = projectPaths.packagePath
|
|
21
|
+
let pkg: any = {}
|
|
22
|
+
try { pkg = JSON.parse(fs.readFileSync(pkgFile).toString()) } catch {}
|
|
23
|
+
const title: string = pkg.name ?? ''
|
|
24
|
+
// let summary = pkg.description;
|
|
25
|
+
// let spdx: string = pkg.license ?? ''
|
|
26
|
+
// const contactName: string = pkg.author ?? ''
|
|
27
|
+
const version: string = pkg.version ?? ''
|
|
28
|
+
|
|
29
|
+
// license and version definitely come from package.json
|
|
30
|
+
// description and title might get overridden by service.info file
|
|
31
|
+
const infoFile = path.join(projectPaths.functionPath, 'apiService.info.json')
|
|
32
|
+
let svcInfo: any = {}
|
|
33
|
+
if (fs.existsSync(infoFile)) {
|
|
34
|
+
svcInfo = JSON.parse(fs.readFileSync(infoFile).toString())
|
|
35
|
+
}
|
|
36
|
+
// spdx = svcInfo.contact?.spdx ?? spdx
|
|
37
|
+
|
|
38
|
+
const info = {
|
|
39
|
+
title: svcInfo.name ?? title,
|
|
40
|
+
// summary: summary,
|
|
41
|
+
description: svcInfo.description,
|
|
42
|
+
version: svcInfo.version ?? version ?? new Date().toUTCString()
|
|
43
|
+
}
|
|
44
|
+
builder.addInfo(info)
|
|
45
|
+
|
|
46
|
+
// map our defs into openApi values
|
|
47
|
+
for (const def of defs) {
|
|
48
|
+
const pathDef = {}
|
|
49
|
+
if (def.private === true && !includePrivate) continue // skip private
|
|
50
|
+
|
|
51
|
+
const parameters = def.parameters ?? []
|
|
52
|
+
const methods = def.allowedMethods.split(',')
|
|
53
|
+
const schemas = def.schemas ?? {}
|
|
54
|
+
for (const schemaName of Object.getOwnPropertyNames(schemas)) {
|
|
55
|
+
const schema = schemas[schemaName]
|
|
56
|
+
addTypeSchema(builder, schemaName, schema)
|
|
57
|
+
}
|
|
58
|
+
for (let method of methods) {
|
|
59
|
+
method = method.trim().toLowerCase()
|
|
60
|
+
addFunctionMethod(pathDef, method, def)
|
|
61
|
+
for (const param of parameters) {
|
|
62
|
+
addParameter(pathDef, param)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
addCORSOptionMethod(pathDef)
|
|
66
|
+
builder.addPath((def.pathMap ?? '/' + (def.name as string)), pathDef)
|
|
67
|
+
|
|
68
|
+
builder.addSchema('Empty', {
|
|
69
|
+
title: 'Empty Schema',
|
|
70
|
+
type: 'object'
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const outFile = yamlFile ?? path.join(projectPaths.basePath, 'webroot', 'docs', 'apidoc.yaml')
|
|
75
|
+
|
|
76
|
+
const str2ab = (str: string): Uint8Array => {
|
|
77
|
+
const buf = new ArrayBuffer(str.length * 2) // 2 bytes for each char
|
|
78
|
+
const bufView = new Uint8Array(buf)
|
|
79
|
+
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
80
|
+
bufView[i] = str.charCodeAt(i)
|
|
81
|
+
}
|
|
82
|
+
return bufView
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const yaml = builder.getSpecAsYaml()
|
|
86
|
+
const bytes = str2ab(yaml)
|
|
87
|
+
if (!includePrivate) {
|
|
88
|
+
fs.writeFileSync(outFile, yaml)
|
|
89
|
+
}
|
|
90
|
+
return bytes
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function addTypeSchema (builder: any, schemaName: string, schema: any): void {
|
|
94
|
+
const ref: any = { title: schemaName, type: 'object', properties: {} }
|
|
95
|
+
for (const prop of Object.getOwnPropertyNames(schema)) {
|
|
96
|
+
const scType: any = schemaType('', schema[prop], false)
|
|
97
|
+
|
|
98
|
+
ref.properties[prop] = scType
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
builder.addSchema(schemaName, ref)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function addFunctionMethod (pathDef: any, method: string, def: any): void {
|
|
105
|
+
// TODO: Define a return schema and put that here
|
|
106
|
+
const retDef: any = (def.returns)['200']
|
|
107
|
+
const content: any = {}
|
|
108
|
+
const mime = retDef?.content ?? retDef?.mime ?? 'text/plain'
|
|
109
|
+
content[mime] = {}
|
|
110
|
+
|
|
111
|
+
const methData = {
|
|
112
|
+
summary: def.name,
|
|
113
|
+
description: def.description,
|
|
114
|
+
responses: {
|
|
115
|
+
200: {
|
|
116
|
+
description: retDef?.description ?? 'Success Response',
|
|
117
|
+
content
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
pathDef[method] = methData
|
|
122
|
+
}
|
|
123
|
+
function addCORSOptionMethod (pathDef: any): void {
|
|
124
|
+
if (pathDef.options === undefined) return // already assinged by definition
|
|
125
|
+
// add options for CORS
|
|
126
|
+
pathDef.options = {
|
|
127
|
+
responses: {
|
|
128
|
+
200: {
|
|
129
|
+
description: '200 response',
|
|
130
|
+
content: {
|
|
131
|
+
'application/json': {
|
|
132
|
+
schema: {
|
|
133
|
+
$ref: '#/components/schemas/Empty'
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
'x-amazon-apigateway-integration': {
|
|
140
|
+
responses: {
|
|
141
|
+
default: {
|
|
142
|
+
statusCode: '200'
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
requestTemplates: {
|
|
146
|
+
'application/json': '{"statusCode": 200}'
|
|
147
|
+
},
|
|
148
|
+
passthroughBehavior: 'when_no_match',
|
|
149
|
+
type: 'mock'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function addParameter (pathDef: any, param: any): void {
|
|
155
|
+
if (pathDef.parameters === undefined) pathDef.parameters = []
|
|
156
|
+
const parameters = pathDef.parameters
|
|
157
|
+
const example = param.example ?? param.default ?? ''
|
|
158
|
+
const type = param.type ?? typeof example
|
|
159
|
+
const deflt = param.default ?? example
|
|
160
|
+
|
|
161
|
+
parameters.push({
|
|
162
|
+
in: param.in,
|
|
163
|
+
name: param.name,
|
|
164
|
+
description: param.description,
|
|
165
|
+
example,
|
|
166
|
+
required: param.required,
|
|
167
|
+
schema: schemaType(deflt, type, true)
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function schemaType (deflt: string, namedType: string, innerOnly: boolean): any {
|
|
172
|
+
if (typeof namedType === 'object') return namedType
|
|
173
|
+
const typeFormat = namedType.split(':')
|
|
174
|
+
let type = typeFormat[0]
|
|
175
|
+
const format = typeFormat.length > 1 ? typeFormat[1] : undefined
|
|
176
|
+
if (!(type === 'string' ||
|
|
177
|
+
type === 'number' ||
|
|
178
|
+
type === 'integer' ||
|
|
179
|
+
type === 'boolean' ||
|
|
180
|
+
type === 'int' ||
|
|
181
|
+
type === 'bool'
|
|
182
|
+
)) {
|
|
183
|
+
return innerOnly
|
|
184
|
+
? {
|
|
185
|
+
$ref: `#/components/schemas/${type}`
|
|
186
|
+
}
|
|
187
|
+
: {
|
|
188
|
+
schema: {
|
|
189
|
+
$ref: `#/components/schemas/${type}`
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (type === 'int') type = 'integer'
|
|
194
|
+
if (type === 'bool') type = 'boolean'
|
|
195
|
+
return innerOnly ? { type, format, example: deflt } : { schema: { type, format, example: deflt } }
|
|
196
|
+
}
|
package/src/lib/pathResolve.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import fs from 'fs'
|
|
3
|
-
|
|
4
|
-
// Find the path roots in the project directory
|
|
5
|
-
export function resolvePaths (
|
|
6
|
-
): {
|
|
7
|
-
basePath: string // project base
|
|
8
|
-
buildPath: string // build folder
|
|
9
|
-
functionPath: string // functions folder
|
|
10
|
-
packagePath: string // package.json
|
|
11
|
-
verified: boolean // all of these exist if true, else, may be incomplete project
|
|
12
|
-
} {
|
|
13
|
-
const cwd = process.cwd()
|
|
14
|
-
let funcPath = path.join(cwd, 'functions')
|
|
15
|
-
while (true) {
|
|
16
|
-
if (!fs.existsSync(funcPath)) {
|
|
17
|
-
funcPath = path.normalize(path.join(funcPath, '..'))
|
|
18
|
-
} else {
|
|
19
|
-
const basePath = path.normalize(path.join(funcPath, '..'))
|
|
20
|
-
const buildPath = path.join(basePath, 'build')
|
|
21
|
-
const packagePath = path.join(basePath, 'package.json')
|
|
22
|
-
const verified = fs.existsSync(basePath) && fs.existsSync(funcPath) && fs.existsSync(packagePath)
|
|
23
|
-
return { basePath, buildPath, functionPath: funcPath, packagePath, verified }
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
|
|
4
|
+
// Find the path roots in the project directory
|
|
5
|
+
export function resolvePaths (
|
|
6
|
+
): {
|
|
7
|
+
basePath: string // project base
|
|
8
|
+
buildPath: string // build folder
|
|
9
|
+
functionPath: string // functions folder
|
|
10
|
+
packagePath: string // package.json
|
|
11
|
+
verified: boolean // all of these exist if true, else, may be incomplete project
|
|
12
|
+
} {
|
|
13
|
+
const cwd = process.cwd()
|
|
14
|
+
let funcPath = path.join(cwd, 'functions')
|
|
15
|
+
while (true) {
|
|
16
|
+
if (!fs.existsSync(funcPath)) {
|
|
17
|
+
funcPath = path.normalize(path.join(funcPath, '..'))
|
|
18
|
+
} else {
|
|
19
|
+
const basePath = path.normalize(path.join(funcPath, '..'))
|
|
20
|
+
const buildPath = path.join(basePath, 'build')
|
|
21
|
+
const packagePath = path.join(basePath, 'package.json')
|
|
22
|
+
const verified = fs.existsSync(basePath) && fs.existsSync(funcPath) && fs.existsSync(packagePath)
|
|
23
|
+
return { basePath, buildPath, functionPath: funcPath, packagePath, verified }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/lib/utils.ts
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
/* eslint @typescript-eslint/no-var-requires: "off" */
|
|
2
|
-
import { executeCommand } from './executeCommand'
|
|
3
|
-
import * as ac from 'ansi-colors'
|
|
4
|
-
import * as fs from 'fs'
|
|
5
|
-
|
|
6
|
-
/** General utilities */
|
|
7
|
-
|
|
8
|
-
const zipDir = require('zip-dir')
|
|
9
|
-
|
|
10
|
-
// pause the given number of milliseconds
|
|
11
|
-
export async function delay (
|
|
12
|
-
ms: number // milliseconds to delay
|
|
13
|
-
): Promise<void> {
|
|
14
|
-
return await new Promise(resolve => { setTimeout(resolve, ms) })
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function FolderToZip (
|
|
18
|
-
folderPath: string,
|
|
19
|
-
zipPath: string
|
|
20
|
-
): Promise<Uint8Array> {
|
|
21
|
-
return await new Promise(resolve => {
|
|
22
|
-
zipDir(folderPath, { saveTo: zipPath }, function (err: any, buffer: Uint8Array) {
|
|
23
|
-
if (err !== '' && err !== undefined && err !== null) throw err
|
|
24
|
-
// `buffer` is the buffer of the zipped file
|
|
25
|
-
// And the buffer was saved to `~/myzip.zip`
|
|
26
|
-
resolve(buffer)
|
|
27
|
-
})
|
|
28
|
-
})
|
|
29
|
-
}
|
|
30
|
-
export async function UnzipToFolder (
|
|
31
|
-
zipPath: string,
|
|
32
|
-
folderPath: string,
|
|
33
|
-
replace: boolean = true
|
|
34
|
-
): Promise<void> {
|
|
35
|
-
// TODO: using CLI -- find a good package. "unzip" has vulnerabilities. Try others.
|
|
36
|
-
|
|
37
|
-
if (replace) fs.rmSync(folderPath, { recursive: true, force: true })
|
|
38
|
-
const result: { retcode: number, errStr: string } = await executeCommand('unzip', [zipPath, '-d', folderPath])
|
|
39
|
-
if (result.retcode !== 0) {
|
|
40
|
-
console.error(ac.red.bold(`failed to stage webroot (${result.retcode}): ${result.errStr}`))
|
|
41
|
-
throw Error()
|
|
42
|
-
}
|
|
43
|
-
}
|
|
1
|
+
/* eslint @typescript-eslint/no-var-requires: "off" */
|
|
2
|
+
import { executeCommand } from './executeCommand'
|
|
3
|
+
import * as ac from 'ansi-colors'
|
|
4
|
+
import * as fs from 'fs'
|
|
5
|
+
|
|
6
|
+
/** General utilities */
|
|
7
|
+
|
|
8
|
+
const zipDir = require('zip-dir')
|
|
9
|
+
|
|
10
|
+
// pause the given number of milliseconds
|
|
11
|
+
export async function delay (
|
|
12
|
+
ms: number // milliseconds to delay
|
|
13
|
+
): Promise<void> {
|
|
14
|
+
return await new Promise(resolve => { setTimeout(resolve, ms) })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function FolderToZip (
|
|
18
|
+
folderPath: string,
|
|
19
|
+
zipPath: string
|
|
20
|
+
): Promise<Uint8Array> {
|
|
21
|
+
return await new Promise(resolve => {
|
|
22
|
+
zipDir(folderPath, { saveTo: zipPath }, function (err: any, buffer: Uint8Array) {
|
|
23
|
+
if (err !== '' && err !== undefined && err !== null) throw err
|
|
24
|
+
// `buffer` is the buffer of the zipped file
|
|
25
|
+
// And the buffer was saved to `~/myzip.zip`
|
|
26
|
+
resolve(buffer)
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
export async function UnzipToFolder (
|
|
31
|
+
zipPath: string,
|
|
32
|
+
folderPath: string,
|
|
33
|
+
replace: boolean = true
|
|
34
|
+
): Promise<void> {
|
|
35
|
+
// TODO: using CLI -- find a good package. "unzip" has vulnerabilities. Try others.
|
|
36
|
+
|
|
37
|
+
if (replace) fs.rmSync(folderPath, { recursive: true, force: true })
|
|
38
|
+
const result: { retcode: number, errStr: string } = await executeCommand('unzip', [zipPath, '-d', folderPath])
|
|
39
|
+
if (result.retcode !== 0) {
|
|
40
|
+
console.error(ac.red.bold(`failed to stage webroot (${result.retcode}): ${result.errStr}`))
|
|
41
|
+
throw Error()
|
|
42
|
+
}
|
|
43
|
+
}
|