openapi-sampler
Advanced tools
Comparing version 1.0.0-beta.18 to 1.0.0
@@ -97,4 +97,11 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.OpenAPISampler = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ | ||
if (refTokens.length === 0) { | ||
throw Error('Can not set the root object'); | ||
} | ||
for (var i = 0; i < refTokens.length - 1; ++i) { | ||
var tok = refTokens[i]; | ||
if (tok === "__proto__" || tok === "constructor" || tok === "prototype") { | ||
continue | ||
} | ||
if (tok === '-' && Array.isArray(obj)) { | ||
@@ -262,27 +269,33 @@ tok = obj.length; | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } | ||
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } | ||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } | ||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } | ||
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } | ||
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } | ||
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } } | ||
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } | ||
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } | ||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } | ||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } | ||
function allOfSample(into, children, options, spec, context) { | ||
var res = (0, _traverse2.traverse)(into, options, spec); | ||
var subSamples = []; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
var _iterator = _createForOfIteratorHelper(children), | ||
_step; | ||
try { | ||
for (var _iterator = children[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
for (_iterator.s(); !(_step = _iterator.n()).done;) { | ||
var subSchema = _step.value; | ||
@@ -309,14 +322,5 @@ | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
_iterator.e(err); | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return != null) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
_iterator.f(); | ||
} | ||
@@ -373,3 +377,3 @@ | ||
if (schema.type !== undefined) { | ||
return schema.type; | ||
return Array.isArray(schema.type) ? schema.type.length === 0 ? null : schema.type[0] : schema.type; | ||
} | ||
@@ -420,3 +424,4 @@ | ||
function sample(schema, options, spec) { | ||
function sample(schema, options) { | ||
var spec = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : schema; | ||
var opts = Object.assign({}, defaults, options); | ||
@@ -462,6 +467,8 @@ (0, _traverse.clearCache)(); | ||
var depth = context && context.depth || 1; | ||
var arrayLength = schema.minItems || 1; | ||
var arrayLength = Math.min('maxItems' in schema ? schema.maxItems : Infinity, schema.minItems || 1); // for the sake of simplicity, we're treating `contains` in a similar way to `items` | ||
if (Array.isArray(schema.items)) { | ||
arrayLength = Math.max(arrayLength, schema.items.length); | ||
var items = schema.items || schema.contains; | ||
if (Array.isArray(items)) { | ||
arrayLength = Math.max(arrayLength, items.length); | ||
} | ||
@@ -471,10 +478,10 @@ | ||
if (Array.isArray(schema.items)) { | ||
return schema.items[itemNumber] || {}; | ||
return items[itemNumber] || {}; | ||
} | ||
return schema.items || {}; | ||
return items || {}; | ||
}; | ||
var res = []; | ||
if (!schema.items) return res; | ||
if (!items) return res; | ||
@@ -563,31 +570,50 @@ for (var i = 0; i < arrayLength; i++) { | ||
function sampleNumber(schema) { | ||
var res; | ||
var res = 0; | ||
if (schema.maximum && schema.minimum) { | ||
res = schema.exclusiveMinimum ? Math.floor(schema.minimum) + 1 : schema.minimum; | ||
if (typeof schema.exclusiveMinimum === 'boolean' || typeof schema.exclusiveMaximum === 'boolean') { | ||
//legacy support for jsonschema draft 4 of exclusiveMaximum/exclusiveMinimum as booleans | ||
if (schema.maximum && schema.minimum) { | ||
res = schema.exclusiveMinimum ? Math.floor(schema.minimum) + 1 : schema.minimum; | ||
if (schema.exclusiveMaximum && res >= schema.maximum || !schema.exclusiveMaximum && res > schema.maximum) { | ||
res = (schema.maximum + schema.minimum) / 2; | ||
if (schema.exclusiveMaximum && res >= schema.maximum || !schema.exclusiveMaximum && res > schema.maximum) { | ||
res = (schema.maximum + schema.minimum) / 2; | ||
} | ||
return res; | ||
} | ||
return res; | ||
} | ||
if (schema.minimum) { | ||
if (schema.exclusiveMinimum) { | ||
return Math.floor(schema.minimum) + 1; | ||
} else { | ||
return schema.minimum; | ||
} | ||
} | ||
if (schema.minimum) { | ||
if (schema.exclusiveMinimum) { | ||
return Math.floor(schema.minimum) + 1; | ||
} else { | ||
if (schema.maximum) { | ||
if (schema.exclusiveMaximum) { | ||
return schema.maximum > 0 ? 0 : Math.floor(schema.maximum) - 1; | ||
} else { | ||
return schema.maximum > 0 ? 0 : schema.maximum; | ||
} | ||
} | ||
} else { | ||
if (schema.minimum) { | ||
return schema.minimum; | ||
} | ||
} | ||
if (schema.maximum) { | ||
if (schema.exclusiveMaximum) { | ||
return schema.maximum > 0 ? 0 : Math.floor(schema.maximum) - 1; | ||
} else { | ||
return schema.maximum > 0 ? 0 : schema.maximum; | ||
if (schema.exclusiveMinimum) { | ||
res = Math.floor(schema.exclusiveMinimum) + 1; | ||
if (res === schema.exclusiveMaximum) { | ||
res = (res + Math.floor(schema.exclusiveMaximum) - 1) / 2; | ||
} | ||
} else if (schema.exclusiveMaximum) { | ||
res = Math.floor(schema.exclusiveMaximum) - 1; | ||
} else if (schema.maximum) { | ||
res = schema.maximum; | ||
} | ||
} | ||
return 0; | ||
return res; | ||
} | ||
@@ -605,3 +631,3 @@ | ||
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
@@ -683,4 +709,8 @@ function sampleObject(schema) { | ||
function commonDateTimeSample(min, max, omitTime) { | ||
var res = (0, _utils.toRFCDateTime)(new Date('2019-08-24T14:15:22.123Z'), omitTime, false); | ||
function commonDateTimeSample(_ref) { | ||
var min = _ref.min, | ||
max = _ref.max, | ||
omitTime = _ref.omitTime, | ||
omitDate = _ref.omitDate; | ||
var res = (0, _utils.toRFCDateTime)(new Date('2019-08-24T14:15:22.123Z'), omitTime, omitDate, false); | ||
@@ -699,9 +729,28 @@ if (res.length < min) { | ||
function dateTimeSample(min, max) { | ||
return commonDateTimeSample(min, max); | ||
return commonDateTimeSample({ | ||
min: min, | ||
max: max, | ||
omitTime: false, | ||
omitDate: false | ||
}); | ||
} | ||
function dateSample(min, max) { | ||
return commonDateTimeSample(min, max, true); | ||
return commonDateTimeSample({ | ||
min: min, | ||
max: max, | ||
omitTime: true, | ||
omitDate: false | ||
}); | ||
} | ||
function timeSample(min, max) { | ||
return commonDateTimeSample({ | ||
min: min, | ||
max: max, | ||
omitTime: false, | ||
omitDate: true | ||
}).slice(1); | ||
} | ||
function defaultSample(min, max) { | ||
@@ -733,2 +782,18 @@ var res = (0, _utils.ensureMinLength)('string', min); | ||
function uriReferenceSample() { | ||
return '../dictionary'; | ||
} | ||
function uriTemplateSample() { | ||
return 'http://example.com/{endpoint}'; | ||
} | ||
function iriSample() { | ||
return 'http://example.com'; | ||
} | ||
function iriReferenceSample() { | ||
return '../dictionary'; | ||
} | ||
function uuidSample(_min, _max, propertyName) { | ||
@@ -738,13 +803,41 @@ return (0, _utils.uuid)(propertyName || 'id'); | ||
function jsonPointerSample() { | ||
return '/json/pointer'; | ||
} | ||
function relativeJsonPointerSample() { | ||
return '1/relative/json/pointer'; | ||
} | ||
function regexSample() { | ||
return '/regex/'; | ||
} | ||
var stringFormats = { | ||
'email': emailSample, | ||
'idn-email': emailSample, | ||
// https://tools.ietf.org/html/rfc6531#section-3.3 | ||
'password': passwordSample, | ||
'date-time': dateTimeSample, | ||
'date': dateSample, | ||
'time': timeSample, | ||
// full-time in https://tools.ietf.org/html/rfc3339#section-5.6 | ||
'ipv4': ipv4Sample, | ||
'ipv6': ipv6Sample, | ||
'hostname': hostnameSample, | ||
'idn-hostname': hostnameSample, | ||
// https://tools.ietf.org/html/rfc5890#section-2.3.2.3 | ||
'iri': iriSample, | ||
// https://tools.ietf.org/html/rfc3987 | ||
'iri-reference': iriReferenceSample, | ||
'uri': uriSample, | ||
'uri-reference': uriReferenceSample, | ||
// either a URI or relative-reference https://tools.ietf.org/html/rfc3986#section-4.1 | ||
'uri-template': uriTemplateSample, | ||
'uuid': uuidSample, | ||
'default': defaultSample | ||
'default': defaultSample, | ||
'json-pointer': jsonPointerSample, | ||
'relative-json-pointer': relativeJsonPointerSample, | ||
// https://tools.ietf.org/html/draft-handrews-relative-json-pointer-01 | ||
'regex': regexSample | ||
}; | ||
@@ -780,5 +873,5 @@ | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } | ||
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } | ||
@@ -810,6 +903,2 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
if (schema.$ref) { | ||
if (!spec) { | ||
throw new Error('Your schema contains $ref. You must provide full specification in the third parameter.'); | ||
} | ||
var ref = decodeURIComponent(schema.$ref); | ||
@@ -850,3 +939,3 @@ | ||
(0, _utils.popSchemaStack)(seenSchemasStack, context); | ||
return (0, _allOf.allOfSample)(_objectSpread({}, schema, { | ||
return (0, _allOf.allOfSample)(_objectSpread(_objectSpread({}, schema), {}, { | ||
allOf: undefined | ||
@@ -870,2 +959,6 @@ }), schema.allOf, options, spec, context); | ||
if (schema.if && schema.then) { | ||
return traverse((0, _utils.mergeDeep)(schema.if, schema.then), options, spec, context); | ||
} | ||
var example = null; | ||
@@ -885,2 +978,6 @@ var type = null; | ||
if (Array.isArray(type) && schema.type.length > 0) { | ||
type = schema.type[0]; | ||
} | ||
if (!type) { | ||
@@ -919,3 +1016,3 @@ type = (0, _infer.inferType)(schema); | ||
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
@@ -930,4 +1027,4 @@ function pad(number) { | ||
function toRFCDateTime(date, omitTime, milliseconds) { | ||
var res = date.getUTCFullYear() + '-' + pad(date.getUTCMonth() + 1) + '-' + pad(date.getUTCDate()); | ||
function toRFCDateTime(date, omitTime, omitDate, milliseconds) { | ||
var res = omitDate ? '' : date.getUTCFullYear() + '-' + pad(date.getUTCMonth() + 1) + '-' + pad(date.getUTCDate()); | ||
@@ -934,0 +1031,0 @@ if (!omitTime) { |
{ | ||
"name": "openapi-sampler", | ||
"version": "1.0.0-beta.18", | ||
"version": "1.0.0", | ||
"description": "Tool for generation samples based on OpenAPI payload/response schema", | ||
@@ -39,2 +39,4 @@ "main": "dist/openapi-sampler.js", | ||
"@babel/register": "^7.7.0", | ||
"ajv": "^8.1.0", | ||
"ajv-formats": "^2.0.2", | ||
"babel-eslint": "^10.0.3", | ||
@@ -62,2 +64,3 @@ "babel-loader": "^8.0.6", | ||
"gulp-uglify": "^3.0.2", | ||
"it-each": "^0.4.0", | ||
"json-loader": "^0.5.7", | ||
@@ -83,4 +86,5 @@ "karma": "^4.4.1", | ||
"dependencies": { | ||
"json-pointer": "^0.6.0" | ||
"@types/json-schema": "^7.0.7", | ||
"json-pointer": "^0.6.1" | ||
} | ||
} |
@@ -8,18 +8,29 @@ # openapi-sampler | ||
## Features | ||
- deterministic (given a particular input, will always produce the same output) | ||
- Supports `allOf` | ||
- Deterministic (given a particular input, will always produce the same output) | ||
- Supports compound keywords: `allOf`, `oneOf`, `anyOf`, `if/then/else` | ||
- Supports `additionalProperties` | ||
- Uses `default`, `const`, `enum` and `examples` where possible | ||
- Full array support: supports `minItems`, and tuples (`items` as an array) | ||
- Good array support: supports `contains`, `minItems`, `maxItems`, and tuples (`items` as an array) | ||
- Supports `minLength`, `maxLength`, `min`, `max`, `exclusiveMinimum`, `exclusiveMaximum` | ||
- Supports the next `string` formats: | ||
- Supports the following `string` formats: | ||
- idn-email | ||
- password | ||
- date-time | ||
- date | ||
- time | ||
- ipv4 | ||
- ipv6 | ||
- hostname | ||
- idn-hostname | ||
- uri | ||
- uri-reference | ||
- uri-template | ||
- iri | ||
- iri-reference | ||
- uuid | ||
- json-pointer | ||
- relative-json-pointer | ||
- regex | ||
- Infers schema type automatically following same rules as [json-schema-faker](https://www.npmjs.com/package/json-schema-faker#inferred-types) | ||
@@ -26,0 +37,0 @@ - Support for `$ref` resolving |
@@ -29,3 +29,3 @@ const schemaKeywordTypes = { | ||
if (schema.type !== undefined) { | ||
return schema.type; | ||
return Array.isArray(schema.type) ? schema.type.length === 0 ? null : schema.type[0] : schema.type; | ||
} | ||
@@ -32,0 +32,0 @@ const keywords = Object.keys(schemaKeywordTypes); |
@@ -11,3 +11,3 @@ import { traverse, clearCache } from './traverse'; | ||
export function sample(schema, options, spec) { | ||
export function sample(schema, options, spec = schema) { | ||
let opts = Object.assign({}, defaults, options); | ||
@@ -14,0 +14,0 @@ clearCache(); |
@@ -5,5 +5,7 @@ import { traverse } from '../traverse'; | ||
let arrayLength = schema.minItems || 1; | ||
if (Array.isArray(schema.items)) { | ||
arrayLength = Math.max(arrayLength, schema.items.length); | ||
let arrayLength = Math.min('maxItems' in schema ? schema.maxItems : Infinity, schema.minItems || 1); | ||
// for the sake of simplicity, we're treating `contains` in a similar way to `items` | ||
const items = schema.items || schema.contains; | ||
if (Array.isArray(items)) { | ||
arrayLength = Math.max(arrayLength, items.length); | ||
} | ||
@@ -13,9 +15,9 @@ | ||
if (Array.isArray(schema.items)) { | ||
return schema.items[itemNumber] || {}; | ||
return items[itemNumber] || {}; | ||
} | ||
return schema.items || {}; | ||
return items || {}; | ||
}; | ||
let res = []; | ||
if (!schema.items) return res; | ||
if (!items) return res; | ||
@@ -22,0 +24,0 @@ for (let i = 0; i < arrayLength; i++) { |
export function sampleNumber(schema) { | ||
let res; | ||
if (schema.maximum && schema.minimum) { | ||
res = schema.exclusiveMinimum ? Math.floor(schema.minimum) + 1 : schema.minimum; | ||
if ((schema.exclusiveMaximum && res >= schema.maximum) || | ||
((!schema.exclusiveMaximum && res > schema.maximum))) { | ||
res = (schema.maximum + schema.minimum) / 2; | ||
let res = 0; | ||
if (typeof schema.exclusiveMinimum === 'boolean' || typeof schema.exclusiveMaximum === 'boolean') { //legacy support for jsonschema draft 4 of exclusiveMaximum/exclusiveMinimum as booleans | ||
if (schema.maximum && schema.minimum) { | ||
res = schema.exclusiveMinimum ? Math.floor(schema.minimum) + 1 : schema.minimum; | ||
if ((schema.exclusiveMaximum && res >= schema.maximum) || | ||
((!schema.exclusiveMaximum && res > schema.maximum))) { | ||
res = (schema.maximum + schema.minimum) / 2; | ||
} | ||
return res; | ||
} | ||
return res; | ||
} | ||
if (schema.minimum) { | ||
if (schema.exclusiveMinimum) { | ||
return Math.floor(schema.minimum) + 1; | ||
} else { | ||
if (schema.minimum) { | ||
if (schema.exclusiveMinimum) { | ||
return Math.floor(schema.minimum) + 1; | ||
} else { | ||
return schema.minimum; | ||
} | ||
} | ||
if (schema.maximum) { | ||
if (schema.exclusiveMaximum) { | ||
return (schema.maximum > 0) ? 0 : Math.floor(schema.maximum) - 1; | ||
} else { | ||
return (schema.maximum > 0) ? 0 : schema.maximum; | ||
} | ||
} | ||
} else { | ||
if (schema.minimum) { | ||
return schema.minimum; | ||
} | ||
} | ||
if (schema.maximum) { | ||
if (schema.exclusiveMaximum) { | ||
return (schema.maximum > 0) ? 0 : Math.floor(schema.maximum) - 1; | ||
} else { | ||
return (schema.maximum > 0) ? 0 : schema.maximum; | ||
if (schema.exclusiveMinimum) { | ||
res = Math.floor(schema.exclusiveMinimum) + 1; | ||
if (res === schema.exclusiveMaximum) { | ||
res = (res + Math.floor(schema.exclusiveMaximum) - 1) / 2; | ||
} | ||
} else if (schema.exclusiveMaximum) { | ||
res = Math.floor(schema.exclusiveMaximum) - 1; | ||
} else if (schema.maximum) { | ||
res = schema.maximum; | ||
} | ||
} | ||
return 0; | ||
return res; | ||
} |
@@ -20,4 +20,4 @@ 'use strict'; | ||
function commonDateTimeSample(min, max, omitTime) { | ||
let res = toRFCDateTime(new Date('2019-08-24T14:15:22.123Z'), omitTime, false); | ||
function commonDateTimeSample({ min, max, omitTime, omitDate }) { | ||
let res = toRFCDateTime(new Date('2019-08-24T14:15:22.123Z'), omitTime, omitDate, false); | ||
if (res.length < min) { | ||
@@ -33,9 +33,13 @@ console.warn(`Using minLength = ${min} is incorrect with format "date-time"`); | ||
function dateTimeSample(min, max) { | ||
return commonDateTimeSample(min, max); | ||
return commonDateTimeSample({ min, max, omitTime: false, omitDate: false }); | ||
} | ||
function dateSample(min, max) { | ||
return commonDateTimeSample(min, max, true); | ||
return commonDateTimeSample({ min, max, omitTime: true, omitDate: false }); | ||
} | ||
function timeSample(min, max) { | ||
return commonDateTimeSample({ min, max, omitTime: false, omitDate: true }).slice(1); | ||
} | ||
function defaultSample(min, max) { | ||
@@ -65,2 +69,18 @@ let res = ensureMinLength('string', min); | ||
function uriReferenceSample() { | ||
return '../dictionary'; | ||
} | ||
function uriTemplateSample() { | ||
return 'http://example.com/{endpoint}'; | ||
} | ||
function iriSample() { | ||
return 'http://example.com'; | ||
} | ||
function iriReferenceSample() { | ||
return '../dictionary'; | ||
} | ||
function uuidSample(_min, _max, propertyName) { | ||
@@ -70,13 +90,35 @@ return uuid(propertyName || 'id'); | ||
function jsonPointerSample() { | ||
return '/json/pointer'; | ||
} | ||
function relativeJsonPointerSample() { | ||
return '1/relative/json/pointer'; | ||
} | ||
function regexSample() { | ||
return '/regex/'; | ||
} | ||
const stringFormats = { | ||
'email': emailSample, | ||
'idn-email': emailSample, // https://tools.ietf.org/html/rfc6531#section-3.3 | ||
'password': passwordSample, | ||
'date-time': dateTimeSample, | ||
'date': dateSample, | ||
'time': timeSample, // full-time in https://tools.ietf.org/html/rfc3339#section-5.6 | ||
'ipv4': ipv4Sample, | ||
'ipv6': ipv6Sample, | ||
'hostname': hostnameSample, | ||
'idn-hostname': hostnameSample, // https://tools.ietf.org/html/rfc5890#section-2.3.2.3 | ||
'iri': iriSample, // https://tools.ietf.org/html/rfc3987 | ||
'iri-reference': iriReferenceSample, | ||
'uri': uriSample, | ||
'uri-reference': uriReferenceSample, // either a URI or relative-reference https://tools.ietf.org/html/rfc3986#section-4.1 | ||
'uri-template': uriTemplateSample, | ||
'uuid': uuidSample, | ||
'default': defaultSample | ||
'default': defaultSample, | ||
'json-pointer': jsonPointerSample, | ||
'relative-json-pointer': relativeJsonPointerSample, // https://tools.ietf.org/html/draft-handrews-relative-json-pointer-01 | ||
'regex': regexSample, | ||
}; | ||
@@ -83,0 +125,0 @@ |
import { _samplers } from './openapi-sampler'; | ||
import { allOfSample } from './allOf'; | ||
import { inferType } from './infer'; | ||
import { getResultForCircular, popSchemaStack } from './utils'; | ||
import { getResultForCircular, mergeDeep, popSchemaStack } from './utils'; | ||
import JsonPointer from 'json-pointer'; | ||
@@ -31,5 +31,2 @@ | ||
if (schema.$ref) { | ||
if (!spec) { | ||
throw new Error('Your schema contains $ref. You must provide full specification in the third parameter.'); | ||
} | ||
let ref = decodeURIComponent(schema.$ref); | ||
@@ -90,2 +87,6 @@ if (ref.startsWith('#')) { | ||
if (schema.if && schema.then) { | ||
return traverse(mergeDeep(schema.if, schema.then), options, spec, context); | ||
} | ||
let example = null; | ||
@@ -103,2 +104,5 @@ let type = null; | ||
type = schema.type; | ||
if (Array.isArray(type) && schema.type.length > 0) { | ||
type = schema.type[0]; | ||
} | ||
if (!type) { | ||
@@ -105,0 +109,0 @@ type = inferType(schema); |
@@ -10,6 +10,6 @@ 'use strict'; | ||
export function toRFCDateTime(date, omitTime, milliseconds) { | ||
var res = date.getUTCFullYear() + | ||
export function toRFCDateTime(date, omitTime, omitDate, milliseconds) { | ||
var res = omitDate ? '' : (date.getUTCFullYear() + | ||
'-' + pad(date.getUTCMonth() + 1) + | ||
'-' + pad(date.getUTCDate()); | ||
'-' + pad(date.getUTCDate())); | ||
if (!omitTime) { | ||
@@ -96,2 +96,2 @@ res += 'T' + pad(date.getUTCHours()) + | ||
} | ||
} | ||
} |
@@ -47,2 +47,20 @@ 'use strict'; | ||
it('should support type array', function() { | ||
schema = { | ||
'type': ['string', 'number'] | ||
}; | ||
result = OpenAPISampler.sample(schema); | ||
expected = 'string'; | ||
expect(result).to.deep.equal(expected); | ||
}); | ||
it('should use null for null', function() { | ||
schema = { | ||
type: 'null' | ||
}; | ||
result = OpenAPISampler.sample(schema); | ||
expected = null; | ||
expect(result).to.deep.equal(expected); | ||
}); | ||
it('should use null if type is not specified', function() { | ||
@@ -55,2 +73,11 @@ schema = { | ||
}); | ||
it('should use null if type array is empty', function() { | ||
schema = { | ||
type: [] | ||
}; | ||
result = OpenAPISampler.sample(schema); | ||
expected = null; | ||
expect(result).to.deep.equal(expected); | ||
}); | ||
}); | ||
@@ -433,51 +460,69 @@ | ||
describe('oneOf and anyOf', function() { | ||
it('should support oneOf', function() { | ||
describe('Compound keywords', () => { | ||
it('should support basic if/then/else usage', () => { | ||
schema = { | ||
oneOf: [ | ||
{ | ||
type: 'string' | ||
}, | ||
{ | ||
type: 'number' | ||
} | ||
] | ||
type: 'object', | ||
if: {properties: {foo: {type: 'string', format: 'email'}}}, | ||
then: {properties: {bar: {type: 'string'}}}, | ||
else: {properties: {baz: {type: 'number'}}}, | ||
}; | ||
result = OpenAPISampler.sample(schema); | ||
expected = 'string'; | ||
expect(result).to.equal(expected); | ||
}); | ||
it('should support anyOf', function() { | ||
schema = { | ||
anyOf: [ | ||
{ | ||
type: 'string' | ||
}, | ||
{ | ||
type: 'number' | ||
} | ||
] | ||
expected = { | ||
foo: 'user@example.com', | ||
bar: 'string' | ||
}; | ||
result = OpenAPISampler.sample(schema); | ||
expected = 'string'; | ||
expect(result).to.equal(expected); | ||
}); | ||
expect(result).to.deep.equal(expected); | ||
}) | ||
it('should prefer oneOf if anyOf and oneOf are on the same level ', function() { | ||
schema = { | ||
anyOf: [ | ||
{ | ||
type: 'string' | ||
} | ||
], | ||
oneOf: [ | ||
{ | ||
type: 'number' | ||
} | ||
] | ||
}; | ||
result = OpenAPISampler.sample(schema); | ||
expected = 0; | ||
expect(result).to.equal(expected); | ||
describe('oneOf and anyOf', function () { | ||
it('should support oneOf', function () { | ||
schema = { | ||
oneOf: [ | ||
{ | ||
type: 'string' | ||
}, | ||
{ | ||
type: 'number' | ||
} | ||
] | ||
}; | ||
result = OpenAPISampler.sample(schema); | ||
expected = 'string'; | ||
expect(result).to.equal(expected); | ||
}); | ||
it('should support anyOf', function () { | ||
schema = { | ||
anyOf: [ | ||
{ | ||
type: 'string' | ||
}, | ||
{ | ||
type: 'number' | ||
} | ||
] | ||
}; | ||
result = OpenAPISampler.sample(schema); | ||
expected = 'string'; | ||
expect(result).to.equal(expected); | ||
}); | ||
it('should prefer oneOf if anyOf and oneOf are on the same level ', function () { | ||
schema = { | ||
anyOf: [ | ||
{ | ||
type: 'string' | ||
} | ||
], | ||
oneOf: [ | ||
{ | ||
type: 'number' | ||
} | ||
] | ||
}; | ||
result = OpenAPISampler.sample(schema); | ||
expected = 0; | ||
expect(result).to.equal(expected); | ||
}); | ||
}); | ||
@@ -488,6 +533,8 @@ }); | ||
it('should follow $ref', function() { | ||
schema = { | ||
$ref: '#/defs/Schema' | ||
}; | ||
const spec = { | ||
const schema = { | ||
properties: { | ||
test: { | ||
$ref: '#/defs/Schema' | ||
} | ||
}, | ||
defs: { | ||
@@ -504,5 +551,7 @@ Schema: { | ||
}; | ||
result = OpenAPISampler.sample(schema, {}, spec); | ||
result = OpenAPISampler.sample(schema, {}); | ||
expected = { | ||
a: 'string' | ||
test: { | ||
a: 'string' | ||
} | ||
}; | ||
@@ -575,3 +624,3 @@ expect(result).to.deep.equal(expected); | ||
expect(() => OpenAPISampler.sample(schema)).to | ||
.throw(/You must provide full specification in the third parameter/); | ||
.throw(/Invalid reference token: defs/); | ||
}); | ||
@@ -578,0 +627,0 @@ |
@@ -14,4 +14,11 @@ import { sampleArray } from '../../src/samplers/array.js'; | ||
expect(res).to.deep.equal([0]); | ||
res = sampleArray({contains: {type: 'number'}}); | ||
expect(res).to.deep.equal([0]); | ||
}); | ||
it('should return correct number of elements based on maxItems', () => { | ||
res = sampleArray({items: {type: 'number'}, maxItems: 0}); | ||
expect(res).to.deep.equal([]); | ||
}); | ||
it('should return correct number of elements based on minItems', () => { | ||
@@ -22,3 +29,3 @@ res = sampleArray({items: {type: 'number'}, minItems: 3}); | ||
it('should correcly sample tuples', () => { | ||
it('should correctly sample tuples', () => { | ||
res = sampleArray({items: [{type: 'number'}, {type: 'string'}, {}]}); | ||
@@ -25,0 +32,0 @@ expect(res).to.deep.equal([0, 'string', null]); |
@@ -40,2 +40,7 @@ import { sampleNumber } from '../../src/samplers/number.js'; | ||
it('should return maximum -1 if maximum is negative and exclusiveMaximum', () => { | ||
res = sampleNumber({maximum: -3, exclusiveMaximum: true, minimum: 1, exclusiveMinimum: true}); | ||
expect(res).to.equal(-1); | ||
}); | ||
it('should return minimum if both minimum and maximum are specified', () => { | ||
@@ -46,13 +51,34 @@ res = sampleNumber({maximum: 10, minimum: 3}); | ||
// (2, 3) -> 2.5 | ||
it('should return middle point if integer is not possible', () => { | ||
res = sampleNumber({minimum: 2, maximum: 3, exclusiveMinimum: true, exclusiveMaximum: true}); | ||
expect(res).to.equal(2.5); | ||
it('should return exclusiveMinimum + 1 if exclusiveMinimum is specified for openapi3.1', () => { | ||
res = sampleNumber({exclusiveMinimum: 3}); | ||
expect(res).to.equal(4); | ||
}); | ||
// (2, 3] -> 3 | ||
it('should return closer to minimum possible int', () => { | ||
res = sampleNumber({minimum: 2, maximum: 3, exclusiveMinimum: true}); | ||
expect(res).to.equal(3); | ||
it('should return exclusiveMaximum - 1 if exclusiveMaximum is specified for openapi3.1', () => { | ||
res = sampleNumber({exclusiveMaximum: -3}); | ||
expect(res).to.equal(-4); | ||
}); | ||
// (2, 3) -> 2.5 | ||
it('should return middle point if boundary integer is not possible for openapi3.1', () => { | ||
res = sampleNumber({exclusiveMinimum: 2, exclusiveMaximum: 3}); | ||
expect(res).to.equal(2.5); | ||
}); | ||
// [2, 3] -> 2 | ||
// (8, 13) -> 9 | ||
it('should return closer to minimum possible int for openapi3.1', () => { | ||
res = sampleNumber({minimum: 2, maximum: 3}); | ||
expect(res).to.equal(2); | ||
res = sampleNumber({exclusiveMinimum: 8, exclusiveMaximum: 13}); | ||
expect(res).to.equal(9); | ||
}); | ||
it('should return closer to minimum possible int for openapi3.1', () => { | ||
res = sampleNumber({minimum: 2, maximum: 3}); | ||
expect(res).to.equal(2); | ||
res = sampleNumber({exclusiveMinimum: 8, exclusiveMaximum: 13}); | ||
expect(res).to.equal(9); | ||
}); | ||
}); |
import { sampleString } from '../../src/samplers/string.js'; | ||
import Ajv from 'ajv'; | ||
import addFormats from 'ajv-formats'; | ||
const ajv = new Ajv({ allErrors: true, messages: true, strict: true }); | ||
addFormats(ajv); | ||
require('it-each')(); | ||
const IPV4_REGEXP = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; | ||
@@ -77,2 +86,17 @@ const IPV6_REGEXP = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/; | ||
it('should return deterministic time string for format date-time', () => { | ||
res = sampleString({format: 'time'}); | ||
expect(res).to.equal('14:15:22Z'); | ||
}); | ||
it('should not throw if incorrect maxLength applied to time', () => { | ||
res = sampleString({format: 'time', maxLength: 5}); | ||
expect(res).to.equal('14:15:22Z') | ||
}); | ||
it('should not throw if incorrect minLength applied to time', () => { | ||
res = sampleString({format: 'time', minLength: 100}); | ||
expect(res).to.equal('14:15:22Z') | ||
}); | ||
it('should return ip for ipv4 format', () => { | ||
@@ -109,2 +133,27 @@ res = sampleString({format: 'ipv4'}); | ||
}); | ||
it.each([ | ||
'email', | ||
// 'idn-email', // unsupported by ajv-formats | ||
// 'password', // unsupported by ajv-formats | ||
'date-time', | ||
'date', | ||
'time', | ||
'ipv4', | ||
'ipv6', | ||
'hostname', | ||
// 'idn-hostname', // unsupported by ajv-formats | ||
'uri', | ||
'uri-reference', | ||
'uri-template', | ||
// 'iri', // unsupported by ajv-formats | ||
// 'iri-reference', // unsupported by ajv-formats | ||
'uuid', | ||
'json-pointer', | ||
'relative-json-pointer', | ||
'regex' | ||
], 'should return valid %s', format => { | ||
const schema = {type: 'string',format}; | ||
expect(ajv.compile(schema)(sampleString(schema))).to.be.true; | ||
}); | ||
}); |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
98705
41
2717
0
83
2
46
+ Added@types/json-schema@^7.0.7
+ Added@types/json-schema@7.0.15(transitive)
Updatedjson-pointer@^0.6.1