@platformatic/composer 2.74.3 → 3.0.0-alpha.2
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/config.d.ts +2 -30
- package/eslint.config.js +11 -2
- package/index.d.ts +58 -17
- package/index.js +29 -212
- package/lib/application.js +186 -0
- package/lib/commands/index.js +15 -0
- package/lib/commands/openapi-fetch-schemas.js +47 -0
- package/lib/composer-hook.js +9 -9
- package/lib/errors.js +15 -10
- package/lib/generator.js +127 -0
- package/lib/graphql-fetch.js +44 -46
- package/lib/graphql-generator.js +12 -10
- package/lib/graphql.js +13 -9
- package/lib/{proxy/not-host-constraints.js → not-host-constraints.js} +3 -5
- package/lib/openapi-composer.js +39 -41
- package/lib/openapi-config-schema.js +26 -30
- package/lib/openapi-generator.js +115 -112
- package/lib/openapi-load-config.js +14 -14
- package/lib/openapi-modifier.js +12 -21
- package/lib/openapi-scalar.js +3 -5
- package/lib/proxy.js +13 -12
- package/lib/{root-endpoint/index.js → root.js} +12 -12
- package/lib/schema.js +41 -25
- package/lib/stackable.js +29 -39
- package/lib/upgrade.js +6 -8
- package/lib/utils.js +5 -16
- package/lib/versions/2.0.0.js +4 -6
- package/lib/versions/3.0.0.js +14 -0
- package/package.json +15 -18
- package/schema.json +8 -153
- package/.c8rc +0 -6
- package/composer.mjs +0 -54
- package/help/create.txt +0 -11
- package/help/help.txt +0 -7
- package/help/openapi schemas fetch.txt +0 -9
- package/help/start.txt +0 -54
- package/index.test-d.ts +0 -23
- package/lib/create.mjs +0 -84
- package/lib/generator/README.md +0 -30
- package/lib/generator/composer-generator.d.ts +0 -11
- package/lib/generator/composer-generator.js +0 -128
- package/lib/openapi-fetch-schemas.mjs +0 -61
- /package/{lib/root-endpoint/public → public}/images/dark_mode.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/ellipse.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/external-link.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/favicon.ico +0 -0
- /package/{lib/root-endpoint/public → public}/images/graphiql.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/graphql.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/light_mode.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/openapi.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/platformatic-logo-dark.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/platformatic-logo-light.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/reverse-proxy.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/triangle_dark.svg +0 -0
- /package/{lib/root-endpoint/public → public}/images/triangle_light.svg +0 -0
- /package/{lib/root-endpoint/public → public}/index.html +0 -0
- /package/{lib/root-endpoint/public → public}/index.njk +0 -0
- /package/{lib/root-endpoint/public → public}/main.css +0 -0
package/lib/errors.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const createError = require('@fastify/error')
|
|
1
|
+
import createError from '@fastify/error'
|
|
4
2
|
|
|
5
3
|
const ERROR_PREFIX = 'PLT_COMPOSER'
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
export const FastifyInstanceIsAlreadyListeningError = createError(
|
|
6
|
+
`${ERROR_PREFIX}_FASTIFY_INSTANCE_IS_ALREADY_LISTENING`,
|
|
7
|
+
'Fastify instance is already listening. Cannot call "addComposerOnRouteHook"!'
|
|
8
|
+
)
|
|
9
|
+
export const FailedToFetchOpenAPISchemaError = createError(
|
|
10
|
+
`${ERROR_PREFIX}_FAILED_TO_FETCH_OPENAPI_SCHEMA`,
|
|
11
|
+
'Failed to fetch OpenAPI schema from %s'
|
|
12
|
+
)
|
|
13
|
+
export const ValidationErrors = createError(`${ERROR_PREFIX}_VALIDATION_ERRORS`, 'Validation errors: %s')
|
|
14
|
+
export const PathAlreadyExistsError = createError(`${ERROR_PREFIX}_PATH_ALREADY_EXISTS`, 'Path "%s" already exists')
|
|
15
|
+
export const CouldNotReadOpenAPIConfigError = createError(
|
|
16
|
+
`${ERROR_PREFIX}_COULD_NOT_READ_OPENAPI_CONFIG`,
|
|
17
|
+
'Could not read openapi config for "%s" service'
|
|
18
|
+
)
|
package/lib/generator.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Generator as ServiceGenerator } from '@platformatic/service'
|
|
2
|
+
|
|
3
|
+
export class Generator extends ServiceGenerator {
|
|
4
|
+
constructor (opts) {
|
|
5
|
+
super({
|
|
6
|
+
...opts,
|
|
7
|
+
module: '@platformatic/composer'
|
|
8
|
+
})
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
getDefaultConfig () {
|
|
12
|
+
const defaultBaseConfig = super.getDefaultConfig()
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
...defaultBaseConfig,
|
|
16
|
+
plugin: false,
|
|
17
|
+
routes: false,
|
|
18
|
+
tests: false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async _beforePrepare () {
|
|
23
|
+
if (this.config.isUpdating) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await super._beforePrepare()
|
|
28
|
+
|
|
29
|
+
this.addEnvVars(
|
|
30
|
+
{
|
|
31
|
+
PLT_EXAMPLE_ORIGIN: 'http://127.0.0.1:3043'
|
|
32
|
+
},
|
|
33
|
+
{ overwrite: false, default: true }
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
this.config.dependencies = {
|
|
37
|
+
'@platformatic/composer': `^${this.platformaticVersion}`
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async _afterPrepare () {
|
|
42
|
+
if (this.config.isUpdating) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await super._afterPrepare()
|
|
47
|
+
const PLT_ENVIRONMENT_TEMPLATE = `
|
|
48
|
+
import { type FastifyInstance } from 'fastify'
|
|
49
|
+
import { PlatformaticApplication, PlatformaticComposerConfig } from '@platformatic/composer'
|
|
50
|
+
|
|
51
|
+
declare module 'fastify' {
|
|
52
|
+
interface FastifyInstance {
|
|
53
|
+
platformatic: PlatformaticApplication<PlatformaticComposerConfig>
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
`
|
|
57
|
+
|
|
58
|
+
const README = `
|
|
59
|
+
# Platformatic Composer API
|
|
60
|
+
|
|
61
|
+
This is a generated [Platformatic Composer](https://docs.platformatic.dev/docs/composer/overview) application.
|
|
62
|
+
|
|
63
|
+
## Requirements
|
|
64
|
+
|
|
65
|
+
Platformatic supports macOS, Linux and Windows ([WSL](https://docs.microsoft.com/windows/wsl/) recommended).
|
|
66
|
+
You'll need to have [Node.js](https://nodejs.org/) >= v18.8.0 or >= v20.6.0
|
|
67
|
+
|
|
68
|
+
## Setup
|
|
69
|
+
|
|
70
|
+
1. Install dependencies:
|
|
71
|
+
|
|
72
|
+
\`\`\`bash
|
|
73
|
+
npm install
|
|
74
|
+
\`\`\`
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
Run the API with:
|
|
79
|
+
|
|
80
|
+
\`\`\`bash
|
|
81
|
+
npm start
|
|
82
|
+
\`\`\`
|
|
83
|
+
|
|
84
|
+
### Explore
|
|
85
|
+
- ⚡ The Platformatic Composer server is running at http://localhost:3042/
|
|
86
|
+
- 📔 View the REST API's Swagger documentation at http://localhost:3042/documentation/
|
|
87
|
+
`
|
|
88
|
+
|
|
89
|
+
this.addFile({ path: '', file: 'plt-env.d.ts', contents: PLT_ENVIRONMENT_TEMPLATE })
|
|
90
|
+
this.addFile({ path: '', file: 'README.md', contents: README })
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async _getConfigFileContents () {
|
|
94
|
+
const config = await super._getConfigFileContents()
|
|
95
|
+
delete config.service
|
|
96
|
+
config.$schema = `https://schemas.platformatic.dev/@platformatic/composer/${this.platformaticVersion}.json`
|
|
97
|
+
|
|
98
|
+
config.composer = {
|
|
99
|
+
services: [
|
|
100
|
+
{
|
|
101
|
+
id: 'example',
|
|
102
|
+
origin: `{${this.getEnvVarName('PLT_EXAMPLE_ORIGIN')}}`,
|
|
103
|
+
openapi: {
|
|
104
|
+
url: '/documentation/json'
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
refreshTimeout: 1000
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (this.runtime !== null) {
|
|
112
|
+
config.composer.services = this.runtime.services
|
|
113
|
+
.filter(serviceMeta => serviceMeta.service.module !== '@platformatic/composer')
|
|
114
|
+
.map(serviceMeta => {
|
|
115
|
+
return {
|
|
116
|
+
id: serviceMeta.name,
|
|
117
|
+
openapi: {
|
|
118
|
+
url: '/documentation/json',
|
|
119
|
+
prefix: `/${serviceMeta.name}`
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return config
|
|
126
|
+
}
|
|
127
|
+
}
|
package/lib/graphql-fetch.js
CHANGED
|
@@ -1,49 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const { compose } = require('@platformatic/graphql-composer')
|
|
1
|
+
import { compose } from '@platformatic/graphql-composer'
|
|
4
2
|
|
|
5
3
|
const placeholderSdl = 'Query { _info: String }'
|
|
6
|
-
const placeholderResolvers = { Query: { _info: 'platformatic
|
|
7
|
-
|
|
8
|
-
function createSupergraph ({ sdl = null, resolvers = {} } = {}) {
|
|
9
|
-
// in case of temporary failures of subgraphs on watching, the service can restart if no subgraphs are (tempoary) available
|
|
10
|
-
if (!sdl) {
|
|
11
|
-
return {
|
|
12
|
-
sdl: placeholderSdl,
|
|
13
|
-
resolvers: placeholderResolvers,
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return { sdl, resolvers }
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function isSameGraphqlSchema (a, b) {
|
|
20
|
-
// TODO review
|
|
21
|
-
return a?.sdl === b?.sdl
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function serviceToSubgraphConfig (service) {
|
|
25
|
-
if (!service.graphql) { return }
|
|
26
|
-
return {
|
|
27
|
-
name: service.graphql.name || service.id || service.origin,
|
|
28
|
-
entities: service.graphql.entities,
|
|
29
|
-
server: {
|
|
30
|
-
host: service.graphql.host || service.origin,
|
|
31
|
-
composeEndpoint: service.graphql.composeEndpoint,
|
|
32
|
-
graphqlEndpoint: service.graphql.graphqlEndpoint,
|
|
33
|
-
},
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async function fetchGraphqlSubgraphs (services, options, app) {
|
|
38
|
-
const subgraphs = services.map(serviceToSubgraphConfig).filter(s => !!s)
|
|
39
|
-
const composer = await compose({ ...toComposerOptions(options, app), subgraphs })
|
|
40
|
-
|
|
41
|
-
return createSupergraph({
|
|
42
|
-
logger: app.log,
|
|
43
|
-
sdl: composer.toSdl(),
|
|
44
|
-
resolvers: composer.resolvers,
|
|
45
|
-
})
|
|
46
|
-
}
|
|
4
|
+
const placeholderResolvers = { Query: { _info: '@platformatic/composer' } }
|
|
47
5
|
|
|
48
6
|
// TODO support subscriptions
|
|
49
7
|
// const defaultSubscriptionsOptions = {
|
|
@@ -78,8 +36,48 @@ function toComposerOptions (options, app) {
|
|
|
78
36
|
app.log.error({ err }, 'running onSubgraphError')
|
|
79
37
|
}
|
|
80
38
|
}
|
|
81
|
-
}
|
|
39
|
+
}
|
|
82
40
|
}
|
|
83
41
|
}
|
|
84
42
|
|
|
85
|
-
|
|
43
|
+
export function createSupergraph ({ sdl = null, resolvers = {} } = {}) {
|
|
44
|
+
// in case of temporary failures of subgraphs on watching, the service can restart if no subgraphs are (tempoary) available
|
|
45
|
+
if (!sdl) {
|
|
46
|
+
return {
|
|
47
|
+
sdl: placeholderSdl,
|
|
48
|
+
resolvers: placeholderResolvers
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { sdl, resolvers }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function isSameGraphqlSchema (a, b) {
|
|
55
|
+
// TODO review
|
|
56
|
+
return a?.sdl === b?.sdl
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function serviceToSubgraphConfig (service) {
|
|
60
|
+
if (!service.graphql) {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
name: service.graphql.name || service.id || service.origin,
|
|
65
|
+
entities: service.graphql.entities,
|
|
66
|
+
server: {
|
|
67
|
+
host: service.graphql.host || service.origin,
|
|
68
|
+
composeEndpoint: service.graphql.composeEndpoint,
|
|
69
|
+
graphqlEndpoint: service.graphql.graphqlEndpoint
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function fetchGraphqlSubgraphs (services, options, app) {
|
|
75
|
+
const subgraphs = services.map(serviceToSubgraphConfig).filter(s => !!s)
|
|
76
|
+
const composer = await compose({ ...toComposerOptions(options, app), subgraphs })
|
|
77
|
+
|
|
78
|
+
return createSupergraph({
|
|
79
|
+
logger: app.log,
|
|
80
|
+
sdl: composer.toSdl(),
|
|
81
|
+
resolvers: composer.resolvers
|
|
82
|
+
})
|
|
83
|
+
}
|
package/lib/graphql-generator.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import fp from 'fastify-plugin'
|
|
2
|
+
import mercurius from 'mercurius'
|
|
3
|
+
import { fetchGraphqlSubgraphs } from './graphql-fetch.js'
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
async function composeGraphql (app, opts) {
|
|
8
|
-
if (!opts.services.some(s => s.graphql)) { return }
|
|
5
|
+
async function graphqlGeneratorPlugin (app, opts) {
|
|
6
|
+
if (!opts.services.some(s => s.graphql)) {
|
|
7
|
+
return
|
|
8
|
+
}
|
|
9
9
|
|
|
10
10
|
const services = []
|
|
11
11
|
|
|
12
12
|
for (const service of opts.services) {
|
|
13
|
-
if (!service.graphql) {
|
|
13
|
+
if (!service.graphql) {
|
|
14
|
+
continue
|
|
15
|
+
}
|
|
14
16
|
services.push(service)
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
const graphqlConfig = {
|
|
18
|
-
graphiql: opts.graphql?.graphiql
|
|
20
|
+
graphiql: opts.graphql?.graphiql
|
|
19
21
|
}
|
|
20
22
|
if (services.length > 0) {
|
|
21
23
|
const graphqlSupergraph = await fetchGraphqlSubgraphs(services, opts.graphql, app)
|
|
@@ -28,4 +30,4 @@ async function composeGraphql (app, opts) {
|
|
|
28
30
|
await app.register(mercurius, graphqlConfig)
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
export const graphqlGenerator = fp(graphqlGeneratorPlugin)
|
package/lib/graphql.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const fp = require('fastify-plugin')
|
|
4
|
-
const { createSupergraph } = require('./graphql-fetch')
|
|
1
|
+
import fp from 'fastify-plugin'
|
|
2
|
+
import { createSupergraph } from './graphql-fetch.js'
|
|
5
3
|
|
|
6
4
|
const graphqlSupergraphSymbol = Symbol('graphqlSupergraph')
|
|
7
5
|
|
|
8
|
-
async function
|
|
6
|
+
export async function graphqlPlugin (app, opts) {
|
|
9
7
|
app.decorate('graphqlSupergraph', {
|
|
10
|
-
getter () {
|
|
11
|
-
|
|
8
|
+
getter () {
|
|
9
|
+
return this[graphqlSupergraphSymbol]
|
|
10
|
+
},
|
|
11
|
+
setter (v) {
|
|
12
|
+
this[graphqlSupergraphSymbol] = v
|
|
13
|
+
}
|
|
12
14
|
})
|
|
13
15
|
app.decorate('graphqlComposerOptions', {
|
|
14
|
-
getter () {
|
|
16
|
+
getter () {
|
|
17
|
+
return opts
|
|
18
|
+
}
|
|
15
19
|
})
|
|
16
20
|
|
|
17
21
|
app.graphqlSupergraph = createSupergraph()
|
|
18
22
|
}
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
export const graphql = fp(graphqlPlugin)
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
module.exports = {
|
|
1
|
+
export const notHostConstraints = {
|
|
4
2
|
name: 'notHost',
|
|
5
|
-
storage
|
|
3
|
+
storage () {
|
|
6
4
|
const store = []
|
|
7
5
|
|
|
8
6
|
return {
|
|
@@ -23,7 +21,7 @@ module.exports = {
|
|
|
23
21
|
store
|
|
24
22
|
}
|
|
25
23
|
},
|
|
26
|
-
deriveConstraint
|
|
24
|
+
deriveConstraint (req) {
|
|
27
25
|
return req.headers.host || req.headers[':authority']
|
|
28
26
|
},
|
|
29
27
|
mustMatchWhenDerived: false,
|
package/lib/openapi-composer.js
CHANGED
|
@@ -1,9 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
import rfdc from 'rfdc'
|
|
2
|
+
import { PathAlreadyExistsError } from './errors.js'
|
|
2
3
|
|
|
3
|
-
const clone =
|
|
4
|
-
const errors = require('./errors')
|
|
4
|
+
const clone = rfdc()
|
|
5
5
|
|
|
6
|
-
function
|
|
6
|
+
function generateOperationIdApiPrefix (operationId) {
|
|
7
|
+
return (
|
|
8
|
+
operationId
|
|
9
|
+
.trim()
|
|
10
|
+
.replace(/[^A-Z0-9]+/gi, '_')
|
|
11
|
+
.replace(/^_+|_+$/g, '') + '_'
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function namespaceSchemaRefs (apiPrefix, schema) {
|
|
16
|
+
if (schema.$ref && schema.$ref.startsWith('#/components/schemas')) {
|
|
17
|
+
schema.$ref = schema.$ref.replace('#/components/schemas/', '#/components/schemas/' + apiPrefix)
|
|
18
|
+
}
|
|
19
|
+
for (const childSchema of Object.values(schema)) {
|
|
20
|
+
if (typeof childSchema === 'object') {
|
|
21
|
+
namespaceSchemaRefs(apiPrefix, childSchema)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function namespaceSchemaOperationIds (apiPrefix, schema) {
|
|
27
|
+
if (schema.operationId) {
|
|
28
|
+
schema.operationId = apiPrefix + schema.operationId
|
|
29
|
+
}
|
|
30
|
+
for (const childSchema of Object.values(schema)) {
|
|
31
|
+
if (typeof childSchema === 'object') {
|
|
32
|
+
namespaceSchemaOperationIds(apiPrefix, childSchema)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function composeOpenApi (apis, options = {}) {
|
|
7
38
|
const mergedPaths = {}
|
|
8
39
|
const mergedSchemas = {}
|
|
9
40
|
const mergedSecuritySchemes = {}
|
|
@@ -31,7 +62,7 @@ function composeOpenApi (apis, options = {}) {
|
|
|
31
62
|
const mergedPath = prefix ? prefix + path : path
|
|
32
63
|
|
|
33
64
|
if (mergedPaths[mergedPath]) {
|
|
34
|
-
throw new
|
|
65
|
+
throw new PathAlreadyExistsError(mergedPath)
|
|
35
66
|
}
|
|
36
67
|
mergedPaths[mergedPath] = pathSchema
|
|
37
68
|
}
|
|
@@ -59,45 +90,12 @@ function composeOpenApi (apis, options = {}) {
|
|
|
59
90
|
openapi: '3.0.0',
|
|
60
91
|
info: {
|
|
61
92
|
title: options.title || 'Platformatic Composer',
|
|
62
|
-
version: options.version || '1.0.0'
|
|
93
|
+
version: options.version || '1.0.0'
|
|
63
94
|
},
|
|
64
95
|
components: {
|
|
65
96
|
securitySchemes: mergedSecuritySchemes,
|
|
66
|
-
schemas: mergedSchemas
|
|
97
|
+
schemas: mergedSchemas
|
|
67
98
|
},
|
|
68
|
-
paths: mergedPaths
|
|
99
|
+
paths: mergedPaths
|
|
69
100
|
}
|
|
70
101
|
}
|
|
71
|
-
|
|
72
|
-
function generateOperationIdApiPrefix (operationId) {
|
|
73
|
-
return operationId.trim()
|
|
74
|
-
.replace(/[^A-Z0-9]+/ig, '_')
|
|
75
|
-
.replace(/^_+|_+$/g, '') + '_'
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function namespaceSchemaRefs (apiPrefix, schema) {
|
|
79
|
-
if (schema.$ref && schema.$ref.startsWith('#/components/schemas')) {
|
|
80
|
-
schema.$ref = schema.$ref.replace(
|
|
81
|
-
'#/components/schemas/',
|
|
82
|
-
'#/components/schemas/' + apiPrefix
|
|
83
|
-
)
|
|
84
|
-
}
|
|
85
|
-
for (const childSchema of Object.values(schema)) {
|
|
86
|
-
if (typeof childSchema === 'object') {
|
|
87
|
-
namespaceSchemaRefs(apiPrefix, childSchema)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function namespaceSchemaOperationIds (apiPrefix, schema) {
|
|
93
|
-
if (schema.operationId) {
|
|
94
|
-
schema.operationId = apiPrefix + schema.operationId
|
|
95
|
-
}
|
|
96
|
-
for (const childSchema of Object.values(schema)) {
|
|
97
|
-
if (typeof childSchema === 'object') {
|
|
98
|
-
namespaceSchemaOperationIds(apiPrefix, childSchema)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
module.exports = composeOpenApi
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
1
|
const ignoreSchema = {
|
|
4
2
|
type: 'object',
|
|
5
3
|
properties: {
|
|
6
|
-
ignore: { type: 'boolean' }
|
|
4
|
+
ignore: { type: 'boolean' }
|
|
7
5
|
},
|
|
8
|
-
additionalProperties: false
|
|
6
|
+
additionalProperties: false
|
|
9
7
|
}
|
|
10
8
|
|
|
11
9
|
const aliasSchema = {
|
|
12
10
|
type: 'object',
|
|
13
11
|
properties: {
|
|
14
|
-
alias: { type: 'string' }
|
|
15
|
-
}
|
|
12
|
+
alias: { type: 'string' }
|
|
13
|
+
}
|
|
16
14
|
}
|
|
17
15
|
|
|
18
16
|
const jsonSchemaSchema = {
|
|
@@ -28,16 +26,16 @@ const jsonSchemaSchema = {
|
|
|
28
26
|
{
|
|
29
27
|
type: 'object',
|
|
30
28
|
properties: {
|
|
31
|
-
rename: { type: 'string' }
|
|
29
|
+
rename: { type: 'string' }
|
|
32
30
|
},
|
|
33
|
-
additionalProperties: false
|
|
34
|
-
}
|
|
35
|
-
]
|
|
36
|
-
}
|
|
31
|
+
additionalProperties: false
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
37
35
|
},
|
|
38
|
-
items: { $ref: 'json-schema' }
|
|
36
|
+
items: { $ref: 'json-schema' }
|
|
39
37
|
},
|
|
40
|
-
additionalProperties: false
|
|
38
|
+
additionalProperties: false
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
const routeSchema = {
|
|
@@ -49,15 +47,15 @@ const routeSchema = {
|
|
|
49
47
|
responses: {
|
|
50
48
|
type: 'object',
|
|
51
49
|
properties: {
|
|
52
|
-
200: { $ref: 'json-schema' }
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
]
|
|
50
|
+
200: { $ref: 'json-schema' }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
]
|
|
58
56
|
}
|
|
59
57
|
|
|
60
|
-
const openApiConfigSchema = {
|
|
58
|
+
export const openApiConfigSchema = {
|
|
61
59
|
type: 'object',
|
|
62
60
|
properties: {
|
|
63
61
|
paths: {
|
|
@@ -76,18 +74,16 @@ const openApiConfigSchema = {
|
|
|
76
74
|
delete: routeSchema,
|
|
77
75
|
options: routeSchema,
|
|
78
76
|
head: routeSchema,
|
|
79
|
-
trace: routeSchema
|
|
77
|
+
trace: routeSchema
|
|
80
78
|
},
|
|
81
|
-
additionalProperties: false
|
|
82
|
-
}
|
|
83
|
-
]
|
|
84
|
-
}
|
|
85
|
-
}
|
|
79
|
+
additionalProperties: false
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
86
84
|
},
|
|
87
85
|
additionalProperties: false,
|
|
88
86
|
definitions: {
|
|
89
|
-
'json-schema': jsonSchemaSchema
|
|
90
|
-
}
|
|
87
|
+
'json-schema': jsonSchemaSchema
|
|
88
|
+
}
|
|
91
89
|
}
|
|
92
|
-
|
|
93
|
-
module.exports = openApiConfigSchema
|