Skip to content

Commit 0deb371

Browse files
committed
feat(project): instantiate method for Boolean, String, Number, Null
1 parent 0b037f0 commit 0deb371

File tree

3 files changed

+186
-0
lines changed

3 files changed

+186
-0
lines changed

packages/minim-api-description/lib/api-description.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ const copy = require('./elements/copy');
3434
const category = require('./elements/category');
3535
const extension = require('./elements/extension');
3636
const enumeration = require('./elements/enum');
37+
const defineInstantiate = require('./define-instantiate');
3738

3839
const namespace = (options) => {
40+
defineInstantiate(options.base);
3941
httpHeaders(options.base);
4042
hrefVariables(options.base);
4143
asset(options.base);
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/* eslint-disable no-bitwise, no-underscore-dangle */
2+
3+
const setFlag = (mask, options) => (options | mask);
4+
const isFlag = (mask, options) => (options & mask) !== 0;
5+
6+
const FIXED_FLAG = 1 << 0;
7+
const NULLABLE_FLAG = 1 << 1;
8+
9+
function findDefault(e) {
10+
if (undefined !== e._attributes) {
11+
const result = e.attributes.get('default');
12+
if (undefined !== result) {
13+
return result;
14+
}
15+
}
16+
return null;
17+
}
18+
19+
function hasTypeAttribute(e, attribute) {
20+
if (undefined !== e._attributes) {
21+
const attrs = e.attributes.get('typeAttributes');
22+
if (undefined !== attrs && undefined !== attrs.content) {
23+
return undefined !== attrs.content.find(attr => attr.content === attribute);
24+
}
25+
}
26+
return false;
27+
}
28+
29+
const hasFixedTypeAttribute = e => hasTypeAttribute(e, 'fixed');
30+
const hasNullableTypeAttribute = e => hasTypeAttribute(e, 'nullable');
31+
32+
function updateTypeAttributes(e, options) {
33+
let result = options;
34+
if (hasFixedTypeAttribute(e)) {
35+
result = setFlag(FIXED_FLAG, result);
36+
}
37+
if (hasNullableTypeAttribute(e)) {
38+
result = setFlag(NULLABLE_FLAG, result);
39+
}
40+
return result;
41+
}
42+
43+
module.exports = (namespace) => {
44+
const { Element } = namespace.elements;
45+
const {
46+
Array: ArrayElement,
47+
String: StringElement,
48+
Boolean: BooleanElement,
49+
Number: NumberElement,
50+
Null: NullElement,
51+
} = namespace.elements;
52+
53+
function findFirstSample(e) {
54+
if (undefined !== e._attributes) {
55+
const samples = e.attributes.get('samples');
56+
if (samples instanceof ArrayElement) {
57+
if (undefined !== samples.content && samples.content.length > 0) {
58+
return samples.content[0];
59+
}
60+
}
61+
}
62+
return null;
63+
}
64+
65+
const isPrimitive = e => (e instanceof StringElement) || (e instanceof NumberElement) || (e instanceof BooleanElement);
66+
67+
// Generate default value for leaf elements (Boolean, String, Number, Null)
68+
function generateValue(e) {
69+
if (e instanceof BooleanElement) {
70+
return false;
71+
}
72+
if (e instanceof NumberElement) {
73+
return 0;
74+
}
75+
if (e instanceof StringElement) {
76+
return '';
77+
}
78+
if (e instanceof NullElement) {
79+
return null;
80+
}
81+
return undefined;
82+
}
83+
84+
// Create instance of leaf element (Boolean, String, Number, Null)
85+
function instantiateLeaf(e, options) {
86+
const opts = updateTypeAttributes(e, options);
87+
if (e.content) {
88+
return [e.content, 'content'];
89+
}
90+
const sample = findFirstSample(e);
91+
if (sample) {
92+
return [sample.content, 'sample'];
93+
}
94+
const dflt = findDefault(e);
95+
if (dflt) {
96+
return [dflt.content, 'default'];
97+
}
98+
if (isFlag(NULLABLE_FLAG, opts)) {
99+
return [null, 'content'];
100+
}
101+
102+
return [generateValue(e), 'generated'];
103+
}
104+
105+
function instantiate(e, options) {
106+
if (isPrimitive(e) === true) {
107+
return instantiateLeaf(e, options);
108+
}
109+
if (e instanceof NullElement) {
110+
return instantiateLeaf(e, options);
111+
}
112+
return undefined;
113+
}
114+
115+
if (!Object.getOwnPropertyNames(Element.prototype).includes('instantiate')) {
116+
Object.defineProperty(Element.prototype, 'instantiate', {
117+
value() { return instantiate(this, 0); },
118+
});
119+
}
120+
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
const { expect } = require('chai');
2+
const minim = require('minim');
3+
const apiDescription = require('../lib/api-description');
4+
5+
const namespace = minim.namespace().use(apiDescription);
6+
7+
const StringElement = namespace.elements.String;
8+
const ArrayElement = namespace.elements.Array;
9+
10+
describe('instantiate StringElement', () => {
11+
it('returns content', () => {
12+
const element = new StringElement('hello');
13+
const value = element.instantiate();
14+
15+
expect(value).to.deep.equal(['hello', 'content']);
16+
});
17+
18+
it('prefers content over default and samples', () => {
19+
const element = new StringElement('hello');
20+
element.attributes.set('default', new StringElement('moin'));
21+
element.attributes.set('samples', new ArrayElement(
22+
new StringElement('zdravicko')
23+
));
24+
const value = element.instantiate();
25+
26+
expect(value).to.deep.equal(['hello', 'content']);
27+
});
28+
29+
it('prefers a sample over a default', () => {
30+
const element = new StringElement();
31+
element.attributes.set('default', new StringElement('moin'));
32+
element.attributes.set('samples', new ArrayElement([
33+
new StringElement('zdravicko'),
34+
]));
35+
const value = element.instantiate();
36+
37+
expect(value).to.deep.equal(['zdravicko', 'sample']);
38+
});
39+
40+
it('prefers default over generating a value', () => {
41+
const element = new StringElement();
42+
element.attributes.set('default', new StringElement('moin'));
43+
const value = element.instantiate();
44+
45+
expect(value).to.deep.equal(['moin', 'default']);
46+
});
47+
48+
it('generates an empty string if no content, default, samples and not nullable', () => {
49+
const element = new StringElement();
50+
const value = element.instantiate();
51+
52+
expect(value).to.deep.equal(['', 'generated']);
53+
});
54+
55+
it('generates null if no content, default, samples and nullable', () => {
56+
const element = new StringElement();
57+
element.attributes.set('typeAttributes', new ArrayElement([
58+
new StringElement('nullable'),
59+
]));
60+
const value = element.instantiate();
61+
62+
expect(value).to.deep.equal([null, 'content']);
63+
});
64+
});

0 commit comments

Comments
 (0)