fable 3.0.14 → 3.0.17

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/debug/Harness.js CHANGED
@@ -1,9 +1,31 @@
1
1
  const libFable = require('../source/Fable.js');
2
2
 
3
+ class SimpleService extends libFable.ServiceProviderBase
4
+ {
5
+ constructor(pFable, pOptions, pServiceHash)
6
+ {
7
+ super(pFable, pOptions, pServiceHash);
8
+
9
+ this.serviceType = 'SimpleService';
10
+ }
11
+
12
+ doSomething()
13
+ {
14
+ this.fable.log.info(`SimpleService ${this.UUID}::${this.Hash} is doing something.`);
15
+ }
16
+ }
17
+
3
18
  let testFable = new libFable({});
4
19
 
5
- testFable.serviceManager.addServiceType('SimpleService');
20
+ testFable.serviceManager.addServiceType('SimpleService', SimpleService);
6
21
 
7
22
  testFable.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true}, 'SimpleService-123');
8
23
 
9
- console.log(`Initialized Service ${testFable.serviceManager.services['SimpleService']['SimpleService-123'].serviceType} as UUID ${testFable.serviceManager.services['SimpleService']['SimpleService-123'].UUID} with hash ${testFable.serviceManager.services['SimpleService']['SimpleService-123'].Hash}`);
24
+
25
+ testFable.serviceManager.services['SimpleService']['SimpleService-123'].doSomething();
26
+
27
+ testFable.serviceManager.services['SimpleService']['SimpleService-123'].doSomething();
28
+
29
+ console.log(`Initialized Service ${testFable.serviceManager.services['SimpleService']['SimpleService-123'].serviceType} as UUID ${testFable.serviceManager.services['SimpleService']['SimpleService-123'].UUID} with hash ${testFable.serviceManager.services['SimpleService']['SimpleService-123'].Hash}`);
30
+
31
+ testFable.serviceManager.services['SimpleService']['SimpleService-123'].doSomething();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fable",
3
- "version": "3.0.14",
3
+ "version": "3.0.17",
4
4
  "description": "An entity behavior management and API bundling library.",
5
5
  "main": "source/Fable.js",
6
6
  "scripts": {
@@ -31,6 +31,8 @@ class FableOperation
31
31
  {
32
32
  this.fable = pFable;
33
33
 
34
+ this.name = pOperationName;
35
+
34
36
  this.state = JSON.parse(_OperationStatePrototype);
35
37
 
36
38
  this.state.Metadata.GUID = this.fable.getUUID();
@@ -0,0 +1,106 @@
1
+ const libFableServiceBase = require('./Fable-ServiceProviderBase.js');
2
+
3
+ class FableServiceTemplate extends libFableServiceBase
4
+ {
5
+ // Underscore and lodash have a behavior, _.template, which compiles a
6
+ // string-based template with code snippets into simple executable pieces,
7
+ // with the added twist of returning a precompiled function ready to go.
8
+ //
9
+ // NOTE: This does not implement underscore escape expressions
10
+ // NOTE: This does not implement underscore magic browser variable assignment
11
+ //
12
+ // This is an implementation of that.
13
+ // TODO: Make this use precedent, add configuration, add debugging.
14
+ constructor(pFable, pOptions, pServiceHash)
15
+ {
16
+ super(pFable, pOptions, pServiceHash);
17
+
18
+ this.serviceType = 'Template';
19
+
20
+ // These are the exact regex's used in lodash/underscore
21
+ // TODO: Switch this to precedent
22
+ this.Matchers = (
23
+ {
24
+ Evaluate: /<%([\s\S]+?)%>/g,
25
+ Interpolate: /<%=([\s\S]+?)%>/g,
26
+ Escaper: /\\|'|\r|\n|\t|\u2028|\u2029/g,
27
+ Unescaper: /\\(\\|'|r|n|t|u2028|u2029)/g,
28
+ // This is how underscore does it, so we are keeping it for now.
29
+ GuaranteedNonMatch: /.^/
30
+ });
31
+
32
+ // This is a helper for the escaper and unescaper functions.
33
+ // Right now we are going to keep what underscore is doing, but, not forever.
34
+ this.templateEscapes = {
35
+ '\\': '\\',
36
+ "'": "'",
37
+ 'r': '\r',
38
+ '\r': 'r',
39
+ 'n': '\n',
40
+ '\n': 'n',
41
+ 't': '\t',
42
+ '\t': 't',
43
+ 'u2028': '\u2028',
44
+ '\u2028': 'u2028',
45
+ 'u2029': '\u2029',
46
+ '\u2029': 'u2029'
47
+ };
48
+
49
+ // This is defined as such to underscore that it is a dynamic programming
50
+ // function on this class.
51
+ this.renderFunction = false;
52
+ this.templateString = false;
53
+ }
54
+
55
+ renderTemplate(pData)
56
+ {
57
+ return this.renderFunction(pData);
58
+ }
59
+
60
+ templateFunction(pData)
61
+ {
62
+ let fRenderTemplateBound = this.renderTemplate.bind(this);
63
+ return fRenderTemplateBound;
64
+ }
65
+
66
+ buildTemplateFunction(pTemplateText, pData)
67
+ {
68
+ // For now this is being kept in a weird form ... this is to mimic the old
69
+ // underscore code until this is rewritten using precedent.
70
+ this.TemplateSource = "__p+='" + pTemplateText
71
+ .replace(this.Matchers.Escaper,
72
+ (pMatch)=>
73
+ {
74
+ return `\\${this.templateEscapes[pMatch]}`;
75
+ })
76
+ .replace(this.Matchers.Interpolate || this.Matchers.GuaranteedNonMatch,
77
+ (pMatch, pCode) =>
78
+ {
79
+ return `'+\n(${decodeURIComponent(pCode)})+\n'`;
80
+ })
81
+ .replace(this.Matchers.Evaluate || this.Matchers.GuaranteedNonMatch,
82
+ (pMatch, pCode) =>
83
+ {
84
+ return `';\n${decodeURIComponent(pCode)}\n;__p+='`;
85
+ }) + `';\n`;
86
+
87
+
88
+ this.TemplateSource = `with(pTemplateDataObject||{}){\n${this.TemplateSource}}\n`;
89
+ this.TemplateSource = `var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n${this.TemplateSource}return __p;\n`;
90
+
91
+ this.renderFunction = new Function('pTemplateDataObject', this.TemplateSource);
92
+
93
+ if (typeof(pData) != 'undefined')
94
+ {
95
+ return this.renderFunction(pData);
96
+ }
97
+
98
+ // Provide the compiled function source as a convenience for build time
99
+ // precompilation.
100
+ this.TemplateSourceCompiled = 'function(obj){\n' + this.TemplateSource + '}';
101
+
102
+ return this.templateFunction();
103
+ }
104
+ }
105
+
106
+ module.exports = FableServiceTemplate;
@@ -32,7 +32,7 @@ class FableService
32
32
  // Add the container for instantiated services to go in
33
33
  this.services[pServiceType] = {};
34
34
 
35
- if (typeof(pServiceClass) == 'object' && pServiceClass.prototype instanceof libFableServiceBase)
35
+ if ((typeof(pServiceClass) == 'function') && (pServiceClass.prototype instanceof libFableServiceBase))
36
36
  {
37
37
  // Add the class to the list of classes
38
38
  this.serviceClasses[pServiceType] = pServiceClass;
@@ -47,7 +47,7 @@ class FableService
47
47
  instantiateServiceProvider(pServiceType, pOptions, pCustomServiceHash)
48
48
  {
49
49
  // Instantiate the service
50
- let tmpService = new this.serviceClasses[pServiceType](this.fable, pOptions, pCustomServiceHash);
50
+ let tmpService = this.instantiateServiceProviderWithoutRegistration(pServiceType, pOptions, pCustomServiceHash);
51
51
 
52
52
  // Add the service to the service map
53
53
  this.services[pServiceType][tmpService.Hash] = tmpService;
@@ -61,6 +61,14 @@ class FableService
61
61
  return tmpService;
62
62
  }
63
63
 
64
+ // Create a service provider but don't register it to live forever in fable.services
65
+ instantiateServiceProviderWithoutRegistration(pServiceType, pOptions, pCustomServiceHash)
66
+ {
67
+ // Instantiate the service
68
+ let tmpService = new this.serviceClasses[pServiceType](this.fable, pOptions, pCustomServiceHash);
69
+ return tmpService;
70
+ }
71
+
64
72
  setDefaultServiceInstantiation(pServiceType, pServiceHash)
65
73
  {
66
74
  if (this.services[pServiceType].hasOwnProperty(pServiceHash))
@@ -71,18 +79,8 @@ class FableService
71
79
 
72
80
  return false;
73
81
  }
74
-
75
- getServiceByHash(pServiceHash)
76
- {
77
- if (this.services.hasOwnProperty(pServiceHash))
78
- {
79
- return this.services[pServiceHash];
80
- }
81
-
82
- return false;
83
- }
84
82
  }
85
83
 
86
84
  module.exports = FableService;
87
85
 
88
- module.exports.FableServiceBase = libFableServiceBase;
86
+ module.exports.ServiceProviderBase = libFableServiceBase;
@@ -10,7 +10,7 @@ class FableServiceProviderBase
10
10
  {
11
11
  this.fable = pFable;
12
12
 
13
- this.options = pOptions;
13
+ this.options = (typeof(pOptions) === 'object') ? pOptions : {};
14
14
 
15
15
  this.serviceType = 'Unknown';
16
16
 
@@ -1,7 +1,6 @@
1
- const libFableUtilityTemplate = require('./Fable-Utility-Template.js');
2
1
  // TODO: These are still pretty big -- consider the smaller polyfills
3
2
  const libAsyncWaterfall = require('async.waterfall');
4
- const libAsyncEachLimit = require('async.eachLimit');
3
+ const libAsyncEachLimit = require('async.eachlimit');
5
4
 
6
5
  class FableUtility
7
6
  {
@@ -9,6 +8,8 @@ class FableUtility
9
8
  {
10
9
  this.fable = pFable;
11
10
 
11
+ this.templates = {};
12
+
12
13
  // These two functions are used extensively throughout
13
14
  this.waterfall = libAsyncWaterfall;
14
15
  this.eachLimit = libAsyncEachLimit;
@@ -26,11 +27,21 @@ class FableUtility
26
27
  // with the added twist of returning a precompiled function ready to go.
27
28
  template(pTemplateText, pData)
28
29
  {
29
- let tmpTemplate = new libFableUtilityTemplate(this.fable, pTemplateText);
30
+ let tmpTemplate = this.fable.serviceManager.instantiateServiceProviderWithoutRegistration('Template');
30
31
 
31
32
  return tmpTemplate.buildTemplateFunction(pTemplateText, pData);
32
33
  }
33
34
 
35
+ // Build a template function from a template hash, and, register it with the service provider
36
+ buildHashedTemplate(pTemplateHash, pTemplateText, pData)
37
+ {
38
+ let tmpTemplate = this.fable.serviceManager.instantiateServiceProvider('Template', {}, pTemplateHash);
39
+
40
+ this.templates[pTemplateHash] = tmpTemplate.buildTemplateFunction(pTemplateText, pData);
41
+
42
+ return this.templates[pTemplateHash];
43
+ }
44
+
34
45
  // This is a safe, modern version of chunk from underscore
35
46
  // Algorithm pulled from a mix of these two polyfills:
36
47
  // https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore#_chunk
package/source/Fable.js CHANGED
@@ -10,6 +10,8 @@ const libFableLog = require('fable-log');
10
10
  const libFableUtility = require('./Fable-Utility.js');
11
11
  const libFableServiceManager = require('./Fable-ServiceManager.js');
12
12
 
13
+ const libFableServiceTemplate = require('./Fable-Service-Template.js');
14
+
13
15
  const libFableOperation = require('./Fable-Operation.js');
14
16
 
15
17
  class Fable
@@ -39,6 +41,11 @@ class Fable
39
41
  this.Operations = {};
40
42
 
41
43
  this.serviceManager = new libFableServiceManager(this);
44
+
45
+ this.serviceManager.addServiceType('Template', libFableServiceTemplate);
46
+
47
+ this.services = this.serviceManager.services;
48
+ this.defaultServices = this.serviceManager.defaultServices;
42
49
  }
43
50
 
44
51
  get settings()
@@ -81,7 +88,7 @@ class Fable
81
88
  }
82
89
  else
83
90
  {
84
- return this.pOperations[pOperationHash];
91
+ return this.Operations[pOperationHash];
85
92
  }
86
93
  }
87
94
  }
@@ -30,13 +30,33 @@ suite
30
30
  let testFable = new libFable();
31
31
  let tmpOperation = testFable.createOperation('Big Complex Integration Operation', 'INTEGRATION-123');
32
32
  Expect(tmpOperation).to.be.an('object');
33
+ Expect(testFable.getOperation('INTEGRATION-123')).to.equal(tmpOperation);
34
+ Expect(testFable.getOperation('BADHASH')).to.be.false;
33
35
  Expect(testFable.Operations.hasOwnProperty('INTEGRATION-123')).to.equal(true);
34
- tmpOperation.log.info('Test 123');
36
+ tmpOperation.log.info(`Operation GUID ${tmpOperation.GUID} ---- Test 123`);
35
37
  Expect(tmpOperation.state.Log.length).to.equal(1);
36
38
  Expect(tmpOperation.state.Log[0]).to.contain('Test 123');
37
39
  }
38
40
  );
39
41
  test
42
+ (
43
+ 'Create an Operation and try to create another with the hash',
44
+ function()
45
+ {
46
+ let testFable = new libFable();
47
+ let tmpOperation = testFable.createOperation('Big Complex Integration Operation', 'INTEGRATION-123');
48
+ Expect(tmpOperation).to.be.an('object');
49
+ Expect(tmpOperation.name).to.equal('Big Complex Integration Operation');
50
+
51
+ let tmpCollisionOperation = testFable.createOperation('Another Big Complex Integration Operation with Colliding Name', 'INTEGRATION-123');
52
+ Expect(tmpCollisionOperation).to.be.an('object');
53
+ Expect(tmpCollisionOperation.name).to.equal('Another Big Complex Integration Operation with Colliding Name');
54
+
55
+ Expect(testFable.getOperation('INTEGRATION-123')).to.equal(tmpOperation);
56
+
57
+ }
58
+ );
59
+ test
40
60
  (
41
61
  'Create a basic Integration Operation without a Hash',
42
62
  function()
@@ -54,10 +74,11 @@ suite
54
74
  tmpOperation.log.debug('Debug something.', {TestData:'Ignition Complete'});
55
75
  tmpOperation.log.warn('Something was almost bad.');
56
76
  tmpOperation.log.error('This was an error!');
77
+ tmpOperation.log.error('And this was an error with some sort of data!', {TestData:'Ignition Complete'});
57
78
  tmpOperation.log.fatal('It was fatal.');
58
- Expect(tmpOperation.state.Log.length).to.equal(7);
79
+ Expect(tmpOperation.state.Log.length).to.equal(9);
59
80
  Expect(tmpOperation.state.Log[3]).to.equal('{"TestData":"Ignition Complete"}')
60
- Expect(tmpOperation.state.Errors.length).to.equal(2);
81
+ Expect(tmpOperation.state.Errors.length).to.equal(4);
61
82
  }
62
83
  );
63
84
  }
@@ -11,6 +11,41 @@ var libFable = require('../source/Fable.js');
11
11
  var Chai = require("chai");
12
12
  var Expect = Chai.expect;
13
13
 
14
+ class SimpleService extends libFable.ServiceProviderBase
15
+ {
16
+ constructor(pFable, pOptions, pServiceHash)
17
+ {
18
+ super(pFable, pOptions, pServiceHash);
19
+
20
+ this.serviceType = 'SimpleService';
21
+ }
22
+
23
+ doSomething()
24
+ {
25
+ this.fable.log.info(`SimpleService ${this.UUID}::${this.Hash} is doing something.`);
26
+ }
27
+ }
28
+
29
+ class MockDatabaseService extends libFable.ServiceProviderBase
30
+ {
31
+ constructor(pFable, pOptions, pServiceHash)
32
+ {
33
+ super(pFable, pOptions, pServiceHash);
34
+
35
+ this.serviceType = 'MockDatabaseService';
36
+ }
37
+
38
+ connect()
39
+ {
40
+ this.fable.log.info(`MockDatabaseService ${this.UUID}::${this.Hash} is connecting to a database.`);
41
+ }
42
+
43
+ commit(pRecord)
44
+ {
45
+ this.fable.log.info(`MockDatabaseService ${this.UUID}::${this.Hash} is committing a record ${pRecord}.`);
46
+ }
47
+ }
48
+
14
49
  suite
15
50
  (
16
51
  'Fable Service Manager',
@@ -48,15 +83,117 @@ suite
48
83
  function()
49
84
  {
50
85
  testFable = new libFable();
51
- testFable.serviceManager.addServiceType('SimpleService');
86
+ testFable.serviceManager.addServiceType('SimpleService', SimpleService);
52
87
  testFable.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true}, 'SimpleService-123');
53
88
 
54
89
  Expect(testFable.serviceManager.services['SimpleService']['SimpleService-123']).to.be.an('object');
55
90
 
56
91
  Expect(testFable.serviceManager.defaultServices['SimpleService']).to.be.an('object');
92
+
93
+ testFable.serviceManager.defaultServices.SimpleService.doSomething();
94
+
57
95
  Expect(testFable.serviceManager.defaultServices['SimpleService'].Hash).to.equal('SimpleService-123');
58
96
  }
59
97
  );
98
+ test
99
+ (
100
+ 'Use the Default Service with a different hash',
101
+ function()
102
+ {
103
+ let testFable = new libFable({});
104
+
105
+ testFable.serviceManager.addServiceType('SimpleService', SimpleService);
106
+
107
+ testFable.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true}, 'SimpleService-13');
108
+
109
+ testFable.serviceManager.services['SimpleService']['SimpleService-13'].doSomething();
110
+
111
+ Expect(testFable.serviceManager.services['SimpleService']['SimpleService-13']).to.be.an('object');
112
+ }
113
+ );
114
+
115
+ test
116
+ (
117
+ 'Instantiate a service without registering it to Fable',
118
+ function()
119
+ {
120
+ let testFable = new libFable({});
121
+
122
+ testFable.serviceManager.addServiceType('SimpleService', SimpleService);
123
+
124
+ let tmpService = testFable.serviceManager.instantiateServiceProviderWithoutRegistration('SimpleService', {SomeOption: true}, 'SimpleService-99');
125
+
126
+ Expect(testFable.services.SimpleService['SimpleService-99']).to.be.an('undefined');
127
+
128
+ Expect(tmpService).to.be.an('object');
129
+ }
130
+ );
131
+
132
+ test
133
+ (
134
+ 'Change the default service provider',
135
+ function()
136
+ {
137
+ let testFable = new libFable({});
138
+
139
+ testFable.serviceManager.addServiceType('SimpleService', SimpleService);
140
+ testFable.serviceManager.addServiceType('DatabaseService', MockDatabaseService);
141
+
142
+ testFable.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true});
143
+ testFable.serviceManager.defaultServices.SimpleService.doSomething();
144
+
145
+ testFable.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'PrimaryConnection');
146
+
147
+ Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('PrimaryConnection');
148
+
149
+ testFable.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'SecondaryConnection');
150
+
151
+ Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('PrimaryConnection');
152
+
153
+ testFable.serviceManager.defaultServices.DatabaseService.connect();
154
+ testFable.serviceManager.defaultServices.DatabaseService.commit('Test Record');
155
+
156
+ testFable.serviceManager.setDefaultServiceInstantiation('DatabaseService', 'SecondaryConnection');
157
+
158
+ testFable.serviceManager.defaultServices.DatabaseService.connect();
159
+ testFable.serviceManager.defaultServices.DatabaseService.commit('Another Test Record');
160
+
161
+ Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('SecondaryConnection');
162
+ }
163
+ );
164
+
165
+ test
166
+ (
167
+ 'Attempt to change the default service provider to a nonexistant provider',
168
+ function()
169
+ {
170
+ let testFable = new libFable({});
171
+
172
+ testFable.serviceManager.addServiceType('SimpleService', SimpleService);
173
+ testFable.serviceManager.addServiceType('DatabaseService', MockDatabaseService);
174
+
175
+ testFable.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true});
176
+ testFable.serviceManager.defaultServices.SimpleService.doSomething();
177
+
178
+ testFable.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'PrimaryConnection');
179
+
180
+ Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('PrimaryConnection');
181
+
182
+ testFable.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'SecondaryConnection');
183
+
184
+ Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('PrimaryConnection');
185
+
186
+ testFable.serviceManager.defaultServices.DatabaseService.connect();
187
+ testFable.serviceManager.defaultServices.DatabaseService.commit('Test Record');
188
+
189
+ Expect(testFable.serviceManager.setDefaultServiceInstantiation('DatabaseService', 'TertiaryConnection')).to.be.false;
190
+
191
+ testFable.serviceManager.defaultServices.DatabaseService.connect();
192
+ testFable.serviceManager.defaultServices.DatabaseService.commit('Another Test Record');
193
+
194
+ Expect(testFable.serviceManager.defaultServices.DatabaseService.Hash).to.equal('PrimaryConnection');
195
+ }
196
+ );
60
197
  }
61
198
  );
62
199
  }
@@ -58,9 +58,52 @@ suite
58
58
  function()
59
59
  {
60
60
  testFable = new libFable();
61
- let tmpTemplate = testFable.Utility.template('There are <%= Count %> things....');
61
+ let tmpTemplate = testFable.Utility.template('There // %> are \\ */ /* <%= Count %> things....');
62
62
  Expect(tmpTemplate).to.be.a('function');
63
- Expect(tmpTemplate({Count:1000})).to.equal('There are 1000 things....');
63
+ Expect(tmpTemplate({Count:1000})).to.equal('There // %> are \\ */ /* 1000 things....');
64
+ }
65
+ );
66
+ test
67
+ (
68
+ 'Processed Template like Underscore Work With Variables and no scope leakage',
69
+ function()
70
+ {
71
+ testFable = new libFable();
72
+ let tmpTemplate = testFable.Utility.template('There are so many of these things (<%= Count %> to be exact)....');
73
+ Expect(tmpTemplate).to.be.a('function');
74
+ Expect(tmpTemplate({Count:1000})).to.equal('There are so many of these things (1000 to be exact)....');
75
+ let tmpOtherTemplate = testFable.Utility.template('Things count: <%= Count %>');
76
+ Expect(tmpOtherTemplate).to.be.a('function');
77
+ Expect(tmpOtherTemplate({Count:600})).to.equal('Things count: 600');
78
+ Expect(tmpTemplate({Count:256})).to.equal('There are so many of these things (256 to be exact)....');
79
+ }
80
+ );
81
+ test
82
+ (
83
+ 'Processed Template like Underscore Work With Variables and no scope leakage',
84
+ function()
85
+ {
86
+ testFable = new libFable();
87
+ testFable.Utility.buildHashedTemplate('HeadLine', '<h1><%= TitleText %> Page</h1>');
88
+ testFable.Utility.buildHashedTemplate('Slogan', '<p>Some people, like <%= Name %>, have all the fun.</p>');
89
+
90
+ // Access the low level service render function
91
+ Expect(testFable.services.Template.HeadLine.renderFunction({TitleText:'Test'})).to.equal('<h1>Test Page</h1>');
92
+ Expect(testFable.services.Template.Slogan.renderFunction({Name:'Jim'})).to.equal('<p>Some people, like Jim, have all the fun.</p>');
93
+
94
+ // Use the high level simpler one
95
+ Expect(testFable.Utility.templates.HeadLine({TitleText:'A New'})).to.equal('<h1>A New Page</h1>');
96
+ Expect(testFable.Utility.templates.Slogan({Name:'Bob'})).to.equal('<p>Some people, like Bob, have all the fun.</p>');
97
+ }
98
+ );
99
+ test
100
+ (
101
+ 'Processed Template with default scope',
102
+ function()
103
+ {
104
+ testFable = new libFable();
105
+ let tmpTemplate = testFable.Utility.template('There are <%= Count %> things....', {Count:1000});
106
+ Expect(tmpTemplate).to.equal('There are 1000 things....');
64
107
  }
65
108
  );
66
109
  test
@@ -1,108 +0,0 @@
1
- class FableUtility
2
- {
3
- // Underscore and lodash have a behavior, _.template, which compiles a
4
- // string-based template with code snippets into simple executable pieces,
5
- // with the added twist of returning a precompiled function ready to go.
6
- //
7
- // NOTE: This does not implement underscore escape expressions
8
- // NOTE: This does not implement underscore magic browser variable assignment
9
- //
10
- // This is an implementation of that.
11
- // TODO: Make this use precedent, add configuration, add debugging.
12
- constructor(pFable, pTemplateText)
13
- {
14
- this.fable = pFable;
15
-
16
- // These are the exact regex's used in lodash/underscore
17
- // TODO: Switch this to precedent
18
- this.Matchers = (
19
- {
20
- Evaluate: /<%([\s\S]+?)%>/g,
21
- Interpolate: /<%=([\s\S]+?)%>/g,
22
- Escaper: /\\|'|\r|\n|\t|\u2028|\u2029/g,
23
- Unescaper: /\\(\\|'|r|n|t|u2028|u2029)/g,
24
- // This is how underscore does it, so we are keeping it for now.
25
- GuaranteedNonMatch: /.^/
26
- });
27
-
28
- // This is a helper for the escaper and unescaper functions.
29
- // Right now we are going to keep what underscore is doing, but, not forever.
30
- this.templateEscapes = {
31
- '\\': '\\',
32
- "'": "'",
33
- 'r': '\r',
34
- '\r': 'r',
35
- 'n': '\n',
36
- '\n': 'n',
37
- 't': '\t',
38
- '\t': 't',
39
- 'u2028': '\u2028',
40
- '\u2028': 'u2028',
41
- 'u2029': '\u2029',
42
- '\u2029': 'u2029'
43
- };
44
-
45
- // This is defined as such to underscore that it is a dynamic programming
46
- // function on this class.
47
- this.renderFunction = ()=>{return ``};
48
- }
49
-
50
- // Underscore and lodash have a behavior, _.extend, which merges objects.
51
- // Now that es6 gives us this, use the native thingy.
52
- extend(pDestinationObject, ...pSourceObjects)
53
- {
54
- return Object.assign(pDestinationObject, ...pSourceObjects);
55
- }
56
-
57
- renderTemplate(pData)
58
- {
59
- return this.renderFunction(pData);
60
- }
61
-
62
- templateFunction(pData)
63
- {
64
- let fRenderTemplateBound = this.renderTemplate.bind(this);
65
- return fRenderTemplateBound;
66
- }
67
-
68
- buildTemplateFunction(pTemplateText, pData)
69
- {
70
- // For now this is being kept in a weird form ... this is to mimic the old
71
- // underscore code until this is rewritten using precedent.
72
- this.TemplateSource = "__p+='" + pTemplateText
73
- .replace(this.Matchers.Escaper,
74
- (pMatch)=>
75
- {
76
- return `\\${this.templateEscapes[pMatch]}`;
77
- })
78
- .replace(this.Matchers.Interpolate || this.Matchers.GuaranteedNonMatch,
79
- (pMatch, pCode) =>
80
- {
81
- return `'+\n(${decodeURIComponent(pCode)})+\n'`;
82
- })
83
- .replace(this.Matchers.Evaluate || this.Matchers.GuaranteedNonMatch,
84
- (pMatch, pCode) =>
85
- {
86
- return `';\n${decodeURIComponent(pCode)}\n;__p+='`;
87
- }) + `';\n`;
88
-
89
-
90
- this.TemplateSource = `with(pTemplateDataObject||{}){\n${this.TemplateSource}}\n`;
91
- this.TemplateSource = `var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n${this.TemplateSource}return __p;\n`;
92
-
93
- this.renderFunction = new Function('pTemplateDataObject', this.TemplateSource);
94
-
95
- if (typeof(pData) != 'undefined')
96
- {
97
- return this.renderFunction(pData);
98
- }
99
-
100
- // Provide the compiled function source as a convenience for build time
101
- // precompilation.
102
- this.TemplateSourceCompiled = 'function(obj){\n' + this.TemplateSource + '}';
103
-
104
- return this.templateFunction();
105
- }
106
- }
107
-
108
- module.exports = FableUtility;