@thinksharpe/react-compiler-unmemo 0.5.5 → 0.5.6
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/README.md +1 -1
- package/helpers/remove-hooks.mjs +24 -6
- package/package.json +1 -1
- package/react-compiler-unmemo.mjs +2 -2
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://nodejs.org)
|
|
6
|
-
[](./tests)
|
|
7
7
|
|
|
8
8
|
A codemod that removes `useMemo` and `useCallback` from your React codebase so you can adopt [React Compiler](https://react.dev/learn/react-compiler) without the manual cleanup.
|
|
9
9
|
|
package/helpers/remove-hooks.mjs
CHANGED
|
@@ -24,6 +24,20 @@ import path from "path";
|
|
|
24
24
|
|
|
25
25
|
// ─── Core Parsing Helpers ────────────────────────────────────────────────────
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Check if the character at idx is escaped by counting consecutive
|
|
29
|
+
* backslashes before it. Odd count means escaped, even means not.
|
|
30
|
+
*/
|
|
31
|
+
export function isEscaped(str, idx) {
|
|
32
|
+
let count = 0;
|
|
33
|
+
let pos = idx - 1;
|
|
34
|
+
while (pos >= 0 && str[pos] === "\\") {
|
|
35
|
+
count++;
|
|
36
|
+
pos--;
|
|
37
|
+
}
|
|
38
|
+
return count % 2 === 1;
|
|
39
|
+
}
|
|
40
|
+
|
|
27
41
|
/**
|
|
28
42
|
* Find the matching closing paren for an opening paren at startIdx.
|
|
29
43
|
* Counts nested parens/brackets/braces and respects strings and template literals.
|
|
@@ -37,10 +51,9 @@ export function findClosingParen(content, startIdx) {
|
|
|
37
51
|
|
|
38
52
|
for (let i = startIdx; i < content.length; i++) {
|
|
39
53
|
const ch = content[i];
|
|
40
|
-
const prev = i > 0 ? content[i - 1] : "";
|
|
41
54
|
|
|
42
55
|
// Handle escape sequences
|
|
43
|
-
if ((inString || inTemplate) && ch === "\\" &&
|
|
56
|
+
if ((inString || inTemplate) && ch === "\\" && !isEscaped(content, i)) {
|
|
44
57
|
i++; // skip next char
|
|
45
58
|
continue;
|
|
46
59
|
}
|
|
@@ -124,7 +137,7 @@ export function stripDepsArray(inner) {
|
|
|
124
137
|
const ch = inner[i];
|
|
125
138
|
|
|
126
139
|
// Simple string tracking
|
|
127
|
-
if ((ch === '"' || ch === "'" || ch === "`") && (
|
|
140
|
+
if ((ch === '"' || ch === "'" || ch === "`") && !isEscaped(inner, i)) {
|
|
128
141
|
if (!inString) {
|
|
129
142
|
inString = true;
|
|
130
143
|
stringChar = ch;
|
|
@@ -178,7 +191,7 @@ export function unwrapArrowFn(inner) {
|
|
|
178
191
|
for (let i = 0; i < inner.length - 1; i++) {
|
|
179
192
|
const ch = inner[i];
|
|
180
193
|
|
|
181
|
-
if ((ch === '"' || ch === "'" || ch === "`") && (
|
|
194
|
+
if ((ch === '"' || ch === "'" || ch === "`") && !isEscaped(inner, i)) {
|
|
182
195
|
if (!inString) {
|
|
183
196
|
inString = true;
|
|
184
197
|
stringChar = ch;
|
|
@@ -482,8 +495,8 @@ export function processFile(filePath, { dryRun = false } = {}) {
|
|
|
482
495
|
if (!found) break;
|
|
483
496
|
}
|
|
484
497
|
|
|
485
|
-
// Phase 3: Clean up imports (
|
|
486
|
-
|
|
498
|
+
// Phase 3: Clean up imports (always run — hooks are unnecessary with React Compiler)
|
|
499
|
+
{
|
|
487
500
|
const importPatterns = [
|
|
488
501
|
{
|
|
489
502
|
regex: /import React, \{([^}]*)\} from (["'])react\2[^\S\n]*;?/g,
|
|
@@ -534,6 +547,11 @@ export function processFile(filePath, { dryRun = false } = {}) {
|
|
|
534
547
|
content = content.replace(/\n\n\n+/g, "\n\n");
|
|
535
548
|
}
|
|
536
549
|
|
|
550
|
+
// Track if imports were cleaned even without hook call changes
|
|
551
|
+
if (content !== original) {
|
|
552
|
+
changed = true;
|
|
553
|
+
}
|
|
554
|
+
|
|
537
555
|
if (changed && !dryRun) {
|
|
538
556
|
fs.writeFileSync(filePath, content);
|
|
539
557
|
}
|
package/package.json
CHANGED
|
@@ -34,7 +34,7 @@ import { run as removeHooks } from "./helpers/remove-hooks.mjs";
|
|
|
34
34
|
|
|
35
35
|
const args = process.argv.slice(2);
|
|
36
36
|
|
|
37
|
-
if (args.includes("--version") || args.includes("-v")) {
|
|
37
|
+
if (args.includes("--version") || args.includes("-v") || args[0] === "version") {
|
|
38
38
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
39
39
|
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, "package.json"), "utf8"));
|
|
40
40
|
console.log(pkg.version);
|
|
@@ -63,7 +63,7 @@ if (!targetDir) {
|
|
|
63
63
|
console.log(" --verbose Show detailed output per transformation");
|
|
64
64
|
console.log(" --files <glob> File glob pattern (default: src/**/*.{tsx,ts})");
|
|
65
65
|
console.log(" --skip-fix Skip the type annotation fix step");
|
|
66
|
-
console.log(" --version, -v Show version number");
|
|
66
|
+
console.log(" --version, -v Show version number (use 'version' subcommand with npx)");
|
|
67
67
|
console.log();
|
|
68
68
|
console.log("Examples:");
|
|
69
69
|
console.log(" npx react-compiler-unmemo ./my-react-app # preview (safe default)");
|