@ceraph/react-native-mcp 0.3.3 → 0.4.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 +335 -68
- package/dist/babel-plugin/index.cjs +1 -0
- package/dist/babel-plugin/index.js +1 -0
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +1 -47
- package/dist/index.d.ts +106 -1
- package/dist/index.js +2 -1651
- package/dist/shim/async-storage-ops.d.ts +26 -0
- package/dist/shim/async-storage-ops.js +1 -0
- package/dist/shim/boot.d.ts +9 -0
- package/dist/shim/boot.js +1 -141
- package/dist/shim/camera.js +1 -62
- package/dist/shim/command-poll.d.ts +18 -0
- package/dist/shim/command-poll.js +1 -0
- package/dist/shim/config.js +1 -56
- package/dist/shim/console-capture.d.ts +16 -0
- package/dist/shim/console-capture.js +1 -0
- package/dist/shim/deep-link.js +1 -25
- package/dist/shim/dev-guard.js +1 -3
- package/dist/shim/dev-host.d.ts +1 -0
- package/dist/shim/dev-host.js +1 -0
- package/dist/shim/error-handler.js +1 -66
- package/dist/shim/fetch-interceptor.js +1 -93
- package/dist/shim/index.d.ts +3 -0
- package/dist/shim/index.js +1 -6
- package/dist/shim/keep-awake.js +1 -118
- package/dist/shim/network-ownership.d.ts +4 -0
- package/dist/shim/network-ownership.js +1 -0
- package/dist/shim/optimistic-observer.d.ts +29 -0
- package/dist/shim/optimistic-observer.js +1 -0
- package/dist/shim/reload.js +1 -76
- package/dist/shim/reset.d.ts +30 -0
- package/dist/shim/reset.js +1 -0
- package/dist/shim/signal-capture.d.ts +8 -0
- package/dist/shim/signal-capture.js +1 -15
- package/dist/shim/signal-transport.d.ts +14 -1
- package/dist/shim/signal-transport.js +1 -43
- package/dist/shim/xhr-interceptor.d.ts +39 -0
- package/dist/shim/xhr-interceptor.js +1 -0
- package/package.json +40 -11
- package/dist/app-lifecycle.d.ts +0 -50
- package/dist/app-lifecycle.js +0 -487
- package/dist/camera-image-writer.d.ts +0 -43
- package/dist/camera-image-writer.js +0 -280
- package/dist/camera-registry-sync.d.ts +0 -18
- package/dist/camera-registry-sync.js +0 -117
- package/dist/device-autonomy.d.ts +0 -30
- package/dist/device-autonomy.js +0 -117
- package/dist/error-parser.d.ts +0 -51
- package/dist/error-parser.js +0 -275
- package/dist/expo-manager.d.ts +0 -62
- package/dist/expo-manager.js +0 -447
- package/dist/init/ast-camera.d.ts +0 -29
- package/dist/init/ast-camera.js +0 -267
- package/dist/init/ast-layout.d.ts +0 -15
- package/dist/init/ast-layout.js +0 -167
- package/dist/init/claude-hook-constants.d.ts +0 -9
- package/dist/init/claude-hook-constants.js +0 -91
- package/dist/init/lan-ip.d.ts +0 -11
- package/dist/init/lan-ip.js +0 -51
- package/dist/init/monorepo.d.ts +0 -13
- package/dist/init/monorepo.js +0 -185
- package/dist/init/oauth.d.ts +0 -52
- package/dist/init/oauth.js +0 -220
- package/dist/init/package-manager.d.ts +0 -11
- package/dist/init/package-manager.js +0 -60
- package/dist/init/prompt.d.ts +0 -12
- package/dist/init/prompt.js +0 -68
- package/dist/init/shell-profile.d.ts +0 -22
- package/dist/init/shell-profile.js +0 -85
- package/dist/init/steps.d.ts +0 -135
- package/dist/init/steps.js +0 -399
- package/dist/init/url-scheme.d.ts +0 -42
- package/dist/init/url-scheme.js +0 -187
- package/dist/init/walkthrough.d.ts +0 -76
- package/dist/init/walkthrough.js +0 -340
- package/dist/init.d.ts +0 -8
- package/dist/init.js +0 -395
- package/dist/iproxy-manager.d.ts +0 -32
- package/dist/iproxy-manager.js +0 -216
- package/dist/mac-caffeinate.d.ts +0 -10
- package/dist/mac-caffeinate.js +0 -56
- package/dist/permission-interceptor.d.ts +0 -29
- package/dist/permission-interceptor.js +0 -185
- package/dist/prebuild-detector.d.ts +0 -19
- package/dist/prebuild-detector.js +0 -174
- package/dist/preflight.d.ts +0 -34
- package/dist/preflight.js +0 -847
- package/dist/screen.d.ts +0 -184
- package/dist/screen.js +0 -931
- package/dist/signal-listener.d.ts +0 -27
- package/dist/signal-listener.js +0 -135
- package/dist/simulator-boot.d.ts +0 -52
- package/dist/simulator-boot.js +0 -227
- package/dist/target.d.ts +0 -48
- package/dist/target.js +0 -267
- package/dist/uninstall/cli-runner.d.ts +0 -32
- package/dist/uninstall/cli-runner.js +0 -223
- package/dist/uninstall/footprint.d.ts +0 -40
- package/dist/uninstall/footprint.js +0 -288
- package/dist/uninstall/mcp-tools.d.ts +0 -14
- package/dist/uninstall/mcp-tools.js +0 -175
- package/dist/uninstall/revert-auth.d.ts +0 -22
- package/dist/uninstall/revert-auth.js +0 -31
- package/dist/uninstall/revert-boot.d.ts +0 -24
- package/dist/uninstall/revert-boot.js +0 -242
- package/dist/uninstall/revert-camera.d.ts +0 -12
- package/dist/uninstall/revert-camera.js +0 -199
- package/dist/uninstall/revert-ceraph-dir.d.ts +0 -27
- package/dist/uninstall/revert-ceraph-dir.js +0 -38
- package/dist/uninstall/revert-claude-hooks.d.ts +0 -19
- package/dist/uninstall/revert-claude-hooks.js +0 -191
- package/dist/uninstall/revert-gitignore.d.ts +0 -17
- package/dist/uninstall/revert-gitignore.js +0 -43
- package/dist/uninstall/revert-mcp-clients.d.ts +0 -57
- package/dist/uninstall/revert-mcp-clients.js +0 -194
- package/dist/uninstall/revert-package.d.ts +0 -34
- package/dist/uninstall/revert-package.js +0 -98
- package/dist/uninstall/revert-scheme.d.ts +0 -36
- package/dist/uninstall/revert-scheme.js +0 -139
- package/dist/uninstall/revert-signal-host-env.d.ts +0 -31
- package/dist/uninstall/revert-signal-host-env.js +0 -61
- package/dist/uninstall/walkthrough.d.ts +0 -80
- package/dist/uninstall/walkthrough.js +0 -1244
- package/dist/utils/atomic-write.d.ts +0 -1
- package/dist/utils/atomic-write.js +0 -30
- package/dist/wait-for-device.d.ts +0 -68
- package/dist/wait-for-device.js +0 -368
- package/dist/wda-manager.d.ts +0 -38
- package/dist/wda-manager.js +0 -186
- package/dist/wda-simulator.d.ts +0 -28
- package/dist/wda-simulator.js +0 -257
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { IndentationText, Node, Project, SyntaxKind, } from "ts-morph";
|
|
4
|
-
const SHIM_MODULE = "@ceraph/react-native-mcp/shim";
|
|
5
|
-
const INSTALL_CALL = "installCeraph";
|
|
6
|
-
async function fileExists(path) {
|
|
7
|
-
try {
|
|
8
|
-
await readFile(path, "utf-8");
|
|
9
|
-
return true;
|
|
10
|
-
}
|
|
11
|
-
catch {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
export async function detectRevertTarget(projectDir) {
|
|
16
|
-
const expo = join(projectDir, "app", "_layout.tsx");
|
|
17
|
-
if (await fileExists(expo)) {
|
|
18
|
-
return { kind: "expo-router", filePath: expo };
|
|
19
|
-
}
|
|
20
|
-
const expoJsx = join(projectDir, "app", "_layout.jsx");
|
|
21
|
-
if (await fileExists(expoJsx)) {
|
|
22
|
-
return { kind: "expo-router", filePath: expoJsx };
|
|
23
|
-
}
|
|
24
|
-
for (const name of ["App.tsx", "App.jsx"]) {
|
|
25
|
-
const p = join(projectDir, name);
|
|
26
|
-
if (await fileExists(p)) {
|
|
27
|
-
return { kind: "bare-rn", filePath: p };
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
function findDefaultExportFunction(source) {
|
|
33
|
-
for (const fn of source.getFunctions()) {
|
|
34
|
-
if (fn.isDefaultExport())
|
|
35
|
-
return fn;
|
|
36
|
-
}
|
|
37
|
-
const exportAssignment = source
|
|
38
|
-
.getStatements()
|
|
39
|
-
.find((s) => Node.isExportAssignment(s));
|
|
40
|
-
if (exportAssignment && Node.isExportAssignment(exportAssignment)) {
|
|
41
|
-
const expr = exportAssignment.getExpression();
|
|
42
|
-
if (Node.isIdentifier(expr)) {
|
|
43
|
-
const symbol = expr.getSymbol();
|
|
44
|
-
if (symbol) {
|
|
45
|
-
const decl = symbol.getDeclarations()[0];
|
|
46
|
-
if (decl && Node.isVariableDeclaration(decl)) {
|
|
47
|
-
const init = decl.getInitializer();
|
|
48
|
-
if (init && Node.isArrowFunction(init))
|
|
49
|
-
return init;
|
|
50
|
-
if (init && Node.isFunctionExpression(init))
|
|
51
|
-
return init;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if (Node.isArrowFunction(expr))
|
|
56
|
-
return expr;
|
|
57
|
-
if (Node.isFunctionExpression(expr))
|
|
58
|
-
return expr;
|
|
59
|
-
}
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
function isSoloInstallCeraphStatement(stmt) {
|
|
63
|
-
if (Node.isExpressionStatement(stmt)) {
|
|
64
|
-
const expr = stmt.getExpression();
|
|
65
|
-
if (Node.isCallExpression(expr)) {
|
|
66
|
-
const callee = expr.getExpression();
|
|
67
|
-
if (Node.isIdentifier(callee) && callee.getText() === INSTALL_CALL) {
|
|
68
|
-
return true;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
function classifyUseEffect(call) {
|
|
75
|
-
const args = call.getArguments();
|
|
76
|
-
if (args.length === 0)
|
|
77
|
-
return "unrelated";
|
|
78
|
-
const callback = args[0];
|
|
79
|
-
let body = null;
|
|
80
|
-
if (Node.isArrowFunction(callback) || Node.isFunctionExpression(callback)) {
|
|
81
|
-
const b = callback.getBody();
|
|
82
|
-
if (Node.isBlock(b))
|
|
83
|
-
body = b;
|
|
84
|
-
else {
|
|
85
|
-
if (Node.isCallExpression(b)) {
|
|
86
|
-
const callee = b.getExpression();
|
|
87
|
-
if (Node.isIdentifier(callee) && callee.getText() === INSTALL_CALL) {
|
|
88
|
-
return "installCeraph-only";
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return "unrelated";
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
return "unrelated";
|
|
96
|
-
}
|
|
97
|
-
if (!body)
|
|
98
|
-
return "unrelated";
|
|
99
|
-
const statements = body.getStatements();
|
|
100
|
-
if (statements.length === 0)
|
|
101
|
-
return "unrelated";
|
|
102
|
-
let hasInstallCeraph = false;
|
|
103
|
-
let hasOthers = false;
|
|
104
|
-
for (const s of statements) {
|
|
105
|
-
if (isSoloInstallCeraphStatement(s)) {
|
|
106
|
-
hasInstallCeraph = true;
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
hasOthers = true;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (!hasInstallCeraph)
|
|
113
|
-
return "unrelated";
|
|
114
|
-
return hasOthers ? "installCeraph-with-others" : "installCeraph-only";
|
|
115
|
-
}
|
|
116
|
-
function listUseEffectsInBody(fn) {
|
|
117
|
-
const block = fn.getBody();
|
|
118
|
-
if (!block || !Node.isBlock(block))
|
|
119
|
-
return [];
|
|
120
|
-
const out = [];
|
|
121
|
-
block.forEachDescendant((node) => {
|
|
122
|
-
if (Node.isCallExpression(node)) {
|
|
123
|
-
const callee = node.getExpression();
|
|
124
|
-
if (Node.isIdentifier(callee) && callee.getText() === "useEffect") {
|
|
125
|
-
out.push(node);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
return out;
|
|
130
|
-
}
|
|
131
|
-
function dropUseEffectImportIfOrphan(source) {
|
|
132
|
-
const decl = source.getImportDeclaration("react");
|
|
133
|
-
if (!decl)
|
|
134
|
-
return false;
|
|
135
|
-
const named = decl.getNamedImports();
|
|
136
|
-
const target = named.find((n) => n.getName() === "useEffect");
|
|
137
|
-
if (!target)
|
|
138
|
-
return false;
|
|
139
|
-
const aliasNode = target.getAliasNode();
|
|
140
|
-
if (aliasNode)
|
|
141
|
-
return false;
|
|
142
|
-
let stillReferenced = false;
|
|
143
|
-
source.forEachDescendant((node) => {
|
|
144
|
-
if (stillReferenced)
|
|
145
|
-
return;
|
|
146
|
-
if (Node.isIdentifier(node) && node.getText() === "useEffect") {
|
|
147
|
-
const parent = node.getParent();
|
|
148
|
-
if (parent && (Node.isImportSpecifier(parent) || Node.isImportClause(parent))) {
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
stillReferenced = true;
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
if (stillReferenced)
|
|
155
|
-
return false;
|
|
156
|
-
target.remove();
|
|
157
|
-
const remaining = decl.getNamedImports();
|
|
158
|
-
const hasDefault = decl.getDefaultImport() != null;
|
|
159
|
-
const hasNamespace = decl.getNamespaceImport() != null;
|
|
160
|
-
if (remaining.length === 0 && !hasDefault && !hasNamespace) {
|
|
161
|
-
decl.remove();
|
|
162
|
-
}
|
|
163
|
-
return true;
|
|
164
|
-
}
|
|
165
|
-
function removeInstallCeraphImport(source) {
|
|
166
|
-
const decl = source.getImportDeclaration(SHIM_MODULE);
|
|
167
|
-
if (!decl)
|
|
168
|
-
return false;
|
|
169
|
-
const named = decl.getNamedImports();
|
|
170
|
-
const target = named.find((n) => n.getName() === INSTALL_CALL);
|
|
171
|
-
if (!target)
|
|
172
|
-
return false;
|
|
173
|
-
target.remove();
|
|
174
|
-
const remaining = decl.getNamedImports();
|
|
175
|
-
const hasDefault = decl.getDefaultImport() != null;
|
|
176
|
-
if (remaining.length === 0 && !hasDefault) {
|
|
177
|
-
decl.remove();
|
|
178
|
-
}
|
|
179
|
-
return true;
|
|
180
|
-
}
|
|
181
|
-
export async function revertBoot(projectDir) {
|
|
182
|
-
const target = await detectRevertTarget(projectDir);
|
|
183
|
-
if (!target) {
|
|
184
|
-
return { status: "no-layout-found" };
|
|
185
|
-
}
|
|
186
|
-
const project = new Project({
|
|
187
|
-
useInMemoryFileSystem: false,
|
|
188
|
-
skipAddingFilesFromTsConfig: true,
|
|
189
|
-
skipFileDependencyResolution: true,
|
|
190
|
-
skipLoadingLibFiles: true,
|
|
191
|
-
compilerOptions: { allowJs: true, jsx: 1 },
|
|
192
|
-
manipulationSettings: { indentationText: IndentationText.TwoSpaces },
|
|
193
|
-
});
|
|
194
|
-
const source = project.addSourceFileAtPath(target.filePath);
|
|
195
|
-
const fn = findDefaultExportFunction(source);
|
|
196
|
-
if (!fn) {
|
|
197
|
-
const removedImport = removeInstallCeraphImport(source);
|
|
198
|
-
if (removedImport) {
|
|
199
|
-
await writeFile(target.filePath, source.getFullText(), "utf-8");
|
|
200
|
-
return {
|
|
201
|
-
status: "reverted",
|
|
202
|
-
target,
|
|
203
|
-
removedUseEffect: false,
|
|
204
|
-
removedImport: true,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
return { status: "already-reverted", target };
|
|
208
|
-
}
|
|
209
|
-
const useEffects = listUseEffectsInBody(fn);
|
|
210
|
-
const candidates = useEffects.map((u) => ({ call: u, kind: classifyUseEffect(u) }));
|
|
211
|
-
const soloCandidates = candidates.filter((c) => c.kind === "installCeraph-only");
|
|
212
|
-
const mixedCandidates = candidates.filter((c) => c.kind === "installCeraph-with-others");
|
|
213
|
-
if (mixedCandidates.length > 0) {
|
|
214
|
-
return {
|
|
215
|
-
status: "skipped",
|
|
216
|
-
target,
|
|
217
|
-
reason: "useEffect contains other statements",
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
let removedUseEffect = false;
|
|
221
|
-
for (const c of soloCandidates) {
|
|
222
|
-
const stmt = c.call.getFirstAncestorByKind(SyntaxKind.ExpressionStatement);
|
|
223
|
-
if (stmt) {
|
|
224
|
-
stmt.remove();
|
|
225
|
-
removedUseEffect = true;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
const removedImport = removeInstallCeraphImport(source);
|
|
229
|
-
if (removedUseEffect) {
|
|
230
|
-
dropUseEffectImportIfOrphan(source);
|
|
231
|
-
}
|
|
232
|
-
if (!removedUseEffect && !removedImport) {
|
|
233
|
-
return { status: "already-reverted", target };
|
|
234
|
-
}
|
|
235
|
-
await writeFile(target.filePath, source.getFullText(), "utf-8");
|
|
236
|
-
return {
|
|
237
|
-
status: "reverted",
|
|
238
|
-
target,
|
|
239
|
-
removedUseEffect,
|
|
240
|
-
removedImport,
|
|
241
|
-
};
|
|
242
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export interface CameraFileRevertResult {
|
|
2
|
-
path: string;
|
|
3
|
-
relPath: string;
|
|
4
|
-
ceraphCamerasRemoved: number;
|
|
5
|
-
importDropped: boolean;
|
|
6
|
-
importRestored: boolean;
|
|
7
|
-
}
|
|
8
|
-
export interface RevertCameraResult {
|
|
9
|
-
files: CameraFileRevertResult[];
|
|
10
|
-
filesScanned: number;
|
|
11
|
-
}
|
|
12
|
-
export declare function revertCamera(projectDir: string): Promise<RevertCameraResult>;
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { writeFile, readdir } from "node:fs/promises";
|
|
2
|
-
import { join, relative, sep } from "node:path";
|
|
3
|
-
import { IndentationText, Node, Project, SyntaxKind, } from "ts-morph";
|
|
4
|
-
const SHIM_MODULE = "@ceraph/react-native-mcp/shim";
|
|
5
|
-
const SHIM_NAMED = "CeraphCamera";
|
|
6
|
-
const EXPO_MODULE = "expo-camera";
|
|
7
|
-
const EXPO_NAMED = "CameraView";
|
|
8
|
-
const SCAN_ROOTS = ["app", "src", "screens"];
|
|
9
|
-
const SCAN_EXTENSIONS = new Set([".tsx", ".jsx"]);
|
|
10
|
-
const SKIP_DIRS = new Set([
|
|
11
|
-
"node_modules",
|
|
12
|
-
"dist",
|
|
13
|
-
"build",
|
|
14
|
-
".git",
|
|
15
|
-
".ceraph",
|
|
16
|
-
".rn-mcp-cache",
|
|
17
|
-
".expo",
|
|
18
|
-
".next",
|
|
19
|
-
"ios",
|
|
20
|
-
"android",
|
|
21
|
-
]);
|
|
22
|
-
async function listCandidateFiles(projectDir) {
|
|
23
|
-
const out = [];
|
|
24
|
-
async function walk(dir) {
|
|
25
|
-
let entries;
|
|
26
|
-
try {
|
|
27
|
-
entries = await readdir(dir, { withFileTypes: true });
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
for (const entry of entries) {
|
|
33
|
-
const abs = join(dir, entry.name);
|
|
34
|
-
if (entry.isDirectory()) {
|
|
35
|
-
if (SKIP_DIRS.has(entry.name))
|
|
36
|
-
continue;
|
|
37
|
-
await walk(abs);
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
if (!entry.isFile())
|
|
41
|
-
continue;
|
|
42
|
-
const dot = entry.name.lastIndexOf(".");
|
|
43
|
-
if (dot < 0)
|
|
44
|
-
continue;
|
|
45
|
-
const ext = entry.name.slice(dot).toLowerCase();
|
|
46
|
-
if (!SCAN_EXTENSIONS.has(ext))
|
|
47
|
-
continue;
|
|
48
|
-
out.push(abs);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
for (const sub of SCAN_ROOTS) {
|
|
52
|
-
await walk(join(projectDir, sub));
|
|
53
|
-
}
|
|
54
|
-
for (const candidate of ["App.tsx", "App.jsx"]) {
|
|
55
|
-
out.push(join(projectDir, candidate));
|
|
56
|
-
}
|
|
57
|
-
return out;
|
|
58
|
-
}
|
|
59
|
-
function buildProject(filePaths) {
|
|
60
|
-
const project = new Project({
|
|
61
|
-
useInMemoryFileSystem: false,
|
|
62
|
-
skipAddingFilesFromTsConfig: true,
|
|
63
|
-
skipFileDependencyResolution: true,
|
|
64
|
-
skipLoadingLibFiles: true,
|
|
65
|
-
compilerOptions: { allowJs: true, jsx: 1 },
|
|
66
|
-
manipulationSettings: { indentationText: IndentationText.TwoSpaces },
|
|
67
|
-
});
|
|
68
|
-
for (const path of filePaths) {
|
|
69
|
-
try {
|
|
70
|
-
project.addSourceFileAtPath(path);
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return project;
|
|
76
|
-
}
|
|
77
|
-
function listJsxByName(source, name) {
|
|
78
|
-
const out = [];
|
|
79
|
-
source.forEachDescendant((node) => {
|
|
80
|
-
if (Node.isJsxOpeningElement(node) || Node.isJsxSelfClosingElement(node)) {
|
|
81
|
-
const tag = node.getTagNameNode();
|
|
82
|
-
if (tag.getText() === name) {
|
|
83
|
-
out.push(node);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
return out;
|
|
88
|
-
}
|
|
89
|
-
function removeImageKeyAttribute(node) {
|
|
90
|
-
const attrs = node.getAttributes();
|
|
91
|
-
for (const attr of attrs) {
|
|
92
|
-
if (Node.isJsxAttribute(attr)) {
|
|
93
|
-
const nameNode = attr.getNameNode();
|
|
94
|
-
if (nameNode.getText() === "imageKey") {
|
|
95
|
-
attr.remove();
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
function renameCeraphCamerasToCameraView(source) {
|
|
101
|
-
let count = 0;
|
|
102
|
-
for (let safety = 0; safety < 10_000; safety++) {
|
|
103
|
-
const tags = listJsxByName(source, SHIM_NAMED);
|
|
104
|
-
if (tags.length === 0)
|
|
105
|
-
break;
|
|
106
|
-
const target = tags[0];
|
|
107
|
-
target.getTagNameNode().replaceWithText(EXPO_NAMED);
|
|
108
|
-
if (Node.isJsxOpeningElement(target)) {
|
|
109
|
-
const parent = target.getParentIfKind(SyntaxKind.JsxElement);
|
|
110
|
-
if (parent) {
|
|
111
|
-
const closing = parent.getClosingElement();
|
|
112
|
-
closing.getTagNameNode().replaceWithText(EXPO_NAMED);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
removeImageKeyAttribute(target);
|
|
116
|
-
count++;
|
|
117
|
-
}
|
|
118
|
-
return count;
|
|
119
|
-
}
|
|
120
|
-
function dropCeraphCameraFromShimImport(source) {
|
|
121
|
-
const decl = source.getImportDeclaration(SHIM_MODULE);
|
|
122
|
-
if (!decl)
|
|
123
|
-
return false;
|
|
124
|
-
const named = decl.getNamedImports();
|
|
125
|
-
const target = named.find((n) => n.getName() === SHIM_NAMED);
|
|
126
|
-
if (!target)
|
|
127
|
-
return false;
|
|
128
|
-
target.remove();
|
|
129
|
-
const remaining = decl.getNamedImports();
|
|
130
|
-
const hasDefault = decl.getDefaultImport() != null;
|
|
131
|
-
if (remaining.length === 0 && !hasDefault) {
|
|
132
|
-
decl.remove();
|
|
133
|
-
}
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
function ensureCameraViewImport(source) {
|
|
137
|
-
const decl = source.getImportDeclaration(EXPO_MODULE);
|
|
138
|
-
if (decl) {
|
|
139
|
-
const named = decl.getNamedImports();
|
|
140
|
-
if (named.some((n) => n.getName() === EXPO_NAMED))
|
|
141
|
-
return false;
|
|
142
|
-
decl.addNamedImport(EXPO_NAMED);
|
|
143
|
-
return true;
|
|
144
|
-
}
|
|
145
|
-
source.addImportDeclaration({
|
|
146
|
-
moduleSpecifier: EXPO_MODULE,
|
|
147
|
-
namedImports: [EXPO_NAMED],
|
|
148
|
-
});
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
export async function revertCamera(projectDir) {
|
|
152
|
-
const candidates = await listCandidateFiles(projectDir);
|
|
153
|
-
const project = buildProject(candidates);
|
|
154
|
-
const files = [];
|
|
155
|
-
let filesScanned = 0;
|
|
156
|
-
for (const source of project.getSourceFiles()) {
|
|
157
|
-
filesScanned++;
|
|
158
|
-
const tags = listJsxByName(source, SHIM_NAMED);
|
|
159
|
-
if (tags.length === 0) {
|
|
160
|
-
const importDecl = source.getImportDeclaration(SHIM_MODULE);
|
|
161
|
-
const hasOrphanImport = importDecl != null &&
|
|
162
|
-
importDecl.getNamedImports().some((n) => n.getName() === SHIM_NAMED);
|
|
163
|
-
if (!hasOrphanImport)
|
|
164
|
-
continue;
|
|
165
|
-
const dropped = dropCeraphCameraFromShimImport(source);
|
|
166
|
-
if (!dropped)
|
|
167
|
-
continue;
|
|
168
|
-
const filePath = source.getFilePath();
|
|
169
|
-
await writeFile(filePath, source.getFullText(), "utf-8");
|
|
170
|
-
files.push({
|
|
171
|
-
path: filePath,
|
|
172
|
-
relPath: relative(projectDir, filePath).split(sep).join("/"),
|
|
173
|
-
ceraphCamerasRemoved: 0,
|
|
174
|
-
importDropped: true,
|
|
175
|
-
importRestored: false,
|
|
176
|
-
});
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
const ceraphCamerasRemoved = renameCeraphCamerasToCameraView(source);
|
|
180
|
-
const remainingShimTags = listJsxByName(source, SHIM_NAMED);
|
|
181
|
-
const importDropped = remainingShimTags.length === 0
|
|
182
|
-
? dropCeraphCameraFromShimImport(source)
|
|
183
|
-
: false;
|
|
184
|
-
const hasCameraViewJsx = listJsxByName(source, EXPO_NAMED).length > 0;
|
|
185
|
-
const importRestored = hasCameraViewJsx
|
|
186
|
-
? ensureCameraViewImport(source)
|
|
187
|
-
: false;
|
|
188
|
-
const filePath = source.getFilePath();
|
|
189
|
-
await writeFile(filePath, source.getFullText(), "utf-8");
|
|
190
|
-
files.push({
|
|
191
|
-
path: filePath,
|
|
192
|
-
relPath: relative(projectDir, filePath).split(sep).join("/"),
|
|
193
|
-
ceraphCamerasRemoved,
|
|
194
|
-
importDropped,
|
|
195
|
-
importRestored,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
return { files, filesScanned };
|
|
199
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export type RevertCeraphDirResult = {
|
|
2
|
-
status: "skipped-needs-confirmation";
|
|
3
|
-
path: string;
|
|
4
|
-
paths: string[];
|
|
5
|
-
} | {
|
|
6
|
-
status: "deleted";
|
|
7
|
-
path: string;
|
|
8
|
-
deletedEntries: string[];
|
|
9
|
-
} | {
|
|
10
|
-
status: "already-reverted";
|
|
11
|
-
path: string;
|
|
12
|
-
};
|
|
13
|
-
export interface RevertCeraphDirInput {
|
|
14
|
-
projectDir: string;
|
|
15
|
-
confirm: boolean;
|
|
16
|
-
}
|
|
17
|
-
export interface RevertCeraphDirDeps {
|
|
18
|
-
rm?: (p: string, opts: {
|
|
19
|
-
recursive: true;
|
|
20
|
-
force: true;
|
|
21
|
-
}) => Promise<void>;
|
|
22
|
-
readdir?: (p: string) => Promise<string[]>;
|
|
23
|
-
stat?: (p: string) => Promise<{
|
|
24
|
-
isDirectory: () => boolean;
|
|
25
|
-
}>;
|
|
26
|
-
}
|
|
27
|
-
export declare function revertCeraphDir(input: RevertCeraphDirInput, deps?: RevertCeraphDirDeps): Promise<RevertCeraphDirResult>;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { rm, readdir, stat } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
async function dirExists(path, statFn) {
|
|
4
|
-
try {
|
|
5
|
-
const s = await statFn(path);
|
|
6
|
-
return s.isDirectory();
|
|
7
|
-
}
|
|
8
|
-
catch {
|
|
9
|
-
return false;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
export async function revertCeraphDir(input, deps = {}) {
|
|
13
|
-
const ceraphPath = join(input.projectDir, ".ceraph");
|
|
14
|
-
const rmFn = deps.rm ?? ((p, o) => rm(p, o));
|
|
15
|
-
const readdirFn = deps.readdir ?? ((p) => readdir(p));
|
|
16
|
-
const statFn = deps.stat ?? ((p) => stat(p));
|
|
17
|
-
const exists = await dirExists(ceraphPath, statFn);
|
|
18
|
-
if (!exists) {
|
|
19
|
-
return { status: "already-reverted", path: ceraphPath };
|
|
20
|
-
}
|
|
21
|
-
let entries = [];
|
|
22
|
-
try {
|
|
23
|
-
entries = await readdirFn(ceraphPath);
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
entries = [];
|
|
27
|
-
}
|
|
28
|
-
entries.sort();
|
|
29
|
-
if (!input.confirm) {
|
|
30
|
-
return {
|
|
31
|
-
status: "skipped-needs-confirmation",
|
|
32
|
-
path: ceraphPath,
|
|
33
|
-
paths: entries.map((e) => join(ceraphPath, e)),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
await rmFn(ceraphPath, { recursive: true, force: true });
|
|
37
|
-
return { status: "deleted", path: ceraphPath, deletedEntries: entries };
|
|
38
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export type RevertClaudeHooksStatus = "reverted" | "already-reverted" | "manual" | "skipped";
|
|
2
|
-
export interface RevertClaudeHooksResult {
|
|
3
|
-
status: RevertClaudeHooksStatus;
|
|
4
|
-
details: {
|
|
5
|
-
scriptsDeleted: string[];
|
|
6
|
-
scriptsLeftAlone: string[];
|
|
7
|
-
settingsFilesModified: string[];
|
|
8
|
-
settingsFilesUntouched: string[];
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
export interface RevertClaudeHooksDeps {
|
|
12
|
-
readFile?: (p: string) => Promise<string>;
|
|
13
|
-
writeFile?: (p: string, c: string) => Promise<void>;
|
|
14
|
-
unlink?: (p: string) => Promise<void>;
|
|
15
|
-
fileExists?: (p: string) => Promise<boolean>;
|
|
16
|
-
}
|
|
17
|
-
export declare function revertClaudeHooks(input: {
|
|
18
|
-
projectDir: string;
|
|
19
|
-
}, deps?: RevertClaudeHooksDeps): Promise<RevertClaudeHooksResult>;
|