api-elements
Advanced tools
Comparing version 0.3.1 to 0.3.2
# API Elements (JavaScript) CHANGELOG | ||
## 0.3.2 (2020-09-23) | ||
### Bug Fixes | ||
- Inherit fixed attribute in `valueOf` | ||
### Enhancements | ||
- Dereference elements in valueOf | ||
## 0.3.1 (2020-09-07) | ||
@@ -4,0 +14,0 @@ |
@@ -1,134 +0,47 @@ | ||
/* eslint-disable no-bitwise, no-underscore-dangle */ | ||
/* eslint-disable no-underscore-dangle */ | ||
const R = require('ramda'); | ||
const { | ||
Element, | ||
ArrayElement, | ||
ObjectElement, | ||
StringElement, | ||
BooleanElement, | ||
NumberElement, | ||
NullElement, | ||
} = require('minim'); | ||
const { | ||
isFixed, | ||
isFixedType, | ||
isRequired, | ||
isNullable, | ||
isOptional, | ||
isPrimitive, | ||
isEnum, | ||
isArray, | ||
isObject, | ||
getDefault, | ||
getFirstSample, | ||
isNonEmptyArray, | ||
isEmptyArray, | ||
isRef, | ||
isObjectWithUndefinedValues, | ||
trivialValue, | ||
getStructureMembers, | ||
} = require('./utils'); | ||
const EnumElement = require('./elements/Enum'); | ||
const setFlag = (mask, options) => (options | mask); | ||
const clearFlag = (mask, options) => (options & ~mask); | ||
const isFlag = (mask, options) => (options & mask) !== 0; | ||
const FIXED_FLAG = 1 << 0; | ||
const NULLABLE_FLAG = 1 << 1; | ||
const FIXED_TYPE_FLAG = 1 << 2; | ||
function findDefault(e) { | ||
if (undefined !== e._attributes) { | ||
const result = e.attributes.get('default'); | ||
if (undefined !== result) { | ||
return result; | ||
} | ||
} | ||
return null; | ||
} | ||
function hasTypeAttribute(e, attribute) { | ||
if (undefined !== e._attributes) { | ||
const typeAttributes = e.attributes.get('typeAttributes'); | ||
if (typeAttributes) { | ||
return typeAttributes.includes(attribute); | ||
} | ||
} | ||
return false; | ||
} | ||
const hasFixedTypeAttribute = e => hasTypeAttribute(e, 'fixed'); | ||
const hasFixedTypeTypeAttribute = e => hasTypeAttribute(e, 'fixedType'); | ||
const hasNullableTypeAttribute = e => hasTypeAttribute(e, 'nullable'); | ||
const hasOptionalTypeAttribute = e => hasTypeAttribute(e, 'optional'); | ||
function updateTypeAttributes(e, options) { | ||
let result = options; | ||
if (hasFixedTypeAttribute(e)) { | ||
result = setFlag(FIXED_FLAG, result); | ||
} | ||
if (hasFixedTypeTypeAttribute(e)) { | ||
result = setFlag(FIXED_TYPE_FLAG, result); | ||
} | ||
if (hasNullableTypeAttribute(e)) { | ||
result = setFlag(NULLABLE_FLAG, result); | ||
} | ||
return result; | ||
} | ||
function inheritFlags(options) { | ||
return clearFlag(clearFlag(FIXED_TYPE_FLAG | NULLABLE_FLAG, options)); | ||
} | ||
function findFirstSample(e) { | ||
if (undefined !== e._attributes) { | ||
const samples = e.attributes.get('samples'); | ||
if (samples instanceof ArrayElement) { | ||
if (undefined !== samples.content && samples.content.length > 0) { | ||
return samples.content[0]; | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
const isPrimitive = e => (e instanceof StringElement) || (e instanceof NumberElement) || (e instanceof BooleanElement); | ||
const isEnumElement = e => e instanceof EnumElement; | ||
const isArrayElement = e => e instanceof ArrayElement; | ||
const isObjectElement = e => e instanceof ObjectElement; | ||
const hasSample = e => findFirstSample(e) !== null; | ||
const hasDefault = e => findDefault(e) !== null; | ||
const hasContent = e => e.content !== undefined; | ||
const hasValue = R.anyPass([hasContent, hasSample, hasDefault]); | ||
const hasNoValue = R.complement(hasValue); | ||
const isNoValuePrimitive = R.both(isPrimitive, hasNoValue); | ||
const isNonEmptyArrayElement = e => isArrayElement(e) && e.content && !e.isEmpty; | ||
const isEmptyArray = e => isArrayElement(e) && e.content.every(isNoValuePrimitive); | ||
const isObjectWithUndefinedValues = e => isObjectElement(e) | ||
&& e.content.every(prop => prop.value === undefined || prop.value.content === undefined); | ||
function trivialValue(e) { | ||
if (e instanceof BooleanElement) { | ||
return new BooleanElement(false); | ||
} | ||
if (e instanceof NumberElement) { | ||
return new NumberElement(0); | ||
} | ||
if (e instanceof StringElement) { | ||
return new StringElement(''); | ||
} | ||
if (e instanceof NullElement) { | ||
return new NullElement(); | ||
} | ||
return undefined; | ||
} | ||
function mapValue(e, options, f, elements) { | ||
/** | ||
* 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, inheritFixed, elements) { | ||
if (e === undefined) { | ||
return e; | ||
return undefined; | ||
} | ||
const opts = updateTypeAttributes(e, options); | ||
const isElementFixed = inheritFixed || isFixed(e); | ||
if (e.content && !isEmptyArray(e) && !isObjectWithUndefinedValues(e)) { | ||
const result = f(e, opts, elements, 'content'); | ||
if (e.content && !isEmptyArray(e, elements) && !isObjectWithUndefinedValues(e, elements)) { | ||
const result = f(e, isElementFixed, elements, 'content'); | ||
if (undefined !== result) { | ||
if (result !== undefined) { | ||
return result; | ||
@@ -138,6 +51,6 @@ } | ||
const sample = findFirstSample(e); | ||
const sample = getFirstSample(e); | ||
if (sample) { | ||
const result = f(sample, opts, elements, 'sample'); | ||
if (undefined !== result) { | ||
const result = f(sample, isElementFixed, elements, 'sample'); | ||
if (result !== undefined) { | ||
return result; | ||
@@ -147,6 +60,6 @@ } | ||
const dflt = findDefault(e); | ||
const dflt = getDefault(e); | ||
if (dflt) { | ||
const result = f(dflt, opts, elements, 'default'); | ||
if (undefined !== result) { | ||
const result = f(dflt, isElementFixed, elements, 'default'); | ||
if (result !== undefined) { | ||
return result; | ||
@@ -156,7 +69,7 @@ } | ||
// reconsider content for array element (prefer sample/default first) | ||
if (isNonEmptyArrayElement(e)) { | ||
const result = f(e, opts, elements, 'content'); | ||
// reconsider content for array and object element (prefer sample/default first) | ||
if (isNonEmptyArray(e, elements) && isObject(e, elements)) { | ||
const result = f(e, isElementFixed, elements, 'content'); | ||
if (undefined !== result) { | ||
if (result !== undefined) { | ||
return result; | ||
@@ -166,5 +79,5 @@ } | ||
if (isFlag(NULLABLE_FLAG, opts)) { | ||
const result = f(new NullElement(), opts, elements, 'nullable'); | ||
if (undefined !== result) { | ||
if (isNullable(e)) { | ||
const result = f(new NullElement(), isElementFixed, elements, 'nullable'); | ||
if (result !== undefined) { | ||
return result; | ||
@@ -175,3 +88,3 @@ } | ||
if (elements) { | ||
if (e.element === 'ref') { | ||
if (isRef(e)) { | ||
const result = elements[e.content]; | ||
@@ -181,20 +94,21 @@ const inheritedElements = R.filter(el => !el.id.equals(e.content), elements); | ||
if (e.path && e.path.toValue() === 'content') { | ||
return mapValue(result.content, opts, f, inheritedElements); | ||
return mapValue(result.content, f, isElementFixed, inheritedElements); | ||
} | ||
return mapValue(result, opts, f, inheritedElements); | ||
return mapValue(result, f, isElementFixed, inheritedElements); | ||
} | ||
const result = elements[e.element]; | ||
if (result) { | ||
if (result !== undefined) { | ||
const inheritedElements = R.filter(el => !el.id.equals(e.element), elements); | ||
return mapValue(result, opts, f, inheritedElements); | ||
return mapValue(result, f, isElementFixed, inheritedElements); | ||
} | ||
} | ||
if (isEnumElement(e)) { | ||
const enums = e.enumerations; | ||
if (enums && enums.content && enums.content[0]) { | ||
const result = f(enums.content[0], opts, elements, 'generated'); | ||
if (undefined !== result) { | ||
if (isEnum(e, elements)) { | ||
const content = getStructureMembers(e, elements); | ||
if (content && content[0]) { | ||
const result = f(content[0], isElementFixed, elements, 'generated'); | ||
if (result !== undefined) { | ||
return result; | ||
@@ -207,4 +121,4 @@ } | ||
if (trivial) { | ||
const result = f(trivial, opts, elements, 'generated'); | ||
if (undefined !== result) { | ||
const result = f(trivial, isElementFixed, elements, 'generated'); | ||
if (result !== undefined) { | ||
return result; | ||
@@ -214,4 +128,4 @@ } | ||
if (isArrayElement(e) && e.isEmpty) { | ||
return f(e, opts, elements, 'generated'); | ||
if ((isArray(e, elements) && e.isEmpty) || isObject(e, elements)) { | ||
return f(e, isElementFixed, elements, 'generated'); | ||
} | ||
@@ -222,10 +136,15 @@ | ||
function reduceValue(e, options, elements) { | ||
const opts = updateTypeAttributes(e, options); | ||
/** | ||
* 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, inheritFixed, elements) { | ||
if (e.content === undefined) { | ||
return mapValue(e, opts, e => e.content, elements); | ||
return mapValue(e, e => e.content, inheritFixed, elements); | ||
} | ||
if (isPrimitive(e)) { | ||
if (isPrimitive(e, elements)) { | ||
return e.content; | ||
@@ -238,18 +157,18 @@ } | ||
if (isEnumElement(e)) { | ||
return mapValue(e.content, inheritFlags(opts), reduceValue, elements); | ||
if (isEnum(e, elements)) { | ||
return mapValue(e.content, reduceValue, inheritFixed, elements); | ||
} | ||
if (isObjectElement(e)) { | ||
if (isObject(e, elements)) { | ||
let result = {}; | ||
const isFixed = isFlag(FIXED_FLAG, opts); | ||
const isFixedType = isFlag(FIXED_TYPE_FLAG, opts); | ||
const content = getStructureMembers(e, elements); | ||
const isElementFixedType = isFixedType(e); | ||
e.content.some((item) => { | ||
const skippable = hasOptionalTypeAttribute(item) || (!isFixed && !isFixedType && !hasTypeAttribute(item, 'required')); | ||
content.some((item) => { | ||
const isSkippable = isOptional(item) || (!inheritFixed && !isElementFixedType && !isRequired(item)); | ||
const key = mapValue(item.key, inheritFlags(opts), reduceValue, elements); | ||
const key = mapValue(item.key, reduceValue, inheritFixed, elements); | ||
if (key === undefined) { | ||
if (skippable) { | ||
if (isSkippable) { | ||
return false; | ||
@@ -262,5 +181,5 @@ } | ||
const value = mapValue(item.value, inheritFlags(opts), reduceValue, elements); | ||
const value = mapValue(item.value, reduceValue, inheritFixed, elements); | ||
if (value === undefined) { | ||
if (skippable) { | ||
if (isSkippable) { | ||
return false; | ||
@@ -280,6 +199,7 @@ } | ||
if (e instanceof ArrayElement) { | ||
const result = e.map(item => mapValue(item, inheritFlags(opts), reduceValue, elements)); | ||
if (isArray(e, elements)) { | ||
const content = getStructureMembers(e, elements); | ||
const result = content.map(item => mapValue(item, reduceValue, inheritFixed, elements)); | ||
if (!isFlag(FIXED_FLAG, opts) && !isFlag(FIXED_TYPE_FLAG, opts)) { | ||
if (!inheritFixed && !isFixedType(e)) { | ||
return result.filter(item => item !== undefined); | ||
@@ -299,18 +219,23 @@ } | ||
module.exports = () => { | ||
if (!Object.getOwnPropertyNames(Element.prototype).includes('valueOf')) { | ||
Object.defineProperty(Element.prototype, 'valueOf', { | ||
value(flags, elements) { | ||
if (flags !== undefined && flags.source) { | ||
return mapValue(this, 0, (value, opts, elements, source) => { | ||
const result = reduceValue(value, opts, elements); | ||
if (undefined === result) { | ||
return undefined; | ||
} | ||
return [reduceValue(value, opts, elements), source]; | ||
}, elements); | ||
} | ||
return mapValue(this, 0, (value, opts) => reduceValue(value, opts, elements), elements); | ||
}, | ||
}); | ||
if (Object.getOwnPropertyNames(Element.prototype).includes('valueOf')) { | ||
return; | ||
} | ||
Object.defineProperty(Element.prototype, 'valueOf', { | ||
value(flags, elements) { | ||
if (flags && flags.source) { | ||
return mapValue(this, (value, attrs, elements, source) => { | ||
const result = reduceValue(value, attrs, elements); | ||
if (result === undefined) { | ||
return undefined; | ||
} | ||
return [result, source]; | ||
}, false, elements); | ||
} | ||
return mapValue(this, reduceValue, false, elements); | ||
}, | ||
}); | ||
}; |
{ | ||
"name": "api-elements", | ||
"version": "0.3.1", | ||
"version": "0.3.2", | ||
"description": "API Elements JavaScript", | ||
@@ -35,3 +35,3 @@ "author": "Apiary.io <support@apiary.io>", | ||
}, | ||
"gitHead": "d226305421ff42dfa30041568eb639a0755aa16b" | ||
"gitHead": "fdb70bfffae4ddfffbc4348f7e22a8de979cadc2" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
55657
26
1398
0