@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 CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
5
5
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=flat-square)](https://nodejs.org)
6
- [![Tests](https://img.shields.io/badge/tests-69%20passing-brightgreen?style=flat-square)](./tests)
6
+ [![Tests](https://img.shields.io/badge/tests-74%20passing-brightgreen?style=flat-square)](./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
 
@@ -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 === "\\" && prev !== "\\") {
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 === "`") && (i === 0 || inner[i - 1] !== "\\")) {
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 === "`") && (i === 0 || inner[i - 1] !== "\\")) {
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 (skip matches inside strings/comments)
486
- if (changed) {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thinksharpe/react-compiler-unmemo",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
4
  "description": "Remove useMemo and useCallback hooks from React codebases to leverage React Compiler automatic optimization",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -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)");