Skip to content

Commit b62034e

Browse files
committed
feat: 项目配置的验证支持使用远程配置文件
1 parent 33faee1 commit b62034e

7 files changed

Lines changed: 107 additions & 20 deletions

File tree

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ crate-type = ["cdylib"]
1212
napi = { version = "2", default-features = false, features = [
1313
"napi4",
1414
"serde-json",
15+
"async"
1516
] }
1617
napi-derive = { version = "2", default-features = false }
1718

@@ -20,6 +21,8 @@ jsonschema = "0.17"
2021
emojis = "0.6.0"
2122
console = "0.15.7"
2223
regex = "1.8.3"
24+
reqwest = "0.11.18"
25+
tokio = "1.28.2"
2326

2427
[build-dependencies]
2528
napi-build = "2.0.1"

assets/config_schema.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,14 @@
142142
"oneOf": [
143143
{
144144
"type": "string",
145-
"enum": ["webpack4", "webpack5"]
145+
"enum": ["webpack4", "webpack5", "vite"]
146146
},
147147
{
148148
"type": "object",
149149
"properties": {
150150
"type": {
151151
"type": "string",
152-
"enum": ["webpack4", "webpack5"]
152+
"enum": ["webpack4", "webpack5", "vite"]
153153
},
154154
"prebundle": {
155155
"type": "object",

index.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ exports.default = (ctx) => {
2020
fn() {
2121
return __awaiter(this, void 0, void 0, function* () {
2222
const { appPath, nodeModulesPath, configPath } = ctx.paths;
23-
const { fs, chalk, PROJECT_CONFIG } = ctx.helper;
23+
const { fs, chalk, getUserHomeDir, TARO_CONFIG_FOLDER, TARO_BASE_CONFIG, PROJECT_CONFIG } = ctx.helper;
2424
if (!configPath || !fs.existsSync(configPath)) {
2525
console.log(chalk.red(`找不到项目配置文件${PROJECT_CONFIG},请确定当前目录是 Taro 项目根目录!`));
2626
process.exit(1);
@@ -31,8 +31,24 @@ exports.default = (ctx) => {
3131
}
3232
return v;
3333
});
34+
let remoteConfigSchemaUrl = 'https://raw.githubusercontent.com/NervJS/taro-doctor/main/assets/config_schema.json';
35+
let useRemoteConfigSchema = true;
36+
const homedir = getUserHomeDir();
37+
if (homedir) {
38+
const taroConfigPath = path.join(homedir, TARO_CONFIG_FOLDER);
39+
const taroConfig = path.join(taroConfigPath, TARO_BASE_CONFIG);
40+
if (fs.existsSync(taroConfig)) {
41+
const config = yield fs.readJSON(taroConfig);
42+
remoteConfigSchemaUrl = config && config.remoteConfigSchemaUrl ? config.remoteConfigSchemaUrl : remoteConfigSchemaUrl;
43+
useRemoteConfigSchema = config && config.useRemoteConfigSchema ? config.useRemoteConfigSchema : useRemoteConfigSchema;
44+
}
45+
else {
46+
yield fs.createFile(taroConfig);
47+
yield fs.writeJSON(taroConfig, { remoteConfigSchemaUrl, useRemoteConfigSchema });
48+
}
49+
}
3450
(0, js_binding_1.validateEnvPrint)();
35-
(0, js_binding_1.validateConfigPrint)(configStr);
51+
yield (0, js_binding_1.validateConfigPrint)(configStr, remoteConfigSchemaUrl, useRemoteConfigSchema);
3652
(0, js_binding_1.validatePackagePrint)(appPath, nodeModulesPath);
3753
(0, js_binding_1.validateRecommendPrint)(appPath);
3854
yield validateEslintPrint(ctx.initialConfig, chalk);

index.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default (ctx) => {
1717
name: 'doctor',
1818
async fn() {
1919
const { appPath, nodeModulesPath, configPath } = ctx.paths
20-
const { fs, chalk, PROJECT_CONFIG } = ctx.helper
20+
const { fs, chalk, getUserHomeDir, TARO_CONFIG_FOLDER, TARO_BASE_CONFIG, PROJECT_CONFIG } = ctx.helper
2121

2222
if (!configPath || !fs.existsSync(configPath)) {
2323
console.log(chalk.red(`找不到项目配置文件${PROJECT_CONFIG},请确定当前目录是 Taro 项目根目录!`))
@@ -29,8 +29,23 @@ export default (ctx) => {
2929
}
3030
return v
3131
})
32+
let remoteConfigSchemaUrl = 'https://raw.githubusercontent.com/NervJS/taro-doctor/main/assets/config_schema.json'
33+
let useRemoteConfigSchema = true
34+
const homedir = getUserHomeDir()
35+
if (homedir) {
36+
const taroConfigPath = path.join(homedir, TARO_CONFIG_FOLDER)
37+
const taroConfig = path.join(taroConfigPath, TARO_BASE_CONFIG)
38+
if (fs.existsSync(taroConfig)) {
39+
const config = await fs.readJSON(taroConfig)
40+
remoteConfigSchemaUrl = config && config.remoteConfigSchemaUrl ? config.remoteConfigSchemaUrl : remoteConfigSchemaUrl
41+
useRemoteConfigSchema = config && config.useRemoteConfigSchema ? config.useRemoteConfigSchema : useRemoteConfigSchema
42+
} else {
43+
await fs.createFile(taroConfig)
44+
await fs.writeJSON(taroConfig, { remoteConfigSchemaUrl, useRemoteConfigSchema })
45+
}
46+
}
3247
validateEnvPrint()
33-
validateConfigPrint(configStr)
48+
await validateConfigPrint(configStr, remoteConfigSchemaUrl, useRemoteConfigSchema)
3449
validatePackagePrint(appPath, nodeModulesPath)
3550
validateRecommendPrint(appPath)
3651
await validateEslintPrint(ctx.initialConfig, chalk)

js-binding.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ export interface ValidateResult {
1919
isValid: boolean
2020
messages: Array<Message>
2121
}
22-
export function validateConfig(configStr: string): ValidateResult
23-
export function validateConfigPrint(configStr: string): boolean
22+
export function validateConfig(configStr: string, remoteSchemaUrl: string, useRemoteSchema: boolean): Promise<ValidateResult>
23+
export function validateConfigPrint(configStr: string, remoteSchemaUrl: string, useRemoteSchema: boolean): Promise<boolean>
2424
export function validatePackage(appPath: string, nodeModulesPath: string): ValidateResult
2525
export function validatePackagePrint(appPath: string, nodeModulesPath: string): boolean
2626
export function validateEnv(): ValidateResult

src/lib.rs

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#![deny(clippy::all)]
22

33
mod validators;
4-
54
use std::{error::Error, fs, path::PathBuf};
65

7-
use validators::{env::EnvValidator, message::ValidateResult, recommend::RecommendValidator};
6+
use validators::{env::EnvValidator, message::ValidateResult, recommend::RecommendValidator, common::fetch_data_text};
87

98
use crate::validators::{
109
common::Validator,
@@ -17,8 +16,8 @@ use crate::validators::{
1716
extern crate napi_derive;
1817

1918
#[napi]
20-
pub fn validate_config(config_str: String) -> ValidateResult {
21-
let result = validate_config_core(config_str);
19+
pub async fn validate_config(config_str: String, remote_schema_url: String, use_remote_schema: bool) -> ValidateResult {
20+
let result = validate_config_core(config_str, remote_schema_url, use_remote_schema).await;
2221
let messages = match result {
2322
Ok(messages) => messages,
2423
Err(e) => {
@@ -42,8 +41,8 @@ pub fn validate_config(config_str: String) -> ValidateResult {
4241
}
4342

4443
#[napi]
45-
pub fn validate_config_print(config_str: String) -> bool {
46-
let result = validate_config_core(config_str);
44+
pub async fn validate_config_print(config_str: String, remote_schema_url: String, use_remote_schema: bool) -> bool {
45+
let result = validate_config_core(config_str, remote_schema_url, use_remote_schema).await;
4746
let messages = match result {
4847
Ok(messages) => messages,
4948
Err(e) => {
@@ -220,14 +219,35 @@ pub fn validate_recommend_print(app_path: String) -> bool {
220219
is_valid
221220
}
222221

223-
fn validate_config_core(config_str: String) -> Result<Vec<Message>, Box<dyn Error>> {
224-
let tip = Message {
222+
async fn validate_config_core(config_str: String, remote_schema_url: String, use_remote_schema: bool) -> Result<Vec<Message>, Box<dyn Error>> {
223+
let mut tip = vec![Message {
225224
kind: MessageKind::Info,
226225
content: String::from("验证项目配置 (/config/index.js) !"),
227226
solution: None,
227+
}];
228+
let schema_str = if use_remote_schema {
229+
match fetch_data_text(&remote_schema_url).await {
230+
Ok(schema_str) => {
231+
tip.push(Message {
232+
kind: MessageKind::Success,
233+
content: String::from(format!("成功获取远程配置验证文件:{}", remote_schema_url)),
234+
solution: None,
235+
});
236+
schema_str
237+
},
238+
Err(_) => {
239+
tip.push(Message {
240+
kind: MessageKind::Warning,
241+
content: String::from("无法获取远程配置验证文件,将使用本地配置验证文件!"),
242+
solution: None,
243+
});
244+
include_str!("../assets/config_schema.json").to_string()
245+
}
246+
}
247+
} else {
248+
include_str!("../assets/config_schema.json").to_string()
228249
};
229-
let schema_str = include_str!("../assets/config_schema.json");
230-
let config_validator_result = ConfigValidator::build(String::from(schema_str), config_str);
250+
let config_validator_result = ConfigValidator::build(schema_str, config_str);
231251
let mut messages = match config_validator_result {
232252
Ok(config_validator) => config_validator.validate(),
233253
Err(e) => vec![Message {
@@ -243,7 +263,7 @@ fn validate_config_core(config_str: String) -> Result<Vec<Message>, Box<dyn Erro
243263
solution: None,
244264
})
245265
}
246-
messages.insert(0, tip);
266+
messages.splice(0..0, tip);
247267
Ok(messages)
248268
}
249269

src/validators/common.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{cmp::Ordering, error::Error, fs, path::PathBuf};
1+
use std::{cmp::Ordering, error::Error, fs, path::PathBuf, time::Duration};
22

33
use serde_json::{from_str, Value};
44

@@ -14,6 +14,14 @@ pub struct PackageInfo {
1414
pub json: Value,
1515
}
1616

17+
/**
18+
* @description: 获取 package.json 信息
19+
* @param {&str} node_modules_path
20+
* @param {&str} name
21+
* @return {Result<PackageInfo, Box<dyn Error>>}
22+
* @example:
23+
* get_package_info("./node_modules", "react")
24+
*/
1725
pub fn get_package_info(
1826
node_modules_path: &str,
1927
name: &str,
@@ -51,6 +59,12 @@ pub fn get_package_info(
5159
}
5260
}
5361

62+
/**
63+
* @description: 比较版本号
64+
* @param {&str} a
65+
* @param {&str} b
66+
* @return {Option<Ordering>}
67+
*/
5468
pub fn compare_versions(a: &str, b: &str) -> Option<Ordering> {
5569
let parts1: Vec<u64> = a.split('.').filter_map(|s| s.parse().ok()).collect();
5670
let parts2: Vec<u64> = b.split('.').filter_map(|s| s.parse().ok()).collect();
@@ -68,3 +82,22 @@ pub fn compare_versions(a: &str, b: &str) -> Option<Ordering> {
6882
Ordering::Equal => Some(Ordering::Equal),
6983
}
7084
}
85+
86+
/**
87+
* @description: 获取远程数据
88+
* @param {&str} url
89+
* @return {Result<String, reqwest::Error>}
90+
*/
91+
pub async fn fetch_data_text(url: &str) -> Result<String, reqwest::Error> {
92+
let client = reqwest::Client::builder()
93+
.timeout(Duration::from_secs(1))
94+
.build()?;
95+
let response = client.get(url).send().await?;
96+
if response.status().is_success() {
97+
let text = response.text().await?;
98+
Ok(text)
99+
} else {
100+
let error = response.error_for_status();
101+
Err(error.unwrap_err())
102+
}
103+
}

0 commit comments

Comments
 (0)