@thinksharpe/react-compiler-unmemo 0.5.0
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/LICENSE +21 -0
- package/README.md +158 -0
- package/docs/architecture.md +157 -0
- package/docs/edge-cases.md +247 -0
- package/helpers/fix-type-annotations.mjs +153 -0
- package/helpers/remove-hooks.mjs +522 -0
- package/package.json +51 -0
- package/react-compiler-unmemo.mjs +128 -0
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@thinksharpe/react-compiler-unmemo",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Remove useMemo and useCallback hooks from React codebases to leverage React Compiler automatic optimization",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"author": "Thinksharpe",
|
|
8
|
+
"homepage": "https://github.com/thinksharpe/react-compiler-unmemo",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/thinksharpe/react-compiler-unmemo.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/thinksharpe/react-compiler-unmemo/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react",
|
|
18
|
+
"react-compiler",
|
|
19
|
+
"react-19",
|
|
20
|
+
"useMemo",
|
|
21
|
+
"useCallback",
|
|
22
|
+
"codemod",
|
|
23
|
+
"migration",
|
|
24
|
+
"performance",
|
|
25
|
+
"automatic-memoization"
|
|
26
|
+
],
|
|
27
|
+
"bin": {
|
|
28
|
+
"react-compiler-unmemo": "react-compiler-unmemo.mjs"
|
|
29
|
+
},
|
|
30
|
+
"main": "./react-compiler-unmemo.mjs",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": "./react-compiler-unmemo.mjs"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"react-compiler-unmemo.mjs",
|
|
36
|
+
"helpers/",
|
|
37
|
+
"docs/",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
],
|
|
41
|
+
"scripts": {
|
|
42
|
+
"start": "node react-compiler-unmemo.mjs"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"glob": "^11.0.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {}
|
|
51
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* react-compiler-unmemo.mjs
|
|
5
|
+
*
|
|
6
|
+
* Runner that executes the full React Compiler hook removal pipeline:
|
|
7
|
+
* 1. Remove useMemo/useCallback hooks
|
|
8
|
+
* 2. Fix type annotations lost during removal
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* npx react-compiler-unmemo <directory> [options]
|
|
12
|
+
*
|
|
13
|
+
* Options:
|
|
14
|
+
* --write Apply changes to files (default is dry-run / preview)
|
|
15
|
+
* --verbose Show detailed output for each transformation
|
|
16
|
+
* --files <glob> File glob pattern (default: helpers/**\/*.{tsx,ts})
|
|
17
|
+
* --skip-fix Skip the type annotation fix step
|
|
18
|
+
*
|
|
19
|
+
* Examples:
|
|
20
|
+
* npx react-compiler-unmemo ./my-react-app # preview (dry-run)
|
|
21
|
+
* npx react-compiler-unmemo ./my-react-app --write # apply changes
|
|
22
|
+
* npx react-compiler-unmemo ./my-react-app --write --verbose
|
|
23
|
+
* npx react-compiler-unmemo /absolute/path/to/project --files "app/**\/*.tsx"
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import path from "path";
|
|
27
|
+
import { run as fixTypes } from "./helpers/fix-type-annotations.mjs";
|
|
28
|
+
import { run as removeHooks } from "./helpers/remove-hooks.mjs";
|
|
29
|
+
|
|
30
|
+
// ─── CLI ─────────────────────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
const args = process.argv.slice(2);
|
|
33
|
+
const write = args.includes("--write");
|
|
34
|
+
const dryRun = !write;
|
|
35
|
+
const verbose = args.includes("--verbose");
|
|
36
|
+
const skipFix = args.includes("--skip-fix");
|
|
37
|
+
|
|
38
|
+
const filesIdx = args.indexOf("--files");
|
|
39
|
+
const fileGlob = filesIdx !== -1 && args[filesIdx + 1] ? args[filesIdx + 1] : undefined;
|
|
40
|
+
|
|
41
|
+
// First positional arg is the directory
|
|
42
|
+
const positionalArgs = args.filter(
|
|
43
|
+
(a) => !a.startsWith("--") && (args.indexOf(a) === 0 || !["--files", "--dir"].includes(args[args.indexOf(a) - 1])),
|
|
44
|
+
);
|
|
45
|
+
const targetDir = positionalArgs[0] ? path.resolve(positionalArgs[0]) : null;
|
|
46
|
+
|
|
47
|
+
if (!targetDir) {
|
|
48
|
+
console.log("Usage: npx react-compiler-unmemo <directory> [options]");
|
|
49
|
+
console.log();
|
|
50
|
+
console.log("Options:");
|
|
51
|
+
console.log(" --write Apply changes to files (default is preview/dry-run)");
|
|
52
|
+
console.log(" --verbose Show detailed output per transformation");
|
|
53
|
+
console.log(" --files <glob> File glob pattern (default: src/**/*.{tsx,ts})");
|
|
54
|
+
console.log(" --skip-fix Skip the type annotation fix step");
|
|
55
|
+
console.log();
|
|
56
|
+
console.log("Examples:");
|
|
57
|
+
console.log(" npx react-compiler-unmemo ./my-react-app # preview (safe default)");
|
|
58
|
+
console.log(" npx react-compiler-unmemo ./my-react-app --write # apply changes");
|
|
59
|
+
console.log(" npx react-compiler-unmemo ./my-react-app --write --verbose");
|
|
60
|
+
console.log(' npx react-compiler-unmemo /path/to/project --files "app/**/*.tsx"');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ─── Step 1: Remove hooks ────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
console.log("━".repeat(60));
|
|
67
|
+
console.log(" Step 1/2: Remove useMemo & useCallback");
|
|
68
|
+
console.log("━".repeat(60));
|
|
69
|
+
console.log();
|
|
70
|
+
|
|
71
|
+
const hookResult = removeHooks(targetDir, { fileGlob, dryRun, verbose });
|
|
72
|
+
|
|
73
|
+
// ─── Step 2: Fix type annotations ────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
if (!skipFix) {
|
|
76
|
+
console.log();
|
|
77
|
+
console.log("━".repeat(60));
|
|
78
|
+
console.log(" Step 2/2: Fix type annotations");
|
|
79
|
+
console.log("━".repeat(60));
|
|
80
|
+
console.log();
|
|
81
|
+
|
|
82
|
+
const fixResult = fixTypes(targetDir, { fileGlob, dryRun });
|
|
83
|
+
|
|
84
|
+
// ─── Summary ─────────────────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
console.log();
|
|
87
|
+
console.log("═".repeat(60));
|
|
88
|
+
console.log(" Summary");
|
|
89
|
+
console.log("═".repeat(60));
|
|
90
|
+
console.log();
|
|
91
|
+
console.log(` Files modified: ${hookResult.changedCount}`);
|
|
92
|
+
console.log(` Hooks removed: ${hookResult.totalTransformations}`);
|
|
93
|
+
console.log(` Types fixed: ${fixResult.fixCount}`);
|
|
94
|
+
console.log(` Errors: ${hookResult.errors.length + fixResult.errors.length}`);
|
|
95
|
+
if (hookResult.remaining.length > 0) {
|
|
96
|
+
console.log(` Remaining refs: ${hookResult.remaining.length} files`);
|
|
97
|
+
}
|
|
98
|
+
if (dryRun) {
|
|
99
|
+
console.log();
|
|
100
|
+
console.log(" (dry run — no files were written)");
|
|
101
|
+
console.log(" Run with --write to apply changes.");
|
|
102
|
+
} else {
|
|
103
|
+
console.log();
|
|
104
|
+
console.log(" Next steps:");
|
|
105
|
+
console.log(" 1. Run your build tool to check for type errors");
|
|
106
|
+
console.log(" 2. Review docs/edge-cases.md for known manual fixes");
|
|
107
|
+
console.log(" 3. Run again if new files are added");
|
|
108
|
+
}
|
|
109
|
+
console.log();
|
|
110
|
+
|
|
111
|
+
const hasErrors = hookResult.errors.length + fixResult.errors.length > 0;
|
|
112
|
+
process.exit(hasErrors ? 1 : 0);
|
|
113
|
+
} else {
|
|
114
|
+
console.log();
|
|
115
|
+
console.log("═".repeat(60));
|
|
116
|
+
console.log(" Summary (type fix skipped)");
|
|
117
|
+
console.log("═".repeat(60));
|
|
118
|
+
console.log();
|
|
119
|
+
console.log(` Files modified: ${hookResult.changedCount}`);
|
|
120
|
+
console.log(` Hooks removed: ${hookResult.totalTransformations}`);
|
|
121
|
+
console.log(` Errors: ${hookResult.errors.length}`);
|
|
122
|
+
if (hookResult.remaining.length > 0) {
|
|
123
|
+
console.log(` Remaining refs: ${hookResult.remaining.length} files`);
|
|
124
|
+
}
|
|
125
|
+
console.log();
|
|
126
|
+
|
|
127
|
+
process.exit(hookResult.errors.length > 0 ? 1 : 0);
|
|
128
|
+
}
|