-
Notifications
You must be signed in to change notification settings - Fork 10
/
index_.coffee
207 lines (162 loc) · 5.8 KB
/
index_.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
random = require 'otw/like/_/random'
type = require 'otw/like/_/type'
randexp = do () ->
_randexp = require 'randexp'
(pattern) -> new _randexp(pattern).gen()
module.exports = exports = (schema, options = {}) ->
options.root_schema = schema
generator = new exports.Generator options
return generator.generate()
class exports.Generator
constructor: (options) ->
@options = options
generate: (schema = null, depth = 0) ->
schema = @options.root_schema unless schema
return schema unless type(schema) is 'object'
return @enum schema, depth if schema.enum
if schema.$ref
return @ref schema.$ref, depth
switch schema.type
when 'string', 'number', 'integer', 'boolean', 'array', 'object', 'null'
return @[schema.type] schema, depth
else
if type(schema.type) is 'array'
return @oneOf schema, depth
# FIXME what if type(schema.type) = 'object' and _.size(schema.type) > 0 ?
if schema.type is 'any' or type(schema.type) is 'undefined' or (type(schema.type) is 'object' and _.size(schema.type) is 0)
return @any schema, depth
# FIXME what type is this?
console.log schema.type
throw "what type is this ?"
# enum
'enum': (schema, depth = 0) ->
randomOptions =
minimum: 0
maximum: schema.enum.length - 1
randomIndex = @random 'integer', randomOptions
enumValue = schema.enum[randomIndex]
@generate enumValue, depth + 1
# type = null
'null': () ->
null
# type = boolean
boolean: (schema, depth = 0) ->
@random 'boolean'
# type = number / integer
number: (schema, depth = 0) ->
@integer schema, depth
integer: (schema, depth = 0) ->
minimum = schema.exclusiveMinimum + 1 if schema.exclusiveMinimum
minimum ?= schema.minimum
maximum = schema.exclusiveMaximum - 1 if schema.exclusiveMaximum
maximum ?= schema.maximum
decimals = 0
decimals = @random 'number', {minimum: 0, maximum: 3} if schema.type is 'number'
randomOptions =
minimum: minimum
maximum: maximum
divisibleBy: schema.divisibleBy
decimals: decimals
@random 'number', randomOptions
# type = string
string: (schema, depth = 0) ->
return randexp schema.pattern if schema.pattern
# FIXME format should not be ignored
randomOptions =
minLength: schema.minLength
maxLength: schema.maxLength
@random 'string', randomOptions
# type = array
array: (schema, depth = 0) ->
o = []
if type(schema.items) is 'object' and schema.items.$ref
result = @ref schema.items.$ref, depth
return [result]
if type(schema.items) is 'array' and schema.items.length
for itemSchema in schema.items
o.push @generate itemSchema, depth + 1
if schema.additionalItems
if type(schema.minItems) isnt 'undefined'
minimum = schema.minItems - o.length
else
minimum = 1
minimum = 1 if minimum < 0
# minimum set to 1, not 0, on purpose
if type(schema.maxItems) isnt 'undefined'
maximum = schema.maxItems - o.length
else
maximum = o.length + @random 'integer', {minimum: 0, maximum: 2}
randomOptions =
minimum: minimum
maximum: maximum
howManyMoreItems = @random 'integer', randomOptions
while howManyMoreItems
howManyMoreItemsLeft = howManyMoreItems - o.length
if howManyMoreItemsLeft
for i in [1..howManyMoreItemsLeft]
o.push @generate schema.additionalItems, depth + 1
o = _.deepUnique o if schema.uniqueItems
howManyMoreItemsLeft = howManyMoreItems - o.length
break unless howManyMoreItemsLeft
o
# type = object
object: (schema, depth = 0) ->
if schema.oneOf
oneof_schema = type: schema.oneOf
return @oneOf oneof_schema, depth
o = {}
for key, prop of schema.properties
continue unless @options.method is 'all' or (type(schema.required) is 'array' and key in schema.required)
# FIXME
# continue if random 'boolean'
o[key] = @generate prop, depth + 1
if type(schema.additionalProperties) is 'object'
# break if schema.additionalProperties.$ref?[0] is '#'
randomOptions =
minimum: 1
maximum: 3
# minimum set to 1, not 0, on purpose
howManyMoreProperties = @random 'integer', randomOptions
for i in [0..howManyMoreProperties]
o[@random 'string', {minimum: 0, maximum: 10}] = @generate schema.additionalProperties, depth+1
else if @options.additional and schema.additionalProperties isnt false
o[@random 'string', {minimum: 0, maximum: 10}] = @generate {type: 'any'}, depth+1
if @options.schemaid and schema.id
o.$schema = schema.id
return o
# type = any
any: (schema, depth = 0) ->
types = ['string', 'number', 'integer', 'boolean', 'object', 'null']
randomOptions =
minimum: 0
maximum: types.length-1
typeIndex = @random 'integer', randomOptions
@generate {type: types[typeIndex]}, depth + 1
# type = []
oneOf: (schema, depth = 0) ->
return 0 unless schema.type.length # treat as 'any'
randomOptions =
minimum: 0
maximum: schema.type.length-1
typeIndex = @random 'integer', randomOptions
@generate schema.type[typeIndex], depth + 1
ref: (ref, depth = 0) ->
path = ref.split('/')
if path[0] != '#'
throw "ref does not start with #: " + ref
schema = @options.root_schema
for name in path.slice(1)
schema = schema[name]
if not schema
throw "$ref traversal failed: " + ref
return @generate schema, depth
random: (type, options) ->
if @options.random
return random.apply random, arguments
switch type
when 'number', 'integer', 'int'
0
when 'boolean', 'bool'
false
when 'string'
""