uniorg-parse 0.4.5 → 0.5.2
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/lib/entities.js +1 -5
- package/lib/entities.js.map +1 -1
- package/lib/index.d.ts +1 -2
- package/lib/index.js +1 -6
- package/lib/index.js.map +1 -1
- package/lib/parse-options.js +1 -4
- package/lib/parse-options.js.map +1 -1
- package/lib/parser.d.ts +1 -1
- package/lib/parser.js +111 -115
- package/lib/parser.js.map +1 -1
- package/lib/reader.js +50 -59
- package/lib/reader.js.map +1 -1
- package/lib/unified-org-parse.js +4 -6
- package/lib/unified-org-parse.js.map +1 -1
- package/lib/utils.d.ts +1 -1
- package/lib/utils.js +9 -14
- package/lib/utils.js.map +1 -1
- package/package.json +14 -11
- package/lib/parser.spec.d.ts +0 -1
- package/lib/parser.spec.js +0 -507
- package/lib/parser.spec.js.map +0 -1
package/lib/parser.js
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const vfile_1 = __importDefault(require("vfile"));
|
|
8
|
-
const unist_builder_1 = __importDefault(require("unist-builder"));
|
|
9
|
-
const entities_1 = require("./entities");
|
|
10
|
-
const utils_1 = require("./utils");
|
|
11
|
-
const parse_options_1 = require("./parse-options");
|
|
12
|
-
const reader_1 = require("./reader");
|
|
1
|
+
import { VFile } from 'vfile';
|
|
2
|
+
import { u } from 'unist-builder';
|
|
3
|
+
import { getOrgEntity } from './entities.js';
|
|
4
|
+
import { restrictionFor, greaterElements, unescapeCodeInString, escapeRegExp, OrgRegexUtils, } from './utils.js';
|
|
5
|
+
import { defaultOptions } from './parse-options.js';
|
|
6
|
+
import { Reader } from './reader.js';
|
|
13
7
|
/*
|
|
14
8
|
(defun rasen/org-debug ()
|
|
15
9
|
"Show org AST for the current buffer."
|
|
@@ -50,20 +44,19 @@ var ParseMode;
|
|
|
50
44
|
/** Default parsing mode. */
|
|
51
45
|
ParseMode[ParseMode["Default"] = 7] = "Default";
|
|
52
46
|
})(ParseMode || (ParseMode = {}));
|
|
53
|
-
function parse(file, options) {
|
|
54
|
-
return new Parser(
|
|
47
|
+
export function parse(file, options) {
|
|
48
|
+
return new Parser(new VFile(file), options).parse();
|
|
55
49
|
}
|
|
56
|
-
exports.parse = parse;
|
|
57
50
|
class Parser {
|
|
58
51
|
constructor(file, options = {}) {
|
|
59
|
-
this.r = new
|
|
60
|
-
this.options =
|
|
61
|
-
this.re = new
|
|
52
|
+
this.r = new Reader(file);
|
|
53
|
+
this.options = { ...defaultOptions, ...options };
|
|
54
|
+
this.re = new OrgRegexUtils(this.options);
|
|
62
55
|
}
|
|
63
56
|
parse() {
|
|
64
57
|
this.parseEmptyLines();
|
|
65
58
|
const children = this.parseElements(ParseMode.TopComment);
|
|
66
|
-
return
|
|
59
|
+
return u('org-data', { contentsBegin: 0, contentsEnd: this.r.endOffset() }, children);
|
|
67
60
|
}
|
|
68
61
|
// General parsing structure
|
|
69
62
|
parseElements(mode, structure) {
|
|
@@ -78,26 +71,31 @@ class Parser {
|
|
|
78
71
|
prevOffset = offset;
|
|
79
72
|
const element = this.parseElement(mode, structure);
|
|
80
73
|
const type = element.type;
|
|
74
|
+
// @ts-expect-error contentsBegin is not defined for "literals"
|
|
81
75
|
const cbeg = element.contentsBegin;
|
|
76
|
+
// @ts-expect-error contentsBegin is not defined for "literals"
|
|
82
77
|
const cend = element.contentsEnd;
|
|
83
78
|
if (cbeg === undefined || cend === undefined) {
|
|
84
79
|
// do nothing
|
|
85
80
|
}
|
|
86
|
-
else if (
|
|
81
|
+
else if (greaterElements.has(type)) {
|
|
87
82
|
this.r.narrow(cbeg, cend);
|
|
88
83
|
appendChildren(element, this.parseElements(Parser.nextMode(mode, type, true), element.type === 'plain-list' || element.type === 'list-item'
|
|
89
|
-
?
|
|
84
|
+
? // @ts-expect-error Property 'structure' does not exist on type 'OrgData'
|
|
85
|
+
element.structure
|
|
90
86
|
: undefined));
|
|
91
87
|
this.r.widen();
|
|
92
88
|
// Delete structure from lists. It’s only here to facilitate
|
|
93
89
|
// parsing and should not be exposed to the user.
|
|
90
|
+
// @ts-expect-error Property 'structure' does not exist on type 'OrgData'
|
|
94
91
|
if (element.structure) {
|
|
92
|
+
// @ts-expect-error Property 'structure' does not exist on type 'OrgData'
|
|
95
93
|
delete element.structure;
|
|
96
94
|
}
|
|
97
95
|
}
|
|
98
96
|
else {
|
|
99
97
|
this.r.narrow(cbeg, cend);
|
|
100
|
-
appendChildren(element, this.parseObjects(
|
|
98
|
+
appendChildren(element, this.parseObjects(restrictionFor(element.type)));
|
|
101
99
|
this.r.widen();
|
|
102
100
|
}
|
|
103
101
|
elements.push(element);
|
|
@@ -135,7 +133,6 @@ class Parser {
|
|
|
135
133
|
return ParseMode.Default;
|
|
136
134
|
}
|
|
137
135
|
parseElement(mode, structure) {
|
|
138
|
-
var _a, _b;
|
|
139
136
|
// List Item.
|
|
140
137
|
if (mode === ParseMode.ListItem)
|
|
141
138
|
return this.parseListItem(structure);
|
|
@@ -256,7 +253,7 @@ class Parser {
|
|
|
256
253
|
const offset = this.r.offset();
|
|
257
254
|
this.r.advance(this.r.line());
|
|
258
255
|
const nextLineOffset = this.r.offset();
|
|
259
|
-
const firstNonTable =
|
|
256
|
+
const firstNonTable = this.r.match(/^[ \t]*($|[^|])/m)?.index ?? null;
|
|
260
257
|
this.r.advance(firstNonTable);
|
|
261
258
|
const isTable = this.r.offset() > nextLineOffset && this.r.lookingAt(ruleRe);
|
|
262
259
|
this.r.resetOffset(offset);
|
|
@@ -296,13 +293,15 @@ class Parser {
|
|
|
296
293
|
if (objectBegin !== prevEnd) {
|
|
297
294
|
// parse text before object
|
|
298
295
|
const value = this.r.substring(prevEnd, objectBegin);
|
|
299
|
-
objects.push(
|
|
296
|
+
objects.push(u('text', { value }));
|
|
300
297
|
}
|
|
298
|
+
// @ts-expect-error contentsBegin is not defined for "literals"
|
|
301
299
|
const cbeg = o.contentsBegin;
|
|
300
|
+
// @ts-expect-error contentsBegin is not defined for "literals"
|
|
302
301
|
const cend = o.contentsEnd;
|
|
303
302
|
if (cbeg !== undefined && cend !== undefined) {
|
|
304
303
|
this.r.narrow(cbeg, cend);
|
|
305
|
-
appendChildren(o, this.parseObjects(
|
|
304
|
+
appendChildren(o, this.parseObjects(restrictionFor(o.type)));
|
|
306
305
|
this.r.widen();
|
|
307
306
|
}
|
|
308
307
|
objects.push(o);
|
|
@@ -313,7 +312,7 @@ class Parser {
|
|
|
313
312
|
const text = this.r.rest();
|
|
314
313
|
this.r.advance(text.length);
|
|
315
314
|
if (text.trim().length) {
|
|
316
|
-
objects.push(
|
|
315
|
+
objects.push(u('text', { value: text }));
|
|
317
316
|
}
|
|
318
317
|
return objects;
|
|
319
318
|
}
|
|
@@ -468,26 +467,25 @@ class Parser {
|
|
|
468
467
|
? this.r.offset() + endOfSubtree.index
|
|
469
468
|
: this.r.endOffset();
|
|
470
469
|
this.r.resetOffset(contentsEnd);
|
|
471
|
-
return
|
|
470
|
+
return u('section', { contentsBegin, contentsEnd }, []);
|
|
472
471
|
}
|
|
473
472
|
parseHeadline() {
|
|
474
|
-
var _a, _b, _c;
|
|
475
473
|
const begin = this.r.offset();
|
|
476
474
|
this.r.advance(this.r.line());
|
|
477
475
|
this.r.narrow(begin, this.r.offset());
|
|
478
476
|
const stars = this.r.advance(this.r.forceLookingAt(/^(\*+)[ \t]+/));
|
|
479
477
|
const level = stars[1].length;
|
|
480
478
|
const todoM = this.r.advance(this.r.lookingAt(new RegExp('^' + this.options.todoKeywords.join('|'))));
|
|
481
|
-
const todoKeyword =
|
|
479
|
+
const todoKeyword = todoM?.[0] ?? null;
|
|
482
480
|
this.r.advance(this.r.lookingAt(/^[ \t]*/));
|
|
483
481
|
const priorityM = this.r.advance(this.r.lookingAt(/^\[#.\]/));
|
|
484
|
-
const priority =
|
|
482
|
+
const priority = priorityM?.[0][2] ?? null;
|
|
485
483
|
this.r.advance(this.r.lookingAt(/^[ \t]*/));
|
|
486
484
|
const commented = !!this.r.advance(this.r.lookingAt(/^COMMENT/));
|
|
487
485
|
this.r.advance(this.r.lookingAt(/^[ \t]*/));
|
|
488
486
|
const titleStart = this.r.offset();
|
|
489
487
|
const tagsM = this.r.lookingAt(/^(.*?)[ \t]+:([\w@#%:]+):[ \t]*$/m);
|
|
490
|
-
const tags =
|
|
488
|
+
const tags = tagsM?.[2].split(':') ?? [];
|
|
491
489
|
const titleEnd = tagsM
|
|
492
490
|
? titleStart + tagsM.index + tagsM[1].length
|
|
493
491
|
: titleStart + this.r.forceLookingAt(/.*/)[0].length;
|
|
@@ -497,7 +495,7 @@ class Parser {
|
|
|
497
495
|
// Reset line restriction.
|
|
498
496
|
this.r.widen();
|
|
499
497
|
this.parseEmptyLines();
|
|
500
|
-
return
|
|
498
|
+
return u('headline', {
|
|
501
499
|
level,
|
|
502
500
|
todoKeyword,
|
|
503
501
|
priority,
|
|
@@ -531,7 +529,7 @@ class Parser {
|
|
|
531
529
|
this.r.widen();
|
|
532
530
|
this.r.advance(this.r.line());
|
|
533
531
|
this.parseEmptyLines();
|
|
534
|
-
return
|
|
532
|
+
return u('planning', { scheduled, deadline, closed });
|
|
535
533
|
}
|
|
536
534
|
parsePropertyDrawer() {
|
|
537
535
|
this.r.advance(this.r.line());
|
|
@@ -541,7 +539,7 @@ class Parser {
|
|
|
541
539
|
const contentsEnd = this.r.offset();
|
|
542
540
|
this.r.advance(this.r.line());
|
|
543
541
|
this.parseEmptyLines();
|
|
544
|
-
return
|
|
542
|
+
return u('property-drawer', { contentsBegin, contentsEnd }, []);
|
|
545
543
|
}
|
|
546
544
|
parseBlock(type, pattern, affiliated) {
|
|
547
545
|
const endM = this.r.match(new RegExp(`^[ \\t]*#\\+end_${pattern}[ \\t]*$`, 'im'));
|
|
@@ -556,7 +554,7 @@ class Parser {
|
|
|
556
554
|
this.r.advance(this.r.line());
|
|
557
555
|
this.parseEmptyLines();
|
|
558
556
|
const _end = this.r.offset();
|
|
559
|
-
return
|
|
557
|
+
return u(type, { affiliated, contentsBegin, contentsEnd }, []);
|
|
560
558
|
}
|
|
561
559
|
parseComment() {
|
|
562
560
|
let valueLines = [];
|
|
@@ -572,7 +570,7 @@ class Parser {
|
|
|
572
570
|
if (value[value.length - 1] === '\n') {
|
|
573
571
|
value = value.substring(0, value.length - 1);
|
|
574
572
|
}
|
|
575
|
-
return
|
|
573
|
+
return u('comment', { value: value });
|
|
576
574
|
}
|
|
577
575
|
parseFixedWidth(affiliated) {
|
|
578
576
|
let valueLines = [];
|
|
@@ -584,7 +582,7 @@ class Parser {
|
|
|
584
582
|
valueLines.push(m[1]);
|
|
585
583
|
}
|
|
586
584
|
const value = valueLines.join('\n');
|
|
587
|
-
return
|
|
585
|
+
return u('fixed-width', { affiliated, value });
|
|
588
586
|
}
|
|
589
587
|
parseCommentBlock(affiliated) {
|
|
590
588
|
const comment = this.parseBlock('comment-block', 'comment', affiliated);
|
|
@@ -593,7 +591,7 @@ class Parser {
|
|
|
593
591
|
return comment;
|
|
594
592
|
}
|
|
595
593
|
const value = this.r.substring(comment.contentsBegin, comment.contentsEnd);
|
|
596
|
-
return
|
|
594
|
+
return u('comment-block', { affiliated, value });
|
|
597
595
|
}
|
|
598
596
|
parseSrcBlock(affiliated) {
|
|
599
597
|
const endM = this.r.match(/^[ \t]*#\+end_src[ \t]*$/im);
|
|
@@ -606,12 +604,12 @@ class Parser {
|
|
|
606
604
|
const begin = this.r.offset();
|
|
607
605
|
const contentsBegin = begin + this.r.line().length;
|
|
608
606
|
const contentsEnd = begin + endM.index;
|
|
609
|
-
const value =
|
|
607
|
+
const value = unescapeCodeInString(this.r.substring(contentsBegin, contentsEnd));
|
|
610
608
|
this.r.resetOffset(contentsEnd);
|
|
611
609
|
this.r.advance(this.r.line());
|
|
612
610
|
this.parseEmptyLines();
|
|
613
611
|
const _end = this.r.offset();
|
|
614
|
-
return
|
|
612
|
+
return u('src-block', { affiliated, language, value });
|
|
615
613
|
}
|
|
616
614
|
parseExampleBlock(affiliated) {
|
|
617
615
|
// TODO: parse switches
|
|
@@ -621,30 +619,29 @@ class Parser {
|
|
|
621
619
|
return block;
|
|
622
620
|
}
|
|
623
621
|
const value = this.r.substring(block.contentsBegin, block.contentsEnd);
|
|
624
|
-
return
|
|
622
|
+
return u('example-block', { affiliated, value });
|
|
625
623
|
}
|
|
626
624
|
parseExportBlock(affiliated) {
|
|
627
|
-
var _a;
|
|
628
625
|
const endM = this.r.match(/^[ \t]*#\+end_export[ \t]*$/im);
|
|
629
626
|
if (!endM) {
|
|
630
627
|
// Incomplete block: parse it as a paragraph.
|
|
631
628
|
return this.parseParagraph(affiliated);
|
|
632
629
|
}
|
|
633
630
|
const headerM = this.r.forceMatch(/^[ \t]*#\+begin_export(?:[ \t]+(\S+))?[ \t]*$/im);
|
|
634
|
-
const backend =
|
|
631
|
+
const backend = headerM[1] ?? null;
|
|
635
632
|
const begin = this.r.offset();
|
|
636
633
|
const contentsBegin = begin + this.r.line().length;
|
|
637
634
|
const contentsEnd = begin + endM.index;
|
|
638
|
-
const value =
|
|
635
|
+
const value = unescapeCodeInString(this.r.substring(contentsBegin, contentsEnd));
|
|
639
636
|
this.r.resetOffset(contentsEnd);
|
|
640
637
|
this.r.advance(this.r.line());
|
|
641
638
|
this.parseEmptyLines();
|
|
642
639
|
const _end = this.r.offset();
|
|
643
|
-
return
|
|
640
|
+
return u('export-block', { affiliated, backend, value });
|
|
644
641
|
}
|
|
645
642
|
parseSpecialBlock(affiliated) {
|
|
646
643
|
const blockType = this.r.forceLookingAt(/[ \t]*#\+begin_(\S+)/i)[1];
|
|
647
|
-
const endM = this.r.match(new RegExp(`^[ \\t]*#\\+end_${
|
|
644
|
+
const endM = this.r.match(new RegExp(`^[ \\t]*#\\+end_${escapeRegExp(blockType)}[ \\t]*$`, 'im'));
|
|
648
645
|
if (!endM) {
|
|
649
646
|
this.r.message('incomplete block', this.r.offset(), 'uniorg');
|
|
650
647
|
// Incomplete block: parse it as a paragraph.
|
|
@@ -657,29 +654,30 @@ class Parser {
|
|
|
657
654
|
this.r.advance(this.r.line());
|
|
658
655
|
this.parseEmptyLines();
|
|
659
656
|
const _end = this.r.offset();
|
|
660
|
-
return
|
|
657
|
+
return u('special-block', { affiliated, blockType, contentsBegin, contentsEnd }, []);
|
|
661
658
|
}
|
|
662
659
|
parseAffiliatedKeywords() {
|
|
663
|
-
var _a, _b, _c, _d;
|
|
664
660
|
const offset = this.r.offset();
|
|
665
661
|
const result = {};
|
|
666
662
|
while (!this.r.eof()) {
|
|
667
663
|
const keywordM = this.r.lookingAt(affiliatedRe);
|
|
668
664
|
if (!keywordM)
|
|
669
665
|
break;
|
|
670
|
-
const rawKeyword = (
|
|
671
|
-
|
|
666
|
+
const rawKeyword = (keywordM.groups.dualKeyword ??
|
|
667
|
+
keywordM.groups.regularKeyword ??
|
|
668
|
+
keywordM.groups.attributeKeyword).toUpperCase();
|
|
669
|
+
const keyword = keywordTranslationTable[rawKeyword] ?? rawKeyword;
|
|
672
670
|
// true if keyword should have its value parsed
|
|
673
671
|
const isParsed = parsedKeywords.has(keyword);
|
|
674
672
|
this.r.advance(keywordM);
|
|
675
673
|
this.r.narrow(this.r.offset(), this.r.offset() + this.r.line().length);
|
|
676
674
|
const mainValue = isParsed
|
|
677
|
-
? this.parseObjects(
|
|
675
|
+
? this.parseObjects(restrictionFor('keyword'))
|
|
678
676
|
: this.r.rest().trim();
|
|
679
677
|
this.r.widen();
|
|
680
678
|
this.r.advance(this.r.line());
|
|
681
679
|
const isDual = dualKeywords.has(keyword);
|
|
682
|
-
const dualValue = isDual ?
|
|
680
|
+
const dualValue = isDual ? keywordM.groups.dualValue ?? null : null;
|
|
683
681
|
const value = dualValue === null ? mainValue : [mainValue, dualValue];
|
|
684
682
|
if (multipleKeywords.has(keyword) ||
|
|
685
683
|
// Attributes can always appear on multiple lines.
|
|
@@ -705,7 +703,7 @@ class Parser {
|
|
|
705
703
|
const value = m[2].trim();
|
|
706
704
|
this.r.advance(this.r.line());
|
|
707
705
|
this.parseEmptyLines();
|
|
708
|
-
return
|
|
706
|
+
return u('keyword', { affiliated, key, value });
|
|
709
707
|
}
|
|
710
708
|
parseLatexEnvironment(affiliated) {
|
|
711
709
|
const beginOffset = this.r.offset();
|
|
@@ -721,7 +719,7 @@ class Parser {
|
|
|
721
719
|
const endOffset = this.r.offset();
|
|
722
720
|
this.parseEmptyLines();
|
|
723
721
|
const value = this.r.substring(beginOffset, endOffset);
|
|
724
|
-
return
|
|
722
|
+
return u('latex-environment', { affiliated, value });
|
|
725
723
|
}
|
|
726
724
|
parseDrawer(affiliated) {
|
|
727
725
|
const endM = this.r.match(/^[ \t]*:END:[ \t]*$/im);
|
|
@@ -737,7 +735,7 @@ class Parser {
|
|
|
737
735
|
this.r.resetOffset(contentsEnd);
|
|
738
736
|
this.r.advance(this.r.line());
|
|
739
737
|
this.parseEmptyLines();
|
|
740
|
-
return
|
|
738
|
+
return u('drawer', { affiliated, name, contentsBegin, contentsEnd }, []);
|
|
741
739
|
}
|
|
742
740
|
parseClock() {
|
|
743
741
|
this.r.advance(this.r.forceMatch(/^[ \t]*CLOCK:[ \t]*/));
|
|
@@ -747,16 +745,15 @@ class Parser {
|
|
|
747
745
|
const duration = durationM ? durationM[1] : null;
|
|
748
746
|
const status = duration ? 'closed' : 'running';
|
|
749
747
|
this.parseEmptyLines();
|
|
750
|
-
return
|
|
748
|
+
return u('clock', { value, duration, status });
|
|
751
749
|
}
|
|
752
750
|
parseNodeProperty() {
|
|
753
|
-
var _a;
|
|
754
751
|
const propertyRe = /^[ \t]*:(?<key>\S+):(?:(?<value1>$)|[ \t]+(?<value2>.*?))[ \t]*$/m;
|
|
755
752
|
const m = this.r.forceLookingAt(propertyRe);
|
|
756
753
|
const key = m.groups['key'];
|
|
757
|
-
const value =
|
|
754
|
+
const value = m.groups['value1'] ?? m.groups['value2'];
|
|
758
755
|
this.r.advance(this.r.line());
|
|
759
|
-
return
|
|
756
|
+
return u('node-property', { key, value });
|
|
760
757
|
}
|
|
761
758
|
parseParagraph(affiliated) {
|
|
762
759
|
const contentsBegin = this.r.offset();
|
|
@@ -810,16 +807,15 @@ class Parser {
|
|
|
810
807
|
const contentsEnd = next ? this.r.offset() : this.r.endOffset();
|
|
811
808
|
this.r.resetOffset(contentsEnd);
|
|
812
809
|
this.parseEmptyLines();
|
|
813
|
-
return
|
|
810
|
+
return u('paragraph', { affiliated, contentsBegin, contentsEnd }, []);
|
|
814
811
|
}
|
|
815
812
|
parseFootnoteDefinition(affiliated) {
|
|
816
|
-
var _a;
|
|
817
813
|
const m = this.r.forceLookingAt(footnoteDefinitionRe);
|
|
818
814
|
const label = m[1];
|
|
819
815
|
const begin = this.r.offset();
|
|
820
816
|
this.r.advance(this.r.line());
|
|
821
817
|
const endM = this.r.match(footnoteDefinitionSeparatorRe);
|
|
822
|
-
this.r.advance(endM
|
|
818
|
+
this.r.advance(endM?.index);
|
|
823
819
|
let contentsEnd = endM ? this.r.offset() : this.r.endOffset();
|
|
824
820
|
if (endM && endM[0][0] === '[') {
|
|
825
821
|
// At a new footnote definition, make sure we end before any
|
|
@@ -830,7 +826,7 @@ class Parser {
|
|
|
830
826
|
lines = lines.slice(1, lines.length - 1);
|
|
831
827
|
while (lines.length) {
|
|
832
828
|
const line = lines.pop();
|
|
833
|
-
if (
|
|
829
|
+
if (line.match(affiliatedRe)?.index === 0) {
|
|
834
830
|
// -1 to compensate for \n
|
|
835
831
|
this.r.advance(-line.length - 1);
|
|
836
832
|
}
|
|
@@ -846,18 +842,18 @@ class Parser {
|
|
|
846
842
|
this.r.widen();
|
|
847
843
|
this.r.resetOffset(contentsEnd);
|
|
848
844
|
this.parseEmptyLines();
|
|
849
|
-
return
|
|
845
|
+
return u('footnote-definition', { affiliated, label, contentsBegin, contentsEnd }, []);
|
|
850
846
|
}
|
|
851
847
|
parseHorizontalRule(affiliated) {
|
|
852
848
|
this.r.advance(this.r.line());
|
|
853
849
|
this.parseEmptyLines();
|
|
854
|
-
return
|
|
850
|
+
return u('horizontal-rule', { affiliated });
|
|
855
851
|
}
|
|
856
852
|
parseDiarySexp(affiliated) {
|
|
857
853
|
const value = this.r.forceLookingAt(/^(%%\(.*)[ \t]*$/m)[1];
|
|
858
854
|
this.r.advance(this.r.line());
|
|
859
855
|
this.parseEmptyLines();
|
|
860
|
-
return
|
|
856
|
+
return u('diary-sexp', { affiliated, value });
|
|
861
857
|
}
|
|
862
858
|
parseTable(affiliated) {
|
|
863
859
|
const contentsBegin = this.r.offset();
|
|
@@ -878,10 +874,10 @@ class Parser {
|
|
|
878
874
|
}
|
|
879
875
|
this.parseEmptyLines();
|
|
880
876
|
if (tableType === 'org') {
|
|
881
|
-
return
|
|
877
|
+
return u('table', { tableType, tblfm, contentsBegin, contentsEnd }, []);
|
|
882
878
|
}
|
|
883
879
|
else {
|
|
884
|
-
return
|
|
880
|
+
return u('table', {
|
|
885
881
|
affiliated,
|
|
886
882
|
tableType,
|
|
887
883
|
tblfm,
|
|
@@ -900,14 +896,14 @@ class Parser {
|
|
|
900
896
|
// contentsBegin matches contentsEnd.
|
|
901
897
|
const contentsEnd = rowType === 'rule' ? contentsBegin : this.r.offset();
|
|
902
898
|
this.r.advance(this.r.line());
|
|
903
|
-
return
|
|
899
|
+
return u('table-row', { rowType, contentsBegin, contentsEnd }, []);
|
|
904
900
|
}
|
|
905
901
|
parseTableCell() {
|
|
906
902
|
this.r.advance(this.r.forceLookingAt(/^[ \t]*/));
|
|
907
903
|
const contentsBegin = this.r.offset();
|
|
908
904
|
const m = this.r.advance(this.r.forceLookingAt(/(.*?)[ \t]*(?:\||$)/m));
|
|
909
905
|
const contentsEnd = contentsBegin + m[1].length;
|
|
910
|
-
return
|
|
906
|
+
return u('table-cell', { contentsBegin, contentsEnd }, []);
|
|
911
907
|
}
|
|
912
908
|
parseList(structure, affiliated) {
|
|
913
909
|
const contentsBegin = this.r.offset();
|
|
@@ -930,7 +926,7 @@ class Parser {
|
|
|
930
926
|
}
|
|
931
927
|
const contentsEnd = pos;
|
|
932
928
|
this.r.resetOffset(contentsEnd);
|
|
933
|
-
return
|
|
929
|
+
return u('plain-list', {
|
|
934
930
|
affiliated,
|
|
935
931
|
indent,
|
|
936
932
|
listType,
|
|
@@ -942,14 +938,13 @@ class Parser {
|
|
|
942
938
|
}, []);
|
|
943
939
|
}
|
|
944
940
|
parseListItem(structure) {
|
|
945
|
-
var _a, _b;
|
|
946
941
|
const offset = this.r.offset();
|
|
947
942
|
const m = this.r.advance(this.r.forceMatch(this.re.fullListItemRe()));
|
|
948
943
|
const bullet = m.groups.bullet;
|
|
949
|
-
const counter =
|
|
944
|
+
const counter = m.groups.counter ?? null;
|
|
950
945
|
const checkbox = m.groups.checkbox === '[ ]'
|
|
951
946
|
? 'off'
|
|
952
|
-
:
|
|
947
|
+
: m.groups.checkbox?.toLowerCase() === '[x]'
|
|
953
948
|
? 'on'
|
|
954
949
|
: m.groups.checkbox === '[-]'
|
|
955
950
|
? 'trans'
|
|
@@ -958,7 +953,7 @@ class Parser {
|
|
|
958
953
|
const contentsBegin = this.r.offset();
|
|
959
954
|
const contentsEnd = item.end;
|
|
960
955
|
this.r.resetOffset(contentsEnd);
|
|
961
|
-
return
|
|
956
|
+
return u('list-item', {
|
|
962
957
|
indent: item.indent,
|
|
963
958
|
bullet,
|
|
964
959
|
counter,
|
|
@@ -969,16 +964,15 @@ class Parser {
|
|
|
969
964
|
}, item.tag ? [item.tag] : []);
|
|
970
965
|
}
|
|
971
966
|
parseListStructure() {
|
|
972
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
973
967
|
const items = [];
|
|
974
968
|
const struct = [];
|
|
975
969
|
while (true) {
|
|
976
|
-
if (this.r.eof() ||
|
|
970
|
+
if (this.r.eof() || this.r.match(this.re.listEndRe())?.index === 0) {
|
|
977
971
|
break;
|
|
978
972
|
}
|
|
979
973
|
const m = this.r.match(this.re.listItemRe());
|
|
980
974
|
if (m) {
|
|
981
|
-
const indent = m.groups.
|
|
975
|
+
const indent = (m.groups.indent1?.length || 0) + (m.groups.indent2?.length || 0);
|
|
982
976
|
// end previous siblings
|
|
983
977
|
while (items.length && items[items.length - 1].indent >= indent) {
|
|
984
978
|
const item = items.pop();
|
|
@@ -996,21 +990,21 @@ class Parser {
|
|
|
996
990
|
let tag = null;
|
|
997
991
|
if (fullM.groups.tag !== undefined) {
|
|
998
992
|
const tagStartOffset = this.r.offset() +
|
|
999
|
-
(
|
|
1000
|
-
(
|
|
1001
|
-
(
|
|
1002
|
-
(
|
|
993
|
+
(fullM.groups.indent?.length ?? 0) +
|
|
994
|
+
(fullM.groups.bullet?.length ?? 0) +
|
|
995
|
+
(fullM.groups.counter_group?.length ?? 0) +
|
|
996
|
+
(fullM.groups.checkbox_group?.length ?? 0);
|
|
1003
997
|
const tagStopOffset = tagStartOffset + fullM.groups.tag.length;
|
|
1004
998
|
this.r.narrow(tagStartOffset, tagStopOffset);
|
|
1005
|
-
tag =
|
|
999
|
+
tag = u('list-item-tag', {}, this.parseObjects(restrictionFor('list-item')));
|
|
1006
1000
|
this.r.widen();
|
|
1007
1001
|
}
|
|
1008
1002
|
const item = {
|
|
1009
1003
|
begin: this.r.offset(),
|
|
1010
1004
|
indent,
|
|
1011
1005
|
bullet,
|
|
1012
|
-
counter: counter
|
|
1013
|
-
checkbox: checkbox
|
|
1006
|
+
counter: counter ?? null,
|
|
1007
|
+
checkbox: checkbox ?? null,
|
|
1014
1008
|
tag,
|
|
1015
1009
|
// will be overwritten later
|
|
1016
1010
|
end: this.r.offset(),
|
|
@@ -1066,7 +1060,7 @@ class Parser {
|
|
|
1066
1060
|
const contentsBegin = begin + m[2].length + (inside ? 1 : 0);
|
|
1067
1061
|
const contentsEnd = begin + m[2].length + m[3].length - (inside ? 1 : 0);
|
|
1068
1062
|
const _end = this.r.offset();
|
|
1069
|
-
return
|
|
1063
|
+
return u('superscript', { contentsBegin, contentsEnd, children: [] });
|
|
1070
1064
|
}
|
|
1071
1065
|
parseSubscript() {
|
|
1072
1066
|
this.r.backoff(1); // backoff by one, to match previous char (should be non-space)
|
|
@@ -1079,7 +1073,7 @@ class Parser {
|
|
|
1079
1073
|
const contentsBegin = begin + m[2].length + (inside ? 1 : 0);
|
|
1080
1074
|
const contentsEnd = begin + m[2].length + m[3].length - (inside ? 1 : 0);
|
|
1081
1075
|
const _end = this.r.offset();
|
|
1082
|
-
return
|
|
1076
|
+
return u('subscript', { contentsBegin, contentsEnd, children: [] });
|
|
1083
1077
|
}
|
|
1084
1078
|
parseUnderline() {
|
|
1085
1079
|
// backoff one char to check border
|
|
@@ -1090,7 +1084,7 @@ class Parser {
|
|
|
1090
1084
|
const contentsBegin = this.r.offset() + m.index + m[1].length + m[3].length;
|
|
1091
1085
|
const contentsEnd = contentsBegin + m[4].length;
|
|
1092
1086
|
this.r.resetOffset(contentsEnd + 1);
|
|
1093
|
-
return
|
|
1087
|
+
return u('underline', { contentsBegin, contentsEnd }, []);
|
|
1094
1088
|
}
|
|
1095
1089
|
parseBold() {
|
|
1096
1090
|
// backoff one char to check border
|
|
@@ -1101,7 +1095,7 @@ class Parser {
|
|
|
1101
1095
|
const contentsBegin = this.r.offset() + m.index + m[1].length + m[3].length;
|
|
1102
1096
|
const contentsEnd = contentsBegin + m[4].length;
|
|
1103
1097
|
this.r.resetOffset(contentsEnd + 1);
|
|
1104
|
-
return
|
|
1098
|
+
return u('bold', { contentsBegin, contentsEnd }, []);
|
|
1105
1099
|
}
|
|
1106
1100
|
parseItalic() {
|
|
1107
1101
|
// backoff one char to check border
|
|
@@ -1112,7 +1106,7 @@ class Parser {
|
|
|
1112
1106
|
const contentsBegin = this.r.offset() + m.index + m[1].length + m[3].length;
|
|
1113
1107
|
const contentsEnd = contentsBegin + m[4].length;
|
|
1114
1108
|
this.r.resetOffset(contentsEnd + 1);
|
|
1115
|
-
return
|
|
1109
|
+
return u('italic', { contentsBegin, contentsEnd }, []);
|
|
1116
1110
|
}
|
|
1117
1111
|
parseCode() {
|
|
1118
1112
|
// backoff one char to check border
|
|
@@ -1124,7 +1118,7 @@ class Parser {
|
|
|
1124
1118
|
const contentsBegin = this.r.offset() + m.index + m[1].length + m[3].length;
|
|
1125
1119
|
const contentsEnd = contentsBegin + m[4].length;
|
|
1126
1120
|
this.r.resetOffset(contentsEnd + 1);
|
|
1127
|
-
return
|
|
1121
|
+
return u('code', { value }, []);
|
|
1128
1122
|
}
|
|
1129
1123
|
parseVerbatim() {
|
|
1130
1124
|
this.r.backoff(1);
|
|
@@ -1135,7 +1129,7 @@ class Parser {
|
|
|
1135
1129
|
const contentsBegin = this.r.offset() + m.index + m[1].length + m[3].length;
|
|
1136
1130
|
const contentsEnd = contentsBegin + m[4].length;
|
|
1137
1131
|
this.r.resetOffset(contentsEnd + 1);
|
|
1138
|
-
return
|
|
1132
|
+
return u('verbatim', { value }, []);
|
|
1139
1133
|
}
|
|
1140
1134
|
parseStrikeThrough() {
|
|
1141
1135
|
// backoff one char to check border
|
|
@@ -1146,10 +1140,9 @@ class Parser {
|
|
|
1146
1140
|
const contentsBegin = this.r.offset() + m.index + m[1].length + m[3].length;
|
|
1147
1141
|
const contentsEnd = contentsBegin + m[4].length;
|
|
1148
1142
|
this.r.resetOffset(contentsEnd + 1);
|
|
1149
|
-
return
|
|
1143
|
+
return u('strike-through', { contentsBegin, contentsEnd }, []);
|
|
1150
1144
|
}
|
|
1151
1145
|
parseEntity() {
|
|
1152
|
-
var _a;
|
|
1153
1146
|
const m = this.r.advance(this.r.lookingAt(/^\\(?:(?<value1>_ +)|(?<value2>there4|sup[123]|frac[13][24]|[a-zA-Z]+)(?<brackets>$|\{\}|\P{Letter}))/mu));
|
|
1154
1147
|
if (!m)
|
|
1155
1148
|
return null;
|
|
@@ -1160,13 +1153,12 @@ class Parser {
|
|
|
1160
1153
|
// as text later.
|
|
1161
1154
|
this.r.backoff(m.groups.brackets.length);
|
|
1162
1155
|
}
|
|
1163
|
-
const value =
|
|
1156
|
+
const value = getOrgEntity(m.groups.value1 ?? m.groups.value2);
|
|
1164
1157
|
if (!value)
|
|
1165
1158
|
return null;
|
|
1166
|
-
return
|
|
1159
|
+
return u('entity', { useBrackets: hasBrackets, ...value });
|
|
1167
1160
|
}
|
|
1168
1161
|
parseLatexFragment() {
|
|
1169
|
-
var _a;
|
|
1170
1162
|
const begin = this.r.offset();
|
|
1171
1163
|
const prefix = this.r.peek(2);
|
|
1172
1164
|
let contents = null;
|
|
@@ -1183,20 +1175,20 @@ class Parser {
|
|
|
1183
1175
|
default: {
|
|
1184
1176
|
// Macro.
|
|
1185
1177
|
const m = this.r.advance(this.r.lookingAt(/^\\[a-zA-Z]+\*?((\[[^\]\[\n{}]*\])|(\{[^{}\n]*\}))*/));
|
|
1186
|
-
contents = m
|
|
1178
|
+
contents = m?.[0];
|
|
1187
1179
|
}
|
|
1188
1180
|
}
|
|
1189
1181
|
}
|
|
1190
1182
|
else if (prefix[1] === '$') {
|
|
1191
1183
|
const m = this.r.advance(this.r.match(/\$\$((?:.|\n)*?)\$\$/m));
|
|
1192
|
-
contents = m
|
|
1184
|
+
contents = m?.[1];
|
|
1193
1185
|
}
|
|
1194
1186
|
else {
|
|
1195
1187
|
// TODO: limit search to 2 lines
|
|
1196
1188
|
const charBefore = this.r.substring(this.r.offset() - 1, this.r.offset());
|
|
1197
1189
|
if (charBefore !== '$' &&
|
|
1198
1190
|
!' \t\n,.;'.includes(prefix[1]) &&
|
|
1199
|
-
(contents =
|
|
1191
|
+
(contents = this.r.advance(this.r.match(/\$((?:.|\n)*?)\$/m))?.[1]) &&
|
|
1200
1192
|
!' \t\n,.'.includes(this.r.substring(this.r.offset() - 1, this.r.offset())) &&
|
|
1201
1193
|
this.r.lookingAt(/^(\p{Punctuation}|\p{White_Space}|\p{Open_Punctuation}|\p{Close_Punctuation}|\\"|'|$)/mu)) {
|
|
1202
1194
|
// we've found the end
|
|
@@ -1210,10 +1202,9 @@ class Parser {
|
|
|
1210
1202
|
if (begin === end)
|
|
1211
1203
|
return null;
|
|
1212
1204
|
const value = this.r.substring(begin, end);
|
|
1213
|
-
return
|
|
1205
|
+
return u('latex-fragment', { value, contents: contents ?? value });
|
|
1214
1206
|
}
|
|
1215
1207
|
parseFootnoteReference() {
|
|
1216
|
-
var _a;
|
|
1217
1208
|
const begin = this.r.offset();
|
|
1218
1209
|
const m = this.r.match(footnoteRe);
|
|
1219
1210
|
if (!m)
|
|
@@ -1242,9 +1233,10 @@ class Parser {
|
|
|
1242
1233
|
? 'inline'
|
|
1243
1234
|
: 'standard';
|
|
1244
1235
|
const label = footnoteType === 'inline'
|
|
1245
|
-
?
|
|
1236
|
+
? m.groups.label_inline ?? null
|
|
1237
|
+
: m.groups.label;
|
|
1246
1238
|
if (footnoteType === 'inline') {
|
|
1247
|
-
return
|
|
1239
|
+
return u('footnote-reference', {
|
|
1248
1240
|
label,
|
|
1249
1241
|
footnoteType,
|
|
1250
1242
|
contentsBegin,
|
|
@@ -1252,7 +1244,7 @@ class Parser {
|
|
|
1252
1244
|
}, []);
|
|
1253
1245
|
}
|
|
1254
1246
|
else {
|
|
1255
|
-
return
|
|
1247
|
+
return u('footnote-reference', { label, footnoteType }, []);
|
|
1256
1248
|
}
|
|
1257
1249
|
}
|
|
1258
1250
|
parseLink() {
|
|
@@ -1286,9 +1278,13 @@ class Parser {
|
|
|
1286
1278
|
.replace(/(\\+)([\[\]])/g, (p1, p2) => '\\'.repeat(p1.length / 2) + p2);
|
|
1287
1279
|
// TODO: org-link-expand-abbrev
|
|
1288
1280
|
const { linkType, path } = this.linkType(rawLink);
|
|
1289
|
-
return
|
|
1281
|
+
return u('link', {
|
|
1282
|
+
format: 'bracket',
|
|
1283
|
+
linkType,
|
|
1290
1284
|
rawLink,
|
|
1291
|
-
path
|
|
1285
|
+
path,
|
|
1286
|
+
...contents,
|
|
1287
|
+
}, []);
|
|
1292
1288
|
}
|
|
1293
1289
|
// TODO: this is different from OrgRegexUtils.linkPlainRe
|
|
1294
1290
|
// Type 3: Plain link, e.g., https://orgmode.org
|
|
@@ -1296,7 +1292,7 @@ class Parser {
|
|
|
1296
1292
|
const plainM = this.r.advance(this.r.lookingAt(linkPlainRe));
|
|
1297
1293
|
if (plainM) {
|
|
1298
1294
|
const m = plainM;
|
|
1299
|
-
return
|
|
1295
|
+
return u('link', {
|
|
1300
1296
|
format: 'plain',
|
|
1301
1297
|
linkType: m[1],
|
|
1302
1298
|
rawLink: m[0],
|
|
@@ -1313,7 +1309,7 @@ class Parser {
|
|
|
1313
1309
|
const linkType = m[1];
|
|
1314
1310
|
const rawLink = m[0].substring(1, m[0].length - 1); // strip < >
|
|
1315
1311
|
const path = m[2].replace(/[ \t]*\n[ \t]*/g, '');
|
|
1316
|
-
return
|
|
1312
|
+
return u('link', { format: 'angle', linkType, rawLink, path }, []);
|
|
1317
1313
|
}
|
|
1318
1314
|
return null;
|
|
1319
1315
|
}
|
|
@@ -1384,8 +1380,9 @@ class Parser {
|
|
|
1384
1380
|
: dateEnd
|
|
1385
1381
|
? Parser.parseDate(dateEnd)
|
|
1386
1382
|
: timeRange
|
|
1387
|
-
?
|
|
1388
|
-
|
|
1383
|
+
? { ...start, ...timeRange }
|
|
1384
|
+
: null;
|
|
1385
|
+
return u('timestamp', {
|
|
1389
1386
|
timestampType,
|
|
1390
1387
|
rawValue,
|
|
1391
1388
|
start,
|
|
@@ -1428,7 +1425,7 @@ class Parser {
|
|
|
1428
1425
|
}
|
|
1429
1426
|
const drawerRe = /^[ \t]*:((?:\w|[-_])+):[ \t]*$/m;
|
|
1430
1427
|
const latexBeginEnvironmentRe = /^[ \t]*\\begin\{([A-Za-z0-9*]+)\}/i;
|
|
1431
|
-
const latexEndEnvironmentRe = (name) => new RegExp(`\\\\end\\{${
|
|
1428
|
+
const latexEndEnvironmentRe = (name) => new RegExp(`\\\\end\\{${escapeRegExp(name)}\\}[ \\t]*$`, 'mi');
|
|
1432
1429
|
const affiliatedKeywords = [
|
|
1433
1430
|
'CAPTION',
|
|
1434
1431
|
'DATA',
|
|
@@ -1475,9 +1472,8 @@ const footnoteRe = /\[fn:(?:(?<label_inline>[-_\w]+)?(?<inline>:)|(?<label>[-_\w
|
|
|
1475
1472
|
const footnoteDefinitionRe = /^\[fn:([-_\w]+)\]/;
|
|
1476
1473
|
const footnoteDefinitionSeparatorRe = /^\*|^\[fn:([-_\w]+)\]|^([ \t]*\n){2,}/m;
|
|
1477
1474
|
function appendChildren(node, children) {
|
|
1478
|
-
var _a;
|
|
1479
1475
|
if ('children' in node) {
|
|
1480
|
-
const newChildren = [...(
|
|
1476
|
+
const newChildren = [...(node.children ?? []), ...children];
|
|
1481
1477
|
node.children = newChildren;
|
|
1482
1478
|
}
|
|
1483
1479
|
}
|