fable 3.1.73 → 3.1.75

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.
@@ -161,6 +161,10 @@ Basic math operations with arbitrary precision:
161
161
  - [bezierpoint](./bezierpoint.md) - Evaluate point on cubic Bezier curve
162
162
  - [beziercurvefit](./beziercurvefit.md) - Fit cubic Bezier curve to data points
163
163
 
164
+ ### Identifier Generation
165
+
166
+ - [generateguid](./generateguid.md) - Generate a unique GUID string
167
+
164
168
  ### Other Utilities
165
169
 
166
170
  - [generatearrayofobjectsfromsets](./generatearrayofobjectsfromsets.md) - Generate objects from sets
@@ -0,0 +1,56 @@
1
+ # generateguid
2
+
3
+ Generates a GUID string.
4
+
5
+ ## Syntax
6
+
7
+ ```
8
+ generateguid()
9
+ ```
10
+
11
+ ## Parameters
12
+
13
+ None
14
+
15
+ ## Returns
16
+
17
+ String - A newly generated GUID, e.g. `'0x53c7c0bed0010000'`.
18
+
19
+ ## Description
20
+
21
+ The `generateguid` function returns a unique identifier by delegating to `fable.getUUID()`. The underlying [UUID service](../uuid.md) uses the Snowflake ID pattern, encoding a timestamp together with the configured DataCenter and Worker IDs so that distributed processes can mint IDs without coordination.
22
+
23
+ Each call produces a new identifier.
24
+
25
+ ## Examples
26
+
27
+ ### Basic Usage
28
+
29
+ ```expression
30
+ Result = GENERATEGUID()
31
+ // Result: "0x53c7c0bed0010000" (different each call)
32
+ ```
33
+
34
+ ### Tagging a Record
35
+
36
+ ```expression
37
+ // Stamp a synthetic record with a fresh ID
38
+ RecordID = GENERATEGUID()
39
+ ```
40
+
41
+ ## Use Cases
42
+
43
+ - **Synthetic IDs**: Assign identifiers to records produced inside an expression
44
+ - **Test data**: Generate unique keys for fixtures and mocks
45
+ - **Correlation IDs**: Mint a trace/correlation token to thread through downstream calls
46
+
47
+ ## Related Functions
48
+
49
+ - [randominteger](./randominteger.md) - Random integer (not guaranteed unique)
50
+
51
+ ## Notes
52
+
53
+ - Returns the result as a string
54
+ - Backed by `fable.getUUID()` / the Fable UUID service ([details](../uuid.md))
55
+ - Configure DataCenter and Worker IDs via the `UUID` settings block on the Fable instance to keep IDs distinct across processes
56
+ - Each call produces a different value
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fable",
3
- "version": "3.1.73",
3
+ "version": "3.1.75",
4
4
  "description": "A service dependency injection, configuration and logging library.",
5
5
  "main": "source/Fable.js",
6
6
  "scripts": {
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "homepage": "https://github.com/stevenvelozo/fable",
53
53
  "devDependencies": {
54
- "pict-docuserve": "^1.3.0",
54
+ "pict-docuserve": "^1.3.2",
55
55
  "quackage": "^1.2.3"
56
56
  },
57
57
  "dependencies": {
@@ -520,5 +520,10 @@
520
520
  "beziercurvefit": {
521
521
  "Name": "Fit a Cubic Bezier Curve to a Set of Data Points",
522
522
  "Address": "fable.Math.bezierCurveFit"
523
+ },
524
+
525
+ "generateguid": {
526
+ "Name": "Generate a GUID string",
527
+ "Address": "fable.getUUID"
523
528
  }
524
529
  }
@@ -129,7 +129,10 @@ class StringParser
129
129
  }
130
130
  else
131
131
  {
132
+ // Partial end-pattern match aborted -- roll Pattern back to the start node so
133
+ // subsequent characters scan for the end pattern from the beginning again.
132
134
  pParserState.EndPatternMatchBegan = false;
135
+ pParserState.Pattern = pParserState.PatternStartNode;
133
136
  this.appendOutputBuffer(pCharacter, pParserState);
134
137
  }
135
138
  }
@@ -303,7 +306,10 @@ class StringParser
303
306
  }
304
307
  else
305
308
  {
309
+ // Partial end-pattern match aborted -- roll Pattern back to the start node so
310
+ // subsequent characters scan for the end pattern from the beginning again.
306
311
  pParserState.EndPatternMatchBegan = false;
312
+ pParserState.Pattern = pParserState.PatternStartNode;
307
313
  this.appendOutputBuffer(pCharacter, pParserState);
308
314
  }
309
315
  }
@@ -331,6 +331,8 @@ suite
331
331
  let tmpResultPrecise = _Parser.solve('Result = (160 * PR * Z) / (C / 100) * PR * Z + (160 * (1 - C / 100))', { C: "-13", PR: "1.5", Z: "20.03" })
332
332
  Expect(tmpResultPrecise).to.equal("-1110837.0769230769230769230307");
333
333
 
334
+ Expect(_Parser.solve('Result = generateguid()').length).to.equal(36);
335
+
334
336
  return fDone();
335
337
  }
336
338
  );
@@ -392,6 +392,83 @@ suite
392
392
  }, null, { ScopeValue: 1 });
393
393
  }
394
394
  );
395
+
396
+ // Regression tests for the partial-end-pattern rollback fix:
397
+ // when the parser begins matching an end pattern but the next
398
+ // character breaks it, the parser must roll Pattern back to
399
+ // the start node so subsequent characters re-scan for the end
400
+ // pattern from the beginning. Without that rollback, content
401
+ // containing the end pattern's leading character followed
402
+ // later by its trailing character (e.g. `>` ... `}` for the
403
+ // `{<...>}` syntax) was misread as a closing delimiter.
404
+ test
405
+ (
406
+ 'End-pattern rollback: stray leading-char in content does not falsely close.',
407
+ (fDone) =>
408
+ {
409
+ let testMetaTemplate = loadMetaTemplateModule();
410
+ testMetaTemplate.addPattern('{<', '>}',
411
+ (pHash) => `[${pHash}]`);
412
+
413
+ // `> ... }` appears in the body but `>}` only appears at the very end.
414
+ // Before the fix, the partial end-match at the first `>` would
415
+ // leave Pattern at the `>`-node, and the later `}` would falsely
416
+ // close the block.
417
+ let tmpResult = testMetaTemplate.parseString('{<a > b > c }}}>}');
418
+ Expect(tmpResult).to.equal('[a > b > c }}}]');
419
+ fDone();
420
+ }
421
+ );
422
+ test
423
+ (
424
+ 'End-pattern rollback (async): stray leading-char in content does not falsely close.',
425
+ (fDone) =>
426
+ {
427
+ let testMetaTemplate = loadMetaTemplateModule();
428
+ testMetaTemplate.addPatternBoth('{<', '>}',
429
+ (pHash) => `[${pHash}]`,
430
+ (pHash, pData, fCallback) => fCallback(null, `[async:${pHash}]`));
431
+
432
+ testMetaTemplate.parseString('{<a > b > c }}}>}', {},
433
+ (pError, pValue) =>
434
+ {
435
+ Expect(pValue).to.equal('[async:a > b > c }}}]');
436
+ fDone();
437
+ });
438
+ }
439
+ );
440
+ test
441
+ (
442
+ 'End-pattern rollback: false-start of end pattern followed by literal end pattern.',
443
+ (fDone) =>
444
+ {
445
+ let testMetaTemplate = loadMetaTemplateModule();
446
+ testMetaTemplate.addPattern('{~', '~}',
447
+ (pHash) => `<${pHash}>`);
448
+
449
+ // `~` (end-leading char) followed by content and then a real `~}`.
450
+ let tmpResult = testMetaTemplate.parseString('{~Foo~Bar Baz~Qux~}');
451
+ Expect(tmpResult).to.equal('<Foo~Bar Baz~Qux>');
452
+ fDone();
453
+ }
454
+ );
455
+ test
456
+ (
457
+ 'End-pattern rollback: false-start in middle does not eat a trailing end-char.',
458
+ (fDone) =>
459
+ {
460
+ let testMetaTemplate = loadMetaTemplateModule();
461
+ testMetaTemplate.addPattern('{~', '~}',
462
+ (pHash) => `<${pHash}>`);
463
+
464
+ // `~xyz}` in the middle -- the `~` is the leading end char and `}`
465
+ // is the trailing end char, but they don't appear adjacent. Before
466
+ // the fix, the parser would close at the `}` after `xyz`.
467
+ let tmpResult = testMetaTemplate.parseString('{~before~xyz}after~}');
468
+ Expect(tmpResult).to.equal('<before~xyz}after>');
469
+ fDone();
470
+ }
471
+ );
395
472
  }
396
473
  );
397
474
  }
@@ -1,327 +0,0 @@
1
- /* ============================================================================
2
- Pict Docuserve - Base Styles & Theme Variables
3
- ============================================================================ */
4
-
5
- /* ----------------------------------------------------------------------------
6
- Theme variables — light defaults on :root.
7
- Dark mode applies when either:
8
- (a) the user explicitly selected dark via <html data-theme="dark">
9
- (b) the user hasn't chosen anything AND the system prefers dark
10
- An explicit <html data-theme="light"> pins the light palette regardless.
11
- ---------------------------------------------------------------------------- */
12
-
13
- :root
14
- {
15
- /* Surfaces */
16
- --docuserve-bg: #FDFBF7;
17
- --docuserve-bg-elevated: #FFFFFF;
18
- --docuserve-border: #DDD6CA;
19
- --docuserve-border-soft: #EAE3D8;
20
-
21
- /* Text */
22
- --docuserve-text: #2A241E;
23
- --docuserve-text-strong: #3D3229;
24
- --docuserve-text-muted: #5E5549;
25
- --docuserve-text-dim: #8A7F72;
26
-
27
- /* Accent / links */
28
- --docuserve-accent: #2E7D74;
29
- --docuserve-accent-hover: #236660;
30
-
31
- /* Top bar */
32
- --docuserve-topbar-bg: #3D3229;
33
- --docuserve-topbar-text: #E8E0D4;
34
- --docuserve-topbar-text-muted: #B5AA9A;
35
- --docuserve-topbar-text-dim: #8A7F72;
36
- --docuserve-topbar-hover-bg: #524438;
37
- --docuserve-topbar-version-bg: rgba(255, 255, 255, 0.06);
38
- --docuserve-topbar-version-border: rgba(255, 255, 255, 0.08);
39
- --docuserve-topbar-version-text: #B5AA9A;
40
-
41
- /* Sidebar */
42
- --docuserve-sidebar-bg: #FAF7F1;
43
- --docuserve-sidebar-border: #DDD6CA;
44
- --docuserve-sidebar-border-soft: #E5DED1;
45
- --docuserve-sidebar-text: #423D37;
46
- --docuserve-sidebar-group-title: #3D3229;
47
- --docuserve-sidebar-module-text: #5E5549;
48
- --docuserve-sidebar-hover-bg: #EAE3D8;
49
- --docuserve-sidebar-hover-text: #2E7D74;
50
- --docuserve-sidebar-active-bg: #E5DED1;
51
- --docuserve-sidebar-active-text: #2E7D74;
52
- --docuserve-sidebar-search-bg: #FFFFFF;
53
- --docuserve-sidebar-search-border: #DDD6CA;
54
-
55
- /* Inline code */
56
- --docuserve-inline-code-bg: #F0ECE4;
57
- --docuserve-inline-code-text: #9E3A50;
58
-
59
- /* Code block panel */
60
- --docuserve-code-bg: #F6F3EE;
61
- --docuserve-code-border: #E5DED1;
62
- --docuserve-code-gutter-bg: #EFEAE0;
63
- --docuserve-code-gutter-border: #DDD6CA;
64
- --docuserve-code-gutter-text: #A59986;
65
- --docuserve-code-text: #2A241E;
66
-
67
- /* Syntax tokens — low-chroma dark-on-light palette */
68
- --docuserve-tok-keyword: #A03472;
69
- --docuserve-tok-string: #1A6640;
70
- --docuserve-tok-number: #B25A00;
71
- --docuserve-tok-comment: #8A7F72;
72
- --docuserve-tok-operator: #2E7D74;
73
- --docuserve-tok-punctuation: #2A241E;
74
- --docuserve-tok-function: #2A5DB0;
75
- --docuserve-tok-property: #9E3A50;
76
- --docuserve-tok-tag: #9E3A50;
77
- --docuserve-tok-attr-name: #B25A00;
78
- --docuserve-tok-attr-value: #1A6640;
79
-
80
- /* Tables, blockquotes, mermaid */
81
- --docuserve-table-header-bg: #F5F0E8;
82
- --docuserve-table-row-alt-bg: #F9F6F0;
83
- --docuserve-blockquote-bg: #F7F5F0;
84
- --docuserve-blockquote-border: #2E7D74;
85
- --docuserve-blockquote-text: #5E5549;
86
- --docuserve-mermaid-bg: #FFFFFF;
87
-
88
- /* Scrollbars */
89
- --docuserve-scrollbar-track: #F5F0E8;
90
- --docuserve-scrollbar-thumb: #D4CCBE;
91
- --docuserve-scrollbar-thumb-hover: #B5AA9A;
92
- }
93
-
94
- @media (prefers-color-scheme: dark)
95
- {
96
- :root:not([data-theme="light"])
97
- {
98
- --docuserve-bg: #15120F;
99
- --docuserve-bg-elevated: #1B1814;
100
- --docuserve-border: #2F2823;
101
- --docuserve-border-soft: #26211C;
102
-
103
- --docuserve-text: #E8E0D4;
104
- --docuserve-text-strong: #F2ECE0;
105
- --docuserve-text-muted: #B5AA9A;
106
- --docuserve-text-dim: #7A6F62;
107
-
108
- --docuserve-accent: #5DB8A8;
109
- --docuserve-accent-hover: #7FCCB8;
110
-
111
- --docuserve-topbar-bg: #1A1612;
112
- --docuserve-topbar-text: #E8E0D4;
113
- --docuserve-topbar-text-muted: #B5AA9A;
114
- --docuserve-topbar-text-dim: #7A6F62;
115
- --docuserve-topbar-hover-bg: #2A241E;
116
- --docuserve-topbar-version-bg: rgba(255, 255, 255, 0.05);
117
- --docuserve-topbar-version-border: rgba(255, 255, 255, 0.09);
118
- --docuserve-topbar-version-text: #B5AA9A;
119
-
120
- --docuserve-sidebar-bg: #1B1814;
121
- --docuserve-sidebar-border: #2F2823;
122
- --docuserve-sidebar-border-soft: #26211C;
123
- --docuserve-sidebar-text: #C9C0B3;
124
- --docuserve-sidebar-group-title: #F2ECE0;
125
- --docuserve-sidebar-module-text: #B5AA9A;
126
- --docuserve-sidebar-hover-bg: #2A241E;
127
- --docuserve-sidebar-hover-text: #7FCCB8;
128
- --docuserve-sidebar-active-bg: #2F2823;
129
- --docuserve-sidebar-active-text: #7FCCB8;
130
- --docuserve-sidebar-search-bg: #26211C;
131
- --docuserve-sidebar-search-border: #2F2823;
132
-
133
- --docuserve-inline-code-bg: #2A241E;
134
- --docuserve-inline-code-text: #E8B07A;
135
-
136
- --docuserve-code-bg: #1E1A17;
137
- --docuserve-code-border: #2F2823;
138
- --docuserve-code-gutter-bg: #17130F;
139
- --docuserve-code-gutter-border: #2F2823;
140
- --docuserve-code-gutter-text: #6A6052;
141
- --docuserve-code-text: #E8E0D4;
142
-
143
- --docuserve-tok-keyword: #C678DD;
144
- --docuserve-tok-string: #98C379;
145
- --docuserve-tok-number: #D19A66;
146
- --docuserve-tok-comment: #7F848E;
147
- --docuserve-tok-operator: #56B6C2;
148
- --docuserve-tok-punctuation: #E8E0D4;
149
- --docuserve-tok-function: #61AFEF;
150
- --docuserve-tok-property: #E06C75;
151
- --docuserve-tok-tag: #E06C75;
152
- --docuserve-tok-attr-name: #D19A66;
153
- --docuserve-tok-attr-value: #98C379;
154
-
155
- --docuserve-table-header-bg: #26211C;
156
- --docuserve-table-row-alt-bg: #1F1B17;
157
- --docuserve-blockquote-bg: #1F1B17;
158
- --docuserve-blockquote-border: #5DB8A8;
159
- --docuserve-blockquote-text: #C9C0B3;
160
- --docuserve-mermaid-bg: #E8E0D4;
161
-
162
- --docuserve-scrollbar-track: #1B1814;
163
- --docuserve-scrollbar-thumb: #3A322B;
164
- --docuserve-scrollbar-thumb-hover: #524438;
165
- }
166
- }
167
-
168
- :root[data-theme="dark"]
169
- {
170
- --docuserve-bg: #15120F;
171
- --docuserve-bg-elevated: #1B1814;
172
- --docuserve-border: #2F2823;
173
- --docuserve-border-soft: #26211C;
174
-
175
- --docuserve-text: #E8E0D4;
176
- --docuserve-text-strong: #F2ECE0;
177
- --docuserve-text-muted: #B5AA9A;
178
- --docuserve-text-dim: #7A6F62;
179
-
180
- --docuserve-accent: #5DB8A8;
181
- --docuserve-accent-hover: #7FCCB8;
182
-
183
- --docuserve-topbar-bg: #1A1612;
184
- --docuserve-topbar-text: #E8E0D4;
185
- --docuserve-topbar-text-muted: #B5AA9A;
186
- --docuserve-topbar-text-dim: #7A6F62;
187
- --docuserve-topbar-hover-bg: #2A241E;
188
- --docuserve-topbar-version-bg: rgba(255, 255, 255, 0.05);
189
- --docuserve-topbar-version-border: rgba(255, 255, 255, 0.09);
190
- --docuserve-topbar-version-text: #B5AA9A;
191
-
192
- --docuserve-sidebar-bg: #1B1814;
193
- --docuserve-sidebar-border: #2F2823;
194
- --docuserve-sidebar-border-soft: #26211C;
195
- --docuserve-sidebar-text: #C9C0B3;
196
- --docuserve-sidebar-group-title: #F2ECE0;
197
- --docuserve-sidebar-module-text: #B5AA9A;
198
- --docuserve-sidebar-hover-bg: #2A241E;
199
- --docuserve-sidebar-hover-text: #7FCCB8;
200
- --docuserve-sidebar-active-bg: #2F2823;
201
- --docuserve-sidebar-active-text: #7FCCB8;
202
- --docuserve-sidebar-search-bg: #26211C;
203
- --docuserve-sidebar-search-border: #2F2823;
204
-
205
- --docuserve-inline-code-bg: #2A241E;
206
- --docuserve-inline-code-text: #E8B07A;
207
-
208
- --docuserve-code-bg: #1E1A17;
209
- --docuserve-code-border: #2F2823;
210
- --docuserve-code-gutter-bg: #17130F;
211
- --docuserve-code-gutter-border: #2F2823;
212
- --docuserve-code-gutter-text: #6A6052;
213
- --docuserve-code-text: #E8E0D4;
214
-
215
- --docuserve-tok-keyword: #C678DD;
216
- --docuserve-tok-string: #98C379;
217
- --docuserve-tok-number: #D19A66;
218
- --docuserve-tok-comment: #7F848E;
219
- --docuserve-tok-operator: #56B6C2;
220
- --docuserve-tok-punctuation: #E8E0D4;
221
- --docuserve-tok-function: #61AFEF;
222
- --docuserve-tok-property: #E06C75;
223
- --docuserve-tok-tag: #E06C75;
224
- --docuserve-tok-attr-name: #D19A66;
225
- --docuserve-tok-attr-value: #98C379;
226
-
227
- --docuserve-table-header-bg: #26211C;
228
- --docuserve-table-row-alt-bg: #1F1B17;
229
- --docuserve-blockquote-bg: #1F1B17;
230
- --docuserve-blockquote-border: #5DB8A8;
231
- --docuserve-blockquote-text: #C9C0B3;
232
- --docuserve-mermaid-bg: #E8E0D4;
233
-
234
- --docuserve-scrollbar-track: #1B1814;
235
- --docuserve-scrollbar-thumb: #3A322B;
236
- --docuserve-scrollbar-thumb-hover: #524438;
237
- }
238
-
239
- /* ----------------------------------------------------------------------------
240
- Reset and base
241
- ---------------------------------------------------------------------------- */
242
-
243
- *, *::before, *::after
244
- {
245
- box-sizing: border-box;
246
- }
247
-
248
- html, body
249
- {
250
- margin: 0;
251
- padding: 0;
252
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
253
- font-size: 16px;
254
- line-height: 1.5;
255
- color: var(--docuserve-text);
256
- background-color: var(--docuserve-bg);
257
- -webkit-font-smoothing: antialiased;
258
- -moz-osx-font-smoothing: grayscale;
259
- transition: background-color 0.15s ease, color 0.15s ease;
260
- }
261
-
262
- /* Typography */
263
- h1, h2, h3, h4, h5, h6
264
- {
265
- margin-top: 0;
266
- line-height: 1.3;
267
- color: var(--docuserve-text-strong);
268
- }
269
-
270
- a
271
- {
272
- color: var(--docuserve-accent);
273
- text-decoration: none;
274
- }
275
-
276
- a:hover
277
- {
278
- color: var(--docuserve-accent-hover);
279
- }
280
-
281
- /* Application container */
282
- #Docuserve-Application-Container
283
- {
284
- min-height: 100vh;
285
- }
286
-
287
- /* Utility: scrollbar styling */
288
- ::-webkit-scrollbar
289
- {
290
- width: 8px;
291
- height: 8px;
292
- }
293
-
294
- ::-webkit-scrollbar-track
295
- {
296
- background: var(--docuserve-scrollbar-track);
297
- }
298
-
299
- ::-webkit-scrollbar-thumb
300
- {
301
- background: var(--docuserve-scrollbar-thumb);
302
- border-radius: 4px;
303
- }
304
-
305
- ::-webkit-scrollbar-thumb:hover
306
- {
307
- background: var(--docuserve-scrollbar-thumb-hover);
308
- }
309
-
310
- /* Responsive adjustments */
311
- @media (max-width: 768px)
312
- {
313
- html
314
- {
315
- font-size: 14px;
316
- }
317
-
318
- #Docuserve-Sidebar-Container
319
- {
320
- display: none;
321
- }
322
-
323
- .docuserve-body
324
- {
325
- flex-direction: column;
326
- }
327
- }