@adecore/editor-react 0.31.12 → 0.33.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 (137) hide show
  1. package/dist/AnchoredPopup.js +73 -19
  2. package/dist/AttributionCard.js +162 -4
  3. package/dist/BaselineStatus.js +62 -8
  4. package/dist/CallHierarchyPanel.js +977 -60
  5. package/dist/ChangeReview.js +76 -25
  6. package/dist/CodeAuthorsCard.js +314 -14
  7. package/dist/CompletionPopup.js +490 -83
  8. package/dist/DiffView.js +548 -181
  9. package/dist/EditorContextMenu.js +352 -34
  10. package/dist/EditorView.js +276 -99
  11. package/dist/FindReplace.js +525 -67
  12. package/dist/HoverCard.js +378 -38
  13. package/dist/HoverSections.js +367 -56
  14. package/dist/LanguagePopups.js +95 -34
  15. package/dist/Markdown.js +41 -6
  16. package/dist/PanelResizeHandle.js +199 -66
  17. package/dist/PathText.js +49 -7
  18. package/dist/PeekPanel.js +675 -72
  19. package/dist/PickPopup.js +304 -34
  20. package/dist/RenameCard.js +679 -85
  21. package/dist/RenderedDocs.js +329 -58
  22. package/dist/SignatureCard.js +91 -7
  23. package/dist/SplitDiffView.js +344 -254
  24. package/dist/SymbolPicker.js +440 -85
  25. package/dist/call-hierarchy-model.js +102 -68
  26. package/dist/call-hierarchy.js +458 -359
  27. package/dist/code-actions-model.js +88 -76
  28. package/dist/code-actions.js +372 -283
  29. package/dist/code-authors.js +64 -55
  30. package/dist/code-vision-model.js +134 -127
  31. package/dist/code-vision.js +224 -206
  32. package/dist/completion-call.js +94 -67
  33. package/dist/completion-model.js +334 -244
  34. package/dist/completion.js +840 -649
  35. package/dist/conflict-model.js +35 -29
  36. package/dist/context-menu-rows.js +42 -17
  37. package/dist/context-menu.js +64 -46
  38. package/dist/definition-link.js +88 -85
  39. package/dist/diagnostics-model.js +74 -55
  40. package/dist/diagnostics.js +121 -100
  41. package/dist/diff-expansion.js +38 -35
  42. package/dist/diff-overlays.js +144 -22
  43. package/dist/diff-syntax.js +65 -42
  44. package/dist/diff-wordmarks.js +26 -23
  45. package/dist/doc-comment-model.js +265 -216
  46. package/dist/editor-language.js +177 -152
  47. package/dist/error-message.js +2 -2
  48. package/dist/find-query.js +49 -36
  49. package/dist/folding.js +81 -62
  50. package/dist/format-on-type.js +86 -67
  51. package/dist/highlight-layers.js +19 -20
  52. package/dist/highlights.js +105 -83
  53. package/dist/history.js +44 -38
  54. package/dist/holder.js +18 -18
  55. package/dist/host-types.js +1 -1
  56. package/dist/hover-content.js +167 -129
  57. package/dist/hover.js +285 -245
  58. package/dist/index.js +10 -10
  59. package/dist/inlay-hints.js +369 -324
  60. package/dist/key-priority.js +34 -31
  61. package/dist/language-ids.js +45 -42
  62. package/dist/line-edits.js +74 -28
  63. package/dist/line-text.js +18 -3
  64. package/dist/locales/en.json +38 -38
  65. package/dist/locales/nl.json +41 -41
  66. package/dist/models.js +1 -1
  67. package/dist/navigation-history.js +40 -41
  68. package/dist/navigation.js +141 -123
  69. package/dist/panel-size.js +8 -8
  70. package/dist/patch-decorations.js +236 -160
  71. package/dist/patch-layout.js +331 -262
  72. package/dist/paths.js +3 -3
  73. package/dist/peek-model.js +86 -69
  74. package/dist/peek.js +254 -192
  75. package/dist/pick.js +164 -157
  76. package/dist/popup-focus.js +5 -5
  77. package/dist/popup-placement.js +36 -21
  78. package/dist/popups.js +13 -13
  79. package/dist/project-language.js +228 -211
  80. package/dist/project-problems.js +81 -69
  81. package/dist/proposal-model.js +163 -126
  82. package/dist/recent-choices.js +25 -25
  83. package/dist/refresher.js +44 -49
  84. package/dist/rename-model.js +113 -113
  85. package/dist/rename.js +321 -233
  86. package/dist/rendered-docs.d.ts +4 -2
  87. package/dist/rendered-docs.js +384 -318
  88. package/dist/rendering-context.js +5 -3
  89. package/dist/rendering.js +22 -4
  90. package/dist/review-group.js +42 -39
  91. package/dist/row-host.d.ts +4 -2
  92. package/dist/row-host.js +90 -78
  93. package/dist/selection-ranges.js +21 -17
  94. package/dist/semantic-delta.js +22 -19
  95. package/dist/semantic-model.js +86 -73
  96. package/dist/semantic-tokens.js +201 -162
  97. package/dist/shortcut-keys.js +16 -10
  98. package/dist/signature-model.js +34 -28
  99. package/dist/signature.js +177 -129
  100. package/dist/snippet-field-transforms.js +118 -106
  101. package/dist/snippet-indent.js +48 -43
  102. package/dist/snippet-range-order.js +11 -11
  103. package/dist/snippet-session.js +703 -667
  104. package/dist/snippet-transform-client.js +59 -59
  105. package/dist/snippet-transform-format.js +285 -263
  106. package/dist/snippet-transform-protocol.js +1 -1
  107. package/dist/snippet-transform-queue.js +163 -153
  108. package/dist/snippet-transform-worker.js +42 -35
  109. package/dist/snippet-variable-names.js +1 -36
  110. package/dist/snippet-variables.js +53 -63
  111. package/dist/snippet.js +477 -405
  112. package/dist/split-alignment.js +47 -35
  113. package/dist/split-scroll.js +42 -40
  114. package/dist/symbol-links.js +33 -25
  115. package/dist/symbol-picker-model.js +126 -116
  116. package/dist/symbol-picker.js +98 -59
  117. package/dist/symbols.js +117 -88
  118. package/dist/testing.js +248 -165
  119. package/dist/timers.js +35 -30
  120. package/dist/use-panel-body.js +49 -8
  121. package/dist/use-problem-counts.js +29 -15
  122. package/dist/view-state.js +54 -33
  123. package/dist/word-diff.js +18 -18
  124. package/dist/workspace-edit.js +300 -249
  125. package/package.json +6 -6
  126. package/src/CallHierarchyPanel.tsx +2 -2
  127. package/src/DiffView.tsx +3 -3
  128. package/src/FindReplace.tsx +2 -2
  129. package/src/LanguagePopups.tsx +2 -0
  130. package/src/PeekPanel.tsx +3 -3
  131. package/src/RenderedDocs.tsx +9 -10
  132. package/src/SymbolPicker.tsx +2 -2
  133. package/src/diff-overlays.tsx +6 -4
  134. package/src/locales/en.json +38 -38
  135. package/src/locales/nl.json +41 -41
  136. package/src/rendered-docs.ts +14 -3
  137. package/src/row-host.ts +14 -3
@@ -1,302 +1,324 @@
1
1
  import { MAX_TRANSFORM_FORMAT, MAX_TRANSFORM_NODES, MAX_TRANSFORM_PATTERN, MAX_TRANSFORM_JOBS, MAX_TRANSFORM_VALUE, MAX_TRANSFORM_CHARACTERS, MAX_TRANSFORM_MATCHES, MAX_TRANSFORM_WORK } from './snippet-transform-protocol.js';
2
2
  const CASES = new Set(['upcase', 'downcase', 'capitalize', 'camelcase', 'pascalcase']);
3
3
  function readFormat(source, start, stopAtSlash) {
4
- const nodes = [];
5
- let at = start, text = '';
6
- const bound = () => {
7
- if (at - start > MAX_TRANSFORM_FORMAT) {
8
- throw new RangeError('The transform format is too long.');
9
- }
10
- };
11
- const push = (node) => {
12
- if (nodes.length >= MAX_TRANSFORM_NODES) {
13
- throw new RangeError('The transform format has too many nodes.');
14
- }
15
- nodes.push(node);
16
- };
17
- const flush = () => {
18
- if (text !== '') {
19
- push({ kind: 'text', text });
20
- text = '';
21
- }
22
- };
23
- const string = (colon = false) => {
24
- let value = '';
25
- while (at < source.length && source[at] !== '}' && !(colon && source[at] === ':')) {
26
- if (source[at] === '\\') {
27
- if (!['$', '}', '\\'].includes(source[at + 1] ?? '')) {
28
- throw new SyntaxError('Invalid conditional transform escape.');
29
- }
30
- at++;
31
- }
32
- value += source[at++];
33
- bound();
4
+ const nodes = [];
5
+ let at = start,
6
+ text = '';
7
+ const bound = () => {
8
+ if (at - start > MAX_TRANSFORM_FORMAT) {
9
+ throw new RangeError('The transform format is too long.');
10
+ }
11
+ };
12
+ const push = node => {
13
+ if (nodes.length >= MAX_TRANSFORM_NODES) {
14
+ throw new RangeError('The transform format has too many nodes.');
15
+ }
16
+ nodes.push(node);
17
+ };
18
+ const flush = () => {
19
+ if (text !== '') {
20
+ push({
21
+ kind: 'text',
22
+ text
23
+ });
24
+ text = '';
25
+ }
26
+ };
27
+ const string = (colon = false) => {
28
+ let value = '';
29
+ while (at < source.length && source[at] !== '}' && !(colon && source[at] === ':')) {
30
+ if (source[at] === '\\') {
31
+ if (!['$', '}', '\\'].includes(source[at + 1] ?? '')) {
32
+ throw new SyntaxError('Invalid conditional transform escape.');
34
33
  }
35
- return value;
34
+ at++;
35
+ }
36
+ value += source[at++];
37
+ bound();
38
+ }
39
+ return value;
40
+ };
41
+ while (at < source.length && !(stopAtSlash && source[at] === '/')) {
42
+ bound();
43
+ if (source[at] === '\\' && (source[at + 1] === '\\' || source[at + 1] === '/')) {
44
+ at++;
45
+ text += source[at++];
46
+ continue;
47
+ }
48
+ if (source[at] !== '$') {
49
+ text += source[at++];
50
+ continue;
51
+ }
52
+ at++;
53
+ const brace = source[at] === '{';
54
+ if (brace) {
55
+ at++;
56
+ }
57
+ const start = at;
58
+ while (at < source.length && source.charCodeAt(at) >= 48 && source.charCodeAt(at) <= 57) {
59
+ at++;
60
+ }
61
+ if (at === start) {
62
+ if (brace) {
63
+ throw new SyntaxError('A transform format needs a capture index.');
64
+ }
65
+ text += '$';
66
+ continue;
67
+ }
68
+ const index = Number(source.slice(start, at));
69
+ if (index > 99) {
70
+ throw new RangeError('Transform captures are limited to 99.');
71
+ }
72
+ flush();
73
+ let node = {
74
+ kind: 'capture',
75
+ index
36
76
  };
37
- while (at < source.length && !(stopAtSlash && source[at] === '/')) {
38
- bound();
39
- if (source[at] === '\\' && (source[at + 1] === '\\' || source[at + 1] === '/')) {
40
- at++;
41
- text += source[at++];
42
- continue;
43
- }
44
- if (source[at] !== '$') {
45
- text += source[at++];
46
- continue;
47
- }
77
+ if (brace) {
78
+ if (source[at] === ':') {
48
79
  at++;
49
- const brace = source[at] === '{';
50
- if (brace) {
80
+ const operator = source[at];
81
+ if (operator === '/') {
82
+ at++;
83
+ const operation = string();
84
+ if (!CASES.has(operation)) {
85
+ throw new SyntaxError('Unknown transform case operation.');
86
+ }
87
+ node = {
88
+ kind: 'capture',
89
+ index,
90
+ case: operation
91
+ };
92
+ } else if (operator === '+') {
93
+ at++;
94
+ node = {
95
+ kind: 'conditional',
96
+ index,
97
+ if: string()
98
+ };
99
+ } else if (operator === '?') {
100
+ at++;
101
+ const when = string(true);
102
+ if (source[at++] !== ':') {
103
+ throw new SyntaxError('A conditional transform needs both branches.');
104
+ }
105
+ node = {
106
+ kind: 'conditional',
107
+ index,
108
+ if: when,
109
+ else: string()
110
+ };
111
+ } else {
112
+ if (operator === '-') {
51
113
  at++;
114
+ }
115
+ node = {
116
+ kind: 'conditional',
117
+ index,
118
+ else: string()
119
+ };
52
120
  }
53
- const start = at;
54
- while (at < source.length && source.charCodeAt(at) >= 48 && source.charCodeAt(at) <= 57) {
55
- at++;
56
- }
57
- if (at === start) {
58
- if (brace) {
59
- throw new SyntaxError('A transform format needs a capture index.');
60
- }
61
- text += '$';
62
- continue;
63
- }
64
- const index = Number(source.slice(start, at));
65
- if (index > 99) {
66
- throw new RangeError('Transform captures are limited to 99.');
67
- }
68
- flush();
69
- let node = { kind: 'capture', index };
70
- if (brace) {
71
- if (source[at] === ':') {
72
- at++;
73
- const operator = source[at];
74
- if (operator === '/') {
75
- at++;
76
- const operation = string();
77
- if (!CASES.has(operation)) {
78
- throw new SyntaxError('Unknown transform case operation.');
79
- }
80
- node = { kind: 'capture', index, case: operation };
81
- }
82
- else if (operator === '+') {
83
- at++;
84
- node = { kind: 'conditional', index, if: string() };
85
- }
86
- else if (operator === '?') {
87
- at++;
88
- const when = string(true);
89
- if (source[at++] !== ':') {
90
- throw new SyntaxError('A conditional transform needs both branches.');
91
- }
92
- node = { kind: 'conditional', index, if: when, else: string() };
93
- }
94
- else {
95
- if (operator === '-') {
96
- at++;
97
- }
98
- node = { kind: 'conditional', index, else: string() };
99
- }
100
- }
101
- if (source[at++] !== '}') {
102
- throw new SyntaxError('An unclosed transform capture cannot be applied.');
103
- }
104
- }
105
- push(node);
106
- }
107
- flush();
108
- bound();
109
- if (stopAtSlash && source[at] !== '/') {
110
- throw new SyntaxError('Unclosed snippet transform format.');
121
+ }
122
+ if (source[at++] !== '}') {
123
+ throw new SyntaxError('An unclosed transform capture cannot be applied.');
124
+ }
111
125
  }
112
- return { nodes, end: at };
126
+ push(node);
127
+ }
128
+ flush();
129
+ bound();
130
+ if (stopAtSlash && source[at] !== '/') {
131
+ throw new SyntaxError('Unclosed snippet transform format.');
132
+ }
133
+ return {
134
+ nodes,
135
+ end: at
136
+ };
113
137
  }
114
138
  export function compileSnippetTransformFormat(source) {
115
- return readFormat(source, 0, false).nodes;
139
+ return readFormat(source, 0, false).nodes;
116
140
  }
117
141
  export function scanSnippetTransform(source, at) {
118
- if (source[at++] !== '/') {
119
- throw new SyntaxError('A snippet transform needs an opening slash.');
142
+ if (source[at++] !== '/') {
143
+ throw new SyntaxError('A snippet transform needs an opening slash.');
144
+ }
145
+ let pattern = '';
146
+ while (at < source.length && source[at] !== '/') {
147
+ const character = source[at++];
148
+ if (character === '\\' && source[at] === '/') {
149
+ pattern += source[at++];
150
+ } else {
151
+ pattern += character;
120
152
  }
121
- let pattern = '';
122
- while (at < source.length && source[at] !== '/') {
123
- const character = source[at++];
124
- if (character === '\\' && source[at] === '/') {
125
- pattern += source[at++];
126
- }
127
- else {
128
- pattern += character;
129
- }
130
- if (pattern.length > MAX_TRANSFORM_PATTERN) {
131
- throw new RangeError('The snippet transform pattern is too long.');
132
- }
133
- }
134
- if (source[at++] !== '/') {
135
- throw new SyntaxError('Unclosed snippet transform pattern.');
153
+ if (pattern.length > MAX_TRANSFORM_PATTERN) {
154
+ throw new RangeError('The snippet transform pattern is too long.');
136
155
  }
137
- const parsed = readFormat(source, at, true);
138
- at = parsed.end + 1;
139
- let flags = '';
140
- while (at < source.length && source[at] !== '}') {
141
- const flag = source[at++];
142
- if (!'gimsu'.includes(flag) || flags.includes(flag)) {
143
- throw new SyntaxError('Invalid snippet transform flags.');
144
- }
145
- flags += flag;
146
- }
147
- if (source[at++] !== '}') {
148
- throw new SyntaxError('Unclosed snippet transform flags.');
156
+ }
157
+ if (source[at++] !== '/') {
158
+ throw new SyntaxError('Unclosed snippet transform pattern.');
159
+ }
160
+ const parsed = readFormat(source, at, true);
161
+ at = parsed.end + 1;
162
+ let flags = '';
163
+ while (at < source.length && source[at] !== '}') {
164
+ const flag = source[at++];
165
+ if (!'gimsu'.includes(flag) || flags.includes(flag)) {
166
+ throw new SyntaxError('Invalid snippet transform flags.');
149
167
  }
150
- return { pattern, flags, format: parsed.nodes, end: at };
168
+ flags += flag;
169
+ }
170
+ if (source[at++] !== '}') {
171
+ throw new SyntaxError('Unclosed snippet transform flags.');
172
+ }
173
+ return {
174
+ pattern,
175
+ flags,
176
+ format: parsed.nodes,
177
+ end: at
178
+ };
151
179
  }
152
180
  function capitalize(value) {
153
- const first = value.slice(0, (value.codePointAt(0) ?? 0) > 0xffff ? 2 : 1);
154
- return first.toUpperCase() + value.slice(first.length);
181
+ const first = value.slice(0, (value.codePointAt(0) ?? 0) > 0xffff ? 2 : 1);
182
+ return first.toUpperCase() + value.slice(first.length);
155
183
  }
156
184
  function changeCase(value, operation) {
157
- if (operation === 'upcase') {
158
- return value.toUpperCase();
159
- }
160
- if (operation === 'downcase') {
161
- return value.toLowerCase();
162
- }
163
- if (operation === 'capitalize') {
164
- return capitalize(value);
185
+ if (operation === 'upcase') {
186
+ return value.toUpperCase();
187
+ }
188
+ if (operation === 'downcase') {
189
+ return value.toLowerCase();
190
+ }
191
+ if (operation === 'capitalize') {
192
+ return capitalize(value);
193
+ }
194
+ if (operation === 'camelcase' || operation === 'pascalcase') {
195
+ const words = value.match(/[\p{L}0-9]+/gu);
196
+ if (words === null) {
197
+ return value;
165
198
  }
166
- if (operation === 'camelcase' || operation === 'pascalcase') {
167
- const words = value.match(/[\p{L}0-9]+/gu);
168
- if (words === null) {
169
- return value;
170
- }
171
- return words
172
- .map((word, index) => (operation === 'camelcase' && index === 0 ? word.slice(0, 1).toLowerCase() + word.slice(1) : capitalize(word)))
173
- .join('');
174
- }
175
- return value;
199
+ return words.map((word, index) => operation === 'camelcase' && index === 0 ? word.slice(0, 1).toLowerCase() + word.slice(1) : capitalize(word)).join('');
200
+ }
201
+ return value;
176
202
  }
177
203
  export function validateSnippetTransformJobs(jobs) {
178
- if (!Array.isArray(jobs) || jobs.length > MAX_TRANSFORM_JOBS) {
179
- throw new RangeError('Too many snippet transform jobs.');
204
+ if (!Array.isArray(jobs) || jobs.length > MAX_TRANSFORM_JOBS) {
205
+ throw new RangeError('Too many snippet transform jobs.');
206
+ }
207
+ let characters = 0;
208
+ const patterns = new Set();
209
+ for (const job of jobs) {
210
+ if (typeof job.value !== 'string' || job.value.length > MAX_TRANSFORM_VALUE || typeof job.pattern !== 'string' || job.pattern.length > MAX_TRANSFORM_PATTERN) {
211
+ throw new RangeError('A snippet transform value or pattern is too large.');
180
212
  }
181
- let characters = 0;
182
- const patterns = new Set();
183
- for (const job of jobs) {
184
- if (typeof job.value !== 'string' ||
185
- job.value.length > MAX_TRANSFORM_VALUE ||
186
- typeof job.pattern !== 'string' ||
187
- job.pattern.length > MAX_TRANSFORM_PATTERN) {
188
- throw new RangeError('A snippet transform value or pattern is too large.');
189
- }
190
- characters += job.value.length + job.pattern.length;
191
- if (characters > MAX_TRANSFORM_CHARACTERS || !Array.isArray(job.format) || job.format.length > MAX_TRANSFORM_NODES) {
192
- throw new RangeError('The snippet transform batch is too large.');
193
- }
194
- if (typeof job.flags !== 'string' ||
195
- Array.from(job.flags).some((flag) => !'gimsu'.includes(flag)) ||
196
- new Set(job.flags).size !== job.flags.length) {
197
- throw new SyntaxError('Snippet transforms support the flags g, i, m, s and u once each.');
198
- }
199
- let formatLength = 0;
200
- for (const node of job.format) {
201
- if (node.kind === 'text') {
202
- if (typeof node.text !== 'string') {
203
- throw new SyntaxError('Invalid transform text.');
204
- }
205
- formatLength += node.text.length;
206
- }
207
- else if (node.kind === 'capture' || node.kind === 'conditional') {
208
- if (!Number.isInteger(node.index) || node.index < 0 || node.index > 99) {
209
- throw new RangeError('Invalid transform capture index.');
210
- }
211
- if (node.kind === 'capture' && node.case !== undefined && !CASES.has(node.case)) {
212
- throw new SyntaxError('Invalid transform case operation.');
213
- }
214
- if (node.kind === 'conditional') {
215
- if ((node.if !== undefined && typeof node.if !== 'string') || (node.else !== undefined && typeof node.else !== 'string')) {
216
- throw new SyntaxError('Invalid transform branches.');
217
- }
218
- formatLength += (node.if?.length ?? 0) + (node.else?.length ?? 0);
219
- }
220
- }
221
- else {
222
- throw new SyntaxError('Invalid transform format node.');
223
- }
213
+ characters += job.value.length + job.pattern.length;
214
+ if (characters > MAX_TRANSFORM_CHARACTERS || !Array.isArray(job.format) || job.format.length > MAX_TRANSFORM_NODES) {
215
+ throw new RangeError('The snippet transform batch is too large.');
216
+ }
217
+ if (typeof job.flags !== 'string' || Array.from(job.flags).some(flag => !'gimsu'.includes(flag)) || new Set(job.flags).size !== job.flags.length) {
218
+ throw new SyntaxError('Snippet transforms support the flags g, i, m, s and u once each.');
219
+ }
220
+ let formatLength = 0;
221
+ for (const node of job.format) {
222
+ if (node.kind === 'text') {
223
+ if (typeof node.text !== 'string') {
224
+ throw new SyntaxError('Invalid transform text.');
224
225
  }
225
- if (formatLength > MAX_TRANSFORM_FORMAT) {
226
- throw new RangeError('The transform format is too long.');
226
+ formatLength += node.text.length;
227
+ } else if (node.kind === 'capture' || node.kind === 'conditional') {
228
+ if (!Number.isInteger(node.index) || node.index < 0 || node.index > 99) {
229
+ throw new RangeError('Invalid transform capture index.');
227
230
  }
228
- characters += formatLength;
229
- if (characters > MAX_TRANSFORM_CHARACTERS) {
230
- throw new RangeError('The snippet transform batch is too large.');
231
+ if (node.kind === 'capture' && node.case !== undefined && !CASES.has(node.case)) {
232
+ throw new SyntaxError('Invalid transform case operation.');
231
233
  }
232
- const key = job.flags + '\0' + job.pattern;
233
- if (!patterns.has(key)) {
234
- // Compilation validates syntax; only the worker executes patterns supplied by a server.
235
- new RegExp(job.pattern, job.flags);
236
- patterns.add(key);
234
+ if (node.kind === 'conditional') {
235
+ if (node.if !== undefined && typeof node.if !== 'string' || node.else !== undefined && typeof node.else !== 'string') {
236
+ throw new SyntaxError('Invalid transform branches.');
237
+ }
238
+ formatLength += (node.if?.length ?? 0) + (node.else?.length ?? 0);
237
239
  }
240
+ } else {
241
+ throw new SyntaxError('Invalid transform format node.');
242
+ }
238
243
  }
244
+ if (formatLength > MAX_TRANSFORM_FORMAT) {
245
+ throw new RangeError('The transform format is too long.');
246
+ }
247
+ characters += formatLength;
248
+ if (characters > MAX_TRANSFORM_CHARACTERS) {
249
+ throw new RangeError('The snippet transform batch is too large.');
250
+ }
251
+ const key = job.flags + '\0' + job.pattern;
252
+ if (!patterns.has(key)) {
253
+ // Compilation validates syntax; only the worker executes patterns supplied by a server.
254
+ new RegExp(job.pattern, job.flags);
255
+ patterns.add(key);
256
+ }
257
+ }
239
258
  }
240
259
  export function createSnippetTransformBudget() {
241
- return { remaining: MAX_TRANSFORM_WORK, matches: 0 };
260
+ return {
261
+ remaining: MAX_TRANSFORM_WORK,
262
+ matches: 0
263
+ };
242
264
  }
243
265
  function spend(budget, amount) {
244
- budget.remaining -= amount;
245
- if (budget.remaining < 0) {
246
- throw new RangeError('The snippet transform work budget was exceeded.');
247
- }
266
+ budget.remaining -= amount;
267
+ if (budget.remaining < 0) {
268
+ throw new RangeError('The snippet transform work budget was exceeded.');
269
+ }
248
270
  }
249
271
  export function applySnippetTransform(job, maximum = MAX_TRANSFORM_CHARACTERS, expression = new RegExp(job.pattern, job.flags), budget = createSnippetTransformBudget()) {
250
- expression.lastIndex = 0;
251
- spend(budget, job.value.length);
252
- const pieces = [];
253
- let at = 0, length = 0, matches = 0;
254
- const append = (text) => {
255
- if (text === '') {
256
- return;
257
- }
258
- length += text.length;
259
- if (length > maximum) {
260
- throw new RangeError('The snippet transform output is too large.');
261
- }
262
- pieces.push(text);
263
- };
264
- const format = (captures) => {
265
- for (const node of job.format) {
266
- spend(budget, 1);
267
- if (node.kind === 'text') {
268
- append(node.text);
269
- }
270
- else {
271
- const capture = captures[node.index] ?? '';
272
- if (node.kind === 'capture' && node.case !== undefined) {
273
- spend(budget, capture.length);
274
- }
275
- append(node.kind === 'capture' ? changeCase(capture, node.case) : capture !== '' ? (node.if ?? capture) : (node.else ?? ''));
276
- }
277
- }
278
- };
279
- for (let match = expression.exec(job.value); match !== null; match = expression.exec(job.value)) {
280
- if (++budget.matches > MAX_TRANSFORM_MATCHES) {
281
- throw new RangeError('The snippet transform batch has too many matches.');
282
- }
283
- matches++;
284
- spend(budget, 1);
285
- append(job.value.slice(at, match.index));
286
- format(match);
287
- at = match.index + match[0].length;
288
- if (!expression.global) {
289
- break;
290
- }
291
- if (match[0].length === 0) {
292
- expression.lastIndex += expression.unicode && (job.value.codePointAt(expression.lastIndex) ?? 0) > 0xffff ? 2 : 1;
272
+ expression.lastIndex = 0;
273
+ spend(budget, job.value.length);
274
+ const pieces = [];
275
+ let at = 0,
276
+ length = 0,
277
+ matches = 0;
278
+ const append = text => {
279
+ if (text === '') {
280
+ return;
281
+ }
282
+ length += text.length;
283
+ if (length > maximum) {
284
+ throw new RangeError('The snippet transform output is too large.');
285
+ }
286
+ pieces.push(text);
287
+ };
288
+ const format = captures => {
289
+ for (const node of job.format) {
290
+ spend(budget, 1);
291
+ if (node.kind === 'text') {
292
+ append(node.text);
293
+ } else {
294
+ const capture = captures[node.index] ?? '';
295
+ if (node.kind === 'capture' && node.case !== undefined) {
296
+ spend(budget, capture.length);
293
297
  }
298
+ append(node.kind === 'capture' ? changeCase(capture, node.case) : capture !== '' ? node.if ?? capture : node.else ?? '');
299
+ }
294
300
  }
295
- if (matches === 0 && job.format.some((node) => node.kind === 'conditional' && Boolean(node.else))) {
296
- format([]);
301
+ };
302
+ for (let match = expression.exec(job.value); match !== null; match = expression.exec(job.value)) {
303
+ if (++budget.matches > MAX_TRANSFORM_MATCHES) {
304
+ throw new RangeError('The snippet transform batch has too many matches.');
297
305
  }
298
- else {
299
- append(job.value.slice(at));
306
+ matches++;
307
+ spend(budget, 1);
308
+ append(job.value.slice(at, match.index));
309
+ format(match);
310
+ at = match.index + match[0].length;
311
+ if (!expression.global) {
312
+ break;
300
313
  }
301
- return pieces.join('');
302
- }
314
+ if (match[0].length === 0) {
315
+ expression.lastIndex += expression.unicode && (job.value.codePointAt(expression.lastIndex) ?? 0) > 0xffff ? 2 : 1;
316
+ }
317
+ }
318
+ if (matches === 0 && job.format.some(node => node.kind === 'conditional' && Boolean(node.else))) {
319
+ format([]);
320
+ } else {
321
+ append(job.value.slice(at));
322
+ }
323
+ return pieces.join('');
324
+ }
@@ -5,4 +5,4 @@ export const MAX_TRANSFORM_MATCHES = 10_000;
5
5
  export const MAX_TRANSFORM_WORK = 1_000_000;
6
6
  export const MAX_TRANSFORM_PATTERN = 1024;
7
7
  export const MAX_TRANSFORM_FORMAT = 10_000;
8
- export const MAX_TRANSFORM_NODES = 1000;
8
+ export const MAX_TRANSFORM_NODES = 1000;