|
1 | 1 | // Please see the note about writing patches in ./index |
2 | 2 |
|
3 | | -import { LocationResult, showDiff } from './index'; |
| 3 | +import { showDiff } from './index'; |
4 | 4 |
|
5 | | -const getVerbosePropertyLocation = (oldFile: string): LocationResult | null => { |
6 | | - // Older CC shape: createElement(X, {...spinnerTip...overrideMessage...}) |
| 5 | +interface VerboseEdit { |
| 6 | + startIndex: number; |
| 7 | + endIndex: number; |
| 8 | + replacement: string; |
| 9 | +} |
| 10 | + |
| 11 | +const getVerbosePropertyEdit = (oldFile: string): VerboseEdit | null => { |
| 12 | + // Older CC shape: createElement(X, {...spinnerTip...overrideMessage...}). |
| 13 | + // Here, `verbose:X` is an object-literal value and can be safely replaced |
| 14 | + // with the literal `verbose:true`. |
7 | 15 | const createElementPattern = |
8 | 16 | /createElement\([$\w]+,\{[^}]+spinnerTip[^}]+overrideMessage[^}]+\}/; |
9 | | - // CC >= 2.1.113: the spinner component receives its props as a destructured |
10 | | - // function parameter rather than a createElement object literal, and |
11 | | - // spinnerTip is no longer on the same object (it's pulled from state |
12 | | - // separately). Anchor on overrideMessage + verbose instead. |
13 | | - const destructurePattern = |
14 | | - /\{[^{}]{0,400}overrideMessage:[$\w]+,[^{}]{0,200}verbose:[^,}]+[^{}]{0,200}\}/; |
15 | | - |
16 | | - const createElementMatch = |
17 | | - oldFile.match(createElementPattern) || oldFile.match(destructurePattern); |
18 | | - |
19 | | - if (!createElementMatch || createElementMatch.index === undefined) { |
20 | | - console.error( |
21 | | - 'patch: verbose: failed to find spinner props containing overrideMessage and verbose' |
22 | | - ); |
23 | | - return null; |
| 17 | + const objLitMatch = oldFile.match(createElementPattern); |
| 18 | + if (objLitMatch && objLitMatch.index !== undefined) { |
| 19 | + const verboseMatch = objLitMatch[0].match(/verbose:[^,}]+/); |
| 20 | + if (!verboseMatch || verboseMatch.index === undefined) { |
| 21 | + console.error('patch: verbose: failed to find verbose property'); |
| 22 | + return null; |
| 23 | + } |
| 24 | + const start = objLitMatch.index + verboseMatch.index; |
| 25 | + return { |
| 26 | + startIndex: start, |
| 27 | + endIndex: start + verboseMatch[0].length, |
| 28 | + replacement: 'verbose:true', |
| 29 | + }; |
24 | 30 | } |
25 | 31 |
|
26 | | - const extractedString = createElementMatch[0]; |
27 | | - |
28 | | - const verbosePattern = /verbose:[^,}]+/; |
29 | | - const verboseMatch = extractedString.match(verbosePattern); |
30 | | - |
31 | | - if (!verboseMatch || verboseMatch.index === undefined) { |
32 | | - console.error('patch: verbose: failed to find verbose property'); |
33 | | - return null; |
| 32 | + // CC >= 2.1.113: props are a destructured function parameter |
| 33 | + // function X({...,overrideMessage:z,spinnerSuffix:M,verbose:Y,...}){...} |
| 34 | + // Replacing `verbose:Y` with `verbose:true` is a SyntaxError in this |
| 35 | + // context (the right-hand side of a destructure binding must be an |
| 36 | + // assignment target, not a literal). Instead: leave the destructure alone |
| 37 | + // and inject `Y=!0;` at the start of the function body so the local |
| 38 | + // variable is always forced true regardless of caller. |
| 39 | + const destructurePattern = |
| 40 | + /\{[^{}]{0,400}overrideMessage:[$\w]+,[^{}]{0,200}verbose:([$\w]+)[^{}]{0,200}\}\)\{/; |
| 41 | + const destructureMatch = oldFile.match(destructurePattern); |
| 42 | + if (destructureMatch && destructureMatch.index !== undefined) { |
| 43 | + const varName = destructureMatch[1]; |
| 44 | + // Position right after the `){` that opens the function body |
| 45 | + const bodyStart = destructureMatch.index + destructureMatch[0].length; |
| 46 | + return { |
| 47 | + startIndex: bodyStart, |
| 48 | + endIndex: bodyStart, |
| 49 | + replacement: `${varName}=!0;`, |
| 50 | + }; |
34 | 51 | } |
35 | 52 |
|
36 | | - // Calculate absolute positions in the original file |
37 | | - const absoluteVerboseStart = createElementMatch.index + verboseMatch.index; |
38 | | - const absoluteVerboseEnd = absoluteVerboseStart + verboseMatch[0].length; |
39 | | - |
40 | | - return { |
41 | | - startIndex: absoluteVerboseStart, |
42 | | - endIndex: absoluteVerboseEnd, |
43 | | - }; |
| 53 | + console.error( |
| 54 | + 'patch: verbose: failed to find spinner props containing overrideMessage and verbose' |
| 55 | + ); |
| 56 | + return null; |
44 | 57 | }; |
45 | 58 |
|
46 | 59 | export const writeVerboseProperty = (oldFile: string): string | null => { |
47 | | - const location = getVerbosePropertyLocation(oldFile); |
48 | | - if (!location) { |
| 60 | + const edit = getVerbosePropertyEdit(oldFile); |
| 61 | + if (!edit) { |
49 | 62 | return null; |
50 | 63 | } |
51 | 64 |
|
52 | | - const newCode = 'verbose:true'; |
53 | 65 | const newFile = |
54 | | - oldFile.slice(0, location.startIndex) + |
55 | | - newCode + |
56 | | - oldFile.slice(location.endIndex); |
| 66 | + oldFile.slice(0, edit.startIndex) + |
| 67 | + edit.replacement + |
| 68 | + oldFile.slice(edit.endIndex); |
57 | 69 |
|
58 | | - showDiff(oldFile, newFile, newCode, location.startIndex, location.endIndex); |
| 70 | + showDiff(oldFile, newFile, edit.replacement, edit.startIndex, edit.endIndex); |
59 | 71 | return newFile; |
60 | 72 | }; |
0 commit comments