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

Commit

Permalink
fix(core): inherit fixed attribute in valueOf (#564)
Browse files Browse the repository at this point in the history
  • Loading branch information
patricksmms committed Sep 23, 2020
1 parent 9d2ab4e commit fdb70bf
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 33 deletions.
6 changes: 5 additions & 1 deletion packages/api-elements/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# API Elements (JavaScript) CHANGELOG

## 0.3.2 (2020-09-15)
## 0.3.2 (2020-09-23)

### Bug Fixes

- Inherit fixed attribute in `valueOf`

### Enhancements

Expand Down
61 changes: 34 additions & 27 deletions packages/api-elements/lib/define-value-of.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const {
} = require('minim');
const {
isFixed,
isFixedType,
isRequired,
isNullable,
isOptional,
Expand All @@ -27,17 +28,20 @@ const {
/**
* Map the element values
* @param {element} e - element
* @param {boolean} inheritFixed - inherited fixed attribute
* @param {function} f - map function
* @param {object=} elements - object map of elements to look for inherited types
* @return {any}
*/
function mapValue(e, f, elements) {
function mapValue(e, f, inheritFixed, elements) {
if (e === undefined) {
return undefined;
}

const isElementFixed = inheritFixed || isFixed(e);

if (e.content && !isEmptyArray(e, elements) && !isObjectWithUndefinedValues(e, elements)) {
const result = f(e, elements, 'content');
const result = f(e, isElementFixed, elements, 'content');

if (result !== undefined) {
return result;
Expand All @@ -46,31 +50,31 @@ function mapValue(e, f, elements) {

const sample = getFirstSample(e);
if (sample) {
const result = f(sample, elements, 'sample');
const result = f(sample, isElementFixed, elements, 'sample');
if (result !== undefined) {
return result;
}
}

const dflt = getDefault(e);
if (dflt) {
const result = f(dflt, elements, 'default');
const result = f(dflt, isElementFixed, elements, 'default');
if (result !== undefined) {
return result;
}
}

// reconsider content for array and object element (prefer sample/default first)
if (isNonEmptyArray(e, elements) && isObject(e, elements)) {
const result = f(e, elements, 'content');
const result = f(e, isElementFixed, elements, 'content');

if (result !== undefined) {
return result;
}
}

if (isNullable(e)) {
const result = f(new NullElement(), elements, 'nullable');
const result = f(new NullElement(), isElementFixed, elements, 'nullable');
if (result !== undefined) {
return result;
}
Expand All @@ -82,24 +86,24 @@ function mapValue(e, f, elements) {
const inheritedElements = R.filter(el => !el.id.equals(e.content), elements);

if (e.path && e.path.toValue() === 'content') {
return mapValue(result.content, f, inheritedElements);
return mapValue(result.content, f, isElementFixed, inheritedElements);
}

return mapValue(result, f, inheritedElements);
return mapValue(result, f, isElementFixed, inheritedElements);
}

const result = elements[e.element];
if (result !== undefined) {
const inheritedElements = R.filter(el => !el.id.equals(e.element), elements);
return mapValue(result, f, inheritedElements);
return mapValue(result, f, isElementFixed, inheritedElements);
}
}

if (isEnum(e, elements)) {
const content = getStructureMembers(e, elements);

if (content && content[0]) {
const result = f(content[0], elements, 'generated');
const result = f(content[0], isElementFixed, elements, 'generated');
if (result !== undefined) {
return result;
}
Expand All @@ -108,14 +112,14 @@ function mapValue(e, f, elements) {

const trivial = trivialValue(e);
if (trivial) {
const result = f(trivial, elements, 'generated');
const result = f(trivial, isElementFixed, elements, 'generated');
if (result !== undefined) {
return result;
}
}

if ((isArray(e, elements) && e.isEmpty) || isObject(e, elements)) {
return f(e, elements, 'generated');
return f(e, isElementFixed, elements, 'generated');
}

return undefined;
Expand All @@ -124,12 +128,13 @@ function mapValue(e, f, elements) {
/**
* Reduce the element value
* @param {element} e - element
* @param {boolean} inheritFixed - inherited fixed attribute
* @param {object=} elements - object map of elements to look for inherited types
* @return {any}
*/
function reduceValue(e, elements) {
function reduceValue(e, inheritFixed, elements) {
if (e.content === undefined) {
return mapValue(e, e => e.content, elements);
return mapValue(e, e => e.content, inheritFixed, elements);
}

if (isPrimitive(e, elements)) {
Expand All @@ -141,20 +146,19 @@ function reduceValue(e, elements) {
}

if (isEnum(e, elements)) {
return mapValue(e.content, reduceValue, elements);
return mapValue(e.content, reduceValue, inheritFixed, elements);
}

if (isObject(e, elements)) {
let result = {};

const isFixedElement = isFixed(e);

const content = getStructureMembers(e, elements);
const isElementFixedType = isFixedType(e);

content.some((item) => {
const isSkippable = isOptional(item) || (!isFixedElement && !isRequired(item));
const isSkippable = isOptional(item) || (!inheritFixed && !isElementFixedType && !isRequired(item));

const key = mapValue(item.key, reduceValue, elements);
const key = mapValue(item.key, reduceValue, inheritFixed, elements);
if (key === undefined) {
if (isSkippable) {
return false;
Expand All @@ -164,7 +168,7 @@ function reduceValue(e, elements) {
return true;
}

const value = mapValue(item.value, reduceValue, elements);
const value = mapValue(item.value, reduceValue, inheritFixed, elements);
if (value === undefined) {
if (isSkippable) {
return false;
Expand All @@ -183,9 +187,9 @@ function reduceValue(e, elements) {

if (isArray(e, elements)) {
const content = getStructureMembers(e, elements);
const result = content.map(item => mapValue(item, reduceValue, elements));
const result = content.map(item => mapValue(item, reduceValue, inheritFixed, elements));

if (!isFixed(e)) {
if (!inheritFixed && !isFixedType(e)) {
return result.filter(item => item !== undefined);
}

Expand All @@ -207,15 +211,18 @@ module.exports = () => {
Object.defineProperty(Element.prototype, 'valueOf', {
value(flags, elements) {
if (flags && flags.source) {
return mapValue(this, (value, elements, source) => {
const result = reduceValue(value, elements);
return mapValue(this, (value, attrs, elements, source) => {
const result = reduceValue(value, attrs, elements);

if (result === undefined) {
return undefined;
}
return [reduceValue(value, elements), source];
}, elements);

return [result, source];
}, false, elements);
}
return mapValue(this, value => reduceValue(value, elements), elements);

return mapValue(this, reduceValue, false, elements);
},
});
};
12 changes: 10 additions & 2 deletions packages/api-elements/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,18 @@ function hasTypeAttribute(e, attribute) {
}

/**
* Check if element has 'fixed' or 'fixedType' typeAttribute set
* Check if element has 'fixed' typeAttribute set
* @param {element} e - element
* @return {boolean}
*/
const isFixed = e => hasTypeAttribute(e, 'fixed') || hasTypeAttribute(e, 'fixedType');
const isFixed = e => hasTypeAttribute(e, 'fixed');

/**
* Check if element has 'fixedType' typeAttribute set
* @param {element} e - element
* @return {boolean}
*/
const isFixedType = e => hasTypeAttribute(e, 'fixedType');

/**
* Check if element has 'required' typeAttribute set
Expand Down Expand Up @@ -358,6 +365,7 @@ function getStructureMembers(e, elements) {

module.exports = {
isFixed,
isFixedType,
isRequired,
isNullable,
isOptional,
Expand Down
16 changes: 13 additions & 3 deletions packages/api-elements/test/utils-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { expect } = require('chai');
const {
isFixed,
isFixedType,
isRequired,
isNullable,
isOptional,
Expand Down Expand Up @@ -42,19 +43,28 @@ describe('isFixed', () => {
expect(value).to.be.true;
});

it('returns `false` if the element typeAttributes do not contain`fixed`', () => {
const element = new Element();
const value = isFixed(element);

expect(value).to.be.false;
});
});

describe('isFixedType', () => {
it('returns `true` if the element typeAttributes contain `fixedType`', () => {
const element = new Element();
element.attributes.set('typeAttributes', new ArrayElement([
new StringElement('fixedType'),
]));
const value = isFixed(element);
const value = isFixedType(element);

expect(value).to.be.true;
});

it('returns `false` if the element typeAttributes do not contain`fixed` or `fixedType`', () => {
it('returns `false` if the element typeAttributes do not contain `fixedType`', () => {
const element = new Element();
const value = isFixed(element);
const value = isFixedType(element);

expect(value).to.be.false;
});
Expand Down
Loading

0 comments on commit fdb70bf

Please sign in to comment.