fable 3.1.72 → 3.1.73

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.
Files changed (37) hide show
  1. package/docs/README.md +30 -6
  2. package/docs/_brand.json +18 -0
  3. package/docs/_playground.json +10 -0
  4. package/docs/_sidebar.md +2 -0
  5. package/docs/_version.json +3 -3
  6. package/docs/architecture.md +201 -39
  7. package/docs/index.html +6 -7
  8. package/docs/pict-docuserve.min.js +91 -0
  9. package/docs/pict-docuserve.min.js.map +1 -0
  10. package/docs/playground.md +38 -0
  11. package/docs/retold-catalog.json +1 -1
  12. package/docs/retold-keyword-index.json +8721 -8105
  13. package/docs/services/README.md +26 -9
  14. package/docs/services/anticipate.md +104 -40
  15. package/docs/services/csv-parser.md +63 -35
  16. package/docs/services/data-format.md +154 -49
  17. package/docs/services/data-generation.md +77 -16
  18. package/docs/services/dates.md +103 -36
  19. package/docs/services/environment-data.md +13 -2
  20. package/docs/services/expression-parser.md +280 -68
  21. package/docs/services/file-persistence.md +142 -150
  22. package/docs/services/logging.md +93 -37
  23. package/docs/services/logic.md +70 -22
  24. package/docs/services/manifest.md +114 -26
  25. package/docs/services/math.md +168 -63
  26. package/docs/services/meta-template.md +312 -158
  27. package/docs/services/object-cache.md +94 -11
  28. package/docs/services/operation.md +68 -6
  29. package/docs/services/progress-time.md +74 -13
  30. package/docs/services/progress-tracker-set.md +101 -3
  31. package/docs/services/rest-client.md +136 -104
  32. package/docs/services/settings-manager.md +133 -40
  33. package/docs/services/template.md +71 -22
  34. package/docs/services/utility.md +121 -29
  35. package/docs/services/uuid.md +58 -10
  36. package/package.json +2 -2
  37. package/.claude/settings.local.json +0 -8
@@ -45,23 +45,35 @@ These services are created when first requested:
45
45
  ### Accessing Services
46
46
 
47
47
  ```javascript
48
+ const libFable = require('fable');
49
+ const fable = new libFable({ Product: 'ServicesDemo', ProductVersion: '1.0.0' });
50
+
48
51
  // Auto-instantiated services are available directly
49
- fable.Dates.dayJS().format('YYYY-MM-DD');
50
- fable.Math.addPrecise('1', '2');
52
+ console.log('Today:', fable.Dates.dayJS().format('YYYY-MM-DD'));
53
+ console.log('1 + 2 =', fable.Math.addPrecise('1', '2'));
51
54
 
52
55
  // On-demand services need to be instantiated first
53
56
  const restClient = fable.instantiateServiceProvider('RestClient');
54
- restClient.getJSON('https://api.example.com/data', (err, res, data) => {
55
- console.log(data);
56
- });
57
+ console.log('restClient instantiated:', typeof restClient);
58
+
59
+ // In Node.js you would then call:
60
+ // restClient.getJSON('https://api.example.com/data', (err, res, data) => console.log(data));
61
+ // (Network calls are skipped here so the playground demo stays self-contained.)
57
62
  ```
58
63
 
59
64
  ### Creating Multiple Instances
60
65
 
61
66
  ```javascript
67
+ const libFable = require('fable');
68
+ const fable = new libFable({ Product: 'ServicesDemo', ProductVersion: '1.0.0' });
69
+
62
70
  // Create named instances for different purposes
63
- const apiClient = fable.instantiateServiceProvider('RestClient', {}, 'api');
71
+ const apiClient = fable.instantiateServiceProvider('RestClient', {}, 'api');
64
72
  const authClient = fable.instantiateServiceProvider('RestClient', {}, 'auth');
73
+ console.log('apiClient typeof:', typeof apiClient);
74
+ console.log('authClient typeof:', typeof authClient);
75
+ console.log('Both instances live in fable.servicesMap.RestClient — keys:',
76
+ Object.keys(fable.servicesMap.RestClient));
65
77
  ```
66
78
 
67
79
  ### Service Options
@@ -69,8 +81,13 @@ const authClient = fable.instantiateServiceProvider('RestClient', {}, 'auth');
69
81
  Most services accept an options object during instantiation:
70
82
 
71
83
  ```javascript
72
- const service = fable.instantiateServiceProvider('ServiceType', {
73
- option1: 'value1',
74
- option2: 'value2'
84
+ const libFable = require('fable');
85
+ const fable = new libFable({ Product: 'ServicesDemo', ProductVersion: '1.0.0' });
86
+
87
+ // Shape of the call — replace 'Template' with whichever service you want.
88
+ const service = fable.instantiateServiceProvider('Template', {
89
+ // option1: 'value1',
90
+ // option2: 'value2'
75
91
  }, 'optional-hash');
92
+ console.log('Service instantiated via the generic pattern:', typeof service);
76
93
  ```
@@ -5,11 +5,16 @@ The Anticipate service provides asynchronous operation sequencing, allowing you
5
5
  ## Access
6
6
 
7
7
  ```javascript
8
+ const libFable = require('fable');
9
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
10
+
8
11
  // On-demand service - instantiate when needed
9
- const tmpAnticipate = fable.instantiateServiceProvider('Anticipate');
12
+ const tmpAnticipateService = fable.instantiateServiceProvider('Anticipate');
13
+ console.log('Service instance:', typeof tmpAnticipateService);
10
14
 
11
15
  // Or use the factory method (creates unregistered instance)
12
- const tmpAnticipate = fable.newAnticipate();
16
+ const tmpAnticipateFactory = fable.newAnticipate();
17
+ console.log('Factory instance:', typeof tmpAnticipateFactory);
13
18
  ```
14
19
 
15
20
  ## Basic Usage
@@ -17,6 +22,9 @@ const tmpAnticipate = fable.newAnticipate();
17
22
  ### Sequential Operations
18
23
 
19
24
  ```javascript
25
+ const libFable = require('fable');
26
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
27
+
20
28
  const tmpAnticipate = fable.newAnticipate();
21
29
 
22
30
  tmpAnticipate.anticipate(function (fCallback)
@@ -60,6 +68,14 @@ tmpAnticipate.wait(function (pError)
60
68
  Since Anticipate callbacks receive only `fCallback`, use closure scope or external variables to share data between steps:
61
69
 
62
70
  ```javascript
71
+ const libFable = require('fable');
72
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
73
+
74
+ // Stubbed async helpers for the playground demo
75
+ function fetchUser(pId, fCallback) { setTimeout(() => fCallback({ id: pId, name: 'User#' + pId }), 5); }
76
+ function loadPreferences(pId, fCallback) { setTimeout(() => fCallback({ theme: 'dark' }), 5); }
77
+ function render(pUser, pPrefs) { console.log('rendered:', pUser, pPrefs); }
78
+
63
79
  const tmpAnticipate = fable.newAnticipate();
64
80
  let tmpUser = null;
65
81
  let tmpPreferences = null;
@@ -91,6 +107,10 @@ tmpAnticipate.wait(function (pError)
91
107
  {
92
108
  console.error('Workflow failed:', pError);
93
109
  }
110
+ else
111
+ {
112
+ console.log('Workflow done.');
113
+ }
94
114
  });
95
115
  ```
96
116
 
@@ -101,11 +121,17 @@ tmpAnticipate.wait(function (pError)
101
121
  Add an asynchronous operation to the queue. Operations run sequentially by default (one at a time).
102
122
 
103
123
  ```javascript
124
+ const libFable = require('fable');
125
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
126
+ const tmpAnticipate = fable.newAnticipate();
127
+
104
128
  tmpAnticipate.anticipate(function (fCallback)
105
129
  {
106
130
  // Do async work
131
+ console.log('async work running');
107
132
  fCallback(); // Call when done, or fCallback(pError) to signal failure
108
133
  });
134
+ tmpAnticipate.wait(function (pError) { console.log('wait done, pError:', pError); });
109
135
  ```
110
136
 
111
137
  The step function receives one parameter:
@@ -116,12 +142,21 @@ The step function receives one parameter:
116
142
  Register a callback to run when all queued operations complete (or when an error occurs):
117
143
 
118
144
  ```javascript
145
+ const libFable = require('fable');
146
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
147
+ const tmpAnticipate = fable.newAnticipate();
148
+
149
+ tmpAnticipate.anticipate(function (fCallback) { console.log('step done'); fCallback(); });
119
150
  tmpAnticipate.wait(function (pError)
120
151
  {
121
152
  if (pError)
122
153
  {
123
154
  console.error('Error:', pError);
124
155
  }
156
+ else
157
+ {
158
+ console.log('All operations completed');
159
+ }
125
160
  });
126
161
  ```
127
162
 
@@ -130,8 +165,12 @@ tmpAnticipate.wait(function (pError)
130
165
  Control concurrency. Default is `1` (sequential). Set higher for parallel execution:
131
166
 
132
167
  ```javascript
168
+ const libFable = require('fable');
169
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
170
+
133
171
  const tmpAnticipate = fable.newAnticipate();
134
172
  tmpAnticipate.maxOperations = 5; // Run up to 5 operations concurrently
173
+ console.log('maxOperations:', tmpAnticipate.maxOperations);
135
174
  ```
136
175
 
137
176
  ## Error Handling
@@ -141,6 +180,9 @@ tmpAnticipate.maxOperations = 5; // Run up to 5 operations concurrently
141
180
  When an operation passes an error to its callback, remaining queued operations are skipped and the `wait` callback fires immediately with the error:
142
181
 
143
182
  ```javascript
183
+ const libFable = require('fable');
184
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
185
+
144
186
  const tmpAnticipate = fable.newAnticipate();
145
187
  let tmpPostErrorRan = false;
146
188
 
@@ -162,8 +204,8 @@ tmpAnticipate.anticipate(function (fCallback)
162
204
  });
163
205
  tmpAnticipate.wait(function (pError)
164
206
  {
165
- console.log('Error:', pError); // Error: Something went wrong
166
- console.log('Step 3 ran:', tmpPostErrorRan); // false
207
+ console.log('Caught error:', pError && pError.message); // Something went wrong
208
+ console.log('Step 3 ran:', tmpPostErrorRan); // false
167
209
  });
168
210
  ```
169
211
 
@@ -172,6 +214,11 @@ tmpAnticipate.wait(function (pError)
172
214
  To handle errors without bailing out, catch them inside the step and continue:
173
215
 
174
216
  ```javascript
217
+ const libFable = require('fable');
218
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
219
+
220
+ function riskyOperation() { throw new Error('demo failure'); }
221
+
175
222
  const tmpAnticipate = fable.newAnticipate();
176
223
  let tmpRecoveredError = null;
177
224
 
@@ -192,13 +239,13 @@ tmpAnticipate.anticipate(function (fCallback)
192
239
  {
193
240
  if (tmpRecoveredError)
194
241
  {
195
- console.log('Recovered from:', tmpRecoveredError);
242
+ console.log('Recovered from:', tmpRecoveredError.message);
196
243
  }
197
244
  fCallback();
198
245
  });
199
246
  tmpAnticipate.wait(function (pError)
200
247
  {
201
- console.log('Pipeline completed');
248
+ console.log('Pipeline completed, pError:', pError);
202
249
  });
203
250
  ```
204
251
 
@@ -207,6 +254,12 @@ tmpAnticipate.wait(function (pError)
207
254
  ### Database Migrations
208
255
 
209
256
  ```javascript
257
+ const libFable = require('fable');
258
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
259
+
260
+ // Stub DB driver for the playground demo
261
+ const db = { query: (sql, cb) => { console.log('SQL:', sql); cb(null); } };
262
+
210
263
  const tmpMigrate = fable.newAnticipate();
211
264
 
212
265
  tmpMigrate.anticipate(function (fCallback)
@@ -231,6 +284,17 @@ tmpMigrate.wait(function (pError)
231
284
  ### API Request Chains
232
285
 
233
286
  ```javascript
287
+ const libFable = require('fable');
288
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
289
+
290
+ // Stub API + credentials + process for the playground demo
291
+ const credentials = { user: 'demo', pass: 'demo' };
292
+ const api = {
293
+ login: (creds, cb) => setTimeout(() => cb('tok-' + Math.floor(Math.random() * 1000)), 5),
294
+ getData: (tok, cb) => setTimeout(() => cb({ rows: 3, tok }), 5)
295
+ };
296
+ function processData(pData) { console.log('processed data:', pData); }
297
+
234
298
  const tmpWorkflow = fable.newAnticipate();
235
299
  let tmpToken = null;
236
300
  let tmpData = null;
@@ -253,33 +317,33 @@ tmpWorkflow.anticipate(function (fCallback)
253
317
  });
254
318
  tmpWorkflow.anticipate(function (fCallback)
255
319
  {
256
- process(tmpData);
320
+ processData(tmpData);
257
321
  fCallback();
258
322
  });
259
323
  tmpWorkflow.wait(function (pError)
260
324
  {
261
325
  if (pError) console.error('Workflow failed:', pError);
326
+ else console.log('Workflow OK; token:', tmpToken);
262
327
  });
263
328
  ```
264
329
 
265
330
  ### Parallel Operations
266
331
 
267
332
  ```javascript
333
+ const libFable = require('fable');
334
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
335
+
336
+ // Stub fetchers for the playground demo
337
+ function fetchFromServiceA(cb) { setTimeout(() => { console.log('A done'); cb(); }, 5); }
338
+ function fetchFromServiceB(cb) { setTimeout(() => { console.log('B done'); cb(); }, 5); }
339
+ function fetchFromServiceC(cb) { setTimeout(() => { console.log('C done'); cb(); }, 5); }
340
+
268
341
  const tmpParallel = fable.newAnticipate();
269
342
  tmpParallel.maxOperations = 3; // Run up to 3 at a time
270
343
 
271
- tmpParallel.anticipate(function (fCallback)
272
- {
273
- fetchFromServiceA(function () { fCallback(); });
274
- });
275
- tmpParallel.anticipate(function (fCallback)
276
- {
277
- fetchFromServiceB(function () { fCallback(); });
278
- });
279
- tmpParallel.anticipate(function (fCallback)
280
- {
281
- fetchFromServiceC(function () { fCallback(); });
282
- });
344
+ tmpParallel.anticipate(function (fCallback) { fetchFromServiceA(function () { fCallback(); }); });
345
+ tmpParallel.anticipate(function (fCallback) { fetchFromServiceB(function () { fCallback(); }); });
346
+ tmpParallel.anticipate(function (fCallback) { fetchFromServiceC(function () { fCallback(); }); });
283
347
  tmpParallel.wait(function (pError)
284
348
  {
285
349
  console.log('All fetches complete');
@@ -289,24 +353,21 @@ tmpParallel.wait(function (pError)
289
353
  ### Build Pipeline
290
354
 
291
355
  ```javascript
356
+ const libFable = require('fable');
357
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
358
+
359
+ // Stub build steps for the playground demo
360
+ function cleanBuildDir(cb) { console.log('clean'); cb(); }
361
+ function compile(cb) { console.log('compile'); cb(); }
362
+ function bundle(cb) { console.log('bundle'); cb(); }
363
+ function minify(cb) { console.log('minify'); cb(); }
364
+
292
365
  const tmpBuild = fable.newAnticipate();
293
366
 
294
- tmpBuild.anticipate(function (fCallback)
295
- {
296
- cleanBuildDir(fCallback);
297
- });
298
- tmpBuild.anticipate(function (fCallback)
299
- {
300
- compile(fCallback);
301
- });
302
- tmpBuild.anticipate(function (fCallback)
303
- {
304
- bundle(fCallback);
305
- });
306
- tmpBuild.anticipate(function (fCallback)
307
- {
308
- minify(fCallback);
309
- });
367
+ tmpBuild.anticipate(function (fCallback) { cleanBuildDir(fCallback); });
368
+ tmpBuild.anticipate(function (fCallback) { compile(fCallback); });
369
+ tmpBuild.anticipate(function (fCallback) { bundle(fCallback); });
370
+ tmpBuild.anticipate(function (fCallback) { minify(fCallback); });
310
371
  tmpBuild.wait(function (pError)
311
372
  {
312
373
  if (pError) throw pError;
@@ -319,13 +380,16 @@ tmpBuild.wait(function (pError)
319
380
  Create multiple independent workflows:
320
381
 
321
382
  ```javascript
322
- const tmpUserWorkflow = fable.newAnticipate();
383
+ const libFable = require('fable');
384
+ const fable = new libFable({ Product: 'AnticipateDemo', ProductVersion: '1.0.0' });
385
+
386
+ const tmpUserWorkflow = fable.newAnticipate();
323
387
  const tmpOrderWorkflow = fable.newAnticipate();
324
388
 
325
389
  // These run independently
326
- tmpUserWorkflow.anticipate(function (fCallback) { /* ... */ fCallback(); });
327
- tmpUserWorkflow.wait(function (pError) { /* ... */ });
390
+ tmpUserWorkflow.anticipate(function (fCallback) { console.log('user step'); fCallback(); });
391
+ tmpUserWorkflow.wait(function (pError) { console.log('user workflow done'); });
328
392
 
329
- tmpOrderWorkflow.anticipate(function (fCallback) { /* ... */ fCallback(); });
330
- tmpOrderWorkflow.wait(function (pError) { /* ... */ });
393
+ tmpOrderWorkflow.anticipate(function (fCallback) { console.log('order step'); fCallback(); });
394
+ tmpOrderWorkflow.wait(function (pError) { console.log('order workflow done'); });
331
395
  ```
@@ -5,8 +5,12 @@ The CSVParser service provides line-by-line CSV parsing with support for multi-l
5
5
  ## Access
6
6
 
7
7
  ```javascript
8
+ const libFable = require('fable');
9
+ const fable = new libFable({ Product: 'CSVDemo', ProductVersion: '1.0.0' });
10
+
8
11
  // On-demand service - instantiate when needed
9
12
  const csvParser = fable.instantiateServiceProvider('CSVParser', {}, 'CSV Parser-123');
13
+ console.log('csvParser:', typeof csvParser);
10
14
  ```
11
15
 
12
16
  ## Basic Usage
@@ -16,28 +20,32 @@ const csvParser = fable.instantiateServiceProvider('CSVParser', {}, 'CSV Parser-
16
20
  The primary method is `parseCSVLine()`, which processes one line at a time and returns a parsed record (or `false` if the line is part of a multi-line quoted field or is the header row):
17
21
 
18
22
  ```javascript
19
- const libFS = require('fs');
20
- const libReadline = require('readline');
21
-
23
+ const libFable = require('fable');
24
+ const fable = new libFable({ Product: 'CSVDemo', ProductVersion: '1.0.0' });
22
25
  const csvParser = fable.instantiateServiceProvider('CSVParser');
23
- const records = [];
24
26
 
25
- const rl = libReadline.createInterface({
26
- input: libFS.createReadStream('data.csv'),
27
- crlfDelay: Infinity
28
- });
29
-
30
- rl.on('line', (line) => {
31
- let record = csvParser.parseCSVLine(line);
32
- if (record) {
27
+ // In Node.js the typical streaming pattern is:
28
+ // const libFS = require('fs');
29
+ // const libReadline = require('readline');
30
+ // const rl = libReadline.createInterface({ input: libFS.createReadStream('data.csv'), crlfDelay: Infinity });
31
+ // rl.on('line', line => { const rec = csvParser.parseCSVLine(line); if (rec) records.push(rec); });
32
+ // rl.on('close', () => console.log(`Parsed ${records.length} records`));
33
+ //
34
+ // The browser playground has no fs/readline, so the snippet below parses an
35
+ // in-memory CSV string line-by-line using the exact same parseCSVLine() loop:
36
+
37
+ const csvSource = "name,age,city\nJohn,30,New York\nJane,25,Boston";
38
+ const records = [];
39
+ for (const line of csvSource.split('\n'))
40
+ {
41
+ const record = csvParser.parseCSVLine(line);
42
+ if (record)
43
+ {
33
44
  records.push(record);
34
45
  }
35
- });
36
-
37
- rl.on('close', () => {
38
- console.log(`Parsed ${records.length} records`);
39
- // records[0] is an object like { name: 'John', age: '30', city: 'New York' }
40
- });
46
+ }
47
+ console.log(`Parsed ${records.length} records`);
48
+ console.log('records[0]:', records[0]);
41
49
  ```
42
50
 
43
51
  ### Using FilePersistence Wrapper
@@ -45,17 +53,13 @@ rl.on('close', () => {
45
53
  The FilePersistence service provides a convenience method for CSV reading:
46
54
 
47
55
  ```javascript
48
- fable.instantiateServiceProvider('FilePersistence');
49
-
50
- fable.FilePersistence.readFileCSV('data.csv', {},
51
- (record) => {
52
- // Called for each parsed record (as a JSON object)
53
- console.log(record.name, record.age);
54
- },
55
- () => {
56
- // Called when parsing is complete
57
- console.log('Done!');
58
- });
56
+ // Node.js reference — fable.FilePersistence.readFileCSV uses fs, which the
57
+ // browser playground doesn't expose. The shape of the call:
58
+ console.info("In Node.js:");
59
+ console.info(" fable.instantiateServiceProvider('FilePersistence');");
60
+ console.info(" fable.FilePersistence.readFileCSV('data.csv', {},");
61
+ console.info(" (record) => console.log(record.name, record.age),");
62
+ console.info(" () => console.log('Done!'));");
59
63
  ```
60
64
 
61
65
  ## How Parsing Works
@@ -77,6 +81,9 @@ The CSVParser is stateful and processes lines sequentially:
77
81
  Set these properties on the parser instance after creation:
78
82
 
79
83
  ```javascript
84
+ const libFable = require('fable');
85
+ const fable = new libFable({ Product: 'CSVDemo', ProductVersion: '1.0.0' });
86
+
80
87
  const csvParser = fable.instantiateServiceProvider('CSVParser');
81
88
 
82
89
  csvParser.Delimiter = ';'; // Default: ','
@@ -86,6 +93,11 @@ csvParser.HeaderLineIndex = 0; // Default: 0 - which line is the header
86
93
  csvParser.EmitJSON = true; // Default: true - emit objects vs arrays
87
94
  csvParser.EmitHeader = false; // Default: false - return header row or skip it
88
95
  csvParser.EscapedQuoteString = '"'; // Default: '"' - replacement for escaped quotes
96
+
97
+ console.log('Delimiter:', csvParser.Delimiter);
98
+ console.log('QuoteCharacter:', csvParser.QuoteCharacter);
99
+ console.log('HasHeader:', csvParser.HasHeader);
100
+ console.log('EmitJSON:', csvParser.EmitJSON);
89
101
  ```
90
102
 
91
103
  ## Methods
@@ -99,7 +111,12 @@ Parse a single line of CSV. Returns a record object, an array, or `false`.
99
111
  Manually set column headers (an array of strings):
100
112
 
101
113
  ```javascript
114
+ const libFable = require('fable');
115
+ const fable = new libFable({ Product: 'CSVDemo', ProductVersion: '1.0.0' });
116
+ const csvParser = fable.instantiateServiceProvider('CSVParser');
117
+
102
118
  csvParser.setHeader(['name', 'age', 'city']);
119
+ console.log('Header set; field names:', csvParser.HeaderFieldNames);
103
120
  ```
104
121
 
105
122
  ### `marshalRowToJSON(rowArray)`
@@ -107,8 +124,12 @@ csvParser.setHeader(['name', 'age', 'city']);
107
124
  Convert a row array into a JSON object using the current headers:
108
125
 
109
126
  ```javascript
127
+ const libFable = require('fable');
128
+ const fable = new libFable({ Product: 'CSVDemo', ProductVersion: '1.0.0' });
129
+ const csvParser = fable.instantiateServiceProvider('CSVParser');
130
+
110
131
  csvParser.setHeader(['name', 'age']);
111
- csvParser.marshalRowToJSON(['John', '30']);
132
+ console.log(csvParser.marshalRowToJSON(['John', '30']));
112
133
  // Returns { name: 'John', age: '30' }
113
134
  ```
114
135
 
@@ -123,11 +144,18 @@ Emit the currently accumulated row. If `formatAsJSON` is true (default), returns
123
144
  ## Parser State Properties
124
145
 
125
146
  ```javascript
126
- csvParser.LinesParsed // Total number of lines processed
127
- csvParser.RowsEmitted // Total number of data rows emitted
128
- csvParser.InQuote // Whether currently inside a quoted field
129
- csvParser.Header // Current header array
130
- csvParser.HeaderFieldNames // Trimmed header field names used as object keys
147
+ const libFable = require('fable');
148
+ const fable = new libFable({ Product: 'CSVDemo', ProductVersion: '1.0.0' });
149
+ const csvParser = fable.instantiateServiceProvider('CSVParser');
150
+
151
+ // Parse a small CSV inline so the state properties have something to show:
152
+ for (const line of "name,age\nJohn,30".split('\n')) csvParser.parseCSVLine(line);
153
+
154
+ console.log('LinesParsed:', csvParser.LinesParsed);
155
+ console.log('RowsEmitted:', csvParser.RowsEmitted);
156
+ console.log('InQuote:', csvParser.InQuote);
157
+ console.log('Header:', csvParser.Header);
158
+ console.log('HeaderFieldNames:', csvParser.HeaderFieldNames);
131
159
  ```
132
160
 
133
161
  ## Handling Special Cases