clanka 0.2.28 → 0.2.30
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/dist/Agent.d.ts +2 -0
- package/dist/Agent.d.ts.map +1 -1
- package/dist/Agent.js +4 -2
- package/dist/Agent.js.map +1 -1
- package/dist/AgentExecutor.d.ts +227 -1
- package/dist/AgentExecutor.d.ts.map +1 -1
- package/dist/AgentTools.d.ts +123 -0
- package/dist/AgentTools.d.ts.map +1 -1
- package/dist/AgentTools.js +53 -0
- package/dist/AgentTools.js.map +1 -1
- package/dist/ScriptPreprocessing.d.ts.map +1 -1
- package/dist/ScriptPreprocessing.js +326 -292
- package/dist/ScriptPreprocessing.js.map +1 -1
- package/dist/ScriptPreprocessing.test.js +2 -0
- package/dist/ScriptPreprocessing.test.js.map +1 -1
- package/dist/cli.js +3 -4
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/src/Agent.ts +6 -2
- package/src/AgentTools.ts +63 -0
- package/src/ScriptPreprocessing.test.ts +2 -0
- package/src/ScriptPreprocessing.ts +465 -366
- package/src/cli.ts +8 -5
- package/src/fixtures/patch13-broken.txt +149 -0
- package/src/fixtures/patch13-fixed.txt +149 -0
- package/src/fixtures/patch14-broken.txt +68 -0
- package/src/fixtures/patch14-fixed.txt +68 -0
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
const callTemplateTargets = ["applyPatch", "taskComplete"];
|
|
2
|
+
const objectPropertyTargets = [
|
|
3
|
+
{ functionName: "writeFile", propertyName: "content" },
|
|
4
|
+
{ functionName: "updateTask", propertyName: "description" },
|
|
5
|
+
];
|
|
1
6
|
const isIdentifierChar = (char) => char !== undefined && /[A-Za-z0-9_$]/.test(char);
|
|
2
7
|
const isIdentifierStartChar = (char) => char !== undefined && /[A-Za-z_$]/.test(char);
|
|
3
8
|
const hasIdentifierBoundary = (text, index, length) => !isIdentifierChar(text[index - 1]) && !isIdentifierChar(text[index + length]);
|
|
@@ -12,11 +17,11 @@ const findNextIdentifier = (text, identifier, from) => {
|
|
|
12
17
|
return -1;
|
|
13
18
|
};
|
|
14
19
|
const skipWhitespace = (text, start) => {
|
|
15
|
-
let
|
|
16
|
-
while (
|
|
17
|
-
|
|
20
|
+
let index = start;
|
|
21
|
+
while (index < text.length && /\s/.test(text[index])) {
|
|
22
|
+
index++;
|
|
18
23
|
}
|
|
19
|
-
return
|
|
24
|
+
return index;
|
|
20
25
|
};
|
|
21
26
|
const parseIdentifier = (text, start) => {
|
|
22
27
|
if (!isIdentifierStartChar(text[start])) {
|
|
@@ -32,28 +37,125 @@ const parseIdentifier = (text, start) => {
|
|
|
32
37
|
};
|
|
33
38
|
};
|
|
34
39
|
const findPreviousNonWhitespace = (text, from) => {
|
|
35
|
-
let
|
|
36
|
-
while (
|
|
37
|
-
|
|
40
|
+
let index = from;
|
|
41
|
+
while (index >= 0 && /\s/.test(text[index])) {
|
|
42
|
+
index--;
|
|
38
43
|
}
|
|
39
|
-
return
|
|
44
|
+
return index;
|
|
40
45
|
};
|
|
41
46
|
const findNextNonWhitespace = (text, from) => {
|
|
42
|
-
let
|
|
43
|
-
while (
|
|
44
|
-
|
|
47
|
+
let index = from;
|
|
48
|
+
while (index < text.length && /\s/.test(text[index])) {
|
|
49
|
+
index++;
|
|
50
|
+
}
|
|
51
|
+
return index;
|
|
52
|
+
};
|
|
53
|
+
const isEscaped = (text, index) => {
|
|
54
|
+
let slashCount = 0;
|
|
55
|
+
let cursor = index - 1;
|
|
56
|
+
while (cursor >= 0 && text[cursor] === "\\") {
|
|
57
|
+
slashCount++;
|
|
58
|
+
cursor--;
|
|
59
|
+
}
|
|
60
|
+
return slashCount % 2 === 1;
|
|
61
|
+
};
|
|
62
|
+
const needsTemplateEscaping = (text) => {
|
|
63
|
+
for (let index = 0; index < text.length; index++) {
|
|
64
|
+
const char = text[index];
|
|
65
|
+
if (char === "`" && !isEscaped(text, index)) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
if (char === "$" && text[index + 1] === "{" && !isEscaped(text, index)) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return false;
|
|
73
|
+
};
|
|
74
|
+
const findTemplateEnd = (text, start, isTerminator) => {
|
|
75
|
+
let end = -1;
|
|
76
|
+
for (let index = start + 1; index < text.length; index++) {
|
|
77
|
+
if (text[index] !== "`" || isEscaped(text, index)) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (isTerminator(text[index + 1])) {
|
|
81
|
+
end = index;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const next = skipWhitespace(text, index + 1);
|
|
85
|
+
if (isTerminator(text[next])) {
|
|
86
|
+
end = index;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return end;
|
|
90
|
+
};
|
|
91
|
+
const findTypeAnnotationAssignment = (text, start) => {
|
|
92
|
+
let index = start;
|
|
93
|
+
while (index < text.length) {
|
|
94
|
+
const char = text[index];
|
|
95
|
+
if (char === "=") {
|
|
96
|
+
return index;
|
|
97
|
+
}
|
|
98
|
+
if (char === "\n" || char === ";") {
|
|
99
|
+
return -1;
|
|
100
|
+
}
|
|
101
|
+
index++;
|
|
45
102
|
}
|
|
46
|
-
return
|
|
103
|
+
return -1;
|
|
104
|
+
};
|
|
105
|
+
const findClosingParen = (text, openParen) => {
|
|
106
|
+
let depth = 1;
|
|
107
|
+
for (let index = openParen + 1; index < text.length; index++) {
|
|
108
|
+
const char = text[index];
|
|
109
|
+
if (char === "(") {
|
|
110
|
+
depth++;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (char === ")") {
|
|
114
|
+
depth--;
|
|
115
|
+
if (depth === 0) {
|
|
116
|
+
return index;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return -1;
|
|
121
|
+
};
|
|
122
|
+
const findClosingBrace = (text, openBrace) => {
|
|
123
|
+
let depth = 1;
|
|
124
|
+
let stringDelimiter;
|
|
125
|
+
for (let index = openBrace + 1; index < text.length; index++) {
|
|
126
|
+
const char = text[index];
|
|
127
|
+
if (stringDelimiter !== undefined) {
|
|
128
|
+
if (char === stringDelimiter && !isEscaped(text, index)) {
|
|
129
|
+
stringDelimiter = undefined;
|
|
130
|
+
}
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
134
|
+
stringDelimiter = char;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (char === "{") {
|
|
138
|
+
depth++;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (char === "}") {
|
|
142
|
+
depth--;
|
|
143
|
+
if (depth === 0) {
|
|
144
|
+
return index;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return -1;
|
|
47
149
|
};
|
|
48
150
|
const findObjectValueTerminator = (text, start) => {
|
|
49
151
|
let parenDepth = 0;
|
|
50
152
|
let bracketDepth = 0;
|
|
51
153
|
let braceDepth = 0;
|
|
52
154
|
let stringDelimiter;
|
|
53
|
-
for (let
|
|
54
|
-
const char = text[
|
|
155
|
+
for (let index = start; index < text.length; index++) {
|
|
156
|
+
const char = text[index];
|
|
55
157
|
if (stringDelimiter !== undefined) {
|
|
56
|
-
if (char === stringDelimiter && !isEscaped(text,
|
|
158
|
+
if (char === stringDelimiter && !isEscaped(text, index)) {
|
|
57
159
|
stringDelimiter = undefined;
|
|
58
160
|
}
|
|
59
161
|
continue;
|
|
@@ -88,7 +190,7 @@ const findObjectValueTerminator = (text, start) => {
|
|
|
88
190
|
}
|
|
89
191
|
if (char === "}") {
|
|
90
192
|
if (parenDepth === 0 && bracketDepth === 0 && braceDepth === 0) {
|
|
91
|
-
return
|
|
193
|
+
return index;
|
|
92
194
|
}
|
|
93
195
|
if (braceDepth > 0) {
|
|
94
196
|
braceDepth--;
|
|
@@ -99,13 +201,13 @@ const findObjectValueTerminator = (text, start) => {
|
|
|
99
201
|
parenDepth === 0 &&
|
|
100
202
|
bracketDepth === 0 &&
|
|
101
203
|
braceDepth === 0) {
|
|
102
|
-
return
|
|
204
|
+
return index;
|
|
103
205
|
}
|
|
104
206
|
}
|
|
105
207
|
return -1;
|
|
106
208
|
};
|
|
107
209
|
const collectExpressionIdentifiers = (text, start, end) => {
|
|
108
|
-
const
|
|
210
|
+
const identifiers = new Set();
|
|
109
211
|
let cursor = start;
|
|
110
212
|
while (cursor < end) {
|
|
111
213
|
const identifier = parseIdentifier(text, cursor);
|
|
@@ -113,37 +215,14 @@ const collectExpressionIdentifiers = (text, start, end) => {
|
|
|
113
215
|
cursor++;
|
|
114
216
|
continue;
|
|
115
217
|
}
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
if (text[
|
|
119
|
-
|
|
120
|
-
text[nextNonWhitespace] !== "(") {
|
|
121
|
-
out.add(identifier.name);
|
|
218
|
+
const previous = findPreviousNonWhitespace(text, cursor - 1);
|
|
219
|
+
const next = findNextNonWhitespace(text, identifier.end);
|
|
220
|
+
if (text[previous] !== "." && text[next] !== "." && text[next] !== "(") {
|
|
221
|
+
identifiers.add(identifier.name);
|
|
122
222
|
}
|
|
123
223
|
cursor = identifier.end;
|
|
124
224
|
}
|
|
125
|
-
return
|
|
126
|
-
};
|
|
127
|
-
const isEscaped = (text, index) => {
|
|
128
|
-
let slashCount = 0;
|
|
129
|
-
let i = index - 1;
|
|
130
|
-
while (i >= 0 && text[i] === "\\") {
|
|
131
|
-
slashCount++;
|
|
132
|
-
i--;
|
|
133
|
-
}
|
|
134
|
-
return slashCount % 2 === 1;
|
|
135
|
-
};
|
|
136
|
-
const needsTemplateEscaping = (text) => {
|
|
137
|
-
for (let i = 0; i < text.length; i++) {
|
|
138
|
-
const char = text[i];
|
|
139
|
-
if (char === "`" && !isEscaped(text, i)) {
|
|
140
|
-
return true;
|
|
141
|
-
}
|
|
142
|
-
if (char === "$" && text[i + 1] === "{" && !isEscaped(text, i)) {
|
|
143
|
-
return true;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return false;
|
|
225
|
+
return identifiers;
|
|
147
226
|
};
|
|
148
227
|
const normalizePatchEscapedQuotes = (text) => text.includes("*** Begin Patch")
|
|
149
228
|
? text.replace(/\\"([A-Za-z0-9_$.-]+)\\"/g, (match, content, index) => {
|
|
@@ -166,35 +245,36 @@ const normalizeNonPatchEscapedTemplateMarkers = (text) => text
|
|
|
166
245
|
.replace(/\\{2,}(?=`|\$\{)/g, "\\")
|
|
167
246
|
.replace(/(^|\s)\\+(?=\.[A-Za-z0-9_-]+\/)/g, "$1");
|
|
168
247
|
const escapeTemplateLiteralContent = (text) => {
|
|
169
|
-
const
|
|
170
|
-
const isPatchContent =
|
|
248
|
+
const patchNormalized = normalizePatchEscapedQuotes(text);
|
|
249
|
+
const isPatchContent = patchNormalized.includes("*** Begin Patch");
|
|
171
250
|
const normalized = isPatchContent
|
|
172
|
-
?
|
|
173
|
-
: normalizeNonPatchEscapedTemplateMarkers(
|
|
251
|
+
? patchNormalized
|
|
252
|
+
: normalizeNonPatchEscapedTemplateMarkers(patchNormalized);
|
|
174
253
|
if (!needsTemplateEscaping(normalized) &&
|
|
175
|
-
!(isPatchContent && normalized.includes(
|
|
254
|
+
!(isPatchContent && normalized.includes('\\"'))) {
|
|
176
255
|
return normalized;
|
|
177
256
|
}
|
|
178
257
|
let out = "";
|
|
179
|
-
for (let
|
|
180
|
-
const char = normalized[
|
|
258
|
+
for (let index = 0; index < normalized.length; index++) {
|
|
259
|
+
const char = normalized[index];
|
|
181
260
|
if (char === "\\") {
|
|
182
|
-
if (
|
|
183
|
-
(normalized[
|
|
184
|
-
|
|
261
|
+
if ((normalized[index + 1] === "`" && isEscaped(normalized, index + 1)) ||
|
|
262
|
+
(normalized[index + 1] === "$" &&
|
|
263
|
+
normalized[index + 2] === "{" &&
|
|
264
|
+
isEscaped(normalized, index + 1))) {
|
|
185
265
|
out += "\\";
|
|
186
266
|
continue;
|
|
187
267
|
}
|
|
188
268
|
out += "\\\\";
|
|
189
269
|
continue;
|
|
190
270
|
}
|
|
191
|
-
if (char === "`" && !isEscaped(normalized,
|
|
271
|
+
if (char === "`" && !isEscaped(normalized, index)) {
|
|
192
272
|
out += "\\`";
|
|
193
273
|
continue;
|
|
194
274
|
}
|
|
195
275
|
if (char === "$" &&
|
|
196
|
-
normalized[
|
|
197
|
-
!isEscaped(normalized,
|
|
276
|
+
normalized[index + 1] === "{" &&
|
|
277
|
+
!isEscaped(normalized, index)) {
|
|
198
278
|
out += "\\$";
|
|
199
279
|
continue;
|
|
200
280
|
}
|
|
@@ -202,230 +282,122 @@ const escapeTemplateLiteralContent = (text) => {
|
|
|
202
282
|
}
|
|
203
283
|
return out;
|
|
204
284
|
};
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (text[i] !== "`" || isEscaped(text, i)) {
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
if (isTerminator(text[i + 1])) {
|
|
212
|
-
end = i;
|
|
213
|
-
continue;
|
|
214
|
-
}
|
|
215
|
-
const next = skipWhitespace(text, i + 1);
|
|
216
|
-
if (isTerminator(text[next])) {
|
|
217
|
-
end = i;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return end;
|
|
221
|
-
};
|
|
222
|
-
const findTypeAnnotationAssignment = (text, start) => {
|
|
223
|
-
let i = start;
|
|
224
|
-
while (i < text.length) {
|
|
225
|
-
const char = text[i];
|
|
226
|
-
if (char === "=") {
|
|
227
|
-
return i;
|
|
228
|
-
}
|
|
229
|
-
if (char === "\n" || char === ";") {
|
|
230
|
-
return -1;
|
|
231
|
-
}
|
|
232
|
-
i++;
|
|
233
|
-
}
|
|
234
|
-
return -1;
|
|
235
|
-
};
|
|
236
|
-
const findClosingParen = (text, openParen) => {
|
|
237
|
-
let depth = 1;
|
|
238
|
-
for (let i = openParen + 1; i < text.length; i++) {
|
|
239
|
-
const char = text[i];
|
|
240
|
-
if (char === "(") {
|
|
241
|
-
depth++;
|
|
242
|
-
continue;
|
|
243
|
-
}
|
|
244
|
-
if (char === ")") {
|
|
245
|
-
depth--;
|
|
246
|
-
if (depth === 0) {
|
|
247
|
-
return i;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
return -1;
|
|
252
|
-
};
|
|
253
|
-
const findClosingBrace = (text, openBrace) => {
|
|
254
|
-
let depth = 1;
|
|
255
|
-
let stringDelimiter;
|
|
256
|
-
for (let i = openBrace + 1; i < text.length; i++) {
|
|
257
|
-
const char = text[i];
|
|
258
|
-
if (stringDelimiter !== undefined) {
|
|
259
|
-
if (char === stringDelimiter && !isEscaped(text, i)) {
|
|
260
|
-
stringDelimiter = undefined;
|
|
261
|
-
}
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
if (char === '"' || char === "'" || char === "`") {
|
|
265
|
-
stringDelimiter = char;
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
if (char === "{") {
|
|
269
|
-
depth++;
|
|
270
|
-
continue;
|
|
271
|
-
}
|
|
272
|
-
if (char === "}") {
|
|
273
|
-
depth--;
|
|
274
|
-
if (depth === 0) {
|
|
275
|
-
return i;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
return -1;
|
|
280
|
-
};
|
|
281
|
-
const fixObjectLiteralTemplateValues = (text) => text.replace(/\\{2,}(?=`|\$\{)/g, "\\");
|
|
282
|
-
const fixAssignedObjectTemplateValues = (script, variableName) => {
|
|
285
|
+
const normalizeObjectLiteralTemplateMarkers = (text) => text.replace(/\\{2,}(?=`|\$\{)/g, "\\");
|
|
286
|
+
const replaceSlice = (text, start, end, replacement) => `${text.slice(0, start)}${replacement}${text.slice(end)}`;
|
|
287
|
+
const rewriteTemplateContents = (script, findNext, rewrite) => {
|
|
283
288
|
let out = script;
|
|
284
289
|
let cursor = 0;
|
|
285
290
|
while (cursor < out.length) {
|
|
286
|
-
const
|
|
287
|
-
if (
|
|
291
|
+
const range = findNext(out, cursor);
|
|
292
|
+
if (range === undefined) {
|
|
288
293
|
break;
|
|
289
294
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
if (out[assignmentStart] !== "=" ||
|
|
299
|
-
out[assignmentStart + 1] === "=" ||
|
|
300
|
-
out[assignmentStart + 1] === ">") {
|
|
301
|
-
cursor = variableStart + variableName.length;
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
const objectStart = skipWhitespace(out, assignmentStart + 1);
|
|
305
|
-
if (out[objectStart] !== "{") {
|
|
306
|
-
cursor = objectStart + 1;
|
|
307
|
-
continue;
|
|
308
|
-
}
|
|
309
|
-
const objectEnd = findClosingBrace(out, objectStart);
|
|
310
|
-
if (objectEnd === -1) {
|
|
311
|
-
cursor = objectStart + 1;
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
const original = out.slice(objectStart, objectEnd + 1);
|
|
315
|
-
const escaped = fixObjectLiteralTemplateValues(original);
|
|
316
|
-
if (escaped !== original) {
|
|
317
|
-
out = `${out.slice(0, objectStart)}${escaped}${out.slice(objectEnd + 1)}`;
|
|
318
|
-
cursor = objectEnd + (escaped.length - original.length) + 1;
|
|
295
|
+
const original = out.slice(range.contentStart, range.contentEnd);
|
|
296
|
+
const updated = rewrite(original);
|
|
297
|
+
if (updated !== original) {
|
|
298
|
+
out = replaceSlice(out, range.contentStart, range.contentEnd, updated);
|
|
299
|
+
cursor = range.nextCursor + (updated.length - original.length);
|
|
319
300
|
continue;
|
|
320
301
|
}
|
|
321
|
-
cursor =
|
|
322
|
-
}
|
|
323
|
-
return out;
|
|
324
|
-
};
|
|
325
|
-
const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&");
|
|
326
|
-
const collectObjectEntryMapSources = (script, valueIdentifier) => {
|
|
327
|
-
const out = new Set();
|
|
328
|
-
const pattern = new RegExp(`Object\\.entries\\(\\s*([A-Za-z_$][A-Za-z0-9_$]*)\\s*\\)\\s*\\.map\\(\\s*(?:async\\s*)?\\(\\s*\\[\\s*[A-Za-z_$][A-Za-z0-9_$]*\\s*,\\s*${escapeRegExp(valueIdentifier)}\\s*\\]\\s*\\)\\s*=>`, "g");
|
|
329
|
-
for (const match of script.matchAll(pattern)) {
|
|
330
|
-
const sourceIdentifier = match[1];
|
|
331
|
-
if (sourceIdentifier !== undefined) {
|
|
332
|
-
out.add(sourceIdentifier);
|
|
333
|
-
}
|
|
302
|
+
cursor = range.nextCursor;
|
|
334
303
|
}
|
|
335
304
|
return out;
|
|
336
305
|
};
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
342
|
-
for (let i = closeParen - 1; i > templateStart; i--) {
|
|
343
|
-
if (text[i] === "`" && !isEscaped(text, i)) {
|
|
344
|
-
return i;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
return -1;
|
|
348
|
-
};
|
|
349
|
-
const fixCallTemplateArgument = (script, functionName) => {
|
|
350
|
-
let out = script;
|
|
351
|
-
let cursor = 0;
|
|
352
|
-
while (cursor < out.length) {
|
|
353
|
-
const callStart = findNextIdentifier(out, functionName, cursor);
|
|
306
|
+
const findDirectCallTemplate = (text, functionName, from) => {
|
|
307
|
+
let cursor = from;
|
|
308
|
+
while (cursor < text.length) {
|
|
309
|
+
const callStart = findNextIdentifier(text, functionName, cursor);
|
|
354
310
|
if (callStart === -1) {
|
|
355
|
-
|
|
311
|
+
return undefined;
|
|
356
312
|
}
|
|
357
|
-
const openParen = skipWhitespace(
|
|
358
|
-
if (
|
|
313
|
+
const openParen = skipWhitespace(text, callStart + functionName.length);
|
|
314
|
+
if (text[openParen] !== "(") {
|
|
359
315
|
cursor = callStart + functionName.length;
|
|
360
316
|
continue;
|
|
361
317
|
}
|
|
362
|
-
const templateStart = skipWhitespace(
|
|
363
|
-
if (
|
|
318
|
+
const templateStart = skipWhitespace(text, openParen + 1);
|
|
319
|
+
if (text[templateStart] !== "`") {
|
|
364
320
|
cursor = openParen + 1;
|
|
365
321
|
continue;
|
|
366
322
|
}
|
|
367
|
-
const
|
|
323
|
+
const closeParen = findClosingParen(text, openParen);
|
|
324
|
+
let templateEnd = -1;
|
|
325
|
+
if (closeParen !== -1) {
|
|
326
|
+
for (let index = closeParen - 1; index > templateStart; index--) {
|
|
327
|
+
if (text[index] === "`" && !isEscaped(text, index)) {
|
|
328
|
+
templateEnd = index;
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
const patchEnd = text.indexOf("*** End Patch", templateStart);
|
|
335
|
+
const searchStart = patchEnd === -1 ? templateStart + 1 : patchEnd + 1;
|
|
336
|
+
for (let index = searchStart; index < text.length; index++) {
|
|
337
|
+
if (text[index] !== "`" || isEscaped(text, index)) {
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
const candidate = skipWhitespace(text, index + 1);
|
|
341
|
+
if (text[candidate] === ")") {
|
|
342
|
+
templateEnd = index;
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
368
347
|
if (templateEnd === -1) {
|
|
369
348
|
cursor = templateStart + 1;
|
|
370
349
|
continue;
|
|
371
350
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
continue;
|
|
378
|
-
}
|
|
379
|
-
cursor = templateEnd + 1;
|
|
351
|
+
return {
|
|
352
|
+
contentStart: templateStart + 1,
|
|
353
|
+
contentEnd: templateEnd,
|
|
354
|
+
nextCursor: templateEnd + 1,
|
|
355
|
+
};
|
|
380
356
|
}
|
|
381
|
-
return
|
|
357
|
+
return undefined;
|
|
382
358
|
};
|
|
383
|
-
const
|
|
384
|
-
let
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
const callStart = findNextIdentifier(out, functionName, cursor);
|
|
359
|
+
const findObjectPropertyTemplate = (text, target, from) => {
|
|
360
|
+
let cursor = from;
|
|
361
|
+
while (cursor < text.length) {
|
|
362
|
+
const callStart = findNextIdentifier(text, target.functionName, cursor);
|
|
388
363
|
if (callStart === -1) {
|
|
389
|
-
|
|
364
|
+
return undefined;
|
|
390
365
|
}
|
|
391
|
-
const openParen = skipWhitespace(
|
|
392
|
-
if (
|
|
393
|
-
cursor = callStart + functionName.length;
|
|
366
|
+
const openParen = skipWhitespace(text, callStart + target.functionName.length);
|
|
367
|
+
if (text[openParen] !== "(") {
|
|
368
|
+
cursor = callStart + target.functionName.length;
|
|
394
369
|
continue;
|
|
395
370
|
}
|
|
396
|
-
const propertyKey = findNextIdentifier(
|
|
371
|
+
const propertyKey = findNextIdentifier(text, target.propertyName, openParen + 1);
|
|
397
372
|
if (propertyKey === -1) {
|
|
398
373
|
cursor = openParen + 1;
|
|
399
374
|
continue;
|
|
400
375
|
}
|
|
401
|
-
const colon = skipWhitespace(
|
|
402
|
-
if (
|
|
403
|
-
cursor = propertyKey + propertyName.length;
|
|
376
|
+
const colon = skipWhitespace(text, propertyKey + target.propertyName.length);
|
|
377
|
+
if (text[colon] !== ":") {
|
|
378
|
+
cursor = propertyKey + target.propertyName.length;
|
|
404
379
|
continue;
|
|
405
380
|
}
|
|
406
|
-
const templateStart = skipWhitespace(
|
|
407
|
-
if (
|
|
381
|
+
const templateStart = skipWhitespace(text, colon + 1);
|
|
382
|
+
if (text[templateStart] !== "`") {
|
|
408
383
|
cursor = templateStart + 1;
|
|
409
384
|
continue;
|
|
410
385
|
}
|
|
411
|
-
const templateEnd = findTemplateEnd(
|
|
386
|
+
const templateEnd = findTemplateEnd(text, templateStart, (char) => char === "}" || char === ",");
|
|
412
387
|
if (templateEnd === -1) {
|
|
413
388
|
cursor = templateStart + 1;
|
|
414
389
|
continue;
|
|
415
390
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
continue;
|
|
422
|
-
}
|
|
423
|
-
cursor = templateEnd + 1;
|
|
391
|
+
return {
|
|
392
|
+
contentStart: templateStart + 1,
|
|
393
|
+
contentEnd: templateEnd,
|
|
394
|
+
nextCursor: templateEnd + 1,
|
|
395
|
+
};
|
|
424
396
|
}
|
|
425
|
-
return
|
|
397
|
+
return undefined;
|
|
426
398
|
};
|
|
427
399
|
const collectCallArgumentIdentifiers = (script, functionName) => {
|
|
428
|
-
const
|
|
400
|
+
const identifiers = new Set();
|
|
429
401
|
let cursor = 0;
|
|
430
402
|
while (cursor < script.length) {
|
|
431
403
|
const callStart = findNextIdentifier(script, functionName, cursor);
|
|
@@ -445,57 +417,98 @@ const collectCallArgumentIdentifiers = (script, functionName) => {
|
|
|
445
417
|
}
|
|
446
418
|
const argumentEnd = skipWhitespace(script, identifier.end);
|
|
447
419
|
if (script[argumentEnd] === ")" || script[argumentEnd] === ",") {
|
|
448
|
-
|
|
420
|
+
identifiers.add(identifier.name);
|
|
449
421
|
}
|
|
450
422
|
cursor = identifier.end;
|
|
451
423
|
}
|
|
452
|
-
return
|
|
424
|
+
return identifiers;
|
|
453
425
|
};
|
|
454
|
-
const
|
|
455
|
-
const
|
|
426
|
+
const collectObjectPropertyIdentifiers = (script, target) => {
|
|
427
|
+
const identifiers = new Set();
|
|
456
428
|
let cursor = 0;
|
|
457
429
|
while (cursor < script.length) {
|
|
458
|
-
const callStart = findNextIdentifier(script, functionName, cursor);
|
|
430
|
+
const callStart = findNextIdentifier(script, target.functionName, cursor);
|
|
459
431
|
if (callStart === -1) {
|
|
460
432
|
break;
|
|
461
433
|
}
|
|
462
|
-
const openParen = skipWhitespace(script, callStart + functionName.length);
|
|
434
|
+
const openParen = skipWhitespace(script, callStart + target.functionName.length);
|
|
463
435
|
if (script[openParen] !== "(") {
|
|
464
|
-
cursor = callStart + functionName.length;
|
|
436
|
+
cursor = callStart + target.functionName.length;
|
|
465
437
|
continue;
|
|
466
438
|
}
|
|
467
|
-
const propertyKey = findNextIdentifier(script, propertyName, openParen + 1);
|
|
439
|
+
const propertyKey = findNextIdentifier(script, target.propertyName, openParen + 1);
|
|
468
440
|
if (propertyKey === -1) {
|
|
469
441
|
cursor = openParen + 1;
|
|
470
442
|
continue;
|
|
471
443
|
}
|
|
472
|
-
const afterProperty = skipWhitespace(script, propertyKey + propertyName.length);
|
|
444
|
+
const afterProperty = skipWhitespace(script, propertyKey + target.propertyName.length);
|
|
473
445
|
if (script[afterProperty] === ":") {
|
|
474
446
|
const valueStart = skipWhitespace(script, afterProperty + 1);
|
|
475
447
|
const valueEnd = findObjectValueTerminator(script, valueStart);
|
|
476
448
|
if (valueEnd !== -1) {
|
|
477
449
|
for (const identifier of collectExpressionIdentifiers(script, valueStart, valueEnd)) {
|
|
478
|
-
|
|
450
|
+
identifiers.add(identifier);
|
|
479
451
|
}
|
|
480
452
|
}
|
|
481
453
|
cursor = valueStart + 1;
|
|
482
454
|
continue;
|
|
483
455
|
}
|
|
484
456
|
if (script[afterProperty] === "}" || script[afterProperty] === ",") {
|
|
485
|
-
|
|
457
|
+
identifiers.add(target.propertyName);
|
|
486
458
|
cursor = afterProperty + 1;
|
|
487
459
|
continue;
|
|
488
460
|
}
|
|
489
461
|
cursor = afterProperty + 1;
|
|
490
462
|
}
|
|
491
|
-
return
|
|
463
|
+
return identifiers;
|
|
492
464
|
};
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
465
|
+
const rewriteAssignedTemplate = (script, variableName) => rewriteTemplateContents(script, (text, from) => {
|
|
466
|
+
let cursor = from;
|
|
467
|
+
while (cursor < text.length) {
|
|
468
|
+
const variableStart = findNextIdentifier(text, variableName, cursor);
|
|
469
|
+
if (variableStart === -1) {
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
let assignmentStart = skipWhitespace(text, variableStart + variableName.length);
|
|
473
|
+
if (text[assignmentStart] === ":") {
|
|
474
|
+
assignmentStart = findTypeAnnotationAssignment(text, assignmentStart + 1);
|
|
475
|
+
if (assignmentStart === -1) {
|
|
476
|
+
cursor = variableStart + variableName.length;
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (text[assignmentStart] !== "=" ||
|
|
481
|
+
text[assignmentStart + 1] === "=" ||
|
|
482
|
+
text[assignmentStart + 1] === ">") {
|
|
483
|
+
cursor = variableStart + variableName.length;
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
const templateStart = skipWhitespace(text, assignmentStart + 1);
|
|
487
|
+
if (text[templateStart] !== "`") {
|
|
488
|
+
cursor = templateStart + 1;
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const templateEnd = findTemplateEnd(text, templateStart, (char) => char === undefined ||
|
|
492
|
+
char === "\n" ||
|
|
493
|
+
char === "\r" ||
|
|
494
|
+
char === ";" ||
|
|
495
|
+
char === "," ||
|
|
496
|
+
char === ")" ||
|
|
497
|
+
char === "}" ||
|
|
498
|
+
char === "]");
|
|
499
|
+
if (templateEnd === -1) {
|
|
500
|
+
cursor = templateStart + 1;
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
return {
|
|
504
|
+
contentStart: templateStart + 1,
|
|
505
|
+
contentEnd: templateEnd,
|
|
506
|
+
nextCursor: templateEnd + 1,
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
return undefined;
|
|
510
|
+
}, escapeTemplateLiteralContent);
|
|
511
|
+
const rewriteAssignedObjectLiteral = (script, variableName) => {
|
|
499
512
|
let out = script;
|
|
500
513
|
let cursor = 0;
|
|
501
514
|
while (cursor < out.length) {
|
|
@@ -517,63 +530,84 @@ const fixAssignedTemplate = (script, variableName) => {
|
|
|
517
530
|
cursor = variableStart + variableName.length;
|
|
518
531
|
continue;
|
|
519
532
|
}
|
|
520
|
-
const
|
|
521
|
-
if (out[
|
|
522
|
-
cursor =
|
|
533
|
+
const objectStart = skipWhitespace(out, assignmentStart + 1);
|
|
534
|
+
if (out[objectStart] !== "{") {
|
|
535
|
+
cursor = objectStart + 1;
|
|
523
536
|
continue;
|
|
524
537
|
}
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
char === ";" ||
|
|
529
|
-
char === "," ||
|
|
530
|
-
char === ")" ||
|
|
531
|
-
char === "}" ||
|
|
532
|
-
char === "]");
|
|
533
|
-
if (templateEnd === -1) {
|
|
534
|
-
cursor = templateStart + 1;
|
|
538
|
+
const objectEnd = findClosingBrace(out, objectStart);
|
|
539
|
+
if (objectEnd === -1) {
|
|
540
|
+
cursor = objectStart + 1;
|
|
535
541
|
continue;
|
|
536
542
|
}
|
|
537
|
-
const original = out.slice(
|
|
538
|
-
const
|
|
539
|
-
if (
|
|
540
|
-
out =
|
|
541
|
-
cursor =
|
|
543
|
+
const original = out.slice(objectStart, objectEnd + 1);
|
|
544
|
+
const updated = normalizeObjectLiteralTemplateMarkers(original);
|
|
545
|
+
if (updated !== original) {
|
|
546
|
+
out = replaceSlice(out, objectStart, objectEnd + 1, updated);
|
|
547
|
+
cursor = objectEnd + 1 + (updated.length - original.length);
|
|
542
548
|
continue;
|
|
543
549
|
}
|
|
544
|
-
cursor =
|
|
550
|
+
cursor = objectEnd + 1;
|
|
545
551
|
}
|
|
546
552
|
return out;
|
|
547
553
|
};
|
|
548
|
-
const
|
|
554
|
+
const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&");
|
|
555
|
+
const collectObjectEntryMapSources = (script, valueIdentifier) => {
|
|
549
556
|
const identifiers = new Set();
|
|
550
|
-
|
|
557
|
+
const pattern = new RegExp(`Object\\.entries\\(\\s*([A-Za-z_$][A-Za-z0-9_$]*)\\s*\\)\\s*\\.map\\(\\s*(?:async\\s*)?\\(\\s*\\[\\s*[A-Za-z_$][A-Za-z0-9_$]*\\s*,\\s*${escapeRegExp(valueIdentifier)}\\s*\\]\\s*\\)\\s*=>`, "g");
|
|
558
|
+
for (const match of script.matchAll(pattern)) {
|
|
559
|
+
if (match[1] !== undefined) {
|
|
560
|
+
identifiers.add(match[1]);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return identifiers;
|
|
564
|
+
};
|
|
565
|
+
const rewriteDirectTemplates = (script) => {
|
|
566
|
+
let out = script;
|
|
567
|
+
for (const target of objectPropertyTargets) {
|
|
568
|
+
out = rewriteTemplateContents(out, (text, from) => findObjectPropertyTemplate(text, target, from), escapeTemplateLiteralContent);
|
|
569
|
+
}
|
|
570
|
+
for (const functionName of callTemplateTargets) {
|
|
571
|
+
out = rewriteTemplateContents(out, (text, from) => findDirectCallTemplate(text, functionName, from), escapeTemplateLiteralContent);
|
|
572
|
+
}
|
|
573
|
+
return out;
|
|
574
|
+
};
|
|
575
|
+
const collectReferencedTemplateIdentifiers = (script) => {
|
|
576
|
+
const templateIdentifiers = new Set();
|
|
577
|
+
for (const functionName of callTemplateTargets) {
|
|
551
578
|
for (const identifier of collectCallArgumentIdentifiers(script, functionName)) {
|
|
552
|
-
|
|
579
|
+
templateIdentifiers.add(identifier);
|
|
553
580
|
}
|
|
554
581
|
}
|
|
555
|
-
for (const
|
|
556
|
-
for (const identifier of
|
|
557
|
-
|
|
582
|
+
for (const target of objectPropertyTargets) {
|
|
583
|
+
for (const identifier of collectObjectPropertyIdentifiers(script, target)) {
|
|
584
|
+
templateIdentifiers.add(identifier);
|
|
558
585
|
}
|
|
559
586
|
}
|
|
560
587
|
if (script.includes("*** Begin Patch")) {
|
|
561
|
-
|
|
588
|
+
templateIdentifiers.add("patch");
|
|
562
589
|
}
|
|
563
|
-
const
|
|
564
|
-
for (const identifier of
|
|
565
|
-
for (const
|
|
566
|
-
|
|
590
|
+
const objectIdentifiers = new Set();
|
|
591
|
+
for (const identifier of templateIdentifiers) {
|
|
592
|
+
for (const source of collectObjectEntryMapSources(script, identifier)) {
|
|
593
|
+
objectIdentifiers.add(source);
|
|
567
594
|
}
|
|
568
595
|
}
|
|
596
|
+
return {
|
|
597
|
+
templateIdentifiers,
|
|
598
|
+
objectIdentifiers,
|
|
599
|
+
};
|
|
600
|
+
};
|
|
601
|
+
const rewriteAssignedTargets = (script) => {
|
|
602
|
+
const { templateIdentifiers, objectIdentifiers } = collectReferencedTemplateIdentifiers(script);
|
|
569
603
|
let out = script;
|
|
570
|
-
for (const identifier of
|
|
571
|
-
out =
|
|
604
|
+
for (const identifier of templateIdentifiers) {
|
|
605
|
+
out = rewriteAssignedTemplate(out, identifier);
|
|
572
606
|
}
|
|
573
|
-
for (const identifier of
|
|
574
|
-
out =
|
|
607
|
+
for (const identifier of objectIdentifiers) {
|
|
608
|
+
out = rewriteAssignedObjectLiteral(out, identifier);
|
|
575
609
|
}
|
|
576
610
|
return out;
|
|
577
611
|
};
|
|
578
|
-
export const preprocessScript = (script) =>
|
|
612
|
+
export const preprocessScript = (script) => rewriteAssignedTargets(rewriteDirectTemplates(script));
|
|
579
613
|
//# sourceMappingURL=ScriptPreprocessing.js.map
|