simpler-mocks
Advanced tools
Comparing version 2.0.4 to 2.1.0-beta.1
{ | ||
"name": "simpler-mocks", | ||
"version": "2.0.4", | ||
"version": "2.1.0-beta.1", | ||
"description": "REST API mock server made simple. Runs on Node with YAML and JSON mock definitions.", | ||
@@ -29,3 +29,3 @@ "keywords": [ | ||
"engines": { | ||
"node": ">=10.0.0" | ||
"node": ">=12.0.0" | ||
}, | ||
@@ -43,26 +43,27 @@ "scripts": { | ||
"dependencies": { | ||
"argparse": "^1.0.10", | ||
"chance": "^1.1.7", | ||
"chokidar": "^3.4.1", | ||
"argparse": "^2.0.1", | ||
"chance": "^1.1.8", | ||
"chokidar": "^3.5.3", | ||
"globby": "^11.0.1", | ||
"js-yaml": "^3.14.0", | ||
"js-yaml": "^4.1.0", | ||
"js-yaml-js-types": "^1.0.0", | ||
"koa": "^2.13.0", | ||
"koa-bodyparser": "^4.3.0", | ||
"koa-logger": "^3.2.1", | ||
"koa-router": "^9.1.0", | ||
"koa-router": "^12.0.0", | ||
"lodash.get": "^4.4.2", | ||
"lodash.isequalwith": "^4.4.0", | ||
"lodash.ismatchwith": "^4.4.0", | ||
"minimatch": "^3.0.4" | ||
"minimatch": "^5.1.0" | ||
}, | ||
"devDependencies": { | ||
"commitizen": "^4.1.2", | ||
"cz-conventional-changelog": "^3.2.0", | ||
"husky": "^8.0.0", | ||
"jest": "^26.1.0", | ||
"commitizen": "^4.2.5", | ||
"cz-conventional-changelog": "^3.3.0", | ||
"husky": "^8.0.1", | ||
"jest": "^29.0.2", | ||
"nodemon": "^2.0.4", | ||
"prettier": "^2.0.5", | ||
"pretty-quick": "^2.0.1", | ||
"prettier": "^2.7.1", | ||
"pretty-quick": "^3.1.3", | ||
"semantic-release": "^19.0.5", | ||
"supertest": "^4.0.2" | ||
"supertest": "^6.2.4" | ||
}, | ||
@@ -69,0 +70,0 @@ "repository": { |
@@ -8,42 +8,45 @@ #!/usr/bin/env node | ||
const cli = new ArgumentParser({ | ||
addHelp: true, | ||
add_help: true, | ||
prog: 'simpler-mocks', | ||
version: pkg.version, | ||
description: pkg.description | ||
}) | ||
cli.addArgument(['--port', '-p'], { | ||
cli.add_argument('--port', '-p', { | ||
type: 'int', | ||
defaultValue: process.env.MOCKS_PORT || 0, | ||
default: process.env.MOCKS_PORT || 0, | ||
help: 'The port to run the server on. Defaults to a random open port if none is set.' | ||
}) | ||
cli.addArgument(['--silent', '-s'], { | ||
action: 'storeTrue', | ||
cli.add_argument('--silent', '-s', { | ||
action: 'store_true', | ||
help: 'Hides http access logs from the terminal.' | ||
}) | ||
cli.addArgument(['--verbose', '-vv'], { | ||
action: 'storeTrue', | ||
cli.add_argument('--verbose', '-vv', { | ||
action: 'store_true', | ||
help: 'Shows more informational console logs.' | ||
}) | ||
cli.addArgument(['--watch', '-w'], { | ||
action: 'storeTrue', | ||
cli.add_argument('--watch', '-w', { | ||
action: 'store_true', | ||
help: 'Watch the base directory for changes' | ||
}) | ||
cli.addArgument(['--nodelays', '-n'], { | ||
action: 'storeTrue', | ||
cli.add_argument('--nodelays', '-n', { | ||
action: 'store_true', | ||
help: 'Ignores all delay settings in the mocks' | ||
}) | ||
cli.addArgument(['directory'], { | ||
cli.add_argument('directory', { | ||
nargs: '?', | ||
defaultValue: './', | ||
help: | ||
'The directory where mock api definition files are located. Glob syntax supported. Defaults to the current working directory.' | ||
default: './', | ||
help: 'The directory where mock api definition files are located. Glob syntax supported. Defaults to the current working directory.' | ||
}) | ||
const args = cli.parseArgs() | ||
cli.add_argument('-v', '--version', { | ||
action: 'version', | ||
version: `Version: ${pkg.version}` | ||
}) | ||
const args = cli.parse_args() | ||
const mocksDirectory = path.resolve(process.cwd(), args.directory) | ||
@@ -50,0 +53,0 @@ |
const fs = require('fs') | ||
const yaml = require('js-yaml') | ||
const jsTypes = require('js-yaml-js-types') | ||
const _get = require('lodash.get') | ||
@@ -11,2 +12,6 @@ const chance = require('chance').Chance() | ||
const ONCE = 'once' | ||
const OPTIONAL = 'optional' | ||
const WHEN = 'when' | ||
// Example Custom Type | ||
@@ -50,3 +55,3 @@ // https://github.com/nodeca/js-yaml/blob/master/examples/custom_types.js | ||
try { | ||
output = yaml.safeLoad(fileContent, { schema: CUSTOM_TAGS }) | ||
output = yaml.load(fileContent, { schema: CUSTOM_TAGS }) | ||
} catch (error) { | ||
@@ -195,6 +200,9 @@ /* istanbul ignore next */ | ||
kind: 'mapping', | ||
multi: true, | ||
resolve: (data) => data && Object.keys(data).length === 1, // can only have one key | ||
construct: (data) => { | ||
construct: (data, type) => { | ||
const [tag, ...options] = type.split('.') | ||
const [key] = Object.keys(data) | ||
return new types.Save(key, data[key]) | ||
return new types.Save(key, data[key], undefined, options.includes(OPTIONAL)) | ||
} | ||
@@ -223,7 +231,10 @@ }) | ||
kind: 'sequence', | ||
multi: true, | ||
resolve: (data) => data && data.length > 1, // need a key and a matcher | ||
construct: (data) => { | ||
construct: (data, type) => { | ||
const [tag, ...options] = type.split('.') | ||
const value = data.pop() | ||
const key = data.length == 1 ? data[0] : data | ||
return new types.Save(key, value) | ||
return new types.Save(key, value, undefined, options.includes(OPTIONAL)) | ||
} | ||
@@ -233,2 +244,29 @@ }) | ||
/** | ||
* Stores static data if the request meets certain creteria | ||
* Saves the data under the given key only if the matcher returns true | ||
* | ||
* format: !set { key: matcher } | ||
* | ||
* @example | ||
* ```yaml | ||
* name: !set { has_name: yes, when: !any string } | ||
* ``` | ||
*/ | ||
const Set__object = new yaml.Type('!set', { | ||
kind: 'mapping', | ||
multi: true, | ||
resolve: (data) => { | ||
const keys = Object.keys(data) | ||
return data && keys.length === 2 && keys.includes(WHEN) | ||
}, | ||
construct: (data, type) => { | ||
const [tag, ...options] = type.split('.') | ||
const keys = Object.keys(data) | ||
const key = keys.filter((val) => val !== WHEN)[0] | ||
return new types.Save(key, data[WHEN], data[key], options.includes(OPTIONAL)) | ||
} | ||
}) | ||
/** | ||
* Retrieves the value of data that has been persisted using !save | ||
@@ -246,5 +284,8 @@ * If nothing has been saved under that key it returns null | ||
kind: 'scalar', | ||
multi: true, | ||
resolve: (key) => key && typeof key === 'string', | ||
construct: (key) => { | ||
return new types.Get(key) | ||
construct: (key, type) => { | ||
const [tag, ...options] = type.split('.') | ||
return new types.Get(key, undefined, options.includes(ONCE)) | ||
} | ||
@@ -266,6 +307,9 @@ }) | ||
kind: 'mapping', | ||
multi: true, | ||
resolve: (data) => data && Object.keys(data).length === 1, // can only have one key | ||
construct: (data) => { | ||
construct: (data, type) => { | ||
const [tag, ...options] = type.split('.') | ||
const [key] = Object.keys(data) | ||
return new types.Get(key, data[key]) | ||
return new types.Get(key, data[key], options.includes(ONCE)) | ||
} | ||
@@ -278,12 +322,10 @@ }) | ||
*/ | ||
const jsRegExp = yaml.DEFAULT_FULL_SCHEMA.compiledTypeMap.scalar['tag:yaml.org,2002:js/regexp'] | ||
const mockRegExpOptions = { | ||
...jsRegExp, | ||
...jsTypes.regexp.options, | ||
instanceOf: types.CustomRegExp, | ||
construct: (data) => { | ||
const regexp = jsRegExp.construct(data) | ||
const regexp = jsTypes.regexp.construct(data) | ||
return new types.CustomRegExp(regexp) | ||
} | ||
} | ||
delete mockRegExpOptions.tag | ||
delete mockRegExpOptions.predicate | ||
@@ -293,3 +335,4 @@ const RegExp__string = new yaml.Type('!regexp', mockRegExpOptions) | ||
// ----------- // | ||
CUSTOM_TAGS = yaml.Schema.create([ | ||
CUSTOM_TAGS = yaml.DEFAULT_SCHEMA.extend([ | ||
...jsTypes.all, | ||
Any__string, | ||
@@ -307,4 +350,5 @@ Chance__string, | ||
Save__string, | ||
Save__object | ||
Save__object, | ||
Set__object | ||
]) | ||
module.exports = CUSTOM_TAGS |
@@ -98,11 +98,13 @@ const cache = require('./cache') | ||
class Save extends CustomType { | ||
constructor(keys, value) { | ||
value = value || new Any() | ||
constructor(keys, tester, staticVal, optional = false) { | ||
tester = tester || new Any() | ||
super(value) | ||
super(tester) | ||
this.keys = keys | ||
this.staticVal = staticVal | ||
this.optional = optional | ||
} | ||
test(value) { | ||
const result = tester(value, this.data) | ||
test(requestInput) { | ||
const result = tester(requestInput, this.data) | ||
@@ -112,4 +114,7 @@ if (result) { | ||
// the server code is responsible for storing it to a permenent location | ||
const isCustomType = this.data instanceof CustomType | ||
const dataToStore = isCustomType ? this.data : result | ||
let dataToStore = this.staticVal | ||
if (!dataToStore) { | ||
const isCustomType = this.data instanceof CustomType | ||
dataToStore = isCustomType ? this.data : result | ||
} | ||
@@ -125,3 +130,3 @@ if (Array.isArray(this.keys)) { | ||
return result | ||
return this.optional || result | ||
} | ||
@@ -163,6 +168,7 @@ } | ||
class Get extends CustomType { | ||
constructor(key, defaultVal) { | ||
constructor(key, defaultVal, once = false) { | ||
super() | ||
this.key = key | ||
this.default = defaultVal | ||
this.once = once | ||
} | ||
@@ -173,4 +179,10 @@ | ||
// temp storage (current session) first, then the persisted storage | ||
let item = cache._storage[this.key] || cache.storage[this.key] | ||
let value = this._getValue(item, json) || this._getValue(this.default, json) | ||
this.item = this.item || cache._storage[this.key] || cache.storage[this.key] | ||
let value = this._getValue(this.item || this.default, json) | ||
if (this.once) { | ||
delete cache._storage[this.key] | ||
delete cache.storage[this.key] | ||
} | ||
return value || null | ||
@@ -198,2 +210,3 @@ } | ||
valueOf() { | ||
// TODO: valueOf of should not remove from cache | ||
return this._retrieveFromCache() | ||
@@ -233,12 +246,14 @@ } | ||
* | ||
* @param {*} val the value we got from the request | ||
* @param {*} tester the tester (regexp or function) | ||
* @param {*} inputVal the value we got from the request | ||
* @param {*} referenceVal the tester (regexp or function) | ||
*/ | ||
function tester(value, tester) { | ||
if (tester instanceof CustomType) { | ||
return tester.test(value) | ||
} else if (tester instanceof RegExp) { | ||
return tester.test(value) | ||
} else if (typeof tester === 'function') { | ||
return tester(value) | ||
function tester(inputVal, referenceVal) { | ||
if (referenceVal instanceof CustomType) { | ||
return referenceVal.test(inputVal) | ||
} else if (referenceVal instanceof RegExp) { | ||
return referenceVal.test(inputVal) | ||
} else if (typeof referenceVal === 'function') { | ||
return referenceVal(inputVal) | ||
} else if (typeof referenceVal === 'string') { | ||
return inputVal === referenceVal | ||
} | ||
@@ -245,0 +260,0 @@ } |
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
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
40517
1059
14
2
+ Addedjs-yaml-js-types@^1.0.0
+ Addedargparse@2.0.1(transitive)
+ Addedbrace-expansion@2.0.1(transitive)
+ Addedjs-yaml@4.1.0(transitive)
+ Addedjs-yaml-js-types@1.0.1(transitive)
+ Addedkoa-router@12.0.1(transitive)
+ Addedminimatch@5.1.6(transitive)
- Removedargparse@1.0.10(transitive)
- Removedbrace-expansion@1.1.11(transitive)
- Removedconcat-map@0.0.1(transitive)
- Removedjs-yaml@3.14.1(transitive)
- Removedkoa-router@9.4.0(transitive)
- Removedminimatch@3.1.2(transitive)
- Removedsprintf-js@1.0.3(transitive)
Updatedargparse@^2.0.1
Updatedchance@^1.1.8
Updatedchokidar@^3.5.3
Updatedjs-yaml@^4.1.0
Updatedkoa-router@^12.0.0
Updatedminimatch@^5.1.0