Skip to content

Commit f32033f

Browse files
committed
feat: 优化推荐验证
1 parent 7a72ef5 commit f32033f

4 files changed

Lines changed: 150 additions & 30 deletions

File tree

index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
export function validateConfig(configStr: string): void
77
export function validatePackage(appPath: string, nodeModulesPath: string, cliVersion: string): void
88
export function validateEnv(): void
9-
export function validateRecommend(appPath: string, nodeModulesPath: string): void
9+
export function validateRecommend(appPath: string): void

src/lib.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::{ fs, error::Error, path::PathBuf, env };
66

77
use validators::{env::EnvValidator, Recommend::RecommendValidator};
88

9-
use crate::validators::{ message::{ Message, self }, package::{ PackageValidator }, config::ConfigValidator, common::{ Validator } };
9+
use crate::validators::{ message::{ Message, MessageKind }, package::{ PackageValidator }, config::ConfigValidator, common::{ Validator } };
1010

1111
#[macro_use]
1212
extern crate napi_derive;
@@ -15,38 +15,38 @@ extern crate napi_derive;
1515
pub fn validate_config(config_str: String) {
1616
let result = validate_config_core(config_str);
1717
if let Err(e) = result {
18-
println!("{}", Message { kind: message::MessageKind::Error, content: e.to_string(), solution: None });
18+
println!("{}", Message { kind: MessageKind::Error, content: e.to_string(), solution: None });
1919
}
2020
}
2121

2222
#[napi]
2323
pub fn validate_package(app_path: String, node_modules_path: String, cli_version: String) {
2424
let result = validate_package_core(app_path, node_modules_path, cli_version);
2525
if let Err(e) = result {
26-
println!("{}", Message { kind: message::MessageKind::Error, content: e.to_string(), solution: None });
26+
println!("{}", Message { kind: MessageKind::Error, content: e.to_string(), solution: None });
2727
}
2828
}
2929

3030
#[napi]
3131
pub fn validate_env() {
3232
let result = validate_env_core();
3333
if let Err(e) = result {
34-
println!("{}", Message { kind: message::MessageKind::Error, content: e.to_string(), solution: None });
34+
println!("{}", Message { kind: MessageKind::Error, content: e.to_string(), solution: None });
3535
}
3636
}
3737

3838
#[napi]
39-
pub fn validate_recommend(app_path: String, node_modules_path: String) {
40-
let result = validate_recommend_core(app_path, node_modules_path);
39+
pub fn validate_recommend(app_path: String) {
40+
let result = validate_recommend_core(app_path);
4141
if let Err(e) = result {
42-
println!("{}", Message { kind: message::MessageKind::Error, content: e.to_string(), solution: None });
42+
println!("{}", Message { kind: MessageKind::Error, content: e.to_string(), solution: None });
4343
}
4444
}
4545

4646
fn validate_config_core(config_str: String) -> Result<(), Box<dyn Error>> {
4747
let tip = Message {
48-
kind: validators::message::MessageKind::Info,
49-
content: String::from("开始进行项目配置验证!"),
48+
kind: MessageKind::Info,
49+
content: String::from("验证项目配置配置!"),
5050
solution: None
5151
};
5252
println!("{}", tip);
@@ -63,7 +63,7 @@ fn validate_config_core(config_str: String) -> Result<(), Box<dyn Error>> {
6363
Ok(config_validator) => config_validator.validate(),
6464
Err(e) => vec![
6565
Message {
66-
kind: validators::message::MessageKind::Error,
66+
kind: MessageKind::Error,
6767
content: e.to_string(),
6868
solution: None
6969
}
@@ -74,15 +74,15 @@ fn validate_config_core(config_str: String) -> Result<(), Box<dyn Error>> {
7474
println!("{}", message);
7575
}
7676
} else {
77-
println!("{}", Message { kind: message::MessageKind::Success, content: "项目配置正确!".to_string(), solution: None });
77+
println!("{}", Message { kind: MessageKind::Success, content: "项目配置正确!".to_string(), solution: None });
7878
}
7979
Ok(())
8080
}
8181

8282
fn validate_package_core(app_path: String, node_modules_path: String, cli_version: String) -> Result<(), Box<dyn Error>> {
8383
let tip = Message {
84-
kind: validators::message::MessageKind::Info,
85-
content: String::from("开始进行项目依赖安装正确性验证!"),
84+
kind: MessageKind::Info,
85+
content: String::from("验证项目依赖安装正确性!"),
8686
solution: None
8787
};
8888
println!("{}", tip);
@@ -95,7 +95,7 @@ fn validate_package_core(app_path: String, node_modules_path: String, cli_versio
9595
Ok(package_validator) => package_validator.validate(),
9696
Err(e) => vec![
9797
Message {
98-
kind: validators::message::MessageKind::Error,
98+
kind: MessageKind::Error,
9999
content: e.to_string(),
100100
solution: None
101101
}
@@ -108,6 +108,12 @@ fn validate_package_core(app_path: String, node_modules_path: String, cli_versio
108108
}
109109

110110
fn validate_env_core() -> Result<(), Box<dyn Error>> {
111+
let tip = Message {
112+
kind: MessageKind::Info,
113+
content: String::from("验证环境信息!"),
114+
solution: None
115+
};
116+
println!("{}", tip);
111117
let env_validator = EnvValidator::build();
112118
let messages = env_validator.validate();
113119
for message in messages {
@@ -116,13 +122,19 @@ fn validate_env_core() -> Result<(), Box<dyn Error>> {
116122
Ok(())
117123
}
118124

119-
fn validate_recommend_core(app_path: String, node_modules_path: String) -> Result<(), Box<dyn Error>> {
120-
let recommend_validator_result = RecommendValidator::build(&app_path, &node_modules_path);
125+
fn validate_recommend_core(app_path: String) -> Result<(), Box<dyn Error>> {
126+
let tip = Message {
127+
kind: MessageKind::Info,
128+
content: String::from("验证最佳实践!"),
129+
solution: None
130+
};
131+
println!("{}", tip);
132+
let recommend_validator_result = RecommendValidator::build(&app_path);
121133
let messages = match recommend_validator_result {
122134
Ok(recommend_validator) => recommend_validator.validate(),
123135
Err(e) => vec![
124136
Message {
125-
kind: validators::message::MessageKind::Error,
137+
kind: MessageKind::Error,
126138
content: e.to_string(),
127139
solution: None
128140
}

src/validators/message.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl fmt::Display for Message {
2323
match &self.kind {
2424
MessageKind::Error => {
2525
if let Some(solution) = &self.solution {
26-
write!(f, "{} {} {}", style("[✗] ").red(), style(&self.content).white(), style(solution).color256(246))
26+
write!(f, "{} {} {}", style("[✗] ").red(), style(&self.content).white(), style(solution).color256(246))
2727
} else {
2828
write!(f, "{} {}", style("[✗] ").red(), style(&self.content).white())
2929
}
@@ -36,7 +36,7 @@ impl fmt::Display for Message {
3636
},
3737
MessageKind::Warning => {
3838
if let Some(solution) = &self.solution {
39-
write!(f, "{} {} {}", style("[!] ").yellow(), style(&self.content).white(), style(solution).color256(246))
39+
write!(f, "{} {} {}", style("[!] ").yellow(), style(&self.content).white(), style(solution).color256(246))
4040
} else {
4141
write!(f, "{} {}", style("[!] ").yellow(), style(&self.content).white())
4242
}

src/validators/recommend.rs

Lines changed: 118 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
use std::{error::Error, collections::HashSet};
1+
use std::{error::Error, collections::HashSet, fs, path::{PathBuf, MAIN_SEPARATOR}};
22

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

5-
use super::{ common::{Validator, compare_versions, get_package_info}, message::{ Message, MessageKind } };
5+
use super::{ common::{Validator, get_package_info}, message::{ Message, MessageKind } };
66

77
const TEST_FRAMEWORKS: [&str; 6] = ["jest", "mocha", "ava", "tape", "jesmine", "karma"];
88
const LINTERS: [&str; 4] = ["eslint", "jslint", "tslint", "jshint"];
99
const README: [&str; 3] = ["readme", "readme.md", "readme.markdown"];
1010
const GITIGNORE: [&str; 1] = [".gitignore"];
11-
const EDITORCONFIG: [&str; 1] = [".editorconfig"];
11+
const EDITORCONFIG: [&str; 7] = [".editorconfig", "editorconfig", ".prettierrc", ".prettierrc.json", ".prettierrc.yml", ".prettierrc.js", "prettier.config.js"];
1212

1313
pub struct RecommendValidator<'a> {
1414
pub app_path: &'a str,
1515
pub json: Value,
1616
}
1717

1818
impl<'a> RecommendValidator<'a> {
19-
pub fn build(app_path: &'a str, node_modules_path: &'a str) -> Result<Self, Box<dyn Error>> {
20-
let package_info = get_package_info(node_modules_path, "")?;
19+
pub fn build(app_path: &'a str) -> Result<Self, Box<dyn Error>> {
20+
let package_info = get_package_info(app_path, "")?;
2121
Ok(
2222
Self {
2323
app_path,
@@ -30,13 +30,121 @@ impl<'a> RecommendValidator<'a> {
3030
impl<'a> Validator for RecommendValidator<'a> {
3131
fn validate(&self) -> Vec<Message> {
3232
let mut messages = vec![];
33+
let is_intersecting = |a: &HashSet<_>, b: &HashSet<_>| !(*a).is_disjoint(b);
3334
// 读取 package.json
3435
let dev_dependencies = self.json.get("devDependencies").unwrap();
35-
let hasTestFramework = if let Value::Object(dev_dependencies_map) = dev_dependencies {
36-
let dev_dependencies: HashSet<_> = dev_dependencies_map.keys().map(|key| key.to_lowercase()).into_iter().collect();
37-
let test_frameworks: HashSet<_> = TEST_FRAMEWORKS.map(|key| key.to_lowercase()).into_iter().collect();
38-
let has_intersection = !test_frameworks.is_disjoint(&dev_dependencies);
39-
};
36+
let mut has_test_framework = false;
37+
let mut has_linter = false;
38+
if let Value::Object(dev_dependencies_map) = dev_dependencies {
39+
let dev_dependencies: HashSet<String> = dev_dependencies_map.keys().map(|key| key.to_lowercase()).into_iter().collect();
40+
let test_frameworks: HashSet<String> = TEST_FRAMEWORKS.map(|key| key.to_lowercase()).into_iter().collect();
41+
let linters: HashSet<String> = LINTERS.map(|key| key.to_lowercase()).into_iter().collect();
42+
if is_intersecting(&dev_dependencies, &test_frameworks) {
43+
has_test_framework = true;
44+
}
45+
if is_intersecting(&dev_dependencies, &linters) {
46+
has_linter = true;
47+
}
48+
}
49+
50+
if !has_test_framework {
51+
messages.push(
52+
Message {
53+
kind: MessageKind::Warning,
54+
content: String::from("没有检查到常见的测试依赖(jest/mocha/ava/tape/jesmine/karma), 配置测试可以帮助提升项目质量\n"),
55+
solution: Some(String::from("可以参考 https://github.com/NervJS/taro-ui-sample 项目, 其中已经包含了完整的测试配置与范例"))
56+
}
57+
)
58+
}
59+
60+
if !has_linter {
61+
messages.push(
62+
Message {
63+
kind: MessageKind::Warning,
64+
content: String::from("没有检查到常见的 linter (eslint/jslint/jshint/tslint), 配置 linter 可以帮助提升项目质量\n"),
65+
solution: Some(String::from("Taro 还提供了定制的 ESLint 规则, 可以帮助开发者避免一些常见的问题. 使用 taro cli 创建新项目即可体验"))
66+
}
67+
)
68+
}
69+
70+
let app_dir_read = fs::read_dir(self.app_path);
71+
match app_dir_read {
72+
Ok(app_dir) => {
73+
let mut file_list: Vec<PathBuf> = Vec::new();
74+
for entry in app_dir {
75+
match entry {
76+
Ok(entry) => {
77+
let path = entry.path();
78+
if path.is_file() {
79+
file_list.push(path);
80+
}
81+
82+
},
83+
Err(e) => {
84+
messages.push(
85+
Message { kind: MessageKind::Error, content: e.to_string(), solution: None }
86+
)
87+
}
88+
}
89+
}
90+
let mut has_readme = false;
91+
let mut has_gitignore = false;
92+
let mut has_editorconfig = false;
93+
let mut app_path = self.app_path.to_string();
94+
app_path.push(MAIN_SEPARATOR);
95+
let file_list: HashSet<String> = file_list.into_iter().map(|key: PathBuf| key.into_os_string().into_string().unwrap().replace(&app_path, "").to_lowercase()).into_iter().collect();
96+
println!("{:?}", file_list);
97+
let readme_list: HashSet<String> = README.map(|key| key.to_lowercase()).into_iter().collect();
98+
let gitignore_list: HashSet<String> = GITIGNORE.map(|key| key.to_lowercase()).into_iter().collect();
99+
let editorconfig_list: HashSet<String> = EDITORCONFIG.map(|key| key.to_lowercase()).into_iter().collect();
100+
101+
if is_intersecting(&file_list, &readme_list) {
102+
has_readme = true;
103+
}
104+
if is_intersecting(&file_list, &gitignore_list) {
105+
has_gitignore = true;
106+
}
107+
if is_intersecting(&file_list, &editorconfig_list) {
108+
has_editorconfig = true;
109+
}
110+
111+
if !has_readme {
112+
messages.push(
113+
Message {
114+
kind: MessageKind::Warning,
115+
content: String::from("没有检查到 Readme (readme/readme.md/readme.markdown), 编写 Readme 可以方便其他人了解项目"),
116+
solution: None
117+
}
118+
)
119+
}
120+
121+
if !has_gitignore {
122+
messages.push(
123+
Message {
124+
kind: MessageKind::Warning,
125+
content: String::from("没有检查到 .gitignore 配置, 配置 .gitignore 以避免将敏感信息或不必要的内容提交到代码仓库"),
126+
solution: None
127+
}
128+
)
129+
}
130+
131+
if !has_editorconfig {
132+
messages.push(
133+
Message {
134+
kind: MessageKind::Warning,
135+
content: String::from("没有检查到代码格式化配置 (editconfig/prettier), 可进行相关配置以统一项目成员编辑器的代码风格"),
136+
solution: None
137+
}
138+
)
139+
}
140+
},
141+
Err(e) => {
142+
messages.push(
143+
Message { kind: MessageKind::Error, content: e.to_string(), solution: None }
144+
)
145+
}
146+
}
147+
40148
messages
41149
}
42150
}

0 commit comments

Comments
 (0)