@trebco/treb 23.6.2 → 25.0.0-rc1

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 (217) hide show
  1. package/.eslintignore +8 -0
  2. package/.eslintrc.js +164 -0
  3. package/README-shadow-DOM.md +88 -0
  4. package/README.md +37 -130
  5. package/api-config.json +29 -0
  6. package/api-generator/api-generator-types.ts +82 -0
  7. package/api-generator/api-generator.ts +1172 -0
  8. package/api-generator/package.json +3 -0
  9. package/build/treb-spreadsheet.mjs +14 -0
  10. package/{treb.d.ts → build/treb.d.ts} +293 -299
  11. package/esbuild-custom-element.mjs +336 -0
  12. package/esbuild.js +305 -0
  13. package/package.json +43 -14
  14. package/treb-base-types/package.json +5 -0
  15. package/treb-base-types/src/api_types.ts +36 -0
  16. package/treb-base-types/src/area.ts +583 -0
  17. package/treb-base-types/src/basic_types.ts +45 -0
  18. package/treb-base-types/src/cell.ts +612 -0
  19. package/treb-base-types/src/cells.ts +1066 -0
  20. package/treb-base-types/src/color.ts +124 -0
  21. package/treb-base-types/src/import.ts +71 -0
  22. package/treb-base-types/src/index-standalone.ts +29 -0
  23. package/treb-base-types/src/index.ts +42 -0
  24. package/treb-base-types/src/layout.ts +47 -0
  25. package/treb-base-types/src/localization.ts +187 -0
  26. package/treb-base-types/src/rectangle.ts +145 -0
  27. package/treb-base-types/src/render_text.ts +72 -0
  28. package/treb-base-types/src/style.ts +545 -0
  29. package/treb-base-types/src/table.ts +109 -0
  30. package/treb-base-types/src/text_part.ts +54 -0
  31. package/treb-base-types/src/theme.ts +608 -0
  32. package/treb-base-types/src/union.ts +152 -0
  33. package/treb-base-types/src/value-type.ts +164 -0
  34. package/treb-base-types/style/resizable.css +59 -0
  35. package/treb-calculator/modern.tsconfig.json +11 -0
  36. package/treb-calculator/package.json +5 -0
  37. package/treb-calculator/src/calculator.ts +2546 -0
  38. package/treb-calculator/src/complex-math.ts +558 -0
  39. package/treb-calculator/src/dag/array-vertex.ts +198 -0
  40. package/treb-calculator/src/dag/graph.ts +951 -0
  41. package/treb-calculator/src/dag/leaf_vertex.ts +118 -0
  42. package/treb-calculator/src/dag/spreadsheet_vertex.ts +327 -0
  43. package/treb-calculator/src/dag/spreadsheet_vertex_base.ts +44 -0
  44. package/treb-calculator/src/dag/vertex.ts +352 -0
  45. package/treb-calculator/src/descriptors.ts +162 -0
  46. package/treb-calculator/src/expression-calculator.ts +1069 -0
  47. package/treb-calculator/src/function-error.ts +103 -0
  48. package/treb-calculator/src/function-library.ts +103 -0
  49. package/treb-calculator/src/functions/base-functions.ts +1214 -0
  50. package/treb-calculator/src/functions/checkbox.ts +164 -0
  51. package/treb-calculator/src/functions/complex-functions.ts +253 -0
  52. package/treb-calculator/src/functions/finance-functions.ts +399 -0
  53. package/treb-calculator/src/functions/information-functions.ts +102 -0
  54. package/treb-calculator/src/functions/matrix-functions.ts +182 -0
  55. package/treb-calculator/src/functions/sparkline.ts +335 -0
  56. package/treb-calculator/src/functions/statistics-functions.ts +350 -0
  57. package/treb-calculator/src/functions/text-functions.ts +298 -0
  58. package/treb-calculator/src/index.ts +27 -0
  59. package/treb-calculator/src/notifier-types.ts +59 -0
  60. package/treb-calculator/src/primitives.ts +428 -0
  61. package/treb-calculator/src/utilities.ts +305 -0
  62. package/treb-charts/package.json +5 -0
  63. package/treb-charts/src/chart-functions.ts +156 -0
  64. package/treb-charts/src/chart-types.ts +230 -0
  65. package/treb-charts/src/chart.ts +1288 -0
  66. package/treb-charts/src/index.ts +24 -0
  67. package/treb-charts/src/main.ts +37 -0
  68. package/treb-charts/src/rectangle.ts +52 -0
  69. package/treb-charts/src/renderer.ts +1841 -0
  70. package/treb-charts/src/util.ts +122 -0
  71. package/treb-charts/style/charts.scss +221 -0
  72. package/treb-charts/style/old-charts.scss +250 -0
  73. package/treb-embed/markup/layout.html +137 -0
  74. package/treb-embed/markup/toolbar.html +175 -0
  75. package/treb-embed/modern.tsconfig.json +25 -0
  76. package/treb-embed/src/custom-element/content-types.d.ts +18 -0
  77. package/treb-embed/src/custom-element/global.d.ts +11 -0
  78. package/treb-embed/src/custom-element/spreadsheet-constructor.ts +1227 -0
  79. package/treb-embed/src/custom-element/treb-global.ts +44 -0
  80. package/treb-embed/src/custom-element/treb-spreadsheet-element.ts +52 -0
  81. package/treb-embed/src/embedded-spreadsheet.ts +5362 -0
  82. package/treb-embed/src/index.ts +16 -0
  83. package/treb-embed/src/language-model.ts +41 -0
  84. package/treb-embed/src/options.ts +320 -0
  85. package/treb-embed/src/progress-dialog.ts +228 -0
  86. package/treb-embed/src/selection-state.ts +16 -0
  87. package/treb-embed/src/spinner.ts +42 -0
  88. package/treb-embed/src/toolbar-message.ts +96 -0
  89. package/treb-embed/src/types.ts +167 -0
  90. package/treb-embed/style/autocomplete.scss +103 -0
  91. package/treb-embed/style/dark-theme.scss +114 -0
  92. package/treb-embed/style/defaults.scss +36 -0
  93. package/treb-embed/style/dialog.scss +181 -0
  94. package/treb-embed/style/dropdown-select.scss +101 -0
  95. package/treb-embed/style/formula-bar.scss +193 -0
  96. package/treb-embed/style/grid.scss +374 -0
  97. package/treb-embed/style/layout.scss +424 -0
  98. package/treb-embed/style/mouse-mask.scss +67 -0
  99. package/treb-embed/style/note.scss +92 -0
  100. package/treb-embed/style/overlay-editor.scss +102 -0
  101. package/treb-embed/style/spinner.scss +92 -0
  102. package/treb-embed/style/tab-bar.scss +228 -0
  103. package/treb-embed/style/table.scss +80 -0
  104. package/treb-embed/style/theme-defaults.scss +444 -0
  105. package/treb-embed/style/toolbar.scss +416 -0
  106. package/treb-embed/style/tooltip.scss +68 -0
  107. package/treb-embed/style/treb-icons.scss +130 -0
  108. package/treb-embed/style/treb-spreadsheet-element.scss +20 -0
  109. package/treb-embed/style/z-index.scss +43 -0
  110. package/treb-export/docs/charts.md +68 -0
  111. package/treb-export/modern.tsconfig.json +19 -0
  112. package/treb-export/package.json +4 -0
  113. package/treb-export/src/address-type.ts +77 -0
  114. package/treb-export/src/base-template.ts +22 -0
  115. package/treb-export/src/column-width.ts +85 -0
  116. package/treb-export/src/drawing2/chart-template-components2.ts +389 -0
  117. package/treb-export/src/drawing2/chart2.ts +282 -0
  118. package/treb-export/src/drawing2/column-chart-template2.ts +521 -0
  119. package/treb-export/src/drawing2/donut-chart-template2.ts +296 -0
  120. package/treb-export/src/drawing2/drawing2.ts +355 -0
  121. package/treb-export/src/drawing2/embedded-image.ts +71 -0
  122. package/treb-export/src/drawing2/scatter-chart-template2.ts +555 -0
  123. package/treb-export/src/export-worker/export-worker.ts +99 -0
  124. package/treb-export/src/export-worker/index-modern.ts +22 -0
  125. package/treb-export/src/export2.ts +2204 -0
  126. package/treb-export/src/import2.ts +882 -0
  127. package/treb-export/src/relationship.ts +36 -0
  128. package/treb-export/src/shared-strings2.ts +128 -0
  129. package/treb-export/src/template-2.ts +22 -0
  130. package/treb-export/src/unescape_xml.ts +47 -0
  131. package/treb-export/src/workbook-sheet2.ts +182 -0
  132. package/treb-export/src/workbook-style2.ts +1285 -0
  133. package/treb-export/src/workbook-theme2.ts +88 -0
  134. package/treb-export/src/workbook2.ts +491 -0
  135. package/treb-export/src/xml-utils.ts +201 -0
  136. package/treb-export/template/base/[Content_Types].xml +2 -0
  137. package/treb-export/template/base/_rels/.rels +2 -0
  138. package/treb-export/template/base/docProps/app.xml +2 -0
  139. package/treb-export/template/base/docProps/core.xml +12 -0
  140. package/treb-export/template/base/xl/_rels/workbook.xml.rels +2 -0
  141. package/treb-export/template/base/xl/sharedStrings.xml +2 -0
  142. package/treb-export/template/base/xl/styles.xml +2 -0
  143. package/treb-export/template/base/xl/theme/theme1.xml +2 -0
  144. package/treb-export/template/base/xl/workbook.xml +2 -0
  145. package/treb-export/template/base/xl/worksheets/sheet1.xml +2 -0
  146. package/treb-export/template/base.xlsx +0 -0
  147. package/treb-format/package.json +8 -0
  148. package/treb-format/src/format.test.ts +213 -0
  149. package/treb-format/src/format.ts +942 -0
  150. package/treb-format/src/format_cache.ts +199 -0
  151. package/treb-format/src/format_parser.ts +723 -0
  152. package/treb-format/src/index.ts +25 -0
  153. package/treb-format/src/number_format_section.ts +100 -0
  154. package/treb-format/src/value_parser.ts +337 -0
  155. package/treb-grid/package.json +5 -0
  156. package/treb-grid/src/editors/autocomplete.ts +394 -0
  157. package/treb-grid/src/editors/autocomplete_matcher.ts +260 -0
  158. package/treb-grid/src/editors/formula_bar.ts +473 -0
  159. package/treb-grid/src/editors/formula_editor_base.ts +910 -0
  160. package/treb-grid/src/editors/overlay_editor.ts +511 -0
  161. package/treb-grid/src/index.ts +37 -0
  162. package/treb-grid/src/layout/base_layout.ts +2618 -0
  163. package/treb-grid/src/layout/grid_layout.ts +299 -0
  164. package/treb-grid/src/layout/rectangle_cache.ts +86 -0
  165. package/treb-grid/src/render/selection-renderer.ts +414 -0
  166. package/treb-grid/src/render/svg_header_overlay.ts +93 -0
  167. package/treb-grid/src/render/svg_selection_block.ts +187 -0
  168. package/treb-grid/src/render/tile_renderer.ts +2122 -0
  169. package/treb-grid/src/types/annotation.ts +216 -0
  170. package/treb-grid/src/types/border_constants.ts +34 -0
  171. package/treb-grid/src/types/clipboard_data.ts +31 -0
  172. package/treb-grid/src/types/data_model.ts +334 -0
  173. package/treb-grid/src/types/drag_mask.ts +81 -0
  174. package/treb-grid/src/types/grid.ts +7743 -0
  175. package/treb-grid/src/types/grid_base.ts +3644 -0
  176. package/treb-grid/src/types/grid_command.ts +470 -0
  177. package/treb-grid/src/types/grid_events.ts +124 -0
  178. package/treb-grid/src/types/grid_options.ts +97 -0
  179. package/treb-grid/src/types/grid_selection.ts +60 -0
  180. package/treb-grid/src/types/named_range.ts +369 -0
  181. package/treb-grid/src/types/scale-control.ts +202 -0
  182. package/treb-grid/src/types/serialize_options.ts +72 -0
  183. package/treb-grid/src/types/set_range_options.ts +52 -0
  184. package/treb-grid/src/types/sheet.ts +3099 -0
  185. package/treb-grid/src/types/sheet_types.ts +95 -0
  186. package/treb-grid/src/types/tab_bar.ts +464 -0
  187. package/treb-grid/src/types/tile.ts +59 -0
  188. package/treb-grid/src/types/update_flags.ts +75 -0
  189. package/treb-grid/src/util/dom_utilities.ts +44 -0
  190. package/treb-grid/src/util/fontmetrics2.ts +179 -0
  191. package/treb-grid/src/util/ua.ts +104 -0
  192. package/treb-logo.svg +18 -0
  193. package/treb-parser/package.json +5 -0
  194. package/treb-parser/src/csv-parser.ts +122 -0
  195. package/treb-parser/src/index.ts +25 -0
  196. package/treb-parser/src/md-parser.ts +526 -0
  197. package/treb-parser/src/parser-types.ts +397 -0
  198. package/treb-parser/src/parser.test.ts +298 -0
  199. package/treb-parser/src/parser.ts +2673 -0
  200. package/treb-utils/package.json +5 -0
  201. package/treb-utils/src/dispatch.ts +57 -0
  202. package/treb-utils/src/event_source.ts +147 -0
  203. package/treb-utils/src/ievent_source.ts +33 -0
  204. package/treb-utils/src/index.ts +31 -0
  205. package/treb-utils/src/measurement.ts +174 -0
  206. package/treb-utils/src/resizable.ts +160 -0
  207. package/treb-utils/src/scale.ts +137 -0
  208. package/treb-utils/src/serialize_html.ts +124 -0
  209. package/treb-utils/src/template.ts +70 -0
  210. package/treb-utils/src/validate_uri.ts +61 -0
  211. package/tsconfig.json +10 -0
  212. package/tsproject.json +30 -0
  213. package/util/license-plugin-esbuild.js +86 -0
  214. package/util/list-css-vars.sh +46 -0
  215. package/README-esm.md +0 -37
  216. package/treb-bundle.css +0 -2
  217. package/treb-bundle.mjs +0 -15
@@ -0,0 +1,526 @@
1
+ /*
2
+ * This file is part of TREB.
3
+ *
4
+ * TREB is free software: you can redistribute it and/or modify it under the
5
+ * terms of the GNU General Public License as published by the Free Software
6
+ * Foundation, either version 3 of the License, or (at your option) any
7
+ * later version.
8
+ *
9
+ * TREB is distributed in the hope that it will be useful, but WITHOUT ANY
10
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
+ * details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License along
15
+ * with TREB. If not, see <https://www.gnu.org/licenses/>.
16
+ *
17
+ * Copyright 2022-2023 trebco, llc.
18
+ * info@treb.app
19
+ *
20
+ */
21
+
22
+ // support for entities removed, as it adds a lot of bloat. we
23
+ // could easily support numbers (+hex), but html entities require
24
+ // a table. see
25
+ //
26
+ // https://html.spec.whatwg.org/entities.json
27
+ //
28
+ // I don't think we need this, since we're not html -- you can just
29
+ // enter utf8 characters. we might think about emoji entities, though,
30
+ // along the lines of
31
+ //
32
+ // https://github.com/markdown-it/markdown-it-emoji
33
+ //
34
+
35
+ // import * as he from 'he';
36
+
37
+ export interface StringFormat {
38
+ strong?: boolean;
39
+ emphasis?: boolean;
40
+
41
+ strike?: boolean; // TODO
42
+ pre?: boolean; // TODO
43
+ }
44
+
45
+ interface NewlineToken extends StringFormat {
46
+ type: 'newline';
47
+ text: string;
48
+ }
49
+
50
+ interface WhitespaceToken extends StringFormat {
51
+ type: 'whitespace';
52
+ text: string;
53
+ }
54
+
55
+ interface TextToken extends StringFormat {
56
+ type: 'text';
57
+ text: string;
58
+ }
59
+
60
+ interface DelimeterToken extends StringFormat {
61
+ type: 'delimeter';
62
+ text: string;
63
+ left_flanking?: boolean;
64
+ right_flanking?: boolean;
65
+ char: string;
66
+ length: number;
67
+ }
68
+
69
+ type Token = NewlineToken | WhitespaceToken | TextToken | DelimeterToken;
70
+
71
+ /**
72
+ * this external type only has text information
73
+ */
74
+ export interface FormattedString extends StringFormat {
75
+ text: string;
76
+ }
77
+
78
+ /**
79
+ * utility for formatting markdown strings. we split text into tokens
80
+ * by format. implemented as a factory/singleton, stateless.
81
+ *
82
+ * note: in case it's not clear, where I reference MD rules, I mean
83
+ * CommonMark. we may add some GFM as well (strike?).
84
+ *
85
+ * UPDATE: moving into the parser lib, since it's a parser. even though
86
+ * it's totally independent. (has no deps, though, nice).
87
+ */
88
+ export class MDParser {
89
+
90
+ private static _instance: MDParser = new MDParser();
91
+
92
+ protected constructor() {
93
+ // ...
94
+ }
95
+
96
+ public static get instance(): MDParser {
97
+ return this._instance;
98
+ }
99
+
100
+ /**
101
+ * given some formatted text (output of the `Parse` method), return HTML.
102
+ * FIXME: is this used outside of testing? seems like we're wasting bytes.
103
+ *
104
+ * also the way this works adds extra tags if you have nested styles. not
105
+ * an issue if it's just for testing though.
106
+ */
107
+ public HTML(formatted: FormattedString[][]): string {
108
+
109
+ const lines: string[] = [];
110
+
111
+ for (const line of formatted) {
112
+ const text: string[] = [];
113
+
114
+ for (const element of line) {
115
+ if (element.pre) { text.push('<pre>'); }
116
+ if (element.emphasis) { text.push('<em>'); }
117
+ if (element.strong) { text.push('<strong>'); }
118
+ if (element.strike) { text.push('<strike>'); }
119
+
120
+ text.push(element.text);
121
+
122
+ if (element.strike) { text.push('</strike>'); }
123
+ if (element.strong) { text.push('</strong>'); }
124
+ if (element.emphasis) { text.push('</em>'); }
125
+ if (element.pre) { text.push('</pre>'); }
126
+ }
127
+
128
+ lines.push(text.join(''));
129
+ }
130
+
131
+ return lines.join('<br/>\n');
132
+
133
+ }
134
+
135
+ /**
136
+ * this is a replacement for the Parse() method, if you don't actually
137
+ * want to parse markdown. the aim is to have a unified result format,
138
+ * even if we're not handling md.
139
+ */
140
+ public Dummy(text = ''): FormattedString[][] {
141
+ return text.split(/\n/).map(text => [{ text }]);
142
+ }
143
+
144
+ /**
145
+ * given some input text, creates a set of text tokens with
146
+ * emphasis/strong emphasis applied. splits into lines (the
147
+ * outer array). whitespace (other than newlines) is preserved.
148
+ */
149
+ public Parse(text = ''): FormattedString[][] {
150
+
151
+ // first pass: tokenize
152
+
153
+ const tokens = this.Tokenize(text);
154
+
155
+ // for the most part, MD emphapsis/strong can be parsed as if it were
156
+ // using open/close tags. that's not strictly the case, however, and
157
+ // there is at least one situation that has some required ambiguity.
158
+
159
+ // MD does specify "left-flanking" and "right-flanking" delimiter runs,
160
+ // which can open or close formatting, respectively (and a delimeter run
161
+ // may be both left- and right-flanking).
162
+
163
+ // second pass: assign those flanks on delimeters. from CM spec:
164
+
165
+ /*
166
+
167
+ A left-flanking delimiter run is a delimiter run that is (1) not followed by
168
+ Unicode whitespace, and either (2a) not followed by a punctuation character,
169
+ or (2b) followed by a punctuation character and preceded by Unicode whitespace
170
+ or a punctuation character. For purposes of this definition, the beginning and
171
+ the end of the line count as Unicode whitespace.
172
+
173
+ A right-flanking delimiter run is a delimiter run that is (1) not preceded by
174
+ Unicode whitespace, and either (2a) not preceded by a punctuation character,
175
+ or (2b) preceded by a punctuation character and followed by Unicode whitespace
176
+ or a punctuation character. For purposes of this definition, the beginning and
177
+ the end of the line count as Unicode whitespace.
178
+
179
+ */
180
+
181
+ // FIXME: could this not be consolidated with "apply formatting", below? or
182
+ // is the concern that if we do that, we might calculate more than once for
183
+ // any given token? it might still be more efficient...
184
+
185
+ for (let i = 0; i < tokens.length; i++) {
186
+ const token = tokens[i];
187
+ if (token.type === 'delimeter') {
188
+
189
+ const preceding = tokens[i-1];
190
+ const following = tokens[i+1];
191
+
192
+ const preceded_by_whitespace = !preceding || preceding.type === 'whitespace' || preceding.type === 'newline';
193
+ const preceded_by_punctuation = preceding && preceding.type === 'text' && /[^\w\d]$/.test(preceding.text);
194
+
195
+ const followed_by_whitespace = !following || following.type === 'whitespace' || following.type === 'newline';
196
+ const followed_by_punctuation = following && following.type === 'text' && /^[^\w\d]/.test(following.text);
197
+
198
+ token.left_flanking = ((!followed_by_whitespace) && ((!followed_by_punctuation) || preceded_by_whitespace));
199
+ token.right_flanking = ((!preceded_by_whitespace) && ((!preceded_by_punctuation) || followed_by_whitespace));
200
+
201
+ }
202
+ }
203
+
204
+ // next pass does left/right token matching and applies formatting
205
+
206
+ this.ApplyFormatting(tokens);
207
+
208
+ // last pass consolidates text with like formats, scrubs used tokens
209
+ // (actually changes _unused_ tokens -> text), and splits into lines.
210
+
211
+ /*
212
+ const formatted: FormattedString[][] = this.Consolidate(tokens);
213
+
214
+ for (const line of formatted) {
215
+ for (const token of line) {
216
+ token.text = he.decode(token.text);
217
+ }
218
+ }
219
+
220
+ return formatted ; // this.Consolidate(tokens) as FormattedString[][];
221
+ */
222
+
223
+ return this.Consolidate(tokens) as FormattedString[][];
224
+
225
+ }
226
+
227
+ /** is this worth a function call? will it get inlined? */
228
+ protected IsWhitespace(char: string): boolean {
229
+ return char === ' ' || char === '\t';
230
+ }
231
+
232
+ /** is this worth a function call? will it get inlined? */
233
+ protected IsNewline(char: string): boolean {
234
+ return char === '\r' || char === '\n';
235
+ }
236
+
237
+ /** is this worth a function call? will it get inlined? */
238
+ protected IsDelimeter(char: string): boolean {
239
+ return char === '*' || char === '_' || char === '~';
240
+ }
241
+
242
+ /**
243
+ * consolidate text with common formatting. splits into lines (newlines are not rendered).
244
+ */
245
+ protected Consolidate(tokens: Token[]): TextToken[][] {
246
+ const result: TextToken[][] = [];
247
+ const format: StringFormat = {};
248
+
249
+ let line: TextToken[] = [];
250
+ let current_token: TextToken = {type: 'text', text: ''};
251
+ for (const token of tokens) {
252
+ if (token.type === 'newline') {
253
+ if (current_token.text.length) {
254
+ line.push(current_token);
255
+ }
256
+ current_token = {...format, text: '', type: 'text'};
257
+ result.push(line);
258
+ line = [];
259
+ }
260
+ else {
261
+
262
+ // yuck
263
+
264
+ // can we have a method? or maybe this should be a bitmask,
265
+ // so we can use === and only have to worry about 0
266
+
267
+ if ((!!format.strong !== !!token.strong) || (!!format.emphasis !== !!token.emphasis) || (!!format.strike !== !!token.strike)) {
268
+ format.strong = !!token.strong;
269
+ format.emphasis = !!token.emphasis;
270
+ format.strike = !!token.strike;
271
+ if (current_token.text.length) {
272
+ line.push(current_token);
273
+ }
274
+ current_token = {...format, text: '', type: 'text'};
275
+ }
276
+ switch (token.type) {
277
+ case 'text':
278
+ case 'whitespace':
279
+ current_token.text += token.text;
280
+ break;
281
+
282
+ case 'delimeter':
283
+ for (let i = 0; i < token.length; i++) { current_token.text += token.char; }
284
+ break;
285
+
286
+ }
287
+ }
288
+ }
289
+
290
+ if (current_token.text.length) {
291
+ line.push(current_token);
292
+ }
293
+
294
+ if (line.length) {
295
+ result.push(line);
296
+ }
297
+
298
+ return result;
299
+ }
300
+
301
+ /**
302
+ *
303
+ */
304
+ protected ApplyFormatting(tokens: Token[], open?: DelimeterToken): {index: number, token?: DelimeterToken} {
305
+
306
+ // if we're called with no opening token, that's the start
307
+ // of the text block and formatting is clear (no emphasis).
308
+
309
+ // console.info("AF", "open", open);
310
+
311
+ let index = 0;
312
+ const length = tokens.length;
313
+
314
+ for (index = 0; index < length; index++) {
315
+ const token = tokens[index];
316
+
317
+ if (token.type === 'delimeter') {
318
+
319
+ // check if this token can close (all or in part) our opening tag.
320
+ // if so, return closing token and index. note that we are checking
321
+ // length > 0 here; that is because operations may reduce the
322
+ // "available length" when processing.
323
+
324
+ if (open && token.right_flanking && open.char === token.char && token.length > 0) {
325
+ // console.info(" ", "close", token);
326
+ return {index, token};
327
+ }
328
+
329
+ // if not, see if we can start a new block
330
+
331
+ if (token.left_flanking) {
332
+ const result = this.ApplyFormatting(tokens.slice(index + 1), token);
333
+ if (result.token) {
334
+
335
+ // what format do we apply? it depends on the MIN of open, close,
336
+ // because it may be a partial close or it may have extra characters.
337
+
338
+ const format = Math.min(result.token.length, token.length);
339
+
340
+ // what format to we apply to the contained block? depends on the
341
+ // CLOSING delimeter, which may be < the opening delimeter.
342
+
343
+ const strike = token.char === '~';
344
+
345
+ const emphasis = !strike && !!(format % 2);
346
+ const strong = !strike && (format >= 2);
347
+
348
+ /*
349
+ const formats: string[] = [];
350
+ if (emphasis) formats.push('emphasis');
351
+ if (strong) formats.push('strong');
352
+ console.info('applying', formats, 'to tokens from', index + 1, 'to', index + result.index, `(len ${length})`);
353
+ */
354
+
355
+ // apply this format to all the handled tokens (inclusive)
356
+
357
+ for (let i = index + 1; i <= index + result.index; i++) {
358
+ tokens[i].strong = (!!tokens[i].strong) || strong;
359
+ tokens[i].emphasis = (!!tokens[i].emphasis) || emphasis;
360
+ tokens[i].strike = (!!tokens[i].strike) || strike;
361
+ }
362
+
363
+ // now we have to handle two separate cases.
364
+
365
+ // one, the closing delimeter is shorter than the opening delimeter.
366
+ // this happens if you have composite formatting (generally three, but
367
+ // could be more) and only partially close, like
368
+ //
369
+ // ___something_ strange__
370
+ //
371
+ // in that case, we want to handle the opening delimeter again, but
372
+ // only with the remaining length.
373
+ //
374
+ // for case two, closing length >= opening length. in this case, we
375
+ // reduce the lengths of both tokens but don't handle the opening again.
376
+ // in the case of === length, both tokens should basically disappear.
377
+ // if close > open, then the remaining balance will be treated as text.
378
+ // then we can jump ahead by the handled amount.
379
+
380
+ result.token.length -= format;
381
+ token.length -= format;
382
+
383
+ if (token.length > 0) {
384
+ index--; // repeat
385
+ }
386
+ else {
387
+ index += result.index;
388
+ }
389
+
390
+ }
391
+
392
+ }
393
+
394
+ }
395
+
396
+ }
397
+
398
+ // console.info("finished");
399
+
400
+ return {index};
401
+
402
+ }
403
+
404
+ /**
405
+ *
406
+ */
407
+ protected Tokenize(text = ''): Token[] {
408
+ const tokens: Token[] = [];
409
+ const length = text.length;
410
+
411
+ // first pass parse converts text into tokens
412
+
413
+ // FIXME: our escape rule is not quite right -- escape turns out to
414
+ // be pretty complicated, see CM spec @ 6.1. punting for the time being,
415
+ // we just always escape the next character.
416
+
417
+ let index = 0;
418
+ let escape = false;
419
+ let current_token = ''; // implicit text token
420
+
421
+ for (index = 0; index < length; index++) {
422
+ const char = text[index];
423
+
424
+ // we do this three times, but it's kind of hard to fold properly
425
+
426
+ if (this.IsWhitespace(char)) {
427
+
428
+ if (current_token) {
429
+ tokens.push({ type: 'text', text: current_token });
430
+ }
431
+
432
+ let tmp = char;
433
+ for (;;) { // while (true) {
434
+ const next_char = text[index+1];
435
+ if (this.IsWhitespace(next_char)) {
436
+ tmp += next_char;
437
+ index++;
438
+ }
439
+ else {
440
+ break;
441
+ }
442
+ }
443
+ tokens.push({
444
+ type: 'whitespace',
445
+ text: tmp,
446
+ })
447
+ escape = false;
448
+ current_token = '';
449
+
450
+ }
451
+ else if (this.IsNewline(char)) {
452
+
453
+ if (current_token) {
454
+ tokens.push({ type: 'text', text: current_token });
455
+ }
456
+
457
+ let tmp = char;
458
+ for (;;) { // while (true) {
459
+ const next_char = text[index+1];
460
+ if (this.IsNewline(next_char)) {
461
+ tmp += next_char;
462
+ index++;
463
+ }
464
+ else {
465
+ break;
466
+ }
467
+ }
468
+ tokens.push({
469
+ type: 'newline',
470
+ text: tmp,
471
+ })
472
+ escape = false;
473
+ current_token = '';
474
+
475
+ }
476
+ else if (escape) {
477
+ current_token += char;
478
+ escape = false;
479
+ }
480
+ else if (this.IsDelimeter(char)) {
481
+
482
+ if (current_token) {
483
+ tokens.push({ type: 'text', text: current_token });
484
+ }
485
+
486
+ let tmp = char;
487
+ for (;;) { // while (true) {
488
+ const next_char = text[index+1];
489
+ if (next_char === char) { // delimeters do not mix
490
+ tmp += next_char;
491
+ index++;
492
+ }
493
+ else {
494
+ break;
495
+ }
496
+ }
497
+ tokens.push({
498
+ type: 'delimeter',
499
+ text: tmp,
500
+ char,
501
+ length: tmp.length,
502
+ })
503
+ escape = false;
504
+ current_token = '';
505
+
506
+ }
507
+ else if (char === '\\') {
508
+ escape = true;
509
+ }
510
+ else {
511
+ current_token += char;
512
+ }
513
+
514
+ }
515
+
516
+ if (current_token) {
517
+ tokens.push({type: 'text', text: current_token});
518
+ }
519
+
520
+ return tokens;
521
+ }
522
+
523
+ }
524
+
525
+
526
+