@canopycanopycanopy/b-ber-parser-footnotes 3.0.8-nav-memo.2 → 3.0.8-next.100
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/README.md +20 -4
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +358 -387
- package/package.json +16 -20
- package/dist/counter.js +0 -60
package/README.md
CHANGED
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
#
|
|
1
|
+
# b-ber-parser-footnotes
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A markdown-it plugin that parses both inline (`^[…]`) and reference-style (`[^label]` / `[^label]: …`) footnotes from Markdown source and renders them as EPUB-compatible HTML. It emits footnote reference links with `epub:type="noteref"` and footnote list items with `epub:type="footnote"`, and injects hidden back-links (↵) into the footnote body. After processing a document the plugin strips the footnote block from the main token stream and passes it to a callback so the build pipeline can write footnotes to a separate `notes.xhtml` file. A `Counter` helper tracks numbering across pages, supporting both per-document and globally-grouped footnote lists (controlled by `bberState.config.group_footnotes`).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Usage
|
|
6
6
|
|
|
7
|
+
This plugin is consumed by the b-ber build pipeline's `render` and `footnotes` build steps:
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
import footnotePlugin from '@canopycanopycanopy/b-ber-parser-footnotes'
|
|
11
|
+
|
|
12
|
+
md.use(footnotePlugin, footnoteTokens => {
|
|
13
|
+
// footnoteTokens is the extracted footnote block for this document
|
|
14
|
+
})
|
|
7
15
|
```
|
|
8
|
-
|
|
16
|
+
|
|
17
|
+
The callback receives the collected footnote tokens; the pipeline writes them to `notes.xhtml`.
|
|
18
|
+
|
|
19
|
+
## Dev
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
npm test
|
|
9
23
|
```
|
|
24
|
+
|
|
25
|
+
The test suite currently contains only a `test.todo` placeholder — no assertions are implemented yet.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";iBAuIwB,cAAA,CACtB,EAAA,OACA,QAAA,GAAW,MAAA;AAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,401 +1,372 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
23
|
+
let _canopycanopycanopy_b_ber_lib = require("@canopycanopycanopy/b-ber-lib");
|
|
24
|
+
let lodash_isUndefined_js = require("lodash/isUndefined.js");
|
|
25
|
+
lodash_isUndefined_js = __toESM(lodash_isUndefined_js);
|
|
26
|
+
let crypto = require("crypto");
|
|
27
|
+
crypto = __toESM(crypto);
|
|
28
|
+
//#region src/counter.ts
|
|
29
|
+
var Counter = class {
|
|
30
|
+
page;
|
|
31
|
+
list;
|
|
32
|
+
item;
|
|
33
|
+
refs;
|
|
34
|
+
constructor() {
|
|
35
|
+
this.page = -1;
|
|
36
|
+
this.list = 1;
|
|
37
|
+
this.item = 1;
|
|
38
|
+
this.refs = [];
|
|
39
|
+
}
|
|
40
|
+
listCounter(grouped, page) {
|
|
41
|
+
if (page === 0) {
|
|
42
|
+
this.page = -1;
|
|
43
|
+
this.item = 1;
|
|
44
|
+
this.list = 1;
|
|
45
|
+
}
|
|
46
|
+
if (!grouped) return this.item;
|
|
47
|
+
if (page !== this.page) this.list = 1;
|
|
48
|
+
else this.list += 1;
|
|
49
|
+
return this.list;
|
|
50
|
+
}
|
|
51
|
+
listItemCounter(grouped, page) {
|
|
52
|
+
if (!grouped) {
|
|
53
|
+
const n = this.item;
|
|
54
|
+
this.item += 1;
|
|
55
|
+
return n;
|
|
56
|
+
}
|
|
57
|
+
if (page !== this.page) {
|
|
58
|
+
this.page = page;
|
|
59
|
+
this.item = 1;
|
|
60
|
+
} else this.item += 1;
|
|
61
|
+
return this.item;
|
|
62
|
+
}
|
|
63
|
+
setRef = (label) => {
|
|
64
|
+
const idRef = `-${label}-${crypto.default.randomBytes(8).toString("hex")}`;
|
|
65
|
+
this.refs.push(idRef);
|
|
66
|
+
return idRef;
|
|
67
|
+
};
|
|
68
|
+
getRef = () => this.refs.shift();
|
|
69
|
+
};
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/index.ts
|
|
72
|
+
const counter = new Counter();
|
|
21
73
|
function renderFootnoteAnchorName(tokens, idx, _options, env, _slf) {
|
|
22
|
-
|
|
23
|
-
|
|
74
|
+
const n = Number(tokens[idx].meta.id + 1).toString();
|
|
75
|
+
return typeof env.docId === "string" ? `-${env.docId}-${n}` : "";
|
|
24
76
|
}
|
|
25
77
|
function renderFootnoteCaption(tokens, idx, _options, _env, _slf) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
n = Number(tokens[idx].meta.id + 1);
|
|
31
|
-
}
|
|
32
|
-
return tokens[idx].meta.subId > 0 ? `${n}:${tokens[idx].meta.subId}` : n;
|
|
78
|
+
let n;
|
|
79
|
+
if (!_canopycanopycanopy_b_ber_lib.State.config.group_footnotes) n = counter.listItemCounter(_canopycanopycanopy_b_ber_lib.State.config.group_footnotes, _canopycanopycanopy_b_ber_lib.State.footnotes.length);
|
|
80
|
+
else n = Number(tokens[idx].meta.id + 1);
|
|
81
|
+
return tokens[idx].meta.subId > 0 ? `${n}:${tokens[idx].meta.subId}` : n;
|
|
33
82
|
}
|
|
34
83
|
function renderFootnoteRef(tokens, idx, options, env, slf) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
84
|
+
const caption = slf.rules.footnote_caption(tokens, idx, options, env, slf);
|
|
85
|
+
const ref = counter.getRef();
|
|
86
|
+
return `<a epub:type="noteref" class="footnote-ref" href="notes.xhtml#fn${ref}" id="fnref${ref}">${caption}</a>`;
|
|
38
87
|
}
|
|
39
|
-
function renderFootnoteBlockOpen(
|
|
40
|
-
|
|
41
|
-
const start = counter.listCounter(_State.default.config.group_footnotes, _State.default.footnotes.length);
|
|
42
|
-
return `<ol class="footnotes" start="${start}">`;
|
|
88
|
+
function renderFootnoteBlockOpen() {
|
|
89
|
+
return `<ol class="footnotes" start="${counter.listCounter(_canopycanopycanopy_b_ber_lib.State.config.group_footnotes, _canopycanopycanopy_b_ber_lib.State.footnotes.length)}">`;
|
|
43
90
|
}
|
|
44
91
|
function renderFootnoteBlockClose() {
|
|
45
|
-
|
|
92
|
+
return "</ol>";
|
|
46
93
|
}
|
|
47
94
|
function renderFootnoteOpen(tokens, idx, _options, env, _self) {
|
|
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
|
-
nesting: -1
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
return `<li class="footnote" epub:type="footnote" id="fn${ref}">`;
|
|
95
|
+
const ref = counter.setRef(tokens[idx].meta.label);
|
|
96
|
+
const childIndex = idx + 2;
|
|
97
|
+
if (tokens[childIndex]) {
|
|
98
|
+
if (!Array.isArray(tokens[childIndex].children)) tokens[childIndex].children = [];
|
|
99
|
+
tokens[childIndex].children.push({
|
|
100
|
+
type: "inline",
|
|
101
|
+
attrs: [["hidden", "hidden"], ["class", "hidden-backlink"]],
|
|
102
|
+
tag: "span",
|
|
103
|
+
nesting: 1,
|
|
104
|
+
block: false
|
|
105
|
+
}, {
|
|
106
|
+
type: "inline",
|
|
107
|
+
tag: "a",
|
|
108
|
+
attrs: [["href", `${env.reference}#fnref${ref}`]],
|
|
109
|
+
nesting: 1
|
|
110
|
+
}, {
|
|
111
|
+
type: "text",
|
|
112
|
+
block: false,
|
|
113
|
+
content: "↵"
|
|
114
|
+
}, {
|
|
115
|
+
type: "inline",
|
|
116
|
+
tag: "a",
|
|
117
|
+
nesting: -1
|
|
118
|
+
}, {
|
|
119
|
+
type: "inline",
|
|
120
|
+
tag: "span",
|
|
121
|
+
nesting: -1
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return `<li class="footnote" epub:type="footnote" id="fn${ref}">`;
|
|
82
125
|
}
|
|
83
126
|
function renderFootnoteClose() {
|
|
84
|
-
|
|
127
|
+
return "</li>";
|
|
85
128
|
}
|
|
86
|
-
function renderFootnoteAnchor(
|
|
87
|
-
|
|
88
|
-
/* ↩ with escape code to prevent display as Apple Emoji on iOS */
|
|
89
|
-
// return ' <a href="#fnref' + id + '">\u21a9\uFE0E</a>';
|
|
90
|
-
return '';
|
|
129
|
+
function renderFootnoteAnchor() {
|
|
130
|
+
return "";
|
|
91
131
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
token = new state.Token('paragraph_close', 'p', -1);
|
|
334
|
-
token.block = true;
|
|
335
|
-
tokens.push(token);
|
|
336
|
-
} else if (list[i].label) {
|
|
337
|
-
tokens = refTokens[`:${list[i].label}`];
|
|
338
|
-
}
|
|
339
|
-
state.tokens = (0, _concat.default)(_context5 = state.tokens).call(_context5, tokens);
|
|
340
|
-
if (state.tokens[state.tokens.length - 1].type === 'paragraph_close') {
|
|
341
|
-
lastParagraph = state.tokens.pop();
|
|
342
|
-
} else {
|
|
343
|
-
lastParagraph = null;
|
|
344
|
-
}
|
|
345
|
-
t = list[i].count > 0 ? list[i].count : 1;
|
|
346
|
-
for (j = 0; j < t; j++) {
|
|
347
|
-
token = new state.Token('footnote_anchor', '', 0);
|
|
348
|
-
token.meta = {
|
|
349
|
-
id: i,
|
|
350
|
-
subId: j,
|
|
351
|
-
label: list[i].label
|
|
352
|
-
};
|
|
353
|
-
state.tokens.push(token);
|
|
354
|
-
}
|
|
355
|
-
if (lastParagraph) {
|
|
356
|
-
state.tokens.push(lastParagraph);
|
|
357
|
-
}
|
|
358
|
-
token = new state.Token('footnote_close', '', -1);
|
|
359
|
-
state.tokens.push(token);
|
|
360
|
-
}
|
|
361
|
-
token = new state.Token('footnote_block_close', '', -1);
|
|
362
|
-
state.tokens.push(token);
|
|
363
|
-
|
|
364
|
-
// create return value for callback
|
|
365
|
-
insideRef = false;
|
|
366
|
-
footnoteTokens = (0, _filter.default)(_context6 = [...state.tokens]).call(_context6, a => {
|
|
367
|
-
if (a.type === 'footnote_block_open') {
|
|
368
|
-
insideRef = true;
|
|
369
|
-
return true;
|
|
370
|
-
}
|
|
371
|
-
if (a.type === 'footnote_block_close') {
|
|
372
|
-
insideRef = false;
|
|
373
|
-
return true;
|
|
374
|
-
}
|
|
375
|
-
return insideRef;
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
// remove footnotes from `state.tokens`
|
|
379
|
-
insideRef = false;
|
|
380
|
-
state.tokens = (0, _filter.default)(_context7 = state.tokens).call(_context7, _ => {
|
|
381
|
-
if (_.type === 'footnote_block_open') {
|
|
382
|
-
insideRef = true;
|
|
383
|
-
return false;
|
|
384
|
-
}
|
|
385
|
-
if (_.type === 'footnote_block_close') {
|
|
386
|
-
insideRef = false;
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
return !insideRef;
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
// return to MarkdownRenderer class
|
|
393
|
-
callback(footnoteTokens);
|
|
394
|
-
}
|
|
395
|
-
md.block.ruler.before('reference', 'footnote_def', footnoteDef, {
|
|
396
|
-
alt: ['paragraph', 'reference']
|
|
397
|
-
});
|
|
398
|
-
md.inline.ruler.after('image', 'footnote_inline', footnoteInline);
|
|
399
|
-
md.inline.ruler.after('footnote_inline', 'footnote_ref', footnoteRef);
|
|
400
|
-
md.core.ruler.after('inline', 'footnote_tail', footnoteTail);
|
|
401
|
-
};
|
|
132
|
+
function footnotePlugin(md, callback) {
|
|
133
|
+
const { parseLinkLabel } = md.helpers;
|
|
134
|
+
const { isSpace } = md.utils;
|
|
135
|
+
md.renderer.rules.footnote_ref = renderFootnoteRef;
|
|
136
|
+
md.renderer.rules.footnote_block_open = renderFootnoteBlockOpen;
|
|
137
|
+
md.renderer.rules.footnote_block_close = renderFootnoteBlockClose;
|
|
138
|
+
md.renderer.rules.footnote_open = renderFootnoteOpen;
|
|
139
|
+
md.renderer.rules.footnote_close = renderFootnoteClose;
|
|
140
|
+
md.renderer.rules.footnote_anchor = renderFootnoteAnchor;
|
|
141
|
+
md.renderer.rules.footnote_caption = renderFootnoteCaption;
|
|
142
|
+
md.renderer.rules.footnoteAnchorName = renderFootnoteAnchorName;
|
|
143
|
+
function footnoteDef(state, startLine, endLine, silent) {
|
|
144
|
+
const start = state.bMarks[startLine] + state.tShift[startLine];
|
|
145
|
+
const max = state.eMarks[startLine];
|
|
146
|
+
let pos;
|
|
147
|
+
let token;
|
|
148
|
+
let offset;
|
|
149
|
+
let ch;
|
|
150
|
+
if (start + 4 > max) return false;
|
|
151
|
+
if (state.src.charCodeAt(start) !== 91) return false;
|
|
152
|
+
if (state.src.charCodeAt(start + 1) !== 94) return false;
|
|
153
|
+
for (pos = start + 2; pos < max; pos++) {
|
|
154
|
+
if (state.src.charCodeAt(pos) === 32) return false;
|
|
155
|
+
if (state.src.charCodeAt(pos) === 93) break;
|
|
156
|
+
}
|
|
157
|
+
if (pos === start + 2) return false;
|
|
158
|
+
if (pos + 1 >= max || state.src.charCodeAt(++pos) !== 58) return false;
|
|
159
|
+
if (silent) return true;
|
|
160
|
+
pos++;
|
|
161
|
+
if (!state.env.footnotes) state.env.footnotes = {};
|
|
162
|
+
if (!state.env.footnotes.refs) state.env.footnotes.refs = {};
|
|
163
|
+
const label = state.src.slice(start + 2, pos - 2);
|
|
164
|
+
state.env.footnotes.refs[`:${label}`] = -1;
|
|
165
|
+
token = new state.Token("footnote_reference_open", "", 1);
|
|
166
|
+
token.meta = { label };
|
|
167
|
+
token.level = state.level++;
|
|
168
|
+
state.tokens.push(token);
|
|
169
|
+
const oldBMark = state.bMarks[startLine];
|
|
170
|
+
const oldTShift = state.tShift[startLine];
|
|
171
|
+
const oldSCount = state.sCount[startLine];
|
|
172
|
+
const oldParentType = state.parentType;
|
|
173
|
+
const posAfterColon = pos;
|
|
174
|
+
const initial = offset = state.sCount[startLine] + pos - (state.bMarks[startLine] + state.tShift[startLine]);
|
|
175
|
+
while (pos < max) {
|
|
176
|
+
ch = state.src.charCodeAt(pos);
|
|
177
|
+
if (isSpace(ch)) if (ch === 9) offset += 4 - offset % 4;
|
|
178
|
+
else offset++;
|
|
179
|
+
else break;
|
|
180
|
+
pos++;
|
|
181
|
+
}
|
|
182
|
+
state.tShift[startLine] = pos - posAfterColon;
|
|
183
|
+
state.sCount[startLine] = offset - initial;
|
|
184
|
+
state.bMarks[startLine] = posAfterColon;
|
|
185
|
+
state.blkIndent += 4;
|
|
186
|
+
state.parentType = "footnote";
|
|
187
|
+
if (state.sCount[startLine] < state.blkIndent) state.sCount[startLine] += state.blkIndent;
|
|
188
|
+
state.md.block.tokenize(state, startLine, endLine, true);
|
|
189
|
+
state.parentType = oldParentType;
|
|
190
|
+
state.blkIndent -= 4;
|
|
191
|
+
state.tShift[startLine] = oldTShift;
|
|
192
|
+
state.sCount[startLine] = oldSCount;
|
|
193
|
+
state.bMarks[startLine] = oldBMark;
|
|
194
|
+
token = new state.Token("footnote_reference_close", "", -1);
|
|
195
|
+
token.level = --state.level;
|
|
196
|
+
state.tokens.push(token);
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
function footnoteInline(state, silent) {
|
|
200
|
+
const max = state.posMax;
|
|
201
|
+
const start = state.pos;
|
|
202
|
+
let footnoteId;
|
|
203
|
+
let token;
|
|
204
|
+
let tokens;
|
|
205
|
+
if (start + 2 >= max) return false;
|
|
206
|
+
if (state.src.charCodeAt(start) !== 94) return false;
|
|
207
|
+
if (state.src.charCodeAt(start + 1) !== 91) return false;
|
|
208
|
+
const labelStart = start + 2;
|
|
209
|
+
const labelEnd = parseLinkLabel(state, start + 1);
|
|
210
|
+
if (labelEnd < 0) return false;
|
|
211
|
+
if (!silent) {
|
|
212
|
+
if (!state.env.footnotes) state.env.footnotes = {};
|
|
213
|
+
if (!state.env.footnotes.list) state.env.footnotes.list = [];
|
|
214
|
+
footnoteId = state.env.footnotes.list.length;
|
|
215
|
+
state.md.inline.parse(state.src.slice(labelStart, labelEnd), state.md, state.env, tokens = []);
|
|
216
|
+
token = state.push("footnote_ref", "", 0);
|
|
217
|
+
token.meta = { id: footnoteId };
|
|
218
|
+
state.env.footnotes.list[footnoteId] = { tokens };
|
|
219
|
+
}
|
|
220
|
+
state.pos = labelEnd + 1;
|
|
221
|
+
state.posMax = max;
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
function footnoteRef(state, silent) {
|
|
225
|
+
const max = state.posMax;
|
|
226
|
+
const start = state.pos;
|
|
227
|
+
let pos;
|
|
228
|
+
let footnoteId;
|
|
229
|
+
let footnoteSubId;
|
|
230
|
+
let token;
|
|
231
|
+
if (start + 3 > max) return false;
|
|
232
|
+
if (!state.env.footnotes || !state.env.footnotes.refs) return false;
|
|
233
|
+
if (state.src.charCodeAt(start) !== 91) return false;
|
|
234
|
+
if (state.src.charCodeAt(start + 1) !== 94) return false;
|
|
235
|
+
for (pos = start + 2; pos < max; pos++) {
|
|
236
|
+
if (state.src.charCodeAt(pos) === 32) return false;
|
|
237
|
+
if (state.src.charCodeAt(pos) === 10) return false;
|
|
238
|
+
if (state.src.charCodeAt(pos) === 93) break;
|
|
239
|
+
}
|
|
240
|
+
if (pos === start + 2) return false;
|
|
241
|
+
if (pos >= max) return false;
|
|
242
|
+
pos++;
|
|
243
|
+
const label = state.src.slice(start + 2, pos - 1);
|
|
244
|
+
if ((0, lodash_isUndefined_js.default)(state.env.footnotes.refs[`:${label}`])) return false;
|
|
245
|
+
if (!silent) {
|
|
246
|
+
if (!state.env.footnotes.list) state.env.footnotes.list = [];
|
|
247
|
+
if (state.env.footnotes.refs[`:${label}`] < 0) {
|
|
248
|
+
footnoteId = state.env.footnotes.list.length;
|
|
249
|
+
state.env.footnotes.list[footnoteId] = {
|
|
250
|
+
label,
|
|
251
|
+
count: 0
|
|
252
|
+
};
|
|
253
|
+
state.env.footnotes.refs[`:${label}`] = footnoteId;
|
|
254
|
+
} else footnoteId = state.env.footnotes.refs[`:${label}`];
|
|
255
|
+
footnoteSubId = state.env.footnotes.list[footnoteId].count;
|
|
256
|
+
state.env.footnotes.list[footnoteId].count++;
|
|
257
|
+
token = state.push("footnote_ref", "", 0);
|
|
258
|
+
token.meta = {
|
|
259
|
+
id: footnoteId,
|
|
260
|
+
subId: footnoteSubId,
|
|
261
|
+
label
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
state.pos = pos;
|
|
265
|
+
state.posMax = max;
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
function footnoteTail(state) {
|
|
269
|
+
const refTokens = {};
|
|
270
|
+
let i;
|
|
271
|
+
let l;
|
|
272
|
+
let j;
|
|
273
|
+
let t;
|
|
274
|
+
let lastParagraph;
|
|
275
|
+
let token;
|
|
276
|
+
let tokens;
|
|
277
|
+
let current;
|
|
278
|
+
let currentLabel;
|
|
279
|
+
let insideRef = false;
|
|
280
|
+
let footnoteTokens = [];
|
|
281
|
+
if (!state.env.footnotes) return;
|
|
282
|
+
state.tokens = state.tokens.filter((tok) => {
|
|
283
|
+
if (tok.type === "footnote_reference_open") {
|
|
284
|
+
insideRef = true;
|
|
285
|
+
current = [];
|
|
286
|
+
currentLabel = tok.meta.label;
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
if (tok.type === "footnote_reference_close") {
|
|
290
|
+
insideRef = false;
|
|
291
|
+
refTokens[`:${currentLabel}`] = current;
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
if (insideRef) current.push(tok);
|
|
295
|
+
return !insideRef;
|
|
296
|
+
});
|
|
297
|
+
if (!state.env.footnotes.list) return;
|
|
298
|
+
const { list } = state.env.footnotes;
|
|
299
|
+
token = new state.Token("footnote_block_open", "", 1);
|
|
300
|
+
state.tokens.push(token);
|
|
301
|
+
for (i = 0, l = list.length; i < l; i++) {
|
|
302
|
+
token = new state.Token("footnote_open", "", 1);
|
|
303
|
+
token.meta = {
|
|
304
|
+
id: i,
|
|
305
|
+
label: list[i].label
|
|
306
|
+
};
|
|
307
|
+
state.tokens.push(token);
|
|
308
|
+
if (list[i].tokens) {
|
|
309
|
+
tokens = [];
|
|
310
|
+
token = new state.Token("paragraph_open", "p", 1);
|
|
311
|
+
token.block = true;
|
|
312
|
+
tokens.push(token);
|
|
313
|
+
token = new state.Token("inline", "", 0);
|
|
314
|
+
token.children = list[i].tokens;
|
|
315
|
+
token.content = "";
|
|
316
|
+
tokens.push(token);
|
|
317
|
+
token = new state.Token("paragraph_close", "p", -1);
|
|
318
|
+
token.block = true;
|
|
319
|
+
tokens.push(token);
|
|
320
|
+
} else if (list[i].label) tokens = refTokens[`:${list[i].label}`];
|
|
321
|
+
state.tokens = state.tokens.concat(tokens);
|
|
322
|
+
if (state.tokens[state.tokens.length - 1].type === "paragraph_close") lastParagraph = state.tokens.pop();
|
|
323
|
+
else lastParagraph = null;
|
|
324
|
+
t = list[i].count > 0 ? list[i].count : 1;
|
|
325
|
+
for (j = 0; j < t; j++) {
|
|
326
|
+
token = new state.Token("footnote_anchor", "", 0);
|
|
327
|
+
token.meta = {
|
|
328
|
+
id: i,
|
|
329
|
+
subId: j,
|
|
330
|
+
label: list[i].label
|
|
331
|
+
};
|
|
332
|
+
state.tokens.push(token);
|
|
333
|
+
}
|
|
334
|
+
if (lastParagraph) state.tokens.push(lastParagraph);
|
|
335
|
+
token = new state.Token("footnote_close", "", -1);
|
|
336
|
+
state.tokens.push(token);
|
|
337
|
+
}
|
|
338
|
+
token = new state.Token("footnote_block_close", "", -1);
|
|
339
|
+
state.tokens.push(token);
|
|
340
|
+
insideRef = false;
|
|
341
|
+
footnoteTokens = [...state.tokens].filter((a) => {
|
|
342
|
+
if (a.type === "footnote_block_open") {
|
|
343
|
+
insideRef = true;
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
if (a.type === "footnote_block_close") {
|
|
347
|
+
insideRef = false;
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
return insideRef;
|
|
351
|
+
});
|
|
352
|
+
insideRef = false;
|
|
353
|
+
state.tokens = state.tokens.filter((_) => {
|
|
354
|
+
if (_.type === "footnote_block_open") {
|
|
355
|
+
insideRef = true;
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
if (_.type === "footnote_block_close") {
|
|
359
|
+
insideRef = false;
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
return !insideRef;
|
|
363
|
+
});
|
|
364
|
+
callback(footnoteTokens);
|
|
365
|
+
}
|
|
366
|
+
md.block.ruler.before("reference", "footnote_def", footnoteDef, { alt: ["paragraph", "reference"] });
|
|
367
|
+
md.inline.ruler.after("image", "footnote_inline", footnoteInline);
|
|
368
|
+
md.inline.ruler.after("footnote_inline", "footnote_ref", footnoteRef);
|
|
369
|
+
md.core.ruler.after("inline", "footnote_tail", footnoteTail);
|
|
370
|
+
}
|
|
371
|
+
//#endregion
|
|
372
|
+
module.exports = footnotePlugin;
|
package/package.json
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canopycanopycanopy/b-ber-parser-footnotes",
|
|
3
|
-
"version": "3.0.8-
|
|
3
|
+
"version": "3.0.8-next.100+20b74691",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
6
7
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"prepare": "npm run clean && npm run prepare:dist",
|
|
10
|
-
"build": "npm run prepare",
|
|
11
|
-
"watch": "BABEL_ENV=production babel --config-file ../../babel.config.js -d dist/ src/ --watch src",
|
|
8
|
+
"build": "tsdown",
|
|
9
|
+
"typecheck": "tsc --noEmit",
|
|
12
10
|
"test": "jest"
|
|
13
11
|
},
|
|
14
12
|
"author": "Triple Canopy <b-ber@canopycanopycanopy.com> (https://triplecanopy.github.io/)",
|
|
@@ -17,21 +15,19 @@
|
|
|
17
15
|
"access": "public"
|
|
18
16
|
},
|
|
19
17
|
"devDependencies": {
|
|
20
|
-
"@
|
|
21
|
-
"@
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
18
|
+
"@swc/core": "^1.15.40",
|
|
19
|
+
"@swc/jest": "^0.2.39",
|
|
20
|
+
"jest": "^29.7.0",
|
|
21
|
+
"rimraf": "^2.7.1",
|
|
22
|
+
"tsdown": "^0.22.1",
|
|
23
|
+
"typescript": "^6.0.3"
|
|
26
24
|
},
|
|
27
25
|
"dependencies": {
|
|
28
|
-
"@canopycanopycanopy/b-ber-lib": "3.0.8-
|
|
29
|
-
"@canopycanopycanopy/b-ber-logger": "3.0.8-
|
|
30
|
-
"@canopycanopycanopy/b-ber-shapes-directives": "3.0.8-
|
|
31
|
-
"@canopycanopycanopy/b-ber-templates": "3.0.8-
|
|
32
|
-
"lodash": "^4.17.21"
|
|
33
|
-
"lodash.isundefined": "^3.0.1",
|
|
34
|
-
"tar": "^6.1.11"
|
|
26
|
+
"@canopycanopycanopy/b-ber-lib": "3.0.8-next.100+20b74691",
|
|
27
|
+
"@canopycanopycanopy/b-ber-logger": "3.0.8-next.100+20b74691",
|
|
28
|
+
"@canopycanopycanopy/b-ber-shapes-directives": "3.0.8-next.100+20b74691",
|
|
29
|
+
"@canopycanopycanopy/b-ber-templates": "3.0.8-next.100+20b74691",
|
|
30
|
+
"lodash": "^4.17.21"
|
|
35
31
|
},
|
|
36
32
|
"files": [
|
|
37
33
|
"dist"
|
|
@@ -50,5 +46,5 @@
|
|
|
50
46
|
"url": "https://maxwellsimmer.com"
|
|
51
47
|
}
|
|
52
48
|
],
|
|
53
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "20b746918e81513be00a2f04971b00b296850f61"
|
|
54
50
|
}
|
package/dist/counter.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js-stable/object/define-property");
|
|
4
|
-
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
|
|
5
|
-
_Object$defineProperty(exports, "__esModule", {
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.default = void 0;
|
|
9
|
-
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
|
|
10
|
-
var _crypto = _interopRequireDefault(require("crypto"));
|
|
11
|
-
// Keep track of footnotes that have been rendered to start new ordered lists at
|
|
12
|
-
// proper count
|
|
13
|
-
class Counter {
|
|
14
|
-
constructor() {
|
|
15
|
-
(0, _defineProperty2.default)(this, "setRef", label => {
|
|
16
|
-
const hash = _crypto.default.randomBytes(8).toString('hex');
|
|
17
|
-
const idRef = `-${label}-${hash}`;
|
|
18
|
-
this.refs.push(idRef);
|
|
19
|
-
return idRef;
|
|
20
|
-
});
|
|
21
|
-
(0, _defineProperty2.default)(this, "getRef", () => this.refs.shift());
|
|
22
|
-
this.page = -1;
|
|
23
|
-
this.list = 1;
|
|
24
|
-
this.item = 1;
|
|
25
|
-
this.refs = [];
|
|
26
|
-
}
|
|
27
|
-
listCounter(grouped, page) {
|
|
28
|
-
// Reset all counters if the footnotes list is empty. This occurs when
|
|
29
|
-
// running `bber serve`
|
|
30
|
-
if (page === 0) {
|
|
31
|
-
this.page = -1;
|
|
32
|
-
this.item = 1;
|
|
33
|
-
this.list = 1;
|
|
34
|
-
}
|
|
35
|
-
if (!grouped) {
|
|
36
|
-
return this.item;
|
|
37
|
-
}
|
|
38
|
-
if (page !== this.page) {
|
|
39
|
-
this.list = 1;
|
|
40
|
-
} else {
|
|
41
|
-
this.list += 1;
|
|
42
|
-
}
|
|
43
|
-
return this.list;
|
|
44
|
-
}
|
|
45
|
-
listItemCounter(grouped, page) {
|
|
46
|
-
if (!grouped) {
|
|
47
|
-
const n = this.item;
|
|
48
|
-
this.item += 1;
|
|
49
|
-
return n;
|
|
50
|
-
}
|
|
51
|
-
if (page !== this.page) {
|
|
52
|
-
this.page = page;
|
|
53
|
-
this.item = 1;
|
|
54
|
-
} else {
|
|
55
|
-
this.item += 1;
|
|
56
|
-
}
|
|
57
|
-
return this.item;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
var _default = exports.default = Counter;
|