@fuzdev/fuz_code 0.37.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 (76) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +185 -0
  3. package/dist/Code.svelte +146 -0
  4. package/dist/Code.svelte.d.ts +79 -0
  5. package/dist/Code.svelte.d.ts.map +1 -0
  6. package/dist/CodeHighlight.svelte +205 -0
  7. package/dist/CodeHighlight.svelte.d.ts +101 -0
  8. package/dist/CodeHighlight.svelte.d.ts.map +1 -0
  9. package/dist/code_sample.d.ts +8 -0
  10. package/dist/code_sample.d.ts.map +1 -0
  11. package/dist/code_sample.js +2 -0
  12. package/dist/grammar_clike.d.ts +12 -0
  13. package/dist/grammar_clike.d.ts.map +1 -0
  14. package/dist/grammar_clike.js +43 -0
  15. package/dist/grammar_css.d.ts +11 -0
  16. package/dist/grammar_css.d.ts.map +1 -0
  17. package/dist/grammar_css.js +70 -0
  18. package/dist/grammar_js.d.ts +11 -0
  19. package/dist/grammar_js.d.ts.map +1 -0
  20. package/dist/grammar_js.js +180 -0
  21. package/dist/grammar_json.d.ts +11 -0
  22. package/dist/grammar_json.d.ts.map +1 -0
  23. package/dist/grammar_json.js +35 -0
  24. package/dist/grammar_markdown.d.ts +8 -0
  25. package/dist/grammar_markdown.d.ts.map +1 -0
  26. package/dist/grammar_markdown.js +228 -0
  27. package/dist/grammar_markup.d.ts +31 -0
  28. package/dist/grammar_markup.d.ts.map +1 -0
  29. package/dist/grammar_markup.js +192 -0
  30. package/dist/grammar_svelte.d.ts +12 -0
  31. package/dist/grammar_svelte.d.ts.map +1 -0
  32. package/dist/grammar_svelte.js +150 -0
  33. package/dist/grammar_ts.d.ts +11 -0
  34. package/dist/grammar_ts.d.ts.map +1 -0
  35. package/dist/grammar_ts.js +95 -0
  36. package/dist/highlight_manager.d.ts +25 -0
  37. package/dist/highlight_manager.d.ts.map +1 -0
  38. package/dist/highlight_manager.js +139 -0
  39. package/dist/highlight_priorities.d.ts +3 -0
  40. package/dist/highlight_priorities.d.ts.map +1 -0
  41. package/dist/highlight_priorities.gen.d.ts +4 -0
  42. package/dist/highlight_priorities.gen.d.ts.map +1 -0
  43. package/dist/highlight_priorities.gen.js +58 -0
  44. package/dist/highlight_priorities.js +55 -0
  45. package/dist/syntax_styler.d.ts +277 -0
  46. package/dist/syntax_styler.d.ts.map +1 -0
  47. package/dist/syntax_styler.js +426 -0
  48. package/dist/syntax_styler_global.d.ts +3 -0
  49. package/dist/syntax_styler_global.d.ts.map +1 -0
  50. package/dist/syntax_styler_global.js +18 -0
  51. package/dist/syntax_token.d.ts +34 -0
  52. package/dist/syntax_token.d.ts.map +1 -0
  53. package/dist/syntax_token.js +27 -0
  54. package/dist/theme.css +98 -0
  55. package/dist/theme_highlight.css +160 -0
  56. package/dist/theme_variables.css +20 -0
  57. package/dist/tokenize_syntax.d.ts +28 -0
  58. package/dist/tokenize_syntax.d.ts.map +1 -0
  59. package/dist/tokenize_syntax.js +194 -0
  60. package/package.json +117 -0
  61. package/src/lib/code_sample.ts +10 -0
  62. package/src/lib/grammar_clike.ts +48 -0
  63. package/src/lib/grammar_css.ts +84 -0
  64. package/src/lib/grammar_js.ts +215 -0
  65. package/src/lib/grammar_json.ts +38 -0
  66. package/src/lib/grammar_markdown.ts +289 -0
  67. package/src/lib/grammar_markup.ts +225 -0
  68. package/src/lib/grammar_svelte.ts +165 -0
  69. package/src/lib/grammar_ts.ts +114 -0
  70. package/src/lib/highlight_manager.ts +182 -0
  71. package/src/lib/highlight_priorities.gen.ts +71 -0
  72. package/src/lib/highlight_priorities.ts +110 -0
  73. package/src/lib/syntax_styler.ts +583 -0
  74. package/src/lib/syntax_styler_global.ts +20 -0
  75. package/src/lib/syntax_token.ts +49 -0
  76. package/src/lib/tokenize_syntax.ts +270 -0
@@ -0,0 +1,270 @@
1
+ import type {SyntaxGrammar} from './syntax_styler.js';
2
+ import {SyntaxToken, type SyntaxTokenStream} from './syntax_token.js';
3
+
4
+ /**
5
+ * Accepts a string of text as input and the language definitions to use,
6
+ * and returns an array with the tokenized code.
7
+ *
8
+ * When the language definition includes nested tokens, the function is called recursively on each of these tokens.
9
+ *
10
+ * This method could be useful in other contexts as well, as a very crude parser.
11
+ *
12
+ * @param text - a string with the code to be styled
13
+ * @param grammar - an object containing the tokens to use
14
+ *
15
+ * Usually a language definition like `syntax_styler.get_lang('markup')`.
16
+ *
17
+ * @returns an array of strings and tokens, a token stream
18
+ *
19
+ * @example
20
+ * var code = `var foo = 0;`;
21
+ * var tokens = tokenize_syntax(code, SyntaxStyler.langs.js);
22
+ * for (var token of tokens) {
23
+ * if (token instanceof SyntaxToken && token.type === 'number') {
24
+ * console.log(`Found numeric literal: ${token.content}`);
25
+ * }
26
+ * }
27
+ */
28
+ export const tokenize_syntax = (text: string, grammar: SyntaxGrammar): SyntaxTokenStream => {
29
+ // Grammar is already normalized (rest merged, patterns in arrays, etc.)
30
+ var token_list = new LinkedList();
31
+ add_after(token_list, token_list.head, text);
32
+
33
+ match_grammar(text, token_list, grammar, token_list.head, 0);
34
+
35
+ return to_array(token_list);
36
+ };
37
+
38
+ interface RematchOptions {
39
+ cause: string;
40
+ reach: number;
41
+ }
42
+
43
+ const match_grammar = (
44
+ text: string,
45
+ token_list: LinkedList,
46
+ grammar: SyntaxGrammar,
47
+ start_node: LinkedListNode,
48
+ start_pos: number,
49
+ rematch?: RematchOptions,
50
+ ): void => {
51
+ for (var token in grammar) {
52
+ // Grammar is normalized: patterns is always an array of normalized objects
53
+ var patterns = grammar[token];
54
+
55
+ if (!patterns) {
56
+ continue;
57
+ }
58
+
59
+ for (var j = 0; j < patterns.length; ++j) {
60
+ if (rematch?.cause === token + ',' + j) {
61
+ return;
62
+ }
63
+
64
+ var pattern_obj = patterns[j]!;
65
+ // All properties are guaranteed to be present after normalization
66
+ var inside = pattern_obj.inside;
67
+ var lookbehind = pattern_obj.lookbehind;
68
+ var greedy = pattern_obj.greedy;
69
+ var alias = pattern_obj.alias;
70
+
71
+ // Pattern already has global flag if greedy (added during normalization)
72
+ var pattern: RegExp = pattern_obj.pattern;
73
+
74
+ for (
75
+ // iterate the token list and keep track of the current token/string position
76
+ var current_node = start_node.next, pos = start_pos;
77
+ current_node !== token_list.tail;
78
+ pos += current_node!.value!.length, current_node = current_node!.next
79
+ ) {
80
+ if (rematch && pos >= rematch.reach) {
81
+ break;
82
+ }
83
+
84
+ var str = current_node!.value;
85
+
86
+ if (token_list.length > text.length) {
87
+ // Something went terribly wrong, ABORT, ABORT!
88
+ return;
89
+ }
90
+
91
+ if (str instanceof SyntaxToken) {
92
+ continue;
93
+ }
94
+
95
+ var remove_count = 1;
96
+ var match;
97
+
98
+ if (greedy) {
99
+ match = match_pattern(pattern, pos, text, lookbehind);
100
+ if (!match || match.index >= text.length) {
101
+ break;
102
+ }
103
+
104
+ var from = match.index;
105
+ var to = match.index + match[0].length;
106
+ var p = pos;
107
+
108
+ // find the node that contains the match
109
+ p += current_node!.value!.length;
110
+ while (from >= p) {
111
+ current_node = current_node!.next;
112
+ p += current_node!.value!.length;
113
+ }
114
+ // adjust pos (and p)
115
+ p -= current_node!.value!.length;
116
+ pos = p;
117
+
118
+ // the current node is a Token, then the match starts inside another Token, which is invalid
119
+ if (current_node!.value instanceof SyntaxToken) {
120
+ continue;
121
+ }
122
+
123
+ // find the last node which is affected by this match
124
+ for (
125
+ var k = current_node;
126
+ k !== token_list.tail && (p < to || typeof k!.value === 'string');
127
+ k = k!.next
128
+ ) {
129
+ remove_count++;
130
+ p += k!.value!.length;
131
+ }
132
+ remove_count--;
133
+
134
+ // replace with the new match
135
+ str = text.substring(pos, p);
136
+ match.index -= pos;
137
+ } else {
138
+ match = match_pattern(pattern, 0, str!, lookbehind);
139
+ if (!match) {
140
+ continue;
141
+ }
142
+ }
143
+
144
+ var from = match.index;
145
+ var match_str = match[0];
146
+ var before = str!.substring(0, from);
147
+ var after = str!.substring(from + match_str.length);
148
+
149
+ var reach = pos + str!.length;
150
+ if (rematch && reach > rematch.reach) {
151
+ rematch.reach = reach;
152
+ }
153
+
154
+ var remove_from = current_node!.prev;
155
+
156
+ if (before) {
157
+ remove_from = add_after(token_list, remove_from!, before);
158
+ pos += before.length;
159
+ }
160
+
161
+ remove_range(token_list, remove_from!, remove_count);
162
+
163
+ var wrapped = new SyntaxToken(
164
+ token,
165
+ inside ? tokenize_syntax(match_str, inside) : match_str,
166
+ alias,
167
+ match_str,
168
+ );
169
+ current_node = add_after(token_list, remove_from!, wrapped);
170
+
171
+ if (after) {
172
+ add_after(token_list, current_node, after);
173
+ }
174
+
175
+ if (remove_count > 1) {
176
+ // at least one Token object was removed, so we have to do some rematching
177
+ // this can only happen if the current pattern is greedy
178
+
179
+ var nested_rematch: RematchOptions = {
180
+ cause: token + ',' + j,
181
+ reach,
182
+ };
183
+ match_grammar(text, token_list, grammar, current_node.prev!, pos, nested_rematch);
184
+
185
+ // the reach might have been extended because of the rematching
186
+ if (rematch && nested_rematch.reach > rematch.reach) {
187
+ rematch.reach = nested_rematch.reach;
188
+ }
189
+ }
190
+ }
191
+ }
192
+ }
193
+ };
194
+
195
+ class LinkedList<T = string | SyntaxToken> {
196
+ head: LinkedListNode<T>;
197
+ tail: LinkedListNode<T>;
198
+ length: number = 0;
199
+
200
+ constructor() {
201
+ this.head = {value: null, prev: null, next: null};
202
+ this.tail = {value: null, prev: this.head, next: null};
203
+ this.head.next = this.tail;
204
+ }
205
+ }
206
+
207
+ interface LinkedListNode<T = string | SyntaxToken> {
208
+ value: T | null;
209
+ prev: LinkedListNode<T> | null;
210
+ next: LinkedListNode<T> | null;
211
+ }
212
+
213
+ /**
214
+ * Adds a new node with the given value to the list.
215
+ */
216
+ const add_after = <T>(
217
+ list: LinkedList<T>,
218
+ node: LinkedListNode<T>,
219
+ value: T,
220
+ ): LinkedListNode<T> => {
221
+ // assumes that node != list.tail && values.length >= 0
222
+ var next = node.next!;
223
+
224
+ var new_node = {value, prev: node, next};
225
+ node.next = new_node;
226
+ next.prev = new_node;
227
+ list.length++;
228
+
229
+ return new_node;
230
+ };
231
+
232
+ /**
233
+ * Removes `count` nodes after the given node. The given node will not be removed.
234
+ */
235
+ const remove_range = <T>(list: LinkedList<T>, node: LinkedListNode<T>, count: number) => {
236
+ var next = node.next;
237
+ for (var i = 0; i < count && next !== list.tail; i++) {
238
+ next = next!.next;
239
+ }
240
+ node.next = next;
241
+ next!.prev = node;
242
+ list.length -= i;
243
+ };
244
+
245
+ const to_array = <T>(list: LinkedList<T>): Array<T> => {
246
+ var array = [];
247
+ var node = list.head.next;
248
+ while (node !== list.tail) {
249
+ array.push(node!.value!);
250
+ node = node!.next;
251
+ }
252
+ return array;
253
+ };
254
+
255
+ const match_pattern = (
256
+ pattern: RegExp,
257
+ pos: number,
258
+ text: string,
259
+ lookbehind: boolean,
260
+ ): RegExpExecArray | null => {
261
+ pattern.lastIndex = pos;
262
+ var match = pattern.exec(text);
263
+ if (match && lookbehind && match[1]) {
264
+ // change the match to remove the text matched by the lookbehind group
265
+ var lookbehind_length = match[1].length;
266
+ match.index += lookbehind_length;
267
+ match[0] = match[0].substring(lookbehind_length);
268
+ }
269
+ return match;
270
+ };