Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

openapi-sampler

Package Overview
Dependencies
Maintainers
1
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

openapi-sampler - npm Package Compare versions

Comparing version 1.4.0 to 1.5.0

src/samplers/string-regex.js

378

dist/openapi-sampler.js

@@ -304,3 +304,3 @@ (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){

},{"./traverse":12,"./utils":13}],4:[function(require,module,exports){
},{"./traverse":13,"./utils":14}],4:[function(require,module,exports){
"use strict";

@@ -390,3 +390,3 @@

},{"./infer":4,"./samplers/index":8,"./traverse":12}],6:[function(require,module,exports){
},{"./infer":4,"./samplers/index":8,"./traverse":13}],6:[function(require,module,exports){
"use strict";

@@ -427,3 +427,3 @@

},{"../traverse":12}],7:[function(require,module,exports){
},{"../traverse":13}],7:[function(require,module,exports){
"use strict";

@@ -481,3 +481,3 @@

},{"./array":6,"./boolean":7,"./number":9,"./object":10,"./string":11}],9:[function(require,module,exports){
},{"./array":6,"./boolean":7,"./number":9,"./object":10,"./string":12}],9:[function(require,module,exports){
"use strict";

@@ -547,10 +547,11 @@

if (schema && typeof schema.properties === 'object') {
let requiredKeys = Array.isArray(schema.required) ? schema.required : [];
let requiredKeyDict = requiredKeys.reduce((dict, key) => {
dict[key] = true;
return dict;
}, {});
// Prepare for skipNonRequired option
const requiredProperties = Array.isArray(schema.required) ? schema.required : [];
const requiredPropertiesMap = {};
for (const requiredProperty of requiredProperties) {
requiredPropertiesMap[requiredProperty] = true;
}
Object.keys(schema.properties).forEach(propertyName => {
// skip before traverse that could be costly
if (options.skipNonRequired && !requiredKeyDict.hasOwnProperty(propertyName)) {
if (options.skipNonRequired && !requiredPropertiesMap.hasOwnProperty(propertyName)) {
return;

@@ -580,6 +581,347 @@ }

}
// Strictly enforce maxProperties constraint
if (schema && typeof schema.properties === 'object' && schema.maxProperties !== undefined && Object.keys(res).length > schema.maxProperties) {
const filteredResult = {};
let propertiesAdded = 0;
// Always include required properties first, if present
const requiredProperties = Array.isArray(schema.required) ? schema.required : [];
requiredProperties.forEach(propName => {
if (res[propName] !== undefined) {
filteredResult[propName] = res[propName];
propertiesAdded++;
}
});
// Add other properties until maxProperties is reached
Object.keys(res).forEach(propName => {
if (propertiesAdded < schema.maxProperties && !filteredResult.hasOwnProperty(propName)) {
filteredResult[propName] = res[propName];
propertiesAdded++;
}
});
res = filteredResult;
}
return res;
}
},{"../traverse":12}],11:[function(require,module,exports){
},{"../traverse":13}],11:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.regexSample = regexSample;
/**
Faker - Copyright (c) 2022-2023
This software consists of voluntary contributions made by many individuals.
For exact contribution history, see the revision history
available at https://github.com/faker-js/faker
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
===
From: https://github.com/faker-js/faker/commit/a9f98046c7d5eeaabe12fc587024c06d683800b8
To: https://github.com/faker-js/faker/commit/29234378807c4141588861f69421bf20b5ac635e
Based on faker.js, copyright Marak Squires and contributor, what follows below is the original license.
===
faker.js - Copyright (c) 2020
Marak Squires
http://github.com/marak/faker.js/
faker.js was inspired by and has used data definitions from:
* https://github.com/stympy/faker/ - Copyright (c) 2007-2010 Benjamin Curtis
* http://search.cpan.org/~jasonk/Data-Faker-0.07/ - Copyright 2004-2005 by Jason Kohles
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/** @returns {boolean} */
function boolSample() {
return true;
}
/**
* @param {number} min - inclusive
* @param {number} _max - inclusive
* @returns {number}
*/
function intSample(min, _max) {
return min;
}
/**
* Returns a number based on given RegEx-based quantifier symbol or quantifier values.
*
* @param {string} quantifierSymbol Quantifier symbols can be either of these: `?`, `*`, `+`.
* @param {string} quantifierMin Quantifier minimum value. If given without a maximum, this will be used as the quantifier value.
* @param {string} quantifierMax Quantifier maximum value. Will randomly get a value between the minimum and maximum if both are provided.
*
* @returns {number} a random number based on the given quantifier parameters.
*
* @example
* getRepetitionsBasedOnQuantifierParameters('*', null, null) // 3
* getRepetitionsBasedOnQuantifierParameters(null, 10, null) // 10
* getRepetitionsBasedOnQuantifierParameters(null, 5, 8) // 6
*
* @since 8.0.0
*/
function getRepetitionsBasedOnQuantifierParameters(quantifierSymbol, quantifierMin, quantifierMax) {
let repetitions = 1;
if (quantifierSymbol) {
switch (quantifierSymbol) {
case '?':
{
repetitions = boolSample() ? 0 : 1;
break;
}
case '*':
{
const limit = 8;
repetitions = intSample(0, limit);
break;
}
case '+':
{
const limit = 8;
repetitions = intSample(1, limit);
break;
}
default:
throw new Error('Unknown quantifier symbol provided.');
}
} else if (quantifierMin != null && quantifierMax != null) {
repetitions = intSample(parseInt(quantifierMin), parseInt(quantifierMax));
} else if (quantifierMin != null && quantifierMax == null) {
repetitions = parseInt(quantifierMin);
}
return repetitions;
}
/**
* Generates a string matching the given regex like expressions.
*
* This function doesn't provide full support of actual `RegExp`.
* Features such as grouping, anchors and character classes are not supported.
* If you are looking for a library that randomly generates strings based on
* `RegExp`s, see [randexp.js](https://github.com/fent/randexp.js)
*
* Supported patterns:
* - `x{times}` => Repeat the `x` exactly `times` times.
* - `x{min,max}` => Repeat the `x` `min` to `max` times.
* - `[x-y]` => Randomly get a character between `x` and `y` (inclusive).
* - `[x-y]{times}` => Randomly get a character between `x` and `y` (inclusive) and repeat it `times` times.
* - `[x-y]{min,max}` => Randomly get a character between `x` and `y` (inclusive) and repeat it `min` to `max` times.
* - `[^...]` => Randomly get an ASCII number or letter character that is not in the given range. (e.g. `[^0-9]` will get a random non-numeric character).
* - `[-...]` => Include dashes in the range. Must be placed after the negate character `^` and before any character sets if used (e.g. `[^-0-9]` will not get any numeric characters or dashes).
* - `/[x-y]/i` => Randomly gets an uppercase or lowercase character between `x` and `y` (inclusive).
* - `x?` => Randomly decide to include or not include `x`.
* - `[x-y]?` => Randomly decide to include or not include characters between `x` and `y` (inclusive).
* - `x*` => Repeat `x` 0 or more times.
* - `[x-y]*` => Repeat characters between `x` and `y` (inclusive) 0 or more times.
* - `x+` => Repeat `x` 1 or more times.
* - `[x-y]+` => Repeat characters between `x` and `y` (inclusive) 1 or more times.
* - `.` => returns a wildcard ASCII character that can be any number, character or symbol. Can be combined with quantifiers as well.
*
* @param {string | RegExp} pattern The template string/RegExp to generate a matching string for.
* @returns {string} A string matching the given pattern.
*
* @throws If min value is more than max value in quantifier. e.g. `#{10,5}`
* @throws If invalid quantifier symbol is passed in.
*
* @example
* regexSample('#{5}') // '#####'
* regexSample('#{2,9}') // '#######'
* regexSample('[1-7]') // '5'
* regexSample('#{3}test[1-5]') // '###test3'
* regexSample('[0-9a-dmno]') // '5'
* regexSample('[^a-zA-Z0-8]') // '9'
* regexSample('[a-d0-6]{2,8}') // 'a0dc45b0'
* regexSample('[-a-z]{5}') // 'a-zab'
* regexSample(/[A-Z0-9]{4}-[A-Z0-9]{4}/) // 'BS4G-485H'
* regexSample(/[A-Z]{5}/i) // 'pDKfh'
* regexSample(/.{5}/) // '14(#B'
* regexSample(/Joh?n/) // 'Jon'
* regexSample(/ABC*DE/) // 'ABDE'
* regexSample(/bee+p/) // 'beeeeeeeep'
*
* @since 8.0.0
*/
function regexSample(pattern) {
let isCaseInsensitive = false;
if (pattern instanceof RegExp) {
var _pattern$match;
isCaseInsensitive = pattern.flags.includes('i');
pattern = pattern.toString();
pattern = ((_pattern$match = pattern.match(/\/(.+?)\//)) === null || _pattern$match === void 0 ? void 0 : _pattern$match[1]) ?? ''; // Remove frontslash from front and back of RegExp
}
let min;
let max;
let repetitions;
// Deal with single wildcards
const SINGLE_CHAR_REG = /([.A-Za-z0-9])(?:\{(\d+)(?:\,(\d+)|)\}|(\?|\*|\+))(?![^[]*]|[^{]*})/;
let token = pattern.match(SINGLE_CHAR_REG);
while (token != null) {
const quantifierMin = token[2];
const quantifierMax = token[3];
const quantifierSymbol = token[4];
repetitions = getRepetitionsBasedOnQuantifierParameters(quantifierSymbol, quantifierMin, quantifierMax);
pattern = pattern.slice(0, token.index) + token[1].repeat(repetitions) + pattern.slice(token.index + token[0].length);
token = pattern.match(SINGLE_CHAR_REG);
}
const SINGLE_RANGE_REG = /(\d-\d|\w-\w|\d|\w|[-!@#$&()`.+,/"])/;
const RANGE_ALPHANUMEMRIC_REG = /\[(\^|)(-|)(.+?)\](?:\{(\d+)(?:\,(\d+)|)\}|(\?|\*|\+)|)/;
// Deal with character classes with quantifiers `[a-z0-9]{min[, max]}`
token = pattern.match(RANGE_ALPHANUMEMRIC_REG);
while (token != null) {
const isNegated = token[1] === '^';
const includesDash = token[2] === '-';
const quantifierMin = token[4];
const quantifierMax = token[5];
const quantifierSymbol = token[6];
const rangeCodes = [];
let ranges = token[3];
let range = ranges.match(SINGLE_RANGE_REG);
if (includesDash) {
// 45 is the ascii code for '-'
rangeCodes.push(45);
}
while (range != null) {
if (range[0].indexOf('-') === -1) {
// handle non-ranges
if (isCaseInsensitive && isNaN(Number(range[0]))) {
rangeCodes.push(range[0].toUpperCase().charCodeAt(0));
rangeCodes.push(range[0].toLowerCase().charCodeAt(0));
} else {
rangeCodes.push(range[0].charCodeAt(0));
}
} else {
// handle ranges
const rangeMinMax = range[0].split('-').map(x => x.charCodeAt(0));
min = rangeMinMax[0];
max = rangeMinMax[1];
// throw error if min larger than max
if (min > max) {
throw new Error('Character range provided is out of order.');
}
for (let i = min; i <= max; i++) {
if (isCaseInsensitive && isNaN(Number(String.fromCharCode(i)))) {
const ch = String.fromCharCode(i);
rangeCodes.push(ch.toUpperCase().charCodeAt(0));
rangeCodes.push(ch.toLowerCase().charCodeAt(0));
} else {
rangeCodes.push(i);
}
}
}
ranges = ranges.substring(range[0].length);
range = ranges.match(SINGLE_RANGE_REG);
}
repetitions = getRepetitionsBasedOnQuantifierParameters(quantifierSymbol, quantifierMin, quantifierMax);
if (isNegated) {
let index = -1;
// 0-9
for (let i = 48; i <= 57; i++) {
index = rangeCodes.indexOf(i);
if (index > -1) {
rangeCodes.splice(index, 1);
continue;
}
rangeCodes.push(i);
}
// A-Z
for (let i = 65; i <= 90; i++) {
index = rangeCodes.indexOf(i);
if (index > -1) {
rangeCodes.splice(index, 1);
continue;
}
rangeCodes.push(i);
}
// a-z
for (let i = 97; i <= 122; i++) {
index = rangeCodes.indexOf(i);
if (index > -1) {
rangeCodes.splice(index, 1);
continue;
}
rangeCodes.push(i);
}
}
const generatedString = Array.from({
length: repetitions
}, () => String.fromCharCode(rangeCodes[intSample(0, rangeCodes.length - 1)])).join('');
pattern = pattern.slice(0, token.index) + generatedString + pattern.slice(token.index + token[0].length);
token = pattern.match(RANGE_ALPHANUMEMRIC_REG);
}
const RANGE_REP_REG = /(.)\{(\d+)\,(\d+)\}/;
// Deal with quantifier ranges `{min,max}`
token = pattern.match(RANGE_REP_REG);
while (token != null) {
min = parseInt(token[2]);
max = parseInt(token[3]);
// throw error if min larger than max
if (min > max) {
throw new Error('Numbers out of order in {} quantifier.');
}
repetitions = intSample(min, max);
pattern = pattern.slice(0, token.index) + token[1].repeat(repetitions) + pattern.slice(token.index + token[0].length);
token = pattern.match(RANGE_REP_REG);
}
const REP_REG = /(.)\{(\d+)\}/;
// Deal with repeat `{num}`
token = pattern.match(REP_REG);
while (token != null) {
repetitions = parseInt(token[2]);
pattern = pattern.slice(0, token.index) + token[1].repeat(repetitions) + pattern.slice(token.index + token[0].length);
token = pattern.match(REP_REG);
}
return pattern;
}
},{}],12:[function(require,module,exports){
'use strict';

@@ -592,2 +934,5 @@

var _utils = require("../utils");
var faker = _interopRequireWildcard(require("./string-regex"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const passwordSymbols = 'qwerty!@#$%^123456';

@@ -647,3 +992,6 @@ function emailSample() {

}
function defaultSample(min, max) {
function defaultSample(min, max, _propertyName, pattern) {
if (pattern) {
return faker.regexSample(pattern);
}
let res = (0, _utils.ensureMinLength)('string', min);

@@ -726,6 +1074,6 @@ if (max && res.length > max) {

let propertyName = context && context.propertyName;
return sampler(schema.minLength | 0, schema.maxLength, propertyName);
return sampler(schema.minLength || 0, schema.maxLength, propertyName, schema.pattern);
}
},{"../utils":13}],12:[function(require,module,exports){
},{"../utils":14,"./string-regex":11}],13:[function(require,module,exports){
"use strict";

@@ -902,3 +1250,3 @@

},{"./allOf":3,"./infer":4,"./openapi-sampler":5,"./utils":13,"json-pointer":2}],13:[function(require,module,exports){
},{"./allOf":3,"./infer":4,"./openapi-sampler":5,"./utils":14,"json-pointer":2}],14:[function(require,module,exports){
'use strict';

@@ -905,0 +1253,0 @@

2

package.json
{
"name": "openapi-sampler",
"version": "1.4.0",
"version": "1.5.0",
"description": "Tool for generation samples based on OpenAPI payload/response schema",

@@ -5,0 +5,0 @@ "main": "dist/openapi-sampler.js",

@@ -14,3 +14,3 @@ # openapi-sampler

- Good array support: supports `contains`, `minItems`, `maxItems`, and tuples (`items` as an array)
- Supports `minLength`, `maxLength`, `min`, `max`, `exclusiveMinimum`, `exclusiveMaximum`
- Supports `minLength`, `maxLength`, `min`, `max`, `exclusiveMinimum`, `exclusiveMaximum`, ([limited](https://fakerjs.dev/api/helpers.html#fromregexp)) `pattern`
- Supports the following `string` formats:

@@ -44,3 +44,3 @@ - email

npm install openapi-sampler --save
npm install openapi-sampler

@@ -47,0 +47,0 @@ or using [yarn](https://yarnpkg.com)

@@ -7,11 +7,14 @@ import { traverse } from '../traverse';

if (schema && typeof schema.properties === 'object') {
let requiredKeys = (Array.isArray(schema.required) ? schema.required : []);
let requiredKeyDict = requiredKeys.reduce((dict, key) => {
dict[key] = true;
return dict;
}, {});
// Prepare for skipNonRequired option
const requiredProperties = Array.isArray(schema.required) ? schema.required : [];
const requiredPropertiesMap = {};
for (const requiredProperty of requiredProperties) {
requiredPropertiesMap[requiredProperty] = true;
}
Object.keys(schema.properties).forEach(propertyName => {
// skip before traverse that could be costly
if (options.skipNonRequired && !requiredKeyDict.hasOwnProperty(propertyName)) {
if (options.skipNonRequired && !requiredPropertiesMap.hasOwnProperty(propertyName)) {
return;

@@ -37,3 +40,29 @@ }

}
// Strictly enforce maxProperties constraint
if (schema && typeof schema.properties === 'object' && schema.maxProperties !== undefined && Object.keys(res).length > schema.maxProperties) {
const filteredResult = {};
let propertiesAdded = 0;
// Always include required properties first, if present
const requiredProperties = Array.isArray(schema.required) ? schema.required : [];
requiredProperties.forEach(propName => {
if (res[propName] !== undefined) {
filteredResult[propName] = res[propName];
propertiesAdded++;
}
});
// Add other properties until maxProperties is reached
Object.keys(res).forEach(propName => {
if (propertiesAdded < schema.maxProperties && !filteredResult.hasOwnProperty(propName)) {
filteredResult[propName] = res[propName];
propertiesAdded++;
}
});
res = filteredResult;
}
return res;
}
'use strict';
import { ensureMinLength, toRFCDateTime, uuid } from '../utils';
import * as faker from './string-regex';

@@ -45,3 +46,6 @@ const passwordSymbols = 'qwerty!@#$%^123456';

function defaultSample(min, max) {
function defaultSample(min, max, _propertyName, pattern) {
if (pattern) {
return faker.regexSample(pattern);
}
let res = ensureMinLength('string', min);

@@ -131,3 +135,8 @@ if (max && res.length > max) {

let propertyName = context && context.propertyName;
return sampler(schema.minLength | 0, schema.maxLength, propertyName);
return sampler(
schema.minLength || 0,
schema.maxLength,
propertyName,
schema.pattern,
);
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc