@tinta-lang/syntax 0.0.0-stage → 0.1.0-dev.0

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.
Files changed (245) hide show
  1. package/LICENSE +21 -0
  2. package/THIRD_PARTY_NOTICES.txt +13651 -0
  3. package/dist/directive.d.ts +40 -0
  4. package/dist/editing.d.ts +46 -0
  5. package/dist/enrichment.d.ts +5 -0
  6. package/dist/expression.d.ts +26 -0
  7. package/dist/image-destinations.d.ts +3 -0
  8. package/dist/index.d.ts +8 -0
  9. package/dist/index.js +10118 -0
  10. package/dist/parser.d.ts +40 -0
  11. package/dist/registry.d.ts +144 -0
  12. package/dist/source.d.ts +28 -0
  13. package/package.json +280 -3
  14. package/parser-provenance.json +1419 -0
  15. package/patches/README.md +5 -0
  16. package/patches/micromark.patch +84 -0
  17. package/vendor/@noble/hashes/LICENSE +21 -0
  18. package/vendor/@noble/hashes/_md.js +209 -0
  19. package/vendor/@noble/hashes/_u64.js +77 -0
  20. package/vendor/@noble/hashes/package.json +91 -0
  21. package/vendor/@noble/hashes/sha2.js +446 -0
  22. package/vendor/@noble/hashes/utils.js +687 -0
  23. package/vendor/character-entities/index.js +2132 -0
  24. package/vendor/character-entities/license +22 -0
  25. package/vendor/character-entities/package.json +78 -0
  26. package/vendor/decode-named-character-reference/index.js +19 -0
  27. package/vendor/decode-named-character-reference/license +22 -0
  28. package/vendor/decode-named-character-reference/package.json +90 -0
  29. package/vendor/devlop/lib/default.js +9 -0
  30. package/vendor/devlop/license +22 -0
  31. package/vendor/devlop/package.json +80 -0
  32. package/vendor/longest-streak/index.js +36 -0
  33. package/vendor/longest-streak/license +22 -0
  34. package/vendor/longest-streak/package.json +73 -0
  35. package/vendor/markdown-table/index.js +393 -0
  36. package/vendor/markdown-table/license +22 -0
  37. package/vendor/markdown-table/package.json +77 -0
  38. package/vendor/mdast-util-from-markdown/index.js +2 -0
  39. package/vendor/mdast-util-from-markdown/lib/index.js +1270 -0
  40. package/vendor/mdast-util-from-markdown/license +22 -0
  41. package/vendor/mdast-util-from-markdown/package.json +98 -0
  42. package/vendor/mdast-util-gfm-strikethrough/index.js +5 -0
  43. package/vendor/mdast-util-gfm-strikethrough/lib/index.js +133 -0
  44. package/vendor/mdast-util-gfm-strikethrough/license +22 -0
  45. package/vendor/mdast-util-gfm-strikethrough/package.json +84 -0
  46. package/vendor/mdast-util-gfm-table/index.js +2 -0
  47. package/vendor/mdast-util-gfm-table/lib/index.js +300 -0
  48. package/vendor/mdast-util-gfm-table/license +22 -0
  49. package/vendor/mdast-util-gfm-table/package.json +101 -0
  50. package/vendor/mdast-util-gfm-task-list-item/index.js +4 -0
  51. package/vendor/mdast-util-gfm-task-list-item/lib/index.js +141 -0
  52. package/vendor/mdast-util-gfm-task-list-item/license +22 -0
  53. package/vendor/mdast-util-gfm-task-list-item/package.json +90 -0
  54. package/vendor/mdast-util-phrasing/index.js +1 -0
  55. package/vendor/mdast-util-phrasing/lib/index.js +45 -0
  56. package/vendor/mdast-util-phrasing/license +23 -0
  57. package/vendor/mdast-util-phrasing/package.json +78 -0
  58. package/vendor/mdast-util-to-markdown/index.js +3 -0
  59. package/vendor/mdast-util-to-markdown/lib/configure.js +98 -0
  60. package/vendor/mdast-util-to-markdown/lib/handle/blockquote.js +40 -0
  61. package/vendor/mdast-util-to-markdown/lib/handle/break.js +41 -0
  62. package/vendor/mdast-util-to-markdown/lib/handle/code.js +86 -0
  63. package/vendor/mdast-util-to-markdown/lib/handle/definition.js +83 -0
  64. package/vendor/mdast-util-to-markdown/lib/handle/emphasis.js +67 -0
  65. package/vendor/mdast-util-to-markdown/lib/handle/heading.js +84 -0
  66. package/vendor/mdast-util-to-markdown/lib/handle/html.js +27 -0
  67. package/vendor/mdast-util-to-markdown/lib/handle/image-reference.js +78 -0
  68. package/vendor/mdast-util-to-markdown/lib/handle/image.js +92 -0
  69. package/vendor/mdast-util-to-markdown/lib/handle/index.js +45 -0
  70. package/vendor/mdast-util-to-markdown/lib/handle/inline-code.js +86 -0
  71. package/vendor/mdast-util-to-markdown/lib/handle/link-reference.js +78 -0
  72. package/vendor/mdast-util-to-markdown/lib/handle/link.js +129 -0
  73. package/vendor/mdast-util-to-markdown/lib/handle/list-item.js +73 -0
  74. package/vendor/mdast-util-to-markdown/lib/handle/list.js +107 -0
  75. package/vendor/mdast-util-to-markdown/lib/handle/paragraph.js +27 -0
  76. package/vendor/mdast-util-to-markdown/lib/handle/root.js +34 -0
  77. package/vendor/mdast-util-to-markdown/lib/handle/strong.js +67 -0
  78. package/vendor/mdast-util-to-markdown/lib/handle/text.js +30 -0
  79. package/vendor/mdast-util-to-markdown/lib/handle/thematic-break.js +27 -0
  80. package/vendor/mdast-util-to-markdown/lib/index.js +213 -0
  81. package/vendor/mdast-util-to-markdown/lib/join.js +56 -0
  82. package/vendor/mdast-util-to-markdown/lib/unsafe.js +160 -0
  83. package/vendor/mdast-util-to-markdown/lib/util/association.js +33 -0
  84. package/vendor/mdast-util-to-markdown/lib/util/character.js +32 -0
  85. package/vendor/mdast-util-to-markdown/lib/util/check-bullet-ordered.js +25 -0
  86. package/vendor/mdast-util-to-markdown/lib/util/check-bullet-other.js +42 -0
  87. package/vendor/mdast-util-to-markdown/lib/util/check-bullet.js +25 -0
  88. package/vendor/mdast-util-to-markdown/lib/util/check-emphasis.js +25 -0
  89. package/vendor/mdast-util-to-markdown/lib/util/check-fence.js +25 -0
  90. package/vendor/mdast-util-to-markdown/lib/util/check-list-item-indent.js +25 -0
  91. package/vendor/mdast-util-to-markdown/lib/util/check-quote.js +25 -0
  92. package/vendor/mdast-util-to-markdown/lib/util/check-rule-repetition.js +25 -0
  93. package/vendor/mdast-util-to-markdown/lib/util/check-rule.js +25 -0
  94. package/vendor/mdast-util-to-markdown/lib/util/check-strong.js +25 -0
  95. package/vendor/mdast-util-to-markdown/lib/util/compile-pattern.js +30 -0
  96. package/vendor/mdast-util-to-markdown/lib/util/container-flow.js +93 -0
  97. package/vendor/mdast-util-to-markdown/lib/util/container-phrasing.js +704 -0
  98. package/vendor/mdast-util-to-markdown/lib/util/encode-character-reference.js +11 -0
  99. package/vendor/mdast-util-to-markdown/lib/util/encode-info.js +82 -0
  100. package/vendor/mdast-util-to-markdown/lib/util/format-code-as-indented.js +27 -0
  101. package/vendor/mdast-util-to-markdown/lib/util/format-heading-as-setext.js +39 -0
  102. package/vendor/mdast-util-to-markdown/lib/util/format-link-as-autolink.js +39 -0
  103. package/vendor/mdast-util-to-markdown/lib/util/html-kind.js +63 -0
  104. package/vendor/mdast-util-to-markdown/lib/util/indent-lines.js +40 -0
  105. package/vendor/mdast-util-to-markdown/lib/util/pattern-in-scope.js +52 -0
  106. package/vendor/mdast-util-to-markdown/lib/util/safe.js +263 -0
  107. package/vendor/mdast-util-to-markdown/lib/util/track.js +55 -0
  108. package/vendor/mdast-util-to-markdown/license +22 -0
  109. package/vendor/mdast-util-to-markdown/package.json +88 -0
  110. package/vendor/mdast-util-to-string/index.js +5 -0
  111. package/vendor/mdast-util-to-string/lib/index.js +108 -0
  112. package/vendor/mdast-util-to-string/license +22 -0
  113. package/vendor/mdast-util-to-string/package.json +78 -0
  114. package/vendor/micromark/index.js +60 -0
  115. package/vendor/micromark/lib/compile.js +1068 -0
  116. package/vendor/micromark/lib/constructs.js +85 -0
  117. package/vendor/micromark/lib/create-tokenizer.js +615 -0
  118. package/vendor/micromark/lib/initialize/content.js +79 -0
  119. package/vendor/micromark/lib/initialize/document.js +370 -0
  120. package/vendor/micromark/lib/initialize/flow.js +58 -0
  121. package/vendor/micromark/lib/initialize/text.js +216 -0
  122. package/vendor/micromark/lib/parse.js +56 -0
  123. package/vendor/micromark/lib/postprocess.js +18 -0
  124. package/vendor/micromark/lib/preprocess.js +112 -0
  125. package/vendor/micromark/license +22 -0
  126. package/vendor/micromark/package.json +87 -0
  127. package/vendor/micromark-core-commonmark/index.js +22 -0
  128. package/vendor/micromark-core-commonmark/lib/attention.js +231 -0
  129. package/vendor/micromark-core-commonmark/lib/autolink.js +233 -0
  130. package/vendor/micromark-core-commonmark/lib/blank-line.js +61 -0
  131. package/vendor/micromark-core-commonmark/lib/block-quote.js +143 -0
  132. package/vendor/micromark-core-commonmark/lib/character-escape.js +64 -0
  133. package/vendor/micromark-core-commonmark/lib/character-reference.js +149 -0
  134. package/vendor/micromark-core-commonmark/lib/code-fenced.js +422 -0
  135. package/vendor/micromark-core-commonmark/lib/code-indented.js +159 -0
  136. package/vendor/micromark-core-commonmark/lib/code-text.js +225 -0
  137. package/vendor/micromark-core-commonmark/lib/content.js +163 -0
  138. package/vendor/micromark-core-commonmark/lib/definition.js +254 -0
  139. package/vendor/micromark-core-commonmark/lib/hard-break-escape.js +60 -0
  140. package/vendor/micromark-core-commonmark/lib/heading-atx.js +191 -0
  141. package/vendor/micromark-core-commonmark/lib/html-flow.js +827 -0
  142. package/vendor/micromark-core-commonmark/lib/html-text.js +678 -0
  143. package/vendor/micromark-core-commonmark/lib/label-end.js +561 -0
  144. package/vendor/micromark-core-commonmark/lib/label-start-image.js +110 -0
  145. package/vendor/micromark-core-commonmark/lib/label-start-link.js +63 -0
  146. package/vendor/micromark-core-commonmark/lib/line-ending.js +33 -0
  147. package/vendor/micromark-core-commonmark/lib/list.js +213 -0
  148. package/vendor/micromark-core-commonmark/lib/partial-non-lazy-continuation.js +61 -0
  149. package/vendor/micromark-core-commonmark/lib/setext-underline.js +187 -0
  150. package/vendor/micromark-core-commonmark/lib/thematic-break.js +102 -0
  151. package/vendor/micromark-core-commonmark/license +22 -0
  152. package/vendor/micromark-core-commonmark/package.json +62 -0
  153. package/vendor/micromark-extension-gfm-strikethrough/index.js +3 -0
  154. package/vendor/micromark-extension-gfm-strikethrough/lib/html.js +26 -0
  155. package/vendor/micromark-extension-gfm-strikethrough/lib/syntax.js +142 -0
  156. package/vendor/micromark-extension-gfm-strikethrough/license +22 -0
  157. package/vendor/micromark-extension-gfm-strikethrough/package.json +129 -0
  158. package/vendor/micromark-extension-gfm-table/index.js +2 -0
  159. package/vendor/micromark-extension-gfm-table/lib/edit-map.js +222 -0
  160. package/vendor/micromark-extension-gfm-table/lib/html.js +135 -0
  161. package/vendor/micromark-extension-gfm-table/lib/infer.js +52 -0
  162. package/vendor/micromark-extension-gfm-table/lib/syntax.js +846 -0
  163. package/vendor/micromark-extension-gfm-table/license +22 -0
  164. package/vendor/micromark-extension-gfm-table/package.json +86 -0
  165. package/vendor/micromark-extension-gfm-task-list-item/index.js +2 -0
  166. package/vendor/micromark-extension-gfm-task-list-item/lib/html.js +29 -0
  167. package/vendor/micromark-extension-gfm-task-list-item/lib/syntax.js +158 -0
  168. package/vendor/micromark-extension-gfm-task-list-item/license +22 -0
  169. package/vendor/micromark-extension-gfm-task-list-item/package.json +131 -0
  170. package/vendor/micromark-factory-destination/index.js +206 -0
  171. package/vendor/micromark-factory-destination/license +22 -0
  172. package/vendor/micromark-factory-destination/package.json +57 -0
  173. package/vendor/micromark-factory-label/index.js +148 -0
  174. package/vendor/micromark-factory-label/license +22 -0
  175. package/vendor/micromark-factory-label/package.json +60 -0
  176. package/vendor/micromark-factory-space/index.js +116 -0
  177. package/vendor/micromark-factory-space/license +22 -0
  178. package/vendor/micromark-factory-space/package.json +46 -0
  179. package/vendor/micromark-factory-title/index.js +158 -0
  180. package/vendor/micromark-factory-title/license +22 -0
  181. package/vendor/micromark-factory-title/package.json +58 -0
  182. package/vendor/micromark-factory-whitespace/index.js +44 -0
  183. package/vendor/micromark-factory-whitespace/license +22 -0
  184. package/vendor/micromark-factory-whitespace/package.json +57 -0
  185. package/vendor/micromark-util-character/index.js +246 -0
  186. package/vendor/micromark-util-character/license +22 -0
  187. package/vendor/micromark-util-character/package.json +57 -0
  188. package/vendor/micromark-util-chunked/index.js +81 -0
  189. package/vendor/micromark-util-chunked/license +22 -0
  190. package/vendor/micromark-util-chunked/package.json +57 -0
  191. package/vendor/micromark-util-classify-character/index.js +27 -0
  192. package/vendor/micromark-util-classify-character/license +22 -0
  193. package/vendor/micromark-util-classify-character/package.json +59 -0
  194. package/vendor/micromark-util-combine-extensions/index.js +143 -0
  195. package/vendor/micromark-util-combine-extensions/license +22 -0
  196. package/vendor/micromark-util-combine-extensions/package.json +52 -0
  197. package/vendor/micromark-util-decode-numeric-character-reference/index.js +32 -0
  198. package/vendor/micromark-util-decode-numeric-character-reference/license +22 -0
  199. package/vendor/micromark-util-decode-numeric-character-reference/package.json +59 -0
  200. package/vendor/micromark-util-decode-string/index.js +45 -0
  201. package/vendor/micromark-util-decode-string/license +22 -0
  202. package/vendor/micromark-util-decode-string/package.json +63 -0
  203. package/vendor/micromark-util-edit-map/index.js +225 -0
  204. package/vendor/micromark-util-edit-map/license +22 -0
  205. package/vendor/micromark-util-edit-map/package.json +48 -0
  206. package/vendor/micromark-util-encode/index.js +33 -0
  207. package/vendor/micromark-util-encode/license +22 -0
  208. package/vendor/micromark-util-encode/package.json +47 -0
  209. package/vendor/micromark-util-html-tag-name/index.js +93 -0
  210. package/vendor/micromark-util-html-tag-name/license +22 -0
  211. package/vendor/micromark-util-html-tag-name/package.json +47 -0
  212. package/vendor/micromark-util-normalize-identifier/index.js +33 -0
  213. package/vendor/micromark-util-normalize-identifier/license +22 -0
  214. package/vendor/micromark-util-normalize-identifier/package.json +58 -0
  215. package/vendor/micromark-util-resolve-all/index.js +32 -0
  216. package/vendor/micromark-util-resolve-all/license +22 -0
  217. package/vendor/micromark-util-resolve-all/package.json +48 -0
  218. package/vendor/micromark-util-sanitize-uri/index.js +107 -0
  219. package/vendor/micromark-util-sanitize-uri/license +22 -0
  220. package/vendor/micromark-util-sanitize-uri/package.json +59 -0
  221. package/vendor/micromark-util-subtokenize/index.js +228 -0
  222. package/vendor/micromark-util-subtokenize/lib/splice-buffer.js +251 -0
  223. package/vendor/micromark-util-subtokenize/license +22 -0
  224. package/vendor/micromark-util-subtokenize/package.json +60 -0
  225. package/vendor/unist-util-is/index.js +7 -0
  226. package/vendor/unist-util-is/lib/index.js +296 -0
  227. package/vendor/unist-util-is/license +22 -0
  228. package/vendor/unist-util-is/package.json +103 -0
  229. package/vendor/unist-util-stringify-position/index.js +1 -0
  230. package/vendor/unist-util-stringify-position/lib/index.js +84 -0
  231. package/vendor/unist-util-stringify-position/license +22 -0
  232. package/vendor/unist-util-stringify-position/package.json +80 -0
  233. package/vendor/unist-util-visit/index.js +2 -0
  234. package/vendor/unist-util-visit/lib/index.js +312 -0
  235. package/vendor/unist-util-visit/license +22 -0
  236. package/vendor/unist-util-visit/package.json +108 -0
  237. package/vendor/unist-util-visit-parents/index.js +2 -0
  238. package/vendor/unist-util-visit-parents/lib/color.js +7 -0
  239. package/vendor/unist-util-visit-parents/lib/index.js +399 -0
  240. package/vendor/unist-util-visit-parents/license +22 -0
  241. package/vendor/unist-util-visit-parents/package.json +106 -0
  242. package/vendor/zwitch/index.js +118 -0
  243. package/vendor/zwitch/license +22 -0
  244. package/vendor/zwitch/package.json +72 -0
  245. package/README.md +0 -3
@@ -0,0 +1,704 @@
1
+ /**
2
+ * @import {Attention, Handle, Info, State} from 'mdast-util-to-markdown'
3
+ * @import {PhrasingParents} from '../types.js'
4
+ */
5
+
6
+ import {asciiPunctuation} from 'micromark-util-character'
7
+ import {classifyCharacter} from 'micromark-util-classify-character'
8
+ import {firstCharacter, lastCharacter} from './character.js'
9
+ import {encodeCharacterReference} from './encode-character-reference.js'
10
+ import {encodeInfo} from './encode-info.js'
11
+ import {htmlKind} from './html-kind.js'
12
+
13
+ /**
14
+ * Markers for builtin attention (emphasis, strong) to whether they are stricter:
15
+ * whether they cannot open and close inside words.
16
+ *
17
+ * Builtin runs pair following CommonMark rules for emphasis and strong:
18
+ * they are split,
19
+ * using one or two markers at a time,
20
+ * with the rule of 3.
21
+ * Other markers pair like GFM strikethrough:
22
+ * whole runs pair with a run of the same size.
23
+ *
24
+ * @type {Map<string, boolean>}
25
+ */
26
+ const builtins = new Map([
27
+ ['*', false],
28
+ ['_', true]
29
+ ])
30
+
31
+ /**
32
+ * @typedef AttentionResult
33
+ * Attention, of which the sequence is chosen later.
34
+ * @property {Array<Item>} children
35
+ * Serialized children.
36
+ * @property {Array<string>} sequences
37
+ * Sequences that can be used, in order of preference.
38
+ */
39
+
40
+ /**
41
+ * @typedef Improvement
42
+ * Improvement of attention sequences.
43
+ * @property {Map<AttentionResult, string>} chosen
44
+ * Chosen sequences for each attention.
45
+ * @property {Array<Token>} tokens
46
+ * Tokens involved in the improvement.
47
+ * @property {Mistake | undefined} mistake
48
+ * Mistake that led to this improvement, if any.
49
+ */
50
+
51
+ /**
52
+ * @typedef {AttentionResult | string} Item
53
+ * Serialized phrasing.
54
+ */
55
+
56
+ /**
57
+ * @typedef Mistake
58
+ * Sequence that does not form its attention.
59
+ * @property {Array<AttentionResult>} attention
60
+ * Attention to try other sequences for.
61
+ * @property {number} index
62
+ * Index of the token.
63
+ */
64
+
65
+ /**
66
+ * @typedef Run
67
+ * Sequences next to each other with the same marker.
68
+ * @property {boolean} close
69
+ * Whether it can close.
70
+ * @property {number} end
71
+ * Index after the last marker not used (to open).
72
+ * @property {Array<Token>} markers
73
+ * Sequence of each marker.
74
+ * @property {boolean} open
75
+ * Whether it can open.
76
+ * @property {boolean} split
77
+ * Whether it can be split (built-in attention).
78
+ * @property {number} start
79
+ * Index of the first marker not used (to close).
80
+ * @property {Array<Token>} tokens
81
+ * Sequences.
82
+ */
83
+
84
+ /**
85
+ * @typedef Token
86
+ * Rendered phrasing.
87
+ * @property {AttentionResult | undefined} attention
88
+ * Attention, if this is one of its sequences.
89
+ * @property {string} value
90
+ * Value.
91
+ */
92
+
93
+ /**
94
+ * Get candidates for a mistake:
95
+ * attention to try other sequences for,
96
+ * later first.
97
+ *
98
+ * @param {Array<Token>} tokens
99
+ * Tokens.
100
+ * @param {Array<Token>} involved
101
+ * Sequences involved in the mistake.
102
+ * @param {Map<Token, Run>} runOf
103
+ * Run of each sequence.
104
+ * @returns {Array<AttentionResult>}
105
+ * Candidates.
106
+ */
107
+ function candidates(tokens, involved, runOf) {
108
+ /** @type {Set<AttentionResult | undefined>} */
109
+ const related = new Set()
110
+
111
+ // The attention involved, and attention in runs with its sequences.
112
+ for (const token of tokens) {
113
+ const siblings = runOf.get(token)
114
+ if (
115
+ siblings &&
116
+ token.attention &&
117
+ involved.some((d) => d.attention === token.attention)
118
+ ) {
119
+ for (const sibling of siblings.tokens) {
120
+ related.add(sibling.attention)
121
+ }
122
+ }
123
+ }
124
+
125
+ /** @type {Array<AttentionResult>} */
126
+ const ordered = []
127
+
128
+ for (const token of tokens) {
129
+ if (token.attention && related.delete(token.attention)) {
130
+ ordered.push(token.attention)
131
+ }
132
+ }
133
+
134
+ // Later first: attention that opens later is inner or next.
135
+ ordered.reverse()
136
+ return ordered
137
+ }
138
+
139
+ /**
140
+ * Check whether sequences form their attention, like `micromark`.
141
+ *
142
+ * Sequences of `*` and `_` pair like emphasis and strong in CommonMark,
143
+ * others like strikethrough in GFM.
144
+ *
145
+ * @param {Array<Token>} tokens
146
+ * Tokens.
147
+ * @param {string} before
148
+ * Characters before.
149
+ * @param {string} after
150
+ * Characters after.
151
+ * @returns {Mistake | undefined}
152
+ * First mistake, if any.
153
+ */
154
+ function check(tokens, before, after) {
155
+ /** @type {Array<Run>} */
156
+ const runs = []
157
+ /** @type {Map<Token, Array<Token>>} */
158
+ const wrong = new Map()
159
+ /** @type {Map<Token, Run>} */
160
+ const runOf = new Map()
161
+ let index = 0
162
+
163
+ while (index < tokens.length) {
164
+ if (!tokens[index].attention) {
165
+ index++
166
+ continue
167
+ }
168
+
169
+ const marker = tokens[index].value.charAt(0)
170
+ const strict = builtins.get(marker)
171
+ let end = index + 1
172
+
173
+ while (
174
+ end < tokens.length &&
175
+ tokens[end].attention &&
176
+ tokens[end].value.charAt(0) === marker
177
+ ) {
178
+ end++
179
+ }
180
+
181
+ const head = index ? tokens[index - 1].value : before
182
+ const previous = classifyCharacter(head.charCodeAt(head.length - 1))
183
+ const next = classifyCharacter(
184
+ (end < tokens.length ? tokens[end].value : after).charCodeAt(0)
185
+ )
186
+ const open = !next || (next === 2 && Boolean(previous))
187
+ const close = !previous || (previous === 2 && Boolean(next))
188
+ /** @type {Run} */
189
+ const run = {
190
+ tokens: tokens.slice(index, end),
191
+ markers: [],
192
+ start: 0,
193
+ end: 0,
194
+ // Underscores are strict, they cannot open or close inside words.
195
+ open: strict ? open && (Boolean(previous) || !close) : open,
196
+ close: strict ? close && (Boolean(next) || !open) : close,
197
+ // All builtins can split runs.
198
+ split: strict !== undefined
199
+ }
200
+
201
+ for (const token of run.tokens) {
202
+ // Every sequence is wrong until it pairs with its other sequence.
203
+ wrong.set(token, [...run.tokens])
204
+ runOf.set(token, run)
205
+ let size = token.value.length
206
+ while (size--) run.markers.push(token)
207
+ }
208
+
209
+ run.end = run.markers.length
210
+ runs.push(run)
211
+ index = end
212
+ }
213
+
214
+ pair(runs, wrong)
215
+
216
+ index = -1
217
+
218
+ while (++index < tokens.length) {
219
+ const involved = wrong.get(tokens[index])
220
+ if (involved) return {attention: candidates(tokens, involved, runOf), index}
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Serialize the children of a parent that contains phrasing children.
226
+ *
227
+ * @param {PhrasingParents} parent
228
+ * Parent of phrasing nodes.
229
+ * @param {State} state
230
+ * Info passed around about the current state.
231
+ * @param {Info} info
232
+ * Info on where we are in the document we are generating.
233
+ * @returns {string}
234
+ * Serialized result.
235
+ */
236
+ export function containerPhrasing(parent, state, info) {
237
+ return serialize(phrasing(parent, state, info), info.before, info.after)
238
+ }
239
+
240
+ /**
241
+ * Encode the first or last character of tokens as a character reference,
242
+ * if it is text.
243
+ *
244
+ * @param {Array<Token>} tokens
245
+ * Tokens.
246
+ * @param {boolean} start
247
+ * Whether to encode the first or last character.
248
+ * @returns {undefined}
249
+ * Nothing.
250
+ */
251
+ function encode(tokens, start) {
252
+ const token = tokens[start ? 0 : tokens.length - 1]
253
+
254
+ if (!token || token.attention) return
255
+
256
+ const character = start
257
+ ? firstCharacter(token.value)
258
+ : lastCharacter(token.value)
259
+ const reference = encodeCharacterReference(
260
+ /** @type {number} */ (character.codePointAt(0))
261
+ )
262
+
263
+ token.value = start
264
+ ? reference + token.value.slice(character.length)
265
+ : token.value.slice(0, token.value.length - character.length) + reference
266
+ }
267
+
268
+ /**
269
+ * Try other sequences for the candidates of a mistake and use the first that
270
+ * moves the mistake further.
271
+ *
272
+ * @param {Array<Item>} items
273
+ * Items.
274
+ * @param {Map<AttentionResult, string>} chosen
275
+ * Sequences to use instead of preferred sequences.
276
+ * @param {Mistake} mistake
277
+ * Mistake.
278
+ * @param {string} before
279
+ * Characters before.
280
+ * @param {string} after
281
+ * Characters after.
282
+ * @returns {Improvement | undefined}
283
+ * Result if better.
284
+ */
285
+ function improve(items, chosen, mistake, before, after) {
286
+ for (const attention of mistake.attention) {
287
+ const current = chosen.get(attention) || attention.sequences[0]
288
+
289
+ for (const sequence of attention.sequences) {
290
+ if (sequence === current) continue
291
+ const trial = new Map(chosen)
292
+ trial.set(attention, sequence)
293
+ const tokens = render(items, trial, before, after)
294
+ const next = check(tokens, before, after)
295
+
296
+ if (!next || next.index > mistake.index) {
297
+ return {chosen: trial, mistake: next, tokens}
298
+ }
299
+ }
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Pair runs like `micromark` and mark sequences that do form their attention
305
+ * as fine.
306
+ *
307
+ * Each pair uses markers from the end of an opener and the start of a closer.
308
+ * It forms the intended attention if those markers are exactly the whole
309
+ * opening and closing sequence of one attention.
310
+ * Otherwise attention is mixed up:
311
+ * either sequences of different attention pair,
312
+ * part of a sequence is used (such as `**` of strong as `*`),
313
+ * or several sequences are used together (such as `*` and `*` as `**`).
314
+ * Then the sequences involved are recorded with each other.
315
+ *
316
+ * @param {Array<Run>} runs
317
+ * Runs.
318
+ * @param {Map<Token, Array<Token>>} wrong
319
+ * Sequences that are wrong, with the sequences involved.
320
+ * @returns {undefined}
321
+ * Nothing, `wrong` is changed.
322
+ */
323
+ function pair(runs, wrong) {
324
+ let index = 0
325
+
326
+ while (index < runs.length) {
327
+ const closer = runs[index]
328
+ const marker = closer.tokens[0].value.charAt(0)
329
+ const closerSize = closer.end - closer.start
330
+ let open = closer.close && closerSize ? index : 0
331
+
332
+ while (open--) {
333
+ const opener = runs[open]
334
+ const openerSize = opener.end - opener.start
335
+
336
+ if (
337
+ opener.tokens[0].value.charAt(0) === marker &&
338
+ opener.open &&
339
+ openerSize &&
340
+ (closer.split
341
+ ? // The rule of 3, on the sizes that are left.
342
+ !((opener.close || closer.open) && closerSize % 3) ||
343
+ (openerSize + closerSize) % 3
344
+ : // Others pair whole runs of the same size.
345
+ openerSize === opener.markers.length && openerSize === closerSize)
346
+ ) {
347
+ const size = closer.split
348
+ ? openerSize > 1 && closerSize > 1
349
+ ? 2
350
+ : 1
351
+ : closerSize
352
+ const opening = opener.markers.slice(opener.end - size, opener.end)
353
+ const closing = closer.markers.slice(closer.start, closer.start + size)
354
+ const openToken = opening[0]
355
+ const closeToken = closing[0]
356
+
357
+ if (
358
+ // Whole sequences:
359
+ // the markers of a sequence are next to each other,
360
+ // so if the first and last marker are of one sequence of that size,
361
+ // all markers are exactly that sequence.
362
+ openToken === opening[size - 1] &&
363
+ openToken.value.length === size &&
364
+ closeToken === closing[size - 1] &&
365
+ closeToken.value.length === size &&
366
+ // Of the same attention, so its opening and closing sequence.
367
+ openToken.attention === closeToken.attention
368
+ ) {
369
+ wrong.delete(openToken)
370
+ wrong.delete(closeToken)
371
+ } else {
372
+ const involved = [...new Set([...opening, ...closing])]
373
+ // Add to what is involved already: a sequence can be in several pairs.
374
+ for (const token of involved) {
375
+ const list = wrong.get(token)
376
+ if (list) list.push(...involved)
377
+ }
378
+ }
379
+
380
+ opener.end -= size
381
+ closer.start += size
382
+ break
383
+ }
384
+ }
385
+
386
+ // Stay on this run if it can close more.
387
+ if (open === -1 || closer.start === closer.end) index++
388
+ }
389
+ }
390
+
391
+ /**
392
+ * Get the sequences that can be used for attention, in order of preference.
393
+ *
394
+ * @param {string} type
395
+ * Node type.
396
+ * @param {Array<string>} markers
397
+ * Markers.
398
+ * @param {Array<number>} sizes
399
+ * Sizes.
400
+ * @returns {Array<string>}
401
+ * Sequences.
402
+ */
403
+ function attentionSequences(type, markers, sizes) {
404
+ if (markers.length === 0) {
405
+ throw new Error(
406
+ 'Cannot serialize `' +
407
+ type +
408
+ '` as attention without markers, expected one or more markers'
409
+ )
410
+ }
411
+
412
+ if (sizes.length === 0) {
413
+ throw new Error(
414
+ 'Cannot serialize `' +
415
+ type +
416
+ '` as attention without sizes, expected one or more sizes'
417
+ )
418
+ }
419
+
420
+ for (const size of sizes) {
421
+ if (!Number.isSafeInteger(size) || size < 1) {
422
+ throw new Error(
423
+ 'Cannot serialize `' +
424
+ type +
425
+ '` as attention with `' +
426
+ size +
427
+ '` as size, expected positive integer'
428
+ )
429
+ }
430
+ }
431
+
432
+ /** @type {Array<string>} */
433
+ const sequences = []
434
+
435
+ for (const marker of markers) {
436
+ if (marker.length !== 1) {
437
+ throw new Error(
438
+ 'Cannot serialize `' +
439
+ type +
440
+ '` as attention with `' +
441
+ marker +
442
+ '` as marker, expected a single ascii character'
443
+ )
444
+ }
445
+
446
+ if (!asciiPunctuation(marker.charCodeAt(0))) {
447
+ throw new Error(
448
+ 'Cannot serialize `' +
449
+ type +
450
+ '` as attention with `' +
451
+ marker +
452
+ '` as marker, expected ascii punctuation'
453
+ )
454
+ }
455
+
456
+ for (const size of sizes) {
457
+ sequences.push(marker.repeat(size))
458
+ }
459
+ }
460
+
461
+ return sequences
462
+ }
463
+
464
+ /**
465
+ * Serialize the children of a parent that contains phrasing children,
466
+ * keeping attention separate,
467
+ * so that its markers can be chosen later.
468
+ *
469
+ * @param {PhrasingParents} parent
470
+ * Parent of phrasing nodes.
471
+ * @param {State} state
472
+ * Info passed around about the current state.
473
+ * @param {Info} info
474
+ * Info on where we are in the document we are generating.
475
+ * @returns {Array<Item>}
476
+ * Items.
477
+ */
478
+ function phrasing(parent, state, info) {
479
+ const indexStack = state.indexStack
480
+ const children = parent.children || []
481
+ /** @type {Array<Item>} */
482
+ const results = []
483
+ let index = -1
484
+ let before = info.before
485
+
486
+ indexStack.push(-1)
487
+ let tracker = state.createTracker(info)
488
+
489
+ while (++index < children.length) {
490
+ const child = children[index]
491
+ /** @type {string} */
492
+ let after
493
+
494
+ indexStack[indexStack.length - 1] = index
495
+
496
+ if (index + 1 < children.length) {
497
+ /** @type {Handle} */
498
+ // @ts-expect-error: hush, it’s actually a `zwitch`.
499
+ let handle = state.handle.handlers[children[index + 1].type]
500
+ // @ts-expect-error: hush, it’s actually a `zwitch`.
501
+ if (handle && handle.peek) handle = handle.peek
502
+ after = handle
503
+ ? firstCharacter(
504
+ handle(children[index + 1], parent, state, {
505
+ before: '',
506
+ after: '',
507
+ ...tracker.current()
508
+ })
509
+ )
510
+ : ''
511
+ } else {
512
+ after = info.after
513
+ }
514
+
515
+ // In some cases, html (text) can be found in phrasing right after an eol.
516
+ // When we’d serialize that, it could be seen as html (flow): all its kinds
517
+ // except 7 can interrupt a paragraph.
518
+ // As we can’t escape or so to prevent it from happening,
519
+ // we take a somewhat reasonable approach:
520
+ // replace that eol with a space.
521
+ // See: <https://github.com/syntax-tree/mdast-util-to-markdown/issues/15>
522
+ const previous = results[results.length - 1]
523
+
524
+ if (
525
+ typeof previous === 'string' &&
526
+ (before === '\r' || before === '\n') &&
527
+ child.type === 'html' &&
528
+ htmlKind(child.value) !== 7
529
+ ) {
530
+ results[results.length - 1] = previous.replace(/(\r?\n|\r)$/, ' ')
531
+ before = ' '
532
+
533
+ // To do: does this work to reset tracker?
534
+ tracker = state.createTracker(info)
535
+ tracker.move(serialize(results, info.before, info.after))
536
+ }
537
+
538
+ /** @type {(Handle & {attention?: Attention | undefined}) | undefined} */
539
+ // @ts-expect-error: hush, it’s actually a `zwitch`.
540
+ const handle = state.handle.handlers[child.type]
541
+
542
+ if (handle && handle.attention) {
543
+ const {construct, markers, sizes} = handle.attention(child, state)
544
+ const sequences = attentionSequences(child.type, markers, sizes)
545
+ const sequence = sequences[0]
546
+ const exit = state.enter(construct)
547
+ tracker.move(sequence)
548
+ const inside = phrasing(/** @type {PhrasingParents} */ (child), state, {
549
+ ...tracker.current(),
550
+ before: sequence,
551
+ after: sequence
552
+ })
553
+ tracker.move(serialize(inside, sequence, sequence))
554
+ tracker.move(sequence)
555
+ exit()
556
+ results.push({children: inside, sequences})
557
+ before = sequence.charAt(sequence.length - 1)
558
+ } else {
559
+ const value = state.handle(child, parent, state, {
560
+ ...tracker.current(),
561
+ after,
562
+ before
563
+ })
564
+
565
+ if (!value) continue
566
+ tracker.move(value)
567
+ results.push(value)
568
+ before = lastCharacter(value)
569
+ }
570
+ }
571
+
572
+ indexStack.pop()
573
+
574
+ return results
575
+ }
576
+
577
+ /**
578
+ * Render items with sequences;
579
+ * encoding characters around attention where needed.
580
+ *
581
+ * @param {Array<Item>} items
582
+ * Serialized phrasing.
583
+ * @param {Map<AttentionResult, string>} chosen
584
+ * Sequences to use instead of preferred sequences.
585
+ * @param {string} before
586
+ * Characters before.
587
+ * @param {string} after
588
+ * Characters after.
589
+ * @returns {Array<Token>}
590
+ * Tokens.
591
+ */
592
+ function render(items, chosen, before, after) {
593
+ /** @type {Array<Token>} */
594
+ const tokens = []
595
+ /** @type {string | undefined} */
596
+ let encodeAfter
597
+ let previous = lastCharacter(before)
598
+ let index = -1
599
+
600
+ while (++index < items.length) {
601
+ const item = items[index]
602
+
603
+ if (typeof item === 'string') {
604
+ /** @type {Token} */
605
+ const token = {value: item, attention: undefined}
606
+
607
+ // If attention before had to encode the character after it, encode it.
608
+ if (encodeAfter && encodeAfter === firstCharacter(item)) {
609
+ encode([token], true)
610
+ }
611
+
612
+ encodeAfter = undefined
613
+ tokens.push(token)
614
+ if (token.value) previous = lastCharacter(token.value)
615
+ continue
616
+ }
617
+
618
+ const sequence = chosen.get(item) || item.sequences[0]
619
+ const marker = sequence.charAt(0)
620
+ const next = items[index + 1]
621
+ const outsideBefore = previous
622
+ const outsideAfter = firstCharacter(
623
+ next === undefined
624
+ ? after
625
+ : typeof next === 'string'
626
+ ? next
627
+ : chosen.get(next) || next.sequences[0]
628
+ )
629
+ const inside = render(item.children, chosen, sequence, sequence)
630
+ const head = inside.length > 0 ? inside[0].value : ''
631
+ const open = encodeInfo(
632
+ outsideBefore.charCodeAt(outsideBefore.length - 1),
633
+ head.charCodeAt(0),
634
+ marker
635
+ )
636
+
637
+ if (open.inside) encode(inside, true)
638
+
639
+ const tail =
640
+ inside.length > 0 ? lastCharacter(inside[inside.length - 1].value) : ''
641
+ const close = encodeInfo(
642
+ outsideAfter.charCodeAt(0),
643
+ tail.charCodeAt(tail.length - 1),
644
+ marker
645
+ )
646
+
647
+ if (close.inside) encode(inside, false)
648
+
649
+ if (open.outside && outsideBefore !== '\n' && outsideBefore !== '\r') {
650
+ encode(tokens, false)
651
+ }
652
+
653
+ if (close.outside) encodeAfter = outsideAfter
654
+
655
+ tokens.push({value: sequence, attention: item}, ...inside, {
656
+ value: sequence,
657
+ attention: item
658
+ })
659
+ previous = sequence.charAt(sequence.length - 1)
660
+ }
661
+
662
+ return tokens
663
+ }
664
+
665
+ /**
666
+ * Serialize phrasing with attention.
667
+ *
668
+ * Whether attention forms depends on everything around it.
669
+ * This checks that it does and tries other sequences if not.
670
+ *
671
+ * @param {Array<Item>} items
672
+ * Phrasing items.
673
+ * @param {string} before
674
+ * Characters before.
675
+ * @param {string} after
676
+ * Characters after.
677
+ * @returns {string}
678
+ * Serialized markdown.
679
+ */
680
+ function serialize(items, before, after) {
681
+ /** @type {Map<AttentionResult, string>} */
682
+ let chosen = new Map()
683
+ const initial = render(items, chosen, before, after)
684
+ let tokens = initial
685
+ let mistake = check(tokens, before, after)
686
+
687
+ while (mistake) {
688
+ const next = improve(items, chosen, mistake, before, after)
689
+
690
+ if (!next) {
691
+ tokens = initial
692
+ break
693
+ }
694
+
695
+ chosen = next.chosen
696
+ tokens = next.tokens
697
+ mistake = next.mistake
698
+ }
699
+
700
+ // Join the tokens.
701
+ let result = ''
702
+ for (const token of tokens) result += token.value
703
+ return result
704
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Encode a code point as a character reference.
3
+ *
4
+ * @param {number} code
5
+ * Code point to encode.
6
+ * @returns {string}
7
+ * Encoded character reference.
8
+ */
9
+ export function encodeCharacterReference(code) {
10
+ return '&#x' + code.toString(16).toUpperCase() + ';'
11
+ }