@luvio/model
Advanced tools
Comparing version 3.5.2 to 3.6.0
@@ -10,2 +10,21 @@ /** | ||
/** | ||
* Iterates the extensions in specified order, serching for the ones containing an occurrence | ||
* of the specified extension, and merge them into one single extension (emulates inheritance). | ||
* | ||
* @param name the name of the extension to retrieve | ||
* @param extensions extensions to search into | ||
* @returns the first matching extension, or undefined if none can be found | ||
*/ | ||
function extensionFromName(name, ...extensions) { | ||
// searches all specified extension arrays, looking for an occurrence of the specified extension | ||
return (extensions || []) | ||
.filter(Boolean) | ||
.map((exts) => exts[name]) | ||
.filter(Boolean) | ||
.reduce((result, ext) => { | ||
return Object.assign(result, ext); | ||
}, {}); | ||
} | ||
const DiscriminatorValueTypes = new Set([ | ||
@@ -32,2 +51,117 @@ 'string', | ||
const STRING_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#string'; | ||
const BOOLEAN_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#boolean'; | ||
const INTEGER_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#integer'; | ||
const DOUBLE_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#double'; | ||
const NUMBER_DATA_TYPE = 'http://a.ml/vocabularies/shapes#number'; | ||
const DATE_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#date'; | ||
const TIME_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#time'; | ||
const DATETIME_ONLY_TYPE = 'http://a.ml/vocabularies/shapes#dateTimeOnly'; | ||
const DATETIME_TYPE = 'http://www.w3.org/2001/XMLSchema#dateTime'; | ||
const DATATYPE_TO_SCALAR_TYPE = { | ||
[BOOLEAN_DATA_TYPE]: 'boolean', | ||
[DOUBLE_DATA_TYPE]: 'double', | ||
[INTEGER_DATA_TYPE]: 'integer', | ||
[NUMBER_DATA_TYPE]: 'number', | ||
[STRING_DATA_TYPE]: 'string', | ||
[DATE_DATA_TYPE]: 'date', | ||
[TIME_DATA_TYPE]: 'time', | ||
[DATETIME_ONLY_TYPE]: 'datetime-only', | ||
[DATETIME_TYPE]: 'datetime', | ||
}; | ||
function isTypeShape(domainElement) { | ||
return domainElement instanceof amf.AnyShape; | ||
} | ||
function isAnyShape(domainElement) { | ||
return Object.getPrototypeOf(domainElement) === amf.AnyShape.prototype; | ||
} | ||
function isNilShape(shape) { | ||
return shape instanceof amf.NilShape; | ||
} | ||
function isNodeShape(node) { | ||
return node instanceof amf.NodeShape; | ||
} | ||
function isArrayShape(node) { | ||
return node instanceof amf.ArrayShape; | ||
} | ||
function isScalarShape(shape) { | ||
return shape instanceof amf.ScalarShape; | ||
} | ||
function isUnionShape(shape) { | ||
return shape instanceof amf.UnionShape; | ||
} | ||
function isScalarNode(node) { | ||
return node instanceof amf.ScalarNode; | ||
} | ||
function getEnumValuesFromShape(shape) { | ||
return shape.values.map((val) => extractScalarEnumValue(val, shape)); | ||
} | ||
function extractScalarEnumValue(node, parentShape) { | ||
if (isScalarNode(node)) { | ||
const scalarType = DATATYPE_TO_SCALAR_TYPE[node.dataType.value()]; | ||
switch (scalarType) { | ||
case 'datetime': | ||
return String(node.value.value()); | ||
default: | ||
return coerceValueByType(node.value.value(), { | ||
type: scalarType, | ||
inherits: [], | ||
}); | ||
} | ||
} | ||
else { | ||
throw new Error(`Invalid non-scalar enum value provided for shape ${parentShape.name.value()}`); | ||
} | ||
} | ||
function coerceValueByType(value, type) { | ||
switch (type.type) { | ||
case 'string': | ||
return String(value); | ||
case 'boolean': | ||
return value === 'true'; | ||
case 'number': | ||
case 'double': | ||
case 'integer': | ||
return Number(value); | ||
case 'nil': | ||
return null; | ||
default: | ||
return value; | ||
} | ||
} | ||
const DATA_DATATYPE_PROPERTY_NAME = 'http://www.w3.org/ns/shacl#datatype'; | ||
const DATA_VALUE_PROPERTY_NAME = 'http://a.ml/vocabularies/data#value'; | ||
const NAME_PROPERTY_VALUE = 'http://a.ml/vocabularies/core#name'; | ||
/** | ||
* Reads extensions from the parsed node. | ||
* | ||
* IMPORTANT NOTE: this only works with OpenAPI spec files for now. | ||
*/ | ||
function buildExtensions(customDomainProperties) { | ||
let extensions = {}; | ||
(customDomainProperties || []).forEach((cdp) => { | ||
const name = cdp.name.value(); | ||
const properties = buildExtension(cdp.extension.graph()); | ||
extensions[name] = properties; | ||
}); | ||
return extensions; | ||
} | ||
function buildExtension(graph) { | ||
let properties = {}; | ||
graph | ||
.properties() | ||
.filter((prop) => prop !== NAME_PROPERTY_VALUE) | ||
.forEach((fullname) => { | ||
const propGraph = graph.getObjectByProperty(fullname)[0].graph(); | ||
const rawType = propGraph.scalarByProperty(DATA_DATATYPE_PROPERTY_NAME)[0]; | ||
const rawValue = propGraph.scalarByProperty(DATA_VALUE_PROPERTY_NAME)[0]; | ||
const name = fullname.split('#')[1]; | ||
const type = { type: DATATYPE_TO_SCALAR_TYPE[rawType], inherits: [] }; | ||
const value = coerceValueByType(rawValue, type); | ||
properties[name] = { fullname, type, value }; | ||
}); | ||
return properties; | ||
} | ||
class AmfEndPoint { | ||
@@ -46,2 +180,3 @@ constructor(amfEndPoint, operations, amfTypeFactory, typeRegistry, logger) { | ||
}); | ||
this.extensions = buildExtensions(this.amfEndPoint.customDomainProperties); | ||
} | ||
@@ -77,2 +212,3 @@ } | ||
}); | ||
this.extensions = buildExtensions(this.amfOperation.customDomainProperties); | ||
} | ||
@@ -145,83 +281,2 @@ buildPayloads(r) { | ||
const STRING_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#string'; | ||
const BOOLEAN_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#boolean'; | ||
const INTEGER_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#integer'; | ||
const DOUBLE_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#double'; | ||
const NUMBER_DATA_TYPE = 'http://a.ml/vocabularies/shapes#number'; | ||
const DATE_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#date'; | ||
const TIME_DATA_TYPE = 'http://www.w3.org/2001/XMLSchema#time'; | ||
const DATETIME_ONLY_TYPE = 'http://a.ml/vocabularies/shapes#dateTimeOnly'; | ||
const DATETIME_TYPE = 'http://www.w3.org/2001/XMLSchema#dateTime'; | ||
const DATATYPE_TO_SCALAR_TYPE = { | ||
[BOOLEAN_DATA_TYPE]: 'boolean', | ||
[DOUBLE_DATA_TYPE]: 'double', | ||
[INTEGER_DATA_TYPE]: 'integer', | ||
[NUMBER_DATA_TYPE]: 'number', | ||
[STRING_DATA_TYPE]: 'string', | ||
[DATE_DATA_TYPE]: 'date', | ||
[TIME_DATA_TYPE]: 'time', | ||
[DATETIME_ONLY_TYPE]: 'datetime-only', | ||
[DATETIME_TYPE]: 'datetime', | ||
}; | ||
function isTypeShape(domainElement) { | ||
return domainElement instanceof amf.AnyShape; | ||
} | ||
function isAnyShape(domainElement) { | ||
return Object.getPrototypeOf(domainElement) === amf.AnyShape.prototype; | ||
} | ||
function isNilShape(shape) { | ||
return shape instanceof amf.NilShape; | ||
} | ||
function isNodeShape(node) { | ||
return node instanceof amf.NodeShape; | ||
} | ||
function isArrayShape(node) { | ||
return node instanceof amf.ArrayShape; | ||
} | ||
function isScalarShape(shape) { | ||
return shape instanceof amf.ScalarShape; | ||
} | ||
function isUnionShape(shape) { | ||
return shape instanceof amf.UnionShape; | ||
} | ||
function isScalarNode(node) { | ||
return node instanceof amf.ScalarNode; | ||
} | ||
function getEnumValuesFromShape(shape) { | ||
return shape.values.map((val) => extractScalarEnumValue(val, shape)); | ||
} | ||
function extractScalarEnumValue(node, parentShape) { | ||
if (isScalarNode(node)) { | ||
const scalarType = DATATYPE_TO_SCALAR_TYPE[node.dataType.value()]; | ||
switch (scalarType) { | ||
case 'datetime': | ||
return String(node.value.value()); | ||
default: | ||
return coerceValueByType(node.value.value(), { | ||
type: scalarType, | ||
inherits: [], | ||
}); | ||
} | ||
} | ||
else { | ||
throw new Error(`Invalid non-scalar enum value provided for shape ${parentShape.name.value()}`); | ||
} | ||
} | ||
function coerceValueByType(value, type) { | ||
switch (type.type) { | ||
case 'string': | ||
return String(value); | ||
case 'boolean': | ||
return value === 'true'; | ||
case 'number': | ||
case 'double': | ||
case 'integer': | ||
return Number(value); | ||
case 'nil': | ||
return null; | ||
default: | ||
return value; | ||
} | ||
} | ||
class AMFObjectTypeImpl extends AMFBaseType { | ||
@@ -680,2 +735,8 @@ constructor() { | ||
} | ||
get extensions() { | ||
if (!this._extensions) { | ||
this._extensions = buildExtensions(this.document.encodes.customDomainProperties); | ||
} | ||
return this._extensions; | ||
} | ||
} | ||
@@ -708,2 +769,2 @@ | ||
export { AMFAnyTypeImpl, AMFArrayTypeImpl, AMFBooleanTypeImpl, AMFDateTimeImpl, AMFDateTimeOnlyTypeImpl, AMFDateTypeImpl, AMFDoubleTypeImpl, AMFEnumerableScalarType, AMFIntegerTypeImpl, AMFNilTypeImpl, AMFNumberTypeImpl, AMFObjectTypeImpl, AMFStringTypeImpl, AMFTimeTypeImpl, AMFUnionTypeImpl, BaseTypeRegistry, DiscriminatorValueTypes, amfTypeFactory, getDiscriminatedParent, parseUrl }; | ||
export { AMFAnyTypeImpl, AMFArrayTypeImpl, AMFBooleanTypeImpl, AMFDateTimeImpl, AMFDateTimeOnlyTypeImpl, AMFDateTypeImpl, AMFDoubleTypeImpl, AMFEnumerableScalarType, AMFIntegerTypeImpl, AMFNilTypeImpl, AMFNumberTypeImpl, AMFObjectTypeImpl, AMFStringTypeImpl, AMFTimeTypeImpl, AMFUnionTypeImpl, BaseTypeRegistry, DiscriminatorValueTypes, amfTypeFactory, extensionFromName, getDiscriminatedParent, parseUrl }; |
@@ -7,2 +7,3 @@ import type { AMFType } from './types'; | ||
import type { EndPoint } from '../Endpoint'; | ||
import type { Extensions } from '../Extensions'; | ||
export declare class AMFAPI implements API { | ||
@@ -14,2 +15,3 @@ readonly document: amf.Document; | ||
_servers?: Server[]; | ||
_extensions?: Extensions; | ||
constructor(document: amf.Document, logger: FileParserLogger); | ||
@@ -20,2 +22,3 @@ get webApi(): amf.WebApi; | ||
get types(): ReadOnlyTypeRegistry<AMFType>; | ||
get extensions(): Extensions; | ||
} |
@@ -7,2 +7,3 @@ import type { EndPoint, Parameter } from '../../Endpoint'; | ||
import type { AmfOperation } from './amf-operation'; | ||
import type { Extensions } from '../../Extensions'; | ||
export declare class AmfEndPoint implements EndPoint { | ||
@@ -14,3 +15,4 @@ private amfEndPoint; | ||
uriParameters: Record<string, Parameter>; | ||
extensions: Extensions; | ||
constructor(amfEndPoint: amf.EndPoint, operations: AmfOperation[], amfTypeFactory: AMFTypeFactory, typeRegistry: TypeRegistry<AMFType>, logger: FileParserLogger); | ||
} |
@@ -6,2 +6,3 @@ import type * as amf from 'amf-client-js'; | ||
import type { FileParserLogger } from '@luvio/utils'; | ||
import type { Extensions } from '../../Extensions'; | ||
export declare class AmfOperation implements Operation { | ||
@@ -16,2 +17,3 @@ private amfOperation; | ||
responses: Response[]; | ||
extensions: Extensions; | ||
constructor(amfOperation: amf.Operation, amfTypeFactory: AMFTypeFactory, typeRegistry: TypeRegistry<AMFType>, logger: FileParserLogger); | ||
@@ -18,0 +20,0 @@ buildPayloads(r: amf.Request | amf.Response): Payload[]; |
@@ -0,1 +1,2 @@ | ||
import type { Extensions } from './Extensions'; | ||
import type { EndPoint, Parameter } from './Endpoint'; | ||
@@ -16,2 +17,6 @@ import type { ReadOnlyTypeRegistry } from './TypeRegistry'; | ||
servers: ReadonlyArray<Server>; | ||
/** | ||
* Specification extensions defined at root level. | ||
*/ | ||
extensions: Extensions; | ||
}; | ||
@@ -18,0 +23,0 @@ export type Server = { |
@@ -0,1 +1,2 @@ | ||
import type { Extensions } from './Extensions'; | ||
import type { ScalarType, Type } from './Type'; | ||
@@ -34,2 +35,3 @@ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'CONNECT' | 'OPTIONS' | 'TRACE'; | ||
responses: Response<ResponseType>[]; | ||
extensions: Extensions; | ||
}; | ||
@@ -43,2 +45,3 @@ /** | ||
operations: ReadonlyArray<Operation>; | ||
extensions: Extensions; | ||
}; |
export * from './API'; | ||
export * from './Endpoint'; | ||
export * from './Extensions'; | ||
export * from './Type'; | ||
export * from './TypeRegistry'; | ||
export * from './amf'; |
{ | ||
"name": "@luvio/model", | ||
"version": "3.5.2", | ||
"version": "3.6.0", | ||
"description": "Luvio model", | ||
@@ -24,3 +24,3 @@ "repository": { | ||
"dependencies": { | ||
"@luvio/utils": "^3.5.2", | ||
"@luvio/utils": "^3.6.0", | ||
"amf-client-js": "^5.2.3" | ||
@@ -27,0 +27,0 @@ }, |
49706
25
1206
Updated@luvio/utils@^3.6.0