react-doctor-cli-dev 1.0.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/backend/.env +3 -0
- package/backend/dist/index.js +43 -0
- package/backend/dist/middleware/auth.js +16 -0
- package/backend/dist/routes/reports.js +93 -0
- package/backend/package-lock.json +2000 -0
- package/backend/package.json +30 -0
- package/backend/src/db.ts +24 -0
- package/backend/src/index.ts +49 -0
- package/backend/src/middleware/auth.ts +21 -0
- package/backend/src/routes/reports.ts +110 -0
- package/backend/tsconfig.json +12 -0
- package/cli/bin/react-doctor.js +29 -0
- package/cli/dist/commands/analyze.js +125 -0
- package/cli/dist/commands/full.js +366 -0
- package/cli/dist/commands/install.js +138 -0
- package/cli/dist/commands/profile.js +166 -0
- package/cli/dist/index.js +78 -0
- package/cli/dist/ui.js +113 -0
- package/cli/package-lock.json +936 -0
- package/cli/package.json +34 -0
- package/cli/src/commands/analyze.ts +162 -0
- package/cli/src/commands/full.ts +574 -0
- package/cli/src/commands/install.ts +163 -0
- package/cli/src/commands/profile.ts +246 -0
- package/cli/src/index.ts +84 -0
- package/cli/src/ui.ts +120 -0
- package/cli/tsconfig.json +16 -0
- package/core/report-compiler/index.ts +359 -0
- package/core/report-compiler/test-report-compiler.ts +126 -0
- package/core/rule-engine/context-builder.ts +146 -0
- package/core/rule-engine/evaluator.ts +131 -0
- package/core/rule-engine/index.ts +222 -0
- package/core/rule-engine/rules.json +304 -0
- package/core/rule-engine/suggestion-builder.ts +209 -0
- package/core/rule-engine/test-rule-engine.ts +144 -0
- package/core/rule-engine/types.ts +202 -0
- package/core/runtime/profiler/browser.ts +121 -0
- package/core/runtime/profiler/collectors.ts +216 -0
- package/core/runtime/profiler/index.ts +311 -0
- package/core/runtime/profiler/porfiler.ts +967 -0
- package/core/runtime/profiler/route-scanner.ts +76 -0
- package/core/runtime/profiler/score.ts +59 -0
- package/core/runtime/profiler/server.ts +115 -0
- package/core/runtime/profiler/types.ts +65 -0
- package/core/runtime/test-runtime-profiler.ts +226 -0
- package/core/static-ana/static/analyzer.ts +145 -0
- package/core/static-ana/static/ast-parser.ts +31 -0
- package/core/static-ana/static/detectors/console-log.ts +49 -0
- package/core/static-ana/static/detectors/dead-code.ts +51 -0
- package/core/static-ana/static/detectors/effect-loop.ts +45 -0
- package/core/static-ana/static/detectors/index.ts +16 -0
- package/core/static-ana/static/detectors/inline-function.ts +59 -0
- package/core/static-ana/static/detectors/inline-style.ts +52 -0
- package/core/static-ana/static/detectors/large-component.ts +79 -0
- package/core/static-ana/static/detectors/missing-key.ts +56 -0
- package/core/static-ana/static/detectors/missing-memo.ts +59 -0
- package/core/static-ana/static/detectors/prop-drilling.ts +66 -0
- package/core/static-ana/static/helpers.ts +81 -0
- package/core/static-ana/static/scanner.ts +93 -0
- package/core/static-ana/test-analyzer.ts +115 -0
- package/core/static-ana/types.ts +25 -0
- package/core/tests/mock-react-project/src/app.tsx +22 -0
- package/core/tests/mock-react-project/src/components/Button.tsx +9 -0
- package/core/tests/mock-react-project/src/components/Header.tsx +3 -0
- package/core/tests/mock-react-project/src/components/ListTesting.tsx +51 -0
- package/core/tests/mock-react-project/src/components/UserDashboard.tsx +66 -0
- package/core/tests/mock-react-project/src/utils.ts +4 -0
- package/package.json +55 -0
- package/react-doctor-cli-dev-1.0.0.tgz +0 -0
- package/shared/dist/index.d.ts +2 -0
- package/shared/dist/index.js +19 -0
- package/shared/dist/schemas.d.ts +91 -0
- package/shared/dist/schemas.js +82 -0
- package/shared/dist/types.d.ts +44 -0
- package/shared/dist/types.js +2 -0
- package/shared/package-lock.json +47 -0
- package/shared/package.json +21 -0
- package/shared/src/index.ts +4 -0
- package/shared/src/schemas.ts +136 -0
- package/shared/src/types.ts +137 -0
- package/shared/tsconfig.json +15 -0
- package/tsconfig.json +25 -0
package/backend/.env
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const express_1 = __importDefault(require("express"));
|
|
7
|
+
const cors_1 = __importDefault(require("cors"));
|
|
8
|
+
const helmet_1 = __importDefault(require("helmet"));
|
|
9
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
10
|
+
const reports_1 = __importDefault(require("./routes/reports"));
|
|
11
|
+
dotenv_1.default.config();
|
|
12
|
+
// Debug: Check if API_KEY is loaded
|
|
13
|
+
console.log(`[Debug] API_KEY loaded: ${process.env.API_KEY ? '✓' : '✗'}`);
|
|
14
|
+
console.log(`[Debug] API_KEY value: ${process.env.API_KEY || 'NOT SET'}`);
|
|
15
|
+
const app = (0, express_1.default)();
|
|
16
|
+
const PORT = process.env.PORT || 3000;
|
|
17
|
+
// ─── SECURITY AND PARSING MIDDLEWARE ──────────────────────────────────────────
|
|
18
|
+
app.use((0, helmet_1.default)()); // adds security headers
|
|
19
|
+
app.use((0, cors_1.default)()); // allows dashboard to call the API
|
|
20
|
+
app.use(express_1.default.json({ limit: '50mb' })); // reports can be large (screenshots)
|
|
21
|
+
// ─── ROUTES ───────────────────────────────────────────────────────────────────
|
|
22
|
+
// Use only ONE path (plural is REST convention)
|
|
23
|
+
app.use('/api/reports', reports_1.default);
|
|
24
|
+
// ─── HEALTH CHECK - NO AUTH, USED TO VERIFY SERVER IS UP ──────────────────────
|
|
25
|
+
app.get('/health', (_req, res) => {
|
|
26
|
+
res.json({
|
|
27
|
+
status: 'ok',
|
|
28
|
+
timestamp: new Date().toISOString()
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
// ─── 404 HANDLER ──────────────────────────────────────────────────────────────
|
|
32
|
+
app.use((req, res) => {
|
|
33
|
+
res.status(404).json({ message: 'Route not found' });
|
|
34
|
+
});
|
|
35
|
+
// ─── GLOBAL ERROR HANDLER ─────────────────────────────────────────────────────
|
|
36
|
+
app.use((err, _req, res, _next) => {
|
|
37
|
+
console.error(err.stack);
|
|
38
|
+
res.status(500).json({ message: 'Internal Server Error' });
|
|
39
|
+
});
|
|
40
|
+
// ─── START THE SERVER ─────────────────────────────────────────────────────────
|
|
41
|
+
app.listen(PORT, () => {
|
|
42
|
+
console.log(`React Doctor backend running on http://localhost:${PORT}`);
|
|
43
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requireApiKey = requireApiKey;
|
|
4
|
+
function requireApiKey(req, res, next) {
|
|
5
|
+
const keyHeader = req.headers["x-api-key"];
|
|
6
|
+
const key = Array.isArray(keyHeader) ? keyHeader[0] : keyHeader;
|
|
7
|
+
const expectedKey = process.env.API_KEY?.trim();
|
|
8
|
+
// Debug log
|
|
9
|
+
console.log(`[Auth] Received: "${key}", Expected: "${expectedKey}"`);
|
|
10
|
+
if (!key || key.trim() !== expectedKey) {
|
|
11
|
+
console.warn(`[Auth] API key mismatch!`);
|
|
12
|
+
res.status(401).json({ error: "Unauthorized — invalid or missing API key" });
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
next();
|
|
16
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const express_1 = require("express");
|
|
7
|
+
const db_1 = __importDefault(require("../db"));
|
|
8
|
+
const auth_1 = require("../middleware/auth");
|
|
9
|
+
const router = (0, express_1.Router)();
|
|
10
|
+
router.get("/", (req, res) => {
|
|
11
|
+
try {
|
|
12
|
+
const rows = db_1.default.prepare(`
|
|
13
|
+
SELECT id, project, score, grade, analyzed_at, created_at
|
|
14
|
+
FROM reports
|
|
15
|
+
ORDER BY created_at DESC
|
|
16
|
+
LIMIT 50
|
|
17
|
+
`).all();
|
|
18
|
+
res.json({ count: rows.length, reports: rows });
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
res.status(500).json({ error: "Internal server error" });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
router.get("/project/:name", (req, res) => {
|
|
25
|
+
try {
|
|
26
|
+
const rows = db_1.default.prepare(`
|
|
27
|
+
SELECT id, project, score, grade, analyzed_at, created_at
|
|
28
|
+
FROM reports
|
|
29
|
+
WHERE project = ?
|
|
30
|
+
ORDER BY created_at DESC
|
|
31
|
+
`).all(req.params.name);
|
|
32
|
+
res.json({
|
|
33
|
+
project: req.params.name,
|
|
34
|
+
count: rows.length,
|
|
35
|
+
reports: rows,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
res.status(500).json({ error: "Internal server error" });
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
// ==========================================
|
|
43
|
+
// Endpoint 1: POST /api/report/upload
|
|
44
|
+
// يستقبل التقرير من الـ CLI ويتحقق منه ثم يحفظه
|
|
45
|
+
// ==========================================
|
|
46
|
+
router.post("/upload", auth_1.requireApiKey, (req, res) => {
|
|
47
|
+
try {
|
|
48
|
+
const report = req.body;
|
|
49
|
+
// التحقق من وجود الحقول الإلزامية الثلاثة
|
|
50
|
+
if (!report || !report.projectName || !report.analyzedAt || report.performanceScore === undefined) {
|
|
51
|
+
res.status(400).json({ error: "Invalid report — missing required fields" });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const grade = report.static?.grade ?? "N/A";
|
|
55
|
+
// تجهيز استعلام الإدخال لـ SQLite
|
|
56
|
+
const stmt = db_1.default.prepare(`
|
|
57
|
+
INSERT INTO reports (project, score, grade, analyzed_at, payload)
|
|
58
|
+
VALUES (?, ?, ?, ?, ?)
|
|
59
|
+
`);
|
|
60
|
+
// تنفيذ الاستعلام وحفظ جسم التقرير كـ string
|
|
61
|
+
const result = stmt.run(report.projectName, report.performanceScore, grade, report.analyzedAt, JSON.stringify(report));
|
|
62
|
+
res.status(201).json({
|
|
63
|
+
message: "Report saved successfully",
|
|
64
|
+
id: result.lastInsertRowid,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
console.error("Upload error:", err.message);
|
|
69
|
+
res.status(500).json({ error: "Internal server error" });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
router.get("/:id", (req, res) => {
|
|
73
|
+
try {
|
|
74
|
+
const row = db_1.default.prepare("SELECT * FROM reports WHERE id = ?").get(req.params.id);
|
|
75
|
+
if (!row) {
|
|
76
|
+
res.status(404).json({ error: "Report not found" });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
res.json({
|
|
80
|
+
id: row.id,
|
|
81
|
+
project: row.project,
|
|
82
|
+
score: row.score,
|
|
83
|
+
grade: row.grade,
|
|
84
|
+
analyzedAt: row.analyzed_at,
|
|
85
|
+
createdAt: row.created_at,
|
|
86
|
+
report: JSON.parse(row.payload),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
res.status(500).json({ error: "Internal server error" });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
exports.default = router;
|