|
|
@@ -581,20 +581,23 @@ class MDState {
|
|
581
|
581
|
/** @type {MDState|null} */
|
|
582
|
582
|
#parent = null;
|
|
583
|
583
|
|
|
|
584
|
+ /** @type {MDConfig} */
|
|
|
585
|
+ config;
|
|
|
586
|
+
|
|
584
|
587
|
/**
|
|
585
|
|
- * Tuples of `priority:number` and `MDReader` sorted by `blockPriority`.
|
|
586
|
|
- * @type {Array}
|
|
|
588
|
+ * Array of `MDReader`s sorted by block reading priority.
|
|
|
589
|
+ * @type {MDReader[]}
|
|
587
|
590
|
*/
|
|
588
|
591
|
#readersByBlockPriority = [];
|
|
589
|
592
|
|
|
590
|
593
|
/**
|
|
591
|
|
- * Tuples of `priority:number` and `MDReader` sorted by `tokenizePriority`.
|
|
592
|
|
- * @type {Array}
|
|
|
594
|
+ * Array of `MDReader`s sorted by tokenization priority.
|
|
|
595
|
+ * @type {MDReader[]}
|
|
593
|
596
|
*/
|
|
594
|
597
|
#readersByTokenPriority = [];
|
|
595
|
598
|
|
|
596
|
599
|
/**
|
|
597
|
|
- * Tuples of `priority:number` and `MDReader` sorted by `substitutePriority`.
|
|
|
600
|
+ * Tuples of `pass:number` and `MDReader` sorted substitution priority.
|
|
598
|
601
|
* @type {Array}
|
|
599
|
602
|
*/
|
|
600
|
603
|
#readersBySubstitutePriority = [];
|
|
|
@@ -615,15 +618,18 @@ class MDState {
|
|
615
|
618
|
|
|
616
|
619
|
/**
|
|
617
|
620
|
* @param {string[]} lines - lines of markdown text
|
|
618
|
|
- * @param {Array} readersByBlockPriority - tuple arrays of priority and MDReader
|
|
619
|
|
- * @param {Array} readersByTokenPriority - tuple arrays of priority and MDReader
|
|
|
621
|
+ * @param {MDConfig} config
|
|
|
622
|
+ * @param {MDReader[]} readersByBlockPriority
|
|
|
623
|
+ * @param {MDReader[]} readersByTokenPriority
|
|
620
|
624
|
* @param {Array} readersBySubstitutePriority - tuple arrays of priority and MDReader
|
|
621
|
625
|
*/
|
|
622
|
626
|
constructor(lines,
|
|
|
627
|
+ config=null,
|
|
623
|
628
|
readersByBlockPriority=null,
|
|
624
|
629
|
readersByTokenPriority=null,
|
|
625
|
630
|
readersBySubstitutePriority=null) {
|
|
626
|
631
|
this.#lines = lines;
|
|
|
632
|
+ this.config = config;
|
|
627
|
633
|
this.#readersByBlockPriority = readersByBlockPriority
|
|
628
|
634
|
this.#readersByTokenPriority = readersByTokenPriority
|
|
629
|
635
|
this.#readersBySubstitutePriority = readersBySubstitutePriority
|
|
|
@@ -639,6 +645,7 @@ class MDState {
|
|
639
|
645
|
copy(lines) {
|
|
640
|
646
|
let cp = new MDState(lines);
|
|
641
|
647
|
cp.#parent = this;
|
|
|
648
|
+ cp.config = this.config;
|
|
642
|
649
|
return cp;
|
|
643
|
650
|
}
|
|
644
|
651
|
|
|
|
@@ -698,8 +705,7 @@ class MDState {
|
|
698
|
705
|
this.p++;
|
|
699
|
706
|
}
|
|
700
|
707
|
if (!this.hasLines(1)) return null;
|
|
701
|
|
- for (const tuple of this.root.#readersByBlockPriority) {
|
|
702
|
|
- var reader = tuple[1];
|
|
|
708
|
+ for (const reader of this.root.#readersByBlockPriority) {
|
|
703
|
709
|
const startP = this.p;
|
|
704
|
710
|
const block = reader.readBlock(this);
|
|
705
|
711
|
if (block) {
|
|
|
@@ -759,11 +765,7 @@ class MDState {
|
|
759
|
765
|
continue;
|
|
760
|
766
|
}
|
|
761
|
767
|
var found = false;
|
|
762
|
|
- for (const readerTuple of this.root.#readersByTokenPriority) {
|
|
763
|
|
- /** @type {number} */
|
|
764
|
|
- const priority = readerTuple[0];
|
|
765
|
|
- /** @type {MDReader} */
|
|
766
|
|
- const reader = readerTuple[1];
|
|
|
768
|
+ for (const reader of this.root.#readersByTokenPriority) {
|
|
767
|
769
|
const token = reader.readToken(this, remainder);
|
|
768
|
770
|
if (token === null) continue;
|
|
769
|
771
|
if (token === undefined) {
|
|
|
@@ -825,10 +827,10 @@ class MDState {
|
|
825
|
827
|
anyChanges = false;
|
|
826
|
828
|
for (const readerTuple of this.root.#readersBySubstitutePriority) {
|
|
827
|
829
|
/** @type {number} */
|
|
828
|
|
- const priority = readerTuple[0];
|
|
|
830
|
+ const pass = readerTuple[0];
|
|
829
|
831
|
/** @type {MDReader} */
|
|
830
|
832
|
const reader = readerTuple[1];
|
|
831
|
|
- const changed = reader.substituteTokens(this, priority, nodes);
|
|
|
833
|
+ const changed = reader.substituteTokens(this, pass, nodes);
|
|
832
|
834
|
if (!changed) continue;
|
|
833
|
835
|
anyChanges = true;
|
|
834
|
836
|
break;
|
|
|
@@ -905,76 +907,22 @@ class MDState {
|
|
905
|
907
|
* any combination of these.
|
|
906
|
908
|
* 1. **Blocks** - Processing an array of lines to find block-level structures,
|
|
907
|
909
|
* such as paragraphs, lists, tables, blockquotes, etc. and converting them
|
|
908
|
|
- * into block-level `MDNode`s.
|
|
|
910
|
+ * into block-level `MDNode`s. Override `readBlock`.
|
|
909
|
911
|
* 2. **Inline tokens** - Carving up single lines of markdown into tokens for
|
|
910
|
912
|
* inline formatting, such as strong, emphasis, links, images, etc.
|
|
|
913
|
+ * Override `readToken`.
|
|
911
|
914
|
* 3. **Inline substitution** - Finding patterns of tokens and substituting them
|
|
912
|
|
- * with `MDNode`s.
|
|
|
915
|
+ * with `MDNode`s. Override `substituteTokens`. (`readToken` and
|
|
|
916
|
+ * `substituteTokens` are usually overridden together.)
|
|
913
|
917
|
*
|
|
914
|
|
- * Each parsing phase consults each registered reader, checking if its
|
|
915
|
|
- * recognized syntax is located in a given place in the markdown. The order
|
|
916
|
|
- * the readers are tested is affected by priority values for each phase. This
|
|
917
|
|
- * allows syntactic ambiguities to be resolved in a consistent way (e.g.
|
|
918
|
|
- * `\*\*strong\*\*` and `\*emphasis\*` using similar syntax).
|
|
|
918
|
+ * Readers may have similar, ambiguous syntax (such as `**strong**` and
|
|
|
919
|
+ * `*emphasis*`) and need to process in a certain order. This can be done by
|
|
|
920
|
+ * overriding the `compare` methods to influence which readers to put before
|
|
|
921
|
+ * others in each phase. Furthermore, substitution can occur in multiple passes
|
|
|
922
|
+ * if necessary. These two mechanisms can be used to resolve ambiguities.
|
|
919
|
923
|
*/
|
|
920
|
924
|
class MDReader {
|
|
921
|
925
|
/**
|
|
922
|
|
- * Block reading priority for this reader. Priority is a unitless relative
|
|
923
|
|
- * value used for sorting readers in the block reading process. Core readers
|
|
924
|
|
- * use a range of 0 to 100 but any value is permitted. Generally, more
|
|
925
|
|
- * distinctive, unambiguous block syntax should be prioritized first (low
|
|
926
|
|
- * priority number), while more general block syntax like paragraphs should
|
|
927
|
|
- * be prioritized last (high priority number). If the reader has no block-level
|
|
928
|
|
- * elements, can be set to `null` to skip during that phase.
|
|
929
|
|
- *
|
|
930
|
|
- * @type {number|null}
|
|
931
|
|
- */
|
|
932
|
|
- get blockPriority() { return this.#blockPriority; };
|
|
933
|
|
- #blockPriority;
|
|
934
|
|
-
|
|
935
|
|
- /**
|
|
936
|
|
- * Inline tokenization priority for this reader. Priority is a unitless
|
|
937
|
|
- * relative value used for sorting readers in the tokenization process.
|
|
938
|
|
- * Core readers use a range of 0 to 100 but any value is permitted.
|
|
939
|
|
- * Generally, more distinctive, unambiguous token formats should be
|
|
940
|
|
- * prioritized first (low priority number), while more general, ambiguous
|
|
941
|
|
- * tokens should be prioritized last (high priority number). If the reader
|
|
942
|
|
- * has no inline-level elements, can be set to `null` to skip that phase.
|
|
943
|
|
- *
|
|
944
|
|
- * @type {number|null}
|
|
945
|
|
- */
|
|
946
|
|
- get tokenizePriority() { return this.#tokenizePriority; };
|
|
947
|
|
- #tokenizePriority;
|
|
948
|
|
-
|
|
949
|
|
- /**
|
|
950
|
|
- * Inline token substitution priority/priorities for this reader. Priority
|
|
951
|
|
- * is a unitless relative value or values for sorting readers in the
|
|
952
|
|
- * tokenization process. Core readers use a range of 0 to 100 but any value
|
|
953
|
|
- * is permitted. Generally, more distinctive, unambiguous patterns should
|
|
954
|
|
- * be prioritized first (low priority number), while more general, ambiguous
|
|
955
|
|
- * patterns should be prioritized last (high priority number).
|
|
956
|
|
- *
|
|
957
|
|
- * This property can be an array of numbers, in monotonically increasing
|
|
958
|
|
- * order. In that case, the same reader will occur 2 or more times in the
|
|
959
|
|
- * prioritization list. This can be useful when a reader handles multiple
|
|
960
|
|
- * patterns of differing priority. When `substituteTokens` is called, the
|
|
961
|
|
- * current priority is passed to differentiate which pass is being done.
|
|
962
|
|
- *
|
|
963
|
|
- * If the reader has no inline-level elements, can be set to `null` to skip
|
|
964
|
|
- * that phase.
|
|
965
|
|
- *
|
|
966
|
|
- * @type {number|number[]|null}
|
|
967
|
|
- */
|
|
968
|
|
- get substitutePriority() { return this.#substitutePriority; };
|
|
969
|
|
- #substitutePriority;
|
|
970
|
|
-
|
|
971
|
|
- constructor(blockPriority=100, tokenizePriority=100, substitutePriority=100) {
|
|
972
|
|
- this.#blockPriority = blockPriority;
|
|
973
|
|
- this.#tokenizePriority = tokenizePriority;
|
|
974
|
|
- this.#substitutePriority = substitutePriority;
|
|
975
|
|
- }
|
|
976
|
|
-
|
|
977
|
|
- /**
|
|
978
|
926
|
* Called before processing begins. `state.lines` is populated and the
|
|
979
|
927
|
* line pointer `state.p` will be at `0`. Default implementation does nothing.
|
|
980
|
928
|
*
|
|
|
@@ -1011,11 +959,11 @@ class MDReader {
|
|
1011
|
959
|
* with one or more `MDNode` subclass instances.
|
|
1012
|
960
|
*
|
|
1013
|
961
|
* @param {MDState} state
|
|
1014
|
|
- * @param {number} priority
|
|
|
962
|
+ * @param {number} pass - what substitution pass this is, starting with 1
|
|
1015
|
963
|
* @param {Array} tokens - mixed array of `MDToken` and `MDInlineNode` elements
|
|
1016
|
964
|
* @returns {boolean} `true` if a substitution was performed, `false` if not
|
|
1017
|
965
|
*/
|
|
1018
|
|
- substituteTokens(state, priority, tokens) { return false; }
|
|
|
966
|
+ substituteTokens(state, pass, tokens) { return false; }
|
|
1019
|
967
|
|
|
1020
|
968
|
/**
|
|
1021
|
969
|
* Called after all parsing has completed. An array `blocks` is passed of all
|
|
|
@@ -1030,6 +978,160 @@ class MDReader {
|
|
1030
|
978
|
* @param {MDBlockNode[]} blocks
|
|
1031
|
979
|
*/
|
|
1032
|
980
|
postProcess(state, blocks) {}
|
|
|
981
|
+
|
|
|
982
|
+ /**
|
|
|
983
|
+ * @param {MDReader} other
|
|
|
984
|
+ * @returns {number} -1 if this should be before other, 0 if the same or don't care, 1 if this should be after other
|
|
|
985
|
+ */
|
|
|
986
|
+ compareBlockOrdering(other) {
|
|
|
987
|
+ return 0;
|
|
|
988
|
+ }
|
|
|
989
|
+
|
|
|
990
|
+ /**
|
|
|
991
|
+ * @param {MDReader} other
|
|
|
992
|
+ * @returns {number}
|
|
|
993
|
+ */
|
|
|
994
|
+ compareTokenizeOrdering(other) {
|
|
|
995
|
+ return 0;
|
|
|
996
|
+ }
|
|
|
997
|
+
|
|
|
998
|
+ /**
|
|
|
999
|
+ * @param {MDReader} other
|
|
|
1000
|
+ * @param {number} pass
|
|
|
1001
|
+ * @returns {number}
|
|
|
1002
|
+ */
|
|
|
1003
|
+ compareSubstituteOrdering(other, pass) {
|
|
|
1004
|
+ return 0;
|
|
|
1005
|
+ }
|
|
|
1006
|
+
|
|
|
1007
|
+ get substitutionPassCount() { return 1; }
|
|
|
1008
|
+
|
|
|
1009
|
+ /**
|
|
|
1010
|
+ * For sorting readers with ordering preferences. The `compare` methods
|
|
|
1011
|
+ * don't have the properties of normal sorting compares so need to sort
|
|
|
1012
|
+ * differently.
|
|
|
1013
|
+ *
|
|
|
1014
|
+ * @param {MDReader[]} arr - array to sort
|
|
|
1015
|
+ * @param {function} compareFn - comparison function, taking two array element
|
|
|
1016
|
+ * arguments and returning -1, 0, or 1 for a < b, a == b, and a > b,
|
|
|
1017
|
+ * respectively
|
|
|
1018
|
+ * @param {function} idFn - function for returning a unique hashable id for
|
|
|
1019
|
+ * the array element
|
|
|
1020
|
+ * @returns {MDReader[]} sorted array
|
|
|
1021
|
+ */
|
|
|
1022
|
+ static #kahnTopologicalSort(arr, compareFn, idFn) {
|
|
|
1023
|
+ const graph = {};
|
|
|
1024
|
+ const inDegrees = {};
|
|
|
1025
|
+ const valuesById = {};
|
|
|
1026
|
+
|
|
|
1027
|
+ // Build the graph and compute in-degrees
|
|
|
1028
|
+ for (const elem of arr) {
|
|
|
1029
|
+ const id = idFn(elem);
|
|
|
1030
|
+ graph[id] = [];
|
|
|
1031
|
+ inDegrees[id] = 0;
|
|
|
1032
|
+ valuesById[id] = elem;
|
|
|
1033
|
+ }
|
|
|
1034
|
+
|
|
|
1035
|
+ for (let i = 0; i < arr.length; i++) {
|
|
|
1036
|
+ const elemA = arr[i];
|
|
|
1037
|
+ const idA = idFn(elemA);
|
|
|
1038
|
+ for (let j = 0; j < arr.length; j++) {
|
|
|
1039
|
+ if (i === j) continue;
|
|
|
1040
|
+ const elemB = arr[j];
|
|
|
1041
|
+ const idB = idFn(elemB);
|
|
|
1042
|
+ const comparisonResult = compareFn(elemA, elemB);
|
|
|
1043
|
+ if (comparisonResult < 0) {
|
|
|
1044
|
+ graph[idA].push(idB);
|
|
|
1045
|
+ inDegrees[idB]++;
|
|
|
1046
|
+ } else if (comparisonResult > 0) {
|
|
|
1047
|
+ graph[idB].push(idA);
|
|
|
1048
|
+ inDegrees[idA]++;
|
|
|
1049
|
+ }
|
|
|
1050
|
+ }
|
|
|
1051
|
+ }
|
|
|
1052
|
+
|
|
|
1053
|
+ // Initialize the queue with zero-inDegree nodes
|
|
|
1054
|
+ const queue = [];
|
|
|
1055
|
+ for (const elemId in inDegrees) {
|
|
|
1056
|
+ if (inDegrees[elemId] === 0) {
|
|
|
1057
|
+ queue.push(elemId);
|
|
|
1058
|
+ }
|
|
|
1059
|
+ }
|
|
|
1060
|
+
|
|
|
1061
|
+ // Process the queue and build the topological order list
|
|
|
1062
|
+ const sorted = [];
|
|
|
1063
|
+ while (queue.length > 0) {
|
|
|
1064
|
+ const elemId = queue.shift();
|
|
|
1065
|
+ sorted.push(valuesById[elemId]);
|
|
|
1066
|
+ delete valuesById[elemId];
|
|
|
1067
|
+
|
|
|
1068
|
+ for (const neighbor of graph[elemId]) {
|
|
|
1069
|
+ inDegrees[neighbor]--;
|
|
|
1070
|
+ if (inDegrees[neighbor] === 0) {
|
|
|
1071
|
+ queue.push(neighbor);
|
|
|
1072
|
+ }
|
|
|
1073
|
+ }
|
|
|
1074
|
+ }
|
|
|
1075
|
+ // Anything left over can go at the end. No ordering dependencies.
|
|
|
1076
|
+ for (const elemId in valuesById) {
|
|
|
1077
|
+ sorted.push(valuesById[elemId]);
|
|
|
1078
|
+ }
|
|
|
1079
|
+
|
|
|
1080
|
+ return sorted;
|
|
|
1081
|
+ }
|
|
|
1082
|
+
|
|
|
1083
|
+ /**
|
|
|
1084
|
+ * @param {MDReader[]} readers
|
|
|
1085
|
+ * @returns {MDReader[]}
|
|
|
1086
|
+ */
|
|
|
1087
|
+ static sortReaderForBlocks(readers) {
|
|
|
1088
|
+ const sorted = readers.slice();
|
|
|
1089
|
+ return MDReader.#kahnTopologicalSort(sorted, (a, b) => {
|
|
|
1090
|
+ return a.compareBlockOrdering(b);
|
|
|
1091
|
+ // if (ab != 0) return ab;
|
|
|
1092
|
+ // return -b.compareBlockOrdering(a);
|
|
|
1093
|
+ }, (elem) => elem.constructor.name);
|
|
|
1094
|
+ }
|
|
|
1095
|
+
|
|
|
1096
|
+ /**
|
|
|
1097
|
+ * @param {MDReader[]} readers
|
|
|
1098
|
+ * @returns {MDReader[]}
|
|
|
1099
|
+ */
|
|
|
1100
|
+ static sortReadersForTokenizing(readers) {
|
|
|
1101
|
+ const sorted = readers.slice();
|
|
|
1102
|
+ return MDReader.#kahnTopologicalSort(sorted, (a, b) => {
|
|
|
1103
|
+ return a.compareTokenizeOrdering(b);
|
|
|
1104
|
+ // if (ab != 0) return ab;
|
|
|
1105
|
+ // return -b.compareTokenizeOrdering(a);
|
|
|
1106
|
+ }, (elem) => elem.constructor.name);
|
|
|
1107
|
+ }
|
|
|
1108
|
+
|
|
|
1109
|
+ /**
|
|
|
1110
|
+ * @param {MDReader[]} readers
|
|
|
1111
|
+ * @returns {MDReader[]}
|
|
|
1112
|
+ */
|
|
|
1113
|
+ static sortReadersForSubstitution(readers) {
|
|
|
1114
|
+ var tuples = [];
|
|
|
1115
|
+ var maxPass = 1;
|
|
|
1116
|
+ for (const reader of readers) {
|
|
|
1117
|
+ const passCount = reader.substitutionPassCount;
|
|
|
1118
|
+ for (var pass = 1; pass <= passCount; pass++) {
|
|
|
1119
|
+ tuples.push([ pass, reader ]);
|
|
|
1120
|
+ }
|
|
|
1121
|
+ maxPass = Math.max(maxPass, pass);
|
|
|
1122
|
+ }
|
|
|
1123
|
+ var result = [];
|
|
|
1124
|
+ for (var pass = 1; pass <= maxPass; pass++) {
|
|
|
1125
|
+ var readersThisPass = tuples.filter((tup) => tup[0] == pass);
|
|
|
1126
|
+ const passResult = MDReader.#kahnTopologicalSort(readersThisPass, (a, b) => {
|
|
|
1127
|
+ const aReader = a[1];
|
|
|
1128
|
+ const bReader = b[1];
|
|
|
1129
|
+ return aReader.compareSubstituteOrdering(bReader, pass);
|
|
|
1130
|
+ }, (elem) => `${elem[1].constructor.name}:${elem[0]}`);
|
|
|
1131
|
+ result = result.concat(passResult);
|
|
|
1132
|
+ }
|
|
|
1133
|
+ return result;
|
|
|
1134
|
+ }
|
|
1033
|
1135
|
}
|
|
1034
|
1136
|
|
|
1035
|
1137
|
/**
|
|
|
@@ -1118,6 +1220,13 @@ class MDSubtextReader extends MDReader {
|
|
1118
|
1220
|
if (modifier) modifier.applyTo(block);
|
|
1119
|
1221
|
return block;
|
|
1120
|
1222
|
}
|
|
|
1223
|
+
|
|
|
1224
|
+ compareBlockOrdering(other) {
|
|
|
1225
|
+ if (other instanceof MDUnorderedListReader) {
|
|
|
1226
|
+ return -1;
|
|
|
1227
|
+ }
|
|
|
1228
|
+ return 0;
|
|
|
1229
|
+ }
|
|
1121
|
1230
|
}
|
|
1122
|
1231
|
|
|
1123
|
1232
|
/**
|
|
|
@@ -1410,6 +1519,13 @@ class MDHorizontalRuleReader extends MDReader {
|
|
1410
|
1519
|
}
|
|
1411
|
1520
|
return null;
|
|
1412
|
1521
|
}
|
|
|
1522
|
+
|
|
|
1523
|
+ compareBlockOrdering(other) {
|
|
|
1524
|
+ if (other instanceof MDUnorderedListReader) {
|
|
|
1525
|
+ return -1;
|
|
|
1526
|
+ }
|
|
|
1527
|
+ return 0;
|
|
|
1528
|
+ }
|
|
1413
|
1529
|
}
|
|
1414
|
1530
|
|
|
1415
|
1531
|
/**
|
|
|
@@ -1650,7 +1766,7 @@ class MDFootnoteReader extends MDReader {
|
|
1650
|
1766
|
return null;
|
|
1651
|
1767
|
}
|
|
1652
|
1768
|
|
|
1653
|
|
- substituteTokens(state, priority, tokens) {
|
|
|
1769
|
+ substituteTokens(state, pass, tokens) {
|
|
1654
|
1770
|
var match;
|
|
1655
|
1771
|
if (match = MDToken.findFirstTokens(tokens, [ MDTokenType.Footnote ])) {
|
|
1656
|
1772
|
let symbol = match.tokens[0].content;
|
|
|
@@ -1679,6 +1795,27 @@ class MDFootnoteReader extends MDReader {
|
|
1679
|
1795
|
if (Object.keys(state.footnotes).length == 0) return;
|
|
1680
|
1796
|
blocks.push(new MDFootnoteListNode());
|
|
1681
|
1797
|
}
|
|
|
1798
|
+
|
|
|
1799
|
+ compareBlockOrdering(other) {
|
|
|
1800
|
+ if (other instanceof MDLinkReader || other instanceof MDImageReader) {
|
|
|
1801
|
+ return -1;
|
|
|
1802
|
+ }
|
|
|
1803
|
+ return 0;
|
|
|
1804
|
+ }
|
|
|
1805
|
+
|
|
|
1806
|
+ compareTokenizeOrdering(other) {
|
|
|
1807
|
+ if (other instanceof MDLinkReader || other instanceof MDImageReader) {
|
|
|
1808
|
+ return -1;
|
|
|
1809
|
+ }
|
|
|
1810
|
+ return 0;
|
|
|
1811
|
+ }
|
|
|
1812
|
+
|
|
|
1813
|
+ compareSubstituteOrdering(other, pass) {
|
|
|
1814
|
+ if (other instanceof MDLinkReader || other instanceof MDImageReader) {
|
|
|
1815
|
+ return -1;
|
|
|
1816
|
+ }
|
|
|
1817
|
+ return 0;
|
|
|
1818
|
+ }
|
|
1682
|
1819
|
}
|
|
1683
|
1820
|
|
|
1684
|
1821
|
/**
|
|
|
@@ -1757,17 +1894,8 @@ class MDAbbreviationReader extends MDReader {
|
|
1757
|
1894
|
|
|
1758
|
1895
|
/**
|
|
1759
|
1896
|
* Block reader for simple paragraphs. Paragraphs are separated by a blank (or
|
|
1760
|
|
- * whitespace-only) line. This reader should be prioritized last since there
|
|
1761
|
|
- * is no distinguishing syntax.
|
|
1762
|
|
- *
|
|
1763
|
|
- * Example:
|
|
1764
|
|
- *
|
|
1765
|
|
- * > ```markdown
|
|
1766
|
|
- * > Lorem ipsum dolor
|
|
1767
|
|
- * > sit amet. This is all one paragraph.
|
|
1768
|
|
- * >
|
|
1769
|
|
- * > Beginning of a new paragraph.
|
|
1770
|
|
- * > ```
|
|
|
1897
|
+ * whitespace-only) line. This reader is prioritized after every other reader
|
|
|
1898
|
+ * since there is no distinguishing syntax.
|
|
1771
|
1899
|
*/
|
|
1772
|
1900
|
class MDParagraphReader extends MDReader {
|
|
1773
|
1901
|
readBlock(state) {
|
|
|
@@ -1791,6 +1919,10 @@ class MDParagraphReader extends MDReader {
|
|
1791
|
1919
|
}
|
|
1792
|
1920
|
return null;
|
|
1793
|
1921
|
}
|
|
|
1922
|
+
|
|
|
1923
|
+ compareBlockOrdering(other) {
|
|
|
1924
|
+ return 1; // always dead last
|
|
|
1925
|
+ }
|
|
1794
|
1926
|
}
|
|
1795
|
1927
|
|
|
1796
|
1928
|
/**
|
|
|
@@ -1798,33 +1930,44 @@ class MDParagraphReader extends MDReader {
|
|
1798
|
1930
|
* around some content.
|
|
1799
|
1931
|
*/
|
|
1800
|
1932
|
class MDSimplePairInlineReader extends MDReader {
|
|
|
1933
|
+ get substitutionPassCount() { return 4; }
|
|
|
1934
|
+
|
|
1801
|
1935
|
/**
|
|
1802
|
1936
|
* Attempts a substitution of a matched pair of delimiting token types.
|
|
1803
|
1937
|
* If successful, the substitution is performed on `tokens` and `true` is
|
|
1804
|
1938
|
* returned, otherwise `false` is returned and the array is untouched.
|
|
1805
|
1939
|
*
|
|
1806
|
|
- * If multiple `substitutePriority` values are specified, the first pass
|
|
|
1940
|
+ * If `this.substitutionPassCount` is greater than 1, the first pass
|
|
1807
|
1941
|
* will reject matches with the delimiting character inside the content
|
|
1808
|
|
- * tokens. If a single `substitutePriority` is given or a subsequent pass
|
|
1809
|
|
- * is performed with multiple values any contents will be accepted.
|
|
|
1942
|
+ * tokens. If the reader uses a single pass or a subsequent pass is performed
|
|
|
1943
|
+ * with multiple pass any contents will be accepted.
|
|
1810
|
1944
|
*
|
|
1811
|
1945
|
* @param {MDState} state
|
|
1812
|
|
- * @param {number} priority
|
|
|
1946
|
+ * @param {number} pass
|
|
1813
|
1947
|
* @param {MDToken[]} tokens
|
|
1814
|
1948
|
* @param {class} nodeClass
|
|
1815
|
1949
|
* @param {MDTokenType} delimiter
|
|
1816
|
1950
|
* @param {number} count - how many times the token is repeated to form the delimiter
|
|
1817
|
1951
|
* @returns {boolean} `true` if substitution performed, `false` if not
|
|
1818
|
1952
|
*/
|
|
1819
|
|
- attemptPair(state, priority, tokens, nodeClass, delimiter, count=1, plaintext=false) {
|
|
|
1953
|
+ attemptPair(state, pass, tokens, nodeClass, delimiter, count=1, plaintext=false) {
|
|
|
1954
|
+ // We do four passes. #1: doubles without inner tokens, #2: singles
|
|
|
1955
|
+ // without inner tokens, #3: doubles with paired inner tokens,
|
|
|
1956
|
+ // #4: singles with paired inner tokens
|
|
|
1957
|
+ if (count == 1 && pass != 2 && pass != 4) return;
|
|
|
1958
|
+ if (count == 2 && pass != 1 && pass != 3) return;
|
|
1820
|
1959
|
let delimiters = Array(count).fill(delimiter);
|
|
1821
|
|
- let firstPassPriority = (this.substitutePriority instanceof Array) ? this.substitutePriority[0] : null;
|
|
|
1960
|
+ const isFirstOfMultiplePasses = this.substitutionPassCount > 1 && pass == 1;
|
|
1822
|
1961
|
let match = MDToken.findPairedTokens(tokens, delimiters, delimiters, function(content) {
|
|
1823
|
1962
|
const firstType = content[0] instanceof MDToken ? content[0].type : null;
|
|
1824
|
1963
|
const lastType = content[content.length - 1] instanceof MDToken ? content[content.length - 1].type : null;
|
|
1825
|
1964
|
if (firstType == MDTokenType.Whitespace) return false;
|
|
1826
|
1965
|
if (lastType == MDTokenType.Whitespace) return false;
|
|
1827
|
|
- if (priority == firstPassPriority) {
|
|
|
1966
|
+ for (const token of content) {
|
|
|
1967
|
+ // Don't allow nesting
|
|
|
1968
|
+ if (token.constructor == nodeClass) return false;
|
|
|
1969
|
+ }
|
|
|
1970
|
+ if (isFirstOfMultiplePasses) {
|
|
1828
|
1971
|
var innerCount = 0;
|
|
1829
|
1972
|
for (let token of content) {
|
|
1830
|
1973
|
if (token instanceof MDToken && token.type == delimiter) innerCount++;
|
|
|
@@ -1849,11 +1992,18 @@ class MDEmphasisReader extends MDSimplePairInlineReader {
|
|
1849
|
1992
|
return null;
|
|
1850
|
1993
|
}
|
|
1851
|
1994
|
|
|
1852
|
|
- substituteTokens(state, priority, tokens) {
|
|
1853
|
|
- if (this.attemptPair(state, priority, tokens, MDEmphasisNode, MDTokenType.Asterisk)) return true;
|
|
1854
|
|
- if (this.attemptPair(state, priority, tokens, MDEmphasisNode, MDTokenType.Underscore)) return true;
|
|
|
1995
|
+ substituteTokens(state, pass, tokens) {
|
|
|
1996
|
+ if (this.attemptPair(state, pass, tokens, MDEmphasisNode, MDTokenType.Asterisk)) return true;
|
|
|
1997
|
+ if (this.attemptPair(state, pass, tokens, MDEmphasisNode, MDTokenType.Underscore)) return true;
|
|
1855
|
1998
|
return false;
|
|
1856
|
1999
|
}
|
|
|
2000
|
+
|
|
|
2001
|
+ compareSubstituteOrdering(other, pass) {
|
|
|
2002
|
+ if (other instanceof MDStrongReader) {
|
|
|
2003
|
+ return 1;
|
|
|
2004
|
+ }
|
|
|
2005
|
+ return 0;
|
|
|
2006
|
+ }
|
|
1857
|
2007
|
}
|
|
1858
|
2008
|
|
|
1859
|
2009
|
class MDStrongReader extends MDSimplePairInlineReader {
|
|
|
@@ -1863,11 +2013,18 @@ class MDStrongReader extends MDSimplePairInlineReader {
|
|
1863
|
2013
|
return null;
|
|
1864
|
2014
|
}
|
|
1865
|
2015
|
|
|
1866
|
|
- substituteTokens(state, priority, tokens) {
|
|
1867
|
|
- if (this.attemptPair(state, priority, tokens, MDStrongNode, MDTokenType.Asterisk, 2)) return true;
|
|
1868
|
|
- if (this.attemptPair(state, priority, tokens, MDStrongNode, MDTokenType.Underscore, 2)) return true;
|
|
|
2016
|
+ substituteTokens(state, pass, tokens) {
|
|
|
2017
|
+ if (this.attemptPair(state, pass, tokens, MDStrongNode, MDTokenType.Asterisk, 2)) return true;
|
|
|
2018
|
+ if (this.attemptPair(state, pass, tokens, MDStrongNode, MDTokenType.Underscore, 2)) return true;
|
|
1869
|
2019
|
return false;
|
|
1870
|
2020
|
}
|
|
|
2021
|
+
|
|
|
2022
|
+ compareSubstituteOrdering(other, pass) {
|
|
|
2023
|
+ if (other instanceof MDEmphasisReader) {
|
|
|
2024
|
+ return -1;
|
|
|
2025
|
+ }
|
|
|
2026
|
+ return 0;
|
|
|
2027
|
+ }
|
|
1871
|
2028
|
}
|
|
1872
|
2029
|
|
|
1873
|
2030
|
class MDStrikethroughReader extends MDSimplePairInlineReader {
|
|
|
@@ -1876,9 +2033,11 @@ class MDStrikethroughReader extends MDSimplePairInlineReader {
|
|
1876
|
2033
|
return null;
|
|
1877
|
2034
|
}
|
|
1878
|
2035
|
|
|
1879
|
|
- substituteTokens(state, priority, tokens) {
|
|
1880
|
|
- if (this.attemptPair(state, priority, tokens, MDStrikethroughNode, MDTokenType.Tilde, 2)) return true;
|
|
1881
|
|
- if (this.attemptPair(state, priority, tokens, MDStrikethroughNode, MDTokenType.Tilde)) return true;
|
|
|
2036
|
+ substituteTokens(state, pass, tokens) {
|
|
|
2037
|
+ if (this.attemptPair(state, pass, tokens, MDStrikethroughNode, MDTokenType.Tilde, 2)) return true;
|
|
|
2038
|
+ if (state.config.strikethroughSingleTildeEnabled) {
|
|
|
2039
|
+ if (this.attemptPair(state, pass, tokens, MDStrikethroughNode, MDTokenType.Tilde)) return true;
|
|
|
2040
|
+ }
|
|
1882
|
2041
|
return false;
|
|
1883
|
2042
|
}
|
|
1884
|
2043
|
}
|
|
|
@@ -1889,8 +2048,15 @@ class MDUnderlineReader extends MDSimplePairInlineReader {
|
|
1889
|
2048
|
return null;
|
|
1890
|
2049
|
}
|
|
1891
|
2050
|
|
|
1892
|
|
- substituteTokens(state, priority, tokens) {
|
|
1893
|
|
- return this.attemptPair(state, priority, tokens, MDUnderlineNode, MDTokenType.Underscore, 2);
|
|
|
2051
|
+ substituteTokens(state, pass, tokens) {
|
|
|
2052
|
+ return this.attemptPair(state, pass, tokens, MDUnderlineNode, MDTokenType.Underscore, 2);
|
|
|
2053
|
+ }
|
|
|
2054
|
+
|
|
|
2055
|
+ compareSubstituteOrdering(other, pass) {
|
|
|
2056
|
+ if (other instanceof MDStrongReader) {
|
|
|
2057
|
+ return -1;
|
|
|
2058
|
+ }
|
|
|
2059
|
+ return 0;
|
|
1894
|
2060
|
}
|
|
1895
|
2061
|
}
|
|
1896
|
2062
|
|
|
|
@@ -1900,8 +2066,8 @@ class MDHighlightReader extends MDSimplePairInlineReader {
|
|
1900
|
2066
|
return null;
|
|
1901
|
2067
|
}
|
|
1902
|
2068
|
|
|
1903
|
|
- substituteTokens(state, priority, tokens) {
|
|
1904
|
|
- return this.attemptPair(state, priority, tokens, MDHighlightNode, MDTokenType.Equal, 2);
|
|
|
2069
|
+ substituteTokens(state, pass, tokens) {
|
|
|
2070
|
+ return this.attemptPair(state, pass, tokens, MDHighlightNode, MDTokenType.Equal, 2);
|
|
1905
|
2071
|
}
|
|
1906
|
2072
|
}
|
|
1907
|
2073
|
|
|
|
@@ -1909,10 +2075,6 @@ class MDLinkReader extends MDReader {
|
|
1909
|
2075
|
static #simpleEmailRegex = new RegExp("^<(" + MDUtils.baseEmailRegex.source + ")>", "i"); // 1=email
|
|
1910
|
2076
|
static #simpleURLRegex = new RegExp("^<(" + MDUtils.baseURLRegex.source + ")>", "i"); // 1=URL
|
|
1911
|
2077
|
|
|
1912
|
|
- constructor(tokenizePriority=0.0, substitutePriority=0.0) {
|
|
1913
|
|
- super(tokenizePriority, substitutePriority);
|
|
1914
|
|
- }
|
|
1915
|
|
-
|
|
1916
|
2078
|
readToken(state, line) {
|
|
1917
|
2079
|
var groups;
|
|
1918
|
2080
|
if (groups = MDUtils.tokenizeLabel(line)) {
|
|
|
@@ -1933,7 +2095,7 @@ class MDLinkReader extends MDReader {
|
|
1933
|
2095
|
return null;
|
|
1934
|
2096
|
}
|
|
1935
|
2097
|
|
|
1936
|
|
- substituteTokens(state, priority, tokens) {
|
|
|
2098
|
+ substituteTokens(state, pass, tokens) {
|
|
1937
|
2099
|
var match;
|
|
1938
|
2100
|
if (match = MDToken.findFirstTokens(tokens, [ MDTokenType.Label, MDTokenType.META_OptionalWhitespace, MDTokenType.URL ])) {
|
|
1939
|
2101
|
let text = match.tokens[0].content;
|
|
|
@@ -2009,7 +2171,7 @@ class MDReferencedLinkReader extends MDLinkReader {
|
|
2009
|
2171
|
return new MDNode([]); // empty
|
|
2010
|
2172
|
}
|
|
2011
|
2173
|
|
|
2012
|
|
- substituteTokens(state, priority, tokens) {
|
|
|
2174
|
+ substituteTokens(state, pass, tokens) {
|
|
2013
|
2175
|
var match;
|
|
2014
|
2176
|
if (match = MDToken.findFirstTokens(tokens, [ MDTokenType.Label, MDTokenType.META_OptionalWhitespace, MDTokenType.Label ])) {
|
|
2015
|
2177
|
let text = match.tokens[0].content;
|
|
|
@@ -2022,8 +2184,6 @@ class MDReferencedLinkReader extends MDLinkReader {
|
|
2022
|
2184
|
}
|
|
2023
|
2185
|
|
|
2024
|
2186
|
class MDImageReader extends MDLinkReader {
|
|
2025
|
|
- substituteTokens(state, priority, tokens) {}
|
|
2026
|
|
-
|
|
2027
|
2187
|
readToken(state, line) {
|
|
2028
|
2188
|
const s = super.readToken(state, line);
|
|
2029
|
2189
|
if (s) return s;
|
|
|
@@ -2031,7 +2191,7 @@ class MDImageReader extends MDLinkReader {
|
|
2031
|
2191
|
return null;
|
|
2032
|
2192
|
}
|
|
2033
|
2193
|
|
|
2034
|
|
- substituteTokens(state, priority, tokens) {
|
|
|
2194
|
+ substituteTokens(state, pass, tokens) {
|
|
2035
|
2195
|
var match;
|
|
2036
|
2196
|
if (match = MDToken.findFirstTokens(tokens, [ MDTokenType.Bang, MDTokenType.Label, MDTokenType.META_OptionalWhitespace, MDTokenType.URL ])) {
|
|
2037
|
2197
|
let alt = match.tokens[1].content;
|
|
|
@@ -2052,10 +2212,24 @@ class MDImageReader extends MDLinkReader {
|
|
2052
|
2212
|
}
|
|
2053
|
2213
|
return false;
|
|
2054
|
2214
|
}
|
|
|
2215
|
+
|
|
|
2216
|
+ compareSubstituteOrdering(other, pass) {
|
|
|
2217
|
+ if (other instanceof MDLinkReader) {
|
|
|
2218
|
+ return -1;
|
|
|
2219
|
+ }
|
|
|
2220
|
+ return 0;
|
|
|
2221
|
+ }
|
|
2055
|
2222
|
}
|
|
2056
|
2223
|
|
|
2057
|
2224
|
class MDReferencedImageReader extends MDReferencedLinkReader {
|
|
2058
|
2225
|
readBlock(state) { return null; }
|
|
|
2226
|
+
|
|
|
2227
|
+ compareSubstituteOrdering(other, pass) {
|
|
|
2228
|
+ if (other instanceof MDLinkReader) {
|
|
|
2229
|
+ return -1;
|
|
|
2230
|
+ }
|
|
|
2231
|
+ return 0;
|
|
|
2232
|
+ }
|
|
2059
|
2233
|
}
|
|
2060
|
2234
|
|
|
2061
|
2235
|
class MDCodeSpanReader extends MDSimplePairInlineReader {
|
|
|
@@ -2064,9 +2238,9 @@ class MDCodeSpanReader extends MDSimplePairInlineReader {
|
|
2064
|
2238
|
return null;
|
|
2065
|
2239
|
}
|
|
2066
|
2240
|
|
|
2067
|
|
- substituteTokens(state, priority, tokens) {
|
|
2068
|
|
- if (this.attemptPair(state, priority, tokens, MDCodeNode, MDTokenType.Backtick, 2, true)) return true;
|
|
2069
|
|
- if (this.attemptPair(state, priority, tokens, MDCodeNode, MDTokenType.Backtick, 1, true)) return true;
|
|
|
2241
|
+ substituteTokens(state, pass, tokens) {
|
|
|
2242
|
+ if (this.attemptPair(state, pass, tokens, MDCodeNode, MDTokenType.Backtick, 2, true)) return true;
|
|
|
2243
|
+ if (this.attemptPair(state, pass, tokens, MDCodeNode, MDTokenType.Backtick, 1, true)) return true;
|
|
2070
|
2244
|
}
|
|
2071
|
2245
|
}
|
|
2072
|
2246
|
|
|
|
@@ -2076,8 +2250,20 @@ class MDSubscriptReader extends MDSimplePairInlineReader {
|
|
2076
|
2250
|
return null;
|
|
2077
|
2251
|
}
|
|
2078
|
2252
|
|
|
2079
|
|
- substituteTokens(state, priority, tokens) {
|
|
2080
|
|
- return this.attemptPair(state, priority, tokens, MDSubscriptNode, MDTokenType.Tilde);
|
|
|
2253
|
+ preProcess(state) {
|
|
|
2254
|
+ // Causes a conflict
|
|
|
2255
|
+ state.config.strikethroughSingleTildeEnabled = false;
|
|
|
2256
|
+ }
|
|
|
2257
|
+
|
|
|
2258
|
+ substituteTokens(state, pass, tokens) {
|
|
|
2259
|
+ return this.attemptPair(state, pass, tokens, MDSubscriptNode, MDTokenType.Tilde);
|
|
|
2260
|
+ }
|
|
|
2261
|
+
|
|
|
2262
|
+ compareSubstituteOrdering(other, pass) {
|
|
|
2263
|
+ if (other instanceof MDStrikethroughReader) {
|
|
|
2264
|
+ return -1;
|
|
|
2265
|
+ }
|
|
|
2266
|
+ return 0;
|
|
2081
|
2267
|
}
|
|
2082
|
2268
|
}
|
|
2083
|
2269
|
|
|
|
@@ -2087,8 +2273,8 @@ class MDSuperscriptReader extends MDSimplePairInlineReader {
|
|
2087
|
2273
|
return null;
|
|
2088
|
2274
|
}
|
|
2089
|
2275
|
|
|
2090
|
|
- substituteTokens(state, priority, tokens) {
|
|
2091
|
|
- return this.attemptPair(state, priority, tokens, MDSuperscriptNode, MDTokenType.Caret);
|
|
|
2276
|
+ substituteTokens(state, pass, tokens) {
|
|
|
2277
|
+ return this.attemptPair(state, pass, tokens, MDSuperscriptNode, MDTokenType.Caret);
|
|
2092
|
2278
|
}
|
|
2093
|
2279
|
}
|
|
2094
|
2280
|
|
|
|
@@ -2099,7 +2285,7 @@ class MDHTMLTagReader extends MDReader {
|
|
2099
|
2285
|
return new MDToken(tag.original, MDTokenType.HTMLTag, null, null, tag)
|
|
2100
|
2286
|
}
|
|
2101
|
2287
|
|
|
2102
|
|
- substituteTokens(state, priority, tokens) {
|
|
|
2288
|
+ substituteTokens(state, pass, tokens) {
|
|
2103
|
2289
|
var match;
|
|
2104
|
2290
|
if (match = MDToken.findFirstTokens(tokens, [ MDTokenType.HTMLTag ])) {
|
|
2105
|
2291
|
const tag = match.tokens[0].tag
|
|
|
@@ -2117,7 +2303,7 @@ class MDModifierReader extends MDReader {
|
|
2117
|
2303
|
return null;
|
|
2118
|
2304
|
}
|
|
2119
|
2305
|
|
|
2120
|
|
- substituteTokens(state, priority, tokens) {
|
|
|
2306
|
+ substituteTokens(state, pass, tokens) {
|
|
2121
|
2307
|
// Modifiers are applied elsewhere, and if they're not it's fine if they're
|
|
2122
|
2308
|
// rendered as the original syntax.
|
|
2123
|
2309
|
return false;
|
|
|
@@ -3184,7 +3370,7 @@ class MDTagModifier {
|
|
3184
|
3370
|
}
|
|
3185
|
3371
|
|
|
3186
|
3372
|
class MDConfig {
|
|
3187
|
|
-
|
|
|
3373
|
+ strikethroughSingleTildeEnabled = true;
|
|
3188
|
3374
|
}
|
|
3189
|
3375
|
|
|
3190
|
3376
|
class Markdown {
|
|
|
@@ -3193,22 +3379,22 @@ class Markdown {
|
|
3193
|
3379
|
* @type {MDReader[]}
|
|
3194
|
3380
|
*/
|
|
3195
|
3381
|
static standardReaders = [
|
|
3196
|
|
- new MDUnderlinedHeaderReader(0),
|
|
3197
|
|
- new MDHashHeaderReader(1),
|
|
3198
|
|
- new MDBlockQuoteReader(3),
|
|
3199
|
|
- new MDHorizontalRuleReader(9), // prioritize before unordered list
|
|
3200
|
|
- new MDUnorderedListReader(10),
|
|
3201
|
|
- new MDOrderedListReader(11),
|
|
3202
|
|
- new MDFencedCodeBlockReader(20),
|
|
3203
|
|
- new MDIndentedCodeBlockReader(21),
|
|
3204
|
|
- new MDParagraphReader(100),
|
|
3205
|
|
-
|
|
3206
|
|
- new MDStrongReader(101, 10, [ 0, 2 ]), // prioritize before emphasis (both use * and _)
|
|
3207
|
|
- new MDEmphasisReader(101, 15, [ 5, 55 ]),
|
|
3208
|
|
- new MDCodeSpanReader(101, 20, [ 10, 60 ]),
|
|
3209
|
|
- new MDImageReader(101, 30, 15), // prioritize before links
|
|
3210
|
|
- new MDLinkReader(101, 35, 20),
|
|
3211
|
|
- new MDHTMLTagReader(101, 80, 30),
|
|
|
3382
|
+ new MDUnderlinedHeaderReader(),
|
|
|
3383
|
+ new MDHashHeaderReader(),
|
|
|
3384
|
+ new MDBlockQuoteReader(),
|
|
|
3385
|
+ new MDHorizontalRuleReader(),
|
|
|
3386
|
+ new MDUnorderedListReader(),
|
|
|
3387
|
+ new MDOrderedListReader(),
|
|
|
3388
|
+ new MDFencedCodeBlockReader(),
|
|
|
3389
|
+ new MDIndentedCodeBlockReader(),
|
|
|
3390
|
+ new MDParagraphReader(),
|
|
|
3391
|
+
|
|
|
3392
|
+ new MDStrongReader(),
|
|
|
3393
|
+ new MDEmphasisReader(),
|
|
|
3394
|
+ new MDCodeSpanReader(),
|
|
|
3395
|
+ new MDImageReader(),
|
|
|
3396
|
+ new MDLinkReader(),
|
|
|
3397
|
+ new MDHTMLTagReader(),
|
|
3212
|
3398
|
];
|
|
3213
|
3399
|
|
|
3214
|
3400
|
/**
|
|
|
@@ -3217,20 +3403,20 @@ class Markdown {
|
|
3217
|
3403
|
*/
|
|
3218
|
3404
|
static allReaders = [
|
|
3219
|
3405
|
...this.standardReaders,
|
|
3220
|
|
- new MDSubtextReader(2),
|
|
3221
|
|
- new MDTableReader(40),
|
|
3222
|
|
- new MDDefinitionListReader(50),
|
|
3223
|
|
- new MDFootnoteReader(60, 5, 40), // prioritize before links and images
|
|
3224
|
|
- new MDAbbreviationReader(70),
|
|
3225
|
|
-
|
|
3226
|
|
- new MDUnderlineReader(101, 5, [ 9, 11 ]), // prioritize before emphasis and strong (both use _)
|
|
3227
|
|
- // new MDSubscriptReader(101, 20, [ 11, 51 ]), // prioritize before strikethrough (both use ~)
|
|
3228
|
|
- new MDStrikethroughReader(101, 21, [ 12, 50 ]),
|
|
3229
|
|
- new MDHighlightReader(101, 23, [ 13, 51 ]),
|
|
3230
|
|
- new MDSuperscriptReader(101, 24, [ 14, 54 ]),
|
|
3231
|
|
- new MDReferencedImageReader(91, 31, 16),
|
|
3232
|
|
- new MDReferencedLinkReader(90, 36, 21),
|
|
3233
|
|
- new MDModifierReader(101, 90, 45),
|
|
|
3406
|
+ new MDSubtextReader(),
|
|
|
3407
|
+ new MDTableReader(),
|
|
|
3408
|
+ new MDDefinitionListReader(),
|
|
|
3409
|
+ new MDFootnoteReader(),
|
|
|
3410
|
+ new MDAbbreviationReader(),
|
|
|
3411
|
+
|
|
|
3412
|
+ new MDUnderlineReader(),
|
|
|
3413
|
+ new MDSubscriptReader(),
|
|
|
3414
|
+ new MDStrikethroughReader(),
|
|
|
3415
|
+ new MDHighlightReader(),
|
|
|
3416
|
+ new MDSuperscriptReader(),
|
|
|
3417
|
+ new MDReferencedImageReader(),
|
|
|
3418
|
+ new MDReferencedLinkReader(),
|
|
|
3419
|
+ new MDModifierReader(),
|
|
3234
|
3420
|
];
|
|
3235
|
3421
|
|
|
3236
|
3422
|
/**
|
|
|
@@ -3243,34 +3429,32 @@ class Markdown {
|
|
3243
|
3429
|
*/
|
|
3244
|
3430
|
static completeParser = new Markdown(this.allReaders);
|
|
3245
|
3431
|
|
|
|
3432
|
+ /**
|
|
|
3433
|
+ * @type {MDConfig}
|
|
|
3434
|
+ */
|
|
|
3435
|
+ config;
|
|
|
3436
|
+
|
|
3246
|
3437
|
#readers;
|
|
3247
|
3438
|
|
|
|
3439
|
+ /** @type {MDReader[]} */
|
|
3248
|
3440
|
#readersByBlockPriority;
|
|
|
3441
|
+ /** @type {MDReader[]} */
|
|
3249
|
3442
|
#readersByTokenPriority;
|
|
|
3443
|
+ /** @type {Array} */
|
|
3250
|
3444
|
#readersBySubstitutePriority;
|
|
3251
|
3445
|
|
|
3252
|
3446
|
/**
|
|
3253
|
3447
|
* Creates a Markdown parser with the given syntax readers.
|
|
3254
|
3448
|
*
|
|
3255
|
3449
|
* @param {MDReader[]} readers
|
|
|
3450
|
+ * @param {MDConfig} config
|
|
3256
|
3451
|
*/
|
|
3257
|
|
- constructor(readers=Markdown.allReaders) {
|
|
|
3452
|
+ constructor(readers=Markdown.allReaders, config=new MDConfig()) {
|
|
3258
|
3453
|
this.#readers = readers;
|
|
3259
|
|
- const duplicateAndSort = function(priorityFn) {
|
|
3260
|
|
- var result = [];
|
|
3261
|
|
- for (const reader of readers) {
|
|
3262
|
|
- const p = priorityFn(reader);
|
|
3263
|
|
- const priorities = (p instanceof Array) ? p : [ p ];
|
|
3264
|
|
- for (const priority of priorities) {
|
|
3265
|
|
- result.push([priority, reader]);
|
|
3266
|
|
- }
|
|
3267
|
|
- }
|
|
3268
|
|
- result.sort((a, b) => a[0] - b[0]);
|
|
3269
|
|
- return result;
|
|
3270
|
|
- }
|
|
3271
|
|
- this.#readersByBlockPriority = duplicateAndSort((reader) => reader.blockPriority);
|
|
3272
|
|
- this.#readersByTokenPriority = duplicateAndSort((reader) => reader.tokenizePriority);
|
|
3273
|
|
- this.#readersBySubstitutePriority = duplicateAndSort((reader) => reader.substitutePriority);
|
|
|
3454
|
+ this.config = config;
|
|
|
3455
|
+ this.#readersByBlockPriority = MDReader.sortReaderForBlocks(readers);
|
|
|
3456
|
+ this.#readersByTokenPriority = MDReader.sortReadersForTokenizing(readers);
|
|
|
3457
|
+ this.#readersBySubstitutePriority = MDReader.sortReadersForSubstitution(readers);
|
|
3274
|
3458
|
}
|
|
3275
|
3459
|
|
|
3276
|
3460
|
/**
|
|
|
@@ -3282,6 +3466,7 @@ class Markdown {
|
|
3282
|
3466
|
toHTML(markdown) {
|
|
3283
|
3467
|
const lines = markdown.split(/(?:\n|\r|\r\n)/);
|
|
3284
|
3468
|
const state = new MDState(lines,
|
|
|
3469
|
+ this.config,
|
|
3285
|
3470
|
this.#readersByBlockPriority,
|
|
3286
|
3471
|
this.#readersByTokenPriority,
|
|
3287
|
3472
|
this.#readersBySubstitutePriority);
|