Преглед на файлове

Regexes safely escaped. Renamed MDSpreadsheetBlockReader

main
Rocketsoup преди 1 година
родител
ревизия
ab3689c2bf
променени са 5 файла, в които са добавени 55 реда и са изтрити 10 реда
  1. 39
    2
      js/markdown.js
  2. 2
    2
      js/spreadsheet.js
  3. 1
    1
      markdownjs.html
  4. 1
    1
      spreadsheet.md
  5. 12
    4
      testjs.html

+ 39
- 2
js/markdown.js Целия файл

449
 		}
449
 		}
450
 		return a == b;
450
 		return a == b;
451
 	}
451
 	}
452
+
453
+	/**
454
+	 * @param {string} text
455
+	 */
456
+	static escapeRegex(text) {
457
+		// Partially following escaping scheme from not-yet-widely-supported RegExp.escape.
458
+		// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/escape
459
+		const escapeHex = function(ch) {
460
+			const codepoint = ch.codePointAt(0);
461
+			const s = '00' + codepoint.toString(16);
462
+			return `\\x${s.substring(s.length - 2)}`;
463
+		}
464
+		var escaped = '';
465
+		const l = text.length;
466
+		for (var i = 0; i < l; i++) {
467
+			const ch = text.substring(i, i + 1);
468
+			if (i == 0 && /[a-zA-Z0-9]/.exec(ch)) {
469
+				escaped += escapeHex(ch);
470
+			} else if ("^$\\.*+?()[]{}|/".indexOf(ch) >= 0) {
471
+				escaped += `\\${ch}`;
472
+			} else if (",-=<>#&!%:;@~'`\"".indexOf(ch) >= 0) {
473
+				escaped += escapeHex(ch);
474
+			} else if (ch == '\f') {
475
+				escaped += "\\f";
476
+			} else if (ch == '\n') {
477
+				escaped += "\\n";
478
+			} else if (ch == '\r') {
479
+				escaped += "\\r";
480
+			} else if (ch == '\t') {
481
+				escaped += "\\t";
482
+			} else if (ch == '\v') {
483
+				escaped += "\\v";
484
+			} else {
485
+				escaped += ch;
486
+			}
487
+		}
488
+		return escaped;
489
+	}
452
 }
490
 }
453
 
491
 
454
 
492
 
3224
 			this.#parent.defineAbbreviation(abbreviation, definition);
3262
 			this.#parent.defineAbbreviation(abbreviation, definition);
3225
 			return;
3263
 			return;
3226
 		}
3264
 		}
3227
-		// FIXME: Escape abbreviation
3228
 		this.#abbreviations[abbreviation] = definition;
3265
 		this.#abbreviations[abbreviation] = definition;
3229
-		const regex = new RegExp("\\b(" + abbreviation + ")\\b", "ig");
3266
+		const regex = new RegExp("\\b(" + MDUtils.escapeRegex(abbreviation) + ")\\b", "ig");
3230
 		this.#abbreviationRegexes[abbreviation] = regex;
3267
 		this.#abbreviationRegexes[abbreviation] = regex;
3231
 	}
3268
 	}
3232
 
3269
 

+ 2
- 2
js/spreadsheet.js Целия файл

918
 		if (text === null || search === null || replace === null) {
918
 		if (text === null || search === null || replace === null) {
919
 			throw new CellEvaluationException("SUBSTITUTE expects 3 string arguments");
919
 			throw new CellEvaluationException("SUBSTITUTE expects 3 string arguments");
920
 		}
920
 		}
921
-		const result = text.replaceAll(search, replace); // FIXME: Not case-insensitive
921
+		const result = text.replace(new RegExp(MDUtils.escapeRegex(search), 'gi'), replace);
922
 		return CellValue.fromValue(result);
922
 		return CellValue.fromValue(result);
923
 	}
923
 	}
924
 
924
 
2891
  * post-process step on any tables in the document tree. Must be used with
2891
  * post-process step on any tables in the document tree. Must be used with
2892
  * `MDTableBlockReader`. Tables without at least one formula will not be altered.
2892
  * `MDTableBlockReader`. Tables without at least one formula will not be altered.
2893
  */
2893
  */
2894
-class SpreadsheetBlockReader extends MDBlockReader {
2894
+class MDSpreadsheetBlockReader extends MDBlockReader {
2895
 	readBlock(state) {
2895
 	readBlock(state) {
2896
 		return null;
2896
 		return null;
2897
 	}
2897
 	}

+ 1
- 1
markdownjs.html Целия файл

86
 		<script src="js/markdown.js"></script>
86
 		<script src="js/markdown.js"></script>
87
 		<script src="js/spreadsheet.js"></script>
87
 		<script src="js/spreadsheet.js"></script>
88
 		<script>
88
 		<script>
89
-			var parser = new Markdown([ ...Markdown.allBlockReaders, new SpreadsheetBlockReader() ], Markdown.allInlineReaders);
89
+			var parser = new Markdown([ ...Markdown.allBlockReaders, new MDSpreadsheetBlockReader() ], Markdown.allInlineReaders);
90
 			function onDocumentLoad() {
90
 			function onDocumentLoad() {
91
 				document.getElementById('markdowninput').addEventListener('input', onMarkdownChange);
91
 				document.getElementById('markdowninput').addEventListener('input', onMarkdownChange);
92
 				setTimeout(onMarkdownChange, 0);
92
 				setTimeout(onMarkdownChange, 0);

+ 1
- 1
spreadsheet.md Целия файл

1
 # Spreadsheet Expressions
1
 # Spreadsheet Expressions
2
 
2
 
3
-Spreadsheet expressions are an optional feature not enabled in the default parser configurations. To enable it, include `spreadsheet.js` and create a `Markdown` instance with a `SpreadsheetBlockReader`.
3
+Spreadsheet expressions are an optional feature not enabled in the default parser configurations. To enable it, include `spreadsheet.js` and create a `Markdown` instance with a `MDSpreadsheetBlockReader`.
4
 
4
 
5
 ## Expressions
5
 ## Expressions
6
 
6
 

+ 12
- 4
testjs.html Целия файл

1212
 					this.assertEqual(value.type, CellValue.TYPE_STRING);
1212
 					this.assertEqual(value.type, CellValue.TYPE_STRING);
1213
 					this.assertEqual(value.formattedValue, 'some text');
1213
 					this.assertEqual(value.formattedValue, 'some text');
1214
 					this.assertEqual(value.value, 'some text');
1214
 					this.assertEqual(value.value, 'some text');
1215
-					value = CellValue.fromCellString("'123");
1215
+					value = CellValue.fromCellString("'0123");
1216
 					this.assertEqual(value.type, CellValue.TYPE_STRING);
1216
 					this.assertEqual(value.type, CellValue.TYPE_STRING);
1217
-					this.assertEqual(value.formattedValue, '123');
1218
-					this.assertEqual(value.value, '123');
1217
+					this.assertEqual(value.formattedValue, '0123');
1218
+					this.assertEqual(value.value, '0123');
1219
+					value = CellValue.fromCellString("'=123");
1220
+					this.assertEqual(value.type, CellValue.TYPE_STRING);
1221
+					this.assertEqual(value.formattedValue, '=123');
1222
+					this.assertEqual(value.value, '=123');
1219
 				}
1223
 				}
1220
 
1224
 
1221
 				test_fromCellString_formula() {
1225
 				test_fromCellString_formula() {
1574
 
1578
 
1575
 				test_func_average() {
1579
 				test_func_average() {
1576
 					this._test_simple_formula('=AVERAGE(4, 6, 2, 4)', 4);
1580
 					this._test_simple_formula('=AVERAGE(4, 6, 2, 4)', 4);
1581
+					this._test_simple_formula('=AVERAGE(4, 6, 2, "foo", 4)', 4);
1577
 				}
1582
 				}
1578
 
1583
 
1579
 				test_func_ceiling() {
1584
 				test_func_ceiling() {
1611
 
1616
 
1612
 				test_func_log() {
1617
 				test_func_log() {
1613
 					this._test_simple_formula('=LOG(1000, 10)', 3);
1618
 					this._test_simple_formula('=LOG(1000, 10)', 3);
1619
+					this._test_simple_formula('=LOG(64, 2)', 6);
1614
 				}
1620
 				}
1615
 
1621
 
1616
 				test_func_lower() {
1622
 				test_func_lower() {
1664
 
1670
 
1665
 				test_func_substitute() {
1671
 				test_func_substitute() {
1666
 					this._test_simple_formula('=SUBSTITUTE("cat sat on the mat", "at", "ot")', 'cot sot on the mot');
1672
 					this._test_simple_formula('=SUBSTITUTE("cat sat on the mat", "at", "ot")', 'cot sot on the mot');
1673
+					this._test_simple_formula('=SUBSTITUTE("cAt saT on the mat", "at", "ot")', 'cot sot on the mot');
1674
+					this._test_simple_formula('=SUBSTITUTE("c.*t s.*t on the m.*t", ".*t", "ot")', 'cot sot on the mot');
1667
 				}
1675
 				}
1668
 
1676
 
1669
 				test_func_sum() {
1677
 				test_func_sum() {
1694
 				parser;
1702
 				parser;
1695
 
1703
 
1696
 				setUp() {
1704
 				setUp() {
1697
-					this.parser = new Markdown([ ...Markdown.allBlockReaders, new SpreadsheetBlockReader() ], Markdown.allInlineReaders);
1705
+					this.parser = new Markdown([ ...Markdown.allBlockReaders, new MDSpreadsheetBlockReader() ], Markdown.allInlineReaders);
1698
 				}
1706
 				}
1699
 
1707
 
1700
 				md(markdown) {
1708
 				md(markdown) {

Loading…
Отказ
Запис