@aimeloic/monkey-tester 2.0.6 → 2.0.8

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.
package/htmlTemplate.js CHANGED
@@ -296,14 +296,20 @@ function getHtmlTemplate(endpoints) {
296
296
  let body = undefined;
297
297
  if (['POST', 'PUT', 'PATCH'].includes(ep.method) && ep.fields && ep.fields.length) {
298
298
  const payload = {};
299
+ let hasData = false;
300
+
299
301
  ep.fields.forEach(function(f) {
300
302
  const el = document.getElementById('field-' + f.name);
301
303
  if (!el) return;
302
304
  let v = el.value.trim();
303
- if (f.type === 'number' && v !== '') v = Number(v);
305
+ if (v === '') return; // Avoid submitting empty strings for unfilled fields
306
+
307
+ if (f.type === 'number') v = Number(v);
304
308
  payload[f.name] = v;
309
+ hasData = true;
305
310
  });
306
- body = JSON.stringify(payload);
311
+
312
+ if (hasData) body = JSON.stringify(payload);
307
313
  }
308
314
 
309
315
  setResponse(null, 'loading');
package/index.js CHANGED
@@ -2,4 +2,5 @@
2
2
 
3
3
  const { endtesterExpress } = require('./monkey.js');
4
4
 
5
- module.exports = { endtesterExpress };
5
+ module.exports = { endtesterExpress };
6
+ module.exports.endtesterExpress = endtesterExpress;
package/monkey.js CHANGED
@@ -41,7 +41,6 @@ function extractBodyFields(handler) {
41
41
  let m;
42
42
  while ((m = destructRe.exec(source)) !== null) {
43
43
  m[1].split(',').forEach(part => {
44
- // handle rename (email: userEmail) and default (name = '')
45
44
  const name = part.split(':')[0].split('=')[0].trim();
46
45
  if (name && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) && !seen.has(name)) {
47
46
  seen.set(name, buildField(name));
@@ -84,25 +83,22 @@ function fallbackFields(path) {
84
83
  return [];
85
84
  }
86
85
 
87
- // ─── Extract router prefix from Express layer regexp ─────────────────────────
86
+ // ─── Extract router prefix safely from Express layer ─────────────────────────
88
87
  function extractRouterPrefix(layer) {
89
88
  if (!layer.regexp) return '';
90
- const src = layer.regexp.source;
91
-
92
- // Express serialises router paths as: ^\/<prefix>(?:\/(?=$))?(?=\/|$)
93
- const patterns = [
94
- /^\^\\\/([^\\?$]+)/, // common format
95
- /^\^\\\/([a-zA-Z0-9_/-]+)/, // simple paths
96
- ];
97
- for (const re of patterns) {
98
- const m = re.exec(src);
99
- if (m && m[1]) {
100
- return '/' + m[1].replace(/\\\//g, '/').replace(/\\/g, '');
101
- }
102
- }
103
- // Fallback: check .regexp property stored by Express (Express 5 style)
104
- if (layer.regexp && layer.regexp.fast_slash) return '';
105
- return '';
89
+ if (layer.path) return layer.path; // If explicit paths exist
90
+
91
+ let src = layer.regexp.source;
92
+
93
+ // Strip out boilerplate generated patterns from default express mounting structures
94
+ src = src
95
+ .replace('^\\/', '/')
96
+ .replace('\\/?(?=\\/|$)', '')
97
+ .replace('(?:\\/(?=$))?(?=\\/|$)', '')
98
+ .replace('\\/', '/');
99
+
100
+ const cleanPath = src.split('(?')[0].replace(/\\/g, '');
101
+ return cleanPath === '/' ? '' : cleanPath;
106
102
  }
107
103
 
108
104
  // ─── Walk the Express router stack recursively ────────────────────────────────
@@ -118,7 +114,6 @@ function parseStack(stack, detectedEndpoints, prefix = '') {
118
114
 
119
115
  const fullPath = (prefix + rawPath).replace(/\/+/g, '/') || '/';
120
116
 
121
- // skip the tester's own route
122
117
  if (fullPath.startsWith('/api/tester')) continue;
123
118
 
124
119
  const methods = Object.keys(layer.route.methods || {});
@@ -127,11 +122,12 @@ function parseStack(stack, detectedEndpoints, prefix = '') {
127
122
  const httpMethod = method.toUpperCase();
128
123
  const key = `${httpMethod}::${fullPath}`;
129
124
 
130
- // ── Path params (:id, :slug …) ─────────────────────────────────────
125
+ // ── Path params (:id, :slug …) safely parsed using matchAll ─────────
131
126
  const pathParams = [];
132
127
  const paramRe = /:([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
133
- let pm;
134
- while ((pm = paramRe.exec(fullPath)) !== null) {
128
+ const matches = [...fullPath.matchAll(paramRe)];
129
+
130
+ for (const pm of matches) {
135
131
  pathParams.push({
136
132
  name: pm[1],
137
133
  label: pm[1].charAt(0).toUpperCase() + pm[1].slice(1),
@@ -146,14 +142,12 @@ function parseStack(stack, detectedEndpoints, prefix = '') {
146
142
  for (const handler of handlers) {
147
143
  bodyFields.push(...extractBodyFields(handler));
148
144
  }
149
- // deduplicate by name
150
145
  const seen = new Map();
151
146
  bodyFields = bodyFields.filter(f => {
152
147
  if (seen.has(f.name)) return false;
153
148
  seen.set(f.name, true);
154
149
  return true;
155
150
  });
156
- // fallback if extraction produced nothing
157
151
  if (bodyFields.length === 0) {
158
152
  bodyFields = fallbackFields(fullPath);
159
153
  }
@@ -190,7 +184,7 @@ function endtesterExpress() {
190
184
 
191
185
  const rootStack =
192
186
  (app._router && app._router.stack) || // Express 4
193
- (app.router && app.router.stack) || // Express 5 preview
187
+ (app.router && app.router.stack) || // Express 5
194
188
  [];
195
189
 
196
190
  parseStack(rootStack, detectedEndpoints);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aimeloic/monkey-tester",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "Auto route scanning visual runner dashboard.",
5
5
  "main": "index.js",
6
6
  "type": "module",