diff --git a/lib/typson-schema.js b/lib/typson-schema.js index e3154a9..34732ec 100755 --- a/lib/typson-schema.js +++ b/lib/typson-schema.js @@ -33,7 +33,7 @@ var TypeScript, _, traverse; // from global scope } var api = {}; var primitiveTypes = [ "string", "number", "boolean", "any" ]; - var validationKeywords = [ "type", "minimum", "exclusiveMinimum", "maximum", "exclusiveMaximum", "multipleOf", "minLength", "maxLength", "format", "pattern", "minItems", "maxItems", "uniqueItems", "default", "additionalProperties" ]; + var validationKeywords = [ "type", "minimum", "exclusiveMinimum", "maximum", "exclusiveMaximum", "multipleOf", "minLength", "maxLength", "format", "pattern", "minItems", "maxItems", "uniqueItems", "additionalProperties" ]; var annotedValidationKeywordPattern = /@[a-z.]+\s*[^@\s]+/gi; var TypescriptASTFlags = { "optionalName" : 4, "arrayType" : 8 }; var defaultProperties = { additionalProperties: false}; @@ -314,6 +314,19 @@ var TypeScript, _, traverse; // from global scope return delimiterIndex < 0 ? "" : comment.slice(delimiterIndex); } + /** + * Extracts the default value stored in a comment and registers it on property. + * + * @param comment {string} the full comment. + * @param to {object} the destination variable. + */ + function copyPropertyDefault(comment, to) { + comment = comment.replace(/@default\s+([^@]+)/, function(m, m1) { + to.default = m1.trim(); + return ""; + }); + } + /** * Extracts the schema validation keywords stored in a comment and register them as properties. * A validation keyword starts by a @. It has a name and a value. Several keywords may occur. @@ -322,6 +335,7 @@ var TypeScript, _, traverse; // from global scope * @param to {object} the destination variable. */ function copyValidationKeywords(comment, to) { + copyPropertyDefault(comment, to); annotedValidationKeywordPattern.lastIndex = 0; // TODO: to improve the use of the exec method: it could make the tokenization var annotation; diff --git a/test/spec/bulk.test.js b/test/spec/bulk.test.js index 1e0aab3..0edec06 100644 --- a/test/spec/bulk.test.js +++ b/test/spec/bulk.test.js @@ -74,5 +74,7 @@ assertSchema('module-interface-single', 'main.ts', 'MyObject'); assertSchema('module-interface-deep', 'main.ts', 'MyObject'); + + assertSchema('schema-validation', 'main.ts', 'MyObject'); }); }); diff --git a/test/spec/schema-validation/main.ts b/test/spec/schema-validation/main.ts new file mode 100644 index 0000000..51c0677 --- /dev/null +++ b/test/spec/schema-validation/main.ts @@ -0,0 +1,55 @@ +enum enumOptions { + enumA, // first enumerable value + enumB // second enumerable value +} + +interface MyObject { + /** A prop that can take any value */ + anyProp: any; + /** + * @default 1 + */ + numberProp: number; + minimumProp: number // @minimum 0 + exclusiveMinimumProp: number // @exclusiveMinimum 0 + maximumProp: number // @maximum 10 + exclusiveMaximumProp: number // @exclusiveMaximum 10 + multipleOfProp: number // @multipleOf 2 + booleanProp: boolean; // @default true + /** + * @default + * A default value + * It spans multiple lines + */ + stringProp: string; + minLengthProp: string; // @minLength 10 + maxLengthProp: string; // @maxLength 100 + patternProp: string; // @pattern ^[a-f0-9]{32}$ + formatProp: string; // @format md5 + itemsProp: any[]; + minItemsProp: any[]; // @minItems 2 + maxItemsProp: any[]; // @maxItems 5 + uniqueItemsProp: any[]; // @uniqueItems 3 + nestedProp: MyNestedObject; + /** + * A property which is enumerable + * @default enumA + */ + enumProp: enumOptions; + /** + * @type object + * @additionalProperties true + */ + typeProp: any; + optionalProp?: string; + /** + * @invalidKeyword reject-invalid-keywords + */ + invalidKeywordProp: string; +} + +/** + * @additionalProperties true + */ +interface MyNestedObject { +} \ No newline at end of file diff --git a/test/spec/schema-validation/schema.json b/test/spec/schema-validation/schema.json new file mode 100644 index 0000000..e4cf724 --- /dev/null +++ b/test/spec/schema-validation/schema.json @@ -0,0 +1,131 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "MyObject", + "type": "object", + "properties": { + "anyProp": { + "description": "A prop that can take any value" + }, + "numberProp": { + "default": "1", + "type": "number" + }, + "minimumProp": { + "minimum": 0, + "type": "number" + }, + "exclusiveMinimumProp": { + "exclusiveMinimum": 0, + "type": "number" + }, + "maximumProp": { + "maximum": 10, + "type": "number" + }, + "exclusiveMaximumProp": { + "exclusiveMaximum": 10, + "type": "number" + }, + "multipleOfProp": { + "multipleOf": 2, + "type": "number" + }, + "booleanProp": { + "default": "true", + "type": "boolean" + }, + "stringProp": { + "default": "A default value\nIt spans multiple lines", + "type": "string" + }, + "minLengthProp": { + "minLength": 10, + "type": "string" + }, + "maxLengthProp": { + "maxLength": 100, + "type": "string" + }, + "patternProp": { + "pattern": "^[a-f0-9]{32}$", + "type": "string" + }, + "formatProp": { + "format": "md5", + "type": "string" + }, + "itemsProp": { + "type": "array", + "items": {} + }, + "minItemsProp": { + "minItems": 2, + "type": "array", + "items": {} + }, + "maxItemsProp": { + "maxItems": 5, + "type": "array", + "items": {} + }, + "uniqueItemsProp": { + "uniqueItems": 3, + "type": "array", + "items": {} + }, + "nestedProp": { + "$ref": "#/definitions/MyNestedObject" + }, + "enumProp": { + "description": "A property which is enumerable\n\n| Value | Description\n|-\n| `enumA`| first enumerable value \n| `enumB`| second enumerable value ", + "default": "enumA", + "id": "enumOptions", + "enum": [ + "enumA", + "enumB" + ] + }, + "typeProp": { + "type": "object", + "additionalProperties": true + }, + "optionalProp": { + "type": "string" + }, + "invalidKeywordProp": { + "type": "string" + } + }, + "required": [ + "anyProp", + "numberProp", + "minimumProp", + "exclusiveMinimumProp", + "maximumProp", + "exclusiveMaximumProp", + "multipleOfProp", + "booleanProp", + "stringProp", + "minLengthProp", + "maxLengthProp", + "patternProp", + "formatProp", + "itemsProp", + "minItemsProp", + "maxItemsProp", + "uniqueItemsProp", + "nestedProp", + "enumProp", + "typeProp", + "invalidKeywordProp" + ], + "additionalProperties": false, + "definitions": { + "MyNestedObject": { + "id": "MyNestedObject", + "type": "object", + "additionalProperties": true, + "properties": {} + } + } +}