@platformatic/sql-json-schema-mapper 0.19.1 → 0.19.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/index.js +103 -2
- package/package.json +7 -2
- package/test/types.test.js +189 -0
package/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const CodeBlockWriter = require('code-block-writer').default
|
|
4
|
+
const { property } = require('safe-identifier')
|
|
5
|
+
|
|
3
6
|
function mapSQLTypeToOpenAPIType (sqlType) {
|
|
4
7
|
// TODO support more types
|
|
5
8
|
/* istanbul ignore next */
|
|
@@ -91,7 +94,7 @@ function mapSQLEntityToJSONSchema (entity, ignore = {}) {
|
|
|
91
94
|
properties[field.camelcase].enum = field.enum
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
|
-
|
|
97
|
+
const res = {
|
|
95
98
|
$id: entity.name,
|
|
96
99
|
title: entity.name,
|
|
97
100
|
description: `A ${entity.name}`,
|
|
@@ -99,6 +102,104 @@ function mapSQLEntityToJSONSchema (entity, ignore = {}) {
|
|
|
99
102
|
properties,
|
|
100
103
|
required
|
|
101
104
|
}
|
|
105
|
+
|
|
106
|
+
return res
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function mapOpenAPItoTypes (obj, opts = {}) {
|
|
110
|
+
let { writer, addedProps } = opts
|
|
111
|
+
addedProps ??= new Set()
|
|
112
|
+
writer ??= new CodeBlockWriter()
|
|
113
|
+
const { title, description, properties, required, additionalProperties } = obj
|
|
114
|
+
writer.write('/**').newLine()
|
|
115
|
+
writer.write(` * ${title}`).newLine()
|
|
116
|
+
writer.write(` * ${description}`).newLine()
|
|
117
|
+
writer.write(' */').newLine()
|
|
118
|
+
writer.write(`declare interface ${title}`).block(() => {
|
|
119
|
+
renderProperties(writer, addedProps, properties, additionalProperties, required)
|
|
120
|
+
})
|
|
121
|
+
return writer.toString()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function renderProperties (writer, addedProps, properties = {}, additionalProperties, required = []) {
|
|
125
|
+
for (const name of Object.keys(properties)) {
|
|
126
|
+
const { type, nullable, items } = properties[name]
|
|
127
|
+
addedProps.add(name)
|
|
128
|
+
if (required.indexOf(name) !== -1) {
|
|
129
|
+
writer.write(property(null, name))
|
|
130
|
+
} else {
|
|
131
|
+
writer.write(property(null, name))
|
|
132
|
+
writer.write('?')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let types
|
|
136
|
+
if (Array.isArray(type)) {
|
|
137
|
+
types = type
|
|
138
|
+
} else {
|
|
139
|
+
types = [type]
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (nullable && types.indexOf('null') === -1) {
|
|
143
|
+
types.push('null')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let first = true
|
|
147
|
+
writer.write(': ')
|
|
148
|
+
for (const type of types) {
|
|
149
|
+
if (!first) {
|
|
150
|
+
writer.write(' | ')
|
|
151
|
+
}
|
|
152
|
+
first = false
|
|
153
|
+
if (type === 'null') {
|
|
154
|
+
writer.write('null')
|
|
155
|
+
} else if (type === 'array') {
|
|
156
|
+
switch (items.type) {
|
|
157
|
+
case 'object':
|
|
158
|
+
writer.inlineBlock(() => {
|
|
159
|
+
const current = items
|
|
160
|
+
renderProperties(writer, addedProps, current.properties, current.additionalProperties, current.required)
|
|
161
|
+
})
|
|
162
|
+
writer.write('[]')
|
|
163
|
+
break
|
|
164
|
+
// TODO support arrays in arrays
|
|
165
|
+
default:
|
|
166
|
+
writer.write(`${JSONSchemaToTsType(items.type)}[]`)
|
|
167
|
+
}
|
|
168
|
+
} else if (type === 'object') {
|
|
169
|
+
writer.inlineBlock(() => {
|
|
170
|
+
const current = properties[name]
|
|
171
|
+
renderProperties(writer, addedProps, current.properties, current.additionalProperties, current.required)
|
|
172
|
+
})
|
|
173
|
+
} else {
|
|
174
|
+
writer.write(JSONSchemaToTsType(type))
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
writer.write(';')
|
|
179
|
+
writer.newLine()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (additionalProperties) {
|
|
183
|
+
writer.write('[name: string]: any;')
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function JSONSchemaToTsType (type) {
|
|
188
|
+
switch (type) {
|
|
189
|
+
case 'string':
|
|
190
|
+
return 'string'
|
|
191
|
+
case 'integer':
|
|
192
|
+
return 'number'
|
|
193
|
+
case 'number':
|
|
194
|
+
return 'number'
|
|
195
|
+
/* istanbul ignore next */
|
|
196
|
+
case 'boolean':
|
|
197
|
+
return 'boolean'
|
|
198
|
+
// TODO what other types should we support here?
|
|
199
|
+
/* istanbul ignore next */
|
|
200
|
+
default:
|
|
201
|
+
return 'any'
|
|
202
|
+
}
|
|
102
203
|
}
|
|
103
204
|
|
|
104
|
-
module.exports = { mapSQLTypeToOpenAPIType, mapSQLEntityToJSONSchema }
|
|
205
|
+
module.exports = { mapSQLTypeToOpenAPIType, mapSQLEntityToJSONSchema, mapOpenAPItoTypes }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformatic/sql-json-schema-mapper",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.2",
|
|
4
4
|
"description": "Map SQL entity to JSON schema",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -18,7 +18,12 @@
|
|
|
18
18
|
"snazzy": "^9.0.0",
|
|
19
19
|
"standard": "^17.0.0",
|
|
20
20
|
"tap": "^16.3.4",
|
|
21
|
-
"@platformatic/sql-mapper": "0.19.
|
|
21
|
+
"@platformatic/sql-mapper": "0.19.2"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"code-block-writer": "^12.0.0",
|
|
25
|
+
"dtsgenerator": "^3.18.0",
|
|
26
|
+
"safe-identifier": "^0.4.2"
|
|
22
27
|
},
|
|
23
28
|
"scripts": {
|
|
24
29
|
"lint": "standard | snazzy",
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { test } = require('tap')
|
|
4
|
+
const dtsgenerator = require('dtsgenerator')
|
|
5
|
+
const { mapOpenAPItoTypes } = require('..')
|
|
6
|
+
|
|
7
|
+
let structuredClone = globalThis.structuredClone
|
|
8
|
+
if (structuredClone === undefined) {
|
|
9
|
+
structuredClone = (obj) => JSON.parse(JSON.stringify(obj))
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function referenceTest (name, obj, opts = {}) {
|
|
13
|
+
const { only } = opts
|
|
14
|
+
test(name, { only }, async t => {
|
|
15
|
+
const reference = await dtsgenerator.default({ contents: [dtsgenerator.parseSchema(structuredClone(obj))] })
|
|
16
|
+
const cloned = structuredClone(obj)
|
|
17
|
+
const ours = mapOpenAPItoTypes(cloned)
|
|
18
|
+
t.not(cloned, obj)
|
|
19
|
+
t.same(cloned, obj)
|
|
20
|
+
t.same(ours.trim(), reference.trim())
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
referenceTest('p1', {
|
|
25
|
+
id: 'Page',
|
|
26
|
+
title: 'Page',
|
|
27
|
+
description: 'A Page',
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
id: {
|
|
31
|
+
type: 'integer'
|
|
32
|
+
},
|
|
33
|
+
title: {
|
|
34
|
+
type: 'string'
|
|
35
|
+
},
|
|
36
|
+
metadata: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
additionalProperties: true,
|
|
39
|
+
nullable: true
|
|
40
|
+
},
|
|
41
|
+
section: {
|
|
42
|
+
type: 'number',
|
|
43
|
+
nullable: true
|
|
44
|
+
},
|
|
45
|
+
description: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
nullable: true
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
required: [
|
|
51
|
+
'title'
|
|
52
|
+
]
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
referenceTest('p2', {
|
|
56
|
+
id: 'Page',
|
|
57
|
+
title: 'Page',
|
|
58
|
+
description: 'A Page',
|
|
59
|
+
type: 'object',
|
|
60
|
+
properties: {
|
|
61
|
+
id: {
|
|
62
|
+
type: 'integer'
|
|
63
|
+
},
|
|
64
|
+
metadata: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
additionalProperties: true,
|
|
67
|
+
nullable: true
|
|
68
|
+
},
|
|
69
|
+
section: {
|
|
70
|
+
type: 'number',
|
|
71
|
+
nullable: true
|
|
72
|
+
},
|
|
73
|
+
description: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
nullable: true
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
required: []
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
referenceTest('p3', {
|
|
82
|
+
id: 'GeneratedTest',
|
|
83
|
+
title: 'GeneratedTest',
|
|
84
|
+
description: 'A GeneratedTest',
|
|
85
|
+
type: 'object',
|
|
86
|
+
properties: {
|
|
87
|
+
id: {
|
|
88
|
+
type: 'integer'
|
|
89
|
+
},
|
|
90
|
+
test: {
|
|
91
|
+
type: 'integer',
|
|
92
|
+
nullable: true
|
|
93
|
+
},
|
|
94
|
+
testStored: {
|
|
95
|
+
type: 'integer',
|
|
96
|
+
nullable: true,
|
|
97
|
+
readOnly: true
|
|
98
|
+
},
|
|
99
|
+
testVirtual: {
|
|
100
|
+
type: 'integer',
|
|
101
|
+
nullable: true,
|
|
102
|
+
readOnly: true
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
required: []
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
referenceTest('multiple types', {
|
|
109
|
+
id: 'Page',
|
|
110
|
+
title: 'Page',
|
|
111
|
+
description: 'A Page',
|
|
112
|
+
type: 'object',
|
|
113
|
+
properties: {
|
|
114
|
+
id: {
|
|
115
|
+
type: ['integer', 'string']
|
|
116
|
+
},
|
|
117
|
+
title: {
|
|
118
|
+
type: 'string'
|
|
119
|
+
},
|
|
120
|
+
metadata: {
|
|
121
|
+
type: 'object',
|
|
122
|
+
additionalProperties: true,
|
|
123
|
+
nullable: true
|
|
124
|
+
},
|
|
125
|
+
section: {
|
|
126
|
+
type: ['number', 'null']
|
|
127
|
+
},
|
|
128
|
+
description: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
nullable: true
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
required: [
|
|
134
|
+
'title'
|
|
135
|
+
]
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
referenceTest('arrays', {
|
|
139
|
+
id: 'Page',
|
|
140
|
+
title: 'Page',
|
|
141
|
+
description: 'A Page',
|
|
142
|
+
type: 'object',
|
|
143
|
+
properties: {
|
|
144
|
+
id: {
|
|
145
|
+
type: 'integer'
|
|
146
|
+
},
|
|
147
|
+
title: {
|
|
148
|
+
type: 'string'
|
|
149
|
+
},
|
|
150
|
+
tags: {
|
|
151
|
+
type: 'array',
|
|
152
|
+
items: {
|
|
153
|
+
type: 'string'
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
required: [
|
|
158
|
+
'title'
|
|
159
|
+
]
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
referenceTest('objects in arrays', {
|
|
163
|
+
id: 'Page',
|
|
164
|
+
title: 'Page',
|
|
165
|
+
description: 'A Page',
|
|
166
|
+
type: 'object',
|
|
167
|
+
properties: {
|
|
168
|
+
id: {
|
|
169
|
+
type: 'integer'
|
|
170
|
+
},
|
|
171
|
+
title: {
|
|
172
|
+
type: 'string'
|
|
173
|
+
},
|
|
174
|
+
tags: {
|
|
175
|
+
type: 'array',
|
|
176
|
+
items: {
|
|
177
|
+
type: 'object',
|
|
178
|
+
properties: {
|
|
179
|
+
foo: {
|
|
180
|
+
type: 'string'
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
required: [
|
|
187
|
+
'title'
|
|
188
|
+
]
|
|
189
|
+
})
|