Skip to content

Commit 1e1eaa6

Browse files
committed
feat: add ESLint configuration, update package.json, and enhance download functionality
1 parent a98f02d commit 1e1eaa6

File tree

7 files changed

+6174
-511
lines changed

7 files changed

+6174
-511
lines changed

.editorconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
indent_size = 2
7+
indent_style = space
8+
insert_final_newline = true
9+
max_line_length = 100
10+
quote_type = single
11+
trim_trailing_whitespace = true

.vscode/extensions.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"recommendations": [
3+
"dbaeumer.vscode-eslint",
4+
"editorconfig.editorconfig",
5+
"esbenp.prettier-vscode",
6+
"stylelint.vscode-stylelint"
7+
]
8+
}

.vscode/settings.json

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
3+
"stylelint.validate": ["css", "scss", "less"],
4+
"editor.codeActionsOnSave": {
5+
"source.fixAll.eslint": "explicit",
6+
"source.fixAll.stylelint": "explicit",
7+
"source.organizeImports": "explicit"
8+
},
9+
"editor.rulers": [100],
10+
"editor.defaultFormatter": "esbenp.prettier-vscode",
11+
"editor.formatOnSave": true,
12+
"[javascript]": {
13+
"editor.defaultFormatter": "esbenp.prettier-vscode"
14+
},
15+
"[javascriptreact]": {
16+
"editor.defaultFormatter": "esbenp.prettier-vscode"
17+
},
18+
"[typescript]": {
19+
"editor.defaultFormatter": "esbenp.prettier-vscode"
20+
},
21+
"[typescriptreact]": {
22+
"editor.defaultFormatter": "esbenp.prettier-vscode"
23+
},
24+
"[vue]": {
25+
"editor.defaultFormatter": "esbenp.prettier-vscode"
26+
},
27+
"[css]": {
28+
"editor.defaultFormatter": "esbenp.prettier-vscode"
29+
},
30+
"[less]": {
31+
"editor.defaultFormatter": "esbenp.prettier-vscode"
32+
},
33+
"[scss]": {
34+
"editor.defaultFormatter": "esbenp.prettier-vscode"
35+
},
36+
"[html]": {
37+
"editor.defaultFormatter": "esbenp.prettier-vscode"
38+
},
39+
"[json]": {
40+
"editor.defaultFormatter": "esbenp.prettier-vscode"
41+
},
42+
"[jsonc]": {
43+
"editor.defaultFormatter": "esbenp.prettier-vscode"
44+
}
45+
}

eslint.config.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { base } from 'eslint-config-ali';
2+
3+
export default [...base];

index.js

Lines changed: 139 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -4,157 +4,154 @@ const { exec } = require('child_process');
44
const fs = require('fs');
55
const path = require('path');
66
const https = require('https');
7+
const readline = require('readline');
78

8-
// 获取命令行参数中的端口号和baseUrl
9+
const rl = readline.createInterface({
10+
input: process.stdin,
11+
output: process.stdout,
12+
});
13+
14+
// 获取命令行参数中的端口号
915
let port = process.argv[2] || 4000;
10-
const baseUrl = process.argv[3] || 'https://your-resource-domain.com';
1116

1217
// 验证端口号是否有效
1318
port = parseInt(port);
1419
if (isNaN(port) || port < 1 || port > 65535) {
15-
console.error('Invalid port number. Using default port 4000');
16-
port = 4000;
20+
console.error('Invalid port number. Using default port 4000');
21+
port = 4000;
1722
}
1823

19-
// 原来的颜色代码是 0,115,128,我们改成更亮的蓝绿色
20-
const arrow = '\x1b[38;2;0;200;255m\u2192\x1b[0m'; // 更亮的箭头颜色
21-
const label = '\x1b[37m'; // 更亮的白色文本
22-
const value = '\x1b[38;2;0;255;255m'; // 更亮的青色值
24+
// 颜色代码
25+
const arrow = '\x1b[38;2;0;200;255m\u2192\x1b[0m';
26+
const label = '\x1b[37m';
27+
const value = '\x1b[38;2;0;255;255m';
2328

2429
console.log(`${arrow}${label} Local: ${value}http://127.0.0.1:${port}\x1b[0m`);
25-
console.log(`${arrow}${label} Base URL: ${value}${baseUrl}\x1b[0m`);
26-
const server = exec(`http-server -p ${port}`);
27-
28-
// 创建目录的函数
29-
function ensureDirectoryExists(filePath) {
30-
const dirname = path.dirname(filePath);
31-
if (fs.existsSync(dirname)) {
32-
return true;
33-
}
34-
ensureDirectoryExists(dirname);
35-
fs.mkdirSync(dirname);
36-
}
37-
38-
// 下载文件的函数
39-
function downloadFile(url, filePath, retryCount = 3) {
40-
ensureDirectoryExists(filePath);
41-
42-
// 如果文件已存在,跳过下载
43-
if (fs.existsSync(filePath)) {
44-
console.log(`File already exists: ${filePath}`);
45-
return;
46-
}
47-
48-
const file = fs.createWriteStream(filePath);
49-
let fileSize = 0;
50-
let currentRetry = 0;
51-
52-
const startDownload = () => {
53-
fileSize = 0; // 重置文件大小计数
54-
55-
https.get(url, response => {
56-
// 检查响应状态码
57-
if (response.statusCode !== 200) {
58-
file.close();
59-
fs.unlink(filePath, () => {});
60-
if (currentRetry < retryCount) {
61-
currentRetry++;
62-
console.log(`Retrying download (${currentRetry}/${retryCount}) for ${filePath} due to HTTP status ${response.statusCode}`);
63-
startDownload();
64-
} else {
65-
console.error(`Failed to download ${filePath}: HTTP Status ${response.statusCode} after ${retryCount} retries`);
66-
}
67-
return;
68-
}
69-
70-
response.on('data', (chunk) => {
71-
fileSize += chunk.length;
72-
});
73-
74-
response.pipe(file);
75-
76-
file.on('finish', () => {
77-
file.close(() => {
78-
// 检查文件大小
79-
if (fileSize === 0) {
80-
fs.unlink(filePath, () => {
81-
if (currentRetry < retryCount) {
82-
currentRetry++;
83-
console.log(`Retrying download (${currentRetry}/${retryCount}) for ${filePath} due to empty file`);
84-
startDownload();
85-
} else {
86-
console.error(`Failed to download ${filePath}: File is empty after ${retryCount} retries`);
87-
}
88-
});
89-
} else {
90-
console.log(`Downloaded: ${filePath} (${fileSize} bytes)`);
91-
}
92-
});
93-
});
94-
}).on('error', err => {
95-
file.close();
96-
fs.unlink(filePath, () => {
97-
if (currentRetry < retryCount) {
98-
currentRetry++;
99-
console.log(`Retrying download (${currentRetry}/${retryCount}) for ${filePath} due to error: ${err.message}`);
100-
startDownload();
101-
} else {
102-
console.error(`Download failed for ${filePath} after ${retryCount} retries:`, err.message);
103-
}
104-
});
105-
});
106-
};
107-
108-
// 添加文件写入错误处理
109-
file.on('error', err => {
110-
file.close();
111-
fs.unlink(filePath, () => {
112-
if (currentRetry < retryCount) {
113-
currentRetry++;
114-
console.log(`Retrying download (${currentRetry}/${retryCount}) for ${filePath} due to file write error: ${err.message}`);
115-
startDownload();
116-
} else {
117-
console.error(`File write error for ${filePath} after ${retryCount} retries:`, err.message);
118-
}
119-
});
120-
});
121-
122-
// 开始首次下载
123-
startDownload();
124-
}
125-
126-
// 获取标准输出
127-
server.stdout.on('data', (data) => {
128-
const output = data.toString();
129-
130-
// 定义正则表达式,支持任意文件后缀
131-
const regex = /"GET (\/.*?\.[a-zA-Z0-9]+)" Error \(404\):/g;
132-
133-
// 使用正则表达式匹配包含 404 错误的行并提取路径
134-
const matches = [...output.matchAll(regex)];
135-
if (matches.length > 0) {
136-
matches.forEach((match) => {
137-
const missingFile = match[1].replace(/"/g, ''); // 移除引号
138-
console.log('Missing file:', missingFile);
139-
140-
// 构建完整的本地文件路径(从项目根目录开始)
141-
const localPath = path.join(process.cwd(), missingFile);
142-
143-
// 使用命令行传入的baseUrl构建下载URL
144-
const downloadUrl = `${baseUrl}${missingFile}`;
145-
146-
// 下载文件
147-
downloadFile(downloadUrl, localPath);
148-
});
149-
}
150-
});
151-
152-
// 获取标准错误输出
153-
server.stderr.on('data', (data) => {
154-
console.error('stderr:', data.toString());
155-
});
15630

157-
// 监听进程结束
158-
server.on('close', (code) => {
159-
console.log(`http-server process exited with code ${code}`);
31+
rl.question(`${arrow}${label} Please enter the base URL: \x1b[0m`, (baseUrl) => {
32+
console.log(`${arrow}${label} Base URL: ${value}${baseUrl}\x1b[0m`);
33+
rl.close();
34+
35+
const server = exec(`http-server -p ${port}`);
36+
37+
// 创建目录的函数
38+
function ensureDirectoryExists(filePath) {
39+
const dirname = path.dirname(filePath);
40+
if (fs.existsSync(dirname)) {
41+
return true;
42+
}
43+
ensureDirectoryExists(dirname);
44+
fs.mkdirSync(dirname);
45+
}
46+
47+
// 下载文件的函数
48+
function downloadFile(url, filePath, retryCount = 3) {
49+
ensureDirectoryExists(filePath);
50+
51+
if (fs.existsSync(filePath)) {
52+
console.log(`File already exists: ${filePath}`);
53+
return;
54+
}
55+
56+
const file = fs.createWriteStream(filePath);
57+
let fileSize = 0;
58+
59+
let currentRetry = 0;
60+
61+
const startDownload = () => {
62+
fileSize = 0;
63+
64+
https.get(url, (response) => {
65+
if (response.statusCode !== 200) {
66+
file.close();
67+
fs.unlink(filePath, () => {});
68+
if (currentRetry < retryCount) {
69+
currentRetry++;
70+
console.log(`Retrying download (${currentRetry}/${retryCount}) for ${filePath} due to HTTP status ${response.statusCode}`);
71+
startDownload();
72+
} else {
73+
console.error(`Failed to download ${filePath}: HTTP Status ${response.statusCode} after ${retryCount} retries`);
74+
}
75+
return;
76+
}
77+
78+
response.on('data', (chunk) => {
79+
fileSize += chunk.length;
80+
});
81+
82+
response.pipe(file);
83+
84+
file.on('finish', () => {
85+
file.close(() => {
86+
if (fileSize === 0) {
87+
fs.unlink(filePath, () => {
88+
if (currentRetry < retryCount) {
89+
currentRetry++;
90+
console.log(`Retrying download (${currentRetry}/${retryCount}) for ${filePath} due to empty file`);
91+
startDownload();
92+
} else {
93+
console.error(`Failed to download ${filePath}: File is empty after ${retryCount} retries`);
94+
}
95+
});
96+
} else {
97+
console.log(`Downloaded: ${filePath} (${fileSize} bytes)`);
98+
}
99+
});
100+
});
101+
}).on('error', (err) => {
102+
file.close();
103+
fs.unlink(filePath, () => {
104+
if (currentRetry < retryCount) {
105+
currentRetry++;
106+
console.log(`Retrying download (${currentRetry}/${retryCount}) for ${filePath} due to error: ${err.message}`);
107+
startDownload();
108+
} else {
109+
console.error(`Download failed for ${filePath} after ${retryCount} retries:`, err.message);
110+
}
111+
});
112+
});
113+
};
114+
115+
file.on('error', (err) => {
116+
file.close();
117+
fs.unlink(filePath, () => {
118+
if (currentRetry < retryCount) {
119+
currentRetry++;
120+
console.log(`Retrying download (${currentRetry}/${retryCount}) for ${filePath} due to file write error: ${err.message}`);
121+
startDownload();
122+
} else {
123+
console.error(`File write error for ${filePath} after ${retryCount} retries:`, err.message);
124+
}
125+
});
126+
});
127+
128+
startDownload();
129+
}
130+
131+
server.stdout.on('data', (data) => {
132+
const output = data.toString();
133+
const regex = /"GET (\/.*?\.[a-zA-Z0-9]+)" Error \(404\):/g;
134+
const matches = [...output.matchAll(regex)];
135+
136+
if (matches.length > 0) {
137+
matches.forEach((match) => {
138+
const encodedMissingFile = match[1].replace(/"/g, '');
139+
const decodedMissingFile = decodeURIComponent(encodedMissingFile);
140+
console.log('Missing file:', decodedMissingFile);
141+
142+
const localPath = path.join(process.cwd(), decodedMissingFile);
143+
const downloadUrl = `${baseUrl}${encodedMissingFile}`;
144+
145+
downloadFile(downloadUrl, localPath);
146+
});
147+
}
148+
});
149+
150+
server.stderr.on('data', (data) => {
151+
console.error('stderr:', data.toString());
152+
});
153+
154+
server.on('close', (code) => {
155+
console.log(`http-server process exited with code ${code}`);
156+
});
160157
});

0 commit comments

Comments
 (0)