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.
Files changed (2) hide show
  1. package/install.js +181 -28
  2. 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('https');
4
+ const { https } = require('follow-redirects');
5
5
  const { exec } = require('child_process');
6
6
  const tmp = require('tmp');
7
- const extract = require('extract-zip');
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
- // Download file from GitHub
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(resolve);
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
- extract(zipPath, { dir: extractTo }, (err) => {
32
- if (err) reject(err);
33
- else resolve();
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
- // Main function
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
- console.log('Downloading zip file...');
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
- // Move extracted contents to the destination directory
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
- console.log(`Files have been extracted to ${destDir}`);
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
- // Clean up
86
- tmpDir.removeCallback();
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.4",
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",