deflake 1.2.17 β 1.2.21
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/cli.js +107 -48
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ const fs = require('fs');
|
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const pkg = require('./package.json');
|
|
9
9
|
|
|
10
|
-
// --- COLORS ---
|
|
10
|
+
// --- PREMIUM COLORS ---
|
|
11
11
|
const C = {
|
|
12
12
|
RESET: "\x1b[0m",
|
|
13
13
|
BRIGHT: "\x1b[1m",
|
|
@@ -16,8 +16,10 @@ const C = {
|
|
|
16
16
|
YELLOW: "\x1b[33m",
|
|
17
17
|
CYAN: "\x1b[36m",
|
|
18
18
|
BLUE: "\x1b[34m",
|
|
19
|
+
MAGENTA: "\x1b[35m",
|
|
19
20
|
GRAY: "\x1b[90m",
|
|
20
|
-
|
|
21
|
+
BG_BLUE: "\x1b[44m",
|
|
22
|
+
BG_GREEN: "\x1b[42m"
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
const rawArgs = process.argv.slice(2);
|
|
@@ -43,19 +45,16 @@ async function main() {
|
|
|
43
45
|
|
|
44
46
|
if (commandToRun) {
|
|
45
47
|
const { code } = await runNative(commandToRun);
|
|
46
|
-
|
|
47
48
|
if (code !== 0) {
|
|
48
49
|
console.log(`\nπ΄ Command failed with code ${code}. Activating DeFlake...`);
|
|
49
50
|
const artifacts = detectFailures();
|
|
50
51
|
const applied = await analyzeAndFix(artifacts, client, argv);
|
|
51
|
-
|
|
52
52
|
if (applied > 0 && argv.fix) {
|
|
53
53
|
console.log(`\n${C.BRIGHT}π Fixes applied. Re-running tests to verify...${C.RESET}`);
|
|
54
54
|
await runNative(commandToRun);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
|
|
59
58
|
if (argv.report) showReport();
|
|
60
59
|
}
|
|
61
60
|
|
|
@@ -89,22 +88,17 @@ async function analyzeAndFix(artifacts, client, argv) {
|
|
|
89
88
|
console.log(` ${C.YELLOW}β οΈ No failure artifacts detected. Run 'npx deflake doctor' to check permissions.${C.RESET}`);
|
|
90
89
|
return 0;
|
|
91
90
|
}
|
|
92
|
-
|
|
93
91
|
console.log(`π Analyzing ${artifacts.length} failure(s)...`);
|
|
94
92
|
let count = 0;
|
|
95
|
-
|
|
96
93
|
for (const art of artifacts) {
|
|
97
94
|
process.stdout.write(`β³ Analyzing ${art.name}...`);
|
|
98
95
|
try {
|
|
99
96
|
const content = fs.readFileSync(art.htmlPath, 'utf8');
|
|
100
97
|
const loc = extractLoc(content);
|
|
101
98
|
const source = loc && fs.existsSync(loc.path) ? fs.readFileSync(loc.path, 'utf8') : null;
|
|
102
|
-
|
|
103
99
|
const res = await client.heal(null, art.htmlPath, loc, source, argv.fix);
|
|
104
100
|
if (res?.status === 'success') {
|
|
105
|
-
if (argv.fix)
|
|
106
|
-
if (await applyFix(res, loc)) count++;
|
|
107
|
-
}
|
|
101
|
+
if (argv.fix && await applyFix(res, loc)) count++;
|
|
108
102
|
process.stdout.write(`\rβ
Analysis complete for ${art.name}\n`);
|
|
109
103
|
printFix(res.fix, loc);
|
|
110
104
|
}
|
|
@@ -121,20 +115,13 @@ async function applyFix(res, loc) {
|
|
|
121
115
|
const patches = JSON.parse(res.fix).patches || [];
|
|
122
116
|
const original = fs.readFileSync(loc.path, 'utf8');
|
|
123
117
|
let content = original;
|
|
124
|
-
|
|
125
118
|
for (const p of patches) {
|
|
126
119
|
const lines = content.split('\n');
|
|
127
120
|
const idx = p.line - 1;
|
|
128
121
|
if (idx >= 0 && idx < lines.length) {
|
|
129
122
|
const indent = lines[idx].match(/^\s*/)[0];
|
|
130
123
|
const cleanLine = indent + p.new_line.trim();
|
|
131
|
-
|
|
132
|
-
// π SAFETY GUARD: Prevent top-level await in class bodies
|
|
133
|
-
if (cleanLine.includes('await') && !content.includes('async')) {
|
|
134
|
-
console.log(` β οΈ Blocked illegal await in non-async scope: ${path.basename(loc.path)}`);
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
|
|
124
|
+
if (cleanLine.includes('await') && !content.includes('async')) continue;
|
|
138
125
|
if (!content.includes(p.new_line.trim())) {
|
|
139
126
|
if (p.action === 'INSERT_AFTER') lines.splice(p.line, 0, cleanLine);
|
|
140
127
|
else lines[idx] = cleanLine;
|
|
@@ -142,15 +129,9 @@ async function applyFix(res, loc) {
|
|
|
142
129
|
}
|
|
143
130
|
}
|
|
144
131
|
}
|
|
145
|
-
|
|
146
132
|
fs.writeFileSync(loc.path, content);
|
|
147
|
-
|
|
148
|
-
// π§ͺ SMARTER SYNTAX CHECK
|
|
149
133
|
try {
|
|
150
|
-
|
|
151
|
-
if (content.match(/class\s+\w+\s+\{[\s\S]*?await\s+/)) {
|
|
152
|
-
throw new Error("Illegal await in class body");
|
|
153
|
-
}
|
|
134
|
+
if (content.match(/class\s+\w+\s+\{[\s\S]*?await\s+/)) throw new Error("Illegal await");
|
|
154
135
|
return true;
|
|
155
136
|
} catch(e) {
|
|
156
137
|
fs.writeFileSync(loc.path, original);
|
|
@@ -173,36 +154,114 @@ function printFix(fix, loc) {
|
|
|
173
154
|
}
|
|
174
155
|
|
|
175
156
|
async function runDoctor() {
|
|
176
|
-
console.log(`\n
|
|
177
|
-
|
|
178
|
-
|
|
157
|
+
console.log(`\n${C.BG_BLUE}${C.WHITE}${C.BRIGHT} DEFLAKE MISSION CONTROL - DIAGNOSTIC CENTER ${C.RESET}\n`);
|
|
158
|
+
|
|
159
|
+
// 1. SYSTEM HUB
|
|
160
|
+
console.log(`${C.CYAN}1. SYSTEM CORE${C.RESET}`);
|
|
161
|
+
console.log(` ${C.GRAY}ββ Version: ${C.RESET}${C.BRIGHT}v${pkg.version}${C.RESET}`);
|
|
162
|
+
console.log(` ${C.GRAY}ββ Platform: ${C.RESET}${process.platform} (${process.arch})`);
|
|
163
|
+
console.log(` ${C.GRAY}ββ Project: ${C.RESET}${path.basename(process.cwd())}\n`);
|
|
179
164
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
165
|
+
// 2. PROJECT AUDIT (Discovery Phase)
|
|
166
|
+
console.log(`${C.CYAN}2. PROJECT DISCOVERY & VALIDATION${C.RESET}`);
|
|
167
|
+
const fw = DeFlakeClient.detectFramework();
|
|
168
|
+
console.log(` ${C.GRAY}ββ Framework: ${C.RESET}${C.GREEN}${fw.toUpperCase()}${C.RESET}`);
|
|
169
|
+
|
|
170
|
+
const testDirs = ['tests', 'cypress/e2e', 'test', 'pages'];
|
|
171
|
+
let allFiles = [];
|
|
172
|
+
testDirs.forEach(d => {
|
|
173
|
+
if (fs.existsSync(d)) {
|
|
174
|
+
const files = fs.readdirSync(d, { recursive: true }).filter(f => f.endsWith('.ts') || f.endsWith('.js') || f.endsWith('.cy.js'));
|
|
175
|
+
files.forEach(f => allFiles.push({ name: f, full: path.join(d, f) }));
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
if (allFiles.length > 0) {
|
|
180
|
+
console.log(` ${C.GRAY}ββ Discovery: ${C.RESET}${C.GREEN}${allFiles.length} files detected${C.RESET}`);
|
|
181
|
+
allFiles.slice(0, 8).forEach(file => {
|
|
182
|
+
process.stdout.write(` ${C.GRAY}β ββ ${path.basename(file.name).padEnd(25)}${C.RESET} `);
|
|
183
|
+
try {
|
|
184
|
+
execSync(`node --check "${file.full}"`, { stdio: 'ignore' });
|
|
185
|
+
console.log(`${C.GREEN}β Syntax OK${C.RESET}`);
|
|
186
|
+
} catch (e) {
|
|
187
|
+
console.log(`${C.RED}β SYNTAX ERROR${C.RESET}`);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
if (allFiles.length > 8) console.log(` ${C.GRAY}β ββ ... and ${allFiles.length - 8} more files validated.${C.RESET}`);
|
|
191
|
+
else console.log(` ${C.GRAY}β ββ All source files validated.${C.RESET}`);
|
|
192
|
+
} else {
|
|
193
|
+
console.log(` ${C.GRAY}ββ Discovery: ${C.RED}No test/page files found!${C.RESET}`);
|
|
194
|
+
}
|
|
195
|
+
console.log("");
|
|
196
|
+
|
|
197
|
+
// 3. API & SUBSCRIPTION HUB
|
|
198
|
+
console.log(`${C.CYAN}3. API & CLOUD HUB${C.RESET}`);
|
|
199
|
+
const apiKey = process.env.DEFLAKE_API_KEY || "NOT_SET";
|
|
200
|
+
const masked = apiKey === "NOT_SET" ? apiKey : (apiKey.substring(0, 4) + "****" + apiKey.substring(apiKey.length - 4));
|
|
201
|
+
console.log(` ${C.GRAY}ββ API Key: ${C.RESET}${apiKey === "NOT_SET" ? C.RED : C.GREEN}${masked}${C.RESET}`);
|
|
202
|
+
|
|
203
|
+
if (apiKey !== "NOT_SET") {
|
|
183
204
|
try {
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
205
|
+
process.stdout.write(` ${C.GRAY}ββ Gateway: ${C.RESET}π‘ Pinging...`);
|
|
206
|
+
const client = new DeFlakeClient();
|
|
207
|
+
const start = Date.now();
|
|
208
|
+
const usage = await client.getUsage();
|
|
209
|
+
const latency = Date.now() - start;
|
|
210
|
+
if (usage?.status === 'success') {
|
|
211
|
+
process.stdout.write(`\r ${C.GRAY}ββ Gateway: ${C.RESET}${C.GREEN}ONLINE (${latency}ms)${C.RESET} \n`);
|
|
212
|
+
console.log(` ${C.GRAY}ββ Quota: ${C.RESET}${C.MAGENTA}${usage.data.usage}/${usage.data.limit} fixes used${C.RESET}`);
|
|
213
|
+
} else {
|
|
214
|
+
process.stdout.write(`\r ${C.GRAY}ββ Gateway: ${C.RESET}${C.RED}Connection Failed (${usage?.message || 'Unauthorized'})${C.RESET} \n`);
|
|
215
|
+
}
|
|
193
216
|
} catch (e) {
|
|
194
|
-
|
|
195
|
-
|
|
217
|
+
process.stdout.write(`\r ${C.GRAY}ββ Gateway: ${C.RESET}${C.RED}Link Down (${e.message})${C.RESET} \n`);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
console.log(` ${C.GRAY}ββ Status: ${C.RED}Awaiting credentials...${C.RESET}`);
|
|
221
|
+
}
|
|
222
|
+
console.log("");
|
|
223
|
+
|
|
224
|
+
// 4. THE LIBERATION AUDIT (Permission Status)
|
|
225
|
+
console.log(`${C.CYAN}4. LIBERATION AUDIT (Permission Status)${C.RESET}`);
|
|
226
|
+
const artDirs = [
|
|
227
|
+
{ path: 'test-results', label: 'Test Results' },
|
|
228
|
+
{ path: 'playwright-report', label: 'HTML Report' }
|
|
229
|
+
];
|
|
230
|
+
let allLiberated = true;
|
|
231
|
+
let totalItems = 0;
|
|
232
|
+
|
|
233
|
+
for (const d of artDirs) {
|
|
234
|
+
if (fs.existsSync(d.path)) {
|
|
235
|
+
process.stdout.write(` ${C.GRAY}ββ ${d.label.padEnd(16)}: ${C.RESET}π Checking...`);
|
|
236
|
+
let dItems = 0;
|
|
237
|
+
try {
|
|
238
|
+
const scan = (p) => {
|
|
239
|
+
dItems++;
|
|
240
|
+
totalItems++;
|
|
241
|
+
fs.accessSync(p, fs.constants.R_OK | fs.constants.W_OK);
|
|
242
|
+
if (fs.statSync(p).isDirectory()) fs.readdirSync(p).forEach(f => scan(path.join(p, f)));
|
|
243
|
+
};
|
|
244
|
+
scan(d.path);
|
|
245
|
+
process.stdout.write(`\r ${C.GRAY}ββ ${d.label.padEnd(16)}: ${C.RESET}${C.GREEN}${C.BRIGHT}[LIBERADOS]${C.RESET}${C.GREEN} (${dItems} Γtems accesibles)${C.RESET} \n`);
|
|
246
|
+
} catch (e) {
|
|
247
|
+
process.stdout.write(`\r ${C.GRAY}ββ ${d.label.padEnd(16)}: ${C.RESET}${C.RED}${C.BRIGHT}[BLOQUEADOS]${C.RESET}${C.RED} (Error en: ${path.basename(e.path)})${C.RESET} \n`);
|
|
248
|
+
allLiberated = false;
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
console.log(` ${C.GRAY}ββ ${d.label.padEnd(16)}: ${C.RESET}${C.GRAY}Sin carpeta (AΓΊn no hay resultados)${C.RESET}`);
|
|
196
252
|
}
|
|
197
253
|
}
|
|
198
254
|
|
|
199
|
-
if (
|
|
200
|
-
console.log(`\n
|
|
201
|
-
const
|
|
202
|
-
console.log(`
|
|
255
|
+
if (!allLiberated) {
|
|
256
|
+
console.log(`\n ${C.BG_BLUE}${C.WHITE}${C.BRIGHT} ACCIΓN REQUERIDA: LIBERAR PERMISOS ${C.RESET}`);
|
|
257
|
+
const fix = process.platform === 'win32' ? 'icacls . /grant ${env:USERNAME}:(OI)(CI)F /T' : 'sudo chown -R $(whoami) .';
|
|
258
|
+
console.log(` Ejecuta esto en tu terminal: ${C.CYAN}${fix}${C.RESET}`);
|
|
203
259
|
} else {
|
|
204
|
-
console.log(
|
|
260
|
+
console.log(` ${C.GRAY}ββ AuditorΓa: ${C.RESET}${C.GREEN}${totalItems} archivos verificados con Γ©xito.${C.RESET}`);
|
|
261
|
+
console.log(`\n${C.BG_GREEN}${C.WHITE}${C.BRIGHT} ESTADO DEL SISTEMA: LIBERADO Y OPERATIVO ${C.RESET}`);
|
|
262
|
+
console.log(` Ya puedes correr: ${C.CYAN}npx deflake --fix --report npx playwright test${C.RESET}`);
|
|
205
263
|
}
|
|
264
|
+
console.log("\n" + C.GRAY + "β".repeat(50) + C.RESET + "\n");
|
|
206
265
|
}
|
|
207
266
|
|
|
208
267
|
function showReport() {
|