-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathextension.mjs
More file actions
112 lines (106 loc) · 3.11 KB
/
extension.mjs
File metadata and controls
112 lines (106 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
* Extension for adding up points in an assignment.
*
* No more need to stress that point totals don't add up!! 😰
*
* Defines one role:
*
* - `points` displays points and records number in total
*
* And one directives:
*
* - `pointreport` displays a total of points and bonus points for the current document
*
* For example:
*
* ```markdown
* # Assignment
*
* :::{pointreport}
* :::
*
* - Task 1: {points}`2`
* - Task 2: {points}`2 bonus`
* - Task 3: {points}`1`
* ```
*
* Which creates:
*
* **Total points:** 3 (+ 2 bonus points)
*
* - Task 1: **(2 points)**
* - Task 2: **(2 bonus points)**
* - Task 3: **(1 point)**
*
* ---
*
* Based upon minrk's `taskpoint.py` Sphinx plugin:
* https://gist.github.com/minrk/2234020a647643ae88c63b20d3008e0b
*/
const KNOWN_CATEGORIES = ['all', 'bonus'];
const pointReportDirective = {
name: 'pointreport',
doc: 'Report all of the points in a document.',
run() {
// Leave a paragraph of a special kind that we will process later in a transform.
return [{ type: 'paragraph', kind: 'point-report' }];
},
};
const pointsRole = {
name: 'points',
body: { type: String, required: true },
run(data) {
const [_points, category] = data.body.split(/\s/);
const points = Number.parseInt(_points, 10);
if (!_points || isNaN(points)) {
console.error(`Points must be an integer, received: "${_points}"`);
return [];
}
if (category && !KNOWN_CATEGORIES.includes(category)) {
console.warn(`Unknown point category "${category}"`);
}
return [{ type: 'strong', kind: 'points', points, category }];
},
};
const pointsTransform = {
name: 'points-transform',
stage: 'document',
doc: 'Add up all of the points in a document, and transform the `points` role and the `point-report` to text.',
plugin: (utils) => (tree) => {
const totals = {};
const points = utils.selectAll('strong[kind="points"]', tree);
points.forEach((p) => {
totals[p.category ?? 'all'] ??= 0; // initialize if it doesn't exist yet
totals[p.category ?? 'all'] += p.points;
// Modify the strong node in place
p.children = [
{
type: 'text',
value: `(${p.points} ${p.category ? `${p.category} ` : ''}point${
p.points === 1 ? '' : 's'
})`,
},
];
});
const reports = utils.selectAll('paragraph[kind="point-report"]', tree);
reports.forEach((r) => {
r.totals = totals; // Store these for looking up across documents later!
const extraPoints = Object.entries(totals).filter(([kind]) => kind !== 'all');
const bonus = extraPoints.map(([k, p]) => `+ ${p} ${k} points`).join(', ');
// Modify the paragraph node in place
r.children = [
{ type: 'strong', children: [{ type: 'text', value: 'Total Points:' }] },
{ type: 'text', value: ` ${totals['all']}${bonus ? ` (${bonus})` : ''}` },
];
});
},
};
const plugin = {
name: 'Points Extension',
author: 'Rowan Cockett',
license: 'MIT',
directives: [pointReportDirective],
roles: [pointsRole],
transforms: [pointsTransform],
};
export default plugin;