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
package/docs/README.md
CHANGED
|
@@ -16,10 +16,10 @@ Fable is a comprehensive framework that provides a service-oriented architecture
|
|
|
16
16
|
## Quick Start
|
|
17
17
|
|
|
18
18
|
```javascript
|
|
19
|
-
const
|
|
19
|
+
const libFable = require('fable');
|
|
20
20
|
|
|
21
21
|
// Create a new Fable instance with optional configuration
|
|
22
|
-
const fable = new
|
|
22
|
+
const fable = new libFable({
|
|
23
23
|
Product: 'MyApplication',
|
|
24
24
|
ProductVersion: '1.0.0',
|
|
25
25
|
LogStreams: [
|
|
@@ -54,14 +54,32 @@ Fable services fall into three categories:
|
|
|
54
54
|
### Service Registration
|
|
55
55
|
|
|
56
56
|
```javascript
|
|
57
|
+
const libFable = require('fable');
|
|
58
|
+
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
59
|
+
const fable = new libFable({ Product: 'ServiceRegistrationDemo', ProductVersion: '1.0.0' });
|
|
60
|
+
|
|
61
|
+
// A trivial service class for demonstration purposes
|
|
62
|
+
class MyServiceClass extends libFableServiceBase
|
|
63
|
+
{
|
|
64
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
65
|
+
{
|
|
66
|
+
super(pFable, pOptions, pServiceHash);
|
|
67
|
+
this.serviceType = 'MyService';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const options = { greeting: 'hello' };
|
|
71
|
+
|
|
57
72
|
// Add a service type without instantiating
|
|
58
73
|
fable.addServiceType('MyService', MyServiceClass);
|
|
74
|
+
console.log('Registered service types include MyService:', 'MyService' in fable.serviceTypes);
|
|
59
75
|
|
|
60
76
|
// Add and immediately instantiate a service
|
|
61
|
-
fable.addAndInstantiateServiceType('
|
|
77
|
+
fable.addAndInstantiateServiceType('AnotherService', MyServiceClass);
|
|
78
|
+
console.log('AnotherService instantiated:', typeof fable.AnotherService);
|
|
62
79
|
|
|
63
80
|
// Instantiate a service on-demand
|
|
64
81
|
const myService = fable.instantiateServiceProvider('MyService', options, 'custom-hash');
|
|
82
|
+
console.log('myService.serviceType:', myService.serviceType);
|
|
65
83
|
```
|
|
66
84
|
|
|
67
85
|
## Configuration
|
|
@@ -69,16 +87,22 @@ const myService = fable.instantiateServiceProvider('MyService', options, 'custom
|
|
|
69
87
|
Fable accepts a configuration object that controls various aspects of behavior:
|
|
70
88
|
|
|
71
89
|
```javascript
|
|
72
|
-
const
|
|
90
|
+
const libFable = require('fable');
|
|
91
|
+
|
|
92
|
+
const fable = new libFable({
|
|
73
93
|
Product: 'MyApp',
|
|
74
94
|
ProductVersion: '1.0.0',
|
|
75
95
|
UUID: { DataCenter: 0, Worker: 0 },
|
|
76
96
|
LogStreams: [
|
|
77
|
-
{ level: 'info' }
|
|
78
|
-
|
|
97
|
+
{ level: 'info' }
|
|
98
|
+
// In Node.js you can also write a file-based stream, e.g.:
|
|
99
|
+
// { level: 'error', path: '/var/log/myapp/error.log' }
|
|
79
100
|
],
|
|
80
101
|
RestClientURLPrefix: 'https://api.example.com'
|
|
81
102
|
});
|
|
103
|
+
|
|
104
|
+
console.log('Configured fable:', fable.settings.Product, 'v' + fable.settings.ProductVersion);
|
|
105
|
+
console.log('RestClientURLPrefix setting:', fable.settings.RestClientURLPrefix);
|
|
82
106
|
```
|
|
83
107
|
|
|
84
108
|
## Documentation
|
package/docs/_brand.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Hash": "fable",
|
|
3
|
+
"Name": "Fable",
|
|
4
|
+
"Tagline": "Service dependency injection, configuration, and logging library — the foundation of every Retold application",
|
|
5
|
+
"Palette": "mix",
|
|
6
|
+
"Icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-fable-filled-light\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#af2aef\"/>\n\t\t<g clip-path=\"url(#frame-fable-filled-light)\"><circle cx=\"48\" cy=\"48\" r=\"36\" fill=\"none\" stroke=\"#4ed5e8\" stroke-width=\"2\" opacity=\"0.45\"/>\n\t\t\t\t\t<circle cx=\"48\" cy=\"48\" r=\"22\" fill=\"rgba(255,255,255,0.18)\"/>\n\t\t\t\t\t<circle cx=\"13.69\" cy=\"58.91\" r=\"9\" fill=\"#4ed5e8\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"56\" font-weight=\"700\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">F</text>\n\t</svg>",
|
|
7
|
+
"IconType": "svg",
|
|
8
|
+
"Favicon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-fable-light\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#af2aef\"/>\n\t\t<g clip-path=\"url(#fav-fable-light)\"><circle cx=\"48\" cy=\"48\" r=\"28\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">F</text>\n\t</svg>",
|
|
9
|
+
"FaviconDark": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-fable-dark\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#ce84f2\"/>\n\t\t<g clip-path=\"url(#fav-fable-dark)\"><circle cx=\"48\" cy=\"48\" r=\"28\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">F</text>\n\t</svg>",
|
|
10
|
+
"Colors": {
|
|
11
|
+
"Primary": "#af2aef",
|
|
12
|
+
"Secondary": "#4ed5e8",
|
|
13
|
+
"PrimaryLight": "#af2aef",
|
|
14
|
+
"PrimaryDark": "#ce84f2",
|
|
15
|
+
"SecondaryLight": "#4ed5e8",
|
|
16
|
+
"SecondaryDark": "#a2e6ef"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Imports":
|
|
3
|
+
[
|
|
4
|
+
{ "Name": "fable", "Source": "bundled" },
|
|
5
|
+
{ "Name": "fable-uuid", "Source": "bundled" },
|
|
6
|
+
{ "Name": "fable-settings", "Source": "bundled" },
|
|
7
|
+
{ "Name": "fable-log", "Source": "bundled" },
|
|
8
|
+
{ "Name": "fable-serviceproviderbase","Source": "bundled" }
|
|
9
|
+
]
|
|
10
|
+
}
|
package/docs/_sidebar.md
CHANGED
package/docs/_version.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"Name": "fable",
|
|
3
|
-
"Version": "3.1.
|
|
3
|
+
"Version": "3.1.72",
|
|
4
4
|
"Description": "A service dependency injection, configuration and logging library.",
|
|
5
|
-
"GeneratedAt": "2026-
|
|
6
|
-
"GitCommit": "
|
|
5
|
+
"GeneratedAt": "2026-05-15T13:50:08.507Z",
|
|
6
|
+
"GitCommit": "3564579"
|
|
7
7
|
}
|
package/docs/architecture.md
CHANGED
|
@@ -24,15 +24,24 @@ Fable (Core ServiceManager)
|
|
|
24
24
|
Services depend on Fable rather than creating their own dependencies. Each service receives a reference to the Fable instance during construction, providing access to all other services and shared configuration.
|
|
25
25
|
|
|
26
26
|
```javascript
|
|
27
|
+
const libFable = require('fable');
|
|
28
|
+
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
29
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
30
|
+
|
|
27
31
|
class MyService extends libFableServiceBase {
|
|
28
32
|
constructor(pFable, pOptions, pServiceHash) {
|
|
29
33
|
super(pFable, pOptions, pServiceHash);
|
|
34
|
+
this.serviceType = 'MyService';
|
|
30
35
|
|
|
31
36
|
// Access other services through fable
|
|
32
|
-
this.log
|
|
37
|
+
this.log = this.fable.log;
|
|
33
38
|
this.settings = this.fable.settings;
|
|
34
39
|
}
|
|
35
40
|
}
|
|
41
|
+
|
|
42
|
+
fable.addAndInstantiateServiceType('MyService', MyService);
|
|
43
|
+
console.log('MyService wired up; log + settings accessible:',
|
|
44
|
+
typeof fable.MyService.log, typeof fable.MyService.settings);
|
|
36
45
|
```
|
|
37
46
|
|
|
38
47
|
### Lazy Instantiation
|
|
@@ -40,11 +49,25 @@ class MyService extends libFableServiceBase {
|
|
|
40
49
|
Services can be registered without being instantiated, allowing for on-demand creation when first needed:
|
|
41
50
|
|
|
42
51
|
```javascript
|
|
52
|
+
const libFable = require('fable');
|
|
53
|
+
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
54
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
55
|
+
|
|
56
|
+
class ExpensiveServiceClass extends libFableServiceBase {
|
|
57
|
+
constructor(pFable, pOptions, pServiceHash) {
|
|
58
|
+
super(pFable, pOptions, pServiceHash);
|
|
59
|
+
this.serviceType = 'ExpensiveService';
|
|
60
|
+
console.log('ExpensiveServiceClass instantiated — work happens here.');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
43
64
|
// Register without instantiating
|
|
44
65
|
fable.addServiceType('ExpensiveService', ExpensiveServiceClass);
|
|
66
|
+
console.log('Registered; no instance yet.');
|
|
45
67
|
|
|
46
68
|
// Later, when needed
|
|
47
69
|
const service = fable.instantiateServiceProvider('ExpensiveService');
|
|
70
|
+
console.log('Instantiated:', service.serviceType);
|
|
48
71
|
```
|
|
49
72
|
|
|
50
73
|
### Service Containers
|
|
@@ -52,13 +75,16 @@ const service = fable.instantiateServiceProvider('ExpensiveService');
|
|
|
52
75
|
Each service type maintains a map of instances, supporting multiple named instances of the same service type:
|
|
53
76
|
|
|
54
77
|
```javascript
|
|
78
|
+
const libFable = require('fable');
|
|
79
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
80
|
+
|
|
55
81
|
// Create multiple instances of the same service type
|
|
56
82
|
const clientA = fable.instantiateServiceProvider('RestClient', {}, 'api-client');
|
|
57
83
|
const clientB = fable.instantiateServiceProvider('RestClient', {}, 'auth-client');
|
|
58
84
|
|
|
59
85
|
// Access via services map
|
|
60
|
-
fable.servicesMap.RestClient['api-client'];
|
|
61
|
-
fable.servicesMap.RestClient['auth-client'];
|
|
86
|
+
console.log('api-client:', typeof fable.servicesMap.RestClient['api-client']);
|
|
87
|
+
console.log('auth-client:', typeof fable.servicesMap.RestClient['auth-client']);
|
|
62
88
|
```
|
|
63
89
|
|
|
64
90
|
### Default Service Pattern
|
|
@@ -66,12 +92,15 @@ fable.servicesMap.RestClient['auth-client'];
|
|
|
66
92
|
The first instance of each service type becomes the default accessor on the Fable object:
|
|
67
93
|
|
|
68
94
|
```javascript
|
|
95
|
+
const libFable = require('fable');
|
|
96
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
97
|
+
|
|
69
98
|
// First instantiation becomes default
|
|
70
99
|
fable.instantiateServiceProvider('RestClient', {}, 'primary');
|
|
71
100
|
|
|
72
101
|
// Now accessible directly
|
|
73
|
-
fable.RestClient; // The 'primary' instance
|
|
74
|
-
fable.services.RestClient; // Same as above
|
|
102
|
+
console.log('fable.RestClient:', typeof fable.RestClient); // The 'primary' instance
|
|
103
|
+
console.log('fable.services.RestClient:', typeof fable.services.RestClient); // Same as above
|
|
75
104
|
```
|
|
76
105
|
|
|
77
106
|
## Initialization Phases
|
|
@@ -83,11 +112,21 @@ Fable initializes in distinct phases to ensure proper dependency ordering:
|
|
|
83
112
|
The lowest level state and service infrastructure is established:
|
|
84
113
|
|
|
85
114
|
```javascript
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
this.
|
|
115
|
+
const libFable = require('fable');
|
|
116
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
117
|
+
|
|
118
|
+
// Inside Fable's constructor, Phase 0 sets up its own service-manager state:
|
|
119
|
+
// this.serviceType = 'ServiceManager';
|
|
120
|
+
// this.serviceTypes = []; // Array of registered service types
|
|
121
|
+
// this.servicesMap = {}; // Map of instantiated services by type and hash
|
|
122
|
+
// this.services = {}; // Map of default service instances
|
|
123
|
+
// this.serviceClasses = {}; // Map of service class constructors
|
|
124
|
+
//
|
|
125
|
+
// You can observe these on a constructed instance:
|
|
126
|
+
console.log('serviceType:', fable.serviceType);
|
|
127
|
+
console.log('serviceTypes count:', fable.serviceTypes.length);
|
|
128
|
+
console.log('servicesMap keys:', Object.keys(fable.servicesMap).slice(0, 5), '...');
|
|
129
|
+
console.log('services keys:', Object.keys(fable.services).slice(0, 5), '...');
|
|
91
130
|
```
|
|
92
131
|
|
|
93
132
|
### Phase 1: Core Utility Services
|
|
@@ -95,10 +134,19 @@ this.serviceClasses = {}; // Map of service class constructors
|
|
|
95
134
|
Fundamental services required for Fable to operate:
|
|
96
135
|
|
|
97
136
|
```javascript
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
137
|
+
const libFable = require('fable');
|
|
138
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
139
|
+
|
|
140
|
+
// Inside Fable's constructor, Phase 1 wires up the core utility services:
|
|
141
|
+
// this.SettingsManager = new libFableSettings(pSettings);
|
|
142
|
+
// this.UUID = new libFableUUID(this.SettingsManager.settings);
|
|
143
|
+
// this.Logging = new libFableLog(this.SettingsManager.settings);
|
|
144
|
+
// this.Logging.initialize();
|
|
145
|
+
//
|
|
146
|
+
// On the constructed instance these are all live:
|
|
147
|
+
console.log('SettingsManager:', typeof fable.SettingsManager);
|
|
148
|
+
console.log('UUID:', typeof fable.UUID);
|
|
149
|
+
console.log('Logging:', typeof fable.Logging);
|
|
102
150
|
```
|
|
103
151
|
|
|
104
152
|
### Phase 1.5: Self-Registration
|
|
@@ -106,8 +154,15 @@ this.Logging.initialize();
|
|
|
106
154
|
Fable registers itself as a service, enabling consistent service access patterns:
|
|
107
155
|
|
|
108
156
|
```javascript
|
|
109
|
-
|
|
110
|
-
|
|
157
|
+
const libFable = require('fable');
|
|
158
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
159
|
+
|
|
160
|
+
// Inside Fable's constructor, Phase 1.5 self-registers:
|
|
161
|
+
// this.ServiceManager = this;
|
|
162
|
+
// this.connectFable(this);
|
|
163
|
+
//
|
|
164
|
+
// On the constructed instance, fable.ServiceManager === fable:
|
|
165
|
+
console.log('fable.ServiceManager === fable:', fable.ServiceManager === fable);
|
|
111
166
|
```
|
|
112
167
|
|
|
113
168
|
### Phase 2: Default Built-in Services
|
|
@@ -115,16 +170,24 @@ this.connectFable(this);
|
|
|
115
170
|
All default services are registered and optionally instantiated:
|
|
116
171
|
|
|
117
172
|
```javascript
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
this.
|
|
126
|
-
|
|
127
|
-
//
|
|
173
|
+
const libFable = require('fable');
|
|
174
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
175
|
+
|
|
176
|
+
// Inside Fable's constructor, Phase 2 registers all built-in services:
|
|
177
|
+
// // Auto-instantiated (available immediately)
|
|
178
|
+
// this.addAndInstantiateServiceType('EnvironmentData', ...);
|
|
179
|
+
// this.addAndInstantiateServiceType('Dates', ...);
|
|
180
|
+
// this.addAndInstantiateServiceType('DataFormat', ...);
|
|
181
|
+
// ...
|
|
182
|
+
// // On-demand (registered but not instantiated)
|
|
183
|
+
// this.addServiceType('Template', ...);
|
|
184
|
+
// this.addServiceType('RestClient', ...);
|
|
185
|
+
// ...
|
|
186
|
+
//
|
|
187
|
+
// On the constructed instance, you can see both:
|
|
188
|
+
const autoInstantiated = Object.keys(fable.services).filter(k => fable[k]);
|
|
189
|
+
console.log('Auto-instantiated services:', autoInstantiated.join(', '));
|
|
190
|
+
console.log('Registered service types:', fable.serviceTypes.join(', '));
|
|
128
191
|
```
|
|
129
192
|
|
|
130
193
|
## Service Base Class
|
|
@@ -132,6 +195,10 @@ this.addServiceType('RestClient', ...);
|
|
|
132
195
|
All Fable services extend `CoreServiceProviderBase` from `fable-serviceproviderbase`:
|
|
133
196
|
|
|
134
197
|
```javascript
|
|
198
|
+
const libFable = require('fable');
|
|
199
|
+
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
200
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
201
|
+
|
|
135
202
|
class MyService extends libFableServiceBase {
|
|
136
203
|
constructor(pFable, pOptions, pServiceHash) {
|
|
137
204
|
super(pFable, pOptions, pServiceHash);
|
|
@@ -145,6 +212,14 @@ class MyService extends libFableServiceBase {
|
|
|
145
212
|
// - this.options (passed options)
|
|
146
213
|
// - this.Hash (unique service instance identifier)
|
|
147
214
|
}
|
|
215
|
+
|
|
216
|
+
fable.addAndInstantiateServiceType('MyService', MyService);
|
|
217
|
+
const svc = fable.MyService;
|
|
218
|
+
console.log('serviceType:', svc.serviceType);
|
|
219
|
+
console.log('fable ref:', typeof svc.fable);
|
|
220
|
+
console.log('log:', typeof svc.log);
|
|
221
|
+
console.log('options:', typeof svc.options);
|
|
222
|
+
console.log('Hash:', svc.Hash);
|
|
148
223
|
```
|
|
149
224
|
|
|
150
225
|
## Service Registration Methods
|
|
@@ -154,7 +229,16 @@ class MyService extends libFableServiceBase {
|
|
|
154
229
|
Registers a service class without instantiation:
|
|
155
230
|
|
|
156
231
|
```javascript
|
|
232
|
+
const libFable = require('fable');
|
|
233
|
+
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
234
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
235
|
+
|
|
236
|
+
class MyServiceClass extends libFableServiceBase {
|
|
237
|
+
constructor(pFable, pOptions, pServiceHash) { super(pFable, pOptions, pServiceHash); this.serviceType = 'MyService'; }
|
|
238
|
+
}
|
|
239
|
+
|
|
157
240
|
fable.addServiceType('MyService', MyServiceClass);
|
|
241
|
+
console.log('Registered:', fable.serviceTypes.includes('MyService'));
|
|
158
242
|
```
|
|
159
243
|
|
|
160
244
|
### `addAndInstantiateServiceType(pServiceType, pServiceClass)`
|
|
@@ -162,8 +246,17 @@ fable.addServiceType('MyService', MyServiceClass);
|
|
|
162
246
|
Registers and immediately creates a default instance:
|
|
163
247
|
|
|
164
248
|
```javascript
|
|
249
|
+
const libFable = require('fable');
|
|
250
|
+
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
251
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
252
|
+
|
|
253
|
+
class MyServiceClass extends libFableServiceBase {
|
|
254
|
+
constructor(pFable, pOptions, pServiceHash) { super(pFable, pOptions, pServiceHash); this.serviceType = 'MyService'; }
|
|
255
|
+
}
|
|
256
|
+
|
|
165
257
|
fable.addAndInstantiateServiceType('MyService', MyServiceClass);
|
|
166
258
|
// Creates instance with hash 'MyService-Default'
|
|
259
|
+
console.log('Default instance Hash:', fable.MyService.Hash);
|
|
167
260
|
```
|
|
168
261
|
|
|
169
262
|
### `instantiateServiceProvider(pServiceType, pOptions, pCustomServiceHash)`
|
|
@@ -171,10 +264,22 @@ fable.addAndInstantiateServiceType('MyService', MyServiceClass);
|
|
|
171
264
|
Creates a new instance of a registered service:
|
|
172
265
|
|
|
173
266
|
```javascript
|
|
267
|
+
const libFable = require('fable');
|
|
268
|
+
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
269
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
270
|
+
|
|
271
|
+
class MyServiceClass extends libFableServiceBase {
|
|
272
|
+
constructor(pFable, pOptions, pServiceHash) { super(pFable, pOptions, pServiceHash); this.serviceType = 'MyService'; }
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
fable.addServiceType('MyService', MyServiceClass);
|
|
276
|
+
|
|
174
277
|
const service = fable.instantiateServiceProvider('MyService',
|
|
175
278
|
{ option: 'value' },
|
|
176
279
|
'my-custom-hash'
|
|
177
280
|
);
|
|
281
|
+
console.log('Service Hash:', service.Hash);
|
|
282
|
+
console.log('Service options:', service.options);
|
|
178
283
|
```
|
|
179
284
|
|
|
180
285
|
### `instantiateServiceProviderFromPrototype(pServiceType, pOptions, pCustomServiceHash, pServicePrototype)`
|
|
@@ -182,14 +287,28 @@ const service = fable.instantiateServiceProvider('MyService',
|
|
|
182
287
|
Creates an instance using a custom class that may differ from the registered class:
|
|
183
288
|
|
|
184
289
|
```javascript
|
|
185
|
-
|
|
290
|
+
const libFable = require('fable');
|
|
291
|
+
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
292
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
293
|
+
|
|
294
|
+
class MyServiceClass extends libFableServiceBase {
|
|
295
|
+
constructor(pFable, pOptions, pServiceHash) { super(pFable, pOptions, pServiceHash); this.serviceType = 'MyService'; }
|
|
296
|
+
}
|
|
297
|
+
fable.addServiceType('MyService', MyServiceClass);
|
|
298
|
+
|
|
299
|
+
class CustomizedService extends MyServiceClass {
|
|
300
|
+
constructor(pFable, pOptions, pServiceHash) { super(pFable, pOptions, pServiceHash); this.flavor = 'custom'; }
|
|
301
|
+
}
|
|
186
302
|
|
|
303
|
+
const options = { mode: 'demo' };
|
|
187
304
|
const service = fable.instantiateServiceProviderFromPrototype(
|
|
188
305
|
'MyService',
|
|
189
306
|
options,
|
|
190
307
|
'customized',
|
|
191
308
|
CustomizedService
|
|
192
309
|
);
|
|
310
|
+
console.log('Custom flavor:', service.flavor);
|
|
311
|
+
console.log('Hash:', service.Hash);
|
|
193
312
|
```
|
|
194
313
|
|
|
195
314
|
## Service Access Patterns
|
|
@@ -199,9 +318,12 @@ const service = fable.instantiateServiceProviderFromPrototype(
|
|
|
199
318
|
Auto-instantiated services are available directly on the Fable instance:
|
|
200
319
|
|
|
201
320
|
```javascript
|
|
202
|
-
|
|
203
|
-
fable
|
|
204
|
-
|
|
321
|
+
const libFable = require('fable');
|
|
322
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
323
|
+
|
|
324
|
+
console.log(fable.Dates.dayJS().format('YYYY-MM-DD'));
|
|
325
|
+
console.log(fable.Math.addPrecise('1.5', '2.5'));
|
|
326
|
+
console.log(fable.DataFormat.formatterDollars(1234.56));
|
|
205
327
|
```
|
|
206
328
|
|
|
207
329
|
### Services Map Access
|
|
@@ -209,8 +331,11 @@ fable.DataFormat.formatterDollars(1234.56);
|
|
|
209
331
|
All instantiated services are accessible through the services map:
|
|
210
332
|
|
|
211
333
|
```javascript
|
|
212
|
-
fable
|
|
213
|
-
fable.
|
|
334
|
+
const libFable = require('fable');
|
|
335
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
336
|
+
|
|
337
|
+
console.log('fable.services.Dates:', typeof fable.services.Dates);
|
|
338
|
+
console.log("fable.servicesMap.Dates['Dates-Default']:", typeof fable.servicesMap.Dates['Dates-Default']);
|
|
214
339
|
```
|
|
215
340
|
|
|
216
341
|
### Factory Methods
|
|
@@ -218,11 +343,17 @@ fable.servicesMap.Dates['Dates-Default'];
|
|
|
218
343
|
Some services provide convenient factory methods:
|
|
219
344
|
|
|
220
345
|
```javascript
|
|
346
|
+
const libFable = require('fable');
|
|
347
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
348
|
+
|
|
221
349
|
// Create a new Anticipate instance without registration
|
|
222
350
|
const anticipate = fable.newAnticipate();
|
|
351
|
+
console.log('anticipate:', typeof anticipate);
|
|
223
352
|
|
|
224
353
|
// Create a new Manifest instance without registration
|
|
354
|
+
const definition = { Scope: 'Demo', Descriptors: { Foo: { Hash: 'foo', Type: 'String' } } };
|
|
225
355
|
const manifest = fable.newManyfest(definition);
|
|
356
|
+
console.log('manifest scope:', manifest.scope);
|
|
226
357
|
```
|
|
227
358
|
|
|
228
359
|
## Configuration Flow
|
|
@@ -240,8 +371,16 @@ User Config -> SettingsManager -> Fable.settings -> All Services
|
|
|
240
371
|
Services access configuration through:
|
|
241
372
|
|
|
242
373
|
```javascript
|
|
243
|
-
|
|
244
|
-
|
|
374
|
+
const libFable = require('fable');
|
|
375
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', SomeSetting: 'demo-value' });
|
|
376
|
+
|
|
377
|
+
// Inside a service, you access config via:
|
|
378
|
+
// this.fable.settings.SomeSetting
|
|
379
|
+
// this.fable.SettingsManager.settings
|
|
380
|
+
//
|
|
381
|
+
// At the top level, drop "this.":
|
|
382
|
+
console.log('settings.SomeSetting:', fable.settings.SomeSetting);
|
|
383
|
+
console.log('SettingsManager.settings type:', typeof fable.SettingsManager.settings);
|
|
245
384
|
```
|
|
246
385
|
|
|
247
386
|
## Logging Architecture
|
|
@@ -260,13 +399,22 @@ Log levels: `trace`, `debug`, `info`, `warn`, `error`, `fatal`
|
|
|
260
399
|
Custom log providers can be created by extending `LogProviderBase`:
|
|
261
400
|
|
|
262
401
|
```javascript
|
|
263
|
-
const
|
|
402
|
+
const libFable = require('fable');
|
|
403
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
404
|
+
|
|
405
|
+
const LogProviderBase = require('fable-log').LogProviderBase;
|
|
264
406
|
|
|
265
407
|
class CustomLogProvider extends LogProviderBase {
|
|
266
408
|
write(pLogEntry) {
|
|
267
409
|
// Custom logging implementation
|
|
410
|
+
console.log('CustomLogProvider received:', pLogEntry.msg);
|
|
268
411
|
}
|
|
269
412
|
}
|
|
413
|
+
|
|
414
|
+
const provider = new CustomLogProvider(fable.Logging, { level: 'trace' });
|
|
415
|
+
provider.initialize();
|
|
416
|
+
fable.Logging.addLogger(provider);
|
|
417
|
+
fable.log.info('Hello from custom provider demo');
|
|
270
418
|
```
|
|
271
419
|
|
|
272
420
|
## Browser Compatibility
|
|
@@ -274,15 +422,16 @@ class CustomLogProvider extends LogProviderBase {
|
|
|
274
422
|
Fable supports browser environments through service remapping:
|
|
275
423
|
|
|
276
424
|
```javascript
|
|
277
|
-
// package.json
|
|
278
|
-
{
|
|
425
|
+
// Shape of the browser remap declared in package.json:
|
|
426
|
+
const packageJSONBrowserField = {
|
|
279
427
|
"browser": {
|
|
280
428
|
"./source/service/Fable-Service-EnvironmentData.js":
|
|
281
429
|
"./source/service/Fable-Service-EnvironmentData-Web.js",
|
|
282
430
|
"./source/service/Fable-Service-FilePersistence.js":
|
|
283
431
|
"./source/service/Fable-Service-FilePersistence-Web.js"
|
|
284
432
|
}
|
|
285
|
-
}
|
|
433
|
+
};
|
|
434
|
+
console.log('Browser remap entries:', Object.keys(packageJSONBrowserField.browser).length);
|
|
286
435
|
```
|
|
287
436
|
|
|
288
437
|
The `dist/` folder contains browserified bundles for direct browser use.
|
|
@@ -292,7 +441,9 @@ The `dist/` folder contains browserified bundles for direct browser use.
|
|
|
292
441
|
### Creating Custom Services
|
|
293
442
|
|
|
294
443
|
```javascript
|
|
444
|
+
const libFable = require('fable');
|
|
295
445
|
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
446
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
296
447
|
|
|
297
448
|
class MyCustomService extends libFableServiceBase {
|
|
298
449
|
constructor(pFable, pOptions, pServiceHash) {
|
|
@@ -310,7 +461,7 @@ class MyCustomService extends libFableServiceBase {
|
|
|
310
461
|
fable.addAndInstantiateServiceType('MyCustomService', MyCustomService);
|
|
311
462
|
|
|
312
463
|
// Use it
|
|
313
|
-
fable.MyCustomService.myMethod();
|
|
464
|
+
console.log('myMethod() returns:', fable.MyCustomService.myMethod());
|
|
314
465
|
```
|
|
315
466
|
|
|
316
467
|
### Service Initialization Hook
|
|
@@ -318,9 +469,20 @@ fable.MyCustomService.myMethod();
|
|
|
318
469
|
For advanced scenarios, Fable supports an extra initialization callback:
|
|
319
470
|
|
|
320
471
|
```javascript
|
|
472
|
+
const libFable = require('fable');
|
|
473
|
+
const libFableServiceBase = require('fable-serviceproviderbase');
|
|
474
|
+
const fable = new libFable({ Product: 'ArchitectureDemo', ProductVersion: '1.0.0' });
|
|
475
|
+
|
|
321
476
|
fable.extraServiceInitialization = (pService) => {
|
|
322
477
|
// Perform additional setup on every service
|
|
323
478
|
pService.customProperty = 'value';
|
|
324
479
|
return pService;
|
|
325
480
|
};
|
|
481
|
+
|
|
482
|
+
// Subsequent service instantiations now pass through the hook:
|
|
483
|
+
class DemoService extends libFableServiceBase {
|
|
484
|
+
constructor(pFable, pOptions, pServiceHash) { super(pFable, pOptions, pServiceHash); this.serviceType = 'DemoService'; }
|
|
485
|
+
}
|
|
486
|
+
fable.addAndInstantiateServiceType('DemoService', DemoService);
|
|
487
|
+
console.log('DemoService.customProperty:', fable.DemoService.customProperty);
|
|
326
488
|
```
|
package/docs/index.html
CHANGED
|
@@ -4,12 +4,10 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
7
|
-
<meta name="description" content="Fable <small>3</small> v3.1.
|
|
7
|
+
<meta name="description" content="Fable <small>3</small> v3.1.72 Documentation — A service dependency injection, configuration and logging library.">
|
|
8
8
|
|
|
9
|
-
<title>Fable <small>3</small> v3.1.
|
|
9
|
+
<title>Fable <small>3</small> v3.1.72 Documentation</title>
|
|
10
10
|
|
|
11
|
-
<!-- Application Stylesheet -->
|
|
12
|
-
<link href="css/docuserve.css" rel="stylesheet">
|
|
13
11
|
<!-- KaTeX stylesheet for LaTeX equation rendering -->
|
|
14
12
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
|
|
15
13
|
<!-- PICT Dynamic View CSS Container -->
|
|
@@ -28,12 +26,13 @@
|
|
|
28
26
|
<!-- The root container for the Pict application -->
|
|
29
27
|
<div id="Docuserve-Application-Container"></div>
|
|
30
28
|
|
|
31
|
-
<!-- Mermaid diagram rendering
|
|
29
|
+
<!-- Mermaid diagram rendering. pict-section-content (v0.1.8+) drives
|
|
30
|
+
initialization with theme: 'base' + themeVariables sourced
|
|
31
|
+
from --theme-color-* so diagrams follow the active theme. -->
|
|
32
32
|
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
|
|
33
|
-
<script>mermaid.initialize({ startOnLoad: false, theme: 'default' });</script>
|
|
34
33
|
<!-- KaTeX for LaTeX equation rendering -->
|
|
35
34
|
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"></script>
|
|
36
35
|
<!-- Load the Docuserve PICT Application Bundle from jsDelivr CDN -->
|
|
37
|
-
<script src="https://cdn.jsdelivr.net/npm/pict-docuserve@
|
|
36
|
+
<script src="https://cdn.jsdelivr.net/npm/pict-docuserve@1/dist/pict-docuserve.min.js" type="text/javascript"></script>
|
|
38
37
|
</body>
|
|
39
38
|
</html>
|