-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.js
More file actions
202 lines (177 loc) · 6.49 KB
/
utils.js
File metadata and controls
202 lines (177 loc) · 6.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
const fs = require('fs');
const readline = require('readline');
let chalk = require('chalk');
// --- CHALK FIX AND SETUP (Ensure chalk works or has a fallback) ---
if (chalk && chalk.default) {
chalk = chalk.default;
} else {
// Simple fallback if chalk is unavailable or version is incompatible
chalk = {
red: (s) => s, blue: (s) => s, green: (s) => s, yellow: (s) => s,
cyan: (s) => s, bold: (s) => s, magenta: (s) => s,
stripColor: (s) => s.replace(/\x1b\[[0-9;]*m/g, ''),
underline: (s) => s
};
}
// --------------------------
// Readline configuration for user input
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
/**
* Delays execution for the specified number of milliseconds.
* @param {number} ms Milliseconds to wait.
*/
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**
* Logs a styled message to the console, adding format and emojis.
* @param {string} message Message to log (without newlines or emojis).
* @param {('start'|'info'|'success'|'warn'|'error')} [type='info'] Message type for styling.
*/
function log(message, type = 'info') {
switch (type) {
case 'start':
console.log(chalk.blue(`\n🚀 ${message}`));
break;
case 'info':
console.log(chalk.cyan(`\nℹ️ ${message}`));
break;
case 'success':
console.log(chalk.green(`\n✅ ${message}`));
break;
case 'warn':
console.log(chalk.yellow(`\n⚠️ ${message}`));
break;
case 'error':
console.error(chalk.red(`\n❌ ${message}`));
break;
default:
console.log(message);
}
}
/**
* Logs progress to the console, overwriting the previous line.
* @param {string} message The progress message to display.
*/
function logProgress(message) {
// \r returns the cursor to the beginning of the line.
process.stdout.write(chalk.bold.magenta(`\r${message}`));
}
/**
* Prompts the user for input using the readline interface.
* @param {string} question The question to display.
* @returns {Promise<string>} The user's response.
*/
function askQuestion(question) {
return new Promise((resolve) => {
// Add newline at the beginning of the prompt here
rl.question(chalk.yellow(`\n${question}`), (answer) => {
resolve(answer);
});
});
}
/**
* Closes the readline interface.
*/
function closeReadline() {
rl.close();
}
/**
* Prints a separator line (80 equals signs) formatted in green.
* @param {boolean} [addNewlineBefore=false] Whether to add a newline before the separator.
*/
function printSeparator(addNewlineBefore = false) {
const separator = '='.repeat(80);
if (addNewlineBefore) {
console.log(`\n${chalk.green(separator)}`);
} else {
console.log(chalk.green(separator));
}
}
/**
* Saves the list of question links to a file.
* @param {Array<Object>} questions Array of question objects.
* @param {string} filename The name of the file to save to.
* @param {Object} MESSAGES Message object from config.
*/
function saveLinksToFile(questions, filename, MESSAGES) {
try {
const linkList = questions.map(q => ` "${q.fullUrl}"`).join(',\n');
let content = `// Scraped on: ${new Date().toLocaleString()}\n`;
content += `// Total links found: ${questions.length}\n\n`;
content += `links = [\n${linkList}\n];\n`;
fs.writeFileSync(filename, content, 'utf8');
log(`Simplified link list saved successfully to: ${filename}`, 'success');
} catch (error) {
log(MESSAGES.ERROR_FILE_SAVE(error.message), 'error');
}
}
/**
* Saves the structured Question/Answer data in JSON format.
* @param {Array<Object>} qaData Array of Question/Answer objects.
* @param {string} filename The name of the file to save to.
* @param {Object} MESSAGES Message object from config.
*/
function saveQaToFile(qaData, filename, MESSAGES) {
try {
const jsonContent = JSON.stringify(qaData, null, 2);
fs.writeFileSync(filename, jsonContent, 'utf8');
} catch (error) {
log(MESSAGES.ERROR_FILE_SAVE(error.message), 'error');
}
}
/**
* Generates CSV content from structured QA data with columns for quiz structure.
* @param {Array<Object>} qaData Array of Question/Answer objects.
* @param {string} filename The name of the file to save to.
* @param {Object} MESSAGES Message object from config.
*/
function generateCSVFromQa(qaData, filename, MESSAGES) {
try {
if (!qaData || qaData.length === 0) {
log('No data available to generate CSV.', 'warn');
return;
}
// CSV Headers in English, using COMMA (,) as the column delimiter
let csvContent = "QUESTION,CORRECT ANSWER,YOUR ANSWER,RESULT\n";
qaData.forEach(item => {
const separator = '\n'; // Will be used for line breaks inside the cell
// 1. Format Column A (Question + Options)
let questionText = `Nº ${item.questionNumber}: ${item.question}${separator}`;
item.options.forEach((option, index) => {
const optionLetter = String.fromCharCode(65 + index); // 65 is 'A'
questionText += `${optionLetter}) ${option}${separator}`;
});
const columnA = `"${questionText.trim().replace(/"/g, '""')}"`;
// 2. Column B: Correct Answer
const columnB = item.answer || 'N/A';
const rowNumber = item.questionNumber + 1;
// 3. Column C: Client Answer (Initially Empty)
const columnC = '';
// 4. Column D: Comparison Formula
const formula = `=IF(ISBLANK(C${rowNumber}); "No Answer Selected"; IF(C${rowNumber}=B${rowNumber}; "✅ CORRECT"; "❌ CORRECT ANSWER:" B${rowNumber}))`;
// CONCATENATE: Use COMMA (,) as the column separator
csvContent += `${columnA},${columnB},${columnC},${formula}\n`;
});
// The final CSV filename
const finalFilename = filename.replace('.json', '.csv');
fs.writeFileSync(finalFilename, csvContent, 'utf8');
log(`Quiz CSV file generated successfully: ${finalFilename}`, 'success');
} catch (error) {
log(MESSAGES.ERROR_FILE_SAVE(`Error generating CSV: ${error.message}`), 'error');
}
}
module.exports = {
sleep,
log,
logProgress,
askQuestion,
closeReadline,
saveLinksToFile,
saveQaToFile,
printSeparator,
generateCSVFromQa
};