reslop 0.2.5 → 0.2.7

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 (114) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/LICENSE +1 -1
  3. package/README.md +11 -11
  4. package/bin/reslop.js +3 -8
  5. package/lib/ansi.js +72 -19
  6. package/lib/api.js +1 -1
  7. package/lib/capabilities.js +8 -8
  8. package/lib/cli.js +61 -75
  9. package/lib/clipboard.js +39 -47
  10. package/lib/dashboard/git.js +128 -0
  11. package/lib/dashboard/model.js +357 -0
  12. package/lib/dashboard/npm.js +290 -0
  13. package/lib/dashboard/tree.js +278 -0
  14. package/lib/deps-diff.js +197 -402
  15. package/lib/deps.js +113 -240
  16. package/lib/detect.js +8 -18
  17. package/lib/diff/align.js +41 -113
  18. package/lib/diff/diff.js +12 -43
  19. package/lib/diff/display.js +25 -36
  20. package/lib/diff/edit.js +6 -20
  21. package/lib/diff/inline.js +76 -144
  22. package/lib/diff/items.js +33 -47
  23. package/lib/diff/parse.js +28 -56
  24. package/lib/diff/patch.js +12 -33
  25. package/lib/diff/unit.js +79 -178
  26. package/lib/editor.js +52 -69
  27. package/lib/files.js +79 -91
  28. package/lib/find.js +61 -0
  29. package/lib/git-branches.js +254 -416
  30. package/lib/git-deps.js +148 -272
  31. package/lib/git-reword-todo.js +5 -13
  32. package/lib/git-worktree.js +161 -214
  33. package/lib/git.js +21 -49
  34. package/lib/github.js +67 -181
  35. package/lib/gitlab.js +40 -90
  36. package/lib/highlight/bash.js +55 -177
  37. package/lib/highlight/core.js +155 -141
  38. package/lib/highlight/css.js +25 -58
  39. package/lib/highlight/csv.js +19 -37
  40. package/lib/highlight/dart.js +72 -213
  41. package/lib/highlight/dot.js +14 -14
  42. package/lib/highlight/html.js +42 -63
  43. package/lib/highlight/js.js +177 -506
  44. package/lib/highlight/json.js +17 -37
  45. package/lib/highlight/log.js +19 -25
  46. package/lib/highlight/txt.js +7 -10
  47. package/lib/highlight.js +17 -46
  48. package/lib/keys.js +75 -83
  49. package/lib/manifest.js +67 -126
  50. package/lib/npm-commands.js +120 -169
  51. package/lib/remote.js +140 -190
  52. package/lib/render/branches.js +63 -61
  53. package/lib/render/chrome.js +412 -347
  54. package/lib/render/commits.js +160 -361
  55. package/lib/render/dash-activity.js +212 -0
  56. package/lib/render/dash-blocks.js +496 -0
  57. package/lib/render/dash-table.js +295 -0
  58. package/lib/render/dashboard.js +62 -0
  59. package/lib/render/diff.js +123 -258
  60. package/lib/render/files.js +60 -86
  61. package/lib/render/frame.js +82 -117
  62. package/lib/render/notes.js +150 -210
  63. package/lib/render/npm.js +213 -177
  64. package/lib/render/packages.js +93 -0
  65. package/lib/render/present.js +4 -11
  66. package/lib/render/primitives.js +77 -172
  67. package/lib/render/render.js +5 -14
  68. package/lib/render/report.js +43 -0
  69. package/lib/render/repos.js +226 -0
  70. package/lib/render/search.js +25 -0
  71. package/lib/render/tiles.js +355 -0
  72. package/lib/render/unit.js +15 -31
  73. package/lib/report-model.js +110 -33
  74. package/lib/report-parse.js +56 -37
  75. package/lib/report-render.js +102 -59
  76. package/lib/report-run.js +87 -77
  77. package/lib/report-test.js +221 -99
  78. package/lib/report-tools.js +96 -154
  79. package/lib/review-merge.js +33 -41
  80. package/lib/review.js +69 -129
  81. package/lib/runs.js +225 -0
  82. package/lib/select.js +53 -91
  83. package/lib/session/accessors.js +14 -21
  84. package/lib/session/actions.js +189 -65
  85. package/lib/session/branches.js +164 -222
  86. package/lib/session/change-actions.js +49 -119
  87. package/lib/session/commit.js +298 -352
  88. package/lib/session/compose.js +572 -715
  89. package/lib/session/dashboard.js +530 -0
  90. package/lib/session/dispatch.js +197 -171
  91. package/lib/session/files-pane.js +92 -45
  92. package/lib/session/find.js +94 -0
  93. package/lib/session/items.js +6 -17
  94. package/lib/session/lifecycle.js +420 -466
  95. package/lib/session/load.js +1 -14
  96. package/lib/session/navigation.js +4 -2
  97. package/lib/session/npm.js +403 -420
  98. package/lib/session/ops.js +5 -13
  99. package/lib/session/packages.js +143 -0
  100. package/lib/session/pointer.js +30 -14
  101. package/lib/session/progress.js +39 -30
  102. package/lib/session/review.js +1 -3
  103. package/lib/session/tasks.js +277 -236
  104. package/lib/session/templates.js +51 -59
  105. package/lib/session/terminal.js +85 -132
  106. package/lib/session/view.js +59 -80
  107. package/lib/session/watch.js +201 -212
  108. package/lib/session/workspace.js +455 -0
  109. package/lib/session.js +95 -161
  110. package/lib/update.js +44 -111
  111. package/lib/utilities.js +46 -88
  112. package/lib/workspace.js +166 -0
  113. package/lib/wrap.js +29 -55
  114. package/package.json +1 -1
@@ -1,217 +1,95 @@
1
1
  'use strict';
2
2
 
3
3
  const core = require('./core.js');
4
- const { SQUOTE, emit, wordStyle, readUntilNl } = core;
4
+ const { words, emit, wordStyles, scanWhile, lineEnd } = core;
5
5
 
6
- const BASH_QUOTE = `${SQUOTE}\``;
6
+ const SINGLE_QUOTES = `'\``;
7
7
 
8
- const KEYWORDS = [
9
- 'if',
10
- 'then',
11
- 'else',
12
- 'elif',
13
- 'fi',
14
- 'for',
15
- 'while',
16
- 'until',
17
- 'do',
18
- 'done',
19
- 'case',
20
- 'esac',
21
- 'function',
22
- 'select',
23
- 'in',
24
- 'time',
25
- 'coproc',
26
- ];
8
+ const KEYWORDS = words(`
9
+ if then else elif fi for while until do done case esac function select in
10
+ time coproc
11
+ `);
27
12
 
28
- const BUILTINS = [
29
- 'echo',
30
- 'printf',
31
- 'cd',
32
- 'pwd',
33
- 'exit',
34
- 'export',
35
- 'source',
36
- 'alias',
37
- 'unalias',
38
- 'local',
39
- 'declare',
40
- 'typeset',
41
- 'readonly',
42
- 'unset',
43
- 'shift',
44
- 'read',
45
- 'test',
46
- 'true',
47
- 'false',
48
- 'exec',
49
- 'eval',
50
- 'set',
51
- 'trap',
52
- 'wait',
53
- 'kill',
54
- 'type',
55
- 'command',
56
- 'builtin',
57
- 'return',
58
- 'break',
59
- 'continue',
60
- 'pushd',
61
- 'popd',
62
- 'dirs',
63
- 'getopts',
64
- 'mapfile',
65
- 'readarray',
66
- 'let',
67
- 'umask',
68
- 'ulimit',
69
- 'fg',
70
- 'bg',
71
- 'jobs',
72
- 'hash',
73
- 'help',
74
- 'enable',
75
- 'caller',
76
- 'bind',
77
- 'compgen',
78
- 'complete',
79
- ];
13
+ const BUILTINS = words(`
14
+ echo printf cd pwd exit export source alias unalias local declare typeset
15
+ readonly unset shift read test true false exec eval set trap wait kill type
16
+ command builtin return break continue pushd popd dirs getopts mapfile
17
+ readarray let umask ulimit fg bg jobs hash help enable caller bind compgen
18
+ complete
19
+ `);
80
20
 
81
- const WORD_STYLE = {
82
- ...wordStyle(KEYWORDS, 'control'),
83
- ...wordStyle(BUILTINS, 'function'),
84
- };
21
+ const WORD_STYLE = wordStyles({ control: KEYWORDS, function: BUILTINS });
85
22
 
86
- const readBashVar = (source, i) => {
23
+ const varEnd = (source, i) => {
87
24
  if (source[i + 1] === '{') {
88
- let j = i + 2;
89
- while (j < source.length && source[j] !== '}') j += 1;
90
- if (j < source.length) j += 1;
91
- return { text: source.slice(i, j), end: j };
92
- }
93
- if (/[0-9#?$!*@-]/.test(source[i + 1] || '')) {
94
- return { text: source.slice(i, i + 2), end: i + 2 };
25
+ const close = source.indexOf('}', i + 2);
26
+ return close < 0 ? source.length : close + 1;
95
27
  }
96
- let j = i + 1;
97
- while (j < source.length && /[A-Za-z0-9_]/.test(source[j])) j += 1;
98
- if (j === i + 1) return { text: '$', end: i + 1 };
99
- return { text: source.slice(i, j), end: j };
28
+ if (/[0-9#?$!*@-]/.test(source[i + 1] || '')) return i + 2;
29
+ return scanWhile(source, i + 1, /[A-Za-z0-9_]/);
100
30
  };
101
31
 
102
- const takeQuoted = (source, i) => {
103
- const q = source[i];
104
- let j = i + 1;
32
+ const pushDoubleQuoted = (out, source, i) => {
105
33
  const n = source.length;
106
- while (j < n && source[j] !== q) j += 1;
107
- if (j < n) j += 1;
108
- return { text: source.slice(i, j), end: j };
109
- };
110
-
111
- const takeBashDouble = (source, i, out) => {
112
- let j = i + 1;
113
34
  let chunk = '"';
114
- const n = source.length;
35
+ let j = i + 1;
115
36
  while (j < n && source[j] !== '"') {
116
37
  if (source[j] === '\\' && j + 1 < n) {
117
38
  chunk += source.slice(j, j + 2);
118
39
  j += 2;
119
- continue;
120
- }
121
- if (source[j] === '$') {
40
+ } else if (source[j] === '$') {
122
41
  emit(out, 'string', chunk);
123
42
  chunk = '';
124
- const { text, end } = readBashVar(source, j);
125
- emit(out, 'variable', text);
43
+ const end = varEnd(source, j);
44
+ emit(out, 'variable', source.slice(j, end));
126
45
  j = end;
127
- continue;
46
+ } else {
47
+ chunk += source[j];
48
+ j += 1;
128
49
  }
129
- chunk += source[j];
130
- j += 1;
131
50
  }
132
51
  if (j < n) {
133
52
  chunk += '"';
134
53
  j += 1;
135
54
  }
136
- if (chunk) emit(out, 'string', chunk);
55
+ emit(out, 'string', chunk);
137
56
  return j;
138
57
  };
139
58
 
140
- const bashWordStyle = (word, nextCh) => {
141
- const known = WORD_STYLE[word];
142
- if (known) return known;
143
- if (nextCh === '=') return 'variable';
144
- return 'plain';
145
- };
146
-
147
59
  const highlight = (source) => {
148
60
  const out = [];
149
61
  let i = 0;
150
- const n = source.length;
151
- while (i < n) {
62
+ const take = (style, end) => {
63
+ emit(out, style, source.slice(i, end));
64
+ i = end;
65
+ };
66
+ while (i < source.length) {
152
67
  const ch = source[i];
153
68
  const next = source[i + 1];
154
-
155
69
  if (ch === '#' && (i === 0 || /\s/.test(source[i - 1]))) {
156
- const { text, end } = readUntilNl(source, i);
157
- emit(out, 'comment', text);
158
- i = end;
159
- continue;
70
+ take('comment', lineEnd(source, i));
71
+ } else if (SINGLE_QUOTES.includes(ch)) {
72
+ const close = source.indexOf(ch, i + 1);
73
+ take('string', close < 0 ? source.length : close + 1);
74
+ } else if (ch === '"') {
75
+ i = pushDoubleQuoted(out, source, i);
76
+ } else if (ch === '$') {
77
+ take('variable', varEnd(source, i));
78
+ } else if (ch === '-' && /[A-Za-z0-9]/.test(next || '')) {
79
+ take('attr', scanWhile(source, i + 1, /[A-Za-z0-9_-]/));
80
+ } else if (/[A-Za-z_]/.test(ch)) {
81
+ const end = scanWhile(source, i + 1, /[A-Za-z0-9_]/);
82
+ const word = source.slice(i, end);
83
+ const assign = source[end] === '=' ? 'variable' : 'plain';
84
+ take(WORD_STYLE[word] || assign, end);
85
+ } else if (/[0-9]/.test(ch)) {
86
+ take('number', scanWhile(source, i + 1, /[0-9]/));
87
+ } else if ('|&;<>(){}'.includes(ch)) {
88
+ const doubled = '|&><'.includes(ch) && next === ch;
89
+ take('operator', i + (doubled ? 2 : 1));
90
+ } else {
91
+ take('plain', i + 1);
160
92
  }
161
-
162
- if (BASH_QUOTE.includes(ch)) {
163
- const { text, end } = takeQuoted(source, i);
164
- emit(out, 'string', text);
165
- i = end;
166
- continue;
167
- }
168
-
169
- if (ch === '"') {
170
- i = takeBashDouble(source, i, out);
171
- continue;
172
- }
173
-
174
- if (ch === '$') {
175
- const { text, end } = readBashVar(source, i);
176
- emit(out, 'variable', text);
177
- i = end;
178
- continue;
179
- }
180
-
181
- if (ch === '-' && /[A-Za-z0-9]/.test(next || '')) {
182
- let j = i + 1;
183
- while (j < n && /[A-Za-z0-9_-]/.test(source[j])) j += 1;
184
- emit(out, 'attr', source.slice(i, j));
185
- i = j;
186
- continue;
187
- }
188
-
189
- if (/[A-Za-z_]/.test(ch)) {
190
- let j = i + 1;
191
- while (j < n && /[A-Za-z0-9_]/.test(source[j])) j += 1;
192
- const word = source.slice(i, j);
193
- emit(out, bashWordStyle(word, source[j]), word);
194
- i = j;
195
- continue;
196
- }
197
-
198
- if (/[0-9]/.test(ch)) {
199
- let j = i + 1;
200
- while (j < n && /[0-9]/.test(source[j])) j += 1;
201
- emit(out, 'number', source.slice(i, j));
202
- i = j;
203
- continue;
204
- }
205
-
206
- if ('|&;<>(){}'.includes(ch)) {
207
- const j = i + ('|&><'.includes(ch) && next === ch ? 2 : 1);
208
- emit(out, 'operator', source.slice(i, j));
209
- i = j;
210
- continue;
211
- }
212
-
213
- emit(out, 'plain', ch);
214
- i += 1;
215
93
  }
216
94
  return out;
217
95
  };
@@ -1,34 +1,17 @@
1
1
  'use strict';
2
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
- ];
3
+ const QUOTES = `'"`;
4
+ const ANY_QUOTE = `'"\``;
5
+ const IDENT_START = /[A-Za-z_$]/;
6
+ const IDENT_CHAR = /[A-Za-z0-9_$]/;
7
+ const CONSTANT_RE = /^[A-Z][A-Z0-9_]+$/;
8
+
9
+ const words = (text) => text.trim().split(/\s+/);
10
+
11
+ const OP3 = words('=== !== >>> **= &&= ||= ??=');
12
+ const OP2 = words(
13
+ '== != <= >= && || ?? => ++ -- << >> ** += -= *= /= %= &= |= ^=',
14
+ );
32
15
 
33
16
  const EXPECT_STYLE = {
34
17
  function: 'function',
@@ -36,170 +19,201 @@ const EXPECT_STYLE = {
36
19
  type: 'className',
37
20
  };
38
21
 
22
+ const RADIX_DIGIT = { x: /[0-9a-fA-F_]/, b: /[01_]/, o: /[0-7_]/ };
23
+
39
24
  const emit = (out, style, text) => {
40
- if (!text) return;
41
- out.push({ text, style: style || 'plain' });
25
+ if (text) out.push({ text, style });
42
26
  };
43
27
 
44
- const highlightLines = (highlightLine) => (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 highlightLine(lines[i])) out.push(t);
50
- }
51
- return out;
52
- };
28
+ const highlightLines =
29
+ (highlightLine, separator = '\n') =>
30
+ (source) => {
31
+ const lines = source.split(separator);
32
+ const out = [];
33
+ for (let i = 0; i < lines.length; i += 1) {
34
+ if (i) emit(out, 'plain', '\n');
35
+ for (const token of highlightLine(lines[i])) out.push(token);
36
+ }
37
+ return out;
38
+ };
53
39
 
54
40
  const tokensText = (out) => {
55
- let s = '';
56
- for (const t of out) s += t.text;
57
- return s;
41
+ let text = '';
42
+ for (const token of out) text += token.text;
43
+ return text;
58
44
  };
59
45
 
60
- const wordStyle = (words, style) => {
46
+ const wordStyles = (groups) => {
61
47
  const table = Object.create(null);
62
- for (const word of words) table[word] = style;
48
+ for (const style of Object.keys(groups)) {
49
+ for (const word of groups[style]) table[word] = style;
50
+ }
63
51
  return table;
64
52
  };
65
53
 
66
- const peekIdent = (source, i) => {
67
- if (!/[A-Za-z_$]/.test(source[i] || '')) return null;
68
- let j = i + 1;
69
- while (j < source.length && /[A-Za-z0-9_$]/.test(source[j])) j += 1;
70
- return source.slice(i, j);
54
+ const appendNode = (out, node) => {
55
+ for (const token of node.tokens) out.push(token);
56
+ return node.end;
71
57
  };
72
58
 
73
- const skipWs = (source, i) => {
74
- while (i < source.length && /\s/.test(source[i])) i += 1;
59
+ const scanWhile = (source, start, re) => {
60
+ let i = start;
61
+ while (i < source.length && re.test(source[i])) i += 1;
75
62
  return i;
76
63
  };
77
64
 
78
- const readUntilNl = (source, i) => {
79
- let j = i;
80
- const n = source.length;
81
- while (j < n && source[j] !== '\n') j += 1;
82
- return { text: source.slice(i, j), end: j };
65
+ const lineEnd = (source, i) => {
66
+ const end = source.indexOf('\n', i);
67
+ return end < 0 ? source.length : end;
83
68
  };
84
69
 
85
- const readBlockComment = (source, i) => {
86
- let j = i + 2;
87
- const n = source.length;
88
- while (j < n && !(source[j] === '*' && source[j + 1] === '/')) {
89
- j += 1;
90
- }
91
- j = Math.min(j + 2, n);
92
- return { text: source.slice(i, j), end: j };
70
+ const blockCommentEnd = (source, i) => {
71
+ const end = source.indexOf('*/', i + 2);
72
+ return end < 0 ? source.length : end + 2;
93
73
  };
94
74
 
95
- const skipQuoted = (source, j) => {
96
- const q = source[j];
97
- j += 1;
98
- const n = source.length;
99
- while (j < n && source[j] !== q) {
75
+ const quotedEnd = (source, start) => {
76
+ const quote = source[start];
77
+ let j = start + 1;
78
+ while (j < source.length && source[j] !== quote) {
100
79
  if (source[j] === '\\') j += 1;
101
80
  j += 1;
102
81
  }
103
- j += 1;
104
- return j;
82
+ return j + 1;
105
83
  };
106
84
 
107
- const readJsNumber = (source, i) => {
108
- const n = source.length;
109
- let j = i;
110
- if (source.startsWith('0x', i) || source.startsWith('0X', i)) {
111
- j += 2;
112
- while (j < n && /[0-9a-fA-F_]/.test(source[j])) j += 1;
113
- } else if (source.startsWith('0b', i) || source.startsWith('0B', i)) {
114
- j += 2;
115
- while (j < n && /[01_]/.test(source[j])) j += 1;
116
- } else if (source.startsWith('0o', i) || source.startsWith('0O', i)) {
117
- j += 2;
118
- while (j < n && /[0-7_]/.test(source[j])) j += 1;
119
- } else {
120
- while (j < n && /[0-9_n.]/.test(source[j])) j += 1;
121
- if ('eE'.includes(source[j])) {
122
- j += 1;
123
- if ('+-'.includes(source[j])) j += 1;
124
- while (j < n && /[0-9_]/.test(source[j])) j += 1;
125
- }
126
- }
127
- return { text: source.slice(i, j), end: j };
128
- };
129
-
130
- const readJsOperator = (source, i) => {
131
- const two = source.slice(i, i + 2);
132
- const three = source.slice(i, i + 3);
133
- let j = i + 1;
134
- if (OP3.includes(three)) j = i + 3;
135
- else if (OP2.includes(two)) j = i + 2;
136
- return { text: source.slice(i, j), end: j };
137
- };
138
-
139
- const readString = (source, i) => {
140
- const q = source[i];
85
+ const stringEnd = (source, i) => {
86
+ const quote = source[i];
141
87
  let j = i + 1;
142
- const n = source.length;
143
- while (j < n) {
88
+ while (j < source.length) {
144
89
  if (source[j] === '\\') {
145
90
  j += 2;
146
91
  continue;
147
92
  }
148
- if (source[j] === q) {
149
- j += 1;
150
- break;
151
- }
93
+ if (source[j] === quote) return j + 1;
152
94
  if (source[j] === '\n') break;
153
95
  j += 1;
154
96
  }
155
- return { text: source.slice(i, j), end: j };
97
+ return j;
98
+ };
99
+
100
+ const numberEnd = (source, i) => {
101
+ const prefix = source[i] === '0' ? source[i + 1] : undefined;
102
+ const radix = prefix ? RADIX_DIGIT[prefix.toLowerCase()] : undefined;
103
+ if (radix) return scanWhile(source, i + 2, radix);
104
+ let j = scanWhile(source, i, /[0-9_n.]/);
105
+ if (source[j] !== 'e' && source[j] !== 'E') return j;
106
+ j += 1;
107
+ if (source[j] === '+' || source[j] === '-') j += 1;
108
+ return scanWhile(source, j, /[0-9_]/);
109
+ };
110
+
111
+ const operatorEnd = (source, i) => {
112
+ if (OP3.includes(source.slice(i, i + 3))) return i + 3;
113
+ if (OP2.includes(source.slice(i, i + 2))) return i + 2;
114
+ return i + 1;
156
115
  };
157
116
 
158
- const readTemplateInterp = (source, j) => {
117
+ const interpEnd = (source, start) => {
159
118
  let depth = 1;
160
- const start = j;
161
- const n = source.length;
162
- while (j < n && depth > 0) {
163
- if (ANY_QUOTE.includes(source[j])) {
164
- j = skipQuoted(source, j);
119
+ let j = start;
120
+ while (j < source.length) {
121
+ const ch = source[j];
122
+ if (ANY_QUOTE.includes(ch)) {
123
+ j = quotedEnd(source, j);
165
124
  continue;
166
125
  }
167
- if (source[j] === '{') depth += 1;
168
- if (source[j] === '}') {
126
+ if (ch === '{') depth += 1;
127
+ if (ch === '}') {
169
128
  depth -= 1;
170
129
  if (depth === 0) break;
171
130
  }
172
131
  j += 1;
173
132
  }
174
- return { expr: source.slice(start, j), end: j };
133
+ return j;
175
134
  };
176
135
 
177
- const styleConstant = ({ word }) =>
178
- /^[A-Z][A-Z0-9_]+$/.test(word) ? 'constant' : null;
136
+ const pushInterpolation = (out, source, start, inner) => {
137
+ const end = interpEnd(source, start);
138
+ for (const token of inner(source.slice(start, end))) out.push(token);
139
+ if (source[end] !== '}') return end;
140
+ emit(out, 'interpolation', '}');
141
+ return end + 1;
142
+ };
179
143
 
180
- const stylePascal = ({ word }) => (/^[A-Z]/.test(word) ? 'className' : null);
144
+ const highlightInterpolated = (source, start, body, kind, inner) => {
145
+ const { style, quote, raw } = kind;
146
+ const n = source.length;
147
+ const out = [];
148
+ emit(out, style, source.slice(start, body));
149
+ let j = body;
150
+ let buf = '';
151
+ const flush = () => {
152
+ emit(out, style, buf);
153
+ buf = '';
154
+ };
155
+ while (j < n) {
156
+ const ch = source[j];
157
+ if (!raw && ch === '\\') {
158
+ flush();
159
+ emit(out, 'escape', source.slice(j, j + 2));
160
+ j += 2;
161
+ continue;
162
+ }
163
+ if (source.startsWith(quote, j)) {
164
+ flush();
165
+ emit(out, style, quote);
166
+ j += quote.length;
167
+ break;
168
+ }
169
+ if (!raw && ch === '$' && source[j + 1] === '{') {
170
+ flush();
171
+ emit(out, 'interpolation', '${');
172
+ j = pushInterpolation(out, source, j + 2, inner);
173
+ continue;
174
+ }
175
+ const isDollar = !raw && ch === '$' && kind.dollarIdent;
176
+ if (isDollar && IDENT_START.test(source[j + 1] || '')) {
177
+ flush();
178
+ const end = scanWhile(source, j + 1, IDENT_CHAR);
179
+ emit(out, 'interpolation', source.slice(j, end));
180
+ j = end;
181
+ continue;
182
+ }
183
+ if (!kind.multiline && ch === '\n') break;
184
+ buf += ch;
185
+ j += 1;
186
+ }
187
+ flush();
188
+ return { tokens: out, end: j };
189
+ };
181
190
 
182
- const styleCall = ({ after }) => (after === '(' ? 'function' : null);
191
+ const nameStyle = (word, after) => {
192
+ if (CONSTANT_RE.test(word)) return 'constant';
193
+ if (/^[A-Z]/.test(word)) return 'className';
194
+ if (after === '(') return 'function';
195
+ return null;
196
+ };
183
197
 
184
198
  module.exports = {
185
- SQUOTE,
186
199
  QUOTES,
187
- ANY_QUOTE,
200
+ IDENT_START,
201
+ IDENT_CHAR,
188
202
  EXPECT_STYLE,
203
+ words,
189
204
  emit,
190
205
  highlightLines,
191
206
  tokensText,
192
- wordStyle,
193
- peekIdent,
194
- skipWs,
195
- readUntilNl,
196
- readBlockComment,
197
- skipQuoted,
198
- readJsNumber,
199
- readJsOperator,
200
- readString,
201
- readTemplateInterp,
202
- styleConstant,
203
- stylePascal,
204
- styleCall,
207
+ wordStyles,
208
+ appendNode,
209
+ scanWhile,
210
+ lineEnd,
211
+ blockCommentEnd,
212
+ quotedEnd,
213
+ stringEnd,
214
+ numberEnd,
215
+ operatorEnd,
216
+ pushInterpolation,
217
+ highlightInterpolated,
218
+ nameStyle,
205
219
  };