afront 1.0.4 → 1.0.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/install.js +181 -28
- package/package.json +6 -2
package/install.js
CHANGED
|
@@ -1,23 +1,72 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
|
-
const https = require('
|
|
4
|
+
const { https } = require('follow-redirects');
|
|
5
5
|
const { exec } = require('child_process');
|
|
6
6
|
const tmp = require('tmp');
|
|
7
|
-
const
|
|
7
|
+
const AdmZip = require('adm-zip');
|
|
8
|
+
const readline = require('readline');
|
|
8
9
|
|
|
9
10
|
// Configuration
|
|
10
11
|
const GITHUB_ZIP_URL = 'https://github.com/Asggen/afront/archive/refs/tags/v1.0.2.zip'; // Updated URL
|
|
11
|
-
const DEFAULT_DEST_DIR = path.join(process.cwd(), 'extracted-folder');
|
|
12
12
|
|
|
13
|
-
//
|
|
13
|
+
// Define files to skip
|
|
14
|
+
const SKIP_FILES = ['FUNDING.yml', 'CODE_OF_CONDUCT.md', 'SECURITY.md', 'install.js'];
|
|
15
|
+
|
|
16
|
+
// Initialize readline interface
|
|
17
|
+
const rl = readline.createInterface({
|
|
18
|
+
input: process.stdin,
|
|
19
|
+
output: process.stdout
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Spinner function
|
|
23
|
+
const spinner = (text, delay = 100) => {
|
|
24
|
+
const spinnerChars = ['|', '/', '-', '\\'];
|
|
25
|
+
let i = 0;
|
|
26
|
+
const interval = setInterval(() => {
|
|
27
|
+
readline.cursorTo(process.stdout, 0);
|
|
28
|
+
process.stdout.write(`${text} ${spinnerChars[i++]}`);
|
|
29
|
+
i = i % spinnerChars.length;
|
|
30
|
+
}, delay);
|
|
31
|
+
|
|
32
|
+
return () => {
|
|
33
|
+
clearInterval(interval);
|
|
34
|
+
readline.cursorTo(process.stdout, 0);
|
|
35
|
+
process.stdout.write(`${text} Done.\n`);
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const askQuestion = (question) => {
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
rl.question(question, (answer) => {
|
|
42
|
+
resolve(answer.trim().toLowerCase());
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
14
47
|
const downloadFile = (url, destination) => {
|
|
15
48
|
return new Promise((resolve, reject) => {
|
|
16
49
|
const file = fs.createWriteStream(destination);
|
|
50
|
+
const stopSpinner = spinner('Downloading');
|
|
17
51
|
https.get(url, (response) => {
|
|
52
|
+
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
53
|
+
return downloadFile(response.headers.location, destination).then(resolve).catch(reject);
|
|
54
|
+
}
|
|
55
|
+
if (response.statusCode !== 200) {
|
|
56
|
+
reject(new Error(`Failed to download file. Status code: ${response.statusCode}`));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
18
59
|
response.pipe(file);
|
|
19
60
|
file.on('finish', () => {
|
|
20
|
-
file.close(
|
|
61
|
+
file.close(() => {
|
|
62
|
+
if (fs.statSync(destination).size > 0) {
|
|
63
|
+
stopSpinner();
|
|
64
|
+
resolve();
|
|
65
|
+
} else {
|
|
66
|
+
stopSpinner();
|
|
67
|
+
reject(new Error('Downloaded file is empty.'));
|
|
68
|
+
}
|
|
69
|
+
});
|
|
21
70
|
});
|
|
22
71
|
}).on('error', (err) => {
|
|
23
72
|
fs.unlink(destination, () => reject(err));
|
|
@@ -25,24 +74,40 @@ const downloadFile = (url, destination) => {
|
|
|
25
74
|
});
|
|
26
75
|
};
|
|
27
76
|
|
|
28
|
-
// Extract zip file
|
|
29
77
|
const extractZip = (zipPath, extractTo) => {
|
|
30
78
|
return new Promise((resolve, reject) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
79
|
+
const stopSpinner = spinner('Extracting');
|
|
80
|
+
try {
|
|
81
|
+
const zip = new AdmZip(zipPath);
|
|
82
|
+
zip.extractAllTo(extractTo, true);
|
|
83
|
+
fs.readdir(extractTo, (err, files) => {
|
|
84
|
+
if (err) {
|
|
85
|
+
stopSpinner();
|
|
86
|
+
console.error('Error reading extracted folder:', err);
|
|
87
|
+
reject(err);
|
|
88
|
+
} else {
|
|
89
|
+
stopSpinner();
|
|
90
|
+
resolve();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
} catch (err) {
|
|
94
|
+
stopSpinner();
|
|
95
|
+
console.error('Error extracting zip file:', err);
|
|
96
|
+
reject(err);
|
|
97
|
+
}
|
|
35
98
|
});
|
|
36
99
|
};
|
|
37
100
|
|
|
38
|
-
// Run npm install
|
|
39
101
|
const runNpmInstall = (directory) => {
|
|
40
102
|
return new Promise((resolve, reject) => {
|
|
103
|
+
const stopSpinner = spinner('Running npm install');
|
|
41
104
|
exec('npm install', { cwd: directory }, (err, stdout, stderr) => {
|
|
42
105
|
if (err) {
|
|
106
|
+
stopSpinner();
|
|
43
107
|
console.error('Error running npm install:', stderr);
|
|
44
108
|
reject(err);
|
|
45
109
|
} else {
|
|
110
|
+
stopSpinner();
|
|
46
111
|
console.log('npm install output:', stdout);
|
|
47
112
|
resolve();
|
|
48
113
|
}
|
|
@@ -50,42 +115,130 @@ const runNpmInstall = (directory) => {
|
|
|
50
115
|
});
|
|
51
116
|
};
|
|
52
117
|
|
|
53
|
-
|
|
118
|
+
const createDirIfNotExists = (dirPath) => {
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
fs.mkdir(dirPath, { recursive: true }, (err) => {
|
|
121
|
+
if (err) {
|
|
122
|
+
reject(new Error('Error creating directory:', err));
|
|
123
|
+
} else {
|
|
124
|
+
resolve();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const promptForFolderName = async () => {
|
|
131
|
+
const answer = await askQuestion('AFront: Enter the name of the destination folder: ');
|
|
132
|
+
return answer;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const promptForReplace = async (dirPath) => {
|
|
136
|
+
const answer = await askQuestion(`The directory ${dirPath} already exists. Do you want to replace it? (yes/no): `);
|
|
137
|
+
return answer === 'yes' || answer === 'y';
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const removeDir = (dirPath) => {
|
|
141
|
+
return new Promise((resolve, reject) => {
|
|
142
|
+
console.log(`Removing existing directory: ${dirPath}`);
|
|
143
|
+
fs.rm(dirPath, { recursive: true, force: true }, (err) => {
|
|
144
|
+
if (err) {
|
|
145
|
+
return reject(err);
|
|
146
|
+
}
|
|
147
|
+
resolve();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const moveFiles = (srcPath, destPath) => {
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
fs.readdir(srcPath, (err, files) => {
|
|
155
|
+
if (err) {
|
|
156
|
+
return reject(err);
|
|
157
|
+
}
|
|
158
|
+
let pending = files.length;
|
|
159
|
+
if (!pending) return resolve();
|
|
160
|
+
files.forEach((file) => {
|
|
161
|
+
if (SKIP_FILES.includes(file)) {
|
|
162
|
+
if (!--pending) resolve();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const srcFile = path.join(srcPath, file);
|
|
167
|
+
const destFile = path.join(destPath, file);
|
|
168
|
+
fs.stat(srcFile, (err, stats) => {
|
|
169
|
+
if (err) {
|
|
170
|
+
return reject(err);
|
|
171
|
+
}
|
|
172
|
+
if (stats.isDirectory()) {
|
|
173
|
+
createDirIfNotExists(destFile)
|
|
174
|
+
.then(() => moveFiles(srcFile, destFile))
|
|
175
|
+
.then(() => {
|
|
176
|
+
if (!--pending) resolve();
|
|
177
|
+
})
|
|
178
|
+
.catch(reject);
|
|
179
|
+
} else {
|
|
180
|
+
fs.rename(srcFile, destFile, (err) => {
|
|
181
|
+
if (err) {
|
|
182
|
+
return reject(err);
|
|
183
|
+
}
|
|
184
|
+
if (!--pending) resolve();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
|
|
54
193
|
const main = async () => {
|
|
55
194
|
try {
|
|
56
|
-
// Create a temporary directory
|
|
57
195
|
const tmpDir = tmp.dirSync({ unsafeCleanup: true });
|
|
58
196
|
const zipPath = path.join(tmpDir.name, 'archive.zip');
|
|
59
|
-
const destDir = process.argv[2] || DEFAULT_DEST_DIR;
|
|
60
197
|
|
|
61
|
-
|
|
198
|
+
let folderName = process.argv[2];
|
|
199
|
+
if (folderName === '.') {
|
|
200
|
+
folderName = path.basename(process.cwd());
|
|
201
|
+
} else if (!folderName) {
|
|
202
|
+
folderName = await promptForFolderName();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const destDir = path.join(process.cwd(), folderName);
|
|
206
|
+
|
|
207
|
+
if (fs.existsSync(destDir)) {
|
|
208
|
+
const replace = await promptForReplace(destDir);
|
|
209
|
+
if (replace) {
|
|
210
|
+
await removeDir(destDir);
|
|
211
|
+
await createDirIfNotExists(destDir);
|
|
212
|
+
} else {
|
|
213
|
+
console.log('Operation aborted.');
|
|
214
|
+
rl.close();
|
|
215
|
+
process.exit(0);
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
await createDirIfNotExists(destDir);
|
|
219
|
+
}
|
|
220
|
+
|
|
62
221
|
await downloadFile(GITHUB_ZIP_URL, zipPath);
|
|
63
222
|
console.log('Downloaded successfully.');
|
|
64
223
|
|
|
65
|
-
console.log('Extracting zip file...');
|
|
66
224
|
await extractZip(zipPath, tmpDir.name);
|
|
67
|
-
console.log('Extraction complete.');
|
|
68
225
|
|
|
69
|
-
// Determine the extracted folder name
|
|
70
226
|
const extractedFolderName = fs.readdirSync(tmpDir.name)[0];
|
|
71
227
|
const extractedFolderPath = path.join(tmpDir.name, extractedFolderName);
|
|
72
228
|
|
|
73
|
-
|
|
74
|
-
fs.readdirSync(extractedFolderPath).forEach((file) => {
|
|
75
|
-
fs.renameSync(path.join(extractedFolderPath, file), path.join(destDir, file));
|
|
76
|
-
});
|
|
229
|
+
fs.readdirSync(extractedFolderPath);
|
|
77
230
|
|
|
78
|
-
|
|
231
|
+
await moveFiles(extractedFolderPath, destDir);
|
|
79
232
|
|
|
80
|
-
// Run npm install in the destination directory
|
|
81
|
-
console.log('Running npm install...');
|
|
82
233
|
await runNpmInstall(destDir);
|
|
83
|
-
console.log('npm install completed.');
|
|
84
234
|
|
|
85
|
-
|
|
86
|
-
|
|
235
|
+
rl.close();
|
|
236
|
+
|
|
237
|
+
process.exit(0);
|
|
87
238
|
} catch (err) {
|
|
88
239
|
console.error('Error:', err);
|
|
240
|
+
rl.close();
|
|
241
|
+
process.exit(1);
|
|
89
242
|
}
|
|
90
243
|
};
|
|
91
244
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "afront",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "AFront is a front-end JavaScript library designed to create seamless server-side rendered (SSSR) websites.",
|
|
5
5
|
"main": "webpack.dev.js",
|
|
6
6
|
"scripts": {
|
|
@@ -44,7 +44,11 @@
|
|
|
44
44
|
"readline-sync": "^1.4.10",
|
|
45
45
|
"styled-components": "^6.1.12",
|
|
46
46
|
"terser-webpack-plugin": "^5.3.10",
|
|
47
|
-
"tmp": "^0.2.1"
|
|
47
|
+
"tmp": "^0.2.1",
|
|
48
|
+
"extract-zip": "^2.0.0",
|
|
49
|
+
"adm-zip": "^0.5.15",
|
|
50
|
+
"afront": "^1.0.5",
|
|
51
|
+
"follow-redirects": "^1.15.6"
|
|
48
52
|
},
|
|
49
53
|
"devDependencies": {
|
|
50
54
|
"@babel/cli": "^7.24.8",
|