raml-typesystem
Advanced tools
Comparing version 0.0.28-rc2 to 0.0.29-rc2
@@ -0,6 +1,8 @@ | ||
import tsInterfaces = require("./typesystem-interfaces"); | ||
export import nominalTypes = require("./nominal-types"); | ||
export interface IValidationPath { | ||
name: string; | ||
child?: IValidationPath; | ||
} | ||
export declare type IValidationPath = tsInterfaces.IValidationPath; | ||
export declare type IHasExtra = tsInterfaces.IHasExtra; | ||
export declare var TOP_LEVEL_EXTRA: string; | ||
export declare var DEFINED_IN_TYPES_EXTRA: string; | ||
export declare var USER_DEFINED_EXTRA: string; | ||
export declare function getSchemaUtils(): any; | ||
@@ -119,3 +121,3 @@ export interface IStatus { | ||
*/ | ||
export interface IParsedType { | ||
export interface IParsedType extends IHasExtra { | ||
/** | ||
@@ -122,0 +124,0 @@ * returns list of directly declared sub types of this type |
"use strict"; | ||
var ts = require("./typesystem"); | ||
var tsInterfaces = require("./typesystem-interfaces"); | ||
var tc = require("./parse"); | ||
@@ -12,2 +13,8 @@ var fr = require("./facetRegistry"); | ||
var schemaUtil = require('./schemaUtil'); | ||
exports.TOP_LEVEL_EXTRA = tsInterfaces.TOP_LEVEL_EXTRA; | ||
exports.DEFINED_IN_TYPES_EXTRA = tsInterfaces.DEFINED_IN_TYPES_EXTRA; | ||
exports.USER_DEFINED_EXTRA = tsInterfaces.USER_DEFINED_EXTRA; | ||
// export function instanceOfHasExtra(instance : nominalTypes.ITypeDefinition) : instance is IHasExtra { | ||
// returninstance instanceof ts.AbstractType || instance instanceof nominalTypes.AbstractType; | ||
// } | ||
function getSchemaUtils() { | ||
@@ -14,0 +21,0 @@ return schemaUtil; |
@@ -0,1 +1,2 @@ | ||
import tsInterfaces = require("./typesystem-interfaces"); | ||
export interface INamedEntity { | ||
@@ -103,3 +104,3 @@ nameId(): string; | ||
} | ||
export interface ITypeDefinition extends INamedEntity { | ||
export interface ITypeDefinition extends INamedEntity, tsInterfaces.IHasExtra { | ||
key(): NamedId; | ||
@@ -274,2 +275,6 @@ /** | ||
validate(x: any): Status[]; | ||
/** | ||
* Returns whether this type was defined by a user. | ||
*/ | ||
isUserDefined(): boolean; | ||
} | ||
@@ -276,0 +281,0 @@ export interface FacetValidator { |
@@ -87,3 +87,2 @@ import ti = require("./nominal-interfaces"); | ||
_requirements: ti.ValueRequirement[]; | ||
isUserDefined(): boolean; | ||
private fixedFacets; | ||
@@ -169,3 +168,7 @@ hasArrayInHierarchy(): boolean; | ||
setBuiltIn(builtIn: boolean): void; | ||
private isTopLevel(); | ||
isTopLevel(): boolean; | ||
isUserDefined(): boolean; | ||
putExtra(extraName: string, value: any): void; | ||
getExtra(name: string): any; | ||
private getExtraAdapter(); | ||
} | ||
@@ -172,0 +175,0 @@ export declare class ValueType extends AbstractType implements ITypeDefinition { |
@@ -8,2 +8,3 @@ "use strict"; | ||
var ti = require("./nominal-interfaces"); | ||
var tsInterfaces = require("./typesystem-interfaces"); | ||
var _ = require("./utils"); | ||
@@ -251,5 +252,2 @@ global["extraInjectors"] = []; | ||
}; | ||
AbstractType.prototype.isUserDefined = function () { | ||
return false; | ||
}; | ||
AbstractType.prototype.hasArrayInHierarchy = function () { | ||
@@ -625,12 +623,36 @@ var arr = _.find(this.allSuperTypes(), function (x) { return x instanceof Array; }) != null; | ||
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")); | ||
})) { | ||
//TODO determine whether "topLevel" actually means a simple top-level type and | ||
//this flag is absent due to a bug | ||
if (this.getExtra(tsInterfaces.DEFINED_IN_TYPES_EXTRA) || this.getExtra(tsInterfaces.TOP_LEVEL_EXTRA)) | ||
return true; | ||
} | ||
return false; | ||
}; | ||
AbstractType.prototype.isUserDefined = function () { | ||
return this.getExtra(tsInterfaces.USER_DEFINED_EXTRA); | ||
}; | ||
AbstractType.prototype.putExtra = function (extraName, value) { | ||
var extraAdapter = this.getExtraAdapter(); | ||
if (!extraAdapter) | ||
return; | ||
extraAdapter.putExtra(extraName, value); | ||
}; | ||
AbstractType.prototype.getExtra = function (name) { | ||
var extraAdapter = this.getExtraAdapter(); | ||
if (!extraAdapter) | ||
return null; | ||
return extraAdapter.getExtra(name); | ||
}; | ||
AbstractType.prototype.getExtraAdapter = function () { | ||
if (this.getAdapters()) { | ||
var extraAdapter = _.find(this.getAdapters(), function (adapter) { | ||
//weird duck-typing, but we can touch anything from nominal-types here | ||
if (adapter.getExtra && typeof (adapter.getExtra) == "function" | ||
&& adapter.putExtra && typeof (adapter.putExtra) == "function") { | ||
return true; | ||
} | ||
}); | ||
return extraAdapter; | ||
} | ||
return null; | ||
}; | ||
return AbstractType; | ||
@@ -637,0 +659,0 @@ }(Described)); |
@@ -8,2 +8,3 @@ "use strict"; | ||
var ts = require("./typesystem"); | ||
var tsInterfaces = require("./typesystem-interfaces"); | ||
var rs = require("./restrictions"); | ||
@@ -581,3 +582,3 @@ var typesystem_1 = require("./typesystem"); | ||
r.addType(res); | ||
res.putExtra("topLevel", true); | ||
res.putExtra(tsInterfaces.TOP_LEVEL_EXTRA, true); | ||
} | ||
@@ -594,3 +595,3 @@ return res; | ||
r.addType(res); | ||
res.putExtra("topLevel", true); | ||
res.putExtra(tsInterfaces.TOP_LEVEL_EXTRA, true); | ||
} | ||
@@ -648,3 +649,3 @@ return res; | ||
r.addType(actualResult); | ||
actualResult.putExtra("topLevel", true); | ||
actualResult.putExtra(tsInterfaces.TOP_LEVEL_EXTRA, true); | ||
} | ||
@@ -651,0 +652,0 @@ n.children().forEach(function (x) { |
@@ -71,11 +71,2 @@ "use strict"; | ||
MatchesProperty.prototype.validateSelf = function (registry) { | ||
if (this._type.isAnonymous()) { | ||
var st = this._type.validateType(registry); | ||
if (!st.isOk()) { | ||
var p = new typesystem_2.Status(typesystem_2.Status.ERROR, 0, "property " + this.propId() + " range type has error:" + st.getMessage(), this); | ||
p.setValidationPath({ name: this.propId() }); | ||
return p; | ||
} | ||
return st; | ||
} | ||
if (this._type.isExternal()) { | ||
@@ -91,2 +82,11 @@ var p = new typesystem_2.Status(typesystem_2.Status.ERROR, 0, "It is not allowed to use external types in property definitions", this); | ||
} | ||
if (this._type.isAnonymous()) { | ||
var st = this._type.validateType(registry); | ||
if (!st.isOk()) { | ||
var p = new typesystem_2.Status(typesystem_2.Status.ERROR, 0, "property " + this.propId() + " range type has error:" + st.getMessage(), this); | ||
p.setValidationPath({ name: this.propId() }); | ||
return p; | ||
} | ||
return st; | ||
} | ||
if (this._type.isUnion()) { | ||
@@ -183,3 +183,3 @@ var ui = _.find(this._type.typeFamily(), function (x) { return x.isSubTypeOf(ts.UNKNOWN); }); | ||
if (this._value) { | ||
if (i && typeof i == 'object') { | ||
if (i && typeof i == 'object' && !Array.isArray(i)) { | ||
var nm = {}; | ||
@@ -186,0 +186,0 @@ Object.getOwnPropertyNames(i).forEach(function (n) { return nm[n] = true; }); |
/// <reference path="../../typings/main.d.ts" /> | ||
import su = require("./schemaUtil"); | ||
export interface IValidationPath { | ||
name: string; | ||
child?: IValidationPath; | ||
} | ||
import tsInterfaces = require("./typesystem-interfaces"); | ||
export declare type IValidationPath = tsInterfaces.IValidationPath; | ||
export declare class Status { | ||
@@ -18,7 +16,7 @@ static CODE_CONFLICTING_TYPE_KIND: number; | ||
protected subStatus: Status[]; | ||
protected vp: IValidationPath; | ||
getValidationPath(): IValidationPath; | ||
protected vp: tsInterfaces.IValidationPath; | ||
getValidationPath(): tsInterfaces.IValidationPath; | ||
getValidationPathAsString(): string; | ||
patchPath(p: IValidationPath): IValidationPath; | ||
setValidationPath(c: IValidationPath): void; | ||
patchPath(p: tsInterfaces.IValidationPath): tsInterfaces.IValidationPath; | ||
setValidationPath(c: tsInterfaces.IValidationPath): void; | ||
constructor(severity: number, code: number, message: string, source: any); | ||
@@ -55,3 +53,3 @@ addSubStatus(st: Status): void; | ||
constructor(); | ||
abstract check(i: any, parentPath: IValidationPath): Status; | ||
abstract check(i: any, parentPath: tsInterfaces.IValidationPath): Status; | ||
private static intersections; | ||
@@ -105,3 +103,3 @@ protected intersect(t0: AbstractType, t1: AbstractType): AbstractType; | ||
export declare var VALIDATED_TYPE: AbstractType; | ||
export declare abstract class AbstractType { | ||
export declare abstract class AbstractType implements tsInterfaces.IHasExtra { | ||
protected _name: string; | ||
@@ -255,3 +253,3 @@ protected computeConfluent: boolean; | ||
*/ | ||
validateDirect(i: any, autoClose?: boolean, nullAllowed?: boolean, path?: IValidationPath): Status; | ||
validateDirect(i: any, autoClose?: boolean, nullAllowed?: boolean, path?: tsInterfaces.IValidationPath): Status; | ||
validate(i: any, autoClose?: boolean, nullAllowed?: boolean): Status; | ||
@@ -442,3 +440,3 @@ /** | ||
constructor(val: Constraint[], _extraMessage?: string); | ||
check(i: any, p: IValidationPath): Status; | ||
check(i: any, p: tsInterfaces.IValidationPath): Status; | ||
value(): any[]; | ||
@@ -453,3 +451,3 @@ requiredType(): RootType; | ||
options(): Constraint[]; | ||
check(i: any, p: IValidationPath): Status; | ||
check(i: any, p: tsInterfaces.IValidationPath): Status; | ||
requiredType(): RootType; | ||
@@ -456,0 +454,0 @@ facetName(): string; |
@@ -10,2 +10,3 @@ "use strict"; | ||
var su = require("./schemaUtil"); | ||
var tsInterfaces = require("./typesystem-interfaces"); | ||
var Status = (function () { | ||
@@ -276,2 +277,72 @@ function Status(severity, code, message, source) { | ||
exports.TypeRegistry = TypeRegistry; | ||
var PropertyCyclesValidator = (function () { | ||
function PropertyCyclesValidator() { | ||
} | ||
PropertyCyclesValidator.prototype.getInfos = function (t) { | ||
if (t.getExtra("PInfos")) { | ||
return t.getExtra("PInfos"); | ||
} | ||
var m = {}; | ||
t.meta().forEach(function (x) { | ||
if (x instanceof restr.HasProperty) { | ||
var id = x.value(); | ||
m[id] = { name: id, type: null }; | ||
} | ||
}); | ||
t.meta().forEach(function (x) { | ||
if (x instanceof restr.PropertyIs) { | ||
var id = x.propertyName(); | ||
if (m[id]) { | ||
m[id].type = x.value(); | ||
} | ||
} | ||
}); | ||
t.putExtra("PInfos", m); | ||
return m; | ||
}; | ||
PropertyCyclesValidator.prototype.validate = function (t, visited) { | ||
var _this = this; | ||
var i = this.getInfos(t); | ||
var result = false; | ||
Object.keys(i).forEach(function (x) { | ||
result = result || _this.validateInfo(i[x], visited); | ||
}); | ||
return result; | ||
}; | ||
PropertyCyclesValidator.prototype.validateInfo = function (t, visited) { | ||
var _this = this; | ||
if (visited.some(function (y) { return y == t; })) { | ||
return true; | ||
} | ||
else { | ||
if (t.type instanceof UnionType) { | ||
var ut = t.type; | ||
var passing = true; | ||
ut.options().forEach(function (o) { | ||
if (!_this.validate(o, [t].concat(visited))) { | ||
passing = false; | ||
} | ||
}); | ||
return passing; | ||
} | ||
if (t.type.isArray()) { | ||
} | ||
else { | ||
return this.validate(t.type, [t].concat(visited)); | ||
} | ||
} | ||
}; | ||
PropertyCyclesValidator.prototype.validateType = function (t) { | ||
var _this = this; | ||
var i = this.getInfos(t); | ||
var result = []; | ||
Object.keys(i).forEach(function (x) { | ||
if (_this.validateInfo(i[x], [])) { | ||
result.push(x); | ||
} | ||
}); | ||
return result; | ||
}; | ||
return PropertyCyclesValidator; | ||
}()); | ||
var RestrictionsConflict = (function (_super) { | ||
@@ -427,2 +498,10 @@ __extends(RestrictionsConflict, _super); | ||
}); | ||
var propertyCycles = new PropertyCyclesValidator().validateType(this); | ||
if (propertyCycles.length > 0) { | ||
propertyCycles.forEach(function (p) { | ||
var st = new Status(Status.ERROR, 0, p + "has cyclic dependency", _this); | ||
st.setValidationPath({ name: p }); | ||
rs.addSubStatus(st); | ||
}); | ||
} | ||
} | ||
@@ -432,4 +511,5 @@ return rs; | ||
AbstractType.prototype.validateHierarchy = function (rs) { | ||
var _this = this; | ||
if (!this.isAnonymous()) { | ||
if (this.getExtra("topLevel") && builtInRegistry().get(this.name())) { | ||
if (this.getExtra(tsInterfaces.TOP_LEVEL_EXTRA) && builtInRegistry().get(this.name())) { | ||
rs.addSubStatus(new Status(Status.ERROR, 0, "redefining builtin type:" + this.name(), this)); | ||
@@ -478,2 +558,10 @@ } | ||
} | ||
if (this instanceof UnionType) { | ||
var ut = this; | ||
ut.options().forEach(function (x) { | ||
if (x.isExternal()) { | ||
rs.addSubStatus(new Status(Status.ERROR, 0, "It is not allowed to mix RAML types with externals", _this)); | ||
} | ||
}); | ||
} | ||
}; | ||
@@ -1540,3 +1628,3 @@ ; | ||
NullRestriction.prototype.check = function (i) { | ||
if (i === null || i == undefined) { | ||
if (i === null || i == undefined || i === "null") { | ||
return exports.OK_STATUS; | ||
@@ -1543,0 +1631,0 @@ } |
@@ -88,3 +88,3 @@ "use strict"; | ||
expectedElementNames.push(typeName); | ||
newJson = getArray(rootNode, type, errors); | ||
newJson = getArray(rootNode, type, errors, true); | ||
fillExtras(rootNode, errors, expectedAttributeNames, expectedElementNames); | ||
@@ -125,3 +125,3 @@ } | ||
if (type.isScalar()) { | ||
return toPrimitiveValue(type, node); | ||
return toPrimitiveValue(type, node, errors); | ||
} | ||
@@ -139,3 +139,4 @@ if (type.isUnion()) { | ||
} | ||
function fillExtras(node, errors, expectedAttributeNames, expectedElementNames) { | ||
function fillExtras(node, errors, expectedAttributeNames, expectedElementNames, remove) { | ||
if (remove === void 0) { remove = false; } | ||
if (typeof node !== "object") { | ||
@@ -161,2 +162,5 @@ return; | ||
errors.push('Unexpected element "' + name + '".'); | ||
if (remove) { | ||
delete node[name]; | ||
} | ||
}); | ||
@@ -201,8 +205,17 @@ } | ||
} | ||
function getArray(values, type, errors) { | ||
function getArray(values, type, errors, rootNode) { | ||
if (rootNode === void 0) { rootNode = false; } | ||
var descriptor = xmlDescriptor(type); | ||
var isWrapped = descriptor.wrapped; | ||
var isWrapped = rootNode || 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 (isWrapped) { | ||
var valuesWrapper = values; | ||
values = values && values[typeName]; | ||
fillExtras(valuesWrapper, errors, [], [typeName], true); | ||
} | ||
if (!values) { | ||
return []; | ||
} | ||
values = getArrayValues(values); | ||
if (isArray(values)) { | ||
@@ -216,2 +229,11 @@ values = values.map(function (value) { return buildJson(value, componentType, errors); }); | ||
} | ||
function getArrayValues(preValues) { | ||
if (isArray(preValues)) { | ||
return preValues; | ||
} | ||
if (typeof preValues === 'object') { | ||
return [preValues]; | ||
} | ||
return []; | ||
} | ||
function arrayElementType(arrayType) { | ||
@@ -226,3 +248,3 @@ if (!arrayType || !arrayType.isArray()) { | ||
var descriptor = xmlDescriptor(property.value()); | ||
var ramlName = (property.value() && property.value().isArray() && !descriptor.wrapped) ? arrayElementType(property.value()).name() : property.propId(); | ||
var ramlName = property.propId(); | ||
var actualName = descriptor.name || ramlName; | ||
@@ -264,7 +286,11 @@ if (descriptor.namespace) { | ||
} | ||
function toPrimitiveValue(type, actual) { | ||
function toPrimitiveValue(type, actual, errors) { | ||
if (errors === void 0) { errors = []; } | ||
if (typeof actual === 'object') { | ||
return null; | ||
var result = toPrimitiveValue(type, actual['_']); | ||
delete actual['_']; | ||
fillExtras(actual, errors, [], [], true); | ||
return result; | ||
} | ||
if (!actual) { | ||
if (!actual && actual.trim() !== '') { | ||
return null; | ||
@@ -286,3 +312,6 @@ } | ||
} | ||
return (typeof actual === 'string' && (actual || '')) || null; | ||
if (typeof actual === 'string') { | ||
return actual; | ||
} | ||
return null; | ||
} | ||
@@ -289,0 +318,0 @@ function isArray(instance) { |
@@ -1573,3 +1573,135 @@ "use strict"; | ||
}); | ||
it("validate recursive prop", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas: { | ||
Hello: { | ||
type: "object", | ||
properties: { | ||
"zz": "Hello" | ||
} | ||
}, | ||
} | ||
}); | ||
var st = tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
}); | ||
it("validate nullable recursive prop", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas: { | ||
Hello: { | ||
type: "object", | ||
properties: { | ||
"zz": "Hello | null" | ||
} | ||
}, | ||
} | ||
}); | ||
var st = tp.getType("Hello").validateType(); | ||
assert.isTrue(st.isOk()); | ||
}); | ||
it("validate recursive prop + union", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas: { | ||
Hello: { | ||
type: "object", | ||
properties: { | ||
"zz": "Hello | Hello" | ||
} | ||
}, | ||
} | ||
}); | ||
var st = tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
}); | ||
it("validate nullable", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas: { | ||
Hello: { | ||
type: "object", | ||
properties: { | ||
"zz": "Hello | null" | ||
} | ||
}, | ||
} | ||
}); | ||
var st = tp.getType("Hello").validate({ zz: null }); | ||
assert.isTrue(st.isOk()); | ||
}); | ||
it("validate nullable 2", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas: { | ||
Hello: { | ||
type: "object", | ||
properties: { | ||
"zz": "Hello | null" | ||
} | ||
}, | ||
} | ||
}); | ||
var st = tp.getType("Hello").validate({ zz: "null" }); | ||
assert.isTrue(st.isOk()); | ||
}); | ||
it("validate known properties + array", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas: { | ||
Hello: { | ||
type: "object", | ||
properties: { | ||
"zz": "Hello | null" | ||
}, | ||
example: [1, 2] | ||
}, | ||
} | ||
}); | ||
var st = tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
assert.isTrue(st.getErrors().length == 1); | ||
}); | ||
it("External is more important than anonimous", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas: { | ||
Hello: { | ||
type: "object", | ||
properties: { | ||
"zz": '{ "type": "object"}' | ||
} | ||
}, | ||
} | ||
}); | ||
var st = tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
assert.isTrue(st.getErrors().length == 1); | ||
}); | ||
it("External is more important than anonimous 2", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas: { | ||
Hello: { | ||
type: "object", | ||
properties: { | ||
"zz": { type: '{ "type": "object"}' } | ||
} | ||
}, | ||
} | ||
}); | ||
var st = tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
assert.isTrue(st.getErrors().length == 1); | ||
}); | ||
it("External with union", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas: { | ||
T: '{ "type": "object"}', | ||
Hello: { | ||
type: "object", | ||
properties: { | ||
"zz": { type: "T | number" } | ||
} | ||
}, | ||
} | ||
}); | ||
var st = tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
assert.isTrue(st.getErrors().length == 1); | ||
}); | ||
}); | ||
//# sourceMappingURL=typeValidationTests.js.map |
{ | ||
"name": "raml-typesystem", | ||
"version": "0.0.28-rc2", | ||
"version": "0.0.29-rc2", | ||
"main": "dist/src/index.js", | ||
@@ -5,0 +5,0 @@ "scripts": { |
import ts=require("./typesystem") | ||
import tsInterfaces=require("./typesystem-interfaces") | ||
import tc=require("./parse") | ||
@@ -14,7 +15,11 @@ import fr=require("./facetRegistry") | ||
export interface IValidationPath{ | ||
name: string | ||
child?:IValidationPath | ||
export type IValidationPath = tsInterfaces.IValidationPath; | ||
export type IHasExtra = tsInterfaces.IHasExtra; | ||
export var TOP_LEVEL_EXTRA = tsInterfaces.TOP_LEVEL_EXTRA; | ||
export var DEFINED_IN_TYPES_EXTRA = tsInterfaces.DEFINED_IN_TYPES_EXTRA; | ||
export var USER_DEFINED_EXTRA = tsInterfaces.USER_DEFINED_EXTRA; | ||
} | ||
// export function instanceOfHasExtra(instance : nominalTypes.ITypeDefinition) : instance is IHasExtra { | ||
// returninstance instanceof ts.AbstractType || instance instanceof nominalTypes.AbstractType; | ||
// } | ||
@@ -161,3 +166,3 @@ export function getSchemaUtils(): any { | ||
*/ | ||
export interface IParsedType { | ||
export interface IParsedType extends IHasExtra { | ||
@@ -164,0 +169,0 @@ /** |
@@ -0,1 +1,3 @@ | ||
import tsInterfaces = require("./typesystem-interfaces") | ||
export interface INamedEntity{ | ||
@@ -122,3 +124,3 @@ nameId():string; | ||
} | ||
export interface ITypeDefinition extends INamedEntity { | ||
export interface ITypeDefinition extends INamedEntity,tsInterfaces.IHasExtra { | ||
@@ -336,2 +338,6 @@ | ||
/** | ||
* Returns whether this type was defined by a user. | ||
*/ | ||
isUserDefined() : boolean; | ||
} | ||
@@ -338,0 +344,0 @@ export interface FacetValidator{ |
import ti = require("./nominal-interfaces") | ||
import tsInterfaces = require("./typesystem-interfaces") | ||
export type IAnnotation=ti.IAnnotation; | ||
@@ -282,7 +283,2 @@ export type ITypeDefinition=ti.ITypeDefinition; | ||
isUserDefined(): boolean{ | ||
return false; | ||
} | ||
private fixedFacets:{ [name:string]:any}={} | ||
@@ -732,13 +728,41 @@ | ||
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; | ||
isTopLevel() : boolean { | ||
//TODO determine whether "topLevel" actually means a simple top-level type and | ||
//this flag is absent due to a bug | ||
if(this.getExtra(tsInterfaces.DEFINED_IN_TYPES_EXTRA) || this.getExtra(tsInterfaces.TOP_LEVEL_EXTRA)) return true; | ||
return false; | ||
} | ||
isUserDefined() : boolean { | ||
return this.getExtra(tsInterfaces.USER_DEFINED_EXTRA); | ||
} | ||
putExtra(extraName: string, value : any) : void { | ||
var extraAdapter = this.getExtraAdapter(); | ||
if (!extraAdapter) return; | ||
extraAdapter.putExtra(extraName, value); | ||
} | ||
getExtra(name:string) : any { | ||
var extraAdapter = this.getExtraAdapter(); | ||
if (!extraAdapter) return null; | ||
return extraAdapter.getExtra(name); | ||
} | ||
private getExtraAdapter() : tsInterfaces.IHasExtra { | ||
if(this.getAdapters()) { | ||
var extraAdapter = _.find(this.getAdapters(), adapter=>{ | ||
//weird duck-typing, but we can touch anything from nominal-types here | ||
if ((<any>adapter).getExtra && typeof((<any>adapter).getExtra) == "function" | ||
&& (<any>adapter).putExtra && typeof((<any>adapter).putExtra) == "function") { | ||
return true; | ||
} | ||
}); | ||
return <tsInterfaces.IHasExtra>extraAdapter; | ||
} | ||
return false; | ||
return null; | ||
} | ||
@@ -745,0 +769,0 @@ } |
import ts=require("./typesystem") | ||
import tsInterfaces=require("./typesystem-interfaces") | ||
import rs=require("./restrictions") | ||
@@ -630,3 +631,3 @@ import {AbstractType} from "./typesystem"; | ||
res.putExtra("topLevel",true); | ||
res.putExtra(tsInterfaces.TOP_LEVEL_EXTRA,true); | ||
} | ||
@@ -643,3 +644,3 @@ return res; | ||
r.addType(res); | ||
res.putExtra("topLevel",true); | ||
res.putExtra(tsInterfaces.TOP_LEVEL_EXTRA,true); | ||
} | ||
@@ -700,3 +701,3 @@ return res; | ||
r.addType(actualResult); | ||
actualResult.putExtra("topLevel",true); | ||
actualResult.putExtra(tsInterfaces.TOP_LEVEL_EXTRA,true); | ||
} | ||
@@ -703,0 +704,0 @@ n.children().forEach(x=>{ |
@@ -73,11 +73,2 @@ /// <reference path="../typings/main.d.ts" /> | ||
validateSelf(registry:ts.TypeRegistry):ts.Status { | ||
if (this._type.isAnonymous()){ | ||
var st=this._type.validateType(registry); | ||
if (!st.isOk()){ | ||
var p= new Status(Status.ERROR,0,"property "+this.propId()+" range type has error:"+st.getMessage(),this) | ||
p.setValidationPath({name: this.propId()}) | ||
return p; | ||
} | ||
return st; | ||
} | ||
if (this._type.isExternal()){ | ||
@@ -93,2 +84,12 @@ var p= new Status(Status.ERROR,0,"It is not allowed to use external types in property definitions",this) | ||
} | ||
if (this._type.isAnonymous()){ | ||
var st=this._type.validateType(registry); | ||
if (!st.isOk()){ | ||
var p= new Status(Status.ERROR,0,"property "+this.propId()+" range type has error:"+st.getMessage(),this) | ||
p.setValidationPath({name: this.propId()}) | ||
return p; | ||
} | ||
return st; | ||
} | ||
if (this._type.isUnion()){ | ||
@@ -187,3 +188,3 @@ var ui= _.find(this._type.typeFamily(),x=>x.isSubTypeOf(ts.UNKNOWN)); | ||
if (this._value) { | ||
if (i&&typeof i == 'object') { | ||
if (i&&typeof i == 'object'&&!Array.isArray(i)) { | ||
var nm:{ [name:string]:boolean} = {}; | ||
@@ -190,0 +191,0 @@ Object.getOwnPropertyNames(i).forEach(n=>nm[n] = true); |
/// <reference path="../typings/main.d.ts" /> | ||
import _=require("underscore") | ||
import su=require("./schemaUtil") | ||
import tsInterfaces = require("./typesystem-interfaces") | ||
export interface IValidationPath{ | ||
export type IValidationPath = tsInterfaces.IValidationPath; | ||
name: string | ||
child?:IValidationPath | ||
} | ||
export class Status { | ||
@@ -31,5 +28,5 @@ | ||
protected vp:IValidationPath | ||
protected vp:tsInterfaces.IValidationPath | ||
getValidationPath():IValidationPath{ | ||
getValidationPath():tsInterfaces.IValidationPath{ | ||
return this.vp; | ||
@@ -54,3 +51,3 @@ } | ||
patchPath(p:IValidationPath):IValidationPath{ | ||
patchPath(p:tsInterfaces.IValidationPath):tsInterfaces.IValidationPath{ | ||
if (!p){ | ||
@@ -61,4 +58,4 @@ return null; | ||
var c=p; | ||
var r:IValidationPath=null; | ||
var cp:IValidationPath=null; | ||
var r:tsInterfaces.IValidationPath=null; | ||
var cp:tsInterfaces.IValidationPath=null; | ||
while (c){ | ||
@@ -81,3 +78,3 @@ if (!r){ | ||
} | ||
setValidationPath(c:IValidationPath){ | ||
setValidationPath(c:tsInterfaces.IValidationPath){ | ||
if (this.vp){ | ||
@@ -197,3 +194,3 @@ c=this.patchPath(c); | ||
abstract check(i:any,parentPath:IValidationPath):Status | ||
abstract check(i:any,parentPath:tsInterfaces.IValidationPath):Status | ||
@@ -319,3 +316,86 @@ | ||
} | ||
interface PropertyInfoHandle{ | ||
name:string | ||
type: AbstractType; | ||
} | ||
interface PropertyInfos{ | ||
[name: string]: PropertyInfoHandle; | ||
} | ||
class PropertyCyclesValidator{ | ||
getInfos(t:AbstractType):PropertyInfos{ | ||
if (t.getExtra("PInfos")){ | ||
return t.getExtra("PInfos"); | ||
} | ||
var m:PropertyInfos={}; | ||
t.meta().forEach(x=>{ | ||
if (x instanceof restr.HasProperty){ | ||
var id=(<restr.HasProperty>x).value(); | ||
m[id]={ name: id, type: null}; | ||
} | ||
}) | ||
t.meta().forEach(x=>{ | ||
if (x instanceof restr.PropertyIs){ | ||
var id=(<restr.PropertyIs>x).propertyName(); | ||
if (m[id]){ | ||
m[id].type=(<restr.PropertyIs>x).value(); | ||
} | ||
} | ||
}) | ||
t.putExtra("PInfos",m); | ||
return m; | ||
} | ||
validate(t:AbstractType,visited:PropertyInfoHandle[]):boolean{ | ||
var i=this.getInfos(t); | ||
var result=false; | ||
Object.keys(i).forEach(x=>{ | ||
result=result||this.validateInfo(i[x],visited); | ||
}) | ||
return result; | ||
} | ||
validateInfo(t:PropertyInfoHandle,visited:PropertyInfoHandle[]):boolean{ | ||
if (visited.some(y=>y==t)){ | ||
return true; | ||
} | ||
else{ | ||
if (t.type instanceof UnionType){ | ||
var ut=<UnionType>t.type; | ||
var passing=true; | ||
ut.options().forEach(o=>{ | ||
if (!this.validate(o, [t].concat(visited))){ | ||
passing=false; | ||
} | ||
}) | ||
return passing; | ||
} | ||
if (t.type.isArray()){ | ||
} | ||
else { | ||
return this.validate(t.type, [t].concat(visited)); | ||
} | ||
} | ||
} | ||
validateType(t:AbstractType):string[]{ | ||
var i=this.getInfos(t); | ||
var result:string[]=[]; | ||
Object.keys(i).forEach(x=>{ | ||
if (this.validateInfo(i[x],[])){ | ||
result.push(x); | ||
} | ||
}) | ||
return result; | ||
} | ||
} | ||
export class RestrictionsConflict extends Status{ | ||
@@ -348,3 +428,3 @@ constructor(protected _conflicting:Constraint,protected _stack:RestrictionStackEntry,source:any){ | ||
export var VALIDATED_TYPE:AbstractType=null; | ||
export abstract class AbstractType{ | ||
export abstract class AbstractType implements tsInterfaces.IHasExtra{ | ||
@@ -495,2 +575,11 @@ protected computeConfluent: boolean | ||
}) | ||
var propertyCycles=new PropertyCyclesValidator().validateType(this); | ||
if (propertyCycles.length>0){ | ||
propertyCycles.forEach(p=>{ | ||
var st=new Status(Status.ERROR,0,p+"has cyclic dependency",this); | ||
st.setValidationPath({name:p}) | ||
rs.addSubStatus(st); | ||
}) | ||
} | ||
} | ||
@@ -501,5 +590,9 @@ | ||
public validateHierarchy(rs:Status) { | ||
if (!this.isAnonymous()) { | ||
if (this.getExtra("topLevel") && builtInRegistry().get(this.name())) { | ||
if (this.getExtra(tsInterfaces.TOP_LEVEL_EXTRA) && builtInRegistry().get(this.name())) { | ||
rs.addSubStatus(new Status(Status.ERROR, 0, "redefining builtin type:" + this.name(), this)) | ||
@@ -542,3 +635,3 @@ | ||
if (x.isExternal()){ | ||
hasExternal=true; | ||
hasExternal=true; | ||
} | ||
@@ -553,2 +646,10 @@ else{ | ||
} | ||
if (this instanceof UnionType){ | ||
var ut=<UnionType><any>this; | ||
ut.options().forEach(x=>{ | ||
if (x.isExternal()){ | ||
rs.addSubStatus(new Status(Status.ERROR, 0, "It is not allowed to mix RAML types with externals",this)) | ||
} | ||
}) | ||
} | ||
}; | ||
@@ -723,2 +824,4 @@ | ||
checkConfluent():Status{ | ||
@@ -925,3 +1028,3 @@ if (this.computeConfluent){ | ||
*/ | ||
validateDirect(i:any,autoClose:boolean=false,nullAllowed:boolean=true,path:IValidationPath=null):Status{ | ||
validateDirect(i:any,autoClose:boolean=false,nullAllowed:boolean=true,path:tsInterfaces.IValidationPath=null):Status{ | ||
VALIDATED_TYPE=this; | ||
@@ -1643,3 +1746,3 @@ var result=new Status(Status.OK,0,"",this); | ||
check(i:any):Status { | ||
if (i===null||i==undefined){ | ||
if (i===null||i==undefined||i==="null"){ | ||
return OK_STATUS; | ||
@@ -1696,3 +1799,3 @@ } | ||
check(i:any,p:IValidationPath):Status { | ||
check(i:any,p:tsInterfaces.IValidationPath):Status { | ||
var cs=new Status(Status.OK,0,"",this); | ||
@@ -1739,3 +1842,3 @@ var first:Status=null; | ||
} | ||
check(i:any,p:IValidationPath):Status { | ||
check(i:any,p:tsInterfaces.IValidationPath):Status { | ||
for (var j=0;j<this.val.length;j++){ | ||
@@ -1742,0 +1845,0 @@ var st=this.val[j].check(i,p); |
@@ -116,3 +116,3 @@ /// <reference path="../typings/main.d.ts" /> | ||
newJson = getArray(rootNode, type, errors); | ||
newJson = getArray(rootNode, type, errors, true); | ||
@@ -171,3 +171,3 @@ fillExtras(rootNode, errors, expectedAttributeNames, expectedElementNames); | ||
if(type.isScalar()) { | ||
return toPrimitiveValue(type, node); | ||
return toPrimitiveValue(type, node, errors); | ||
} | ||
@@ -192,3 +192,3 @@ | ||
function fillExtras(node: any, errors: string[], expectedAttributeNames: string[], expectedElementNames: string[]) { | ||
function fillExtras(node: any, errors: string[], expectedAttributeNames: string[], expectedElementNames: string[], remove: boolean = false) { | ||
if(typeof node !== "object") { | ||
@@ -222,2 +222,6 @@ return; | ||
errors.push('Unexpected element "' + name + '".'); | ||
if(remove) { | ||
delete node[name]; | ||
} | ||
}); | ||
@@ -282,6 +286,6 @@ } | ||
function getArray(values: any, type: ts.AbstractType, errors: string[]) { | ||
function getArray(values: any, type: ts.AbstractType, errors: string[], rootNode: boolean = false) { | ||
var descriptor = xmlDescriptor(type); | ||
var isWrapped = descriptor.wrapped; | ||
var isWrapped = rootNode || descriptor.wrapped; | ||
@@ -292,4 +296,16 @@ var componentType = arrayElementType(type); | ||
values = isArray(values) ? values : ((Object.keys(values).length === 1 && [values[Object.keys(values)[0]]]) || values); | ||
if(isWrapped) { | ||
var valuesWrapper = values; | ||
values = values && values[typeName]; | ||
fillExtras(valuesWrapper, errors, [], [typeName], true); | ||
} | ||
if(!values) { | ||
return []; | ||
} | ||
values = getArrayValues(values); | ||
if(isArray(values)) { | ||
@@ -304,2 +320,14 @@ values = values.map((value: any) => buildJson(value, componentType, errors)) | ||
function getArrayValues(preValues: any) { | ||
if(isArray(preValues)) { | ||
return preValues; | ||
} | ||
if(typeof preValues === 'object') { | ||
return [preValues]; | ||
} | ||
return []; | ||
} | ||
function arrayElementType(arrayType: ts.AbstractType) { | ||
@@ -318,3 +346,3 @@ if(!arrayType || !arrayType.isArray()) { | ||
var ramlName: string = (property.value() && property.value().isArray() && !descriptor.wrapped) ? arrayElementType(property.value()).name() : property.propId(); | ||
var ramlName: string = property.propId(); | ||
@@ -372,8 +400,14 @@ var actualName = descriptor.name || ramlName; | ||
function toPrimitiveValue(type: ts.AbstractType, actual: any): any { | ||
function toPrimitiveValue(type: ts.AbstractType, actual: any, errors: string[] = []): any { | ||
if(typeof actual === 'object') { | ||
return null; | ||
var result = toPrimitiveValue(type, actual['_']); | ||
delete actual['_']; | ||
fillExtras(actual, errors, [], [], true); | ||
return result; | ||
} | ||
if(!actual) { | ||
if(!actual && actual.trim() !== '') { | ||
return null; | ||
@@ -400,3 +434,7 @@ } | ||
return (typeof actual === 'string' && (actual || '')) || null; | ||
if(typeof actual === 'string') { | ||
return actual; | ||
} | ||
return null; | ||
} | ||
@@ -403,0 +441,0 @@ |
@@ -1732,3 +1732,165 @@ import ps= require("./actualParse") | ||
}) | ||
it("validate recursive prop", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas:{ | ||
Hello:{ | ||
type: "object", | ||
properties:{ | ||
"zz" :"Hello" | ||
} | ||
}, | ||
} | ||
}) | ||
var st= tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
}) | ||
it("validate nullable recursive prop", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas:{ | ||
Hello:{ | ||
type: "object", | ||
properties:{ | ||
"zz" :"Hello | null" | ||
} | ||
}, | ||
} | ||
}) | ||
var st= tp.getType("Hello").validateType(); | ||
assert.isTrue(st.isOk()); | ||
}) | ||
it("validate recursive prop + union", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas:{ | ||
Hello:{ | ||
type: "object", | ||
properties:{ | ||
"zz" :"Hello | Hello" | ||
} | ||
}, | ||
} | ||
}) | ||
var st= tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
}) | ||
it("validate nullable", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas:{ | ||
Hello:{ | ||
type: "object", | ||
properties:{ | ||
"zz" :"Hello | null" | ||
} | ||
}, | ||
} | ||
}) | ||
var st= tp.getType("Hello").validate({zz: null}); | ||
assert.isTrue(st.isOk()); | ||
}) | ||
it("validate nullable 2", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas:{ | ||
Hello:{ | ||
type: "object", | ||
properties:{ | ||
"zz" :"Hello | null" | ||
} | ||
}, | ||
} | ||
}) | ||
var st= tp.getType("Hello").validate({zz: "null"}); | ||
assert.isTrue(st.isOk()); | ||
}) | ||
it("validate known properties + array", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas:{ | ||
Hello:{ | ||
type: "object", | ||
properties:{ | ||
"zz" :"Hello | null" | ||
} | ||
, | ||
example: [1,2] | ||
}, | ||
} | ||
}) | ||
var st= tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
assert.isTrue(st.getErrors().length==1); | ||
}) | ||
it("External is more important than anonimous", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas:{ | ||
Hello:{ | ||
type: "object", | ||
properties:{ | ||
"zz" : '{ "type": "object"}' | ||
} | ||
}, | ||
} | ||
}) | ||
var st= tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
assert.isTrue(st.getErrors().length==1); | ||
}) | ||
it("External is more important than anonimous 2", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas:{ | ||
Hello:{ | ||
type: "object", | ||
properties:{ | ||
"zz" : { type: '{ "type": "object"}'} | ||
} | ||
}, | ||
} | ||
}) | ||
var st= tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
assert.isTrue(st.getErrors().length==1); | ||
}) | ||
it("External with union", function () { | ||
var tp = ps.parseJSONTypeCollection({ | ||
schemas:{ | ||
T: '{ "type": "object"}', | ||
Hello:{ | ||
type: "object", | ||
properties:{ | ||
"zz" : { type: "T | number"} | ||
} | ||
}, | ||
} | ||
}) | ||
var st= tp.getType("Hello").validateType(); | ||
assert.isTrue(!st.isOk()); | ||
assert.isTrue(st.getErrors().length==1); | ||
}) | ||
}) |
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
1741286
142
39368