retold 4.0.4 → 4.0.7

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 (92) hide show
  1. package/.claude/launch.json +29 -0
  2. package/.claude/settings.local.json +60 -2
  3. package/CLAUDE.md +4 -2
  4. package/README.md +4 -2
  5. package/Retold-Modules-Manifest.json +576 -0
  6. package/docs/README.md +7 -1
  7. package/docs/{cover.md → _cover.md} +1 -1
  8. package/docs/_sidebar.md +30 -3
  9. package/docs/architecture/architecture.md +5 -2
  10. package/docs/architecture/dependencies/_generate-graph.js +186 -0
  11. package/docs/architecture/dependencies/_generate-svg.js +364 -0
  12. package/docs/architecture/dependencies/in-ecosystem-dependency-graph-generation.md +97 -0
  13. package/docs/architecture/dependencies/in-ecosystem-dependency-graph.json +3168 -0
  14. package/docs/architecture/dependencies/in-ecosystem-dependency-graph.md +221 -0
  15. package/docs/architecture/dependencies/in-ecosystem-dependency-graph.svg +664 -0
  16. package/docs/architecture/documentation-style-guide.md +65 -0
  17. package/docs/architecture/example-app-style-guide.md +154 -0
  18. package/docs/architecture/modules.md +17 -5
  19. package/docs/architecture/templating/data-access.md +196 -0
  20. package/docs/architecture/templating/data-formatting.md +350 -0
  21. package/docs/architecture/templating/data-generation.md +72 -0
  22. package/docs/architecture/templating/debugging.md +181 -0
  23. package/docs/architecture/templating/entity.md +99 -0
  24. package/docs/architecture/templating/iteration.md +170 -0
  25. package/docs/architecture/templating/jellyfish-deep-dive.md +271 -0
  26. package/docs/architecture/templating/jellyfish-templates.md +476 -0
  27. package/docs/architecture/templating/logic.md +185 -0
  28. package/docs/architecture/templating/ref-breakpoint.md +38 -0
  29. package/docs/architecture/templating/ref-data.md +51 -0
  30. package/docs/architecture/templating/ref-dateonlyformat.md +43 -0
  31. package/docs/architecture/templating/ref-dateonlyymd.md +39 -0
  32. package/docs/architecture/templating/ref-datetimeformat.md +59 -0
  33. package/docs/architecture/templating/ref-datetimeymd.md +44 -0
  34. package/docs/architecture/templating/ref-dejs.md +42 -0
  35. package/docs/architecture/templating/ref-digits.md +36 -0
  36. package/docs/architecture/templating/ref-dj.md +50 -0
  37. package/docs/architecture/templating/ref-dollars.md +36 -0
  38. package/docs/architecture/templating/ref-dt.md +38 -0
  39. package/docs/architecture/templating/ref-dvbk.md +46 -0
  40. package/docs/architecture/templating/ref-dwaf.md +45 -0
  41. package/docs/architecture/templating/ref-dwtf.md +45 -0
  42. package/docs/architecture/templating/ref-entity.md +47 -0
  43. package/docs/architecture/templating/ref-hce.md +29 -0
  44. package/docs/architecture/templating/ref-hcs.md +38 -0
  45. package/docs/architecture/templating/ref-join.md +45 -0
  46. package/docs/architecture/templating/ref-joinunique.md +34 -0
  47. package/docs/architecture/templating/ref-ls.md +37 -0
  48. package/docs/architecture/templating/ref-lv.md +38 -0
  49. package/docs/architecture/templating/ref-lvt.md +33 -0
  50. package/docs/architecture/templating/ref-ne.md +40 -0
  51. package/docs/architecture/templating/ref-pascalcaseidentifier.md +41 -0
  52. package/docs/architecture/templating/ref-pict.md +42 -0
  53. package/docs/architecture/templating/ref-pluckjoinunique.md +39 -0
  54. package/docs/architecture/templating/ref-rn.md +35 -0
  55. package/docs/architecture/templating/ref-rns.md +35 -0
  56. package/docs/architecture/templating/ref-sbr.md +36 -0
  57. package/docs/architecture/templating/ref-solve.md +46 -0
  58. package/docs/architecture/templating/ref-tbda.md +41 -0
  59. package/docs/architecture/templating/ref-tbr.md +43 -0
  60. package/docs/architecture/templating/ref-tbt.md +46 -0
  61. package/docs/architecture/templating/ref-template.md +40 -0
  62. package/docs/architecture/templating/ref-tfa.md +32 -0
  63. package/docs/architecture/templating/ref-tfm.md +43 -0
  64. package/docs/architecture/templating/ref-tif.md +45 -0
  65. package/docs/architecture/templating/ref-tifabs.md +41 -0
  66. package/docs/architecture/templating/ref-ts.md +41 -0
  67. package/docs/architecture/templating/ref-tsfm.md +42 -0
  68. package/docs/architecture/templating/ref-tswp.md +45 -0
  69. package/docs/architecture/templating/ref-tvs.md +48 -0
  70. package/docs/architecture/templating/ref-view.md +40 -0
  71. package/docs/architecture/templating/ref-vrs.md +39 -0
  72. package/docs/architecture/templating/solvers.md +153 -0
  73. package/docs/architecture/templating/template-composition.md +196 -0
  74. package/docs/architecture/templating/template-expressions.md +217 -0
  75. package/docs/architecture/templating/views.md +154 -0
  76. package/docs/examples/todolist/todo-list.md +1 -1
  77. package/docs/modules/apps.md +26 -0
  78. package/docs/modules/pict.md +18 -0
  79. package/docs/modules/utility.md +23 -1
  80. package/docs/retold-catalog.json +829 -102
  81. package/docs/retold-keyword-index.json +195212 -115957
  82. package/modules/CLAUDE.md +1 -0
  83. package/modules/Checkout.sh +1 -0
  84. package/modules/Diff.sh +86 -0
  85. package/modules/Include-Retold-Module-List.sh +4 -2
  86. package/modules/Status.sh +1 -0
  87. package/modules/Update.sh +1 -0
  88. package/modules/apps/Apps.md +1 -0
  89. package/modules/utility/Utility.md +1 -0
  90. package/package.json +9 -11
  91. package/docs/retold-building-documentation.md +0 -33
  92. package/modules/Retold-Modules.md +0 -24
@@ -0,0 +1,350 @@
1
+ # Data Formatting Expressions
2
+
3
+ Formatting expressions transform resolved values for display -- numbers, dates, currencies, and string manipulation.
4
+
5
+ ## Digits
6
+
7
+ Formats a number with two decimal places and thousands separators.
8
+
9
+ **Tags:** `{~Digits:ADDRESS~}`
10
+
11
+ **Parameters:**
12
+
13
+ | Parameter | Description |
14
+ |-----------|-------------|
15
+ | ADDRESS | Path to a numeric value |
16
+
17
+ **Examples:**
18
+
19
+ ```html
20
+ <span>{~Digits:Record.Quantity~} units</span>
21
+ <td>{~Digits:Record.Population~}</td>
22
+ ```
23
+
24
+ ```javascript
25
+ _Pict.parseTemplate('{~Digits:Record.Value~}', { Value: 1234567.891 });
26
+ // '1,234,567.89'
27
+
28
+ _Pict.parseTemplate('{~Digits:Record.Value~}', { Value: 42 });
29
+ // '42.00'
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Dollars
35
+
36
+ Formats a number as US currency with a dollar sign, two decimal places, and thousands separators.
37
+
38
+ **Tags:** `{~Dollars:ADDRESS~}`
39
+
40
+ **Parameters:**
41
+
42
+ | Parameter | Description |
43
+ |-----------|-------------|
44
+ | ADDRESS | Path to a numeric value |
45
+
46
+ **Examples:**
47
+
48
+ ```html
49
+ <span class="price">{~Dollars:Record.Price~}</span>
50
+ <td>Total: {~Dollars:AppData.Order.Total~}</td>
51
+ ```
52
+
53
+ ```javascript
54
+ _Pict.parseTemplate('{~Dollars:Record.Price~}', { Price: 1234.5 });
55
+ // '$1,234.50'
56
+
57
+ _Pict.parseTemplate('{~Dollars:Record.Price~}', { Price: 9.9 });
58
+ // '$9.90'
59
+ ```
60
+
61
+ ---
62
+
63
+ ## PascalCaseIdentifier
64
+
65
+ Converts a string to PascalCase -- capitalizes the first letter of each word and removes non-alphanumeric characters.
66
+
67
+ **Tags:** `{~PascalCaseIdentifier:ADDRESS~}`
68
+
69
+ **Parameters:**
70
+
71
+ | Parameter | Description |
72
+ |-----------|-------------|
73
+ | ADDRESS | Path to a string value |
74
+
75
+ **Examples:**
76
+
77
+ ```javascript
78
+ _Pict.parseTemplate('{~PascalCaseIdentifier:Record.Name~}',
79
+ { Name: 'meadow-endpoints' });
80
+ // 'MeadowEndpoints'
81
+
82
+ _Pict.parseTemplate('{~PascalCaseIdentifier:Record.Name~}',
83
+ { Name: 'hello world' });
84
+ // 'HelloWorld'
85
+
86
+ _Pict.parseTemplate('{~PascalCaseIdentifier:Record.Name~}',
87
+ { Name: 'some_variable_name' });
88
+ // 'SomeVariableName'
89
+ ```
90
+
91
+ Useful for generating code identifiers, CSS class names, or display labels from raw strings.
92
+
93
+ ---
94
+
95
+ ## DateTimeYMD
96
+
97
+ Formats a date-time value as `YYYY-MM-DD`. Timezone-aware -- respects `pict.options.Timezone` when converting.
98
+
99
+ **Tags:** `{~DateTimeYMD:ADDRESS~}` `{~DateYMD:ADDRESS~}`
100
+
101
+ **Parameters:**
102
+
103
+ | Parameter | Description |
104
+ |-----------|-------------|
105
+ | ADDRESS | Path to a date-time string or value |
106
+
107
+ **Examples:**
108
+
109
+ ```html
110
+ <time>{~DateTimeYMD:Record.CreateDate~}</time>
111
+ ```
112
+
113
+ ```javascript
114
+ _Pict.options.Timezone = 'America/Los_Angeles';
115
+ _Pict.parseTemplate('{~DateTimeYMD:Record.Date~}',
116
+ { Date: '2023-05-25T05:54:46.000Z' });
117
+ // '2023-05-24' (adjusted from UTC to Pacific)
118
+ ```
119
+
120
+ ---
121
+
122
+ ## DateTimeFormat
123
+
124
+ Formats a date-time value using a custom DayJS format string. Timezone-aware.
125
+
126
+ **Tags:** `{~DateTimeFormat:ADDRESS^FORMAT_STRING~}` `{~DateFormat:ADDRESS^FORMAT_STRING~}`
127
+
128
+ **Parameters:**
129
+
130
+ | Parameter | Description |
131
+ |-----------|-------------|
132
+ | ADDRESS | Path to a date-time string or value |
133
+ | FORMAT_STRING | DayJS format string (separated by `^`) |
134
+
135
+ **Common Format Tokens:**
136
+
137
+ | Token | Output | Example |
138
+ |-------|--------|---------|
139
+ | `YYYY` | 4-digit year | 2025 |
140
+ | `MM` | Zero-padded month | 01-12 |
141
+ | `MMMM` | Full month name | January |
142
+ | `DD` | Zero-padded day | 01-31 |
143
+ | `Do` | Ordinal day | 1st, 2nd, 3rd |
144
+ | `dddd` | Full day name | Monday |
145
+ | `HH` | 24-hour hour | 00-23 |
146
+ | `hh` | 12-hour hour | 01-12 |
147
+ | `mm` | Minutes | 00-59 |
148
+ | `A` | AM/PM | AM, PM |
149
+
150
+ **Examples:**
151
+
152
+ ```html
153
+ <time>{~DateTimeFormat:Record.PublishedDate^MMMM Do, YYYY~}</time>
154
+ <span>{~DateTimeFormat:Record.EventTime^dddd, MMMM D YYYY [at] h:mm A~}</span>
155
+ ```
156
+
157
+ ```javascript
158
+ _Pict.options.Timezone = 'America/New_York';
159
+ _Pict.parseTemplate('{~DateTimeFormat:Record.Date^dddd MMMM Do YYYY~}',
160
+ { Date: '2023-05-25T05:54:46.000Z' });
161
+ // 'Wednesday May 24th 2023'
162
+ ```
163
+
164
+ ---
165
+
166
+ ## DateOnlyYMD
167
+
168
+ Formats a date-only value (no time component) as `YYYY-MM-DD`. Forces UTC interpretation to avoid timezone shifting.
169
+
170
+ **Tags:** `{~DateOnlyYMD:ADDRESS~}`
171
+
172
+ **Parameters:**
173
+
174
+ | Parameter | Description |
175
+ |-----------|-------------|
176
+ | ADDRESS | Path to a date string (e.g., `2023-05-25`) |
177
+
178
+ **Examples:**
179
+
180
+ ```javascript
181
+ _Pict.parseTemplate('{~DateOnlyYMD:Record.BirthDate~}',
182
+ { BirthDate: '2023-05-25' });
183
+ // '2023-05-25'
184
+ ```
185
+
186
+ Use this instead of `DateTimeYMD` when working with date-only values. `DateTimeYMD` applies timezone conversion, which can shift a date-only value to the previous or next day. `DateOnlyYMD` forces UTC to prevent this.
187
+
188
+ ---
189
+
190
+ ## DateOnlyFormat
191
+
192
+ Formats a date-only value using a custom DayJS format string. Forces UTC interpretation.
193
+
194
+ **Tags:** `{~DateOnlyFormat:ADDRESS^FORMAT_STRING~}`
195
+
196
+ **Parameters:**
197
+
198
+ | Parameter | Description |
199
+ |-----------|-------------|
200
+ | ADDRESS | Path to a date string |
201
+ | FORMAT_STRING | DayJS format string (separated by `^`) |
202
+
203
+ **Examples:**
204
+
205
+ ```html
206
+ <span>{~DateOnlyFormat:Record.BirthDate^MMMM Do, YYYY~}</span>
207
+ ```
208
+
209
+ ```javascript
210
+ _Pict.parseTemplate('{~DateOnlyFormat:Record.Date^dddd MMMM Do YYYY~}',
211
+ { Date: '2023-05-25' });
212
+ // 'Thursday May 25th 2023'
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Join (J)
218
+
219
+ Joins resolved values from multiple addresses with a separator. Skips empty or falsy values. Flattens arrays.
220
+
221
+ **Tags:** `{~Join:SEPARATOR^ADDRESS1^ADDRESS2^...~}` `{~J:SEPARATOR^ADDRESS1^ADDRESS2^...~}`
222
+
223
+ **Parameters:**
224
+
225
+ | Parameter | Description |
226
+ |-----------|-------------|
227
+ | SEPARATOR | The string to place between joined values |
228
+ | ADDRESS1, ADDRESS2, ... | Addresses to resolve and join (separated by `^`) |
229
+
230
+ **Examples:**
231
+
232
+ ```html
233
+ <p>{~J:, ^Record.City^Record.State^Record.Country~}</p>
234
+ <span>{~J: - ^AppData.Server1^AppData.Server2~}</span>
235
+ ```
236
+
237
+ ```javascript
238
+ _Pict.parseTemplate('{~J:, ^Record.City^Record.State~}',
239
+ { City: 'Portland', State: 'Oregon' });
240
+ // 'Portland, Oregon'
241
+
242
+ // Empty values are skipped
243
+ _Pict.parseTemplate('{~J:, ^Record.City^Record.State^Record.Zip~}',
244
+ { City: 'Portland', State: '', Zip: '97201' });
245
+ // 'Portland, 97201'
246
+ ```
247
+
248
+ ---
249
+
250
+ ## JoinUnique (JU)
251
+
252
+ Joins resolved values, deduplicating before joining. Otherwise identical to Join.
253
+
254
+ **Tags:** `{~JoinUnique:SEPARATOR^ADDRESS1^ADDRESS2^...~}` `{~JU:SEPARATOR^ADDRESS1^ADDRESS2^...~}`
255
+
256
+ **Parameters:**
257
+
258
+ | Parameter | Description |
259
+ |-----------|-------------|
260
+ | SEPARATOR | The string to place between joined values |
261
+ | ADDRESS1, ADDRESS2, ... | Addresses to resolve, deduplicate, and join (separated by `^`) |
262
+
263
+ **Examples:**
264
+
265
+ ```javascript
266
+ _Pict.AppData = { Tag1: 'javascript', Tag2: 'node', Tag3: 'javascript' };
267
+
268
+ _Pict.parseTemplate('{~JU:, ^AppData.Tag1^AppData.Tag2^AppData.Tag3~}');
269
+ // 'javascript, node' (duplicate removed)
270
+ ```
271
+
272
+ ---
273
+
274
+ ## PluckJoinUnique (PJU)
275
+
276
+ Plucks a property from each object in an array, deduplicates the values, and joins them with a separator.
277
+
278
+ **Tags:** `{~PluckJoinUnique:SEPARATOR^PROPERTY^ARRAY_ADDRESS~}` `{~PJU:SEPARATOR^PROPERTY^ARRAY_ADDRESS~}`
279
+
280
+ **Parameters:**
281
+
282
+ | Parameter | Description |
283
+ |-----------|-------------|
284
+ | SEPARATOR | The string to place between joined values |
285
+ | PROPERTY | The property name to pluck from each array item |
286
+ | ARRAY_ADDRESS | Address of the array (separated by `^`) |
287
+
288
+ **Examples:**
289
+
290
+ ```javascript
291
+ _Pict.AppData.Files = [
292
+ { name: 'photo.jpg', source: 'original' },
293
+ { name: 'thumb.jpg', source: 'derivative' },
294
+ { name: 'meta.xml', source: 'metadata' },
295
+ { name: 'large.jpg', source: 'derivative' }
296
+ ];
297
+
298
+ _Pict.parseTemplate('{~PJU:, ^source^AppData.Files~}');
299
+ // 'original, derivative, metadata' (duplicate 'derivative' removed)
300
+ ```
301
+
302
+ Useful for extracting and displaying unique categories, tags, or types from a collection of records.
303
+
304
+ ---
305
+
306
+ ## HtmlCommentStart (HCS)
307
+
308
+ Conditionally outputs `<!-- ` to start an HTML comment, based on the truthiness of a data value. Paired with HtmlCommentEnd to wrap content in comments for conditional display.
309
+
310
+ **Tags:** `{~HtmlCommentStart:ADDRESS~}` `{~HCS:ADDRESS~}` or `{~HCS:ADDRESS:POLARITY~}`
311
+
312
+ **Parameters:**
313
+
314
+ | Parameter | Description |
315
+ |-----------|-------------|
316
+ | ADDRESS | Path to a value to check for truthiness |
317
+ | POLARITY | Optional. Default: comment when value is **falsy**. Set to `1`, `true`, or `t` to comment when **truthy**. |
318
+
319
+ ---
320
+
321
+ ## HtmlCommentEnd (HCE)
322
+
323
+ Conditionally outputs ` -->` to close an HTML comment. Must match a corresponding HtmlCommentStart.
324
+
325
+ **Tags:** `{~HtmlCommentEnd:ADDRESS~}` `{~HCE:ADDRESS~}` or `{~HCE:ADDRESS:POLARITY~}`
326
+
327
+ **Parameters:** Same as HtmlCommentStart.
328
+
329
+ **Combined Example:**
330
+
331
+ ```html
332
+ {~HCS:Record.ShowBanner~}
333
+ <div class="banner">Special Offer!</div>
334
+ {~HCE:Record.ShowBanner~}
335
+ ```
336
+
337
+ ```javascript
338
+ // When ShowBanner is true, content is visible:
339
+ _Pict.parseTemplate(template, { ShowBanner: true });
340
+ // '<div class="banner">Special Offer!</div>'
341
+
342
+ // When ShowBanner is false, content is commented out:
343
+ _Pict.parseTemplate(template, { ShowBanner: false });
344
+ // '<!-- <div class="banner">Special Offer!</div> -->'
345
+
346
+ // Inverted polarity -- comment when true:
347
+ '{~HCS:Record.IsHidden:1~}<p>Content</p>{~HCE:Record.IsHidden:1~}'
348
+ ```
349
+
350
+ This approach is useful for toggling content visibility in server-rendered HTML while keeping the markup in the DOM for debugging.
@@ -0,0 +1,72 @@
1
+ # Data Generation Expressions
2
+
3
+ Data generation expressions produce random values for testing, unique IDs, or placeholder content.
4
+
5
+ ## RandomNumber (RN)
6
+
7
+ Generates a random integer between a minimum and maximum value (inclusive).
8
+
9
+ **Tags:** `{~RandomNumber:MIN,MAX~}` `{~RN:MIN,MAX~}` or `{~RN:~}` (defaults: 0 to 9999999)
10
+
11
+ **Parameters:**
12
+
13
+ | Parameter | Description |
14
+ |-----------|-------------|
15
+ | MIN | Minimum value (default: 0) |
16
+ | MAX | Maximum value (default: 9999999). Separated from MIN by `,`. |
17
+
18
+ **Examples:**
19
+
20
+ ```html
21
+ <!-- Random number 1-100 -->
22
+ <span>Score: {~RN:1,100~}</span>
23
+
24
+ <!-- Random with defaults -->
25
+ <code>ID: {~RN:~}</code>
26
+
27
+ <!-- Random percentage -->
28
+ <div style="width: {~RN:10,100~}%">Progress</div>
29
+ ```
30
+
31
+ ```javascript
32
+ _Pict.parseTemplate('{~RN:1,6~}');
33
+ // A random integer from 1 to 6 (like a die roll)
34
+
35
+ _Pict.parseTemplate('{~RN:1000,9999~}');
36
+ // A random 4-digit number
37
+ ```
38
+
39
+ ---
40
+
41
+ ## RandomNumberString (RNS)
42
+
43
+ Generates a zero-padded random numeric string of a specified length.
44
+
45
+ **Tags:** `{~RandomNumberString:LENGTH~}` `{~RNS:LENGTH~}` or `{~RNS:LENGTH,MAX~}`
46
+
47
+ **Parameters:**
48
+
49
+ | Parameter | Description |
50
+ |-----------|-------------|
51
+ | LENGTH | The number of characters in the output string (default: 4) |
52
+ | MAX | Maximum numeric value (default: 10^LENGTH - 1). Separated from LENGTH by `,`. |
53
+
54
+ **Examples:**
55
+
56
+ ```html
57
+ <!-- 6-character padded random string -->
58
+ <code>REF-{~RNS:6~}</code>
59
+
60
+ <!-- 10-character padded random string -->
61
+ <span>{~RNS:10~}</span>
62
+ ```
63
+
64
+ ```javascript
65
+ _Pict.parseTemplate('{~RNS:4~}');
66
+ // e.g., '0042' or '7831' (always 4 characters, zero-padded)
67
+
68
+ _Pict.parseTemplate('{~RNS:8~}');
69
+ // e.g., '00384729' (always 8 characters, zero-padded)
70
+ ```
71
+
72
+ RandomNumberString is useful for generating reference codes, order numbers, or temporary identifiers that need a consistent length. The zero-padding ensures the output is always exactly LENGTH characters, which is important for display consistency and sortability.
@@ -0,0 +1,181 @@
1
+ # Debugging Expressions
2
+
3
+ Debugging expressions help during development by logging values, inserting breakpoints, and rendering object structures as HTML. They produce no visible output in the rendered template (except DataTree, which renders an HTML representation).
4
+
5
+ ## Breakpoint
6
+
7
+ Inserts a JavaScript `debugger` statement and logs a stack trace. When browser DevTools are open, execution pauses at this point. Returns an empty string.
8
+
9
+ **Tags:** `{~Breakpoint~}` or `{~Breakpoint:LABEL~}`
10
+
11
+ **Parameters:**
12
+
13
+ | Parameter | Description |
14
+ |-----------|-------------|
15
+ | LABEL | Optional. A label logged with the breakpoint for identification. |
16
+
17
+ **Examples:**
18
+
19
+ ```html
20
+ <!-- Pause execution here when DevTools are open -->
21
+ <div>{~Breakpoint~}{~D:Record.Title~}</div>
22
+
23
+ <!-- Labeled breakpoint -->
24
+ {~Breakpoint:before-user-render~}
25
+ {~T:UserCard:AppData.CurrentUser~}
26
+ ```
27
+
28
+ Breakpoint is a development tool. It does not affect the rendered output -- the expression always returns an empty string. Remove breakpoints before deploying to production.
29
+
30
+ ---
31
+
32
+ ## LogStatement (LS)
33
+
34
+ Logs a literal message to the trace log. Returns an empty string.
35
+
36
+ **Tags:** `{~LogStatement:MESSAGE~}` `{~LS:MESSAGE~}`
37
+
38
+ **Parameters:**
39
+
40
+ | Parameter | Description |
41
+ |-----------|-------------|
42
+ | MESSAGE | A literal string to log |
43
+
44
+ **Examples:**
45
+
46
+ ```html
47
+ {~LS:Starting product list render~}
48
+ <ul>{~TS:ProductRow:AppData.Products~}</ul>
49
+ {~LS:Finished product list render~}
50
+ ```
51
+
52
+ ```javascript
53
+ _Pict.parseTemplate('{~LS:Processing order data~}');
54
+ // Logs: 'Processing order data' at trace level
55
+ // Returns: ''
56
+ ```
57
+
58
+ LogStatement logs at the **trace** level. You need `LogLevel: 0` in your Pict configuration to see trace messages. Use it to mark execution flow through templates -- which template set started, which branch was taken.
59
+
60
+ ---
61
+
62
+ ## LogValue (LV)
63
+
64
+ Resolves a value from the address space and logs it with type information. Returns an empty string.
65
+
66
+ **Tags:** `{~LogValue:ADDRESS~}` `{~LV:ADDRESS~}`
67
+
68
+ **Parameters:**
69
+
70
+ | Parameter | Description |
71
+ |-----------|-------------|
72
+ | ADDRESS | Path to the value to log |
73
+
74
+ **Examples:**
75
+
76
+ ```html
77
+ {~LV:AppData.CurrentUser~}
78
+ {~LV:Record.OrderTotal~}
79
+ ```
80
+
81
+ ```javascript
82
+ _Pict.AppData.User = { Name: 'Alice', Role: 'admin' };
83
+ _Pict.parseTemplate('{~LV:AppData.User~}');
84
+ // Logs: 'PICT Template Log Value: [AppData.User] is an object.' + the object
85
+ // Returns: ''
86
+ ```
87
+
88
+ The log output includes the address, the JavaScript type (`typeof`), and the resolved value. This helps identify whether a value is the expected type (string vs number vs object vs undefined).
89
+
90
+ ---
91
+
92
+ ## LogValueTree (LVT)
93
+
94
+ Recursively logs all keys and values of an object to the trace log, up to a specified depth. Returns an empty string.
95
+
96
+ **Tags:** `{~LogValueTree:ADDRESS~}` `{~LVT:ADDRESS~}` or `{~LVT:ADDRESS^DEPTH~}`
97
+
98
+ **Parameters:**
99
+
100
+ | Parameter | Description |
101
+ |-----------|-------------|
102
+ | ADDRESS | Path to the object to log |
103
+ | DEPTH | Optional. Maximum depth to traverse (default: 1). Separated by `^`. |
104
+
105
+ **Examples:**
106
+
107
+ ```html
108
+ <!-- Log top-level keys -->
109
+ {~LVT:AppData.Config~}
110
+
111
+ <!-- Log two levels deep -->
112
+ {~LVT:AppData.User^2~}
113
+ ```
114
+
115
+ ```javascript
116
+ _Pict.AppData.Config = {
117
+ database: { host: 'localhost', port: 3306 },
118
+ cache: { enabled: true, ttl: 300 }
119
+ };
120
+
121
+ _Pict.parseTemplate('{~LVT:AppData.Config^2~}');
122
+ // Logs all nested keys and values up to 2 levels
123
+ // Returns: ''
124
+ ```
125
+
126
+ LogValueTree is useful when you are unsure of an object's structure. Rather than serializing it with `{~DJ:...~}` (which can be unwieldy for large objects), LVT gives a formatted log output showing the tree structure.
127
+
128
+ ---
129
+
130
+ ## DataTree (DT)
131
+
132
+ Renders an object tree as interactive HTML `<div>` elements for visual debugging. Unlike the other debugging expressions, DataTree produces visible output.
133
+
134
+ **Tags:** `{~DataTree:ADDRESS~}` `{~DT:ADDRESS~}` or `{~DT:ADDRESS^DEPTH~}`
135
+
136
+ **Parameters:**
137
+
138
+ | Parameter | Description |
139
+ |-----------|-------------|
140
+ | ADDRESS | Path to the object to render |
141
+ | DEPTH | Optional. Maximum depth to traverse (default: 1). Separated by `^`. |
142
+
143
+ **Examples:**
144
+
145
+ ```html
146
+ <!-- Render object tree in the page -->
147
+ <div class="debug-panel">
148
+ {~DT:AppData.CurrentOrder~}
149
+ </div>
150
+
151
+ <!-- Two levels deep -->
152
+ {~DT:AppData.UserProfile^2~}
153
+ ```
154
+
155
+ ```javascript
156
+ _Pict.AppData.Data = { title: 'Test', count: 42 };
157
+ _Pict.parseTemplate('{~DT:AppData.Data~}');
158
+ // Returns HTML like:
159
+ // <div class="PICT PICTObjectSet">
160
+ // <div class="PICTObjectBranchDepth_0">
161
+ // <div class="PICTObjectBranch">title</div>
162
+ // <div class="PICTObjectBranchValue">Test</div>
163
+ // </div>
164
+ // <div class="PICTObjectBranchDepth_0">
165
+ // <div class="PICTObjectBranch">count</div>
166
+ // <div class="PICTObjectBranchValue">42</div>
167
+ // </div>
168
+ // </div>
169
+ ```
170
+
171
+ The rendered HTML uses CSS classes (`PICTObjectSet`, `PICTObjectBranch`, `PICTObjectBranchValue`, `PICTObjectBranchDepth_N`) that you can style for your debugging panel. DataTree uses customizable templates internally -- `PICT-Object-Wrap` and `PICT-Object-Branch` -- which can be overridden by registering templates with those hashes.
172
+
173
+ ### When to Use Each Debugging Expression
174
+
175
+ | Need | Expression | Produces Output? |
176
+ |------|------------|-----------------|
177
+ | Pause execution in DevTools | `{~Breakpoint~}` | No |
178
+ | Log a message during rendering | `{~LS:message~}` | No |
179
+ | Log a resolved value with type info | `{~LV:address~}` | No |
180
+ | Log an object tree to console | `{~LVT:address~}` | No |
181
+ | Render an object tree as HTML | `{~DT:address~}` | Yes |
@@ -0,0 +1,99 @@
1
+ # Entity Expressions
2
+
3
+ Entity expressions integrate with Pict's Meadow API layer to fetch records from REST endpoints and render them with templates. These are inherently asynchronous.
4
+
5
+ ## Entity (E)
6
+
7
+ Fetches an entity record from a Meadow REST API by type and ID, then renders a template with the fetched record.
8
+
9
+ **Tags:** `{~Entity:ENTITY_TYPE^ID^TEMPLATE_HASH~}` `{~E:ENTITY_TYPE^ID^TEMPLATE_HASH~}`
10
+
11
+ **Parameters:**
12
+
13
+ | Parameter | Description |
14
+ |-----------|-------------|
15
+ | ENTITY_TYPE | The Meadow entity scope (e.g., `Book`, `User`, `Order`) |
16
+ | ID | A static ID or address that resolves to an ID |
17
+ | TEMPLATE_HASH | Hash of the template to render with the fetched record |
18
+
19
+ ### Static ID
20
+
21
+ ```javascript
22
+ _Pict.TemplateProvider.addTemplate('BookCard',
23
+ '<div class="book"><h3>{~D:Record.Title~}</h3><p>By {~D:Record.Author~}</p></div>');
24
+
25
+ _Pict.parseTemplate('{~E:Book^42^BookCard~}', {},
26
+ (pError, pResult) =>
27
+ {
28
+ console.log(pResult);
29
+ // '<div class="book"><h3>Dune</h3><p>By Frank Herbert</p></div>'
30
+ });
31
+ ```
32
+
33
+ ### Dynamic ID from Data
34
+
35
+ The ID parameter can be a data address that resolves to the actual ID value.
36
+
37
+ ```javascript
38
+ _Pict.parseTemplate('{~E:Book^Record.IDBook^BookCard~}',
39
+ { IDBook: 100 },
40
+ (pError, pResult) =>
41
+ {
42
+ console.log(pResult);
43
+ // Fetches Book with ID 100 and renders with BookCard
44
+ });
45
+ ```
46
+
47
+ ### How It Works
48
+
49
+ When the Entity expression encounters `{~E:Book^42^BookCard~}`:
50
+
51
+ 1. It resolves the ID (static `42` or dynamic from a data address)
52
+ 2. Calls `pict.EntityProvider.getEntity('Book', 42, callback)` to fetch the record via REST API
53
+ 3. On success, renders the template `BookCard` with the fetched record as `Record`
54
+ 4. Returns the rendered string through the callback
55
+
56
+ The EntityProvider uses Pict's configured API base URL and authentication to make the HTTP request. This means templates can transparently reference server-side data without the template author managing API calls.
57
+
58
+ ### Synchronous Fallback
59
+
60
+ When called synchronously (no callback), the Entity expression returns an empty string. Entity fetching requires a callback because it involves a network request.
61
+
62
+ ```javascript
63
+ // Sync: returns empty string
64
+ let tmpResult = _Pict.parseTemplate('{~E:Book^42^BookCard~}');
65
+ // ''
66
+
67
+ // Async: returns fetched and rendered content
68
+ _Pict.parseTemplate('{~E:Book^42^BookCard~}', {}, (pError, pResult) =>
69
+ {
70
+ // pResult contains the rendered content
71
+ });
72
+ ```
73
+
74
+ ### Practical Pattern: Related Entity Display
75
+
76
+ A common pattern is displaying related entities in a list. Each item has a foreign key, and the Entity expression fetches and renders the related record inline.
77
+
78
+ ```javascript
79
+ _Pict.TemplateProvider.addTemplate('AuthorName',
80
+ '{~D:Record.FirstName~} {~D:Record.LastName~}');
81
+
82
+ _Pict.TemplateProvider.addTemplate('BookRow',
83
+ '<tr><td>{~D:Record.Title~}</td><td>{~E:Author^Record.IDAuthor^AuthorName~}</td></tr>');
84
+
85
+ _Pict.AppData.Books = [
86
+ { Title: 'Dune', IDAuthor: 1 },
87
+ { Title: 'Neuromancer', IDAuthor: 2 }
88
+ ];
89
+
90
+ _Pict.parseTemplate(
91
+ '<table>{~TS:BookRow:AppData.Books~}</table>',
92
+ {},
93
+ (pError, pResult) =>
94
+ {
95
+ // Each row fetches its author by ID and renders the name
96
+ });
97
+ ```
98
+
99
+ This pattern works because the template engine processes async expressions within template sets correctly -- it waits for all entity fetches to complete before assembling the final output.