Skip to content

Commit 708fe8a

Browse files
committed
Implements optional fields
1 parent 623b847 commit 708fe8a

File tree

7 files changed

+93
-24
lines changed

7 files changed

+93
-24
lines changed

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,15 @@ const sp = require('@json-spec/spec-profiles');
5252
const sb = require('@json-spec/spec-basic');
5353

5454
const person = s.object({
55-
firstName: sp.name({ size: 100 }),
56-
lastName: sp.name({ size: 100 }),
57-
birthDay: sp.birthDay,
58-
postalCd: sp.postalCode_JP,
59-
languages: s.array([
60-
"C", "C++", "Java"
61-
])
55+
required: {
56+
firstName: sp.name({ size: 100 }),
57+
lastName: sp.name({ size: 100 }),
58+
birthDay: sp.birthDay,
59+
postalCd: sp.postalCode_JP,
60+
languages: s.array([
61+
"C", "C++", "Java"
62+
])
63+
}
6264
});
6365

6466
gen.sample(s.gen(person))

examples/tutorial/src/tut1.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ const sb = require('@json-spec/spec-basic');
77
Specification of a person object.
88
*/
99
const person = s.object({
10-
firstName: sp.name({ size: 100 }),
11-
lastName: sp.name({ size: 100 }),
12-
birthDay: sp.birthDay,
13-
postalCd: sp.postalCode_JP,
14-
languages: s.array([
15-
"C", "C++", "Java"
16-
], { distinct: true, maxCount: 3 })
10+
required: {
11+
firstName: sp.firstName({ size: 100, locale:"ja"}),
12+
lastName: sp.lastName({ size: 100, locale: "ja" }),
13+
languages: s.array([
14+
"C", "C++", "Java"
15+
], { distinct: true, maxCount: 3 })
16+
},
17+
optional: {
18+
birthDay: sp.birthDay,
19+
postalCd: sp.postalCode_JP
20+
}
1721
});
1822

1923
console.log(gen.sample(s.gen(person)));

lib/core/src/base.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,15 +231,18 @@ class ObjectSpec extends Spec {
231231

232232
gen(overrides, path, rmap) {
233233
if (this.gfn) return this.gfn();
234-
const generators = {};
234+
const requiredGenerators = {};
235235
for (const k in this.required) {
236-
generators[k] = gensub(this.required[k], overrides, [...path, k], rmap, this.required[k]);
236+
requiredGenerators[k] = gensub(
237+
this.required[k], overrides, [...path, k], rmap, this.required[k]);
237238
}
238-
// TODO optional keys
239-
for (const k in this.optional) {
240239

240+
const optionalGenerators = {};
241+
for (const k in this.optional) {
242+
optionalGenerators[k] = gensub(
243+
this.optional[k], overrides, [...path, k], rmap, this.optional[k]);
241244
}
242-
return g.genObject(generators);
245+
return g.genObject(requiredGenerators, optionalGenerators);
243246
}
244247

245248
explain(path, via, in_, x) {

lib/openapi/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,11 @@ npm install @json-spec/openapi --save-developers
1111
example for Mock server
1212

1313
```
14-
json-spec-server --openapi=[openapi-specification] --jsonspec=[jsonspec-file]
14+
json-spec-server --openapi=[openapi-specification] --jsonspec=[jsonspec-file] --port=[listen-port]
15+
```
16+
17+
example for Mock client
18+
19+
```
20+
json-spec-client --openapi=[openapi-specification] --jsonspec=[jsonspec-file] --base-url=[base-url]
1521
```

lib/openapi/src/core.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@ const SwaggerParser = require('swagger-parser');
55
const parser = new SwaggerParser();
66
const sb = require('@json-spec/spec-basic');
77
const s = require('@json-spec/core');
8+
const gen = require('@json-spec/core/gen');
9+
const faker = require('faker')
10+
11+
function stringFormatToSpec(format, jsonSpecs) {
12+
switch(format) {
13+
case 'date':
14+
return s.spec(x => typeof(x) === 'string',
15+
{ gen: () => gen.fmap(d => d.getFullYear()
16+
+ '-' + ("0" + (d.getMonth() + 1)).slice(-2)
17+
+ '-' + ("0" + d.getDate()).slice(-2),
18+
(rnd, size) => faker.date.past()) });
19+
case 'date-time':
20+
return s.spec(x => typeof(x) === 'string',
21+
{ gen: () => gen.fmap(d => eval(JSON.stringify(d)),
22+
(rnd, size) => faker.date.past()) });
23+
case 'password':
24+
return s.spec(x => typeof(x) === 'string',
25+
{ gen: () => (rnd, size) => faker.internet.password() });
26+
default:
27+
return sb.string;
28+
}
29+
}
830

931
function schemaToSpec(schema, jsonSpecs) {
1032
if (schema['x-json-spec']) {
@@ -27,7 +49,7 @@ function schemaToSpec(schema, jsonSpecs) {
2749
case 'array':
2850
return s.array(schemaToSpec(schema.items, jsonSpecs));
2951
case 'string':
30-
return sb.string;
52+
return stringFormatToSpec(schema.format, jsonSpecs);
3153
case 'number':
3254
return sb.number;
3355
case 'integer':

lib/testcheck/src/generators.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,24 @@ const generators = {
163163
get largeInteger() { return largeInteger_({}) },
164164
}
165165

166-
function genObject(generators) {
166+
function genObject(requiredGenerators, optionalGenerators) {
167167
return (rnd, size) => {
168168
const obj = {};
169-
for (k in generators) {
170-
obj[k] = callGen(generators[k], rnd, size);
169+
for (k in requiredGenerators) {
170+
obj[k] = callGen(requiredGenerators[k], rnd, size);
171171
}
172+
173+
const optKeys = Object.keys(optionalGenerators);
174+
const ary = Array.from({length: optKeys.length}, (v, k) => k);
175+
for (let i = ary.length - 1; i >= 0; i--) {
176+
const j = callGen(choose(0, i), rnd, size);
177+
const tmp = ary[i]; ary[i] = ary[j]; ary[j] = tmp;
178+
}
179+
const cnt = callGen(choose(0, optKeys.length), rnd, size);
180+
ary.slice(cnt).forEach(i => {
181+
const k = optKeys[i];
182+
obj[k] = callGen(optionalGenerators[k], rnd, size);
183+
});
172184
return obj;
173185
};
174186
}

specs/profiles/src/index.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@ const name = ({size=100, locale='en'}) =>
2020
faker.locale = orig;
2121
return ret;
2222
}});
23+
const firstName = ({size=100, locale='en'}) =>
24+
spec(and(basic.string, x => 0 < x.length && x.length <= size),
25+
{gen: () => (rnd, size) => {
26+
const orig = faker.locale;
27+
faker.locale = locale;
28+
const ret = faker.name.firstName();
29+
faker.locale = orig;
30+
return ret;
31+
}});
32+
const lastName = ({size=100, locale='en'}) =>
33+
spec(and(basic.string, x => 0 < x.length && x.length <= size),
34+
{gen: () => (rnd, size) => {
35+
const orig = faker.locale;
36+
faker.locale = locale;
37+
const ret = faker.name.lastName();
38+
faker.locale = orig;
39+
return ret;
40+
}});
2341

2442
const account = ({size=100}) =>
2543
spec(and(basic.string, x => 0 < x.length && x.length <= size),
@@ -40,6 +58,8 @@ const birthDay = spec(and(basic.date, range.dateIn(new Date(1900, 1), new Date()
4058
gen(range.dateIn(new Date(1900, 1), new Date())))});
4159

4260
module.exports = {
61+
firstName,
62+
lastName,
4363
name,
4464
account,
4565
email,

0 commit comments

Comments
 (0)