jxp 2.14.6 → 2.15.1

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.
@@ -1,6 +1,6 @@
1
1
  var _ = require("underscore");
2
2
 
3
- var input1 = {
3
+ var input1 = {
4
4
  due_date: '2016-02-01T00:00:00Z',
5
5
  from_document: '',
6
6
  allow_online_payment: 'false',
@@ -41,45 +41,51 @@ var input1 = {
41
41
  id: '93490358',
42
42
  }
43
43
 
44
- var test1 = { due_date: '2016-02-01T00:00:00Z',
45
- from_document: '',
46
- allow_online_payment: 'false',
47
- paid: 'true',
48
- locked: 'false',
49
- customer_id: '2446859',
50
- modified: '2016-02-02T15:09:06.983',
51
- created: '2016-02-01T21:09:37.873',
52
- date: '2016-02-01T00:00:00Z',
53
- inclusive: 'false',
54
- discount_percentage: '0',
55
- tax_reference: '',
56
- discount: '0',
57
- amount_due: '0',
58
- printed: 'false',
59
- editable: 'true',
60
- has_attachments: 'false',
61
- has_notes: 'false',
62
- has_anticipated_date: 'false',
63
- lines:
64
- [ { SelectionId: '6824935',
65
- TaxTypeId: '965302',
66
- ID: '74465675',
67
- LineType: '0',
68
- Quantity: '1',
69
- Unit: '',
70
- TaxPercentage: '0.14',
71
- DiscountPercentage: '0',
72
- Discount: '0' },
73
- { ID: '74465676',
74
- LineType: '0',
75
- Quantity: '4',
76
- Unit: '',
77
- TaxPercentage: '0.14',
78
- DiscountPercentage: '0',
79
- Discount: '0',
80
- Comments: '' } ],
81
- location: '547d506b184d110c0601314c',
82
- id: '93490358' }
44
+ var test1 = {
45
+ due_date: '2016-02-01T00:00:00Z',
46
+ from_document: '',
47
+ allow_online_payment: 'false',
48
+ paid: 'true',
49
+ locked: 'false',
50
+ customer_id: '2446859',
51
+ modified: '2016-02-02T15:09:06.983',
52
+ created: '2016-02-01T21:09:37.873',
53
+ date: '2016-02-01T00:00:00Z',
54
+ inclusive: 'false',
55
+ discount_percentage: '0',
56
+ tax_reference: '',
57
+ discount: '0',
58
+ amount_due: '0',
59
+ printed: 'false',
60
+ editable: 'true',
61
+ has_attachments: 'false',
62
+ has_notes: 'false',
63
+ has_anticipated_date: 'false',
64
+ lines:
65
+ [{
66
+ SelectionId: '6824935',
67
+ TaxTypeId: '965302',
68
+ ID: '74465675',
69
+ LineType: '0',
70
+ Quantity: '1',
71
+ Unit: '',
72
+ TaxPercentage: '0.14',
73
+ DiscountPercentage: '0',
74
+ Discount: '0'
75
+ },
76
+ {
77
+ ID: '74465676',
78
+ LineType: '0',
79
+ Quantity: '4',
80
+ Unit: '',
81
+ TaxPercentage: '0.14',
82
+ DiscountPercentage: '0',
83
+ Discount: '0',
84
+ Comments: ''
85
+ }],
86
+ location: '547d506b184d110c0601314c',
87
+ id: '93490358'
88
+ }
83
89
 
84
90
  input2 = {
85
91
  'test[0][Yo]': "0Yo",
@@ -161,39 +167,45 @@ var allMatch = /^[a-zA-Z\d_\-]+|\[[a-zA-Z\d_\-][a-zA-Z_\-\d]*\]|\[\d+\]/g;
161
167
 
162
168
  // Based conceptually on the _.extend() function in underscore.js ( see http://documentcloud.github.com/underscore/#extend for more details )
163
169
 
164
- function deepExtend(obj) {
165
- var parentRE = /#{\s*?_\s*?}/,
166
- slice = Array.prototype.slice;
170
+ function deepExtend(obj, depth = 0) {
171
+ const MAX_DEPTH = 20; // Prevent infinite recursion
172
+ if (depth > MAX_DEPTH) {
173
+ console.warn('Maximum depth exceeded in deepExtend');
174
+ return obj;
175
+ }
176
+
177
+ var parentRE = /#{\s*?_\s*?}/,
178
+ slice = Array.prototype.slice;
167
179
 
168
- _.each(slice.call(arguments, 1), function(source) {
169
- for (var prop in source) {
170
- if (_.isUndefined(obj[prop]) || _.isFunction(obj[prop]) || _.isNull(source[prop]) || _.isDate(source[prop])) {
171
- obj[prop] = source[prop];
172
- }
173
- else if (_.isString(source[prop]) && parentRE.test(source[prop])) {
174
- if (_.isString(obj[prop])) {
175
- obj[prop] = source[prop].replace(parentRE, obj[prop]);
176
- }
177
- }
178
- else if (_.isArray(obj[prop]) || _.isArray(source[prop])){
179
- if (!_.isArray(obj[prop]) || !_.isArray(source[prop])){
180
- throw new Error('Trying to combine an array with a non-array (' + prop + ')');
181
- } else {
182
- obj[prop] = _.reject(_.deepExtend(_.clone(obj[prop]), source[prop]), function (item) { return _.isNull(item);});
183
- }
184
- }
185
- else if (_.isObject(obj[prop]) || _.isObject(source[prop])){
186
- if (!_.isObject(obj[prop]) || !_.isObject(source[prop])){
187
- throw new Error('Trying to combine an object with a non-object (' + prop + ')');
188
- } else {
189
- obj[prop] = _.deepExtend(_.clone(obj[prop]), source[prop]);
190
- }
191
- } else {
192
- obj[prop] = source[prop];
193
- }
194
- }
195
- });
196
- return obj;
180
+ _.each(slice.call(arguments, 1), function (source) {
181
+ for (var prop in source) {
182
+ if (_.isUndefined(obj[prop]) || _.isFunction(obj[prop]) || _.isNull(source[prop]) || _.isDate(source[prop])) {
183
+ obj[prop] = source[prop];
184
+ }
185
+ else if (_.isString(source[prop]) && parentRE.test(source[prop])) {
186
+ if (_.isString(obj[prop])) {
187
+ obj[prop] = source[prop].replace(parentRE, obj[prop]);
188
+ }
189
+ }
190
+ else if (_.isArray(obj[prop]) || _.isArray(source[prop])) {
191
+ if (!_.isArray(obj[prop]) || !_.isArray(source[prop])) {
192
+ throw new Error('Trying to combine an array with a non-array (' + prop + ')');
193
+ } else {
194
+ obj[prop] = _.reject(_.deepExtend(_.clone(obj[prop]), source[prop], depth + 1), function (item) { return _.isNull(item); });
195
+ }
196
+ }
197
+ else if (_.isObject(obj[prop]) || _.isObject(source[prop])) {
198
+ if (!_.isObject(obj[prop]) || !_.isObject(source[prop])) {
199
+ throw new Error('Trying to combine an object with a non-object (' + prop + ')');
200
+ } else {
201
+ obj[prop] = _.deepExtend(_.clone(obj[prop]), source[prop], depth + 1);
202
+ }
203
+ } else {
204
+ obj[prop] = source[prop];
205
+ }
206
+ }
207
+ });
208
+ return obj;
197
209
  };
198
210
 
199
211
  _.mixin({ 'deepExtend': deepExtend });
@@ -259,7 +271,13 @@ function isArray(a) {
259
271
  return Array.isArray(a);
260
272
  }
261
273
 
262
- var assignPropVal = function(parts, result, val) {
274
+ var assignPropVal = function (parts, result, val, depth = 0) {
275
+ const MAX_DEPTH = 20; // Prevent infinite recursion
276
+ if (depth > MAX_DEPTH) {
277
+ console.warn('Maximum depth exceeded in assignPropVal');
278
+ return result;
279
+ }
280
+
263
281
  var part = parts.shift().replace(/\[|\]/g, "");
264
282
  if (parts.length) {
265
283
  if (isNumeric(parts[0].replace(/\[|\]/g, ""))) {
@@ -267,14 +285,14 @@ var assignPropVal = function(parts, result, val) {
267
285
  } else {
268
286
  result[part] = {};
269
287
  }
270
- assignPropVal(parts, result[part], val);
288
+ assignPropVal(parts, result[part], val, depth + 1);
271
289
  } else {
272
290
  result[part] = val;
273
291
  }
274
292
  return result;
275
293
  }
276
294
 
277
- var deserialize = function(input) {
295
+ var deserialize = function (input) {
278
296
  // console.log("INPUT", input);
279
297
  var result = {};
280
298
  var newobj = {};
@@ -283,20 +301,19 @@ var deserialize = function(input) {
283
301
  // console.log(prop, parts);
284
302
  var val = input[prop];
285
303
  if (parts) {
286
- var tmp = assignPropVal(parts, result, val);
287
- newobj = _.deepExtend(newobj, tmp);
304
+ var tmp = assignPropVal(parts, result, val, 0);
305
+ newobj = _.deepExtend(newobj, tmp, 0);
288
306
  } else {
289
307
  // console.log("NOT ARRAY", parts);
290
308
  newobj[prop] = input[prop];
291
309
  }
292
-
293
310
  }
294
311
  // input = newobj;
295
312
  // console.log("Munge!", newobj);
296
313
  return newobj;
297
314
  }
298
315
 
299
- var runTest = function(name, input, test) {
316
+ var runTest = function (name, input, test) {
300
317
  var result = deserialize(input);
301
318
  if (_.isEqual(result, test)) {
302
319
  console.log("PASSED " + name);
@@ -306,7 +323,7 @@ var runTest = function(name, input, test) {
306
323
  }
307
324
  }
308
325
 
309
- var test = function() {
326
+ var test = function () {
310
327
  runTest("Test 1", input1, test1);
311
328
  runTest("Test 2", input2, test2);
312
329
  runTest("Test 3", input3, test3);
package/libs/docs.js CHANGED
@@ -8,6 +8,50 @@ const readFile = util.promisify(fs.readFile);
8
8
  const schema_description = require("./schema_description");
9
9
  const errors = require("restify-errors");
10
10
 
11
+ // Helper function to safely serialize schema fields
12
+ const serializeField = (field) => {
13
+ const safeField = {
14
+ path: field.path,
15
+ instance: field.instance,
16
+ options: { ...field.options },
17
+ validators: field.validators?.map(v => ({
18
+ type: v.type?.name,
19
+ message: v.message
20
+ })),
21
+ isRequired: field.isRequired
22
+ };
23
+
24
+ // Handle default value
25
+ if (typeof field.defaultValue === 'function') {
26
+ safeField.defaultValue = '[Function]';
27
+ } else if (field.defaultValue === undefined && field.options.default !== undefined) {
28
+ if (typeof field.options.default === 'function') {
29
+ safeField.defaultValue = '[Function]';
30
+ } else {
31
+ safeField.defaultValue = field.options.default;
32
+ }
33
+ } else {
34
+ safeField.defaultValue = field.defaultValue;
35
+ }
36
+
37
+ // Handle special cases for different field types
38
+ if (field.instance === 'Array' && field.caster) {
39
+ safeField.arrayType = field.caster.instance;
40
+ // Handle array defaults specially
41
+ if (Array.isArray(safeField.defaultValue)) {
42
+ safeField.defaultValue = JSON.stringify(safeField.defaultValue);
43
+ }
44
+ }
45
+ if (field.instance === 'Embedded' || field.instance === 'DocumentArray') {
46
+ safeField.schema = Object.keys(field.schema.paths).map(p => ({
47
+ path: p,
48
+ type: field.schema.paths[p].instance
49
+ }));
50
+ }
51
+
52
+ return safeField;
53
+ };
54
+
11
55
  class Docs {
12
56
  constructor(opts) {
13
57
  this.config = Object.assign({}, opts.config);
@@ -16,7 +60,7 @@ class Docs {
16
60
  this.package = require(path.join(process.cwd(), "package.json"));
17
61
  }
18
62
 
19
- renderTemplate(res, template_file, data={}) {
63
+ renderTemplate(res, template_file, data = {}) {
20
64
  try {
21
65
  const template = pug.compileFile(path.join(__dirname, `../templates/${template_file}.pug`));
22
66
  data.title = data.title || `${this.package.name} API Documentation`;
@@ -28,10 +72,10 @@ class Docs {
28
72
  res.writeHead(200, {
29
73
  'Content-Length': Buffer.byteLength(body),
30
74
  'Content-Type': 'text/html'
31
- });
75
+ });
32
76
  res.write(body);
33
77
  res.end();
34
- } catch(err) {
78
+ } catch (err) {
35
79
  console.error(err);
36
80
  return new errors.InternalServerError(err.toString());
37
81
  }
@@ -64,7 +108,7 @@ class Docs {
64
108
  try {
65
109
  res.send(this.models);
66
110
  next();
67
- } catch(err) {
111
+ } catch (err) {
68
112
  return new errors.InternalServerError(err.toString());
69
113
  }
70
114
  }
@@ -73,7 +117,7 @@ class Docs {
73
117
  try {
74
118
  this.renderTemplate(res, "index", {});
75
119
  next();
76
- } catch(err) {
120
+ } catch (err) {
77
121
  return new errors.InternalServerError(err.toString());
78
122
  }
79
123
  }
@@ -83,7 +127,7 @@ class Docs {
83
127
  const body = await readFile(path.join(__dirname, `../docs`, req.params.md_doc));
84
128
  const md_contents = md.render(body.toString()).body;
85
129
  this.renderTemplate(res, "md", { md_contents });
86
- } catch(err) {
130
+ } catch (err) {
87
131
  return new errors.InternalServerError(err.toString());
88
132
  }
89
133
  }
@@ -91,13 +135,25 @@ class Docs {
91
135
  model(req, res, next) {
92
136
  try {
93
137
  const model = this.models[req.params.modelname];
94
- console.dir(model.schema.opts);
95
- const fields = Object.keys(model.schema.paths);
138
+ const fields = Object.keys(model.schema.paths);
96
139
  fields.sort();
97
140
  const perms = model.schema.opts.perms;
98
- this.renderTemplate(res, "model", { model, fields, perms });
141
+
142
+ // Prepare safe field data for template
143
+ const safeFields = {};
144
+ fields.forEach(fieldName => {
145
+ safeFields[fieldName] = serializeField(model.schema.paths[fieldName]);
146
+ });
147
+
148
+ this.renderTemplate(res, "model", {
149
+ model,
150
+ fields,
151
+ perms,
152
+ safeFields
153
+ });
99
154
  next();
100
- } catch(err) {
155
+ } catch (err) {
156
+ console.error(err);
101
157
  return new errors.InternalServerError(err.toString());
102
158
  }
103
159
  }