@canopycanopycanopy/b-ber-parser-footnotes 3.0.8-nav-memo.4 → 3.0.8-next.96

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 CHANGED
@@ -1,9 +1,25 @@
1
- # `@canopycanopycanopy/b-ber-parser-footnotes`
1
+ # b-ber-parser-footnotes
2
2
 
3
- The `b-ber-parser-footnotes` package is used internally parse footnotes in Markdown.
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
- ## Install
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
- $ npm i -g @canopycanopycanopy/b-ber-parser-footnotes
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.
@@ -0,0 +1,4 @@
1
+ //#region src/index.d.ts
2
+ declare function footnotePlugin(md: any, callback: (tokens: any[]) => void): void;
3
+ export = footnotePlugin;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -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
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
4
- var _isArray = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/array/is-array"));
5
- var _slice = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/slice"));
6
- var _filter = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/filter"));
7
- var _concat = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/concat"));
8
- var _lodash = _interopRequireDefault(require("lodash.isundefined"));
9
- var _State = _interopRequireDefault(require("@canopycanopycanopy/b-ber-lib/State"));
10
- var _counter = _interopRequireDefault(require("./counter"));
11
- /* eslint-disable camelcase */
12
- /* eslint-disable no-param-reassign,no-plusplus */
13
-
14
- /*
15
- Modified version of markdown-it-footnote@3.0.1
16
- https://github.com//markdown-it/markdown-it-footnote
17
- MIT license
18
- */
19
-
20
- const counter = new _counter.default();
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
- const n = Number(tokens[idx].meta.id + 1).toString();
23
- return typeof env.docId === 'string' ? `-${env.docId}-${n}` : '';
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
- let n;
27
- if (!_State.default.config.group_footnotes) {
28
- n = counter.listItemCounter(_State.default.config.group_footnotes, _State.default.footnotes.length);
29
- } else {
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
- const caption = slf.rules.footnote_caption(tokens, idx, options, env, slf);
36
- const ref = counter.getRef();
37
- return `<a epub:type="noteref" class="footnote-ref" href="notes.xhtml#fn${ref}" id="fnref${ref}">${caption}</a>`;
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( /* tokens, idx, options */
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
- return '</ol>';
92
+ return "</ol>";
46
93
  }
47
94
  function renderFootnoteOpen(tokens, idx, _options, env, _self) {
48
- const ref = counter.setRef(tokens[idx].meta.label);
49
- const childIndex = idx + 2;
50
-
51
- // push the backlink into the parent paragraph
52
- if (tokens[childIndex]) {
53
- if (!(0, _isArray.default)(tokens[childIndex].children)) {
54
- tokens[childIndex].children = [];
55
- }
56
- tokens[childIndex].children.push({
57
- type: 'inline',
58
- attrs: [['hidden', 'hidden'], ['class', 'hidden-backlink']],
59
- tag: 'span',
60
- nesting: 1,
61
- block: false
62
- }, {
63
- type: 'inline',
64
- tag: 'a',
65
- attrs: [['href', `${env.reference}#fnref${ref}`]],
66
- nesting: 1
67
- }, {
68
- type: 'text',
69
- block: false,
70
- content: '\u21B5'
71
- }, {
72
- type: 'inline',
73
- tag: 'a',
74
- nesting: -1
75
- }, {
76
- type: 'inline',
77
- tag: 'span',
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
- return '</li>';
127
+ return "</li>";
85
128
  }
86
- function renderFootnoteAnchor( /*tokens, idx, options,env, slf */
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
- module.exports = function footnotePlugin(md, callback) {
93
- const {
94
- parseLinkLabel
95
- } = md.helpers;
96
- const {
97
- isSpace
98
- } = md.utils;
99
- md.renderer.rules.footnote_ref = renderFootnoteRef;
100
- md.renderer.rules.footnote_block_open = renderFootnoteBlockOpen;
101
- md.renderer.rules.footnote_block_close = renderFootnoteBlockClose;
102
- md.renderer.rules.footnote_open = renderFootnoteOpen;
103
- md.renderer.rules.footnote_close = renderFootnoteClose;
104
- md.renderer.rules.footnote_anchor = renderFootnoteAnchor;
105
-
106
- // helpers (only used in other rules, no tokens are attached to those)
107
- md.renderer.rules.footnote_caption = renderFootnoteCaption;
108
- md.renderer.rules.footnoteAnchorName = renderFootnoteAnchorName;
109
-
110
- // Process footnote block definition
111
- function footnoteDef(state, startLine, endLine, silent) {
112
- var _context;
113
- const start = state.bMarks[startLine] + state.tShift[startLine];
114
- const max = state.eMarks[startLine];
115
- let pos;
116
- let token;
117
- let offset;
118
- let ch;
119
-
120
- // line should be at least 5 chars - "[^x]:"
121
- if (start + 4 > max) return false;
122
- if (state.src.charCodeAt(start) !== 0x5b /* [ */) return false;
123
- if (state.src.charCodeAt(start + 1) !== 0x5e /* ^ */) return false;
124
- for (pos = start + 2; pos < max; pos++) {
125
- if (state.src.charCodeAt(pos) === 0x20) return false;
126
- if (state.src.charCodeAt(pos) === 0x5d /* ] */) {
127
- break;
128
- }
129
- }
130
- if (pos === start + 2) return false; // no empty footnote labels
131
- if (pos + 1 >= max || state.src.charCodeAt(++pos) !== 0x3a /* : */) {
132
- return false;
133
- }
134
- if (silent) return true;
135
- pos++;
136
-
137
- // Footnote is found, start parsing footnote body here
138
-
139
- if (!state.env.footnotes) state.env.footnotes = {};
140
- if (!state.env.footnotes.refs) state.env.footnotes.refs = {};
141
- const label = (0, _slice.default)(_context = state.src).call(_context, start + 2, pos - 2);
142
- state.env.footnotes.refs[`:${label}`] = -1;
143
- token = new state.Token('footnote_reference_open', '', 1);
144
- token.meta = {
145
- label
146
- };
147
- token.level = state.level++;
148
- state.tokens.push(token);
149
- const oldBMark = state.bMarks[startLine];
150
- const oldTShift = state.tShift[startLine];
151
- const oldSCount = state.sCount[startLine];
152
- const oldParentType = state.parentType;
153
- const posAfterColon = pos;
154
-
155
- // eslint-disable-next-line no-multi-assign
156
- const initial = offset = state.sCount[startLine] + pos - (state.bMarks[startLine] + state.tShift[startLine]);
157
- while (pos < max) {
158
- ch = state.src.charCodeAt(pos);
159
- if (isSpace(ch)) {
160
- if (ch === 0x09) {
161
- offset += 4 - offset % 4;
162
- } else {
163
- offset++;
164
- }
165
- } else {
166
- break;
167
- }
168
- pos++;
169
- }
170
- state.tShift[startLine] = pos - posAfterColon;
171
- state.sCount[startLine] = offset - initial;
172
- state.bMarks[startLine] = posAfterColon;
173
- state.blkIndent += 4;
174
- state.parentType = 'footnote';
175
- if (state.sCount[startLine] < state.blkIndent) {
176
- state.sCount[startLine] += state.blkIndent;
177
- }
178
- state.md.block.tokenize(state, startLine, endLine, true);
179
- state.parentType = oldParentType;
180
- state.blkIndent -= 4;
181
- state.tShift[startLine] = oldTShift;
182
- state.sCount[startLine] = oldSCount;
183
- state.bMarks[startLine] = oldBMark;
184
- token = new state.Token('footnote_reference_close', '', -1);
185
- token.level = --state.level;
186
- state.tokens.push(token);
187
- return true;
188
- }
189
-
190
- // Process inline footnotes (^[...])
191
- function footnoteInline(state, silent) {
192
- const max = state.posMax;
193
- const start = state.pos;
194
- let footnoteId;
195
- let token;
196
- let tokens;
197
- if (start + 2 >= max) return false;
198
- if (state.src.charCodeAt(start) !== 0x5e /* ^ */) return false;
199
- if (state.src.charCodeAt(start + 1) !== 0x5b /* [ */) return false;
200
- const labelStart = start + 2;
201
- const labelEnd = parseLinkLabel(state, start + 1);
202
-
203
- // Failed to find ']', so it's not a valid note
204
- if (labelEnd < 0) return false;
205
-
206
- // Found the end of the link, and know for a fact it's a valid link; so
207
- // all that's left to do is to call tokenizer.
208
- if (!silent) {
209
- var _context2;
210
- if (!state.env.footnotes) state.env.footnotes = {};
211
- if (!state.env.footnotes.list) state.env.footnotes.list = [];
212
- footnoteId = state.env.footnotes.list.length;
213
- state.md.inline.parse((0, _slice.default)(_context2 = state.src).call(_context2, labelStart, labelEnd), state.md, state.env, tokens = []);
214
- token = state.push('footnote_ref', '', 0);
215
- token.meta = {
216
- id: footnoteId
217
- };
218
- state.env.footnotes.list[footnoteId] = {
219
- tokens
220
- };
221
- }
222
- state.pos = labelEnd + 1;
223
- state.posMax = max;
224
- return true;
225
- }
226
-
227
- // Process footnote references ([^...])
228
- function footnoteRef(state, silent) {
229
- var _context3;
230
- const max = state.posMax;
231
- const start = state.pos;
232
- let pos;
233
- let footnoteId;
234
- let footnoteSubId;
235
- let token;
236
-
237
- // should be at least 4 chars - "[^x]"
238
- if (start + 3 > max) return false;
239
- if (!state.env.footnotes || !state.env.footnotes.refs) return false;
240
- if (state.src.charCodeAt(start) !== 0x5b /* [ */) return false;
241
- if (state.src.charCodeAt(start + 1) !== 0x5e /* ^ */) return false;
242
- for (pos = start + 2; pos < max; pos++) {
243
- if (state.src.charCodeAt(pos) === 0x20) return false;
244
- if (state.src.charCodeAt(pos) === 0x0a) return false;
245
- if (state.src.charCodeAt(pos) === 0x5d /* ] */) break;
246
- }
247
- if (pos === start + 2) return false; // no empty footnote labels
248
- if (pos >= max) return false;
249
- pos++;
250
- const label = (0, _slice.default)(_context3 = state.src).call(_context3, start + 2, pos - 1);
251
- if ((0, _lodash.default)(state.env.footnotes.refs[`:${label}`])) return false;
252
- if (!silent) {
253
- if (!state.env.footnotes.list) state.env.footnotes.list = [];
254
- if (state.env.footnotes.refs[`:${label}`] < 0) {
255
- footnoteId = state.env.footnotes.list.length;
256
- state.env.footnotes.list[footnoteId] = {
257
- label,
258
- count: 0
259
- };
260
- state.env.footnotes.refs[`:${label}`] = footnoteId;
261
- } else {
262
- footnoteId = state.env.footnotes.refs[`:${label}`];
263
- }
264
- footnoteSubId = state.env.footnotes.list[footnoteId].count;
265
- state.env.footnotes.list[footnoteId].count++;
266
- token = state.push('footnote_ref', '', 0);
267
- token.meta = {
268
- id: footnoteId,
269
- subId: footnoteSubId,
270
- label
271
- };
272
- }
273
- state.pos = pos;
274
- state.posMax = max;
275
- return true;
276
- }
277
-
278
- // Glue footnote tokens to end of token stream
279
- function footnoteTail(state) {
280
- var _context4, _context6, _context7;
281
- const refTokens = {};
282
- let i;
283
- let l;
284
- let j;
285
- let t;
286
- let lastParagraph;
287
- let token;
288
- let tokens;
289
- let current;
290
- let currentLabel;
291
- let insideRef = false;
292
- let footnoteTokens = [];
293
- if (!state.env.footnotes) return;
294
- state.tokens = (0, _filter.default)(_context4 = state.tokens).call(_context4, tok => {
295
- if (tok.type === 'footnote_reference_open') {
296
- insideRef = true;
297
- current = [];
298
- currentLabel = tok.meta.label;
299
- return false;
300
- }
301
- if (tok.type === 'footnote_reference_close') {
302
- insideRef = false;
303
- // prepend ':' to avoid conflict with Object.prototype members
304
- refTokens[`:${currentLabel}`] = current;
305
- return false;
306
- }
307
- if (insideRef) current.push(tok);
308
- return !insideRef;
309
- });
310
- if (!state.env.footnotes.list) return;
311
- const {
312
- list
313
- } = state.env.footnotes;
314
- token = new state.Token('footnote_block_open', '', 1);
315
- state.tokens.push(token);
316
- for (i = 0, l = list.length; i < l; i++) {
317
- var _context5;
318
- token = new state.Token('footnote_open', '', 1);
319
- token.meta = {
320
- id: i,
321
- label: list[i].label
322
- };
323
- state.tokens.push(token);
324
- if (list[i].tokens) {
325
- tokens = [];
326
- token = new state.Token('paragraph_open', 'p', 1);
327
- token.block = true;
328
- tokens.push(token);
329
- token = new state.Token('inline', '', 0);
330
- token.children = list[i].tokens;
331
- token.content = '';
332
- tokens.push(token);
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-nav-memo.4+d47a9aae",
3
+ "version": "3.0.8-next.96+7446845b",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
6
7
  "scripts": {
7
- "prepare:dist": "BABEL_ENV=production babel --config-file ../../babel.config.js -d dist/ src/ --ignore **/__tests__/**",
8
- "clean": "rimraf dist",
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
- "@babel/cli": "^7.10.5",
21
- "@babel/core": "^7.10.5",
22
- "@babel/preset-env": "^7.10.4",
23
- "browserslist": "^4.17.4",
24
- "jest": "^26.6.3",
25
- "rimraf": "^2.7.1"
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-nav-memo.4+d47a9aae",
29
- "@canopycanopycanopy/b-ber-logger": "3.0.8-nav-memo.4+d47a9aae",
30
- "@canopycanopycanopy/b-ber-shapes-directives": "3.0.8-nav-memo.4+d47a9aae",
31
- "@canopycanopycanopy/b-ber-templates": "3.0.8-nav-memo.4+d47a9aae",
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.96+7446845b",
27
+ "@canopycanopycanopy/b-ber-logger": "3.0.8-next.96+7446845b",
28
+ "@canopycanopycanopy/b-ber-shapes-directives": "3.0.8-next.96+7446845b",
29
+ "@canopycanopycanopy/b-ber-templates": "3.0.8-next.96+7446845b",
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": "d47a9aae74dec3e3225e363b2434c7abe0fcf21b"
49
+ "gitHead": "7446845bcda4337bfbc9f75b55a1e0ca805023eb"
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;