fable 3.1.72 → 3.1.74
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/docs/README.md +30 -6
- package/docs/_brand.json +18 -0
- package/docs/_playground.json +10 -0
- package/docs/_sidebar.md +2 -0
- package/docs/_version.json +3 -3
- package/docs/architecture.md +201 -39
- package/docs/index.html +6 -7
- package/docs/pict-docuserve.min.js +91 -0
- package/docs/pict-docuserve.min.js.map +1 -0
- package/docs/playground.md +38 -0
- package/docs/retold-catalog.json +1 -1
- package/docs/retold-keyword-index.json +8721 -8105
- package/docs/services/README.md +26 -9
- package/docs/services/anticipate.md +104 -40
- package/docs/services/csv-parser.md +63 -35
- package/docs/services/data-format.md +154 -49
- package/docs/services/data-generation.md +77 -16
- package/docs/services/dates.md +103 -36
- package/docs/services/environment-data.md +13 -2
- package/docs/services/expression-parser.md +280 -68
- package/docs/services/file-persistence.md +142 -150
- package/docs/services/logging.md +93 -37
- package/docs/services/logic.md +70 -22
- package/docs/services/manifest.md +114 -26
- package/docs/services/math.md +168 -63
- package/docs/services/meta-template.md +312 -158
- package/docs/services/object-cache.md +94 -11
- package/docs/services/operation.md +68 -6
- package/docs/services/progress-time.md +74 -13
- package/docs/services/progress-tracker-set.md +101 -3
- package/docs/services/rest-client.md +136 -104
- package/docs/services/settings-manager.md +133 -40
- package/docs/services/template.md +71 -22
- package/docs/services/utility.md +121 -29
- package/docs/services/uuid.md +58 -10
- package/package.json +2 -2
- package/source/services/Fable-Service-MetaTemplate/MetaTemplate-StringParser.js +6 -0
- package/test/MetaTemplating_tests.js +77 -0
- package/.claude/settings.local.json +0 -8
- package/docs/css/docuserve.css +0 -327
|
@@ -5,10 +5,13 @@ The Settings Manager provides centralized configuration management for Fable app
|
|
|
5
5
|
## Access
|
|
6
6
|
|
|
7
7
|
```javascript
|
|
8
|
+
const libFable = require('fable');
|
|
9
|
+
const fable = new libFable({ Product: 'SettingsDemo', ProductVersion: '1.0.0' });
|
|
10
|
+
|
|
8
11
|
// Pre-initialized, available directly
|
|
9
|
-
fable.SettingsManager
|
|
10
|
-
fable.settings
|
|
11
|
-
fable.settingsManager
|
|
12
|
+
console.log('fable.SettingsManager:', typeof fable.SettingsManager);
|
|
13
|
+
console.log('fable.settings:', typeof fable.settings, '(shorthand for SettingsManager.settings)');
|
|
14
|
+
console.log('fable.settingsManager:', typeof fable.settingsManager, '(alias)');
|
|
12
15
|
```
|
|
13
16
|
|
|
14
17
|
## Basic Usage
|
|
@@ -16,12 +19,21 @@ fable.settingsManager // Alias
|
|
|
16
19
|
### Reading Settings
|
|
17
20
|
|
|
18
21
|
```javascript
|
|
22
|
+
const libFable = require('fable');
|
|
23
|
+
const fable = new libFable({
|
|
24
|
+
Product: 'MyApplication',
|
|
25
|
+
ProductVersion: '1.0.0',
|
|
26
|
+
Database: { Host: 'localhost' }
|
|
27
|
+
});
|
|
28
|
+
|
|
19
29
|
// Access settings directly
|
|
20
30
|
const productName = fable.settings.Product;
|
|
21
|
-
const version
|
|
31
|
+
const version = fable.settings.ProductVersion;
|
|
22
32
|
|
|
23
33
|
// Access nested settings
|
|
24
34
|
const dbHost = fable.settings.Database.Host;
|
|
35
|
+
|
|
36
|
+
console.log('productName:', productName, 'version:', version, 'dbHost:', dbHost);
|
|
25
37
|
```
|
|
26
38
|
|
|
27
39
|
### Providing Configuration
|
|
@@ -29,7 +41,9 @@ const dbHost = fable.settings.Database.Host;
|
|
|
29
41
|
Pass settings when creating a Fable instance:
|
|
30
42
|
|
|
31
43
|
```javascript
|
|
32
|
-
const
|
|
44
|
+
const libFable = require('fable');
|
|
45
|
+
|
|
46
|
+
const fable = new libFable({
|
|
33
47
|
Product: 'MyApplication',
|
|
34
48
|
ProductVersion: '1.0.0',
|
|
35
49
|
|
|
@@ -44,6 +58,9 @@ const fable = new Fable({
|
|
|
44
58
|
Timeout: 30000
|
|
45
59
|
}
|
|
46
60
|
});
|
|
61
|
+
|
|
62
|
+
console.log('Database.Host:', fable.settings.Database.Host);
|
|
63
|
+
console.log('API.BaseURL:', fable.settings.API.BaseURL);
|
|
47
64
|
```
|
|
48
65
|
|
|
49
66
|
## Default Settings
|
|
@@ -51,7 +68,7 @@ const fable = new Fable({
|
|
|
51
68
|
Fable provides sensible defaults that your configuration extends:
|
|
52
69
|
|
|
53
70
|
```javascript
|
|
54
|
-
{
|
|
71
|
+
const defaultSettingsShape = {
|
|
55
72
|
Product: 'Fable',
|
|
56
73
|
ProductVersion: '0.0.0',
|
|
57
74
|
|
|
@@ -63,7 +80,8 @@ Fable provides sensible defaults that your configuration extends:
|
|
|
63
80
|
LogStreams: [
|
|
64
81
|
{ level: 'info' }
|
|
65
82
|
]
|
|
66
|
-
}
|
|
83
|
+
};
|
|
84
|
+
console.log('defaultSettingsShape:', defaultSettingsShape);
|
|
67
85
|
```
|
|
68
86
|
|
|
69
87
|
Your settings are merged with these defaults using [precedent](https://github.com/stevenvelozo/precedent).
|
|
@@ -73,24 +91,41 @@ Your settings are merged with these defaults using [precedent](https://github.co
|
|
|
73
91
|
### Using Environment Variables
|
|
74
92
|
|
|
75
93
|
```javascript
|
|
76
|
-
const
|
|
94
|
+
const libFable = require('fable');
|
|
95
|
+
|
|
96
|
+
const env = (typeof process !== 'undefined' && process.env) ? process.env : {};
|
|
97
|
+
|
|
98
|
+
const fable = new libFable({
|
|
77
99
|
Product: 'MyApp',
|
|
78
100
|
|
|
79
101
|
Database: {
|
|
80
|
-
Host:
|
|
81
|
-
Port:
|
|
82
|
-
Password:
|
|
102
|
+
Host: env.DB_HOST || 'localhost',
|
|
103
|
+
Port: parseInt(env.DB_PORT) || 5432,
|
|
104
|
+
Password: env.DB_PASSWORD
|
|
83
105
|
}
|
|
84
106
|
});
|
|
107
|
+
|
|
108
|
+
console.log('Database.Host:', fable.settings.Database.Host);
|
|
109
|
+
console.log('Database.Port:', fable.settings.Database.Port);
|
|
85
110
|
```
|
|
86
111
|
|
|
87
112
|
### Environment-Specific Config Files
|
|
88
113
|
|
|
89
114
|
```javascript
|
|
90
|
-
const
|
|
91
|
-
|
|
115
|
+
const libFable = require('fable');
|
|
116
|
+
|
|
117
|
+
const environment = (typeof process !== 'undefined' && process.env && process.env.NODE_ENV)
|
|
118
|
+
? process.env.NODE_ENV
|
|
119
|
+
: 'development';
|
|
120
|
+
|
|
121
|
+
// In Node.js you would load config like this:
|
|
122
|
+
// const config = require(`./config/${environment}.json`);
|
|
123
|
+
// In this playground we just construct an in-memory equivalent.
|
|
124
|
+
const config = { Product: 'MyApp', Environment: environment };
|
|
92
125
|
|
|
93
|
-
const fable = new
|
|
126
|
+
const fable = new libFable(config);
|
|
127
|
+
console.log('environment:', environment);
|
|
128
|
+
console.log('Configured product:', fable.settings.Product);
|
|
94
129
|
```
|
|
95
130
|
|
|
96
131
|
## Precedent Integration
|
|
@@ -98,6 +133,8 @@ const fable = new Fable(config);
|
|
|
98
133
|
The Settings Manager uses precedent for deep configuration merging:
|
|
99
134
|
|
|
100
135
|
```javascript
|
|
136
|
+
const libFable = require('fable');
|
|
137
|
+
|
|
101
138
|
// Base configuration
|
|
102
139
|
const baseConfig = {
|
|
103
140
|
API: {
|
|
@@ -113,6 +150,10 @@ const envConfig = {
|
|
|
113
150
|
}
|
|
114
151
|
};
|
|
115
152
|
|
|
153
|
+
// Merge happens automatically through Fable's settings layer (precedent)
|
|
154
|
+
const fable = new libFable(baseConfig);
|
|
155
|
+
fable.settingsManager.fill(envConfig);
|
|
156
|
+
console.log('Merged API settings:', fable.settings.API);
|
|
116
157
|
// Result: { API: { Timeout: 30000, RetryCount: 3 } }
|
|
117
158
|
```
|
|
118
159
|
|
|
@@ -121,41 +162,60 @@ const envConfig = {
|
|
|
121
162
|
### Layered Configuration
|
|
122
163
|
|
|
123
164
|
```javascript
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
165
|
+
const libFable = require('fable');
|
|
166
|
+
|
|
167
|
+
// In Node.js you would load these from JSON files on disk:
|
|
168
|
+
// const defaults = require('./config/default.json');
|
|
169
|
+
// const environment = require(`./config/${process.env.NODE_ENV}.json`);
|
|
170
|
+
// const local = require('./config/local.json'); // gitignored
|
|
171
|
+
// For the playground we use in-memory objects to show the layering shape:
|
|
172
|
+
const defaults = { Product: 'MyApp', API: { Timeout: 5000 } };
|
|
173
|
+
const environment = { API: { Timeout: 30000 } };
|
|
174
|
+
const local = { API: { BaseURL: 'http://localhost:8080' } };
|
|
175
|
+
|
|
176
|
+
const fable = new libFable({
|
|
129
177
|
...defaults,
|
|
130
178
|
...environment,
|
|
131
179
|
...local
|
|
132
180
|
});
|
|
181
|
+
|
|
182
|
+
console.log('Layered config result:', fable.settings.API);
|
|
133
183
|
```
|
|
134
184
|
|
|
135
185
|
### Feature Flags
|
|
136
186
|
|
|
137
187
|
```javascript
|
|
138
|
-
const
|
|
188
|
+
const libFable = require('fable');
|
|
189
|
+
|
|
190
|
+
const env = (typeof process !== 'undefined' && process.env) ? process.env : {};
|
|
191
|
+
|
|
192
|
+
const fable = new libFable({
|
|
139
193
|
Features: {
|
|
140
|
-
NewDashboard:
|
|
194
|
+
NewDashboard: env.FEATURE_NEW_DASHBOARD === 'true',
|
|
141
195
|
BetaAPI: false
|
|
142
196
|
}
|
|
143
197
|
});
|
|
144
198
|
|
|
145
199
|
// Usage
|
|
146
200
|
if (fable.settings.Features.NewDashboard) {
|
|
147
|
-
|
|
201
|
+
console.log('NewDashboard feature is ON');
|
|
202
|
+
} else {
|
|
203
|
+
console.log('NewDashboard feature is OFF (set FEATURE_NEW_DASHBOARD=true to enable)');
|
|
148
204
|
}
|
|
149
205
|
```
|
|
150
206
|
|
|
151
207
|
### Service Configuration
|
|
152
208
|
|
|
153
209
|
```javascript
|
|
154
|
-
const
|
|
210
|
+
const libFable = require('fable');
|
|
211
|
+
|
|
212
|
+
const env = (typeof process !== 'undefined' && process.env) ? process.env : {};
|
|
213
|
+
|
|
214
|
+
const fable = new libFable({
|
|
155
215
|
Services: {
|
|
156
216
|
Email: {
|
|
157
217
|
Provider: 'sendgrid',
|
|
158
|
-
APIKey:
|
|
218
|
+
APIKey: env.SENDGRID_API_KEY
|
|
159
219
|
},
|
|
160
220
|
Storage: {
|
|
161
221
|
Provider: 's3',
|
|
@@ -163,6 +223,9 @@ const fable = new Fable({
|
|
|
163
223
|
}
|
|
164
224
|
}
|
|
165
225
|
});
|
|
226
|
+
|
|
227
|
+
console.log('Email provider:', fable.settings.Services.Email.Provider);
|
|
228
|
+
console.log('Storage bucket:', fable.settings.Services.Storage.Bucket);
|
|
166
229
|
```
|
|
167
230
|
|
|
168
231
|
## Accessing Settings in Services
|
|
@@ -170,9 +233,17 @@ const fable = new Fable({
|
|
|
170
233
|
All Fable services can access settings:
|
|
171
234
|
|
|
172
235
|
```javascript
|
|
236
|
+
const libFable = require('fable');
|
|
237
|
+
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
238
|
+
const fable = new libFable({
|
|
239
|
+
Product: 'SettingsServiceDemo',
|
|
240
|
+
API: { BaseURL: 'https://api.example.com' }
|
|
241
|
+
});
|
|
242
|
+
|
|
173
243
|
class MyService extends libFableServiceBase {
|
|
174
244
|
constructor(pFable, pOptions, pServiceHash) {
|
|
175
245
|
super(pFable, pOptions, pServiceHash);
|
|
246
|
+
this.serviceType = 'MyService';
|
|
176
247
|
|
|
177
248
|
// Access global settings
|
|
178
249
|
this.apiUrl = this.fable.settings.API.BaseURL;
|
|
@@ -181,6 +252,11 @@ class MyService extends libFableServiceBase {
|
|
|
181
252
|
this.localOption = this.options.myOption;
|
|
182
253
|
}
|
|
183
254
|
}
|
|
255
|
+
|
|
256
|
+
fable.addAndInstantiateServiceType('MyService', MyService);
|
|
257
|
+
const svc = fable.instantiateServiceProvider('MyService', { myOption: 'demo-value' }, 'demo');
|
|
258
|
+
console.log('apiUrl:', svc.apiUrl);
|
|
259
|
+
console.log('localOption:', svc.localOption);
|
|
184
260
|
```
|
|
185
261
|
|
|
186
262
|
## Common Configuration Options
|
|
@@ -188,40 +264,44 @@ class MyService extends libFableServiceBase {
|
|
|
188
264
|
### Product Information
|
|
189
265
|
|
|
190
266
|
```javascript
|
|
191
|
-
{
|
|
267
|
+
const productInfoConfig = {
|
|
192
268
|
Product: 'MyApp',
|
|
193
269
|
ProductVersion: '1.0.0'
|
|
194
|
-
}
|
|
270
|
+
};
|
|
271
|
+
console.log('productInfoConfig:', productInfoConfig);
|
|
195
272
|
```
|
|
196
273
|
|
|
197
274
|
### UUID Configuration
|
|
198
275
|
|
|
199
276
|
```javascript
|
|
200
|
-
{
|
|
277
|
+
const uuidConfig = {
|
|
201
278
|
UUID: {
|
|
202
279
|
DataCenter: 1, // 0-31
|
|
203
280
|
Worker: 5 // 0-31
|
|
204
281
|
}
|
|
205
|
-
}
|
|
282
|
+
};
|
|
283
|
+
console.log('uuidConfig:', uuidConfig);
|
|
206
284
|
```
|
|
207
285
|
|
|
208
286
|
### Logging Configuration
|
|
209
287
|
|
|
210
288
|
```javascript
|
|
211
|
-
{
|
|
289
|
+
const loggingConfig = {
|
|
212
290
|
LogStreams: [
|
|
213
291
|
{ level: 'info' },
|
|
214
292
|
{ level: 'error', path: '/var/log/app/error.log' }
|
|
215
293
|
]
|
|
216
|
-
}
|
|
294
|
+
};
|
|
295
|
+
console.log('loggingConfig:', loggingConfig);
|
|
217
296
|
```
|
|
218
297
|
|
|
219
298
|
### REST Client Configuration
|
|
220
299
|
|
|
221
300
|
```javascript
|
|
222
|
-
{
|
|
301
|
+
const restClientConfig = {
|
|
223
302
|
RestClientURLPrefix: 'https://api.example.com/v1'
|
|
224
|
-
}
|
|
303
|
+
};
|
|
304
|
+
console.log('restClientConfig:', restClientConfig);
|
|
225
305
|
```
|
|
226
306
|
|
|
227
307
|
## Best Practices
|
|
@@ -233,24 +313,28 @@ class MyService extends libFableServiceBase {
|
|
|
233
313
|
5. **Validate on startup**: Check for required settings early
|
|
234
314
|
|
|
235
315
|
```javascript
|
|
316
|
+
const libFable = require('fable');
|
|
317
|
+
|
|
236
318
|
// Validation example
|
|
237
|
-
const
|
|
319
|
+
const config = { Product: 'MyApp', Database: { Host: 'localhost' } };
|
|
320
|
+
const fable = new libFable(config);
|
|
238
321
|
|
|
239
322
|
if (!fable.settings.Database?.Host) {
|
|
240
323
|
throw new Error('Database.Host is required');
|
|
241
324
|
}
|
|
325
|
+
console.log('Validation passed — Database.Host =', fable.settings.Database.Host);
|
|
242
326
|
```
|
|
243
327
|
|
|
244
328
|
## Reading External Config Files
|
|
245
329
|
|
|
246
330
|
```javascript
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
const fable = new
|
|
331
|
+
// Node.js reference — this pattern uses fs which is not available in the browser playground.
|
|
332
|
+
console.info("In Node.js:");
|
|
333
|
+
console.info(" const fs = require('fs');");
|
|
334
|
+
console.info(" const path = require('path');");
|
|
335
|
+
console.info(" const configPath = path.join(__dirname, 'config.json');");
|
|
336
|
+
console.info(" const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));");
|
|
337
|
+
console.info(" const fable = new (require('fable'))(config);");
|
|
254
338
|
```
|
|
255
339
|
|
|
256
340
|
## Runtime Configuration Updates
|
|
@@ -258,8 +342,17 @@ const fable = new Fable(config);
|
|
|
258
342
|
While generally not recommended, settings can be modified at runtime:
|
|
259
343
|
|
|
260
344
|
```javascript
|
|
345
|
+
const libFable = require('fable');
|
|
346
|
+
const fable = new libFable({
|
|
347
|
+
Product: 'RuntimeMutationDemo',
|
|
348
|
+
MyFeature: { Enabled: false }
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
console.log('Before:', fable.settings.MyFeature.Enabled);
|
|
352
|
+
|
|
261
353
|
// Not recommended, but possible
|
|
262
354
|
fable.settings.MyFeature.Enabled = true;
|
|
263
355
|
|
|
356
|
+
console.log('After:', fable.settings.MyFeature.Enabled);
|
|
264
357
|
// Better: Use a service for dynamic configuration
|
|
265
358
|
```
|
|
@@ -5,11 +5,16 @@ The Template service provides underscore/lodash-style template compilation and r
|
|
|
5
5
|
## Access
|
|
6
6
|
|
|
7
7
|
```javascript
|
|
8
|
+
const libFable = require('fable');
|
|
9
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
10
|
+
|
|
8
11
|
// On-demand service - instantiate when needed
|
|
9
12
|
const template = fable.instantiateServiceProvider('Template');
|
|
13
|
+
console.log('template service:', typeof template);
|
|
10
14
|
|
|
11
15
|
// Or use the Utility service shorthand
|
|
12
16
|
const renderFn = fable.Utility.template('Hello, <%= name %>!');
|
|
17
|
+
console.log('renderFn:', typeof renderFn);
|
|
13
18
|
```
|
|
14
19
|
|
|
15
20
|
## Template Syntax
|
|
@@ -19,10 +24,13 @@ const renderFn = fable.Utility.template('Hello, <%= name %>!');
|
|
|
19
24
|
Output a value:
|
|
20
25
|
|
|
21
26
|
```javascript
|
|
27
|
+
const libFable = require('fable');
|
|
28
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
29
|
+
|
|
22
30
|
const template = fable.instantiateServiceProvider('Template');
|
|
23
31
|
const render = template.buildTemplateFunction('Hello, <%= name %>!');
|
|
24
32
|
|
|
25
|
-
render({ name: 'World' }); // Returns 'Hello, World!'
|
|
33
|
+
console.log(render({ name: 'World' })); // Returns 'Hello, World!'
|
|
26
34
|
```
|
|
27
35
|
|
|
28
36
|
### Evaluation (`<% %>`)
|
|
@@ -30,13 +38,17 @@ render({ name: 'World' }); // Returns 'Hello, World!'
|
|
|
30
38
|
Execute JavaScript code:
|
|
31
39
|
|
|
32
40
|
```javascript
|
|
41
|
+
const libFable = require('fable');
|
|
42
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
43
|
+
const template = fable.instantiateServiceProvider('Template');
|
|
44
|
+
|
|
33
45
|
const render = template.buildTemplateFunction(`
|
|
34
46
|
<% for (var i = 0; i < items.length; i++) { %>
|
|
35
47
|
Item: <%= items[i] %>
|
|
36
48
|
<% } %>
|
|
37
49
|
`);
|
|
38
50
|
|
|
39
|
-
render({ items: ['Apple', 'Banana', 'Cherry'] });
|
|
51
|
+
console.log(render({ items: ['Apple', 'Banana', 'Cherry'] }));
|
|
40
52
|
```
|
|
41
53
|
|
|
42
54
|
## Basic Usage
|
|
@@ -44,14 +56,17 @@ render({ items: ['Apple', 'Banana', 'Cherry'] });
|
|
|
44
56
|
### Create and Use Template
|
|
45
57
|
|
|
46
58
|
```javascript
|
|
59
|
+
const libFable = require('fable');
|
|
60
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
61
|
+
|
|
47
62
|
const template = fable.instantiateServiceProvider('Template');
|
|
48
63
|
|
|
49
64
|
// Build the template function
|
|
50
65
|
const greetingTemplate = template.buildTemplateFunction('Hello, <%= name %>!');
|
|
51
66
|
|
|
52
67
|
// Use it multiple times
|
|
53
|
-
greetingTemplate({ name: 'Alice' }); // 'Hello, Alice!'
|
|
54
|
-
greetingTemplate({ name: 'Bob' }); // 'Hello, Bob!'
|
|
68
|
+
console.log(greetingTemplate({ name: 'Alice' })); // 'Hello, Alice!'
|
|
69
|
+
console.log(greetingTemplate({ name: 'Bob' })); // 'Hello, Bob!'
|
|
55
70
|
```
|
|
56
71
|
|
|
57
72
|
### Immediate Rendering
|
|
@@ -59,7 +74,12 @@ greetingTemplate({ name: 'Bob' }); // 'Hello, Bob!'
|
|
|
59
74
|
Pass data as the second argument to render immediately:
|
|
60
75
|
|
|
61
76
|
```javascript
|
|
77
|
+
const libFable = require('fable');
|
|
78
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
79
|
+
const template = fable.instantiateServiceProvider('Template');
|
|
80
|
+
|
|
62
81
|
const result = template.buildTemplateFunction('Sum: <%= a + b %>', { a: 5, b: 3 });
|
|
82
|
+
console.log(result);
|
|
63
83
|
// Returns 'Sum: 8'
|
|
64
84
|
```
|
|
65
85
|
|
|
@@ -68,12 +88,15 @@ const result = template.buildTemplateFunction('Sum: <%= a + b %>', { a: 5, b: 3
|
|
|
68
88
|
The Utility service provides a convenient wrapper:
|
|
69
89
|
|
|
70
90
|
```javascript
|
|
91
|
+
const libFable = require('fable');
|
|
92
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
93
|
+
|
|
71
94
|
// Create a template function
|
|
72
95
|
const greet = fable.Utility.template('Hello, <%= name %>!');
|
|
73
|
-
greet({ name: 'World' });
|
|
96
|
+
console.log(greet({ name: 'World' }));
|
|
74
97
|
|
|
75
98
|
// Or render immediately
|
|
76
|
-
fable.Utility.template('Hello, <%= name %>!', { name: 'World' });
|
|
99
|
+
console.log(fable.Utility.template('Hello, <%= name %>!', { name: 'World' }));
|
|
77
100
|
```
|
|
78
101
|
|
|
79
102
|
### Hashed Templates
|
|
@@ -81,6 +104,9 @@ fable.Utility.template('Hello, <%= name %>!', { name: 'World' });
|
|
|
81
104
|
Register templates for reuse by name:
|
|
82
105
|
|
|
83
106
|
```javascript
|
|
107
|
+
const libFable = require('fable');
|
|
108
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
109
|
+
|
|
84
110
|
// Register a template
|
|
85
111
|
fable.Utility.buildHashedTemplate('user-card', `
|
|
86
112
|
<div class="card">
|
|
@@ -90,7 +116,7 @@ fable.Utility.buildHashedTemplate('user-card', `
|
|
|
90
116
|
`);
|
|
91
117
|
|
|
92
118
|
// Use the registered template
|
|
93
|
-
fable.Utility.templates['user-card']({ user: { name: 'John', email: 'john@example.com' } });
|
|
119
|
+
console.log(fable.Utility.templates['user-card']({ user: { name: 'John', email: 'john@example.com' } }));
|
|
94
120
|
```
|
|
95
121
|
|
|
96
122
|
## Examples
|
|
@@ -98,6 +124,10 @@ fable.Utility.templates['user-card']({ user: { name: 'John', email: 'john@exampl
|
|
|
98
124
|
### HTML Generation
|
|
99
125
|
|
|
100
126
|
```javascript
|
|
127
|
+
const libFable = require('fable');
|
|
128
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
129
|
+
const template = fable.instantiateServiceProvider('Template');
|
|
130
|
+
|
|
101
131
|
const cardTemplate = template.buildTemplateFunction(`
|
|
102
132
|
<div class="card">
|
|
103
133
|
<h2><%= title %></h2>
|
|
@@ -108,17 +138,21 @@ const cardTemplate = template.buildTemplateFunction(`
|
|
|
108
138
|
</div>
|
|
109
139
|
`);
|
|
110
140
|
|
|
111
|
-
cardTemplate({
|
|
141
|
+
console.log(cardTemplate({
|
|
112
142
|
title: 'Welcome',
|
|
113
143
|
description: 'This is a card component',
|
|
114
144
|
showButton: true,
|
|
115
145
|
buttonText: 'Click Me'
|
|
116
|
-
});
|
|
146
|
+
}));
|
|
117
147
|
```
|
|
118
148
|
|
|
119
149
|
### Lists and Loops
|
|
120
150
|
|
|
121
151
|
```javascript
|
|
152
|
+
const libFable = require('fable');
|
|
153
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
154
|
+
const template = fable.instantiateServiceProvider('Template');
|
|
155
|
+
|
|
122
156
|
const listTemplate = template.buildTemplateFunction(`
|
|
123
157
|
<ul>
|
|
124
158
|
<% for (var i = 0; i < items.length; i++) { %>
|
|
@@ -127,33 +161,41 @@ const listTemplate = template.buildTemplateFunction(`
|
|
|
127
161
|
</ul>
|
|
128
162
|
`);
|
|
129
163
|
|
|
130
|
-
listTemplate({
|
|
164
|
+
console.log(listTemplate({
|
|
131
165
|
items: [
|
|
132
|
-
{ name: 'Apple',
|
|
166
|
+
{ name: 'Apple', price: 1.50 },
|
|
133
167
|
{ name: 'Banana', price: 0.75 }
|
|
134
168
|
]
|
|
135
|
-
});
|
|
169
|
+
}));
|
|
136
170
|
```
|
|
137
171
|
|
|
138
172
|
### Conditional Content
|
|
139
173
|
|
|
140
174
|
```javascript
|
|
175
|
+
const libFable = require('fable');
|
|
176
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
177
|
+
const template = fable.instantiateServiceProvider('Template');
|
|
178
|
+
|
|
141
179
|
const statusTemplate = template.buildTemplateFunction(`
|
|
142
|
-
<% if (status ===
|
|
180
|
+
<% if (status === "active") { %>
|
|
143
181
|
<span class="badge-green">Active</span>
|
|
144
|
-
<% } else if (status ===
|
|
182
|
+
<% } else if (status === "pending") { %>
|
|
145
183
|
<span class="badge-yellow">Pending</span>
|
|
146
184
|
<% } else { %>
|
|
147
185
|
<span class="badge-red">Inactive</span>
|
|
148
186
|
<% } %>
|
|
149
187
|
`);
|
|
150
188
|
|
|
151
|
-
statusTemplate({ status: 'active' });
|
|
189
|
+
console.log(statusTemplate({ status: 'active' }));
|
|
152
190
|
```
|
|
153
191
|
|
|
154
192
|
### Nested Data
|
|
155
193
|
|
|
156
194
|
```javascript
|
|
195
|
+
const libFable = require('fable');
|
|
196
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
197
|
+
const template = fable.instantiateServiceProvider('Template');
|
|
198
|
+
|
|
157
199
|
const profileTemplate = template.buildTemplateFunction(`
|
|
158
200
|
<div class="profile">
|
|
159
201
|
<h1><%= user.name %></h1>
|
|
@@ -166,7 +208,7 @@ const profileTemplate = template.buildTemplateFunction(`
|
|
|
166
208
|
</div>
|
|
167
209
|
`);
|
|
168
210
|
|
|
169
|
-
profileTemplate({
|
|
211
|
+
console.log(profileTemplate({
|
|
170
212
|
user: {
|
|
171
213
|
name: 'John Doe',
|
|
172
214
|
contact: {
|
|
@@ -178,7 +220,7 @@ profileTemplate({
|
|
|
178
220
|
{ street: '456 Oak Ave', city: 'Other City' }
|
|
179
221
|
]
|
|
180
222
|
}
|
|
181
|
-
});
|
|
223
|
+
}));
|
|
182
224
|
```
|
|
183
225
|
|
|
184
226
|
### Print Function
|
|
@@ -186,11 +228,15 @@ profileTemplate({
|
|
|
186
228
|
Use `print()` for inline output:
|
|
187
229
|
|
|
188
230
|
```javascript
|
|
189
|
-
const
|
|
190
|
-
|
|
231
|
+
const libFable = require('fable');
|
|
232
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
233
|
+
const template = fable.instantiateServiceProvider('Template');
|
|
234
|
+
|
|
235
|
+
const printTemplate = template.buildTemplateFunction(`
|
|
236
|
+
<% print("Hello"); print(" "); print("World"); %>
|
|
191
237
|
`);
|
|
192
238
|
|
|
193
|
-
|
|
239
|
+
console.log(printTemplate({})); // Returns 'Hello World'
|
|
194
240
|
```
|
|
195
241
|
|
|
196
242
|
## Template Source Access
|
|
@@ -198,12 +244,15 @@ template({}); // Returns 'Hello World'
|
|
|
198
244
|
After building a template, you can access the generated source:
|
|
199
245
|
|
|
200
246
|
```javascript
|
|
247
|
+
const libFable = require('fable');
|
|
248
|
+
const fable = new libFable({ Product: 'TemplateDemo', ProductVersion: '1.0.0' });
|
|
249
|
+
|
|
201
250
|
const tpl = fable.instantiateServiceProvider('Template');
|
|
202
251
|
tpl.buildTemplateFunction('Hello, <%= name %>!');
|
|
203
252
|
|
|
204
253
|
// Access the generated function source
|
|
205
|
-
console.log(tpl.TemplateSource);
|
|
206
|
-
console.log(tpl.TemplateSourceCompiled);
|
|
254
|
+
console.log('TemplateSource:', tpl.TemplateSource);
|
|
255
|
+
console.log('TemplateSourceCompiled:', tpl.TemplateSourceCompiled);
|
|
207
256
|
```
|
|
208
257
|
|
|
209
258
|
## Escape Handling
|