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