fable 3.1.16 → 3.1.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fable",
3
- "version": "3.1.16",
3
+ "version": "3.1.18",
4
4
  "description": "A service dependency injection, configuration and logging library.",
5
5
  "main": "source/Fable.js",
6
6
  "scripts": {
@@ -35,8 +35,11 @@ class DataFormat extends libFableServiceProviderBase
35
35
 
36
36
  this._UseEngineStringStartsWith = (typeof(String.prototype.startsWith) === 'function');
37
37
  this._UseEngineStringEndsWith = (typeof(String.prototype.endsWith) === 'function');
38
- }
39
38
 
39
+ this._SanitizeObjectKeyRegex = /[^a-zA-Z0-9_]/gi;
40
+ this._SanitizeObjectKeyReplacement = '_';
41
+ this._SanitizeObjectKeyInvalid = 'INVALID';
42
+ }
40
43
 
41
44
  /*************************************************************************
42
45
  * String Manipulation and Comparison Functions
@@ -370,6 +373,21 @@ class DataFormat extends libFableServiceProviderBase
370
373
  return '';
371
374
  }
372
375
 
376
+ /**
377
+ * Clean a string of any characters to create a consistent object key.
378
+ *
379
+ * @param {string} pString The string to clean.
380
+ * @return {string} the cleaned string, or a placeholder if the input is invalid
381
+ */
382
+ sanitizeObjectKey(pString)
383
+ {
384
+ if (typeof pString !== 'string' || pString.length < 1)
385
+ {
386
+ return this._SanitizeObjectKeyInvalid;
387
+ }
388
+ return pString.replace(this._SanitizeObjectKeyRegex, this._SanitizeObjectKeyReplacement);
389
+ }
390
+
373
391
 
374
392
  /*************************************************************************
375
393
  * Number Formatting Functions
@@ -84,11 +84,12 @@ class StringParser
84
84
  * @param {string} pCharacter - The character to append
85
85
  * @param {Object} pParserState - The state object for the current parsing task
86
86
  * @param {any} pData - The data available to the template
87
- * @param {any} pDataContext - The history of data objects/context already passed in
87
+ * @param {Array<any>} pDataContext - The history of data objects/context already passed in
88
88
  * @param {any} [pScope] - A sticky scope that can be used to carry state and simplify template
89
+ * @param {any} [pState] - A catchall state object for plumbing data through template processing.
89
90
  * @private
90
91
  */
91
- parseCharacter (pCharacter, pParserState, pData, pDataContext, pScope)
92
+ parseCharacter (pCharacter, pParserState, pData, pDataContext, pScope, pState)
92
93
  {
93
94
  // If we are already in a pattern match traversal
94
95
  if (pParserState.PatternMatch)
@@ -112,11 +113,11 @@ class StringParser
112
113
  let tmpFunctionContext = ('ParserContext' in pParserState.Pattern) ? pParserState.Pattern.ParserContext : false;
113
114
  if (tmpFunctionContext)
114
115
  {
115
- pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
116
+ pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
116
117
  }
117
118
  else
118
119
  {
119
- pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
120
+ pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
120
121
  }
121
122
  return this.resetOutputBuffer(pParserState);
122
123
  }
@@ -155,11 +156,11 @@ class StringParser
155
156
  let tmpFunctionContext = ('ParserContext' in pParserState.Pattern) ? pParserState.Pattern.ParserContext : false;
156
157
  if (tmpFunctionContext)
157
158
  {
158
- pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
159
+ pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
159
160
  }
160
161
  else
161
162
  {
162
- pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
163
+ pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
163
164
  }
164
165
  return this.resetOutputBuffer(pParserState);
165
166
  }
@@ -192,7 +193,15 @@ class StringParser
192
193
  return false;
193
194
  }
194
195
 
195
- executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope)
196
+ /**
197
+ * @param {Object} pParserState - The state object for the current parsing task
198
+ * @param {Object} pData - The data to pass to the function as a second parameter
199
+ * @param {function} fCallback - The callback function to call when the parse is complete
200
+ * @param {array} pDataContext - The history of data objects/context already passed in
201
+ * @param {any} [pScope] - A sticky scope that can be used to carry state and simplify template
202
+ * @param {any} [pState] - A catchall state object for plumbing data through template processing.
203
+ */
204
+ executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope, pState)
196
205
  {
197
206
  // ... this is the end of a pattern, cut off the end tag and parse it.
198
207
  // Trim the start and end tags off the output buffer now
@@ -213,7 +222,7 @@ class StringParser
213
222
  pParserState.OutputBuffer = pAsyncOutput;
214
223
  this.resetOutputBuffer(pParserState);
215
224
  return fCallback();
216
- }, pDataContext, pScope);
225
+ }, pDataContext, pScope, pState);
217
226
  }
218
227
  else
219
228
  {
@@ -228,7 +237,7 @@ class StringParser
228
237
  pParserState.OutputBuffer = pAsyncOutput;
229
238
  this.resetOutputBuffer(pParserState);
230
239
  return fCallback();
231
- }, pDataContext, pScope);
240
+ }, pDataContext, pScope, pState);
232
241
  }
233
242
  }
234
243
  else
@@ -237,11 +246,11 @@ class StringParser
237
246
  let tmpFunctionContext = ('ParserContext' in pParserState.Pattern) ? pParserState.Pattern.ParserContext : false;
238
247
  if (tmpFunctionContext)
239
248
  {
240
- pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
249
+ pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
241
250
  }
242
251
  else
243
252
  {
244
- pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
253
+ pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
245
254
  }
246
255
  this.resetOutputBuffer(pParserState);
247
256
  return fCallback();
@@ -258,9 +267,10 @@ class StringParser
258
267
  * @param {function} fCallback - The callback function to call when the parse is complete
259
268
  * @param {array} pDataContext - The history of data objects/context already passed in
260
269
  * @param {any} [pScope] - A sticky scope that can be used to carry state and simplify template
270
+ * @param {any} [pState] - A catchall state object for plumbing data through template processing.
261
271
  * @private
262
272
  */
263
- parseCharacterAsync (pCharacter, pParserState, pData, fCallback, pDataContext, pScope)
273
+ parseCharacterAsync (pCharacter, pParserState, pData, fCallback, pDataContext, pScope, pState)
264
274
  {
265
275
  // If we are already in a pattern match traversal
266
276
  if (pParserState.PatternMatch)
@@ -282,7 +292,7 @@ class StringParser
282
292
  // If this last character is the end of the pattern, parse it.
283
293
  if ('Parse' in pParserState.Pattern)
284
294
  {
285
- return this.executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope);
295
+ return this.executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope, pState);
286
296
  }
287
297
  }
288
298
  else if (pCharacter in pParserState.PatternStartNode.PatternEnd)
@@ -316,7 +326,7 @@ class StringParser
316
326
  // If this last character is the end of the pattern, parse it.
317
327
  if ('Parse' in pParserState.Pattern)
318
328
  {
319
- return this.executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope);
329
+ return this.executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope, pState);
320
330
  }
321
331
  }
322
332
  }
@@ -357,8 +367,9 @@ class StringParser
357
367
  * @param {function} fCallback - The callback function to call when the parse is complete
358
368
  * @param {array} pDataContext - The history of data objects/context already passed in
359
369
  * @param {any} [pScope] - A sticky scope that can be used to carry state and simplify template
370
+ * @param {any} [pState] - A catchall state object for plumbing data through template processing.
360
371
  */
361
- parseString (pString, pParseTree, pData, fCallback, pDataContext, pScope)
372
+ parseString (pString, pParseTree, pData, fCallback, pDataContext, pScope, pState)
362
373
  {
363
374
  // TODO: There is danger here if a template function attempts to functionally recurse and doesn't pass this in.
364
375
  let tmpPreviousDataContext = (Array.isArray(pDataContext)) ? pDataContext : [];
@@ -372,7 +383,7 @@ class StringParser
372
383
  for (var i = 0; i < pString.length; i++)
373
384
  {
374
385
  // TODO: This is not fast.
375
- this.parseCharacter(pString[i], tmpParserState, pData, tmpDataContext, pScope);
386
+ this.parseCharacter(pString[i], tmpParserState, pData, tmpDataContext, pScope, pState);
376
387
  }
377
388
 
378
389
  this.flushOutputBuffer(tmpParserState);
@@ -392,7 +403,7 @@ class StringParser
392
403
  tmpAnticipate.anticipate(
393
404
  (fCallback) =>
394
405
  {
395
- this.parseCharacterAsync(pString[i], tmpParserState, pData, fCallback, tmpDataContext, pScope);
406
+ this.parseCharacterAsync(pString[i], tmpParserState, pData, fCallback, tmpDataContext, pScope, pState);
396
407
  });
397
408
  }
398
409
 
@@ -43,15 +43,16 @@ class FableServiceMetaTemplate extends libFableServiceBase
43
43
  * @param {function} fCallback - The callback function to call when a pattern is matched
44
44
  * @param {array} pDataContext - The history of data objects already passed in
45
45
  * @param {any} [pScope] - A sticky scope that can be used to carry state and simplify template
46
+ * @param {any} [pState] - A catchall state object for plumbing data through template processing.
46
47
  * @return {string} The result from the parser
47
48
  */
48
- parseString(pString, pData, fCallback, pDataContext, pScope)
49
+ parseString(pString, pData, fCallback, pDataContext, pScope, pState)
49
50
  {
50
51
  if (this.LogNoisiness > 4)
51
52
  {
52
53
  this.fable.log.trace(`Metatemplate parsing template string [${pString}] where the callback is a ${typeof(fCallback)}`, {TemplateData:pData});
53
54
  }
54
- return this.StringParser.parseString(pString, this.ParseTree, pData, fCallback, pDataContext, pScope);
55
+ return this.StringParser.parseString(pString, this.ParseTree, pData, fCallback, pDataContext, pScope, pState);
55
56
  }
56
57
  }
57
58
 
@@ -302,6 +302,25 @@ suite
302
302
  }
303
303
  );
304
304
  test
305
+ (
306
+ 'Test sanitizing object keys',
307
+ (fTestComplete)=>
308
+ {
309
+ let testFable = new libFable({LogStreams: false});
310
+ let _DataFormat = testFable.services.DataFormat;
311
+ Expect(_DataFormat
312
+ .sanitizeObjectKey('Dogs'))
313
+ .to.equal('Dogs');
314
+ Expect(_DataFormat
315
+ .sanitizeObjectKey('Dogs are cool'))
316
+ .to.equal('Dogs_are_cool');
317
+ Expect(_DataFormat
318
+ .sanitizeObjectKey('Dogs 123 are cool!'))
319
+ .to.equal('Dogs_123_are_cool_');
320
+ return fTestComplete();
321
+ }
322
+ );
323
+ test
305
324
  (
306
325
  'Pad the beginning of a string',
307
326
  (fTestComplete)=>