raml-typesystem
Advanced tools
Comparing version 0.0.27-rc2 to 0.0.28-rc2
@@ -6,2 +6,3 @@ "use strict"; | ||
var restrictions_2 = require("./restrictions"); | ||
var exCalcFlag = "exampleCalculation"; | ||
function example(t) { | ||
@@ -12,52 +13,61 @@ var ms = t.oneMeta(meta.Example); | ||
} | ||
var ms1 = t.oneMeta(meta.Examples); | ||
if (ms1) { | ||
var examples = ms1.examples(); | ||
if (examples && examples.length > 0) { | ||
return examples[0]; | ||
} | ||
if (t.getExtra(exCalcFlag)) { | ||
return null; | ||
} | ||
var d = t.oneMeta(meta.Default); | ||
if (d) { | ||
return d.value(); | ||
} | ||
if (t.isObject()) { | ||
var result = {}; | ||
t.meta().forEach(function (x) { | ||
if (x instanceof restrictions_2.PropertyIs) { | ||
var p = x; | ||
var ex = example(p.value()); | ||
result[p.propertyName()] = ex; | ||
t.putExtra(exCalcFlag, true); | ||
try { | ||
var ms1 = t.oneMeta(meta.Examples); | ||
if (ms1) { | ||
var examples = ms1.examples(); | ||
if (examples && examples.length > 0) { | ||
return examples[0]; | ||
} | ||
}); | ||
t.superTypes().forEach(function (x) { | ||
if (x.oneMeta(meta.Example) || x.oneMeta(meta.Examples)) { | ||
var ex = example(x); | ||
if (ex && typeof ex === "object") { | ||
Object.keys(ex).forEach(function (key) { | ||
result[key] = ex[key]; | ||
}); | ||
} | ||
var d = t.oneMeta(meta.Default); | ||
if (d) { | ||
return d.value(); | ||
} | ||
if (t.isObject()) { | ||
var result = {}; | ||
t.meta().forEach(function (x) { | ||
if (x instanceof restrictions_2.PropertyIs) { | ||
var p = x; | ||
var ex = example(p.value()); | ||
result[p.propertyName()] = ex; | ||
} | ||
}); | ||
t.superTypes().forEach(function (x) { | ||
if (x.oneMeta(meta.Example) || x.oneMeta(meta.Examples)) { | ||
var ex = example(x); | ||
if (ex && typeof ex === "object") { | ||
Object.keys(ex).forEach(function (key) { | ||
result[key] = ex[key]; | ||
}); | ||
} | ||
} | ||
}); | ||
return result; | ||
} | ||
if (t.isArray()) { | ||
var c = t.oneMeta(restrictions_1.ComponentShouldBeOfType); | ||
var resultArray = []; | ||
if (c) { | ||
resultArray.push(example(c.value())); | ||
} | ||
}); | ||
return result; | ||
} | ||
if (t.isArray()) { | ||
var c = t.oneMeta(restrictions_1.ComponentShouldBeOfType); | ||
var resultArray = []; | ||
if (c) { | ||
resultArray.push(example(c.value())); | ||
return resultArray; | ||
} | ||
return resultArray; | ||
if (t.isUnion()) { | ||
return example(t.typeFamily()[0]); | ||
} | ||
if (t.isNumber()) { | ||
return 1; | ||
} | ||
if (t.isBoolean()) { | ||
return true; | ||
} | ||
return "some value"; | ||
} | ||
if (t.isUnion()) { | ||
return example(t.typeFamily()[0]); | ||
finally { | ||
t.putExtra(exCalcFlag, false); | ||
} | ||
if (t.isNumber()) { | ||
return 1; | ||
} | ||
if (t.isBoolean()) { | ||
return true; | ||
} | ||
return "some value"; | ||
} | ||
@@ -64,0 +74,0 @@ exports.example = example; |
@@ -6,2 +6,3 @@ export import nominalTypes = require("./nominal-types"); | ||
} | ||
export declare function getSchemaUtils(): any; | ||
export interface IStatus { | ||
@@ -8,0 +9,0 @@ /** |
@@ -11,2 +11,7 @@ "use strict"; | ||
exports.nominalTypes = require("./nominal-types"); | ||
var schemaUtil = require('./schemaUtil'); | ||
function getSchemaUtils() { | ||
return schemaUtil; | ||
} | ||
exports.getSchemaUtils = getSchemaUtils; | ||
/** | ||
@@ -13,0 +18,0 @@ * loads type collection from JSON type definition |
@@ -125,6 +125,6 @@ "use strict"; | ||
if (typeof val === 'string') { | ||
if (type.isObject() || type.isArray() || type.isExternal()) { | ||
if (type.isObject() || type.isArray() || type.isExternal() || type.isUnion()) { | ||
var exampleString = val; | ||
var firstChar = exampleString.trim().charAt(0); | ||
if (firstChar == "{" || firstChar == "[") { | ||
if ((firstChar == "{" || firstChar == "[") && !type.isUnion()) { | ||
try { | ||
@@ -142,3 +142,10 @@ return JSON.parse(exampleString); | ||
try { | ||
return xmlio.readObject(exampleString, type); | ||
var jsonFromXml = xmlio.readObject(exampleString, type); | ||
var errors = xmlio.getXmlErrors(jsonFromXml); | ||
if (errors) { | ||
var error = new typesystem_1.Status(typesystem_1.Status.ERROR, 0, 'Invalid XML.', {}); | ||
errors.forEach(function (child) { return error.addSubStatus(child); }); | ||
return error; | ||
} | ||
return jsonFromXml; | ||
} | ||
@@ -145,0 +152,0 @@ catch (e) { |
@@ -254,3 +254,3 @@ export interface INamedEntity { | ||
/** | ||
* Returns whether this type contain genuine user defined type in its hierarchy. | ||
* Returns whether this type is genuine user defined type. | ||
* Genuine user defined type is a type user intentionally defined and filled with | ||
@@ -261,2 +261,8 @@ * properties or facets, or having user-defined name as opposed to a synthetic user-defined type. | ||
/** | ||
* Returns whether this type contain genuine user defined type in its hierarchy. | ||
* Genuine user defined type is a type user intentionally defined and filled with | ||
* properties or facets, or having user-defined name as opposed to a synthetic user-defined type. | ||
*/ | ||
hasGenuineUserDefinedTypeInHierarchy(): boolean; | ||
/** | ||
* Returns nearest genuine user-define type in the hierarchy. | ||
@@ -266,3 +272,3 @@ * Genuine user defined type is a type user intentionally defined and filled with | ||
*/ | ||
genuineUserDefinedType(): ITypeDefinition; | ||
genuineUserDefinedTypeInHierarchy(): ITypeDefinition; | ||
kind(): string[]; | ||
@@ -269,0 +275,0 @@ validate(x: any): Status[]; |
@@ -26,2 +26,3 @@ import ti = require("./nominal-interfaces"); | ||
}): T; | ||
getAdapters(): any[]; | ||
} | ||
@@ -145,3 +146,9 @@ export declare class Described extends Adaptable { | ||
*/ | ||
genuineUserDefinedType(): ITypeDefinition; | ||
genuineUserDefinedTypeInHierarchy(): ITypeDefinition; | ||
/** | ||
* Returns whether this type contain genuine user defined type in its hierarchy. | ||
* Genuine user defined type is a type user intentionally defined and filled with | ||
* properties or facets, or having user-defined name as opposed to a synthetic user-defined type. | ||
*/ | ||
hasGenuineUserDefinedTypeInHierarchy(): boolean; | ||
customProperties(): IProperty[]; | ||
@@ -161,2 +168,5 @@ allCustomProperties(): IProperty[]; | ||
kind(): string[]; | ||
isBuiltIn(): boolean; | ||
setBuiltIn(builtIn: boolean): void; | ||
private isTopLevel(); | ||
} | ||
@@ -163,0 +173,0 @@ export declare class ValueType extends AbstractType implements ITypeDefinition { |
@@ -34,2 +34,5 @@ "use strict"; | ||
}; | ||
Adaptable.prototype.getAdapters = function () { | ||
return this.adapters; | ||
}; | ||
return Adaptable; | ||
@@ -490,3 +493,9 @@ }()); | ||
AbstractType.prototype.isGenuineUserDefinedType = function () { | ||
return this.nameId() && this.nameId().length > 0 && !this.buildIn; | ||
if (this.buildIn) | ||
return false; | ||
if (this.properties() && this.properties().length > 0) | ||
return true; | ||
if (this.getFixedFacets() && Object.keys(this.getFixedFacets()).length > 0) | ||
return true; | ||
return this.isTopLevel() && this.nameId() && this.nameId().length > 0; | ||
}; | ||
@@ -498,10 +507,34 @@ /** | ||
*/ | ||
AbstractType.prototype.genuineUserDefinedType = function () { | ||
if (this.getAdapter(Empty)) { | ||
if (this.superTypes().length == 1) { | ||
return this.superTypes()[0]; | ||
AbstractType.prototype.genuineUserDefinedTypeInHierarchy = function () { | ||
if (this.isGenuineUserDefinedType()) | ||
return this; | ||
var result = null; | ||
var allSuperTypes = this.allSuperTypes(); | ||
allSuperTypes.forEach(function (currentSuperType) { | ||
if (!result && currentSuperType.isGenuineUserDefinedType()) { | ||
result = currentSuperType; | ||
} | ||
} | ||
return this; | ||
}); | ||
return result; | ||
}; | ||
/** | ||
* Returns whether this type contain genuine user defined type in its hierarchy. | ||
* Genuine user defined type is a type user intentionally defined and filled with | ||
* properties or facets, or having user-defined name as opposed to a synthetic user-defined type. | ||
*/ | ||
AbstractType.prototype.hasGenuineUserDefinedTypeInHierarchy = function () { | ||
return _.find(this.allSuperTypes(), function (x) { | ||
var mm = x; | ||
if (mm.uc) { | ||
return false; | ||
} | ||
mm.uc = true; | ||
try { | ||
return x.isGenuineUserDefinedType(); | ||
} | ||
finally { | ||
mm.uc = false; | ||
} | ||
}) != null; | ||
}; | ||
AbstractType.prototype.customProperties = function () { | ||
@@ -586,2 +619,19 @@ return [].concat(this._customProperties); | ||
}; | ||
AbstractType.prototype.isBuiltIn = function () { | ||
return this.buildIn; | ||
}; | ||
AbstractType.prototype.setBuiltIn = function (builtIn) { | ||
this.buildIn = builtIn; | ||
}; | ||
AbstractType.prototype.isTopLevel = function () { | ||
if (this.getAdapters() && _.find(this.getAdapters(), function (adapter) { | ||
// return adapter.getExtra && adapter.getExtra("topLevel"); | ||
//TODO determine whether "topLevel" actually means a simple top-level type and | ||
//this flag is absent due to a bug | ||
return adapter.getExtra && (adapter.getExtra("definedInTypes") || adapter.getExtra("topLevel")); | ||
})) { | ||
return true; | ||
} | ||
return false; | ||
}; | ||
return AbstractType; | ||
@@ -588,0 +638,0 @@ }(Described)); |
@@ -6,2 +6,6 @@ /// <reference path="../../typings/main.d.ts" /> | ||
} | ||
export interface Promise { | ||
then(instance: any): any; | ||
resolve(arg: any): any; | ||
} | ||
export interface IContentProvider { | ||
@@ -14,2 +18,4 @@ contextPath(): string; | ||
isAbsolutePath(uri: string): boolean; | ||
contentAsync(arg: any): Promise; | ||
promiseResolve(arg: any): Promise; | ||
} | ||
@@ -30,2 +36,3 @@ export declare class JSONSchemaObject { | ||
private acceptErrors(key, errors, throwImmediately?); | ||
contentAsync(reference: any): Promise; | ||
} | ||
@@ -32,0 +39,0 @@ export interface ValidationError { |
@@ -48,2 +48,15 @@ "use strict"; | ||
}; | ||
DummyProvider.prototype.contentAsync = function (reference) { | ||
var _this = this; | ||
return { | ||
then: function (arg) { return arg(_this.content(reference)); }, | ||
resolve: function () { return null; } | ||
}; | ||
}; | ||
DummyProvider.prototype.promiseResolve = function (arg) { | ||
return { | ||
then: function (arg1) { return arg1(arg); }, | ||
resolve: function () { return null; } | ||
}; | ||
}; | ||
return DummyProvider; | ||
@@ -99,3 +112,9 @@ }()); | ||
references.forEach(function (references) { return validator.setRemoteReference(references.reference, references.content || {}); }); | ||
validator.validateSchema(this.jsonSchema); | ||
try { | ||
validator.validateSchema(this.jsonSchema); | ||
} | ||
catch (Error) { | ||
//we should never be exploding here, instead we'll report this error later | ||
return []; | ||
} | ||
var result = validator.getMissingRemoteReferences(); | ||
@@ -246,2 +265,30 @@ return normalize ? result.map(function (reference) { return _this.provider.normalizePath(reference); }) : result; | ||
}; | ||
JSONSchemaObject.prototype.contentAsync = function (reference) { | ||
var _this = this; | ||
var remoteSchemeContent; | ||
var api = require('json-schema-compatibility'); | ||
var contentPromise = this.provider.contentAsync(reference); | ||
if (!contentPromise) { | ||
return this.provider.promiseResolve({ | ||
reference: reference, | ||
content: null, | ||
error: new Error('Reference not found: ' + reference) | ||
}); | ||
} | ||
var result = contentPromise.then(function (cnt) { | ||
var content = { reference: reference }; | ||
try { | ||
var jsonObject = JSON.parse(cnt); | ||
_this.setupId(jsonObject, _this.provider.normalizePath(reference)); | ||
remoteSchemeContent = api.v4(jsonObject); | ||
delete remoteSchemeContent['$schema']; | ||
content.content = remoteSchemeContent; | ||
} | ||
catch (exception) { | ||
content.error = exception; | ||
} | ||
return content; | ||
}); | ||
return result; | ||
}; | ||
return JSONSchemaObject; | ||
@@ -248,0 +295,0 @@ }()); |
@@ -397,3 +397,5 @@ "use strict"; | ||
} | ||
this.validateMeta(tr).getErrors().forEach(function (x) { return rs.addSubStatus(x); }); | ||
if (rs.isOk()) { | ||
this.validateMeta(tr).getErrors().forEach(function (x) { return rs.addSubStatus(x); }); | ||
} | ||
//if (this.isPolymorphic()||(this.isUnion())) { | ||
@@ -450,5 +452,8 @@ // rs.addSubStatus(this.canDoAc()); | ||
var fs = this.familyWithArray(); | ||
if ((fs.indexOf(this) != -1) || fs.some(function (x) { return x === exports.UNKNOWN || x === exports.RECURRENT; })) { | ||
if ((fs.indexOf(this) != -1) || fs.some(function (x) { return x === exports.RECURRENT; })) { | ||
rs.addSubStatus(new Status(Status.ERROR, 0, "recurrent array type definition", this)); | ||
} | ||
else if (fs.some(function (x) { return x === exports.UNKNOWN; })) { | ||
rs.addSubStatus(new Status(Status.ERROR, 0, "referring to unknown type " + this.oneMeta(restrictions_3.ComponentShouldBeOfType).value().name() + " as an array component type", this)); | ||
} | ||
} | ||
@@ -455,0 +460,0 @@ var supers = this.superTypes(); |
/// <reference path="../../typings/main.d.ts" /> | ||
import ts = require("./typesystem"); | ||
import { Status } from "./typesystem"; | ||
export declare function readObject(content: string, t: ts.AbstractType): any; | ||
export declare function getXmlErrors(root: any): Status[]; |
@@ -6,2 +6,11 @@ "use strict"; | ||
var restrictions_1 = require("./restrictions"); | ||
var metainfo_1 = require("./metainfo"); | ||
var typesystem_1 = require("./typesystem"); | ||
var XML_ERRORS = '@unexpected_root_attributes_and_elements'; | ||
var bodyNames = [ | ||
'application/x-www-form-urlencoded', | ||
'application/json', | ||
'application/xml', | ||
'multipart/form-data' | ||
]; | ||
function readObject(content, t) { | ||
@@ -12,3 +21,3 @@ var result = null; | ||
opts.explicitArray = false; | ||
opts.explicitRoot = isSchema(t); | ||
opts.explicitRoot = isSchema(t) || !t.isExternal(); | ||
xml2js.parseString(content, opts, function (err, res) { | ||
@@ -20,6 +29,36 @@ result = res; | ||
}); | ||
result = postProcess(result, t); | ||
result = isSchema(t) ? result : postProcess(result, actualType(t)); | ||
return result; | ||
} | ||
exports.readObject = readObject; | ||
function getXmlErrors(root) { | ||
var errors = root[XML_ERRORS]; | ||
delete root[XML_ERRORS]; | ||
if (!errors || errors.length === 0) { | ||
return null; | ||
} | ||
return errors.map(function (error) { return new typesystem_1.Status(typesystem_1.Status.ERROR, 0, error, {}); }); | ||
} | ||
exports.getXmlErrors = getXmlErrors; | ||
function actualType(type) { | ||
if (!type) { | ||
return type; | ||
} | ||
if (isBodyLike(type)) { | ||
if (!type.superTypes() || type.superTypes().length === 0) { | ||
return type; | ||
} | ||
if (type.superTypes().length === 1) { | ||
return type.superTypes()[0]; | ||
} | ||
return _.find(type.allSuperTypes(), function (superType) { return superType.name() === 'object'; }) || type; | ||
} | ||
return type; | ||
} | ||
function isBodyLike(type) { | ||
if (!type) { | ||
return false; | ||
} | ||
return _.find(bodyNames, function (name) { return type.name() === name; }) ? true : false; | ||
} | ||
function isSchema(t) { | ||
@@ -37,29 +76,215 @@ if (isXmlContent(t)) { | ||
} | ||
function postProcess(result, t) { | ||
t.meta().forEach(function (x) { | ||
if (x instanceof restrictions_1.PropertyIs) { | ||
var pi = x; | ||
if (pi.value().isNumber()) { | ||
if (result.hasOwnProperty(pi.propertyName())) { | ||
var vl = parseFloat(result[pi.propertyName()]); | ||
if (!isNaN(vl)) { | ||
result[pi.propertyName()] = vl; | ||
} | ||
} | ||
} | ||
if (pi.value().isBoolean()) { | ||
if (result.hasOwnProperty(pi.propertyName())) { | ||
var bvl = result[pi.propertyName()]; | ||
if (bvl == "true") { | ||
result[pi.propertyName()] = true; | ||
} | ||
if (bvl == "false") { | ||
result[pi.propertyName()] = false; | ||
} | ||
} | ||
} | ||
function postProcess(result, type) { | ||
var rootNodeName = Object.keys(result)[0]; | ||
var rootNode = result[rootNodeName]; | ||
var errors = []; | ||
var expectedRootNodeName = rootXmlName(type); | ||
if (expectedRootNodeName !== rootNodeName) { | ||
errors.push('Unexpected root node "' + rootNodeName + '", "' + expectedRootNodeName + '" is expected.'); | ||
} | ||
var newJson; | ||
if (type.isArray()) { | ||
var expectedAttributeNames = []; | ||
var expectedElementNames = []; | ||
var componentMeta = type.meta().filter(function (metaInfo) { return metaInfo instanceof restrictions_1.ComponentShouldBeOfType; })[0]; | ||
var typeName = componentMeta && componentMeta.value().name(); | ||
expectedElementNames.push(typeName); | ||
newJson = getArray(rootNode, type, errors); | ||
fillExtras(rootNode, errors, expectedAttributeNames, expectedElementNames); | ||
} | ||
else { | ||
newJson = buildJson(rootNode, type.isUnion() ? selectFromUnion(rootNode, type) : type, errors); | ||
} | ||
newJson[XML_ERRORS] = errors; | ||
return newJson; | ||
} | ||
function checkErrors(rootNode, actualType) { | ||
var errors = []; | ||
var newJson; | ||
newJson = buildJson(rootNode, actualType, errors); | ||
var validationErrors = actualType.validateDirect(newJson, true, false).getErrors(); | ||
return errors.length + (validationErrors && validationErrors.length); | ||
} | ||
function selectFromUnion(rootNode, union) { | ||
var results = []; | ||
union.typeFamily().forEach(function (type) { return results.push({ type: type, errors: checkErrors(JSON.parse(JSON.stringify(rootNode)), type) }); }); | ||
if (results.length === 0) { | ||
return union; | ||
} | ||
var result = results[0]; | ||
results.forEach(function (oneOf) { | ||
if (oneOf.errors < result.errors) { | ||
result = oneOf; | ||
} | ||
}); | ||
return result.type; | ||
} | ||
function buildJson(node, type, errors) { | ||
var initialRoot = {}; | ||
if (!type) { | ||
return node; | ||
} | ||
if (type.isScalar()) { | ||
return toPrimitiveValue(type, node); | ||
} | ||
if (type.isUnion()) { | ||
return buildJson(node, selectFromUnion(node, type), errors); | ||
} | ||
var infos = getInfos(type); | ||
var expectedAttributeNames = []; | ||
var expectedElementNames = []; | ||
getAttributes(node, infos, expectedAttributeNames).forEach(function (attribute) { return initialRoot[Object.keys(attribute)[0]] = attribute[Object.keys(attribute)[0]]; }); | ||
getElements(node, infos, expectedElementNames, errors).forEach(function (element) { return initialRoot[Object.keys(element)[0]] = element[Object.keys(element)[0]]; }); | ||
fillExtras(node, errors, expectedAttributeNames, expectedElementNames); | ||
return initialRoot; | ||
} | ||
function fillExtras(node, errors, expectedAttributeNames, expectedElementNames) { | ||
if (typeof node !== "object") { | ||
return; | ||
} | ||
if (!node['$']) { | ||
node['$'] = {}; | ||
} | ||
expectedAttributeNames.forEach(function (name) { | ||
delete node['$'][name]; | ||
}); | ||
expectedElementNames.forEach(function (name) { | ||
delete node[name]; | ||
}); | ||
var extraAttributes = Object.keys(node['$']); | ||
delete node['$']; | ||
var extraElements = Object.keys(node); | ||
extraAttributes.forEach(function (name) { | ||
errors.push('Unexpected attribute "' + name + '".'); | ||
}); | ||
extraElements.forEach(function (name) { | ||
errors.push('Unexpected element "' + name + '".'); | ||
}); | ||
} | ||
function getInfos(type) { | ||
return type.meta().filter(function (info) { return info instanceof restrictions_1.PropertyIs; }).map(function (info) { return info; }) || []; | ||
} | ||
function getAttributes(node, infos, expectedNames) { | ||
var nodeAttributes = node['$']; | ||
if (!nodeAttributes) { | ||
return []; | ||
} | ||
var attributeInfos = _.filter(infos, function (info) { return xmlDescriptor(info.value()).attribute; }); | ||
return attributeInfos.map(function (info) { | ||
var attribute = {}; | ||
var key = info.propId(); | ||
var xmlKey = xmlName(info); | ||
expectedNames.push(xmlKey); | ||
var value = nodeAttributes[xmlKey]; | ||
attribute[key] = toPrimitiveValue(info.value(), value); | ||
return attribute[key] === null ? null : attribute; | ||
}).filter(function (attribute) { return attribute; }); | ||
} | ||
function getElements(node, infos, expectedNames, errors) { | ||
var elementInfos = _.filter(infos, function (info) { return !xmlDescriptor(info.value()).attribute; }); | ||
return elementInfos.map(function (info) { | ||
var element = {}; | ||
var descriptor = xmlDescriptor(info.value()); | ||
var key = info.propId(); | ||
var xmlKey = xmlName(info); | ||
expectedNames.push(xmlKey); | ||
var value = node[xmlKey]; | ||
if (info.value().isArray()) { | ||
element[key] = getArray(node[xmlKey], info.value(), errors); | ||
} | ||
else { | ||
element[key] = (value || value === '') ? buildJson(value, info.value(), errors) : null; | ||
} | ||
return element[key] === null ? null : element; | ||
}).filter(function (info) { return info; }); | ||
} | ||
function getArray(values, type, errors) { | ||
var descriptor = xmlDescriptor(type); | ||
var isWrapped = descriptor.wrapped; | ||
var componentType = arrayElementType(type); | ||
var typeName = componentType && componentType.name(); | ||
values = isArray(values) ? values : ((Object.keys(values).length === 1 && [values[Object.keys(values)[0]]]) || values); | ||
if (isArray(values)) { | ||
values = values.map(function (value) { return buildJson(value, componentType, errors); }); | ||
} | ||
else { | ||
values = (typeof values === 'object' && values) || []; | ||
} | ||
return values; | ||
} | ||
function arrayElementType(arrayType) { | ||
if (!arrayType || !arrayType.isArray()) { | ||
return null; | ||
} | ||
var componentMetas = arrayType.meta().filter(function (metaInfo) { return metaInfo instanceof restrictions_1.ComponentShouldBeOfType; }); | ||
return componentMetas && componentMetas.length > 0 && componentMetas[0].value(); | ||
} | ||
function xmlName(property) { | ||
var descriptor = xmlDescriptor(property.value()); | ||
var ramlName = (property.value() && property.value().isArray() && !descriptor.wrapped) ? arrayElementType(property.value()).name() : property.propId(); | ||
var actualName = descriptor.name || ramlName; | ||
if (descriptor.namespace) { | ||
actualName = descriptor.namespace + ':' + actualName; | ||
} | ||
return (descriptor.prefix || '') + actualName; | ||
} | ||
function rootXmlName(type) { | ||
var descriptor = xmlDescriptor(type); | ||
var ramlName = type.name(); | ||
if (ramlName === '' && type.isUnion()) { | ||
ramlName = 'object'; | ||
} | ||
var actualName = descriptor.name || ramlName; | ||
return (descriptor.prefix || '') + actualName; | ||
} | ||
function xmlDescriptor(type) { | ||
var info = type.meta().filter(function (xmlInfo) { return xmlInfo instanceof metainfo_1.XMLInfo; }).map(function (xmlInfo) { return xmlInfo; })[0]; | ||
var result = { | ||
attribute: false, | ||
wrapped: false, | ||
name: false, | ||
namespace: false, | ||
prefix: false | ||
}; | ||
if (!info) { | ||
return result; | ||
} | ||
var infoValue = info.value(); | ||
if (!infoValue) { | ||
return result; | ||
} | ||
Object.keys(result).forEach(function (key) { | ||
result[key] = infoValue[key] || result[key]; | ||
}); | ||
return result; | ||
} | ||
function toPrimitiveValue(type, actual) { | ||
if (typeof actual === 'object') { | ||
return null; | ||
} | ||
if (!actual) { | ||
return null; | ||
} | ||
if (type.isNumber()) { | ||
var parsedValue = parseFloat(actual); | ||
if (!isNaN(parsedValue)) { | ||
return parsedValue; | ||
} | ||
} | ||
if (type.isBoolean()) { | ||
if (actual === 'true') { | ||
return true; | ||
} | ||
if (actual === 'false') { | ||
return false; | ||
} | ||
} | ||
return (typeof actual === 'string' && (actual || '')) || null; | ||
} | ||
function isArray(instance) { | ||
if (!instance) { | ||
return false; | ||
} | ||
return typeof instance === 'object' && typeof instance.length === 'number'; | ||
} | ||
//# sourceMappingURL=xmlio.js.map |
@@ -63,5 +63,46 @@ "use strict"; | ||
function jsonToXml(jsonObject) { | ||
var nodeName = jsonObject && Object.keys(jsonObject)[0]; | ||
if (nodeName) { | ||
var root = jsonObject[nodeName]; | ||
checkAttributes(root); | ||
} | ||
return objectToXml(jsonObject); | ||
} | ||
exports.jsonToXml = jsonToXml; | ||
function checkAttributes(root) { | ||
if (!root || typeof root === 'string') { | ||
return; | ||
} | ||
var attributes = []; | ||
Object.keys(root).forEach(function (key) { | ||
if (key.indexOf('@') === 0) { | ||
var attribute = { key: key, value: root[key] }; | ||
attributes.push(attribute); | ||
} | ||
else { | ||
if (isArray(root[key])) { | ||
var elements = root[key]; | ||
elements.forEach(function (element) { return checkAttributes(element); }); | ||
} | ||
else if (typeof root[key] !== 'string') { | ||
checkAttributes(root[key]); | ||
} | ||
} | ||
}); | ||
if (!root['$']) { | ||
root['$'] = {}; | ||
} | ||
var newAttributes = root['$']; | ||
attributes.forEach(function (attribute) { | ||
delete root[attribute.key]; | ||
var newKey = attribute.key.substring(1); | ||
newAttributes[newKey] = attribute.value; | ||
}); | ||
} | ||
function isArray(instance) { | ||
if (!instance) { | ||
return false; | ||
} | ||
return typeof instance === 'object' && typeof instance.length === 'number'; | ||
} | ||
//# sourceMappingURL=xmlUtil.js.map |
@@ -10,2 +10,8 @@ /// <reference path="../../typings/main.d.ts" /> | ||
isAbsolutePath(uri: string): boolean; | ||
contentAsync(reference: string): Promise; | ||
promiseResolve(arg: any): Promise; | ||
} | ||
export interface Promise { | ||
then(instance: any): any; | ||
resolve(arg: any): any; | ||
} |
@@ -85,2 +85,15 @@ "use strict"; | ||
}; | ||
ContentProvider.prototype.contentAsync = function (reference) { | ||
var _this = this; | ||
return { | ||
then: function (arg) { return arg(_this.content(reference)); }, | ||
resolve: function () { return null; } | ||
}; | ||
}; | ||
ContentProvider.prototype.promiseResolve = function (arg) { | ||
return { | ||
then: function (arg1) { return arg1(arg); }, | ||
resolve: function () { return null; } | ||
}; | ||
}; | ||
return ContentProvider; | ||
@@ -87,0 +100,0 @@ }()); |
@@ -257,3 +257,24 @@ "use strict"; | ||
}); | ||
it("example object ", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
types: { | ||
XX: { | ||
type: "object", | ||
properties: { | ||
name: { | ||
type: "string", | ||
example: "Pavel" | ||
}, | ||
fr: "XX" | ||
} | ||
} | ||
} | ||
}); | ||
var t = tp.getType("XX"); | ||
var nt = nm.toNominal(t, function (x) { return null; }); | ||
var p = nt.examples()[0]; | ||
assert.isTrue(p.isEmpty()); | ||
assert.deepEqual(p.asJSON(), { name: "Pavel", fr: null }); | ||
}); | ||
}); | ||
//# sourceMappingURL=exampleBuilderTests.js.map |
{ | ||
"name": "raml-typesystem", | ||
"version": "0.0.27-rc2", | ||
"version": "0.0.28-rc2", | ||
"main": "dist/src/index.js", | ||
@@ -5,0 +5,0 @@ "scripts": { |
@@ -6,2 +6,3 @@ import rt=require("./typesystem") | ||
import nm=require("./nominal-types") | ||
const exCalcFlag="exampleCalculation"; | ||
export function example(t:rt.AbstractType):any{ | ||
@@ -12,53 +13,61 @@ var ms=t.oneMeta(meta.Example); | ||
} | ||
var ms1=t.oneMeta(meta.Examples); | ||
if (ms1){ | ||
var examples=ms1.examples(); | ||
if (examples&&examples.length>0){ | ||
return examples[0]; | ||
} | ||
if (t.getExtra(exCalcFlag)){ | ||
return null; | ||
} | ||
var d=t.oneMeta(meta.Default); | ||
if (d){ | ||
return d.value(); | ||
} | ||
if (t.isObject()){ | ||
var result:any={}; | ||
t.meta().forEach(x=>{ | ||
if (x instanceof PropertyIs){ | ||
var p:PropertyIs=x; | ||
var ex=example(p.value()); | ||
result[p.propertyName()]=ex; | ||
t.putExtra(exCalcFlag,true) | ||
try { | ||
var ms1 = t.oneMeta(meta.Examples); | ||
if (ms1) { | ||
var examples = ms1.examples(); | ||
if (examples && examples.length > 0) { | ||
return examples[0]; | ||
} | ||
}) | ||
t.superTypes().forEach(x=>{ | ||
if (x.oneMeta(meta.Example)|| x.oneMeta(meta.Examples)) { | ||
var ex=example(x); | ||
if (ex && typeof ex === "object") { | ||
Object.keys(ex).forEach(key=> { | ||
result[key] = ex[key] | ||
}) | ||
} | ||
var d = t.oneMeta(meta.Default); | ||
if (d) { | ||
return d.value(); | ||
} | ||
if (t.isObject()) { | ||
var result:any = {}; | ||
t.meta().forEach(x=> { | ||
if (x instanceof PropertyIs) { | ||
var p:PropertyIs = x; | ||
var ex = example(p.value()); | ||
result[p.propertyName()] = ex; | ||
} | ||
}) | ||
t.superTypes().forEach(x=> { | ||
if (x.oneMeta(meta.Example) || x.oneMeta(meta.Examples)) { | ||
var ex = example(x); | ||
if (ex && typeof ex === "object") { | ||
Object.keys(ex).forEach(key=> { | ||
result[key] = ex[key] | ||
}) | ||
} | ||
} | ||
}) | ||
return result; | ||
} | ||
if (t.isArray()) { | ||
var c = t.oneMeta(ComponentShouldBeOfType); | ||
var resultArray:any[] = []; | ||
if (c) { | ||
resultArray.push(example(c.value())); | ||
} | ||
}) | ||
return result; | ||
} | ||
if (t.isArray()){ | ||
var c=t.oneMeta(ComponentShouldBeOfType); | ||
var resultArray:any[]=[]; | ||
if (c){ | ||
resultArray.push(example(c.value())); | ||
return resultArray; | ||
} | ||
return resultArray; | ||
} | ||
if (t.isUnion()){ | ||
return example(t.typeFamily()[0]); | ||
} | ||
if (t.isNumber()){ | ||
return 1; | ||
} | ||
if (t.isUnion()) { | ||
return example(t.typeFamily()[0]); | ||
} | ||
if (t.isNumber()) { | ||
return 1; | ||
} | ||
if (t.isBoolean()){ | ||
return true; | ||
if (t.isBoolean()) { | ||
return true; | ||
} | ||
return "some value"; | ||
} finally{ | ||
t.putExtra(exCalcFlag,false) | ||
} | ||
return "some value"; | ||
} | ||
@@ -65,0 +74,0 @@ class Example implements nm.IExpandableExample{ |
@@ -12,4 +12,5 @@ import ts=require("./typesystem") | ||
import schemaUtil = require('./schemaUtil'); | ||
export interface IValidationPath{ | ||
name: string | ||
@@ -19,2 +20,7 @@ child?:IValidationPath | ||
} | ||
export function getSchemaUtils(): any { | ||
return schemaUtil; | ||
} | ||
export interface IStatus { | ||
@@ -21,0 +27,0 @@ |
@@ -103,6 +103,6 @@ /// <reference path="../typings/main.d.ts" /> | ||
if (typeof val==='string'){ | ||
if (type.isObject()||type.isArray()||type.isExternal()){ | ||
if (type.isObject() || type.isArray() || type.isExternal() || type.isUnion()){ | ||
var exampleString:string=val; | ||
var firstChar = exampleString.trim().charAt(0); | ||
if (firstChar=="{"||firstChar=="[") { | ||
if ((firstChar=="{" || firstChar=="[") && !type.isUnion()) { | ||
try { | ||
@@ -119,3 +119,15 @@ return JSON.parse(exampleString); | ||
try { | ||
return xmlio.readObject(exampleString,type); | ||
var jsonFromXml = xmlio.readObject(exampleString,type); | ||
var errors: Status[] = xmlio.getXmlErrors(jsonFromXml); | ||
if(errors) { | ||
var error = new Status(Status.ERROR, 0, 'Invalid XML.', {}); | ||
errors.forEach(child => error.addSubStatus(child)); | ||
return error; | ||
} | ||
return jsonFromXml; | ||
} catch (e) { | ||
@@ -122,0 +134,0 @@ |
@@ -311,3 +311,3 @@ export interface INamedEntity{ | ||
/** | ||
* Returns whether this type contain genuine user defined type in its hierarchy. | ||
* Returns whether this type is genuine user defined type. | ||
* Genuine user defined type is a type user intentionally defined and filled with | ||
@@ -319,2 +319,9 @@ * properties or facets, or having user-defined name as opposed to a synthetic user-defined type. | ||
/** | ||
* Returns whether this type contain genuine user defined type in its hierarchy. | ||
* Genuine user defined type is a type user intentionally defined and filled with | ||
* properties or facets, or having user-defined name as opposed to a synthetic user-defined type. | ||
*/ | ||
hasGenuineUserDefinedTypeInHierarchy() : boolean; | ||
/** | ||
* Returns nearest genuine user-define type in the hierarchy. | ||
@@ -324,3 +331,3 @@ * Genuine user defined type is a type user intentionally defined and filled with | ||
*/ | ||
genuineUserDefinedType() : ITypeDefinition; | ||
genuineUserDefinedTypeInHierarchy() : ITypeDefinition; | ||
@@ -327,0 +334,0 @@ kind():string[]; |
@@ -51,2 +51,6 @@ import ti = require("./nominal-interfaces") | ||
} | ||
getAdapters() : any[] { | ||
return this.adapters; | ||
} | ||
} | ||
@@ -577,3 +581,9 @@ export class Described extends Adaptable{ | ||
isGenuineUserDefinedType() : boolean { | ||
return this.nameId()&&this.nameId().length>0&&!this.buildIn; | ||
if (this.buildIn) return false; | ||
if (this.properties() && this.properties().length > 0) return true; | ||
if (this.getFixedFacets() && Object.keys(this.getFixedFacets()).length > 0) return true; | ||
return this.isTopLevel()&&this.nameId()&&this.nameId().length>0; | ||
} | ||
@@ -586,11 +596,38 @@ | ||
*/ | ||
genuineUserDefinedType() : ITypeDefinition { | ||
if (this.getAdapter(Empty)){ | ||
if (this.superTypes().length==1){ | ||
return this.superTypes()[0]; | ||
genuineUserDefinedTypeInHierarchy() : ITypeDefinition { | ||
if (this.isGenuineUserDefinedType()) return this; | ||
var result:ITypeDefinition=null; | ||
var allSuperTypes=this.allSuperTypes(); | ||
allSuperTypes.forEach(currentSuperType=>{ | ||
if (!result && currentSuperType.isGenuineUserDefinedType()){ | ||
result = currentSuperType; | ||
} | ||
} | ||
return this; | ||
}); | ||
return result; | ||
} | ||
/** | ||
* Returns whether this type contain genuine user defined type in its hierarchy. | ||
* Genuine user defined type is a type user intentionally defined and filled with | ||
* properties or facets, or having user-defined name as opposed to a synthetic user-defined type. | ||
*/ | ||
hasGenuineUserDefinedTypeInHierarchy() : boolean { | ||
return _.find(this.allSuperTypes(),x=>{ | ||
var mm=<any>x; | ||
if (mm.uc){ | ||
return false; | ||
} | ||
mm.uc=true; | ||
try{ | ||
return x.isGenuineUserDefinedType() | ||
}finally{ | ||
mm.uc=false | ||
} | ||
})!=null; | ||
} | ||
customProperties():IProperty[]{ | ||
@@ -688,2 +725,23 @@ return [].concat(this._customProperties) | ||
} | ||
isBuiltIn() { | ||
return this.buildIn; | ||
} | ||
setBuiltIn(builtIn : boolean) { | ||
this.buildIn = builtIn; | ||
} | ||
private isTopLevel() : boolean { | ||
if(this.getAdapters() && _.find(this.getAdapters(), adapter=>{ | ||
// return adapter.getExtra && adapter.getExtra("topLevel"); | ||
//TODO determine whether "topLevel" actually means a simple top-level type and | ||
//this flag is absent due to a bug | ||
return adapter.getExtra && (adapter.getExtra("definedInTypes") || adapter.getExtra("topLevel")); | ||
})) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
} | ||
@@ -690,0 +748,0 @@ export class ValueType extends AbstractType implements ITypeDefinition{ |
@@ -25,4 +25,3 @@ import ts=require("./typesystem") | ||
export interface TypeCustomizer{ | ||
export interface TypeCustomizer { | ||
constructProperty(n:string):nt.Property; | ||
@@ -29,0 +28,0 @@ findCustomizer(t:ts.AbstractType):TypeCustomizer; |
@@ -32,2 +32,8 @@ /// <reference path="../typings/main.d.ts" /> | ||
export interface Promise { | ||
then(instance: any): any; | ||
resolve(arg: any): any; | ||
} | ||
export interface IContentProvider { | ||
@@ -45,2 +51,6 @@ contextPath(): string; | ||
isAbsolutePath(uri: string): boolean; | ||
contentAsync(arg: any): Promise; | ||
promiseResolve(arg: any): Promise; | ||
} | ||
@@ -72,2 +82,18 @@ | ||
} | ||
contentAsync(reference: string): Promise { | ||
return { | ||
then: arg => arg(this.content(reference)), | ||
resolve: () => null | ||
}; | ||
} | ||
promiseResolve(arg: any): Promise { | ||
return { | ||
then: arg1 => arg1(arg), | ||
resolve: () => null | ||
} | ||
} | ||
} | ||
@@ -133,3 +159,8 @@ | ||
validator.validateSchema(this.jsonSchema); | ||
try { | ||
validator.validateSchema(this.jsonSchema); | ||
} catch (Error) { | ||
//we should never be exploding here, instead we'll report this error later | ||
return [] | ||
} | ||
@@ -332,2 +363,40 @@ var result = <any[]>validator.getMissingRemoteReferences(); | ||
} | ||
contentAsync(reference: any): Promise { | ||
var remoteSchemeContent: any; | ||
var api: any = require('json-schema-compatibility'); | ||
var contentPromise = this.provider.contentAsync(reference); | ||
if(!contentPromise) { | ||
return this.provider.promiseResolve({ | ||
reference: reference, | ||
content: null, | ||
error: new Error('Reference not found: ' + reference) | ||
}); | ||
} | ||
var result = contentPromise.then((cnt: any) => { | ||
var content: any = {reference: reference}; | ||
try { | ||
var jsonObject = JSON.parse(cnt); | ||
this.setupId(jsonObject, this.provider.normalizePath(reference)); | ||
remoteSchemeContent = api.v4(jsonObject); | ||
delete remoteSchemeContent['$schema']; | ||
content.content = remoteSchemeContent; | ||
} catch(exception) { | ||
content.error = exception; | ||
} | ||
return content; | ||
}); | ||
return result; | ||
} | ||
} | ||
@@ -334,0 +403,0 @@ export interface ValidationError{ |
@@ -454,6 +454,9 @@ /// <reference path="../typings/main.d.ts" /> | ||
} | ||
if (this.getExtra(SCHEMA_AND_TYPE)){ | ||
rs.addSubStatus(new Status(Status.ERROR,0, "schema and type are mutually exclusive",this)); | ||
} | ||
this.validateMeta(tr).getErrors().forEach(x=>rs.addSubStatus(x)); | ||
if (rs.isOk()) { | ||
this.validateMeta(tr).getErrors().forEach(x=>rs.addSubStatus(x)); | ||
} | ||
//if (this.isPolymorphic()||(this.isUnion())) { | ||
@@ -516,6 +519,9 @@ // rs.addSubStatus(this.canDoAc()); | ||
if (this.isArray()) { | ||
var fs=this.familyWithArray(); | ||
if ((fs.indexOf(this)!=-1)||fs.some(x=>x===UNKNOWN||x===RECURRENT)){ | ||
const fs=this.familyWithArray(); | ||
if ((fs.indexOf(this)!=-1)||fs.some(x=>x===RECURRENT)){ | ||
rs.addSubStatus(new Status(Status.ERROR, 0, "recurrent array type definition",this)) | ||
} | ||
else if (fs.some(x=>x===UNKNOWN)){ | ||
rs.addSubStatus(new Status(Status.ERROR, 0, "referring to unknown type "+this.oneMeta(ComponentShouldBeOfType).value().name()+" as an array component type",this)) | ||
} | ||
} | ||
@@ -522,0 +528,0 @@ var supers=this.superTypes(); |
386
src/xmlio.ts
@@ -6,4 +6,15 @@ /// <reference path="../typings/main.d.ts" /> | ||
import {PropertyIs} from "./restrictions"; | ||
import {PropertyIs, ComponentShouldBeOfType} from "./restrictions"; | ||
import {XMLInfo} from "./metainfo"; | ||
import {Status} from "./typesystem"; | ||
var XML_ERRORS = '@unexpected_root_attributes_and_elements'; | ||
var bodyNames: string[] = [ | ||
'application/x-www-form-urlencoded', | ||
'application/json', | ||
'application/xml', | ||
'multipart/form-data' | ||
]; | ||
export function readObject(content:string,t:ts.AbstractType):any{ | ||
@@ -14,3 +25,3 @@ var result:any=null; | ||
opts.explicitArray=false; | ||
opts.explicitRoot= isSchema(t); | ||
opts.explicitRoot= isSchema(t) || !t.isExternal(); | ||
xml2js.parseString(content,opts,function (err,res){ | ||
@@ -22,6 +33,46 @@ result=res; | ||
}); | ||
result=postProcess(result,t); | ||
result = isSchema(t) ? result: postProcess(result, actualType(t)); | ||
return result; | ||
} | ||
export function getXmlErrors(root: any): Status[] { | ||
var errors: any[] = root[XML_ERRORS]; | ||
delete root[XML_ERRORS]; | ||
if(!errors || errors.length === 0) { | ||
return null; | ||
} | ||
return errors.map(error => new Status(Status.ERROR, 0, <string>error, {})) | ||
} | ||
function actualType(type: ts.AbstractType): ts.AbstractType { | ||
if(!type) { | ||
return type; | ||
} | ||
if(isBodyLike(type)) { | ||
if(!type.superTypes() || type.superTypes().length === 0) { | ||
return type; | ||
} | ||
if(type.superTypes().length === 1) { | ||
return type.superTypes()[0]; | ||
} | ||
return _.find(type.allSuperTypes(), superType => superType.name() === 'object') || type; | ||
} | ||
return type; | ||
} | ||
function isBodyLike(type: ts.AbstractType): boolean { | ||
if(!type) { | ||
return false; | ||
} | ||
return _.find(bodyNames, name => type.name() === name) ? true : false; | ||
} | ||
function isSchema(t: ts.AbstractType): boolean { | ||
@@ -43,28 +94,311 @@ if(isXmlContent(t)) { | ||
function postProcess(result:any,t:ts.AbstractType):any{ | ||
t.meta().forEach(x=>{ | ||
if (x instanceof PropertyIs){ | ||
var pi:PropertyIs=x; | ||
if (pi.value().isNumber()){ | ||
if (result.hasOwnProperty(pi.propertyName())){ | ||
var vl=parseFloat(result[pi.propertyName()]); | ||
if (!isNaN(vl)){ | ||
result[pi.propertyName()]=vl; | ||
} | ||
} | ||
} | ||
if (pi.value().isBoolean()){ | ||
if (result.hasOwnProperty(pi.propertyName())){ | ||
var bvl=result[pi.propertyName()]; | ||
if (bvl=="true"){ | ||
result[pi.propertyName()]=true; | ||
} | ||
if (bvl=="false"){ | ||
result[pi.propertyName()]=false; | ||
} | ||
} | ||
} | ||
function postProcess(result: any, type: ts.AbstractType):any{ | ||
var rootNodeName = Object.keys(result)[0]; | ||
var rootNode = result[rootNodeName]; | ||
var errors: string[] = []; | ||
var expectedRootNodeName = rootXmlName(type); | ||
if(expectedRootNodeName !== rootNodeName) { | ||
errors.push('Unexpected root node "' + rootNodeName + '", "' + expectedRootNodeName + '" is expected.'); | ||
} | ||
var newJson: any; | ||
if(type.isArray()) { | ||
var expectedAttributeNames: string[] = []; | ||
var expectedElementNames: string[] = []; | ||
var componentMeta = type.meta().filter(metaInfo => metaInfo instanceof ComponentShouldBeOfType)[0]; | ||
var typeName = componentMeta && componentMeta.value().name(); | ||
expectedElementNames.push(typeName); | ||
newJson = getArray(rootNode, type, errors); | ||
fillExtras(rootNode, errors, expectedAttributeNames, expectedElementNames); | ||
} else { | ||
newJson = buildJson(rootNode, type.isUnion() ? selectFromUnion(rootNode, type) : type, errors); | ||
} | ||
newJson[XML_ERRORS] = errors; | ||
return newJson; | ||
} | ||
function checkErrors(rootNode: any, actualType: ts.AbstractType): number { | ||
var errors: string[] = []; | ||
var newJson: any; | ||
newJson = buildJson(rootNode, actualType, errors); | ||
var validationErrors = actualType.validateDirect(newJson, true, false).getErrors(); | ||
return errors.length + (validationErrors && validationErrors.length); | ||
} | ||
function selectFromUnion(rootNode: any, union: ts.AbstractType): ts.AbstractType { | ||
var results: any[] = []; | ||
union.typeFamily().forEach(type => results.push({type: type, errors: checkErrors(JSON.parse(JSON.stringify(rootNode)), type)})); | ||
if(results.length === 0) { | ||
return union; | ||
} | ||
var result: any = results[0]; | ||
results.forEach((oneOf: any) => { | ||
if(oneOf.errors < result.errors) { | ||
result = oneOf; | ||
} | ||
}); | ||
return result.type; | ||
} | ||
function buildJson(node: any, type: ts.AbstractType, errors: string[]): any { | ||
var initialRoot: any = { | ||
}; | ||
if(!type) { | ||
return node; | ||
} | ||
if(type.isScalar()) { | ||
return toPrimitiveValue(type, node); | ||
} | ||
if(type.isUnion()) { | ||
return buildJson(node, selectFromUnion(node, type), errors); | ||
} | ||
var infos: PropertyIs[] = getInfos(type); | ||
var expectedAttributeNames: string[] = []; | ||
var expectedElementNames: string[] = []; | ||
getAttributes(node, infos, expectedAttributeNames).forEach(attribute => initialRoot[Object.keys(attribute)[0]] = attribute[Object.keys(attribute)[0]]); | ||
getElements(node, infos, expectedElementNames, errors).forEach(element => initialRoot[Object.keys(element)[0]] = element[Object.keys(element)[0]]); | ||
fillExtras(node, errors, expectedAttributeNames, expectedElementNames); | ||
return initialRoot; | ||
} | ||
function fillExtras(node: any, errors: string[], expectedAttributeNames: string[], expectedElementNames: string[]) { | ||
if(typeof node !== "object") { | ||
return; | ||
} | ||
if(!node['$']) { | ||
node['$'] = {}; | ||
} | ||
expectedAttributeNames.forEach(name => { | ||
delete node['$'][name]; | ||
}); | ||
expectedElementNames.forEach(name => { | ||
delete node[name]; | ||
}); | ||
var extraAttributes = Object.keys(node['$']); | ||
delete node['$']; | ||
var extraElements = Object.keys(node); | ||
extraAttributes.forEach(name => { | ||
errors.push('Unexpected attribute "' + name + '".'); | ||
}); | ||
extraElements.forEach(name => { | ||
errors.push('Unexpected element "' + name + '".'); | ||
}); | ||
} | ||
function getInfos(type: ts.AbstractType): PropertyIs[] { | ||
return type.meta().filter((info: any) => info instanceof PropertyIs).map((info: any) => <PropertyIs>info) || []; | ||
} | ||
function getAttributes(node: any, infos: PropertyIs[], expectedNames: string[]): any[] { | ||
var nodeAttributes: any = node['$']; | ||
if(!nodeAttributes) { | ||
return []; | ||
} | ||
var attributeInfos: PropertyIs[] = _.filter(infos, info => xmlDescriptor(info.value()).attribute); | ||
return attributeInfos.map(info => { | ||
var attribute: any = {}; | ||
var key = info.propId(); | ||
var xmlKey = xmlName(info); | ||
expectedNames.push(xmlKey); | ||
var value = nodeAttributes[xmlKey]; | ||
attribute[key] = toPrimitiveValue(info.value(), value); | ||
return attribute[key] === null ? null : attribute; | ||
}).filter((attribute: any) => attribute); | ||
} | ||
function getElements(node: any, infos: PropertyIs[], expectedNames: string[], errors: string[]): any[] { | ||
var elementInfos: PropertyIs[] = _.filter(infos, info => !xmlDescriptor(info.value()).attribute); | ||
return elementInfos.map(info => { | ||
var element: any = {}; | ||
var descriptor = xmlDescriptor(info.value()); | ||
var key = info.propId(); | ||
var xmlKey = xmlName(info); | ||
expectedNames.push(xmlKey); | ||
var value = node[xmlKey]; | ||
if(info.value().isArray()) { | ||
element[key] = getArray(node[xmlKey], info.value(), errors); | ||
} else { | ||
element[key] = (value || value === '') ? buildJson(value, info.value(), errors) : null; | ||
} | ||
return element[key] === null ? null : element; | ||
}).filter((info: any) => info); | ||
} | ||
function getArray(values: any, type: ts.AbstractType, errors: string[]) { | ||
var descriptor = xmlDescriptor(type); | ||
var isWrapped = descriptor.wrapped; | ||
var componentType = arrayElementType(type); | ||
var typeName = componentType && componentType.name(); | ||
values = isArray(values) ? values : ((Object.keys(values).length === 1 && [values[Object.keys(values)[0]]]) || values); | ||
if(isArray(values)) { | ||
values = values.map((value: any) => buildJson(value, componentType, errors)) | ||
} else { | ||
values = (typeof values === 'object' && values) || []; | ||
} | ||
return values; | ||
} | ||
function arrayElementType(arrayType: ts.AbstractType) { | ||
if(!arrayType || !arrayType.isArray()) { | ||
return null; | ||
} | ||
var componentMetas: ComponentShouldBeOfType[] = <ComponentShouldBeOfType[]>arrayType.meta().filter(metaInfo => metaInfo instanceof ComponentShouldBeOfType); | ||
return componentMetas && componentMetas.length > 0 && componentMetas[0].value(); | ||
} | ||
function xmlName(property: PropertyIs): string { | ||
var descriptor: any = xmlDescriptor(property.value()); | ||
var ramlName: string = (property.value() && property.value().isArray() && !descriptor.wrapped) ? arrayElementType(property.value()).name() : property.propId(); | ||
var actualName = descriptor.name || ramlName; | ||
if(descriptor.namespace) { | ||
actualName = descriptor.namespace + ':' + actualName; | ||
} | ||
return (descriptor.prefix || '') + actualName; | ||
} | ||
function rootXmlName(type: ts.AbstractType): string { | ||
var descriptor: any = xmlDescriptor(type); | ||
var ramlName: string = type.name(); | ||
if(ramlName === '' && type.isUnion()) { | ||
ramlName = 'object' | ||
} | ||
var actualName = descriptor.name || ramlName; | ||
return (descriptor.prefix || '') + actualName; | ||
} | ||
function xmlDescriptor(type: ts.AbstractType): any { | ||
var info: XMLInfo = type.meta().filter((xmlInfo: any) => xmlInfo instanceof XMLInfo).map((xmlInfo: any) => <XMLInfo>xmlInfo)[0]; | ||
var result: any = { | ||
attribute: false, | ||
wrapped: false, | ||
name: false, | ||
namespace: false, | ||
prefix: false | ||
} | ||
if(!info) { | ||
return result; | ||
} | ||
var infoValue = info.value(); | ||
if(!infoValue) { | ||
return result; | ||
} | ||
Object.keys(result).forEach((key: string) => { | ||
result[key] = infoValue[key] || result[key]; | ||
}); | ||
return result; | ||
} | ||
function toPrimitiveValue(type: ts.AbstractType, actual: any): any { | ||
if(typeof actual === 'object') { | ||
return null; | ||
} | ||
if(!actual) { | ||
return null; | ||
} | ||
if(type.isNumber()) { | ||
var parsedValue:number = parseFloat(actual); | ||
if(!isNaN(parsedValue)) { | ||
return parsedValue; | ||
} | ||
} | ||
if(type.isBoolean()) { | ||
if (actual === 'true') { | ||
return true; | ||
} | ||
if (actual === 'false') { | ||
return false; | ||
} | ||
} | ||
return (typeof actual === 'string' && (actual || '')) || null; | ||
} | ||
function isArray(instance: any): boolean { | ||
if(!instance) { | ||
return false; | ||
} | ||
return typeof instance === 'object' && typeof instance.length === 'number'; | ||
} |
@@ -85,3 +85,57 @@ /// <reference path="../typings/main.d.ts" /> | ||
export function jsonToXml(jsonObject: any) { | ||
var nodeName = jsonObject && Object.keys(jsonObject)[0]; | ||
if(nodeName) { | ||
var root = jsonObject[nodeName]; | ||
checkAttributes(root); | ||
} | ||
return objectToXml(jsonObject); | ||
} | ||
function checkAttributes(root: any) { | ||
if(!root || typeof root === 'string') { | ||
return; | ||
} | ||
var attributes: any[] = []; | ||
Object.keys(root).forEach(key => { | ||
if(key.indexOf('@') === 0) { | ||
var attribute = {key: key, value: root[key]}; | ||
attributes.push(attribute); | ||
} else { | ||
if(isArray(root[key])) { | ||
var elements = root[key]; | ||
elements.forEach((element: any) => checkAttributes(element)); | ||
} else if(typeof root[key] !== 'string') { | ||
checkAttributes(root[key]); | ||
} | ||
} | ||
}); | ||
if(!root['$']) { | ||
root['$'] = {}; | ||
} | ||
var newAttributes = root['$']; | ||
attributes.forEach(attribute => { | ||
delete root[attribute.key]; | ||
var newKey: string = attribute.key.substring(1); | ||
newAttributes[newKey] = attribute.value; | ||
}); | ||
} | ||
function isArray(instance: any): boolean { | ||
if(!instance) { | ||
return false; | ||
} | ||
return typeof instance === 'object' && typeof instance.length === 'number'; | ||
} |
@@ -112,6 +112,28 @@ //import _ = require("underscore") | ||
} | ||
contentAsync(reference: string): Promise { | ||
return { | ||
then: arg => arg(this.content(reference)), | ||
resolve: () => null | ||
}; | ||
} | ||
promiseResolve(arg: any): Promise { | ||
return { | ||
then: arg1 => arg1(arg), | ||
resolve: () => null | ||
} | ||
} | ||
} | ||
export interface Promise { | ||
then(instance: any): any; | ||
resolve(arg: any): any; | ||
} | ||
function isWebPath(str: string):boolean { | ||
return false; | ||
} |
@@ -283,2 +283,25 @@ import ps= require("./actualParse") | ||
}); | ||
it("example object ", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
types:{ | ||
XX:{ | ||
type:"object", | ||
properties: | ||
{ | ||
name: { | ||
type: "string", | ||
example: "Pavel" | ||
}, | ||
fr:"XX" | ||
} | ||
} | ||
} | ||
}); | ||
var t=tp.getType("XX"); | ||
var nt=nm.toNominal(t,x=>null); | ||
var p=nt.examples()[0]; | ||
assert.isTrue(p.isEmpty()) | ||
assert.deepEqual(p.asJSON(),{ name: "Pavel",fr: null}); | ||
}); | ||
}) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
1712032
38782