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,10 @@
|
|
|
1
|
+
const callTemplateTargets = ["applyPatch", "taskComplete"] as const
|
|
2
|
+
|
|
3
|
+
const objectPropertyTargets = [
|
|
4
|
+
{ functionName: "writeFile", propertyName: "content" },
|
|
5
|
+
{ functionName: "updateTask", propertyName: "description" },
|
|
6
|
+
] as const
|
|
7
|
+
|
|
1
8
|
const isIdentifierChar = (char: string | undefined): boolean =>
|
|
2
9
|
char !== undefined && /[A-Za-z0-9_$]/.test(char)
|
|
3
10
|
|
|
@@ -27,11 +34,11 @@ const findNextIdentifier = (
|
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
const skipWhitespace = (text: string, start: number): number => {
|
|
30
|
-
let
|
|
31
|
-
while (
|
|
32
|
-
|
|
37
|
+
let index = start
|
|
38
|
+
while (index < text.length && /\s/.test(text[index]!)) {
|
|
39
|
+
index++
|
|
33
40
|
}
|
|
34
|
-
return
|
|
41
|
+
return index
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
const parseIdentifier = (
|
|
@@ -41,10 +48,12 @@ const parseIdentifier = (
|
|
|
41
48
|
if (!isIdentifierStartChar(text[start])) {
|
|
42
49
|
return undefined
|
|
43
50
|
}
|
|
51
|
+
|
|
44
52
|
let end = start + 1
|
|
45
53
|
while (end < text.length && isIdentifierChar(text[end])) {
|
|
46
54
|
end++
|
|
47
55
|
}
|
|
56
|
+
|
|
48
57
|
return {
|
|
49
58
|
name: text.slice(start, end),
|
|
50
59
|
end,
|
|
@@ -52,19 +61,134 @@ const parseIdentifier = (
|
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
const findPreviousNonWhitespace = (text: string, from: number): number => {
|
|
55
|
-
let
|
|
56
|
-
while (
|
|
57
|
-
|
|
64
|
+
let index = from
|
|
65
|
+
while (index >= 0 && /\s/.test(text[index]!)) {
|
|
66
|
+
index--
|
|
58
67
|
}
|
|
59
|
-
return
|
|
68
|
+
return index
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
const findNextNonWhitespace = (text: string, from: number): number => {
|
|
63
|
-
let
|
|
64
|
-
while (
|
|
65
|
-
|
|
72
|
+
let index = from
|
|
73
|
+
while (index < text.length && /\s/.test(text[index]!)) {
|
|
74
|
+
index++
|
|
75
|
+
}
|
|
76
|
+
return index
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const isEscaped = (text: string, index: number): boolean => {
|
|
80
|
+
let slashCount = 0
|
|
81
|
+
let cursor = index - 1
|
|
82
|
+
while (cursor >= 0 && text[cursor] === "\\") {
|
|
83
|
+
slashCount++
|
|
84
|
+
cursor--
|
|
85
|
+
}
|
|
86
|
+
return slashCount % 2 === 1
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const needsTemplateEscaping = (text: string): boolean => {
|
|
90
|
+
for (let index = 0; index < text.length; index++) {
|
|
91
|
+
const char = text[index]!
|
|
92
|
+
if (char === "`" && !isEscaped(text, index)) {
|
|
93
|
+
return true
|
|
94
|
+
}
|
|
95
|
+
if (char === "$" && text[index + 1] === "{" && !isEscaped(text, index)) {
|
|
96
|
+
return true
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const findTemplateEnd = (
|
|
103
|
+
text: string,
|
|
104
|
+
start: number,
|
|
105
|
+
isTerminator: (char: string | undefined) => boolean,
|
|
106
|
+
): number => {
|
|
107
|
+
let end = -1
|
|
108
|
+
for (let index = start + 1; index < text.length; index++) {
|
|
109
|
+
if (text[index] !== "`" || isEscaped(text, index)) {
|
|
110
|
+
continue
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (isTerminator(text[index + 1])) {
|
|
114
|
+
end = index
|
|
115
|
+
continue
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const next = skipWhitespace(text, index + 1)
|
|
119
|
+
if (isTerminator(text[next])) {
|
|
120
|
+
end = index
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return end
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const findTypeAnnotationAssignment = (text: string, start: number): number => {
|
|
127
|
+
let index = start
|
|
128
|
+
while (index < text.length) {
|
|
129
|
+
const char = text[index]!
|
|
130
|
+
if (char === "=") {
|
|
131
|
+
return index
|
|
132
|
+
}
|
|
133
|
+
if (char === "\n" || char === ";") {
|
|
134
|
+
return -1
|
|
135
|
+
}
|
|
136
|
+
index++
|
|
137
|
+
}
|
|
138
|
+
return -1
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const findClosingParen = (text: string, openParen: number): number => {
|
|
142
|
+
let depth = 1
|
|
143
|
+
for (let index = openParen + 1; index < text.length; index++) {
|
|
144
|
+
const char = text[index]!
|
|
145
|
+
if (char === "(") {
|
|
146
|
+
depth++
|
|
147
|
+
continue
|
|
148
|
+
}
|
|
149
|
+
if (char === ")") {
|
|
150
|
+
depth--
|
|
151
|
+
if (depth === 0) {
|
|
152
|
+
return index
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return -1
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const findClosingBrace = (text: string, openBrace: number): number => {
|
|
160
|
+
let depth = 1
|
|
161
|
+
let stringDelimiter: '"' | "'" | "`" | undefined
|
|
162
|
+
|
|
163
|
+
for (let index = openBrace + 1; index < text.length; index++) {
|
|
164
|
+
const char = text[index]!
|
|
165
|
+
|
|
166
|
+
if (stringDelimiter !== undefined) {
|
|
167
|
+
if (char === stringDelimiter && !isEscaped(text, index)) {
|
|
168
|
+
stringDelimiter = undefined
|
|
169
|
+
}
|
|
170
|
+
continue
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
174
|
+
stringDelimiter = char
|
|
175
|
+
continue
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (char === "{") {
|
|
179
|
+
depth++
|
|
180
|
+
continue
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (char === "}") {
|
|
184
|
+
depth--
|
|
185
|
+
if (depth === 0) {
|
|
186
|
+
return index
|
|
187
|
+
}
|
|
188
|
+
}
|
|
66
189
|
}
|
|
67
|
-
|
|
190
|
+
|
|
191
|
+
return -1
|
|
68
192
|
}
|
|
69
193
|
|
|
70
194
|
const findObjectValueTerminator = (text: string, start: number): number => {
|
|
@@ -73,11 +197,11 @@ const findObjectValueTerminator = (text: string, start: number): number => {
|
|
|
73
197
|
let braceDepth = 0
|
|
74
198
|
let stringDelimiter: '"' | "'" | "`" | undefined
|
|
75
199
|
|
|
76
|
-
for (let
|
|
77
|
-
const char = text[
|
|
200
|
+
for (let index = start; index < text.length; index++) {
|
|
201
|
+
const char = text[index]!
|
|
78
202
|
|
|
79
203
|
if (stringDelimiter !== undefined) {
|
|
80
|
-
if (char === stringDelimiter && !isEscaped(text,
|
|
204
|
+
if (char === stringDelimiter && !isEscaped(text, index)) {
|
|
81
205
|
stringDelimiter = undefined
|
|
82
206
|
}
|
|
83
207
|
continue
|
|
@@ -114,7 +238,7 @@ const findObjectValueTerminator = (text: string, start: number): number => {
|
|
|
114
238
|
}
|
|
115
239
|
if (char === "}") {
|
|
116
240
|
if (parenDepth === 0 && bracketDepth === 0 && braceDepth === 0) {
|
|
117
|
-
return
|
|
241
|
+
return index
|
|
118
242
|
}
|
|
119
243
|
if (braceDepth > 0) {
|
|
120
244
|
braceDepth--
|
|
@@ -128,7 +252,7 @@ const findObjectValueTerminator = (text: string, start: number): number => {
|
|
|
128
252
|
bracketDepth === 0 &&
|
|
129
253
|
braceDepth === 0
|
|
130
254
|
) {
|
|
131
|
-
return
|
|
255
|
+
return index
|
|
132
256
|
}
|
|
133
257
|
}
|
|
134
258
|
|
|
@@ -140,7 +264,7 @@ const collectExpressionIdentifiers = (
|
|
|
140
264
|
start: number,
|
|
141
265
|
end: number,
|
|
142
266
|
): ReadonlySet<string> => {
|
|
143
|
-
const
|
|
267
|
+
const identifiers = new Set<string>()
|
|
144
268
|
let cursor = start
|
|
145
269
|
|
|
146
270
|
while (cursor < end) {
|
|
@@ -150,43 +274,16 @@ const collectExpressionIdentifiers = (
|
|
|
150
274
|
continue
|
|
151
275
|
}
|
|
152
276
|
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
text[nextNonWhitespace] !== "." &&
|
|
158
|
-
text[nextNonWhitespace] !== "("
|
|
159
|
-
) {
|
|
160
|
-
out.add(identifier.name)
|
|
277
|
+
const previous = findPreviousNonWhitespace(text, cursor - 1)
|
|
278
|
+
const next = findNextNonWhitespace(text, identifier.end)
|
|
279
|
+
if (text[previous] !== "." && text[next] !== "." && text[next] !== "(") {
|
|
280
|
+
identifiers.add(identifier.name)
|
|
161
281
|
}
|
|
162
282
|
|
|
163
283
|
cursor = identifier.end
|
|
164
284
|
}
|
|
165
285
|
|
|
166
|
-
return
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const isEscaped = (text: string, index: number): boolean => {
|
|
170
|
-
let slashCount = 0
|
|
171
|
-
let i = index - 1
|
|
172
|
-
while (i >= 0 && text[i] === "\\") {
|
|
173
|
-
slashCount++
|
|
174
|
-
i--
|
|
175
|
-
}
|
|
176
|
-
return slashCount % 2 === 1
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const needsTemplateEscaping = (text: string): boolean => {
|
|
180
|
-
for (let i = 0; i < text.length; i++) {
|
|
181
|
-
const char = text[i]!
|
|
182
|
-
if (char === "`" && !isEscaped(text, i)) {
|
|
183
|
-
return true
|
|
184
|
-
}
|
|
185
|
-
if (char === "$" && text[i + 1] === "{" && !isEscaped(text, i)) {
|
|
186
|
-
return true
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return false
|
|
286
|
+
return identifiers
|
|
190
287
|
}
|
|
191
288
|
|
|
192
289
|
const normalizePatchEscapedQuotes = (text: string): string =>
|
|
@@ -217,26 +314,29 @@ const normalizeNonPatchEscapedTemplateMarkers = (text: string): string =>
|
|
|
217
314
|
.replace(/(^|\s)\\+(?=\.[A-Za-z0-9_-]+\/)/g, "$1")
|
|
218
315
|
|
|
219
316
|
const escapeTemplateLiteralContent = (text: string): string => {
|
|
220
|
-
const
|
|
221
|
-
const isPatchContent =
|
|
317
|
+
const patchNormalized = normalizePatchEscapedQuotes(text)
|
|
318
|
+
const isPatchContent = patchNormalized.includes("*** Begin Patch")
|
|
222
319
|
const normalized = isPatchContent
|
|
223
|
-
?
|
|
224
|
-
: normalizeNonPatchEscapedTemplateMarkers(
|
|
320
|
+
? patchNormalized
|
|
321
|
+
: normalizeNonPatchEscapedTemplateMarkers(patchNormalized)
|
|
322
|
+
|
|
225
323
|
if (
|
|
226
324
|
!needsTemplateEscaping(normalized) &&
|
|
227
|
-
!(isPatchContent && normalized.includes(
|
|
325
|
+
!(isPatchContent && normalized.includes('\\"'))
|
|
228
326
|
) {
|
|
229
327
|
return normalized
|
|
230
328
|
}
|
|
231
329
|
|
|
232
330
|
let out = ""
|
|
233
|
-
for (let
|
|
234
|
-
const char = normalized[
|
|
331
|
+
for (let index = 0; index < normalized.length; index++) {
|
|
332
|
+
const char = normalized[index]!
|
|
333
|
+
|
|
235
334
|
if (char === "\\") {
|
|
236
335
|
if (
|
|
237
|
-
|
|
238
|
-
(normalized[
|
|
239
|
-
|
|
336
|
+
(normalized[index + 1] === "`" && isEscaped(normalized, index + 1)) ||
|
|
337
|
+
(normalized[index + 1] === "$" &&
|
|
338
|
+
normalized[index + 2] === "{" &&
|
|
339
|
+
isEscaped(normalized, index + 1))
|
|
240
340
|
) {
|
|
241
341
|
out += "\\"
|
|
242
342
|
continue
|
|
@@ -244,303 +344,196 @@ const escapeTemplateLiteralContent = (text: string): string => {
|
|
|
244
344
|
out += "\\\\"
|
|
245
345
|
continue
|
|
246
346
|
}
|
|
247
|
-
|
|
347
|
+
|
|
348
|
+
if (char === "`" && !isEscaped(normalized, index)) {
|
|
248
349
|
out += "\\`"
|
|
249
350
|
continue
|
|
250
351
|
}
|
|
352
|
+
|
|
251
353
|
if (
|
|
252
354
|
char === "$" &&
|
|
253
|
-
normalized[
|
|
254
|
-
!isEscaped(normalized,
|
|
355
|
+
normalized[index + 1] === "{" &&
|
|
356
|
+
!isEscaped(normalized, index)
|
|
255
357
|
) {
|
|
256
358
|
out += "\\$"
|
|
257
359
|
continue
|
|
258
360
|
}
|
|
361
|
+
|
|
259
362
|
out += char
|
|
260
363
|
}
|
|
364
|
+
|
|
261
365
|
return out
|
|
262
366
|
}
|
|
263
367
|
|
|
264
|
-
const
|
|
368
|
+
const normalizeObjectLiteralTemplateMarkers = (text: string): string =>
|
|
369
|
+
text.replace(/\\{2,}(?=`|\$\{)/g, "\\")
|
|
370
|
+
|
|
371
|
+
const replaceSlice = (
|
|
265
372
|
text: string,
|
|
266
373
|
start: number,
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
for (let i = start + 1; i < text.length; i++) {
|
|
271
|
-
if (text[i] !== "`" || isEscaped(text, i)) {
|
|
272
|
-
continue
|
|
273
|
-
}
|
|
274
|
-
if (isTerminator(text[i + 1])) {
|
|
275
|
-
end = i
|
|
276
|
-
continue
|
|
277
|
-
}
|
|
278
|
-
const next = skipWhitespace(text, i + 1)
|
|
279
|
-
if (isTerminator(text[next])) {
|
|
280
|
-
end = i
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
return end
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const findTypeAnnotationAssignment = (text: string, start: number): number => {
|
|
287
|
-
let i = start
|
|
288
|
-
while (i < text.length) {
|
|
289
|
-
const char = text[i]!
|
|
290
|
-
if (char === "=") {
|
|
291
|
-
return i
|
|
292
|
-
}
|
|
293
|
-
if (char === "\n" || char === ";") {
|
|
294
|
-
return -1
|
|
295
|
-
}
|
|
296
|
-
i++
|
|
297
|
-
}
|
|
298
|
-
return -1
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const findClosingParen = (text: string, openParen: number): number => {
|
|
302
|
-
let depth = 1
|
|
303
|
-
for (let i = openParen + 1; i < text.length; i++) {
|
|
304
|
-
const char = text[i]!
|
|
305
|
-
if (char === "(") {
|
|
306
|
-
depth++
|
|
307
|
-
continue
|
|
308
|
-
}
|
|
309
|
-
if (char === ")") {
|
|
310
|
-
depth--
|
|
311
|
-
if (depth === 0) {
|
|
312
|
-
return i
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return -1
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const findClosingBrace = (text: string, openBrace: number): number => {
|
|
320
|
-
let depth = 1
|
|
321
|
-
let stringDelimiter: '"' | "'" | "`" | undefined
|
|
322
|
-
|
|
323
|
-
for (let i = openBrace + 1; i < text.length; i++) {
|
|
324
|
-
const char = text[i]!
|
|
325
|
-
|
|
326
|
-
if (stringDelimiter !== undefined) {
|
|
327
|
-
if (char === stringDelimiter && !isEscaped(text, i)) {
|
|
328
|
-
stringDelimiter = undefined
|
|
329
|
-
}
|
|
330
|
-
continue
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (char === '"' || char === "'" || char === "`") {
|
|
334
|
-
stringDelimiter = char
|
|
335
|
-
continue
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (char === "{") {
|
|
339
|
-
depth++
|
|
340
|
-
continue
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (char === "}") {
|
|
344
|
-
depth--
|
|
345
|
-
if (depth === 0) {
|
|
346
|
-
return i
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
return -1
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
const fixObjectLiteralTemplateValues = (text: string): string =>
|
|
355
|
-
text.replace(/\\{2,}(?=`|\$\{)/g, "\\")
|
|
374
|
+
end: number,
|
|
375
|
+
replacement: string,
|
|
376
|
+
): string => `${text.slice(0, start)}${replacement}${text.slice(end)}`
|
|
356
377
|
|
|
357
|
-
const
|
|
378
|
+
const rewriteTemplateContents = (
|
|
358
379
|
script: string,
|
|
359
|
-
|
|
380
|
+
findNext: (
|
|
381
|
+
text: string,
|
|
382
|
+
from: number,
|
|
383
|
+
) =>
|
|
384
|
+
| {
|
|
385
|
+
readonly contentStart: number
|
|
386
|
+
readonly contentEnd: number
|
|
387
|
+
readonly nextCursor: number
|
|
388
|
+
}
|
|
389
|
+
| undefined,
|
|
390
|
+
rewrite: (content: string) => string,
|
|
360
391
|
): string => {
|
|
361
392
|
let out = script
|
|
362
393
|
let cursor = 0
|
|
363
394
|
|
|
364
395
|
while (cursor < out.length) {
|
|
365
|
-
const
|
|
366
|
-
if (
|
|
396
|
+
const range = findNext(out, cursor)
|
|
397
|
+
if (range === undefined) {
|
|
367
398
|
break
|
|
368
399
|
}
|
|
369
400
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
assignmentStart = findTypeAnnotationAssignment(out, assignmentStart + 1)
|
|
376
|
-
if (assignmentStart === -1) {
|
|
377
|
-
cursor = variableStart + variableName.length
|
|
378
|
-
continue
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (
|
|
383
|
-
out[assignmentStart] !== "=" ||
|
|
384
|
-
out[assignmentStart + 1] === "=" ||
|
|
385
|
-
out[assignmentStart + 1] === ">"
|
|
386
|
-
) {
|
|
387
|
-
cursor = variableStart + variableName.length
|
|
388
|
-
continue
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
const objectStart = skipWhitespace(out, assignmentStart + 1)
|
|
392
|
-
if (out[objectStart] !== "{") {
|
|
393
|
-
cursor = objectStart + 1
|
|
394
|
-
continue
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
const objectEnd = findClosingBrace(out, objectStart)
|
|
398
|
-
if (objectEnd === -1) {
|
|
399
|
-
cursor = objectStart + 1
|
|
401
|
+
const original = out.slice(range.contentStart, range.contentEnd)
|
|
402
|
+
const updated = rewrite(original)
|
|
403
|
+
if (updated !== original) {
|
|
404
|
+
out = replaceSlice(out, range.contentStart, range.contentEnd, updated)
|
|
405
|
+
cursor = range.nextCursor + (updated.length - original.length)
|
|
400
406
|
continue
|
|
401
407
|
}
|
|
402
408
|
|
|
403
|
-
|
|
404
|
-
const escaped = fixObjectLiteralTemplateValues(original)
|
|
405
|
-
if (escaped !== original) {
|
|
406
|
-
out = `${out.slice(0, objectStart)}${escaped}${out.slice(objectEnd + 1)}`
|
|
407
|
-
cursor = objectEnd + (escaped.length - original.length) + 1
|
|
408
|
-
continue
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
cursor = objectEnd + 1
|
|
409
|
+
cursor = range.nextCursor
|
|
412
410
|
}
|
|
413
411
|
|
|
414
412
|
return out
|
|
415
413
|
}
|
|
416
414
|
|
|
417
|
-
const
|
|
418
|
-
text.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")
|
|
419
|
-
|
|
420
|
-
const collectObjectEntryMapSources = (
|
|
421
|
-
script: string,
|
|
422
|
-
valueIdentifier: string,
|
|
423
|
-
): ReadonlySet<string> => {
|
|
424
|
-
const out = new Set<string>()
|
|
425
|
-
const pattern = new RegExp(
|
|
426
|
-
`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*=>`,
|
|
427
|
-
"g",
|
|
428
|
-
)
|
|
429
|
-
|
|
430
|
-
for (const match of script.matchAll(pattern)) {
|
|
431
|
-
const sourceIdentifier = match[1]
|
|
432
|
-
if (sourceIdentifier !== undefined) {
|
|
433
|
-
out.add(sourceIdentifier)
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
return out
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
const findCallTemplateEnd = (
|
|
415
|
+
const findDirectCallTemplate = (
|
|
441
416
|
text: string,
|
|
442
|
-
templateStart: number,
|
|
443
|
-
openParen: number,
|
|
444
|
-
): number => {
|
|
445
|
-
const closeParen = findClosingParen(text, openParen)
|
|
446
|
-
if (closeParen === -1) {
|
|
447
|
-
return -1
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
for (let i = closeParen - 1; i > templateStart; i--) {
|
|
451
|
-
if (text[i] === "`" && !isEscaped(text, i)) {
|
|
452
|
-
return i
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
return -1
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
const fixCallTemplateArgument = (
|
|
460
|
-
script: string,
|
|
461
417
|
functionName: string,
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
418
|
+
from: number,
|
|
419
|
+
):
|
|
420
|
+
| {
|
|
421
|
+
readonly contentStart: number
|
|
422
|
+
readonly contentEnd: number
|
|
423
|
+
readonly nextCursor: number
|
|
424
|
+
}
|
|
425
|
+
| undefined => {
|
|
426
|
+
let cursor = from
|
|
465
427
|
|
|
466
|
-
while (cursor <
|
|
467
|
-
const callStart = findNextIdentifier(
|
|
428
|
+
while (cursor < text.length) {
|
|
429
|
+
const callStart = findNextIdentifier(text, functionName, cursor)
|
|
468
430
|
if (callStart === -1) {
|
|
469
|
-
|
|
431
|
+
return undefined
|
|
470
432
|
}
|
|
471
433
|
|
|
472
|
-
const openParen = skipWhitespace(
|
|
473
|
-
if (
|
|
434
|
+
const openParen = skipWhitespace(text, callStart + functionName.length)
|
|
435
|
+
if (text[openParen] !== "(") {
|
|
474
436
|
cursor = callStart + functionName.length
|
|
475
437
|
continue
|
|
476
438
|
}
|
|
477
439
|
|
|
478
|
-
const templateStart = skipWhitespace(
|
|
479
|
-
if (
|
|
440
|
+
const templateStart = skipWhitespace(text, openParen + 1)
|
|
441
|
+
if (text[templateStart] !== "`") {
|
|
480
442
|
cursor = openParen + 1
|
|
481
443
|
continue
|
|
482
444
|
}
|
|
483
445
|
|
|
484
|
-
const
|
|
446
|
+
const closeParen = findClosingParen(text, openParen)
|
|
447
|
+
let templateEnd = -1
|
|
448
|
+
if (closeParen !== -1) {
|
|
449
|
+
for (let index = closeParen - 1; index > templateStart; index--) {
|
|
450
|
+
if (text[index] === "`" && !isEscaped(text, index)) {
|
|
451
|
+
templateEnd = index
|
|
452
|
+
break
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
} else {
|
|
456
|
+
const patchEnd = text.indexOf("*** End Patch", templateStart)
|
|
457
|
+
const searchStart = patchEnd === -1 ? templateStart + 1 : patchEnd + 1
|
|
458
|
+
for (let index = searchStart; index < text.length; index++) {
|
|
459
|
+
if (text[index] !== "`" || isEscaped(text, index)) {
|
|
460
|
+
continue
|
|
461
|
+
}
|
|
462
|
+
const candidate = skipWhitespace(text, index + 1)
|
|
463
|
+
if (text[candidate] === ")") {
|
|
464
|
+
templateEnd = index
|
|
465
|
+
break
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
485
470
|
if (templateEnd === -1) {
|
|
486
471
|
cursor = templateStart + 1
|
|
487
472
|
continue
|
|
488
473
|
}
|
|
489
474
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
cursor = templateEnd + (escaped.length - original.length) + 1
|
|
495
|
-
continue
|
|
475
|
+
return {
|
|
476
|
+
contentStart: templateStart + 1,
|
|
477
|
+
contentEnd: templateEnd,
|
|
478
|
+
nextCursor: templateEnd + 1,
|
|
496
479
|
}
|
|
497
|
-
|
|
498
|
-
cursor = templateEnd + 1
|
|
499
480
|
}
|
|
500
481
|
|
|
501
|
-
return
|
|
482
|
+
return undefined
|
|
502
483
|
}
|
|
503
484
|
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
):
|
|
509
|
-
|
|
510
|
-
|
|
485
|
+
const findObjectPropertyTemplate = (
|
|
486
|
+
text: string,
|
|
487
|
+
target: (typeof objectPropertyTargets)[number],
|
|
488
|
+
from: number,
|
|
489
|
+
):
|
|
490
|
+
| {
|
|
491
|
+
readonly contentStart: number
|
|
492
|
+
readonly contentEnd: number
|
|
493
|
+
readonly nextCursor: number
|
|
494
|
+
}
|
|
495
|
+
| undefined => {
|
|
496
|
+
let cursor = from
|
|
511
497
|
|
|
512
|
-
while (cursor <
|
|
513
|
-
const callStart = findNextIdentifier(
|
|
498
|
+
while (cursor < text.length) {
|
|
499
|
+
const callStart = findNextIdentifier(text, target.functionName, cursor)
|
|
514
500
|
if (callStart === -1) {
|
|
515
|
-
|
|
501
|
+
return undefined
|
|
516
502
|
}
|
|
517
503
|
|
|
518
|
-
const openParen = skipWhitespace(
|
|
519
|
-
|
|
520
|
-
|
|
504
|
+
const openParen = skipWhitespace(
|
|
505
|
+
text,
|
|
506
|
+
callStart + target.functionName.length,
|
|
507
|
+
)
|
|
508
|
+
if (text[openParen] !== "(") {
|
|
509
|
+
cursor = callStart + target.functionName.length
|
|
521
510
|
continue
|
|
522
511
|
}
|
|
523
512
|
|
|
524
|
-
const propertyKey = findNextIdentifier(
|
|
513
|
+
const propertyKey = findNextIdentifier(
|
|
514
|
+
text,
|
|
515
|
+
target.propertyName,
|
|
516
|
+
openParen + 1,
|
|
517
|
+
)
|
|
525
518
|
if (propertyKey === -1) {
|
|
526
519
|
cursor = openParen + 1
|
|
527
520
|
continue
|
|
528
521
|
}
|
|
529
522
|
|
|
530
|
-
const colon = skipWhitespace(
|
|
531
|
-
if (
|
|
532
|
-
cursor = propertyKey + propertyName.length
|
|
523
|
+
const colon = skipWhitespace(text, propertyKey + target.propertyName.length)
|
|
524
|
+
if (text[colon] !== ":") {
|
|
525
|
+
cursor = propertyKey + target.propertyName.length
|
|
533
526
|
continue
|
|
534
527
|
}
|
|
535
528
|
|
|
536
|
-
const templateStart = skipWhitespace(
|
|
537
|
-
if (
|
|
529
|
+
const templateStart = skipWhitespace(text, colon + 1)
|
|
530
|
+
if (text[templateStart] !== "`") {
|
|
538
531
|
cursor = templateStart + 1
|
|
539
532
|
continue
|
|
540
533
|
}
|
|
541
534
|
|
|
542
535
|
const templateEnd = findTemplateEnd(
|
|
543
|
-
|
|
536
|
+
text,
|
|
544
537
|
templateStart,
|
|
545
538
|
(char) => char === "}" || char === ",",
|
|
546
539
|
)
|
|
@@ -549,25 +542,21 @@ const fixCallObjectPropertyTemplate = (
|
|
|
549
542
|
continue
|
|
550
543
|
}
|
|
551
544
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
cursor = templateEnd + (escaped.length - original.length) + 1
|
|
557
|
-
continue
|
|
545
|
+
return {
|
|
546
|
+
contentStart: templateStart + 1,
|
|
547
|
+
contentEnd: templateEnd,
|
|
548
|
+
nextCursor: templateEnd + 1,
|
|
558
549
|
}
|
|
559
|
-
|
|
560
|
-
cursor = templateEnd + 1
|
|
561
550
|
}
|
|
562
551
|
|
|
563
|
-
return
|
|
552
|
+
return undefined
|
|
564
553
|
}
|
|
565
554
|
|
|
566
555
|
const collectCallArgumentIdentifiers = (
|
|
567
556
|
script: string,
|
|
568
557
|
functionName: string,
|
|
569
558
|
): ReadonlySet<string> => {
|
|
570
|
-
const
|
|
559
|
+
const identifiers = new Set<string>()
|
|
571
560
|
let cursor = 0
|
|
572
561
|
|
|
573
562
|
while (cursor < script.length) {
|
|
@@ -591,36 +580,42 @@ const collectCallArgumentIdentifiers = (
|
|
|
591
580
|
|
|
592
581
|
const argumentEnd = skipWhitespace(script, identifier.end)
|
|
593
582
|
if (script[argumentEnd] === ")" || script[argumentEnd] === ",") {
|
|
594
|
-
|
|
583
|
+
identifiers.add(identifier.name)
|
|
595
584
|
}
|
|
596
585
|
|
|
597
586
|
cursor = identifier.end
|
|
598
587
|
}
|
|
599
588
|
|
|
600
|
-
return
|
|
589
|
+
return identifiers
|
|
601
590
|
}
|
|
602
591
|
|
|
603
|
-
const
|
|
592
|
+
const collectObjectPropertyIdentifiers = (
|
|
604
593
|
script: string,
|
|
605
|
-
|
|
606
|
-
propertyName: string,
|
|
594
|
+
target: (typeof objectPropertyTargets)[number],
|
|
607
595
|
): ReadonlySet<string> => {
|
|
608
|
-
const
|
|
596
|
+
const identifiers = new Set<string>()
|
|
609
597
|
let cursor = 0
|
|
610
598
|
|
|
611
599
|
while (cursor < script.length) {
|
|
612
|
-
const callStart = findNextIdentifier(script, functionName, cursor)
|
|
600
|
+
const callStart = findNextIdentifier(script, target.functionName, cursor)
|
|
613
601
|
if (callStart === -1) {
|
|
614
602
|
break
|
|
615
603
|
}
|
|
616
604
|
|
|
617
|
-
const openParen = skipWhitespace(
|
|
605
|
+
const openParen = skipWhitespace(
|
|
606
|
+
script,
|
|
607
|
+
callStart + target.functionName.length,
|
|
608
|
+
)
|
|
618
609
|
if (script[openParen] !== "(") {
|
|
619
|
-
cursor = callStart + functionName.length
|
|
610
|
+
cursor = callStart + target.functionName.length
|
|
620
611
|
continue
|
|
621
612
|
}
|
|
622
613
|
|
|
623
|
-
const propertyKey = findNextIdentifier(
|
|
614
|
+
const propertyKey = findNextIdentifier(
|
|
615
|
+
script,
|
|
616
|
+
target.propertyName,
|
|
617
|
+
openParen + 1,
|
|
618
|
+
)
|
|
624
619
|
if (propertyKey === -1) {
|
|
625
620
|
cursor = openParen + 1
|
|
626
621
|
continue
|
|
@@ -628,7 +623,7 @@ const collectCallObjectPropertyIdentifiers = (
|
|
|
628
623
|
|
|
629
624
|
const afterProperty = skipWhitespace(
|
|
630
625
|
script,
|
|
631
|
-
propertyKey + propertyName.length,
|
|
626
|
+
propertyKey + target.propertyName.length,
|
|
632
627
|
)
|
|
633
628
|
if (script[afterProperty] === ":") {
|
|
634
629
|
const valueStart = skipWhitespace(script, afterProperty + 1)
|
|
@@ -639,7 +634,7 @@ const collectCallObjectPropertyIdentifiers = (
|
|
|
639
634
|
valueStart,
|
|
640
635
|
valueEnd,
|
|
641
636
|
)) {
|
|
642
|
-
|
|
637
|
+
identifiers.add(identifier)
|
|
643
638
|
}
|
|
644
639
|
}
|
|
645
640
|
cursor = valueStart + 1
|
|
@@ -647,7 +642,7 @@ const collectCallObjectPropertyIdentifiers = (
|
|
|
647
642
|
}
|
|
648
643
|
|
|
649
644
|
if (script[afterProperty] === "}" || script[afterProperty] === ",") {
|
|
650
|
-
|
|
645
|
+
identifiers.add(target.propertyName)
|
|
651
646
|
cursor = afterProperty + 1
|
|
652
647
|
continue
|
|
653
648
|
}
|
|
@@ -655,22 +650,88 @@ const collectCallObjectPropertyIdentifiers = (
|
|
|
655
650
|
cursor = afterProperty + 1
|
|
656
651
|
}
|
|
657
652
|
|
|
658
|
-
return
|
|
653
|
+
return identifiers
|
|
659
654
|
}
|
|
660
655
|
|
|
661
|
-
const
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
const fixTargetCallObjectPropertyTemplates = (script: string): string =>
|
|
667
|
-
callObjectPropertyTargets.reduce(
|
|
668
|
-
(current, [functionName, propertyName]) =>
|
|
669
|
-
fixCallObjectPropertyTemplate(current, functionName, propertyName),
|
|
656
|
+
const rewriteAssignedTemplate = (
|
|
657
|
+
script: string,
|
|
658
|
+
variableName: string,
|
|
659
|
+
): string =>
|
|
660
|
+
rewriteTemplateContents(
|
|
670
661
|
script,
|
|
662
|
+
(text, from) => {
|
|
663
|
+
let cursor = from
|
|
664
|
+
|
|
665
|
+
while (cursor < text.length) {
|
|
666
|
+
const variableStart = findNextIdentifier(text, variableName, cursor)
|
|
667
|
+
if (variableStart === -1) {
|
|
668
|
+
return undefined
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
let assignmentStart = skipWhitespace(
|
|
672
|
+
text,
|
|
673
|
+
variableStart + variableName.length,
|
|
674
|
+
)
|
|
675
|
+
if (text[assignmentStart] === ":") {
|
|
676
|
+
assignmentStart = findTypeAnnotationAssignment(
|
|
677
|
+
text,
|
|
678
|
+
assignmentStart + 1,
|
|
679
|
+
)
|
|
680
|
+
if (assignmentStart === -1) {
|
|
681
|
+
cursor = variableStart + variableName.length
|
|
682
|
+
continue
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
if (
|
|
687
|
+
text[assignmentStart] !== "=" ||
|
|
688
|
+
text[assignmentStart + 1] === "=" ||
|
|
689
|
+
text[assignmentStart + 1] === ">"
|
|
690
|
+
) {
|
|
691
|
+
cursor = variableStart + variableName.length
|
|
692
|
+
continue
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
const templateStart = skipWhitespace(text, assignmentStart + 1)
|
|
696
|
+
if (text[templateStart] !== "`") {
|
|
697
|
+
cursor = templateStart + 1
|
|
698
|
+
continue
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
const templateEnd = findTemplateEnd(
|
|
702
|
+
text,
|
|
703
|
+
templateStart,
|
|
704
|
+
(char) =>
|
|
705
|
+
char === undefined ||
|
|
706
|
+
char === "\n" ||
|
|
707
|
+
char === "\r" ||
|
|
708
|
+
char === ";" ||
|
|
709
|
+
char === "," ||
|
|
710
|
+
char === ")" ||
|
|
711
|
+
char === "}" ||
|
|
712
|
+
char === "]",
|
|
713
|
+
)
|
|
714
|
+
if (templateEnd === -1) {
|
|
715
|
+
cursor = templateStart + 1
|
|
716
|
+
continue
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
return {
|
|
720
|
+
contentStart: templateStart + 1,
|
|
721
|
+
contentEnd: templateEnd,
|
|
722
|
+
nextCursor: templateEnd + 1,
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
return undefined
|
|
727
|
+
},
|
|
728
|
+
escapeTemplateLiteralContent,
|
|
671
729
|
)
|
|
672
730
|
|
|
673
|
-
const
|
|
731
|
+
const rewriteAssignedObjectLiteral = (
|
|
732
|
+
script: string,
|
|
733
|
+
variableName: string,
|
|
734
|
+
): string => {
|
|
674
735
|
let out = script
|
|
675
736
|
let cursor = 0
|
|
676
737
|
|
|
@@ -701,91 +762,129 @@ const fixAssignedTemplate = (script: string, variableName: string): string => {
|
|
|
701
762
|
continue
|
|
702
763
|
}
|
|
703
764
|
|
|
704
|
-
const
|
|
705
|
-
if (out[
|
|
706
|
-
cursor =
|
|
765
|
+
const objectStart = skipWhitespace(out, assignmentStart + 1)
|
|
766
|
+
if (out[objectStart] !== "{") {
|
|
767
|
+
cursor = objectStart + 1
|
|
707
768
|
continue
|
|
708
769
|
}
|
|
709
770
|
|
|
710
|
-
const
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
(char) =>
|
|
714
|
-
char === undefined ||
|
|
715
|
-
char === "\n" ||
|
|
716
|
-
char === "\r" ||
|
|
717
|
-
char === ";" ||
|
|
718
|
-
char === "," ||
|
|
719
|
-
char === ")" ||
|
|
720
|
-
char === "}" ||
|
|
721
|
-
char === "]",
|
|
722
|
-
)
|
|
723
|
-
if (templateEnd === -1) {
|
|
724
|
-
cursor = templateStart + 1
|
|
771
|
+
const objectEnd = findClosingBrace(out, objectStart)
|
|
772
|
+
if (objectEnd === -1) {
|
|
773
|
+
cursor = objectStart + 1
|
|
725
774
|
continue
|
|
726
775
|
}
|
|
727
776
|
|
|
728
|
-
const original = out.slice(
|
|
729
|
-
const
|
|
730
|
-
if (
|
|
731
|
-
out =
|
|
732
|
-
cursor =
|
|
777
|
+
const original = out.slice(objectStart, objectEnd + 1)
|
|
778
|
+
const updated = normalizeObjectLiteralTemplateMarkers(original)
|
|
779
|
+
if (updated !== original) {
|
|
780
|
+
out = replaceSlice(out, objectStart, objectEnd + 1, updated)
|
|
781
|
+
cursor = objectEnd + 1 + (updated.length - original.length)
|
|
733
782
|
continue
|
|
734
783
|
}
|
|
735
784
|
|
|
736
|
-
cursor =
|
|
785
|
+
cursor = objectEnd + 1
|
|
737
786
|
}
|
|
738
787
|
|
|
739
788
|
return out
|
|
740
789
|
}
|
|
741
790
|
|
|
742
|
-
const
|
|
791
|
+
const escapeRegExp = (text: string): string =>
|
|
792
|
+
text.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")
|
|
793
|
+
|
|
794
|
+
const collectObjectEntryMapSources = (
|
|
795
|
+
script: string,
|
|
796
|
+
valueIdentifier: string,
|
|
797
|
+
): ReadonlySet<string> => {
|
|
743
798
|
const identifiers = new Set<string>()
|
|
744
|
-
|
|
799
|
+
const pattern = new RegExp(
|
|
800
|
+
`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*=>`,
|
|
801
|
+
"g",
|
|
802
|
+
)
|
|
803
|
+
|
|
804
|
+
for (const match of script.matchAll(pattern)) {
|
|
805
|
+
if (match[1] !== undefined) {
|
|
806
|
+
identifiers.add(match[1])
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
return identifiers
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
const rewriteDirectTemplates = (script: string): string => {
|
|
814
|
+
let out = script
|
|
815
|
+
|
|
816
|
+
for (const target of objectPropertyTargets) {
|
|
817
|
+
out = rewriteTemplateContents(
|
|
818
|
+
out,
|
|
819
|
+
(text, from) => findObjectPropertyTemplate(text, target, from),
|
|
820
|
+
escapeTemplateLiteralContent,
|
|
821
|
+
)
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
for (const functionName of callTemplateTargets) {
|
|
825
|
+
out = rewriteTemplateContents(
|
|
826
|
+
out,
|
|
827
|
+
(text, from) => findDirectCallTemplate(text, functionName, from),
|
|
828
|
+
escapeTemplateLiteralContent,
|
|
829
|
+
)
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
return out
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
const collectReferencedTemplateIdentifiers = (
|
|
836
|
+
script: string,
|
|
837
|
+
): {
|
|
838
|
+
readonly templateIdentifiers: ReadonlySet<string>
|
|
839
|
+
readonly objectIdentifiers: ReadonlySet<string>
|
|
840
|
+
} => {
|
|
841
|
+
const templateIdentifiers = new Set<string>()
|
|
842
|
+
|
|
843
|
+
for (const functionName of callTemplateTargets) {
|
|
745
844
|
for (const identifier of collectCallArgumentIdentifiers(
|
|
746
845
|
script,
|
|
747
846
|
functionName,
|
|
748
847
|
)) {
|
|
749
|
-
|
|
848
|
+
templateIdentifiers.add(identifier)
|
|
750
849
|
}
|
|
751
850
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
propertyName,
|
|
757
|
-
)) {
|
|
758
|
-
identifiers.add(identifier)
|
|
851
|
+
|
|
852
|
+
for (const target of objectPropertyTargets) {
|
|
853
|
+
for (const identifier of collectObjectPropertyIdentifiers(script, target)) {
|
|
854
|
+
templateIdentifiers.add(identifier)
|
|
759
855
|
}
|
|
760
856
|
}
|
|
857
|
+
|
|
761
858
|
if (script.includes("*** Begin Patch")) {
|
|
762
|
-
|
|
859
|
+
templateIdentifiers.add("patch")
|
|
763
860
|
}
|
|
764
861
|
|
|
765
|
-
const
|
|
766
|
-
for (const identifier of
|
|
767
|
-
for (const
|
|
768
|
-
|
|
769
|
-
identifier,
|
|
770
|
-
)) {
|
|
771
|
-
objectTemplateIdentifiers.add(sourceIdentifier)
|
|
862
|
+
const objectIdentifiers = new Set<string>()
|
|
863
|
+
for (const identifier of templateIdentifiers) {
|
|
864
|
+
for (const source of collectObjectEntryMapSources(script, identifier)) {
|
|
865
|
+
objectIdentifiers.add(source)
|
|
772
866
|
}
|
|
773
867
|
}
|
|
774
868
|
|
|
869
|
+
return {
|
|
870
|
+
templateIdentifiers,
|
|
871
|
+
objectIdentifiers,
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
const rewriteAssignedTargets = (script: string): string => {
|
|
876
|
+
const { templateIdentifiers, objectIdentifiers } =
|
|
877
|
+
collectReferencedTemplateIdentifiers(script)
|
|
878
|
+
|
|
775
879
|
let out = script
|
|
776
|
-
for (const identifier of
|
|
777
|
-
out =
|
|
880
|
+
for (const identifier of templateIdentifiers) {
|
|
881
|
+
out = rewriteAssignedTemplate(out, identifier)
|
|
778
882
|
}
|
|
779
|
-
for (const identifier of
|
|
780
|
-
out =
|
|
883
|
+
for (const identifier of objectIdentifiers) {
|
|
884
|
+
out = rewriteAssignedObjectLiteral(out, identifier)
|
|
781
885
|
}
|
|
886
|
+
|
|
782
887
|
return out
|
|
783
888
|
}
|
|
784
|
-
|
|
785
889
|
export const preprocessScript = (script: string): string =>
|
|
786
|
-
|
|
787
|
-
["applyPatch", "taskComplete"].reduce(
|
|
788
|
-
(current, functionName) => fixCallTemplateArgument(current, functionName),
|
|
789
|
-
fixTargetCallObjectPropertyTemplates(script),
|
|
790
|
-
),
|
|
791
|
-
)
|
|
890
|
+
rewriteAssignedTargets(rewriteDirectTemplates(script))
|