reslop 0.1.1 → 0.1.3
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.
- package/CHANGELOG.md +21 -6
- package/README.md +29 -26
- package/bin/reslop.js +2 -2
- package/lib/ansi.js +0 -1
- package/lib/cli.js +62 -47
- package/lib/clipboard.js +1 -1
- package/lib/deps.js +1440 -0
- package/lib/detect.js +6 -4
- package/lib/diff.js +31 -55
- package/lib/editor.js +1 -1
- package/lib/files.js +58 -15
- package/lib/git.js +649 -69
- package/lib/github.js +28 -34
- package/lib/highlight.js +282 -141
- package/lib/keys.js +35 -39
- package/lib/render.js +250 -153
- package/lib/review.js +22 -42
- package/lib/select.js +16 -18
- package/lib/session.js +301 -227
- package/lib/source.js +7 -3
- package/package.json +1 -1
package/lib/github.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
const { delay } = require('metautil');
|
|
4
4
|
|
|
5
5
|
const diff = require('./diff.js');
|
|
6
|
-
const { parseDiff, itemsFromFiles } = diff;
|
|
7
|
-
const { itemPath } = require('./files.js');
|
|
6
|
+
const { parseDiff, itemsFromFiles, isCtxType } = diff;
|
|
7
|
+
const { itemPath, isPathInScope } = require('./files.js');
|
|
8
|
+
const { foldDepItems } = require('./deps.js');
|
|
8
9
|
|
|
9
10
|
const GITHUB_API = 'https://api.github.com';
|
|
10
11
|
const API_VERSION = '2022-11-28';
|
|
@@ -70,7 +71,6 @@ const parseGithubPrUrl = (text) => {
|
|
|
70
71
|
|
|
71
72
|
const githubToken = (env) => {
|
|
72
73
|
const from = env ?? process.env;
|
|
73
|
-
if (!isRecord(from)) return '';
|
|
74
74
|
return from.GITHUB_TOKEN || from.GH_TOKEN || '';
|
|
75
75
|
};
|
|
76
76
|
|
|
@@ -134,18 +134,15 @@ const isRetryable = (error) => {
|
|
|
134
134
|
const retry = async (run, options) => {
|
|
135
135
|
const attempts = options.attempts ?? RETRY_ATTEMPTS;
|
|
136
136
|
const delayMs = options.delayMs ?? RETRY_DELAY_MS;
|
|
137
|
-
let
|
|
138
|
-
for (let i = 0; i < attempts; i++) {
|
|
137
|
+
for (let i = 0; ; i++) {
|
|
139
138
|
try {
|
|
140
139
|
return await run();
|
|
141
140
|
} catch (error) {
|
|
142
|
-
lastError = error;
|
|
143
141
|
const isLast = i === attempts - 1;
|
|
144
142
|
if (isLast || !isRetryable(error)) throw error;
|
|
145
143
|
await delay(delayMs * (i + 1));
|
|
146
144
|
}
|
|
147
145
|
}
|
|
148
|
-
throw lastError;
|
|
149
146
|
};
|
|
150
147
|
|
|
151
148
|
const githubHeaders = (token, accept) => {
|
|
@@ -164,7 +161,8 @@ const headerValue = (headers, name) => {
|
|
|
164
161
|
return headers.get(name) || '';
|
|
165
162
|
}
|
|
166
163
|
const wanted = name.toLowerCase();
|
|
167
|
-
for (const
|
|
164
|
+
for (const key of Object.keys(headers)) {
|
|
165
|
+
const value = headers[key];
|
|
168
166
|
if (key.toLowerCase() === wanted) return `${value}`;
|
|
169
167
|
}
|
|
170
168
|
return '';
|
|
@@ -252,19 +250,6 @@ const requestGraphql = async (query, variables, options) => {
|
|
|
252
250
|
|
|
253
251
|
const changePath = (file) => file.newPath || file.oldPath || '';
|
|
254
252
|
|
|
255
|
-
const normalizePathSpec = (spec) =>
|
|
256
|
-
`${spec ?? ''}`.replaceAll('\\', '/').replace(/\/+$/, '');
|
|
257
|
-
|
|
258
|
-
const isPathInScope = (rel, paths) => {
|
|
259
|
-
if (!paths.length) return true;
|
|
260
|
-
for (const spec of paths) {
|
|
261
|
-
const norm = normalizePathSpec(spec);
|
|
262
|
-
if (!norm || norm === '.') return true;
|
|
263
|
-
if (rel === norm || rel.startsWith(`${norm}/`)) return true;
|
|
264
|
-
}
|
|
265
|
-
return false;
|
|
266
|
-
};
|
|
267
|
-
|
|
268
253
|
const filterChangeFiles = (files, paths) => {
|
|
269
254
|
if (!paths.length) return files;
|
|
270
255
|
const kept = [];
|
|
@@ -314,14 +299,23 @@ const readRepoName = (data, pr) => {
|
|
|
314
299
|
return `${pr.owner}/${pr.repo}`;
|
|
315
300
|
};
|
|
316
301
|
|
|
302
|
+
const pushChangeFile = (files, seen, rel) => {
|
|
303
|
+
if (!rel || seen.has(rel)) return;
|
|
304
|
+
seen.add(rel);
|
|
305
|
+
files.push(rel);
|
|
306
|
+
};
|
|
307
|
+
|
|
317
308
|
const changeFiles = (items) => {
|
|
318
309
|
const files = [];
|
|
319
310
|
const seen = new Set();
|
|
320
311
|
for (const item of items) {
|
|
312
|
+
if (item.dep) {
|
|
313
|
+
const depFiles = item.dep.files ?? [];
|
|
314
|
+
for (const rel of depFiles) pushChangeFile(files, seen, rel);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
321
317
|
const rel = itemPath(item);
|
|
322
|
-
|
|
323
|
-
seen.add(rel);
|
|
324
|
-
files.push(rel);
|
|
318
|
+
pushChangeFile(files, seen, rel);
|
|
325
319
|
}
|
|
326
320
|
return files;
|
|
327
321
|
};
|
|
@@ -406,8 +400,12 @@ const locateLineInItem = (item, rel, line, side) => {
|
|
|
406
400
|
const inBlock = entry.blockId === item.blockId;
|
|
407
401
|
return { inBlock };
|
|
408
402
|
}
|
|
409
|
-
if (entry.type
|
|
410
|
-
|
|
403
|
+
if (isCtxType(entry.type) || entry.type === 'del') {
|
|
404
|
+
oldNo += 1;
|
|
405
|
+
}
|
|
406
|
+
if (isCtxType(entry.type) || entry.type === 'add') {
|
|
407
|
+
newNo += 1;
|
|
408
|
+
}
|
|
411
409
|
}
|
|
412
410
|
return null;
|
|
413
411
|
};
|
|
@@ -546,7 +544,6 @@ const loadReviewThreads = async (pr, options) => {
|
|
|
546
544
|
const threadComments = (thread) => {
|
|
547
545
|
if (!isRecord(thread)) return [];
|
|
548
546
|
const comments = thread.comments;
|
|
549
|
-
if (Array.isArray(comments)) return comments;
|
|
550
547
|
if (isRecord(comments) && Array.isArray(comments.nodes)) {
|
|
551
548
|
return comments.nodes;
|
|
552
549
|
}
|
|
@@ -581,20 +578,18 @@ const loadDiscussion = async (pr, options) => {
|
|
|
581
578
|
return { reviewComments, reviews, issueComments, resolvedById };
|
|
582
579
|
};
|
|
583
580
|
|
|
584
|
-
const emptyImported = () => ({ feedback: [], todos: [] });
|
|
585
|
-
|
|
586
581
|
const loadImportedNotes = async (pr, items, paths, options) => {
|
|
587
582
|
try {
|
|
588
583
|
const discussion = await loadDiscussion(pr, options);
|
|
589
584
|
return discussionToNotes(discussion, items, paths);
|
|
590
585
|
} catch {
|
|
591
586
|
// ignore: discussion import is optional
|
|
592
|
-
return
|
|
587
|
+
return { feedback: [], todos: [] };
|
|
593
588
|
}
|
|
594
589
|
};
|
|
595
590
|
|
|
596
591
|
const loadPullRequest = async (pr, options = {}) => {
|
|
597
|
-
const token = options.token ??
|
|
592
|
+
const token = options.token ?? '';
|
|
598
593
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
599
594
|
const paths = options.paths ?? [];
|
|
600
595
|
const retryOpts = options.retry ?? {};
|
|
@@ -611,7 +606,8 @@ const loadPullRequest = async (pr, options = {}) => {
|
|
|
611
606
|
});
|
|
612
607
|
const parsed = parseDiff(diffPage.body);
|
|
613
608
|
const files = filterChangeFiles(parsed, paths);
|
|
614
|
-
const
|
|
609
|
+
const parsedItems = itemsFromFiles(files, 'pr');
|
|
610
|
+
const items = foldDepItems(parsedItems);
|
|
615
611
|
const change = toChange(pr, data, items);
|
|
616
612
|
const sourceLabel = `#${change.number}`;
|
|
617
613
|
const imported = await loadImportedNotes(pr, items, paths, request);
|
|
@@ -619,8 +615,6 @@ const loadPullRequest = async (pr, options = {}) => {
|
|
|
619
615
|
};
|
|
620
616
|
|
|
621
617
|
module.exports = {
|
|
622
|
-
GITHUB_API,
|
|
623
|
-
PR_TODO_FILE,
|
|
624
618
|
parseGithubPrUrl,
|
|
625
619
|
githubToken,
|
|
626
620
|
filterChangeFiles,
|
package/lib/highlight.js
CHANGED
|
@@ -294,7 +294,7 @@ const NEXT_EXPECT = {
|
|
|
294
294
|
};
|
|
295
295
|
|
|
296
296
|
const wordStyle = (words, style) => {
|
|
297
|
-
const table =
|
|
297
|
+
const table = {};
|
|
298
298
|
for (const word of words) table[word] = style;
|
|
299
299
|
return table;
|
|
300
300
|
};
|
|
@@ -424,8 +424,6 @@ const styleProperty = ({ out }) => {
|
|
|
424
424
|
return /\.$/.test(prev) ? 'property' : null;
|
|
425
425
|
};
|
|
426
426
|
|
|
427
|
-
const styleVariable = () => 'variable';
|
|
428
|
-
|
|
429
427
|
const IDENT_RULES = [
|
|
430
428
|
styleExpected,
|
|
431
429
|
styleKeyword,
|
|
@@ -434,7 +432,6 @@ const IDENT_RULES = [
|
|
|
434
432
|
styleCall,
|
|
435
433
|
styleAssign,
|
|
436
434
|
styleProperty,
|
|
437
|
-
styleVariable,
|
|
438
435
|
];
|
|
439
436
|
|
|
440
437
|
const identStyle = (ctx) => {
|
|
@@ -442,7 +439,7 @@ const identStyle = (ctx) => {
|
|
|
442
439
|
const style = rule(ctx);
|
|
443
440
|
if (style) return style;
|
|
444
441
|
}
|
|
445
|
-
return '
|
|
442
|
+
return 'variable';
|
|
446
443
|
};
|
|
447
444
|
|
|
448
445
|
const readString = (source, i) => {
|
|
@@ -519,150 +516,293 @@ const isRegexContext = (out) => {
|
|
|
519
516
|
return afterOperator || afterKeyword;
|
|
520
517
|
};
|
|
521
518
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
emit(
|
|
557
|
-
|
|
558
|
-
continue;
|
|
519
|
+
const highlightTemplate = (source, i, highlightExpr) => {
|
|
520
|
+
const n = source.length;
|
|
521
|
+
let j = i + 1;
|
|
522
|
+
const parts = [];
|
|
523
|
+
emit(parts, 'template', '`');
|
|
524
|
+
let buf = '';
|
|
525
|
+
const flush = () => {
|
|
526
|
+
if (buf) {
|
|
527
|
+
emit(parts, 'template', buf);
|
|
528
|
+
buf = '';
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
while (j < n) {
|
|
532
|
+
if (source[j] === '\\') {
|
|
533
|
+
flush();
|
|
534
|
+
emit(parts, 'escape', source.slice(j, j + 2));
|
|
535
|
+
j += 2;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
if (source[j] === '`') {
|
|
539
|
+
flush();
|
|
540
|
+
emit(parts, 'template', '`');
|
|
541
|
+
j += 1;
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
if (source[j] === '$' && source[j + 1] === '{') {
|
|
545
|
+
flush();
|
|
546
|
+
emit(parts, 'interpolation', '${');
|
|
547
|
+
j += 2;
|
|
548
|
+
const interp = readTemplateInterp(source, j);
|
|
549
|
+
const inner = highlightExpr(interp.expr);
|
|
550
|
+
for (const t of inner) parts.push(t);
|
|
551
|
+
j = interp.end;
|
|
552
|
+
if (source[j] === '}') {
|
|
553
|
+
emit(parts, 'interpolation', '}');
|
|
554
|
+
j += 1;
|
|
559
555
|
}
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
buf += source[j];
|
|
559
|
+
j += 1;
|
|
560
|
+
}
|
|
561
|
+
flush();
|
|
562
|
+
return { tokens: parts, end: j };
|
|
563
|
+
};
|
|
560
564
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
565
|
+
const isJsxTagStart = (source, i) => {
|
|
566
|
+
if (source[i] !== '<') return false;
|
|
567
|
+
if (i > 0 && /[A-Za-z0-9_$]/.test(source[i - 1])) return false;
|
|
568
|
+
const next = source[i + 1];
|
|
569
|
+
if (next === '>' || next === '/') return true;
|
|
570
|
+
if (!/[A-Za-z_$]/.test(next || '')) return false;
|
|
571
|
+
let j = i + 1;
|
|
572
|
+
while (j < source.length && /[A-Za-z0-9_$.:-]/.test(source[j])) j += 1;
|
|
573
|
+
const after = source[skipWs(source, j)];
|
|
574
|
+
if (after === '>' || after === '/' || after === '{') return true;
|
|
575
|
+
return /[A-Za-z_$]/.test(after || '');
|
|
576
|
+
};
|
|
567
577
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
continue;
|
|
573
|
-
}
|
|
578
|
+
const jsxNameStyle = (name) => {
|
|
579
|
+
if (/^[A-Z]/.test(name) || name.includes('.')) return 'className';
|
|
580
|
+
return 'tag';
|
|
581
|
+
};
|
|
574
582
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
expectName = null;
|
|
581
|
-
continue;
|
|
582
|
-
}
|
|
583
|
+
const readJsxName = (source, i) => {
|
|
584
|
+
let j = i;
|
|
585
|
+
while (j < source.length && /[A-Za-z0-9_$.:-]/.test(source[j])) j += 1;
|
|
586
|
+
return { text: source.slice(i, j), end: j };
|
|
587
|
+
};
|
|
583
588
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
589
|
+
const highlightJsxExpr = (source, i, inner) => {
|
|
590
|
+
const out = [];
|
|
591
|
+
emit(out, 'interpolation', '{');
|
|
592
|
+
const interp = readTemplateInterp(source, i + 1);
|
|
593
|
+
const tokens = inner(interp.expr);
|
|
594
|
+
for (const t of tokens) out.push(t);
|
|
595
|
+
let end = interp.end;
|
|
596
|
+
if (source[end] === '}') {
|
|
597
|
+
emit(out, 'interpolation', '}');
|
|
598
|
+
end += 1;
|
|
599
|
+
}
|
|
600
|
+
return { tokens: out, end };
|
|
601
|
+
};
|
|
596
602
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
603
|
+
const highlightJsxTagTail = (source, i, inner, out) => {
|
|
604
|
+
const n = source.length;
|
|
605
|
+
let selfClosing = false;
|
|
606
|
+
while (i < n) {
|
|
607
|
+
const ch = source[i];
|
|
608
|
+
if (ch === '>') {
|
|
609
|
+
emit(out, 'punct', '>');
|
|
610
|
+
i += 1;
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
if (ch === '/' && source[i + 1] === '>') {
|
|
614
|
+
emit(out, 'punct', '/>');
|
|
615
|
+
i += 2;
|
|
616
|
+
selfClosing = true;
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
if (/\s/.test(ch)) {
|
|
609
620
|
emit(out, 'plain', ch);
|
|
610
621
|
i += 1;
|
|
622
|
+
continue;
|
|
611
623
|
}
|
|
612
|
-
|
|
624
|
+
if (ch === '{') {
|
|
625
|
+
const expr = highlightJsxExpr(source, i, inner);
|
|
626
|
+
for (const t of expr.tokens) out.push(t);
|
|
627
|
+
i = expr.end;
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
if (QUOTES.includes(ch)) {
|
|
631
|
+
const { text, end } = readString(source, i);
|
|
632
|
+
emit(out, 'string', text);
|
|
633
|
+
i = end;
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
if (ch === '=') {
|
|
637
|
+
emit(out, 'punct', '=');
|
|
638
|
+
i += 1;
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
if (/[A-Za-z_$]/.test(ch)) {
|
|
642
|
+
const { text, end } = readJsxName(source, i);
|
|
643
|
+
emit(out, 'attr', text);
|
|
644
|
+
i = end;
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
emit(out, 'punct', ch);
|
|
648
|
+
i += 1;
|
|
613
649
|
}
|
|
650
|
+
return { end: i, selfClosing };
|
|
651
|
+
};
|
|
614
652
|
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
653
|
+
const highlightJsxElement = (source, i, inner) => {
|
|
654
|
+
const out = [];
|
|
655
|
+
const n = source.length;
|
|
656
|
+
emit(out, 'punct', '<');
|
|
657
|
+
i += 1;
|
|
658
|
+
let closing = false;
|
|
659
|
+
if (source[i] === '/') {
|
|
660
|
+
emit(out, 'punct', '/');
|
|
661
|
+
i += 1;
|
|
662
|
+
closing = true;
|
|
663
|
+
}
|
|
664
|
+
const nameRead = readJsxName(source, i);
|
|
665
|
+
const name = nameRead.text;
|
|
666
|
+
if (name) {
|
|
667
|
+
emit(out, jsxNameStyle(name), name);
|
|
668
|
+
i = nameRead.end;
|
|
669
|
+
}
|
|
670
|
+
const tail = highlightJsxTagTail(source, i, inner, out);
|
|
671
|
+
i = tail.end;
|
|
672
|
+
if (closing || tail.selfClosing) return { tokens: out, end: i };
|
|
673
|
+
while (i < n) {
|
|
674
|
+
if (source.startsWith('</', i)) {
|
|
675
|
+
const close = highlightJsxElement(source, i, inner);
|
|
676
|
+
for (const t of close.tokens) out.push(t);
|
|
677
|
+
return { tokens: out, end: close.end };
|
|
678
|
+
}
|
|
679
|
+
if (source[i] === '{') {
|
|
680
|
+
const expr = highlightJsxExpr(source, i, inner);
|
|
681
|
+
for (const t of expr.tokens) out.push(t);
|
|
682
|
+
i = expr.end;
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
if (source[i] === '<' && isJsxTagStart(source, i)) {
|
|
686
|
+
const child = highlightJsxElement(source, i, inner);
|
|
687
|
+
for (const t of child.tokens) out.push(t);
|
|
688
|
+
i = child.end;
|
|
689
|
+
continue;
|
|
690
|
+
}
|
|
691
|
+
let j = i;
|
|
692
|
+
while (j < n && source[j] !== '<' && source[j] !== '{') j += 1;
|
|
693
|
+
if (j === i) {
|
|
694
|
+
emit(out, 'plain', source[i]);
|
|
695
|
+
i += 1;
|
|
696
|
+
continue;
|
|
656
697
|
}
|
|
657
|
-
|
|
658
|
-
|
|
698
|
+
emit(out, 'plain', source.slice(i, j));
|
|
699
|
+
i = j;
|
|
659
700
|
}
|
|
660
|
-
}
|
|
701
|
+
return { tokens: out, end: i };
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
const highlightJsFamily = (source, options = {}) => {
|
|
705
|
+
const ts = options.ts === true;
|
|
706
|
+
const jsx = options.jsx === true;
|
|
707
|
+
const inner = (expr) => highlightJsFamily(expr, options);
|
|
708
|
+
const out = [];
|
|
709
|
+
let i = 0;
|
|
710
|
+
const n = source.length;
|
|
711
|
+
let expectName = null;
|
|
712
|
+
|
|
713
|
+
while (i < n) {
|
|
714
|
+
const ch = source[i];
|
|
715
|
+
const next = source[i + 1];
|
|
716
|
+
|
|
717
|
+
if (ch === '/' && next === '/') {
|
|
718
|
+
const { text, end } = readUntilNl(source, i);
|
|
719
|
+
emit(out, 'comment', text);
|
|
720
|
+
i = end;
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (ch === '/' && next === '*') {
|
|
725
|
+
const { text, end } = readBlockComment(source, i);
|
|
726
|
+
emit(out, 'comment', text);
|
|
727
|
+
i = end;
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
if (ch === '`') {
|
|
732
|
+
const r = highlightTemplate(source, i, inner);
|
|
733
|
+
for (const t of r.tokens) out.push(t);
|
|
734
|
+
i = r.end;
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (QUOTES.includes(ch)) {
|
|
739
|
+
const { text, end } = readString(source, i);
|
|
740
|
+
emit(out, 'string', text);
|
|
741
|
+
i = end;
|
|
742
|
+
continue;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (ch === '/' && isRegexContext(out)) {
|
|
746
|
+
const { text, end } = readRegex(source, i);
|
|
747
|
+
emit(out, 'regex', text);
|
|
748
|
+
i = end;
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
if (/[0-9]/.test(ch) || (ch === '.' && /[0-9]/.test(next || ''))) {
|
|
753
|
+
const { text, end } = readJsNumber(source, i);
|
|
754
|
+
emit(out, 'number', text);
|
|
755
|
+
i = end;
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
if (ch === '@') {
|
|
760
|
+
let j = i + 1;
|
|
761
|
+
while (j < n && /[A-Za-z0-9_$]/.test(source[j])) j += 1;
|
|
762
|
+
emit(out, 'decorator', source.slice(i, j));
|
|
763
|
+
i = j;
|
|
764
|
+
expectName = null;
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
661
767
|
|
|
662
|
-
|
|
768
|
+
if (/[A-Za-z_$]/.test(ch)) {
|
|
769
|
+
const word = peekIdent(source, i);
|
|
770
|
+
const end = i + word.length;
|
|
771
|
+
const k = skipWs(source, end);
|
|
772
|
+
const after = source[k];
|
|
773
|
+
const ctx = { word, ts, after, source, k, out, expectName };
|
|
774
|
+
emit(out, identStyle(ctx), word);
|
|
775
|
+
if (EXPECT_STYLE[expectName]) expectName = null;
|
|
776
|
+
else expectName = NEXT_EXPECT[word] ?? null;
|
|
777
|
+
i = end;
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
if (jsx && ch === '<' && isJsxTagStart(source, i)) {
|
|
782
|
+
const node = highlightJsxElement(source, i, inner);
|
|
783
|
+
for (const t of node.tokens) out.push(t);
|
|
784
|
+
i = node.end;
|
|
785
|
+
expectName = null;
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
663
788
|
|
|
664
|
-
|
|
665
|
-
|
|
789
|
+
if (/[=<>!+\-*/%&|^~?:]/.test(ch)) {
|
|
790
|
+
const { text, end } = readJsOperator(source, i);
|
|
791
|
+
emit(out, 'operator', text);
|
|
792
|
+
i = end;
|
|
793
|
+
expectName = null;
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
if (/[{}()[\];,.]/.test(ch)) {
|
|
797
|
+
emit(out, 'punct', ch);
|
|
798
|
+
i += 1;
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
emit(out, 'plain', ch);
|
|
802
|
+
i += 1;
|
|
803
|
+
}
|
|
804
|
+
return out;
|
|
805
|
+
};
|
|
666
806
|
|
|
667
807
|
const highlightJson = (source) => {
|
|
668
808
|
const out = [];
|
|
@@ -1146,21 +1286,23 @@ const highlightTxt = (source) => {
|
|
|
1146
1286
|
return out;
|
|
1147
1287
|
};
|
|
1148
1288
|
|
|
1149
|
-
const highlightJs = (source) => highlightJsFamily(source,
|
|
1150
|
-
const highlightTs = (source) => highlightJsFamily(source, true);
|
|
1289
|
+
const highlightJs = (source) => highlightJsFamily(source, {});
|
|
1290
|
+
const highlightTs = (source) => highlightJsFamily(source, { ts: true });
|
|
1291
|
+
const highlightJsx = (source) => highlightJsFamily(source, { jsx: true });
|
|
1292
|
+
const highlightTsx = (source) =>
|
|
1293
|
+
highlightJsFamily(source, { ts: true, jsx: true });
|
|
1151
1294
|
|
|
1152
1295
|
const HIGHLIGHTERS = {
|
|
1153
1296
|
js: highlightJs,
|
|
1154
1297
|
mjs: highlightJs,
|
|
1155
1298
|
ts: highlightTs,
|
|
1299
|
+
jsx: highlightJsx,
|
|
1300
|
+
tsx: highlightTsx,
|
|
1156
1301
|
json: highlightJson,
|
|
1157
1302
|
css: highlightCss,
|
|
1158
1303
|
html: highlightHtml,
|
|
1159
1304
|
csv: highlightCsv,
|
|
1160
1305
|
bash: highlightBash,
|
|
1161
|
-
sh: highlightBash,
|
|
1162
|
-
shell: highlightBash,
|
|
1163
|
-
zsh: highlightBash,
|
|
1164
1306
|
log: highlightLog,
|
|
1165
1307
|
dot: highlightDot,
|
|
1166
1308
|
txt: highlightTxt,
|
|
@@ -1224,8 +1366,7 @@ const overlayTokens = (tokens, spans) => {
|
|
|
1224
1366
|
};
|
|
1225
1367
|
|
|
1226
1368
|
module.exports = {
|
|
1369
|
+
tokensText,
|
|
1227
1370
|
tokenize,
|
|
1228
1371
|
overlayTokens,
|
|
1229
|
-
tokensText,
|
|
1230
|
-
HIGHLIGHTERS,
|
|
1231
1372
|
};
|