bare-script 4.1.2__tar.gz → 4.1.4__tar.gz
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.
- {bare_script-4.1.2/src/bare_script.egg-info → bare_script-4.1.4}/PKG-INFO +27 -1
- {bare_script-4.1.2 → bare_script-4.1.4}/README.md +26 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/setup.cfg +1 -1
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/data.bare +56 -35
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/dataLineChart.bare +42 -22
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/dataTable.bare +79 -61
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/markdownUp.bare +16 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/qrcode.bare +75 -43
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/parser.py +179 -156
- {bare_script-4.1.2 → bare_script-4.1.4/src/bare_script.egg-info}/PKG-INFO +27 -1
- {bare_script-4.1.2 → bare_script-4.1.4}/LICENSE +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/pyproject.toml +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/setup.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/__init__.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/__main__.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/bare.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/__init__.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/args.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/baredoc.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/baredocCLI.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/dataUtil.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/diff.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/draw.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/elementModel.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/forms.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/markdown.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/markdownElements.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/markdownHighlight.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/markdownParser.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/pager.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/schemaDoc.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/unittest.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/include/unittestMock.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/library.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/model.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/options.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/runtime.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/runtime_c.c +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script/value.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script.egg-info/SOURCES.txt +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script.egg-info/dependency_links.txt +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script.egg-info/entry_points.txt +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script.egg-info/requires.txt +0 -0
- {bare_script-4.1.2 → bare_script-4.1.4}/src/bare_script.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bare-script
|
|
3
|
-
Version: 4.1.
|
|
3
|
+
Version: 4.1.4
|
|
4
4
|
Summary: bare-script
|
|
5
5
|
Home-page: https://github.com/craigahobbs/bare-script
|
|
6
6
|
Author: Craig A. Hobbs
|
|
@@ -199,6 +199,32 @@ automatically; otherwise the pure-Python runtime is used as a fallback. Set the
|
|
|
199
199
|
variable `BARESCRIPT_RUNTIME_PY=1` to force the pure-Python runtime.
|
|
200
200
|
|
|
201
201
|
|
|
202
|
+
## Using BareScript with an AI Assistant
|
|
203
|
+
|
|
204
|
+
This repository ships a
|
|
205
|
+
[`SKILL.md`](https://github.com/craigahobbs/bare-script-py/blob/main/SKILL.md)
|
|
206
|
+
file that teaches an AI coding assistant how to write idiomatic BareScript — language syntax, the
|
|
207
|
+
built-in and include libraries, the MarkdownUp application pattern, and the unit-test conventions.
|
|
208
|
+
It is plain Markdown and applies to either BareScript implementation.
|
|
209
|
+
|
|
210
|
+
For [Claude Code](https://claude.com/claude-code) and other tools that follow the
|
|
211
|
+
[Agent Skills](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview)
|
|
212
|
+
convention, install it as a project or user skill:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
mkdir -p .claude/skills/bare-script
|
|
216
|
+
cp SKILL.md .claude/skills/bare-script/SKILL.md
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Use `~/.claude/skills/bare-script/SKILL.md` instead to make it available across all projects. For
|
|
220
|
+
other assistants, include the file's contents in your system prompt or rules file.
|
|
221
|
+
|
|
222
|
+
Once installed, you can prompt the assistant with tasks like:
|
|
223
|
+
|
|
224
|
+
> Build a MarkdownUp application that plays tic-tac-toe against the user, with a reset button
|
|
225
|
+
> and a running win/loss/draw tally rendered as a bar chart.
|
|
226
|
+
|
|
227
|
+
|
|
202
228
|
## Development
|
|
203
229
|
|
|
204
230
|
This package is developed using [python-build](https://github.com/craigahobbs/python-build#readme).
|
|
@@ -174,6 +174,32 @@ automatically; otherwise the pure-Python runtime is used as a fallback. Set the
|
|
|
174
174
|
variable `BARESCRIPT_RUNTIME_PY=1` to force the pure-Python runtime.
|
|
175
175
|
|
|
176
176
|
|
|
177
|
+
## Using BareScript with an AI Assistant
|
|
178
|
+
|
|
179
|
+
This repository ships a
|
|
180
|
+
[`SKILL.md`](https://github.com/craigahobbs/bare-script-py/blob/main/SKILL.md)
|
|
181
|
+
file that teaches an AI coding assistant how to write idiomatic BareScript — language syntax, the
|
|
182
|
+
built-in and include libraries, the MarkdownUp application pattern, and the unit-test conventions.
|
|
183
|
+
It is plain Markdown and applies to either BareScript implementation.
|
|
184
|
+
|
|
185
|
+
For [Claude Code](https://claude.com/claude-code) and other tools that follow the
|
|
186
|
+
[Agent Skills](https://docs.claude.com/en/docs/agents-and-tools/agent-skills/overview)
|
|
187
|
+
convention, install it as a project or user skill:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
mkdir -p .claude/skills/bare-script
|
|
191
|
+
cp SKILL.md .claude/skills/bare-script/SKILL.md
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Use `~/.claude/skills/bare-script/SKILL.md` instead to make it available across all projects. For
|
|
195
|
+
other assistants, include the file's contents in your system prompt or rules file.
|
|
196
|
+
|
|
197
|
+
Once installed, you can prompt the assistant with tasks like:
|
|
198
|
+
|
|
199
|
+
> Build a MarkdownUp application that plays tic-tac-toe against the user, with a reset button
|
|
200
|
+
> and a running win/loss/draw tally rendered as a bar chart.
|
|
201
|
+
|
|
202
|
+
|
|
177
203
|
## Development
|
|
178
204
|
|
|
179
205
|
This package is developed using [python-build](https://github.com/craigahobbs/python-build#readme).
|
|
@@ -33,8 +33,8 @@ function dataParseCSV(text):
|
|
|
33
33
|
linePart = line
|
|
34
34
|
while linePart != null:
|
|
35
35
|
# Quoted field?
|
|
36
|
-
mQuoted = regexMatch(dataParseCSVQuotedField, linePart)
|
|
37
|
-
if mQuoted
|
|
36
|
+
mQuoted = stringStartsWith(linePart, '"') && regexMatch(dataParseCSVQuotedField, linePart)
|
|
37
|
+
if mQuoted:
|
|
38
38
|
groups = objectGet(mQuoted, 'groups')
|
|
39
39
|
arrayPush(row, stringReplace(objectGet(groups, '1'), '""', '"'))
|
|
40
40
|
linePart = stringSlice(linePart, stringLength(objectGet(groups, '0')))
|
|
@@ -96,8 +96,8 @@ function dataValidate(data, csv):
|
|
|
96
96
|
types = {}
|
|
97
97
|
for row in data:
|
|
98
98
|
for field in objectKeys(row):
|
|
99
|
-
value = objectGet(row, field)
|
|
100
99
|
if !objectGet(types, field):
|
|
100
|
+
value = objectGet(row, field)
|
|
101
101
|
valueType = systemType(value)
|
|
102
102
|
if valueType == 'boolean':
|
|
103
103
|
objectSet(types, field, 'boolean')
|
|
@@ -137,14 +137,12 @@ function dataValidate(data, csv):
|
|
|
137
137
|
endif
|
|
138
138
|
endfor
|
|
139
139
|
|
|
140
|
-
# Validate field values
|
|
140
|
+
# Validate field values (typeKeys ensures fieldType is always set by the fix-up pass above)
|
|
141
|
+
typeKeys = objectKeys(types)
|
|
141
142
|
for row in data:
|
|
142
|
-
for field in
|
|
143
|
+
for field in typeKeys:
|
|
143
144
|
value = objectGet(row, field)
|
|
144
145
|
fieldType = objectGet(types, field)
|
|
145
|
-
if fieldType == null:
|
|
146
|
-
continue
|
|
147
|
-
endif
|
|
148
146
|
valueType = systemType(value)
|
|
149
147
|
|
|
150
148
|
# Null string?
|
|
@@ -324,10 +322,15 @@ function dataCalculatedField(data, fieldName, expr, variables):
|
|
|
324
322
|
calcExpr = barescriptParseExpression(expr, false)
|
|
325
323
|
|
|
326
324
|
# Compute the calculated field for each row
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
325
|
+
if variables != null:
|
|
326
|
+
for row in data:
|
|
327
|
+
objectSet(row, fieldName, barescriptEvaluateExpression(calcExpr, objectAssign(objectCopy(row), variables)))
|
|
328
|
+
endfor
|
|
329
|
+
else:
|
|
330
|
+
for row in data:
|
|
331
|
+
objectSet(row, fieldName, barescriptEvaluateExpression(calcExpr, row))
|
|
332
|
+
endfor
|
|
333
|
+
endif
|
|
331
334
|
|
|
332
335
|
return data
|
|
333
336
|
endfunction
|
|
@@ -347,12 +350,19 @@ function dataFilter(data, expr, variables):
|
|
|
347
350
|
filterExpr = barescriptParseExpression(expr, false)
|
|
348
351
|
|
|
349
352
|
# Filter the data
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
353
|
+
if variables != null:
|
|
354
|
+
for row in data:
|
|
355
|
+
if barescriptEvaluateExpression(filterExpr, objectAssign(objectCopy(row), variables)):
|
|
356
|
+
arrayPush(result, row)
|
|
357
|
+
endif
|
|
358
|
+
endfor
|
|
359
|
+
else:
|
|
360
|
+
for row in data:
|
|
361
|
+
if barescriptEvaluateExpression(filterExpr, row):
|
|
362
|
+
arrayPush(result, row)
|
|
363
|
+
endif
|
|
364
|
+
endfor
|
|
365
|
+
endif
|
|
356
366
|
|
|
357
367
|
return result
|
|
358
368
|
endfunction
|
|
@@ -374,6 +384,17 @@ function dataAggregate(data, aggregation):
|
|
|
374
384
|
categories = objectGet(aggregation, 'categories')
|
|
375
385
|
measures = objectGet(aggregation, 'measures')
|
|
376
386
|
|
|
387
|
+
# Precompute per-measure metadata: [outputName, inputFieldKey, function]
|
|
388
|
+
measureMeta = []
|
|
389
|
+
for measure in measures:
|
|
390
|
+
measureFieldKey = objectGet(measure, 'field')
|
|
391
|
+
arrayPush(measureMeta, [ \
|
|
392
|
+
objectGet(measure, 'name', measureFieldKey), \
|
|
393
|
+
measureFieldKey, \
|
|
394
|
+
objectGet(measure, 'function') \
|
|
395
|
+
])
|
|
396
|
+
endfor
|
|
397
|
+
|
|
377
398
|
# Create the aggregate rows
|
|
378
399
|
categoryRows = {}
|
|
379
400
|
for row in data:
|
|
@@ -391,7 +412,7 @@ function dataAggregate(data, aggregation):
|
|
|
391
412
|
|
|
392
413
|
# Get or create the aggregate row
|
|
393
414
|
aggregateRow = objectGet(categoryRows, rowKey)
|
|
394
|
-
if aggregateRow
|
|
415
|
+
if !aggregateRow:
|
|
395
416
|
aggregateRow = {}
|
|
396
417
|
objectSet(categoryRows, rowKey, aggregateRow)
|
|
397
418
|
if categories != null:
|
|
@@ -402,13 +423,13 @@ function dataAggregate(data, aggregation):
|
|
|
402
423
|
endif
|
|
403
424
|
|
|
404
425
|
# Accumulate measure values
|
|
405
|
-
for
|
|
406
|
-
|
|
407
|
-
measureValue = objectGet(row,
|
|
408
|
-
measureValues = objectGet(aggregateRow,
|
|
426
|
+
for meta in measureMeta:
|
|
427
|
+
measureName = arrayGet(meta, 0)
|
|
428
|
+
measureValue = objectGet(row, arrayGet(meta, 1))
|
|
429
|
+
measureValues = objectGet(aggregateRow, measureName)
|
|
409
430
|
if measureValues == null:
|
|
410
431
|
measureValues = []
|
|
411
|
-
objectSet(aggregateRow,
|
|
432
|
+
objectSet(aggregateRow, measureName, measureValues)
|
|
412
433
|
endif
|
|
413
434
|
if measureValue != null:
|
|
414
435
|
arrayPush(measureValues, measureValue)
|
|
@@ -421,32 +442,32 @@ function dataAggregate(data, aggregation):
|
|
|
421
442
|
for categoryRowsKey in objectKeys(categoryRows):
|
|
422
443
|
aggregateRow = objectGet(categoryRows, categoryRowsKey)
|
|
423
444
|
arrayPush(aggregateRows, aggregateRow)
|
|
424
|
-
for
|
|
425
|
-
|
|
426
|
-
measureFunc =
|
|
427
|
-
measureValues = objectGet(aggregateRow,
|
|
445
|
+
for meta in measureMeta:
|
|
446
|
+
measureName = arrayGet(meta, 0)
|
|
447
|
+
measureFunc = arrayGet(meta, 2)
|
|
448
|
+
measureValues = objectGet(aggregateRow, measureName)
|
|
428
449
|
if !arrayLength(measureValues):
|
|
429
|
-
objectSet(aggregateRow,
|
|
450
|
+
objectSet(aggregateRow, measureName, null)
|
|
430
451
|
elif measureFunc == 'count':
|
|
431
|
-
objectSet(aggregateRow,
|
|
452
|
+
objectSet(aggregateRow, measureName, arrayLength(measureValues))
|
|
432
453
|
elif measureFunc == 'max':
|
|
433
454
|
maxVal = arrayGet(measureValues, 0)
|
|
434
455
|
for val in measureValues:
|
|
435
456
|
maxVal = if(val > maxVal, val, maxVal)
|
|
436
457
|
endfor
|
|
437
|
-
objectSet(aggregateRow,
|
|
458
|
+
objectSet(aggregateRow, measureName, maxVal)
|
|
438
459
|
elif measureFunc == 'min':
|
|
439
460
|
minVal = arrayGet(measureValues, 0)
|
|
440
461
|
for val in measureValues:
|
|
441
462
|
minVal = if(val < minVal, val, minVal)
|
|
442
463
|
endfor
|
|
443
|
-
objectSet(aggregateRow,
|
|
464
|
+
objectSet(aggregateRow, measureName, minVal)
|
|
444
465
|
elif measureFunc == 'sum':
|
|
445
466
|
sumVal = 0
|
|
446
467
|
for val in measureValues:
|
|
447
468
|
sumVal = sumVal + val
|
|
448
469
|
endfor
|
|
449
|
-
objectSet(aggregateRow,
|
|
470
|
+
objectSet(aggregateRow, measureName, sumVal)
|
|
450
471
|
elif measureFunc == 'stddev':
|
|
451
472
|
sumVal = 0
|
|
452
473
|
for val in measureValues:
|
|
@@ -457,14 +478,14 @@ function dataAggregate(data, aggregation):
|
|
|
457
478
|
for val in measureValues:
|
|
458
479
|
sumSqDiff = sumSqDiff + (val - avgVal) ** 2
|
|
459
480
|
endfor
|
|
460
|
-
objectSet(aggregateRow,
|
|
481
|
+
objectSet(aggregateRow, measureName, mathSqrt(sumSqDiff / arrayLength(measureValues)))
|
|
461
482
|
else:
|
|
462
483
|
# measureFunc == 'average'
|
|
463
484
|
sumVal = 0
|
|
464
485
|
for val in measureValues:
|
|
465
486
|
sumVal = sumVal + val
|
|
466
487
|
endfor
|
|
467
|
-
objectSet(aggregateRow,
|
|
488
|
+
objectSet(aggregateRow, measureName, sumVal / arrayLength(measureValues))
|
|
468
489
|
endif
|
|
469
490
|
endfor
|
|
470
491
|
endfor
|
|
@@ -195,22 +195,27 @@ function dataLineChartElements(data, lineChart, options):
|
|
|
195
195
|
yMin = null
|
|
196
196
|
xMax = null
|
|
197
197
|
yMax = null
|
|
198
|
+
chartPrecision = objectGet(lineChart, 'precision')
|
|
199
|
+
chartDatetime = objectGet(lineChart, 'datetime')
|
|
198
200
|
if colorField != null:
|
|
199
201
|
# Determine the set of color encoding values
|
|
202
|
+
isSingleY = (arrayLength(yFields) == 1)
|
|
200
203
|
colorValueSet = {}
|
|
201
204
|
pointsMap = {}
|
|
202
205
|
for row in data:
|
|
206
|
+
xRow = objectGet(row, xField)
|
|
207
|
+
colorValue = dataUtilFormatValue(objectGet(row, colorField), chartPrecision, chartDatetime)
|
|
203
208
|
for yField in yFields:
|
|
204
|
-
|
|
205
|
-
rowKey = if(arrayLength(yFields) == 1, colorValue, yField + ', ' + colorValue)
|
|
209
|
+
rowKey = if(isSingleY, colorValue, yField + ', ' + colorValue)
|
|
206
210
|
objectSet(colorValueSet, rowKey, true)
|
|
207
|
-
xRow = objectGet(row, xField)
|
|
208
211
|
yRow = objectGet(row, yField)
|
|
209
212
|
if xRow != null && yRow != null:
|
|
210
|
-
|
|
211
|
-
|
|
213
|
+
rowPoints = objectGet(pointsMap, rowKey)
|
|
214
|
+
if rowPoints == null:
|
|
215
|
+
rowPoints = []
|
|
216
|
+
objectSet(pointsMap, rowKey, rowPoints)
|
|
212
217
|
endif
|
|
213
|
-
arrayPush(
|
|
218
|
+
arrayPush(rowPoints, [xRow, yRow])
|
|
214
219
|
xMin = if(xMin == null, xRow, xMin)
|
|
215
220
|
yMin = if(yMin == null, yRow, if(yRow < yMin, yRow, yMin))
|
|
216
221
|
xMax = xRow
|
|
@@ -265,8 +270,6 @@ function dataLineChartElements(data, lineChart, options):
|
|
|
265
270
|
chartTitle = objectGet(lineChart, 'title')
|
|
266
271
|
chartWidth = objectGet(lineChart, 'width', dataLineChartDefaultWidth)
|
|
267
272
|
chartHeight = objectGet(lineChart, 'height', dataLineChartDefaultHeight)
|
|
268
|
-
chartPrecision = objectGet(lineChart, 'precision')
|
|
269
|
-
chartDatetime = objectGet(lineChart, 'datetime')
|
|
270
273
|
|
|
271
274
|
# Compute Y-axis tick values
|
|
272
275
|
yAxisTicks = []
|
|
@@ -515,29 +518,46 @@ function dataLineChartElements(data, lineChart, options):
|
|
|
515
518
|
|
|
516
519
|
# Render lines
|
|
517
520
|
lineElements = []
|
|
521
|
+
xRange = xMax - xMin
|
|
522
|
+
yRange = yMax - yMin
|
|
523
|
+
xScale = if(xRange == 0, 0, (chartRight - chartLeft) / xRange)
|
|
524
|
+
yScale = if(yRange == 0, 0, (chartTop - chartBottom) / yRange)
|
|
525
|
+
svgPrecision = dataLineChartSvgPrecision
|
|
526
|
+
chartLineWidthValue = numberToFixed(dataLineChartChartLineWidth, svgPrecision)
|
|
518
527
|
for linePoint in linePointsReversed:
|
|
519
528
|
linePointColor = objectGet(linePoint, 'color')
|
|
520
529
|
linePointPoints = objectGet(linePoint, 'points')
|
|
521
530
|
linePointParts = []
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
xPoint =
|
|
526
|
-
yPoint =
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
531
|
+
nPoints = arrayLength(linePointPoints)
|
|
532
|
+
if nPoints == 1:
|
|
533
|
+
point = arrayGet(linePointPoints, 0)
|
|
534
|
+
xPoint = chartLeft + (arrayGet(point, 0) - xMin) * xScale
|
|
535
|
+
yPoint = chartBottom + (arrayGet(point, 1) - yMin) * yScale
|
|
536
|
+
yPointStr = numberToFixed(yPoint, svgPrecision)
|
|
537
|
+
arrayPush(linePointParts, \
|
|
538
|
+
'M ' + numberToFixed(xPoint - 0.5 * dataLineChartChartLineWidth, svgPrecision) + ' ' + yPointStr + \
|
|
539
|
+
' L ' + numberToFixed(xPoint + 0.5 * dataLineChartChartLineWidth, svgPrecision) + ' ' + yPointStr)
|
|
540
|
+
else:
|
|
541
|
+
firstPoint = arrayGet(linePointPoints, 0)
|
|
542
|
+
xPoint = chartLeft + (arrayGet(firstPoint, 0) - xMin) * xScale
|
|
543
|
+
yPoint = chartBottom + (arrayGet(firstPoint, 1) - yMin) * yScale
|
|
544
|
+
arrayPush(linePointParts, \
|
|
545
|
+
'M ' + numberToFixed(xPoint, svgPrecision) + ' ' + numberToFixed(yPoint, svgPrecision))
|
|
546
|
+
ixPoint = 1
|
|
547
|
+
while ixPoint < nPoints:
|
|
548
|
+
point = arrayGet(linePointPoints, ixPoint)
|
|
549
|
+
xPoint = chartLeft + (arrayGet(point, 0) - xMin) * xScale
|
|
550
|
+
yPoint = chartBottom + (arrayGet(point, 1) - yMin) * yScale
|
|
532
551
|
arrayPush(linePointParts, \
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
552
|
+
'L ' + numberToFixed(xPoint, svgPrecision) + ' ' + numberToFixed(yPoint, svgPrecision))
|
|
553
|
+
ixPoint = ixPoint + 1
|
|
554
|
+
endwhile
|
|
555
|
+
endif
|
|
536
556
|
arrayPush(lineElements, { \
|
|
537
557
|
'svg': 'path', \
|
|
538
558
|
'attr': { \
|
|
539
559
|
'stroke': linePointColor, \
|
|
540
|
-
'stroke-width':
|
|
560
|
+
'stroke-width': chartLineWidthValue, \
|
|
541
561
|
'fill': 'none', \
|
|
542
562
|
'd': arrayJoin(linePointParts, ' ') \
|
|
543
563
|
} \
|
|
@@ -111,55 +111,60 @@ function dataTableMarkdown(data, model):
|
|
|
111
111
|
precisionTrim = if(model != null, objectGet(model, 'trim', true), true)
|
|
112
112
|
formats = if(model != null, objectGet(model, 'formats'))
|
|
113
113
|
|
|
114
|
-
#
|
|
114
|
+
# Initialize widths to the field header width
|
|
115
115
|
widths = {}
|
|
116
116
|
for field in fields:
|
|
117
|
-
|
|
118
|
-
if !objectHas(widths, field) || fieldWidth > objectGet(widths, field):
|
|
119
|
-
objectSet(widths, field, fieldWidth)
|
|
120
|
-
endif
|
|
117
|
+
objectSet(widths, field, stringLength(field))
|
|
121
118
|
endfor
|
|
122
119
|
|
|
123
120
|
# Compute the formatted field value strings and widths
|
|
121
|
+
hasDatetimeFormat = precisionDatetime != null
|
|
124
122
|
dataFormat = []
|
|
125
123
|
for row in data:
|
|
126
124
|
rowFormat = {}
|
|
127
125
|
arrayPush(dataFormat, rowFormat)
|
|
128
126
|
for field in fields:
|
|
129
|
-
# Format the value
|
|
127
|
+
# Format the value (newline regex only on string/other types - numbers and datetimes can't contain newlines)
|
|
130
128
|
value = objectGet(row, field)
|
|
131
129
|
valueType = systemType(value)
|
|
132
|
-
if valueType == '
|
|
133
|
-
valueFormat = stringTrim(value)
|
|
134
|
-
elif valueType == 'number':
|
|
130
|
+
if valueType == 'number':
|
|
135
131
|
valueFormat = numberToFixed(value, precisionNumber, precisionTrim)
|
|
136
132
|
elif valueType == 'datetime':
|
|
137
|
-
valueFormat = datetimeISOFormat(value,
|
|
133
|
+
valueFormat = datetimeISOFormat(value, hasDatetimeFormat)
|
|
138
134
|
else:
|
|
139
|
-
valueFormat = stringNew(value)
|
|
135
|
+
valueFormat = if(valueType == 'string', stringTrim(value), stringNew(value))
|
|
136
|
+
valueFormat = regexReplace(dataTableMarkdownRegexMultipleNewline, valueFormat, '<br><br>')
|
|
137
|
+
valueFormat = regexReplace(dataTableMarkdownRegexSingleNewline, valueFormat, ' ')
|
|
140
138
|
endif
|
|
141
139
|
|
|
142
|
-
# Eliminate value string newlines
|
|
143
|
-
valueFormat = regexReplace(dataTableMarkdownRegexMultipleNewline, valueFormat, '<br><br>')
|
|
144
|
-
valueFormat = regexReplace(dataTableMarkdownRegexSingleNewline, valueFormat, ' ')
|
|
145
|
-
|
|
146
140
|
# Set the field value string
|
|
147
141
|
objectSet(rowFormat, field, valueFormat)
|
|
148
142
|
|
|
149
|
-
# Update the field width
|
|
143
|
+
# Update the field width (widths is initialized above for every field)
|
|
150
144
|
valueWidth = stringLength(valueFormat)
|
|
151
|
-
if
|
|
145
|
+
if valueWidth > objectGet(widths, field):
|
|
152
146
|
objectSet(widths, field, valueWidth)
|
|
153
147
|
endif
|
|
154
148
|
endfor
|
|
155
149
|
endfor
|
|
156
150
|
|
|
157
|
-
#
|
|
158
|
-
|
|
151
|
+
# Precompute per-field rendering metadata: [field, width, align, header]
|
|
152
|
+
fieldMeta = []
|
|
159
153
|
for field in fields:
|
|
160
|
-
width = objectGet(widths, field)
|
|
161
154
|
format = if(formats != null, objectGet(formats, field))
|
|
162
|
-
|
|
155
|
+
arrayPush(fieldMeta, [ \
|
|
156
|
+
field, \
|
|
157
|
+
objectGet(widths, field), \
|
|
158
|
+
if(format != null, objectGet(format, 'align')), \
|
|
159
|
+
if(format != null, objectGet(format, 'header', field), field) \
|
|
160
|
+
])
|
|
161
|
+
endfor
|
|
162
|
+
|
|
163
|
+
# Compute the field header separator
|
|
164
|
+
headerSeparator = ''
|
|
165
|
+
for meta in fieldMeta:
|
|
166
|
+
width = arrayGet(meta, 1)
|
|
167
|
+
align = arrayGet(meta, 2)
|
|
163
168
|
alignLeft = if(align == 'center', ':', '-')
|
|
164
169
|
alignRight = if(align == 'center' || align == 'right', ':', '-')
|
|
165
170
|
headerSeparator = headerSeparator + '|' + alignLeft + dataTableMarkdownField('', width, align, '-') + alignRight
|
|
@@ -168,11 +173,10 @@ function dataTableMarkdown(data, model):
|
|
|
168
173
|
|
|
169
174
|
# Compute the table header fields
|
|
170
175
|
headerFields = ''
|
|
171
|
-
for
|
|
172
|
-
width =
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
header = if(format != null, objectGet(format, 'header', field), field)
|
|
176
|
+
for meta in fieldMeta:
|
|
177
|
+
width = arrayGet(meta, 1)
|
|
178
|
+
align = arrayGet(meta, 2)
|
|
179
|
+
header = arrayGet(meta, 3)
|
|
176
180
|
headerFields = headerFields + '| ' + dataTableMarkdownField(header, width, align, ' ') + ' '
|
|
177
181
|
endfor
|
|
178
182
|
headerFields = headerFields + '|'
|
|
@@ -184,15 +188,14 @@ function dataTableMarkdown(data, model):
|
|
|
184
188
|
|
|
185
189
|
# Output each row
|
|
186
190
|
for row in dataFormat:
|
|
187
|
-
|
|
188
|
-
for
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
align =
|
|
192
|
-
|
|
191
|
+
parts = []
|
|
192
|
+
for meta in fieldMeta:
|
|
193
|
+
field = arrayGet(meta, 0)
|
|
194
|
+
width = arrayGet(meta, 1)
|
|
195
|
+
align = arrayGet(meta, 2)
|
|
196
|
+
arrayPush(parts, dataTableMarkdownField(objectGet(row, field), width, align, ' '))
|
|
193
197
|
endfor
|
|
194
|
-
|
|
195
|
-
arrayPush(lines, line)
|
|
198
|
+
arrayPush(lines, '| ' + arrayJoin(parts, ' | ') + ' |')
|
|
196
199
|
endfor
|
|
197
200
|
|
|
198
201
|
return lines
|
|
@@ -271,20 +274,34 @@ function dataTableElements(data, dataTable):
|
|
|
271
274
|
resultRows = []
|
|
272
275
|
resultElements = {'html': 'table', 'elem': resultRows}
|
|
273
276
|
|
|
274
|
-
#
|
|
275
|
-
headerRowElements = []
|
|
277
|
+
# Precompute per-field metadata: [field, isCategory, attr, isMarkdown, headerText]
|
|
276
278
|
fieldArrays = [categories, tableFields]
|
|
277
|
-
|
|
279
|
+
fieldMeta = []
|
|
280
|
+
for fieldArray, ixFieldArray in fieldArrays:
|
|
281
|
+
isCategory = ixFieldArray == 0
|
|
278
282
|
for field in fieldArray:
|
|
279
283
|
fieldFormat = if(fieldFormats != null, objectGet(fieldFormats, field))
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
284
|
+
arrayPush(fieldMeta, [ \
|
|
285
|
+
field, \
|
|
286
|
+
isCategory, \
|
|
287
|
+
dataTableElementsFieldAttr(fieldFormat), \
|
|
288
|
+
fieldFormat != null && objectGet(fieldFormat, 'markdown'), \
|
|
289
|
+
if(fieldFormat != null, objectGet(fieldFormat, 'header')) || field \
|
|
290
|
+
])
|
|
286
291
|
endfor
|
|
287
292
|
endfor
|
|
293
|
+
|
|
294
|
+
# Header row
|
|
295
|
+
headerRowElements = []
|
|
296
|
+
for meta in fieldMeta:
|
|
297
|
+
fieldAttr = arrayGet(meta, 2)
|
|
298
|
+
headerText = arrayGet(meta, 4)
|
|
299
|
+
arrayPush(headerRowElements, { \
|
|
300
|
+
'html': 'th', \
|
|
301
|
+
'attr': fieldAttr, \
|
|
302
|
+
'elem': {'text': headerText} \
|
|
303
|
+
})
|
|
304
|
+
endfor
|
|
288
305
|
arrayPush(resultRows, {'html': 'tr', 'elem': headerRowElements})
|
|
289
306
|
|
|
290
307
|
# Generate the data table's element model
|
|
@@ -292,26 +309,27 @@ function dataTableElements(data, dataTable):
|
|
|
292
309
|
rowPrev = if(ixRow > 0, arrayGet(data, ixRow - 1))
|
|
293
310
|
skip = rowPrev != null
|
|
294
311
|
fieldRowElements = []
|
|
295
|
-
for
|
|
296
|
-
|
|
297
|
-
|
|
312
|
+
for meta in fieldMeta:
|
|
313
|
+
field = arrayGet(meta, 0)
|
|
314
|
+
fieldAttr = arrayGet(meta, 2)
|
|
315
|
+
isMarkdown = arrayGet(meta, 3)
|
|
316
|
+
value = objectGet(row, field)
|
|
298
317
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
318
|
+
# Skip this value?
|
|
319
|
+
if skip:
|
|
320
|
+
isCategory = arrayGet(meta, 1)
|
|
321
|
+
skip = isCategory && systemCompare(value, objectGet(rowPrev, field)) == 0
|
|
322
|
+
endif
|
|
303
323
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
})
|
|
314
|
-
endfor
|
|
324
|
+
fieldElements = if(isMarkdown, \
|
|
325
|
+
markdownElements(markdownParse(stringNew(value))), \
|
|
326
|
+
{'text': dataUtilFormatValue(value, formatPrecision, formatDatetime, formatTrim)} \
|
|
327
|
+
)
|
|
328
|
+
arrayPush(fieldRowElements, { \
|
|
329
|
+
'html': 'td', \
|
|
330
|
+
'attr': fieldAttr, \
|
|
331
|
+
'elem': if(skip, null, fieldElements) \
|
|
332
|
+
})
|
|
315
333
|
endfor
|
|
316
334
|
arrayPush(resultRows, {'html': 'tr', 'elem': fieldRowElements})
|
|
317
335
|
endfor
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
# Licensed under the MIT License
|
|
2
2
|
# https://github.com/craigahobbs/bare-script/blob/main/LICENSE
|
|
3
3
|
|
|
4
|
+
#
|
|
5
|
+
# Stub implementations of the MarkdownUp runtime functions (markdownPrint,
|
|
6
|
+
# elementModelRender, document*, window*, *Storage*) for use under the plain
|
|
7
|
+
# `bare` CLI.
|
|
8
|
+
#
|
|
9
|
+
# DO NOT `include <markdownUp.bare>` from application or test code:
|
|
10
|
+
#
|
|
11
|
+
# - In the real MarkdownUp browser runtime, markdownPrint, elementModelRender,
|
|
12
|
+
# and the document*/window*/*Storage* functions are built-in. Including
|
|
13
|
+
# this file would OVERWRITE the built-ins with the logging stubs, and the
|
|
14
|
+
# app would silently stop rendering.
|
|
15
|
+
# - Under the `bare` CLI, the `-m` / `-l` flags prepend this include for
|
|
16
|
+
# you, so including it again is redundant.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
|
|
4
20
|
include <elementModel.bare>
|
|
5
21
|
include <markdown.bare>
|
|
6
22
|
include <markdownHighlight.bare>
|