reslop 0.1.4 → 0.1.6

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.
@@ -0,0 +1,194 @@
1
+ 'use strict';
2
+
3
+ const SQUOTE = '\x27';
4
+ const QUOTES = `${SQUOTE}"`;
5
+ const ANY_QUOTE = `${QUOTES}\``;
6
+
7
+ const OP3 = ['===', '!==', '>>>', '**=', '&&=', '||=', '??='];
8
+
9
+ const OP2 = [
10
+ '==',
11
+ '!=',
12
+ '<=',
13
+ '>=',
14
+ '&&',
15
+ '||',
16
+ '??',
17
+ '=>',
18
+ '++',
19
+ '--',
20
+ '<<',
21
+ '>>',
22
+ '**',
23
+ '+=',
24
+ '-=',
25
+ '*=',
26
+ '/=',
27
+ '%=',
28
+ '&=',
29
+ '|=',
30
+ '^=',
31
+ ];
32
+
33
+ const EXPECT_STYLE = {
34
+ function: 'function',
35
+ class: 'className',
36
+ type: 'className',
37
+ };
38
+
39
+ const emit = (out, style, text) => {
40
+ if (!text) return;
41
+ out.push({ text, style: style || 'plain' });
42
+ };
43
+
44
+ const tokensText = (out) => {
45
+ let s = '';
46
+ for (const t of out) s += t.text;
47
+ return s;
48
+ };
49
+
50
+ const wordStyle = (words, style) => {
51
+ const table = {};
52
+ for (const word of words) table[word] = style;
53
+ return table;
54
+ };
55
+
56
+ const peekIdent = (source, i) => {
57
+ if (!/[A-Za-z_$]/.test(source[i] || '')) return null;
58
+ let j = i + 1;
59
+ while (j < source.length && /[A-Za-z0-9_$]/.test(source[j])) j += 1;
60
+ return source.slice(i, j);
61
+ };
62
+
63
+ const skipWs = (source, i) => {
64
+ while (i < source.length && /\s/.test(source[i])) i += 1;
65
+ return i;
66
+ };
67
+
68
+ const readUntilNl = (source, i) => {
69
+ let j = i;
70
+ const n = source.length;
71
+ while (j < n && source[j] !== '\n') j += 1;
72
+ return { text: source.slice(i, j), end: j };
73
+ };
74
+
75
+ const readBlockComment = (source, i) => {
76
+ let j = i + 2;
77
+ const n = source.length;
78
+ while (j < n && !(source[j] === '*' && source[j + 1] === '/')) {
79
+ j += 1;
80
+ }
81
+ j = Math.min(j + 2, n);
82
+ return { text: source.slice(i, j), end: j };
83
+ };
84
+
85
+ const skipQuoted = (source, j) => {
86
+ const q = source[j];
87
+ j += 1;
88
+ const n = source.length;
89
+ while (j < n && source[j] !== q) {
90
+ if (source[j] === '\\') j += 1;
91
+ j += 1;
92
+ }
93
+ j += 1;
94
+ return j;
95
+ };
96
+
97
+ const readJsNumber = (source, i) => {
98
+ const n = source.length;
99
+ let j = i;
100
+ if (source.startsWith('0x', i) || source.startsWith('0X', i)) {
101
+ j += 2;
102
+ while (j < n && /[0-9a-fA-F_]/.test(source[j])) j += 1;
103
+ } else if (source.startsWith('0b', i) || source.startsWith('0B', i)) {
104
+ j += 2;
105
+ while (j < n && /[01_]/.test(source[j])) j += 1;
106
+ } else if (source.startsWith('0o', i) || source.startsWith('0O', i)) {
107
+ j += 2;
108
+ while (j < n && /[0-7_]/.test(source[j])) j += 1;
109
+ } else {
110
+ while (j < n && /[0-9_n.]/.test(source[j])) j += 1;
111
+ if ('eE'.includes(source[j])) {
112
+ j += 1;
113
+ if ('+-'.includes(source[j])) j += 1;
114
+ while (j < n && /[0-9_]/.test(source[j])) j += 1;
115
+ }
116
+ }
117
+ return { text: source.slice(i, j), end: j };
118
+ };
119
+
120
+ const readJsOperator = (source, i) => {
121
+ const two = source.slice(i, i + 2);
122
+ const three = source.slice(i, i + 3);
123
+ let j = i + 1;
124
+ if (OP3.includes(three)) j = i + 3;
125
+ else if (OP2.includes(two)) j = i + 2;
126
+ return { text: source.slice(i, j), end: j };
127
+ };
128
+
129
+ const readString = (source, i) => {
130
+ const q = source[i];
131
+ let j = i + 1;
132
+ const n = source.length;
133
+ while (j < n) {
134
+ if (source[j] === '\\') {
135
+ j += 2;
136
+ continue;
137
+ }
138
+ if (source[j] === q) {
139
+ j += 1;
140
+ break;
141
+ }
142
+ if (source[j] === '\n') break;
143
+ j += 1;
144
+ }
145
+ return { text: source.slice(i, j), end: j };
146
+ };
147
+
148
+ const readTemplateInterp = (source, j) => {
149
+ let depth = 1;
150
+ const start = j;
151
+ const n = source.length;
152
+ while (j < n && depth > 0) {
153
+ if (ANY_QUOTE.includes(source[j])) {
154
+ j = skipQuoted(source, j);
155
+ continue;
156
+ }
157
+ if (source[j] === '{') depth += 1;
158
+ if (source[j] === '}') {
159
+ depth -= 1;
160
+ if (depth === 0) break;
161
+ }
162
+ j += 1;
163
+ }
164
+ return { expr: source.slice(start, j), end: j };
165
+ };
166
+
167
+ const styleConstant = ({ word }) =>
168
+ /^[A-Z][A-Z0-9_]+$/.test(word) ? 'constant' : null;
169
+
170
+ const stylePascal = ({ word }) => (/^[A-Z]/.test(word) ? 'className' : null);
171
+
172
+ const styleCall = ({ after }) => (after === '(' ? 'function' : null);
173
+
174
+ module.exports = {
175
+ SQUOTE,
176
+ QUOTES,
177
+ ANY_QUOTE,
178
+ EXPECT_STYLE,
179
+ emit,
180
+ tokensText,
181
+ wordStyle,
182
+ peekIdent,
183
+ skipWs,
184
+ readUntilNl,
185
+ readBlockComment,
186
+ skipQuoted,
187
+ readJsNumber,
188
+ readJsOperator,
189
+ readString,
190
+ readTemplateInterp,
191
+ styleConstant,
192
+ stylePascal,
193
+ styleCall,
194
+ };
@@ -0,0 +1,76 @@
1
+ 'use strict';
2
+
3
+ const { QUOTES, emit, readBlockComment, readString } = require('./core.js');
4
+
5
+ const langs = ['css'];
6
+
7
+ const CSS_NEXT_STYLE = {
8
+ ':': 'property',
9
+ '{': 'tag',
10
+ };
11
+
12
+ const cssWordStyle = (next) => CSS_NEXT_STYLE[next] ?? 'plain';
13
+
14
+ const highlight = (source) => {
15
+ const out = [];
16
+ let i = 0;
17
+ const n = source.length;
18
+ while (i < n) {
19
+ const ch = source[i];
20
+ const next = source[i + 1];
21
+ if (ch === '/' && next === '*') {
22
+ const { text, end } = readBlockComment(source, i);
23
+ emit(out, 'comment', text);
24
+ i = end;
25
+ continue;
26
+ }
27
+ if (QUOTES.includes(ch)) {
28
+ const { text, end } = readString(source, i);
29
+ emit(out, 'string', text);
30
+ i = end;
31
+ continue;
32
+ }
33
+ if (ch === '@') {
34
+ let j = i + 1;
35
+ while (j < n && /[A-Za-z0-9-]/.test(source[j])) j += 1;
36
+ emit(out, 'keyword', source.slice(i, j));
37
+ i = j;
38
+ continue;
39
+ }
40
+ if ('#.'.includes(ch)) {
41
+ let j = i + 1;
42
+ while (j < n && /[A-Za-z0-9_-]/.test(source[j])) j += 1;
43
+ const kind = ch === '#' ? 'constant' : 'className';
44
+ emit(out, kind, source.slice(i, j));
45
+ i = j;
46
+ continue;
47
+ }
48
+ if (/[0-9]/.test(ch)) {
49
+ let j = i;
50
+ while (j < n && /[0-9.%]/.test(source[j])) j += 1;
51
+ emit(out, 'number', source.slice(i, j));
52
+ i = j;
53
+ continue;
54
+ }
55
+ if (/[A-Za-z_-]/.test(ch)) {
56
+ let j = i + 1;
57
+ while (j < n && /[A-Za-z0-9_-]/.test(source[j])) j += 1;
58
+ const word = source.slice(i, j);
59
+ let k = j;
60
+ while (k < n && /\s/.test(source[k])) k += 1;
61
+ emit(out, cssWordStyle(source[k]), word);
62
+ i = j;
63
+ continue;
64
+ }
65
+ if (/[{};:,]/.test(ch)) {
66
+ emit(out, 'punct', ch);
67
+ i += 1;
68
+ continue;
69
+ }
70
+ emit(out, 'plain', ch);
71
+ i += 1;
72
+ }
73
+ return out;
74
+ };
75
+
76
+ module.exports = { langs, highlight };
@@ -0,0 +1,66 @@
1
+ 'use strict';
2
+
3
+ const { emit } = require('./core.js');
4
+
5
+ const langs = ['csv'];
6
+
7
+ const splitCsv = (line) => {
8
+ const cells = [];
9
+ let cur = '';
10
+ let inQ = false;
11
+ for (let i = 0; i < line.length; i += 1) {
12
+ const ch = line[i];
13
+ if (ch === '"') {
14
+ if (inQ && line[i + 1] === '"') {
15
+ cur += '"';
16
+ i += 1;
17
+ } else {
18
+ inQ = !inQ;
19
+ cur += ch;
20
+ }
21
+ continue;
22
+ }
23
+ if (ch === ',' && !inQ) {
24
+ cells.push(cur);
25
+ cur = '';
26
+ continue;
27
+ }
28
+ cur += ch;
29
+ }
30
+ cells.push(cur);
31
+ return cells;
32
+ };
33
+
34
+ const highlightCsvCell = (cell, row, col) => {
35
+ if (row === 0) return { text: cell, style: 'function' };
36
+ const num = /^-?\d+(\.\d+)?$/.test(cell.trim());
37
+ if (num) return { text: cell, style: 'number' };
38
+ if (col % 2 === 0) return { text: cell, style: 'string' };
39
+ return { text: cell, style: 'variable' };
40
+ };
41
+
42
+ const highlightCsvLine = (line, row) => {
43
+ if (!line) return [];
44
+ const cells = splitCsv(line);
45
+ const out = [];
46
+ for (let col = 0; col < cells.length; col += 1) {
47
+ if (col) emit(out, 'punct', ',');
48
+ const cell = highlightCsvCell(cells[col], row, col);
49
+ emit(out, cell.style, cell.text);
50
+ }
51
+ return out;
52
+ };
53
+
54
+ const highlight = (source) => {
55
+ const lines = source.split(/\r?\n/);
56
+ const out = [];
57
+ for (let row = 0; row < lines.length; row += 1) {
58
+ if (row) emit(out, 'plain', '\n');
59
+ for (const t of highlightCsvLine(lines[row], row === 0 ? 1 : row)) {
60
+ out.push(t);
61
+ }
62
+ }
63
+ return out;
64
+ };
65
+
66
+ module.exports = { langs, highlight };
@@ -0,0 +1,261 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ SQUOTE,
5
+ QUOTES,
6
+ EXPECT_STYLE,
7
+ emit,
8
+ wordStyle,
9
+ peekIdent,
10
+ skipWs,
11
+ readUntilNl,
12
+ readBlockComment,
13
+ readJsNumber,
14
+ readJsOperator,
15
+ readTemplateInterp,
16
+ styleConstant,
17
+ stylePascal,
18
+ styleCall,
19
+ } = require('./core.js');
20
+
21
+ const langs = ['dart'];
22
+
23
+ const STORAGE = [
24
+ 'abstract',
25
+ 'as',
26
+ 'base',
27
+ 'class',
28
+ 'const',
29
+ 'covariant',
30
+ 'deferred',
31
+ 'enum',
32
+ 'export',
33
+ 'extends',
34
+ 'extension',
35
+ 'external',
36
+ 'factory',
37
+ 'final',
38
+ 'get',
39
+ 'hide',
40
+ 'implements',
41
+ 'import',
42
+ 'interface',
43
+ 'late',
44
+ 'library',
45
+ 'mixin',
46
+ 'on',
47
+ 'operator',
48
+ 'part',
49
+ 'required',
50
+ 'sealed',
51
+ 'set',
52
+ 'show',
53
+ 'static',
54
+ 'typedef',
55
+ 'var',
56
+ 'with',
57
+ ];
58
+
59
+ const CONTROL = [
60
+ 'assert',
61
+ 'async',
62
+ 'await',
63
+ 'break',
64
+ 'case',
65
+ 'catch',
66
+ 'continue',
67
+ 'default',
68
+ 'do',
69
+ 'else',
70
+ 'for',
71
+ 'if',
72
+ 'in',
73
+ 'is',
74
+ 'new',
75
+ 'rethrow',
76
+ 'return',
77
+ 'switch',
78
+ 'sync',
79
+ 'throw',
80
+ 'try',
81
+ 'when',
82
+ 'while',
83
+ 'yield',
84
+ ];
85
+
86
+ const LITERALS = ['true', 'false', 'null', 'this', 'super'];
87
+
88
+ const TYPES = ['void', 'dynamic', 'Never', 'int', 'double', 'num', 'bool'];
89
+
90
+ const NEXT_EXPECT = {
91
+ class: 'class',
92
+ mixin: 'class',
93
+ enum: 'class',
94
+ extension: 'class',
95
+ typedef: 'type',
96
+ };
97
+
98
+ const WORD_STYLE = {
99
+ ...wordStyle(CONTROL, 'control'),
100
+ ...wordStyle(LITERALS, 'literal'),
101
+ ...wordStyle(STORAGE, 'storage'),
102
+ ...wordStyle(TYPES, 'type'),
103
+ };
104
+
105
+ const dartStringOpen = (source, i) => {
106
+ let at = i;
107
+ const raw = source[i] === 'r';
108
+ if (raw) at = i + 1;
109
+ let quote = '';
110
+ const triple = SQUOTE.repeat(3);
111
+ const dtriple = '"'.repeat(3);
112
+ if (source.startsWith(triple, at) || source.startsWith(dtriple, at)) {
113
+ quote = source.slice(at, at + 3);
114
+ } else if (QUOTES.includes(source[at] || '')) {
115
+ quote = source[at];
116
+ }
117
+ if (!quote) return null;
118
+ return { raw, quote, body: at + quote.length };
119
+ };
120
+
121
+ const dartIdentStyle = (ctx) => {
122
+ const known = WORD_STYLE[ctx.word];
123
+ if (known) return known;
124
+ if (EXPECT_STYLE[ctx.expectName]) return EXPECT_STYLE[ctx.expectName];
125
+ if (styleConstant(ctx)) return 'constant';
126
+ if (stylePascal(ctx)) return 'className';
127
+ if (styleCall(ctx)) return 'function';
128
+ return 'variable';
129
+ };
130
+
131
+ const highlightDartString = (source, i, inner) => {
132
+ const open = dartStringOpen(source, i);
133
+ const n = source.length;
134
+ const parts = [];
135
+ emit(parts, 'string', source.slice(i, open.body));
136
+ let j = open.body;
137
+ let buf = '';
138
+ const flush = () => {
139
+ if (!buf) return;
140
+ emit(parts, 'string', buf);
141
+ buf = '';
142
+ };
143
+ const quote = open.quote;
144
+ while (j < n) {
145
+ if (!open.raw && source[j] === '\\') {
146
+ flush();
147
+ emit(parts, 'escape', source.slice(j, j + 2));
148
+ j += 2;
149
+ continue;
150
+ }
151
+ if (source.startsWith(quote, j)) {
152
+ flush();
153
+ emit(parts, 'string', quote);
154
+ j += quote.length;
155
+ break;
156
+ }
157
+ if (!open.raw && source[j] === '$') {
158
+ const next = source[j + 1];
159
+ if (next === '{') {
160
+ flush();
161
+ emit(parts, 'interpolation', '${');
162
+ j += 2;
163
+ const interp = readTemplateInterp(source, j);
164
+ for (const t of inner(interp.expr)) parts.push(t);
165
+ j = interp.end;
166
+ if (source[j] === '}') {
167
+ emit(parts, 'interpolation', '}');
168
+ j += 1;
169
+ }
170
+ continue;
171
+ }
172
+ if (/[A-Za-z_$]/.test(next || '')) {
173
+ flush();
174
+ const ident = peekIdent(source, j + 1);
175
+ emit(parts, 'interpolation', `$${ident}`);
176
+ j += 1 + ident.length;
177
+ continue;
178
+ }
179
+ }
180
+ if (quote.length === 1 && source[j] === '\n') break;
181
+ buf += source[j];
182
+ j += 1;
183
+ }
184
+ flush();
185
+ return { tokens: parts, end: j };
186
+ };
187
+
188
+ const highlight = (source) => {
189
+ const inner = (expr) => highlight(expr);
190
+ const out = [];
191
+ let i = 0;
192
+ const n = source.length;
193
+ let expectName = null;
194
+ while (i < n) {
195
+ const ch = source[i];
196
+ const next = source[i + 1];
197
+ if (ch === '/' && next === '/') {
198
+ const { text, end } = readUntilNl(source, i);
199
+ emit(out, 'comment', text);
200
+ i = end;
201
+ continue;
202
+ }
203
+ if (ch === '/' && next === '*') {
204
+ const { text, end } = readBlockComment(source, i);
205
+ emit(out, 'comment', text);
206
+ i = end;
207
+ continue;
208
+ }
209
+ if (dartStringOpen(source, i)) {
210
+ const node = highlightDartString(source, i, inner);
211
+ for (const t of node.tokens) out.push(t);
212
+ i = node.end;
213
+ expectName = null;
214
+ continue;
215
+ }
216
+ if (/[0-9]/.test(ch) || (ch === '.' && /[0-9]/.test(next || ''))) {
217
+ const { text, end } = readJsNumber(source, i);
218
+ emit(out, 'number', text);
219
+ i = end;
220
+ continue;
221
+ }
222
+ if (ch === '@' || ch === '#') {
223
+ let j = i + 1;
224
+ while (j < n && /[A-Za-z0-9_$]/.test(source[j])) j += 1;
225
+ const kind = ch === '@' ? 'decorator' : 'constant';
226
+ emit(out, kind, source.slice(i, j));
227
+ i = j;
228
+ expectName = null;
229
+ continue;
230
+ }
231
+ if (/[A-Za-z_$]/.test(ch)) {
232
+ const word = peekIdent(source, i);
233
+ const end = i + word.length;
234
+ const k = skipWs(source, end);
235
+ const after = source[k];
236
+ const ctx = { word, after, expectName };
237
+ emit(out, dartIdentStyle(ctx), word);
238
+ if (EXPECT_STYLE[expectName]) expectName = null;
239
+ else expectName = NEXT_EXPECT[word] ?? null;
240
+ i = end;
241
+ continue;
242
+ }
243
+ if (/[=<>!+\-*/%&|^~?:]/.test(ch)) {
244
+ const { text, end } = readJsOperator(source, i);
245
+ emit(out, 'operator', text);
246
+ i = end;
247
+ expectName = null;
248
+ continue;
249
+ }
250
+ if (/[{}()[\];,.]/.test(ch)) {
251
+ emit(out, 'punct', ch);
252
+ i += 1;
253
+ continue;
254
+ }
255
+ emit(out, 'plain', ch);
256
+ i += 1;
257
+ }
258
+ return out;
259
+ };
260
+
261
+ module.exports = { langs, highlight };
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ const { emit } = require('./core.js');
4
+
5
+ const langs = ['dot'];
6
+
7
+ const aliases = {
8
+ env: 'dot',
9
+ ini: 'dot',
10
+ conf: 'dot',
11
+ cfg: 'dot',
12
+ yaml: 'dot',
13
+ yml: 'dot',
14
+ toml: 'dot',
15
+ };
16
+
17
+ const highlightDotLine = (line) => {
18
+ if (!line) return [];
19
+ const out = [];
20
+ const t = line.trimStart();
21
+ if (t.startsWith('#') || t.startsWith(';')) {
22
+ emit(out, 'comment', line);
23
+ return out;
24
+ }
25
+ if (t.startsWith('!')) {
26
+ const lead = line.slice(0, line.length - t.length);
27
+ emit(out, 'plain', lead);
28
+ emit(out, 'operator', '!');
29
+ emit(out, 'plain', t.slice(1));
30
+ return out;
31
+ }
32
+ const eq = line.match(/^(\s*)([A-Za-z_][A-Za-z0-9_.-]*)(\s*=\s*)(.*)$/);
33
+ if (eq) {
34
+ emit(out, 'plain', eq[1]);
35
+ emit(out, 'variable', eq[2]);
36
+ emit(out, 'operator', eq[3]);
37
+ emit(out, 'string', eq[4]);
38
+ return out;
39
+ }
40
+ emit(out, 'plain', line);
41
+ return out;
42
+ };
43
+
44
+ const highlight = (source) => {
45
+ const lines = source.split('\n');
46
+ const out = [];
47
+ for (let i = 0; i < lines.length; i += 1) {
48
+ if (i) emit(out, 'plain', '\n');
49
+ for (const t of highlightDotLine(lines[i])) out.push(t);
50
+ }
51
+ return out;
52
+ };
53
+
54
+ module.exports = { langs, aliases, highlight };