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/dist/fable.js +33 -17
- package/dist/fable.js.map +1 -1
- package/dist/fable.min.js +2 -2
- package/dist/fable.min.js.map +1 -1
- package/package.json +1 -1
- package/source/services/Fable-Service-DataFormat.js +19 -1
- package/source/services/Fable-Service-MetaTemplate/MetaTemplate-StringParser.js +28 -17
- package/source/services/Fable-Service-MetaTemplate.js +3 -2
- package/test/DataFormat-StringManipulation_tests.js +19 -0
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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)=>
|