Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Commit e653175

Browse files
committed
feat(core): valueOf can now support references
1 parent ac55c73 commit e653175

File tree

2 files changed

+138
-20
lines changed

2 files changed

+138
-20
lines changed

packages/minim-api-description/lib/define-value-of.js

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -98,61 +98,81 @@ module.exports = (namespace) => {
9898
const isEnumElement = e => (e.element === 'enum' || e instanceof EnumElement);
9999
const isPlural = e => (e instanceof ArrayElement) || (e instanceof ObjectElement);
100100

101-
function mapValue(e, options, f) {
101+
function mapValue(e, options, f, elements) {
102102
const opts = updateTypeAttributes(e, options);
103103
if (e.content && (!isPlural(e) || e.content.length > 0)) {
104-
const result = f(e, opts, 'content');
104+
const result = f(e, opts, elements, 'content');
105105
if (undefined !== result) {
106106
return result;
107107
}
108108
}
109109
const sample = findFirstSample(e);
110110
if (sample) {
111-
const result = f(sample, opts, 'sample');
111+
const result = f(sample, opts, elements, 'sample');
112112
if (undefined !== result) {
113113
return result;
114114
}
115115
}
116116
const dflt = findDefault(e);
117117
if (dflt) {
118-
const result = f(dflt, opts, 'default');
118+
const result = f(dflt, opts, elements, 'default');
119119
if (undefined !== result) {
120120
return result;
121121
}
122122
}
123123
if (isFlag(NULLABLE_FLAG, opts)) {
124-
const result = f(new NullElement(), opts, 'nullable');
124+
const result = f(new NullElement(), opts, elements, 'nullable');
125125
if (undefined !== result) {
126126
return result;
127127
}
128128
}
129+
130+
if (elements) {
131+
if (e.element === 'ref') {
132+
const result = elements.filter(el => el.id.equals(e.content))[0];
133+
const inheritedElements = elements.filter(el => !el.id.equals(e.content));
134+
135+
if (e.path && e.path.toValue() === 'content') {
136+
return mapValue(result.content, opts, f, inheritedElements);
137+
}
138+
139+
return mapValue(result, opts, f, inheritedElements);
140+
}
141+
142+
const result = elements.filter(el => el.id.equals(e.element))[0];
143+
if (result) {
144+
const inheritedElements = elements.filter(el => !el.id.equals(e.element));
145+
return mapValue(result, opts, f, inheritedElements);
146+
}
147+
}
148+
129149
if (isEnumElement(e)) {
130150
const enums = e.enumerations;
131151
if (enums && enums.content && enums.content[0]) {
132-
const result = f(enums.content[0], opts, 'generated');
152+
const result = f(enums.content[0], opts, elements, 'generated');
133153
if (undefined !== result) {
134154
return result;
135155
}
136156
}
137157
}
138158
const trivial = trivialValue(e);
139159
if (trivial) {
140-
const result = f(trivial, opts, 'generated');
160+
const result = f(trivial, opts, elements, 'generated');
141161
if (undefined !== result) {
142162
return result;
143163
}
144164
}
145165
if (isPlural(e) && e.content.length === 0) {
146-
return f(e, opts, 'generated');
166+
return f(e, opts, elements, 'generated');
147167
}
148168

149169
return undefined;
150170
}
151171

152-
function reduceValue(e, options) {
172+
function reduceValue(e, options, elements) {
153173
const opts = updateTypeAttributes(e, options);
154174
if (undefined === e.content) {
155-
return mapValue(e, opts, e => e.content);
175+
return mapValue(e, opts, e => e.content, elements);
156176
}
157177
if (isPrimitive(e)) {
158178
return e.content;
@@ -161,7 +181,7 @@ module.exports = (namespace) => {
161181
return null;
162182
}
163183
if (isEnumElement(e)) {
164-
return mapValue(e.content, inheritFlags(opts), reduceValue);
184+
return mapValue(e.content, inheritFlags(opts), reduceValue, elements);
165185
}
166186
if (e instanceof ObjectElement) {
167187
let result = {};
@@ -171,7 +191,7 @@ module.exports = (namespace) => {
171191
&& !isFlag(FIXED_TYPE_FLAG, opts)
172192
&& !hasTypeAttribute(item, 'required'));
173193

174-
const k = mapValue(item.key, inheritFlags(opts), reduceValue);
194+
const k = mapValue(item.key, inheritFlags(opts), reduceValue, elements);
175195

176196
if (undefined === k) {
177197
if (skippable) {
@@ -181,7 +201,7 @@ module.exports = (namespace) => {
181201
return true;
182202
}
183203

184-
const v = mapValue(item.value, inheritFlags(opts), reduceValue);
204+
const v = mapValue(item.value, inheritFlags(opts), reduceValue, elements);
185205
if (undefined === v) {
186206
if (skippable) {
187207
return false;
@@ -196,7 +216,7 @@ module.exports = (namespace) => {
196216
return result;
197217
}
198218
if (e instanceof ArrayElement) {
199-
const result = e.map(item => mapValue(item, inheritFlags(opts), reduceValue));
219+
const result = e.map(item => mapValue(item, inheritFlags(opts), reduceValue, elements));
200220
if (!isFlag(FIXED_FLAG, opts) && !isFlag(FIXED_TYPE_FLAG, opts)) {
201221
return result.filter(item => item !== undefined);
202222
}
@@ -210,17 +230,17 @@ module.exports = (namespace) => {
210230

211231
if (!Object.getOwnPropertyNames(Element.prototype).includes('valueOf')) {
212232
Object.defineProperty(Element.prototype, 'valueOf', {
213-
value(flags) {
233+
value(flags, elements) {
214234
if (flags !== undefined && flags.source) {
215-
return mapValue(this, 0, (value, opts, source) => {
216-
const result = reduceValue(value, opts);
235+
return mapValue(this, 0, (value, opts, elements, source) => {
236+
const result = reduceValue(value, opts, elements);
217237
if (undefined === result) {
218238
return undefined;
219239
}
220-
return [reduceValue(value, opts), source];
221-
});
240+
return [reduceValue(value, opts, elements), source];
241+
}, elements);
222242
}
223-
return mapValue(this, 0, (value, opts) => reduceValue(value, opts));
243+
return mapValue(this, 0, (value, opts) => reduceValue(value, opts, elements), elements);
224244
},
225245
});
226246
}

packages/minim-api-description/test/value-of-test.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const apiDescription = require('../lib/api-description');
44

55
const namespace = minim.namespace().use(apiDescription);
66

7+
const { Element } = namespace;
78
const ArrayElement = namespace.elements.Array;
89
const ObjectElement = namespace.elements.Object;
910
const BooleanElement = namespace.elements.Boolean;
@@ -1106,3 +1107,100 @@ describe('valueOf ObjectElement with source', () => {
11061107
expect(value).to.deep.equal([null, 'nullable']);
11071108
});
11081109
});
1110+
1111+
1112+
describe('valueOf RefElement', () => {
1113+
it('returns value from referenced element', () => {
1114+
const name = new StringElement('doe');
1115+
name.id = 'name';
1116+
1117+
const element = name.toRef('element');
1118+
const value = element.valueOf(undefined, [name]);
1119+
1120+
expect(value).to.equal('doe');
1121+
});
1122+
1123+
it('returns value from referenced elements content', () => {
1124+
const name = new StringElement('doe');
1125+
const container = new Element(name);
1126+
container.id = 'name';
1127+
1128+
const element = container.toRef('content');
1129+
const value = element.valueOf(undefined, [container]);
1130+
1131+
expect(value).to.equal('doe');
1132+
});
1133+
1134+
it('returns value from referenced element recursively', () => {
1135+
const name = new StringElement('doe');
1136+
name.id = 'name';
1137+
1138+
const names = new ArrayElement([name.toRef()]);
1139+
1140+
const value = names.valueOf(undefined, [name]);
1141+
1142+
expect(value).to.deep.equal(['doe']);
1143+
});
1144+
});
1145+
1146+
describe('valueOf RefElement with source', () => {
1147+
it('returns value from referenced element', () => {
1148+
const name = new StringElement('doe');
1149+
name.id = 'name';
1150+
1151+
const element = name.toRef('element');
1152+
const value = element.valueOf({ source: true }, [name]);
1153+
1154+
expect(value).to.deep.equal(['doe', 'content']);
1155+
});
1156+
1157+
it('returns value from referenced elements content', () => {
1158+
const name = new StringElement('doe');
1159+
const container = new Element(name);
1160+
container.id = 'name';
1161+
1162+
const element = container.toRef('content');
1163+
const value = element.valueOf({ source: true }, [container]);
1164+
1165+
expect(value).to.deep.equal(['doe', 'content']);
1166+
});
1167+
1168+
it('returns value from referenced element recursively', () => {
1169+
const name = new StringElement('doe');
1170+
name.id = 'name';
1171+
1172+
const names = new ArrayElement([name.toRef()]);
1173+
1174+
const value = names.valueOf({ source: true }, [name]);
1175+
1176+
expect(value).to.deep.equal([['doe'], 'content']);
1177+
});
1178+
});
1179+
1180+
describe('valueOf referenced element', () => {
1181+
it('returns value from dereferenced element', () => {
1182+
const name = new StringElement('doe');
1183+
name.id = 'name';
1184+
1185+
const element = new Element();
1186+
element.element = 'name';
1187+
1188+
const value = element.valueOf(undefined, [name]);
1189+
1190+
expect(value).to.equal('doe');
1191+
});
1192+
});
1193+
1194+
describe('valueOf referenced element with source', () => {
1195+
it('returns value from dereferenced element', () => {
1196+
const name = new StringElement('doe');
1197+
name.id = 'name';
1198+
1199+
const element = new Element();
1200+
element.element = 'name';
1201+
1202+
const value = element.valueOf({ source: true }, [name]);
1203+
1204+
expect(value).to.deep.equal(['doe', 'content']);
1205+
});
1206+
});

0 commit comments

Comments
 (0)