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.
- package/.claude/launch.json +29 -0
- package/.claude/settings.local.json +60 -2
- package/CLAUDE.md +4 -2
- package/README.md +4 -2
- package/Retold-Modules-Manifest.json +576 -0
- package/docs/README.md +7 -1
- package/docs/{cover.md → _cover.md} +1 -1
- package/docs/_sidebar.md +30 -3
- package/docs/architecture/architecture.md +5 -2
- package/docs/architecture/dependencies/_generate-graph.js +186 -0
- package/docs/architecture/dependencies/_generate-svg.js +364 -0
- package/docs/architecture/dependencies/in-ecosystem-dependency-graph-generation.md +97 -0
- package/docs/architecture/dependencies/in-ecosystem-dependency-graph.json +3168 -0
- package/docs/architecture/dependencies/in-ecosystem-dependency-graph.md +221 -0
- package/docs/architecture/dependencies/in-ecosystem-dependency-graph.svg +664 -0
- package/docs/architecture/documentation-style-guide.md +65 -0
- package/docs/architecture/example-app-style-guide.md +154 -0
- package/docs/architecture/modules.md +17 -5
- package/docs/architecture/templating/data-access.md +196 -0
- package/docs/architecture/templating/data-formatting.md +350 -0
- package/docs/architecture/templating/data-generation.md +72 -0
- package/docs/architecture/templating/debugging.md +181 -0
- package/docs/architecture/templating/entity.md +99 -0
- package/docs/architecture/templating/iteration.md +170 -0
- package/docs/architecture/templating/jellyfish-deep-dive.md +271 -0
- package/docs/architecture/templating/jellyfish-templates.md +476 -0
- package/docs/architecture/templating/logic.md +185 -0
- package/docs/architecture/templating/ref-breakpoint.md +38 -0
- package/docs/architecture/templating/ref-data.md +51 -0
- package/docs/architecture/templating/ref-dateonlyformat.md +43 -0
- package/docs/architecture/templating/ref-dateonlyymd.md +39 -0
- package/docs/architecture/templating/ref-datetimeformat.md +59 -0
- package/docs/architecture/templating/ref-datetimeymd.md +44 -0
- package/docs/architecture/templating/ref-dejs.md +42 -0
- package/docs/architecture/templating/ref-digits.md +36 -0
- package/docs/architecture/templating/ref-dj.md +50 -0
- package/docs/architecture/templating/ref-dollars.md +36 -0
- package/docs/architecture/templating/ref-dt.md +38 -0
- package/docs/architecture/templating/ref-dvbk.md +46 -0
- package/docs/architecture/templating/ref-dwaf.md +45 -0
- package/docs/architecture/templating/ref-dwtf.md +45 -0
- package/docs/architecture/templating/ref-entity.md +47 -0
- package/docs/architecture/templating/ref-hce.md +29 -0
- package/docs/architecture/templating/ref-hcs.md +38 -0
- package/docs/architecture/templating/ref-join.md +45 -0
- package/docs/architecture/templating/ref-joinunique.md +34 -0
- package/docs/architecture/templating/ref-ls.md +37 -0
- package/docs/architecture/templating/ref-lv.md +38 -0
- package/docs/architecture/templating/ref-lvt.md +33 -0
- package/docs/architecture/templating/ref-ne.md +40 -0
- package/docs/architecture/templating/ref-pascalcaseidentifier.md +41 -0
- package/docs/architecture/templating/ref-pict.md +42 -0
- package/docs/architecture/templating/ref-pluckjoinunique.md +39 -0
- package/docs/architecture/templating/ref-rn.md +35 -0
- package/docs/architecture/templating/ref-rns.md +35 -0
- package/docs/architecture/templating/ref-sbr.md +36 -0
- package/docs/architecture/templating/ref-solve.md +46 -0
- package/docs/architecture/templating/ref-tbda.md +41 -0
- package/docs/architecture/templating/ref-tbr.md +43 -0
- package/docs/architecture/templating/ref-tbt.md +46 -0
- package/docs/architecture/templating/ref-template.md +40 -0
- package/docs/architecture/templating/ref-tfa.md +32 -0
- package/docs/architecture/templating/ref-tfm.md +43 -0
- package/docs/architecture/templating/ref-tif.md +45 -0
- package/docs/architecture/templating/ref-tifabs.md +41 -0
- package/docs/architecture/templating/ref-ts.md +41 -0
- package/docs/architecture/templating/ref-tsfm.md +42 -0
- package/docs/architecture/templating/ref-tswp.md +45 -0
- package/docs/architecture/templating/ref-tvs.md +48 -0
- package/docs/architecture/templating/ref-view.md +40 -0
- package/docs/architecture/templating/ref-vrs.md +39 -0
- package/docs/architecture/templating/solvers.md +153 -0
- package/docs/architecture/templating/template-composition.md +196 -0
- package/docs/architecture/templating/template-expressions.md +217 -0
- package/docs/architecture/templating/views.md +154 -0
- package/docs/examples/todolist/todo-list.md +1 -1
- package/docs/modules/apps.md +26 -0
- package/docs/modules/pict.md +18 -0
- package/docs/modules/utility.md +23 -1
- package/docs/retold-catalog.json +829 -102
- package/docs/retold-keyword-index.json +195212 -115957
- package/modules/CLAUDE.md +1 -0
- package/modules/Checkout.sh +1 -0
- package/modules/Diff.sh +86 -0
- package/modules/Include-Retold-Module-List.sh +4 -2
- package/modules/Status.sh +1 -0
- package/modules/Update.sh +1 -0
- package/modules/apps/Apps.md +1 -0
- package/modules/utility/Utility.md +1 -0
- package/package.json +9 -11
- package/docs/retold-building-documentation.md +0 -33
- 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.
|