@schmock/cli 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/bin.js +42 -32
  2. package/dist/index.js +42 -32
  3. package/package.json +3 -3
package/dist/bin.js CHANGED
@@ -23985,14 +23985,14 @@ function parseRouteKey(routeKey) {
23985
23985
  }
23986
23986
  const [, method, path] = match;
23987
23987
  const params = [];
23988
- const paramPattern = /:([^/]+)/g;
23989
- let paramMatch;
23990
- paramMatch = paramPattern.exec(path);
23991
- while (paramMatch !== null) {
23992
- params.push(paramMatch[1]);
23993
- paramMatch = paramPattern.exec(path);
23994
- }
23995
- const regexPath = path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/:([^/]+)/g, "([^/]+)");
23988
+ const regexPath = path.split(/(:[a-zA-Z0-9_-]+)/g).map((segment) => {
23989
+ const paramMatch = segment.match(/^:([a-zA-Z0-9_-]+)$/);
23990
+ if (paramMatch) {
23991
+ params.push(paramMatch[1]);
23992
+ return "([^/]+)";
23993
+ }
23994
+ return segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
23995
+ }).join("");
23996
23996
  const pattern = new RegExp(`^${regexPath}$`);
23997
23997
  return {
23998
23998
  method: toHttpMethod(method),
@@ -24198,6 +24198,7 @@ class CallableMockInstance {
24198
24198
  const existing = this.routes.find((r) => r.method === parsed.method && r.path === parsed.path);
24199
24199
  if (existing) {
24200
24200
  this.logger.log("warning", `Duplicate route: ${route} — first registration wins`);
24201
+ return this;
24201
24202
  }
24202
24203
  const compiledRoute = {
24203
24204
  pattern: parsed.pattern,
@@ -24210,9 +24211,7 @@ class CallableMockInstance {
24210
24211
  this.routes.push(compiledRoute);
24211
24212
  if (parsed.params.length === 0) {
24212
24213
  const key = `${parsed.method} ${normalizePath(parsed.path)}`;
24213
- if (!this.staticRoutes.has(key)) {
24214
- this.staticRoutes.set(key, compiledRoute);
24215
- }
24214
+ this.staticRoutes.set(key, compiledRoute);
24216
24215
  }
24217
24216
  this.logger.log("route", `Route defined: ${route}`, {
24218
24217
  contentType: config.contentType,
@@ -24494,6 +24493,10 @@ class CallableMockInstance {
24494
24493
  timestamp: Date.now(),
24495
24494
  response: { status: response.status, body: response.body }
24496
24495
  });
24496
+ const maxHistorySize = this.globalConfig.maxHistorySize;
24497
+ if (typeof maxHistorySize === "number" && maxHistorySize >= 0 && this.requestHistory.length > maxHistorySize) {
24498
+ this.requestHistory.splice(0, this.requestHistory.length - maxHistorySize);
24499
+ }
24497
24500
  this.emit("request:end", {
24498
24501
  method,
24499
24502
  path: requestPath,
@@ -24576,7 +24579,7 @@ function schmock(config) {
24576
24579
  return callableInstance;
24577
24580
  }
24578
24581
  // ../openapi/package.json
24579
- var version = "2.0.2";
24582
+ var version = "2.0.3";
24580
24583
 
24581
24584
  // ../openapi/src/utils.ts
24582
24585
  function isRecord(value) {
@@ -30005,19 +30008,21 @@ function validateSchema(schema, path = "$") {
30005
30008
  validateSchema(schema.items, `${path}.items`);
30006
30009
  }
30007
30010
  }
30008
- if (hasCircularReference(schema)) {
30009
- throw new SchemaValidationError(path, "Schema contains circular references which are not supported");
30010
- }
30011
- const depth = calculateNestingDepth(schema);
30012
- if (depth > MAX_NESTING_DEPTH) {
30013
- throw new ResourceLimitError("schema_nesting_depth", MAX_NESTING_DEPTH, depth);
30014
- }
30015
- if (depth >= DEEP_NESTING_THRESHOLD) {
30016
- checkForDeepNestingWithArrays(schema, path);
30017
- }
30018
- checkArraySizeLimits(schema, path);
30019
- if (schema.$ref === "#") {
30020
- throw new SchemaValidationError(path, "Self-referencing schemas are not supported");
30011
+ if (path === "$") {
30012
+ if (hasCircularReference(schema)) {
30013
+ throw new SchemaValidationError(path, "Schema contains circular references which are not supported");
30014
+ }
30015
+ if (schema.$ref === "#") {
30016
+ throw new SchemaValidationError(path, "Self-referencing schemas are not supported");
30017
+ }
30018
+ const depth = calculateNestingDepth(schema);
30019
+ if (depth > MAX_NESTING_DEPTH) {
30020
+ throw new ResourceLimitError("schema_nesting_depth", MAX_NESTING_DEPTH, depth);
30021
+ }
30022
+ if (depth >= DEEP_NESTING_THRESHOLD) {
30023
+ checkForDeepNestingWithArrays(schema, path);
30024
+ }
30025
+ checkArraySizeLimits(schema, path);
30021
30026
  }
30022
30027
  }
30023
30028
  function hasCircularReference(schema, currentPath = new Set) {
@@ -31636,17 +31641,21 @@ function processContentNegotiation(context) {
31636
31641
  }
31637
31642
  return;
31638
31643
  }
31639
- var ajv = new import_ajv.default({ allErrors: true });
31640
- var schemaCache = new WeakMap;
31641
- function validateRequestBody(context) {
31644
+ function createBodyValidatorContext() {
31645
+ return {
31646
+ ajv: new import_ajv.default({ allErrors: true }),
31647
+ cache: new WeakMap
31648
+ };
31649
+ }
31650
+ function validateRequestBody(context, validatorCtx) {
31642
31651
  const requestBodySchema = getRouteRequestBody(context.route);
31643
31652
  if (!requestBodySchema || context.body === undefined) {
31644
31653
  return;
31645
31654
  }
31646
- let validate = schemaCache.get(requestBodySchema);
31655
+ let validate = validatorCtx.cache.get(requestBodySchema);
31647
31656
  if (!validate) {
31648
- validate = ajv.compile(requestBodySchema);
31649
- schemaCache.set(requestBodySchema, validate);
31657
+ validate = validatorCtx.ajv.compile(requestBodySchema);
31658
+ validatorCtx.cache.set(requestBodySchema, validate);
31650
31659
  }
31651
31660
  if (!validate(context.body)) {
31652
31661
  const errors = validate.errors?.map((e3) => ({
@@ -31766,6 +31775,7 @@ async function openapi(options) {
31766
31775
  }
31767
31776
  const securitySchemes = spec.securitySchemes;
31768
31777
  const globalSecurity = spec.globalSecurity;
31778
+ const bodyValidatorCtx = createBodyValidatorContext();
31769
31779
  return {
31770
31780
  name: "@schmock/openapi",
31771
31781
  version,
@@ -31827,7 +31837,7 @@ async function openapi(options) {
31827
31837
  if (contentResult)
31828
31838
  return contentResult;
31829
31839
  if (options.validateRequests) {
31830
- const validationResult = validateRequestBody(context);
31840
+ const validationResult = validateRequestBody(context, bodyValidatorCtx);
31831
31841
  if (validationResult) {
31832
31842
  return validationResult;
31833
31843
  }
package/dist/index.js CHANGED
@@ -23984,14 +23984,14 @@ function parseRouteKey(routeKey) {
23984
23984
  }
23985
23985
  const [, method, path] = match;
23986
23986
  const params = [];
23987
- const paramPattern = /:([^/]+)/g;
23988
- let paramMatch;
23989
- paramMatch = paramPattern.exec(path);
23990
- while (paramMatch !== null) {
23991
- params.push(paramMatch[1]);
23992
- paramMatch = paramPattern.exec(path);
23993
- }
23994
- const regexPath = path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/:([^/]+)/g, "([^/]+)");
23987
+ const regexPath = path.split(/(:[a-zA-Z0-9_-]+)/g).map((segment) => {
23988
+ const paramMatch = segment.match(/^:([a-zA-Z0-9_-]+)$/);
23989
+ if (paramMatch) {
23990
+ params.push(paramMatch[1]);
23991
+ return "([^/]+)";
23992
+ }
23993
+ return segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
23994
+ }).join("");
23995
23995
  const pattern = new RegExp(`^${regexPath}$`);
23996
23996
  return {
23997
23997
  method: toHttpMethod(method),
@@ -24197,6 +24197,7 @@ class CallableMockInstance {
24197
24197
  const existing = this.routes.find((r) => r.method === parsed.method && r.path === parsed.path);
24198
24198
  if (existing) {
24199
24199
  this.logger.log("warning", `Duplicate route: ${route} — first registration wins`);
24200
+ return this;
24200
24201
  }
24201
24202
  const compiledRoute = {
24202
24203
  pattern: parsed.pattern,
@@ -24209,9 +24210,7 @@ class CallableMockInstance {
24209
24210
  this.routes.push(compiledRoute);
24210
24211
  if (parsed.params.length === 0) {
24211
24212
  const key = `${parsed.method} ${normalizePath(parsed.path)}`;
24212
- if (!this.staticRoutes.has(key)) {
24213
- this.staticRoutes.set(key, compiledRoute);
24214
- }
24213
+ this.staticRoutes.set(key, compiledRoute);
24215
24214
  }
24216
24215
  this.logger.log("route", `Route defined: ${route}`, {
24217
24216
  contentType: config.contentType,
@@ -24493,6 +24492,10 @@ class CallableMockInstance {
24493
24492
  timestamp: Date.now(),
24494
24493
  response: { status: response.status, body: response.body }
24495
24494
  });
24495
+ const maxHistorySize = this.globalConfig.maxHistorySize;
24496
+ if (typeof maxHistorySize === "number" && maxHistorySize >= 0 && this.requestHistory.length > maxHistorySize) {
24497
+ this.requestHistory.splice(0, this.requestHistory.length - maxHistorySize);
24498
+ }
24496
24499
  this.emit("request:end", {
24497
24500
  method,
24498
24501
  path: requestPath,
@@ -24575,7 +24578,7 @@ function schmock(config) {
24575
24578
  return callableInstance;
24576
24579
  }
24577
24580
  // ../openapi/package.json
24578
- var version = "2.0.2";
24581
+ var version = "2.0.3";
24579
24582
 
24580
24583
  // ../openapi/src/utils.ts
24581
24584
  function isRecord(value) {
@@ -30004,19 +30007,21 @@ function validateSchema(schema, path = "$") {
30004
30007
  validateSchema(schema.items, `${path}.items`);
30005
30008
  }
30006
30009
  }
30007
- if (hasCircularReference(schema)) {
30008
- throw new SchemaValidationError(path, "Schema contains circular references which are not supported");
30009
- }
30010
- const depth = calculateNestingDepth(schema);
30011
- if (depth > MAX_NESTING_DEPTH) {
30012
- throw new ResourceLimitError("schema_nesting_depth", MAX_NESTING_DEPTH, depth);
30013
- }
30014
- if (depth >= DEEP_NESTING_THRESHOLD) {
30015
- checkForDeepNestingWithArrays(schema, path);
30016
- }
30017
- checkArraySizeLimits(schema, path);
30018
- if (schema.$ref === "#") {
30019
- throw new SchemaValidationError(path, "Self-referencing schemas are not supported");
30010
+ if (path === "$") {
30011
+ if (hasCircularReference(schema)) {
30012
+ throw new SchemaValidationError(path, "Schema contains circular references which are not supported");
30013
+ }
30014
+ if (schema.$ref === "#") {
30015
+ throw new SchemaValidationError(path, "Self-referencing schemas are not supported");
30016
+ }
30017
+ const depth = calculateNestingDepth(schema);
30018
+ if (depth > MAX_NESTING_DEPTH) {
30019
+ throw new ResourceLimitError("schema_nesting_depth", MAX_NESTING_DEPTH, depth);
30020
+ }
30021
+ if (depth >= DEEP_NESTING_THRESHOLD) {
30022
+ checkForDeepNestingWithArrays(schema, path);
30023
+ }
30024
+ checkArraySizeLimits(schema, path);
30020
30025
  }
30021
30026
  }
30022
30027
  function hasCircularReference(schema, currentPath = new Set) {
@@ -31635,17 +31640,21 @@ function processContentNegotiation(context) {
31635
31640
  }
31636
31641
  return;
31637
31642
  }
31638
- var ajv = new import_ajv.default({ allErrors: true });
31639
- var schemaCache = new WeakMap;
31640
- function validateRequestBody(context) {
31643
+ function createBodyValidatorContext() {
31644
+ return {
31645
+ ajv: new import_ajv.default({ allErrors: true }),
31646
+ cache: new WeakMap
31647
+ };
31648
+ }
31649
+ function validateRequestBody(context, validatorCtx) {
31641
31650
  const requestBodySchema = getRouteRequestBody(context.route);
31642
31651
  if (!requestBodySchema || context.body === undefined) {
31643
31652
  return;
31644
31653
  }
31645
- let validate = schemaCache.get(requestBodySchema);
31654
+ let validate = validatorCtx.cache.get(requestBodySchema);
31646
31655
  if (!validate) {
31647
- validate = ajv.compile(requestBodySchema);
31648
- schemaCache.set(requestBodySchema, validate);
31656
+ validate = validatorCtx.ajv.compile(requestBodySchema);
31657
+ validatorCtx.cache.set(requestBodySchema, validate);
31649
31658
  }
31650
31659
  if (!validate(context.body)) {
31651
31660
  const errors = validate.errors?.map((e3) => ({
@@ -31765,6 +31774,7 @@ async function openapi(options) {
31765
31774
  }
31766
31775
  const securitySchemes = spec.securitySchemes;
31767
31776
  const globalSecurity = spec.globalSecurity;
31777
+ const bodyValidatorCtx = createBodyValidatorContext();
31768
31778
  return {
31769
31779
  name: "@schmock/openapi",
31770
31780
  version,
@@ -31826,7 +31836,7 @@ async function openapi(options) {
31826
31836
  if (contentResult)
31827
31837
  return contentResult;
31828
31838
  if (options.validateRequests) {
31829
- const validationResult = validateRequestBody(context);
31839
+ const validationResult = validateRequestBody(context, bodyValidatorCtx);
31830
31840
  if (validationResult) {
31831
31841
  return validationResult;
31832
31842
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@schmock/cli",
3
3
  "description": "CLI for running Schmock mock servers from OpenAPI specs",
4
- "version": "2.0.2",
4
+ "version": "2.0.3",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -32,8 +32,8 @@
32
32
  },
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
- "@schmock/core": "^2.0.2",
36
- "@schmock/openapi": "^2.0.2"
35
+ "@schmock/core": "^2.0.3",
36
+ "@schmock/openapi": "^2.0.3"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@amiceli/vitest-cucumber": "^6.5.0",