plotleaf 0.0.0-stage → 0.2.0
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/LICENSE +21 -0
- package/README.md +139 -2
- package/THIRD_PARTY_NOTICES.txt +304 -0
- package/dist/assets/base.js +1 -0
- package/dist/assets/charts.js +45 -0
- package/dist/assets/notices.txt +304 -0
- package/dist/assets/styles.css +631 -0
- package/dist/cli.js +1737 -0
- package/examples/adoption/adoption.json +24 -0
- package/examples/adoption/plans.json +5 -0
- package/examples/adoption/report.md +31 -0
- package/examples/onboarding/funnel.json +30 -0
- package/examples/onboarding/plans.json +14 -0
- package/examples/onboarding/report.md +42 -0
- package/examples/onboarding/signups.json +50 -0
- package/examples/storefront/categories.json +26 -0
- package/examples/storefront/orders.json +30 -0
- package/examples/storefront/report.md +45 -0
- package/examples/storefront/returns.json +10 -0
- package/package.json +80 -4
- package/schema/components.json +551 -0
- package/skills/plotleaf/SKILL.md +78 -0
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"syntax": "markdown-directives",
|
|
4
|
+
"attributes": "Literal strings decoded according to each property schema. No JavaScript expressions.",
|
|
5
|
+
"limits": {
|
|
6
|
+
"markdownBytes": 1048576,
|
|
7
|
+
"jsonBytes": 10485760,
|
|
8
|
+
"totalBytes": 26214400,
|
|
9
|
+
"datasets": 64,
|
|
10
|
+
"rows": 100000,
|
|
11
|
+
"chartRows": 10000,
|
|
12
|
+
"donutSlices": 8,
|
|
13
|
+
"funnelStages": 20,
|
|
14
|
+
"tableRows": 1000,
|
|
15
|
+
"tableColumns": 40
|
|
16
|
+
},
|
|
17
|
+
"data": {
|
|
18
|
+
"shape": "array of flat JSON records",
|
|
19
|
+
"resolution": "relative to the report directory; local .json files only",
|
|
20
|
+
"percent": "ratios: 0.12 displays as 12%",
|
|
21
|
+
"percentagePoints": "point values: 0.8 displays as 0.8 pt",
|
|
22
|
+
"currency": "major units; omit .00 on whole amounts, preserve nonzero cents",
|
|
23
|
+
"locale": "en-GB",
|
|
24
|
+
"timeZone": "UTC"
|
|
25
|
+
},
|
|
26
|
+
"components": {
|
|
27
|
+
"grid": {
|
|
28
|
+
"description": "A responsive row of one to four components.",
|
|
29
|
+
"forms": [
|
|
30
|
+
"container"
|
|
31
|
+
],
|
|
32
|
+
"children": [
|
|
33
|
+
"metric",
|
|
34
|
+
"line",
|
|
35
|
+
"area",
|
|
36
|
+
"bar",
|
|
37
|
+
"donut",
|
|
38
|
+
"funnel",
|
|
39
|
+
"table",
|
|
40
|
+
"callout"
|
|
41
|
+
],
|
|
42
|
+
"props": {
|
|
43
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
44
|
+
"type": "object",
|
|
45
|
+
"properties": {
|
|
46
|
+
"columns": {
|
|
47
|
+
"default": 2,
|
|
48
|
+
"type": "integer",
|
|
49
|
+
"minimum": 1,
|
|
50
|
+
"maximum": 4
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"required": [
|
|
54
|
+
"columns"
|
|
55
|
+
],
|
|
56
|
+
"additionalProperties": false
|
|
57
|
+
},
|
|
58
|
+
"example": ":::grid{columns=\"4\"}\n::metric{label=\"Teams\" value=\"1492\"}\n:::"
|
|
59
|
+
},
|
|
60
|
+
"metric": {
|
|
61
|
+
"description": "A prepared numeric value with optional comparison, direction and sentiment.",
|
|
62
|
+
"forms": [
|
|
63
|
+
"leaf"
|
|
64
|
+
],
|
|
65
|
+
"children": [],
|
|
66
|
+
"props": {
|
|
67
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
68
|
+
"type": "object",
|
|
69
|
+
"properties": {
|
|
70
|
+
"label": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"minLength": 1,
|
|
73
|
+
"maxLength": 1000
|
|
74
|
+
},
|
|
75
|
+
"value": {
|
|
76
|
+
"type": "number"
|
|
77
|
+
},
|
|
78
|
+
"format": {
|
|
79
|
+
"default": "number",
|
|
80
|
+
"type": "string",
|
|
81
|
+
"pattern": "^(number|percent|percentage-points|currency:[A-Z]{3})$"
|
|
82
|
+
},
|
|
83
|
+
"comparison": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"minLength": 1,
|
|
86
|
+
"maxLength": 1000
|
|
87
|
+
},
|
|
88
|
+
"direction": {
|
|
89
|
+
"type": "string",
|
|
90
|
+
"enum": [
|
|
91
|
+
"up",
|
|
92
|
+
"down",
|
|
93
|
+
"flat"
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
"sentiment": {
|
|
97
|
+
"default": "neutral",
|
|
98
|
+
"type": "string",
|
|
99
|
+
"enum": [
|
|
100
|
+
"positive",
|
|
101
|
+
"negative",
|
|
102
|
+
"neutral"
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"required": [
|
|
107
|
+
"label",
|
|
108
|
+
"value",
|
|
109
|
+
"format",
|
|
110
|
+
"sentiment"
|
|
111
|
+
],
|
|
112
|
+
"additionalProperties": false
|
|
113
|
+
},
|
|
114
|
+
"example": "::metric{label=\"Conversion\" value=\"0.103\" format=\"percent\"}"
|
|
115
|
+
},
|
|
116
|
+
"line": {
|
|
117
|
+
"description": "An interactive single-series line chart from local JSON.",
|
|
118
|
+
"forms": [
|
|
119
|
+
"leaf"
|
|
120
|
+
],
|
|
121
|
+
"children": [],
|
|
122
|
+
"props": {
|
|
123
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
124
|
+
"type": "object",
|
|
125
|
+
"properties": {
|
|
126
|
+
"data": {
|
|
127
|
+
"type": "string",
|
|
128
|
+
"minLength": 1,
|
|
129
|
+
"maxLength": 1000
|
|
130
|
+
},
|
|
131
|
+
"x": {
|
|
132
|
+
"type": "string",
|
|
133
|
+
"minLength": 1,
|
|
134
|
+
"maxLength": 1000
|
|
135
|
+
},
|
|
136
|
+
"y": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"minLength": 1,
|
|
139
|
+
"maxLength": 1000
|
|
140
|
+
},
|
|
141
|
+
"title": {
|
|
142
|
+
"type": "string",
|
|
143
|
+
"minLength": 1,
|
|
144
|
+
"maxLength": 1000
|
|
145
|
+
},
|
|
146
|
+
"format": {
|
|
147
|
+
"default": "number",
|
|
148
|
+
"type": "string",
|
|
149
|
+
"pattern": "^(number|percent|percentage-points|currency:[A-Z]{3})$"
|
|
150
|
+
},
|
|
151
|
+
"xType": {
|
|
152
|
+
"default": "category",
|
|
153
|
+
"type": "string",
|
|
154
|
+
"enum": [
|
|
155
|
+
"category",
|
|
156
|
+
"date",
|
|
157
|
+
"number"
|
|
158
|
+
]
|
|
159
|
+
},
|
|
160
|
+
"target": {
|
|
161
|
+
"type": "number"
|
|
162
|
+
},
|
|
163
|
+
"targetLabel": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"minLength": 1,
|
|
166
|
+
"maxLength": 1000
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"required": [
|
|
170
|
+
"data",
|
|
171
|
+
"x",
|
|
172
|
+
"y",
|
|
173
|
+
"title",
|
|
174
|
+
"format",
|
|
175
|
+
"xType"
|
|
176
|
+
],
|
|
177
|
+
"additionalProperties": false
|
|
178
|
+
},
|
|
179
|
+
"example": "::line{data=\"./usage.json\" x=\"date\" y=\"teams\" xType=\"date\" title=\"Active teams\"}"
|
|
180
|
+
},
|
|
181
|
+
"area": {
|
|
182
|
+
"description": "A line chart with a restrained area fill.",
|
|
183
|
+
"forms": [
|
|
184
|
+
"leaf"
|
|
185
|
+
],
|
|
186
|
+
"children": [],
|
|
187
|
+
"props": {
|
|
188
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
189
|
+
"type": "object",
|
|
190
|
+
"properties": {
|
|
191
|
+
"data": {
|
|
192
|
+
"type": "string",
|
|
193
|
+
"minLength": 1,
|
|
194
|
+
"maxLength": 1000
|
|
195
|
+
},
|
|
196
|
+
"x": {
|
|
197
|
+
"type": "string",
|
|
198
|
+
"minLength": 1,
|
|
199
|
+
"maxLength": 1000
|
|
200
|
+
},
|
|
201
|
+
"y": {
|
|
202
|
+
"type": "string",
|
|
203
|
+
"minLength": 1,
|
|
204
|
+
"maxLength": 1000
|
|
205
|
+
},
|
|
206
|
+
"title": {
|
|
207
|
+
"type": "string",
|
|
208
|
+
"minLength": 1,
|
|
209
|
+
"maxLength": 1000
|
|
210
|
+
},
|
|
211
|
+
"format": {
|
|
212
|
+
"default": "number",
|
|
213
|
+
"type": "string",
|
|
214
|
+
"pattern": "^(number|percent|percentage-points|currency:[A-Z]{3})$"
|
|
215
|
+
},
|
|
216
|
+
"xType": {
|
|
217
|
+
"default": "category",
|
|
218
|
+
"type": "string",
|
|
219
|
+
"enum": [
|
|
220
|
+
"category",
|
|
221
|
+
"date",
|
|
222
|
+
"number"
|
|
223
|
+
]
|
|
224
|
+
},
|
|
225
|
+
"target": {
|
|
226
|
+
"type": "number"
|
|
227
|
+
},
|
|
228
|
+
"targetLabel": {
|
|
229
|
+
"type": "string",
|
|
230
|
+
"minLength": 1,
|
|
231
|
+
"maxLength": 1000
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
"required": [
|
|
235
|
+
"data",
|
|
236
|
+
"x",
|
|
237
|
+
"y",
|
|
238
|
+
"title",
|
|
239
|
+
"format",
|
|
240
|
+
"xType"
|
|
241
|
+
],
|
|
242
|
+
"additionalProperties": false
|
|
243
|
+
},
|
|
244
|
+
"example": "::area{data=\"./usage.json\" x=\"date\" y=\"teams\" xType=\"date\" title=\"Active teams\" target=\"1600\"}"
|
|
245
|
+
},
|
|
246
|
+
"bar": {
|
|
247
|
+
"description": "An interactive category bar chart with a zero baseline.",
|
|
248
|
+
"forms": [
|
|
249
|
+
"leaf"
|
|
250
|
+
],
|
|
251
|
+
"children": [],
|
|
252
|
+
"props": {
|
|
253
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
254
|
+
"type": "object",
|
|
255
|
+
"properties": {
|
|
256
|
+
"data": {
|
|
257
|
+
"type": "string",
|
|
258
|
+
"minLength": 1,
|
|
259
|
+
"maxLength": 1000
|
|
260
|
+
},
|
|
261
|
+
"x": {
|
|
262
|
+
"type": "string",
|
|
263
|
+
"minLength": 1,
|
|
264
|
+
"maxLength": 1000
|
|
265
|
+
},
|
|
266
|
+
"y": {
|
|
267
|
+
"type": "string",
|
|
268
|
+
"minLength": 1,
|
|
269
|
+
"maxLength": 1000
|
|
270
|
+
},
|
|
271
|
+
"title": {
|
|
272
|
+
"type": "string",
|
|
273
|
+
"minLength": 1,
|
|
274
|
+
"maxLength": 1000
|
|
275
|
+
},
|
|
276
|
+
"format": {
|
|
277
|
+
"default": "number",
|
|
278
|
+
"type": "string",
|
|
279
|
+
"pattern": "^(number|percent|percentage-points|currency:[A-Z]{3})$"
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
"required": [
|
|
283
|
+
"data",
|
|
284
|
+
"x",
|
|
285
|
+
"y",
|
|
286
|
+
"title",
|
|
287
|
+
"format"
|
|
288
|
+
],
|
|
289
|
+
"additionalProperties": false
|
|
290
|
+
},
|
|
291
|
+
"example": "::bar{data=\"./errors.json\" x=\"category\" y=\"count\" title=\"Errors by category\"}"
|
|
292
|
+
},
|
|
293
|
+
"donut": {
|
|
294
|
+
"description": "A part-to-whole donut with a readable legend and native data table.",
|
|
295
|
+
"forms": [
|
|
296
|
+
"leaf"
|
|
297
|
+
],
|
|
298
|
+
"children": [],
|
|
299
|
+
"props": {
|
|
300
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
301
|
+
"type": "object",
|
|
302
|
+
"properties": {
|
|
303
|
+
"data": {
|
|
304
|
+
"type": "string",
|
|
305
|
+
"minLength": 1,
|
|
306
|
+
"maxLength": 1000
|
|
307
|
+
},
|
|
308
|
+
"category": {
|
|
309
|
+
"type": "string",
|
|
310
|
+
"minLength": 1,
|
|
311
|
+
"maxLength": 1000
|
|
312
|
+
},
|
|
313
|
+
"value": {
|
|
314
|
+
"type": "string",
|
|
315
|
+
"minLength": 1,
|
|
316
|
+
"maxLength": 1000
|
|
317
|
+
},
|
|
318
|
+
"title": {
|
|
319
|
+
"type": "string",
|
|
320
|
+
"minLength": 1,
|
|
321
|
+
"maxLength": 1000
|
|
322
|
+
},
|
|
323
|
+
"format": {
|
|
324
|
+
"default": "number",
|
|
325
|
+
"type": "string",
|
|
326
|
+
"pattern": "^(number|percent|percentage-points|currency:[A-Z]{3})$"
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
"required": [
|
|
330
|
+
"data",
|
|
331
|
+
"category",
|
|
332
|
+
"value",
|
|
333
|
+
"title",
|
|
334
|
+
"format"
|
|
335
|
+
],
|
|
336
|
+
"additionalProperties": false
|
|
337
|
+
},
|
|
338
|
+
"example": "::donut{data=\"./plans.json\" category=\"plan\" value=\"teams\" title=\"Teams by plan\"}",
|
|
339
|
+
"dataRules": {
|
|
340
|
+
"category": "Unique nonblank strings of at most 1000 characters; source order is preserved.",
|
|
341
|
+
"value": "Finite nonnegative numbers with a finite sum. Nulls and numeric strings are invalid. All-zero values show an empty state.",
|
|
342
|
+
"maximumRows": 8
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
"funnel": {
|
|
346
|
+
"description": "Ordered stage/progress rows with prepared values, denominators, shares and optional explicit status. Works without JavaScript.",
|
|
347
|
+
"forms": [
|
|
348
|
+
"leaf"
|
|
349
|
+
],
|
|
350
|
+
"children": [],
|
|
351
|
+
"props": {
|
|
352
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
353
|
+
"type": "object",
|
|
354
|
+
"properties": {
|
|
355
|
+
"data": {
|
|
356
|
+
"type": "string",
|
|
357
|
+
"minLength": 1,
|
|
358
|
+
"maxLength": 1000
|
|
359
|
+
},
|
|
360
|
+
"stage": {
|
|
361
|
+
"type": "string",
|
|
362
|
+
"minLength": 1,
|
|
363
|
+
"maxLength": 1000
|
|
364
|
+
},
|
|
365
|
+
"value": {
|
|
366
|
+
"type": "string",
|
|
367
|
+
"minLength": 1,
|
|
368
|
+
"maxLength": 1000
|
|
369
|
+
},
|
|
370
|
+
"total": {
|
|
371
|
+
"type": "string",
|
|
372
|
+
"minLength": 1,
|
|
373
|
+
"maxLength": 1000
|
|
374
|
+
},
|
|
375
|
+
"share": {
|
|
376
|
+
"type": "string",
|
|
377
|
+
"minLength": 1,
|
|
378
|
+
"maxLength": 1000
|
|
379
|
+
},
|
|
380
|
+
"status": {
|
|
381
|
+
"type": "string",
|
|
382
|
+
"minLength": 1,
|
|
383
|
+
"maxLength": 1000
|
|
384
|
+
},
|
|
385
|
+
"title": {
|
|
386
|
+
"type": "string",
|
|
387
|
+
"minLength": 1,
|
|
388
|
+
"maxLength": 1000
|
|
389
|
+
},
|
|
390
|
+
"format": {
|
|
391
|
+
"default": "number",
|
|
392
|
+
"type": "string",
|
|
393
|
+
"pattern": "^(number|percent|percentage-points|currency:[A-Z]{3})$"
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
"required": [
|
|
397
|
+
"data",
|
|
398
|
+
"stage",
|
|
399
|
+
"value",
|
|
400
|
+
"total",
|
|
401
|
+
"share",
|
|
402
|
+
"title",
|
|
403
|
+
"format"
|
|
404
|
+
],
|
|
405
|
+
"additionalProperties": false
|
|
406
|
+
},
|
|
407
|
+
"example": "::funnel{data=\"./funnel.json\" stage=\"stage\" value=\"teams\" total=\"baseline\" share=\"share\" status=\"status\" title=\"Funnel by stage\"}",
|
|
408
|
+
"dataRules": {
|
|
409
|
+
"stage": "Unique nonblank strings of at most 1000 characters; source order is preserved.",
|
|
410
|
+
"value": "Finite nonnegative number no greater than its row's total.",
|
|
411
|
+
"total": "Finite positive denominator supplied per row. No denominator is inferred from adjacent stages.",
|
|
412
|
+
"share": "Prepared ratio from 0 to 1, matching value / total to within 0.0005 (rounding to 0.1 percentage point).",
|
|
413
|
+
"status": [
|
|
414
|
+
"on-target",
|
|
415
|
+
"below-target",
|
|
416
|
+
"at-risk",
|
|
417
|
+
"neutral"
|
|
418
|
+
],
|
|
419
|
+
"maximumRows": 20
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
"table": {
|
|
423
|
+
"description": "A semantic sortable table, with inferred or explicitly formatted columns.",
|
|
424
|
+
"forms": [
|
|
425
|
+
"leaf",
|
|
426
|
+
"container"
|
|
427
|
+
],
|
|
428
|
+
"children": [
|
|
429
|
+
"column"
|
|
430
|
+
],
|
|
431
|
+
"props": {
|
|
432
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
433
|
+
"type": "object",
|
|
434
|
+
"properties": {
|
|
435
|
+
"data": {
|
|
436
|
+
"type": "string",
|
|
437
|
+
"minLength": 1,
|
|
438
|
+
"maxLength": 1000
|
|
439
|
+
},
|
|
440
|
+
"title": {
|
|
441
|
+
"type": "string",
|
|
442
|
+
"minLength": 1,
|
|
443
|
+
"maxLength": 1000
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
"required": [
|
|
447
|
+
"data"
|
|
448
|
+
],
|
|
449
|
+
"additionalProperties": false
|
|
450
|
+
},
|
|
451
|
+
"example": ":::table{data=\"./plans.json\" title=\"By plan\"}\n::column{field=\"plan\" label=\"Plan\"}\n::column{field=\"change\" label=\"Δ QoQ\" format=\"percent\" sign=\"always\"}\n:::"
|
|
452
|
+
},
|
|
453
|
+
"column": {
|
|
454
|
+
"description": "An explicit field, label and format inside a table.",
|
|
455
|
+
"forms": [
|
|
456
|
+
"leaf"
|
|
457
|
+
],
|
|
458
|
+
"children": [],
|
|
459
|
+
"props": {
|
|
460
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
461
|
+
"type": "object",
|
|
462
|
+
"properties": {
|
|
463
|
+
"field": {
|
|
464
|
+
"type": "string",
|
|
465
|
+
"minLength": 1,
|
|
466
|
+
"maxLength": 1000
|
|
467
|
+
},
|
|
468
|
+
"label": {
|
|
469
|
+
"type": "string",
|
|
470
|
+
"minLength": 1,
|
|
471
|
+
"maxLength": 1000
|
|
472
|
+
},
|
|
473
|
+
"format": {
|
|
474
|
+
"type": "string",
|
|
475
|
+
"pattern": "^(number|percent|percentage-points|currency:[A-Z]{3})$"
|
|
476
|
+
},
|
|
477
|
+
"sign": {
|
|
478
|
+
"default": "auto",
|
|
479
|
+
"type": "string",
|
|
480
|
+
"enum": [
|
|
481
|
+
"auto",
|
|
482
|
+
"always"
|
|
483
|
+
]
|
|
484
|
+
},
|
|
485
|
+
"semantics": {
|
|
486
|
+
"default": "neutral",
|
|
487
|
+
"type": "string",
|
|
488
|
+
"enum": [
|
|
489
|
+
"neutral",
|
|
490
|
+
"higher-is-better",
|
|
491
|
+
"lower-is-better"
|
|
492
|
+
]
|
|
493
|
+
}
|
|
494
|
+
},
|
|
495
|
+
"required": [
|
|
496
|
+
"field",
|
|
497
|
+
"sign",
|
|
498
|
+
"semantics"
|
|
499
|
+
],
|
|
500
|
+
"additionalProperties": false
|
|
501
|
+
},
|
|
502
|
+
"example": "::column{field=\"change\" label=\"Δ QoQ\" format=\"percent\" sign=\"always\" semantics=\"higher-is-better\"}"
|
|
503
|
+
},
|
|
504
|
+
"callout": {
|
|
505
|
+
"description": "A contextual note or warning containing ordinary Markdown.",
|
|
506
|
+
"forms": [
|
|
507
|
+
"container"
|
|
508
|
+
],
|
|
509
|
+
"children": [
|
|
510
|
+
"markdown"
|
|
511
|
+
],
|
|
512
|
+
"props": {
|
|
513
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
514
|
+
"type": "object",
|
|
515
|
+
"properties": {
|
|
516
|
+
"tone": {
|
|
517
|
+
"default": "note",
|
|
518
|
+
"type": "string",
|
|
519
|
+
"enum": [
|
|
520
|
+
"note",
|
|
521
|
+
"warning"
|
|
522
|
+
]
|
|
523
|
+
},
|
|
524
|
+
"title": {
|
|
525
|
+
"type": "string",
|
|
526
|
+
"minLength": 1,
|
|
527
|
+
"maxLength": 1000
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
"required": [
|
|
531
|
+
"tone"
|
|
532
|
+
],
|
|
533
|
+
"additionalProperties": false
|
|
534
|
+
},
|
|
535
|
+
"example": ":::callout{title=\"Coverage\"}\nSeven complete days of prepared data.\n:::"
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
"rules": [
|
|
539
|
+
"Use explicit closing fences for containers.",
|
|
540
|
+
"Components are standalone blocks, not inline/list/blockquote content.",
|
|
541
|
+
"column is only allowed inside table; grids cannot nest.",
|
|
542
|
+
"direction and explicitly supplied sentiment require metric comparison text.",
|
|
543
|
+
"targetLabel requires target.",
|
|
544
|
+
"Dataset fields are literal own-property keys, not expressions.",
|
|
545
|
+
"Charts preserve source order; date/number x values must increase.",
|
|
546
|
+
"Line/area null y values create gaps; bar null y values are invalid.",
|
|
547
|
+
"Donut category/value fields must differ; category count is bounded, and all-zero values do not create equal slices.",
|
|
548
|
+
"Funnel fields must differ; shares and denominators are supplied, validated and displayed per row, with no sorting or status inference.",
|
|
549
|
+
"Filters, maps, images, nested data and executable components are not supported in this release."
|
|
550
|
+
]
|
|
551
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plotleaf
|
|
3
|
+
description: Create and revise plotleaf Markdown reports from prepared JSON, then validate, preview and export portable interactive HTML. Use for plotleaf report authoring, not development of the reporting engine.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# plotleaf report authoring
|
|
7
|
+
|
|
8
|
+
Create one Markdown file with optional local JSON datasets. The agent retrieves, analyses and prepares data; plotleaf renders it. Do not scaffold an application or put analysis code, SQL, JavaScript expressions or scripts into the report.
|
|
9
|
+
|
|
10
|
+
Use an installed `plotleaf` CLI or `npx plotleaf`. In an unpublished source checkout, build it with `bun run build` and use `node dist/cli.js` from the package root instead of fetching an npm release.
|
|
11
|
+
|
|
12
|
+
## Discover the contract
|
|
13
|
+
|
|
14
|
+
Run `plotleaf schema` (or `npx plotleaf schema`) for the current machine-readable component/prop specifications, rules and input limits. Prefer that output over remembered syntax. Supported components in 0.2.0 include `grid`, `metric`, `line`, `area`, `bar`, `donut`, `funnel`, `table`, `column` and `callout`. Donut and funnel require plotleaf 0.2.0 or newer; check the installed CLI's schema when using an older version.
|
|
15
|
+
|
|
16
|
+
Use ordinary Markdown for headings, prose, findings, emphasis, lists, links and dividers. Headings provide sections. Design is built in; do not add custom CSS, raw HTML or framework components. Filters, maps, image/sparkline cells and executable/custom components are future capabilities, not supported syntax.
|
|
17
|
+
|
|
18
|
+
## Author prepared content
|
|
19
|
+
|
|
20
|
+
```markdown
|
|
21
|
+
---
|
|
22
|
+
title: Adoption report
|
|
23
|
+
description: Team adoption and growth from prepared data.
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# Adoption report
|
|
27
|
+
|
|
28
|
+
An overview of the prepared dataset, its period and relevant findings.
|
|
29
|
+
|
|
30
|
+
:::grid{columns="2"}
|
|
31
|
+
::metric{label="Teams" value="1492" comparison="34% vs previous quarter" direction="up" sentiment="positive"}
|
|
32
|
+
::metric{label="Conversion" value="0.103" format="percent"}
|
|
33
|
+
:::
|
|
34
|
+
|
|
35
|
+
::area{data="./usage.json" x="date" y="teams" xType="date" title="Teams with an alert" target="1600" targetLabel="Target"}
|
|
36
|
+
|
|
37
|
+
:::table{data="./plans.json" title="By plan"}
|
|
38
|
+
::column{field="plan" label="Plan"}
|
|
39
|
+
::column{field="teams" label="Teams" format="number"}
|
|
40
|
+
::column{field="change" label="Δ QoQ" format="percent" sign="always" semantics="higher-is-better"}
|
|
41
|
+
:::
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Literal attributes are quoted strings, decoded by the component schema. `::` is a leaf; `:::` encloses a container. Close every container explicitly. Use a longer outer fence (`::::grid`) when placing another container, such as a table, inside it. Put components at the document root or in allowed component containers, not inline or inside lists/blockquotes. `column` belongs only inside a table. A plain `::table{data="./file.json"}` infers all fields; explicit columns select/order/format fields and exclude unused columns from export.
|
|
45
|
+
|
|
46
|
+
- Datasets are JSON arrays of flat scalar records. Paths resolve from the Markdown file's directory. Keep them there or in subdirectories; remote, hidden, absolute and outside-root/symlink paths are rejected.
|
|
47
|
+
- Chart fields are literal keys. Charts do not aggregate, join or sort. Prepare a distinct category per bar; date/number x values must be unique and increasing. `xType="date"` accepts real `YYYY-MM-DD` dates or timestamps with an explicit zone. Dates are displayed in UTC.
|
|
48
|
+
- y values are finite JSON numbers. Line/area nulls create gaps; bar nulls are invalid. Missing fields are errors. Empty arrays produce an explicit no-data state and a warning.
|
|
49
|
+
- Table records have consistent keys and non-null types per column. Scalar values stay text; no HTML cell templates. Sorting uses raw values. Use a smaller prepared summary if validation reports table/point limits; the engine never truncates silently.
|
|
50
|
+
- Numeric formats are `number`, `percent`, `percentage-points` and `currency:GBP` (validated ISO code). Percent uses ratios (`0.12` → 12%); percentage-points uses point values (`0.8` → 0.8 pt); currency uses major units. Whole currency amounts omit `.00`; nonzero cents retain two decimal places. Formatting uses `en-GB`.
|
|
51
|
+
- Metrics, comparisons and business sentiment are supplied by the agent. An increase is not automatically positive. Comparison direction and sentiment are independent; both require comparison text when explicitly supplied. Numeric table changes can declare `higher-is-better` or `lower-is-better` semantics.
|
|
52
|
+
- Include data period, provenance and limitations in the prose where they help readers assess the report. Do not invent findings or imply filters/refresh that the file does not provide.
|
|
53
|
+
|
|
54
|
+
## Part-to-whole and stage views
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
::donut{data="./plans.json" category="plan" value="teams" title="Teams by plan"}
|
|
58
|
+
::funnel{data="./funnel.json" stage="stage" value="teams" total="baseline" share="share" status="status" title="Funnel by stage"}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- Donuts require at most eight unique, nonblank string categories and finite nonnegative values with a finite sum. Prepare mutually exclusive parts of one whole; group a tail into an explicit Other row before rendering if appropriate. Zero values remain in the legend/data; all-zero data is an empty state, never equal slices.
|
|
62
|
+
- Funnel rows supply value, positive denominator and share explicitly, such as `{"stage":"Activated","teams":25,"baseline":100,"share":0.25,"status":"below-target"}`. Shares use ratios and must match value / total within 0.0005 (rounding to 0.1 percentage point). No baseline means an empty array, not a zero denominator.
|
|
63
|
+
- Funnel stage names are unique nonblank strings, with at most 20 stages in source order. Each stage can have its own denominator; explain that choice in prose. Status values are `on-target`, `below-target`, `at-risk` or `neutral`. Omit the status mapping for neutral styling; the engine never infers business status. All mapped fields must differ.
|
|
64
|
+
- Use the full-value data disclosures to check counts behind compact funnel labels. Both components retain readable HTML data without JavaScript. Keep the denominator of any nearby conversion KPI explicit when it differs from the funnel baseline.
|
|
65
|
+
|
|
66
|
+
## Validate, preview and export
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npx plotleaf validate report.md --json
|
|
70
|
+
npx plotleaf dev report.md --no-open
|
|
71
|
+
npx plotleaf build report.md --out ./report.html
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Repair diagnostics using their code, one-based source location, message and hint, then validate again. Preview watches Markdown and referenced JSON; an invalid edit displays diagnostics and recovers after repair. Omit `--no-open` to open a browser. No backend/account is required.
|
|
75
|
+
|
|
76
|
+
Export is one self-contained interactive HTML file. Check it after copying it away from sources and disabling networking. Charts require JavaScript; prose, metrics, tables and native chart-data disclosures remain readable without it. All displayed/embedded values are readable by recipients: collapsing a table or hiding a field visually is not redaction. Prepare sensitive data before rendering; explicit-column tables and chart field projection help avoid exporting unused fields.
|
|
77
|
+
|
|
78
|
+
Inspect the result at a narrow viewport and in both system themes. Preserve the source's meaning and the product's quiet editorial design when making revisions.
|