Skip to content

Commit

Permalink
feat: supports import local file in kcl-vet (#1290)
Browse files Browse the repository at this point in the history
* feat: supports import local file in kcl-vet

Signed-off-by: zongz <[email protected]>

* fix: fix bug

Signed-off-by: zongz <[email protected]>

* fix: make fmt

Signed-off-by: zongz <[email protected]>

* fix: fix test case

Signed-off-by: zongz <[email protected]>

---------

Signed-off-by: zongz <[email protected]>
  • Loading branch information
zong-zhe authored May 8, 2024
1 parent 63d695c commit 5578591
Show file tree
Hide file tree
Showing 16 changed files with 118 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "dep"
edition = "v0.8.0"
version = "0.0.1"

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema A :
name: str
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import .dep as dep

schema B:
a: dep.A
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"a": 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "dep"
edition = "v0.8.0"
version = "0.0.1"

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema A :
name: str
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import .dep as dep

schema B:
a: dep.A
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a: 1
5 changes: 5 additions & 0 deletions kclvm/tools/src/vet/test_datas/validate_cases/dep/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "dep"
edition = "v0.8.0"
version = "0.0.1"

2 changes: 2 additions & 0 deletions kclvm/tools/src/vet/test_datas/validate_cases/dep/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema A :
name: str
4 changes: 4 additions & 0 deletions kclvm/tools/src/vet/test_datas/validate_cases/with_import.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import .dep as dep

schema B:
a: dep.A
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"a": {
"name": "name"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a:
name: name
33 changes: 20 additions & 13 deletions kclvm/tools/src/vet/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,6 @@ mod test_validater {
path::{Path, PathBuf},
};

use regex::Regex;

use crate::{
util::loader::LoaderKind,
vet::{
Expand All @@ -327,15 +325,24 @@ mod test_validater {

use super::{construct_full_path, LOADER_KIND};

const KCL_TEST_CASES: &[&str] = &["test.k", "simple.k", "list.k", "plain_value.k", "complex.k"];
const KCL_TEST_CASES: &[&str] = &[
"test.k",
"simple.k",
"list.k",
"plain_value.k",
"complex.k",
"with_import.k",
];
const KCL_TEST_CASES_WITH_CODE: &[&str] =
&["test.k", "simple.k", "list.k", "plain_value.k", "complex.k"];
const VALIDATED_FILE_TYPE: &[&str] = &["json", "yaml"];

#[test]
fn test_validator() {
test_validate();
println!("test_validate - PASS");
test_invalid_validate();
println!("test_invalid_validate - PASS");
test_invalid_validate_only_code();
println!("test_invalid_validate_only_code - PASS");
test_validate_with_invalid_kcl_path();
println!("test_validate_with_invalid_kcl_path - PASS");
test_validate_with_invalid_file_path();
Expand Down Expand Up @@ -374,7 +381,7 @@ mod test_validater {

match validate(opt) {
Ok(res) => assert!(res),
Err(_) => panic!("Unreachable"),
Err(err) => assert!(false, "{:?}", err),
}
}
}
Expand Down Expand Up @@ -490,9 +497,10 @@ mod test_validater {
}
}

fn test_invalid_validate() {
#[test]
fn test_invalid_validate_only_code() {
for (i, file_suffix) in VALIDATED_FILE_TYPE.iter().enumerate() {
for case in KCL_TEST_CASES {
for case in KCL_TEST_CASES_WITH_CODE {
let validated_file_path = construct_full_path(&format!(
"{}.{}",
Path::new("invalid_validate_cases").join(case).display(),
Expand Down Expand Up @@ -541,11 +549,10 @@ mod test_validater {
panic!("unreachable")
}
Err(err) => {
assert!(Regex::new(
r"^Failed to load KCL file 'validationTempKCLCode.k'. Because .*"
)
.unwrap()
.is_match(&err.to_string()))
assert_eq!(
err.to_string(),
"Cannot find the kcl file, please check the file path validationTempKCLCode.k"
);
}
}
}
Expand Down
67 changes: 53 additions & 14 deletions kclvm/tools/src/vet/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ use super::expr_builder::ExprBuilder;
pub use crate::util::loader::LoaderKind;
use anyhow::Result;
use kclvm_ast::{
ast::{AssignStmt, Expr, ExprContext, Identifier, Module, Node, NodeRef, SchemaStmt, Stmt},
ast::{AssignStmt, Expr, ExprContext, Identifier, Node, NodeRef, Program, SchemaStmt, Stmt},
node_ref,
};
use kclvm_runner::{execute_module, MapErrorResult};
use kclvm_parser::{LoadProgramOptions, ParseSessionRef};
use kclvm_runner::{execute, ExecProgramArgs, MapErrorResult};

const TMP_FILE: &str = "validationTempKCLCode.k";

Expand Down Expand Up @@ -172,14 +173,27 @@ const TMP_FILE: &str = "validationTempKCLCode.k";
/// }
/// ```
pub fn validate(val_opt: ValidateOption) -> Result<bool> {
let k_path = match val_opt.kcl_path {
Some(path) => path,
None => TMP_FILE.to_string(),
};
let k_path = val_opt.kcl_path.unwrap_or_else(|| TMP_FILE.to_string());
let k_code = val_opt.kcl_code.map_or_else(Vec::new, |code| vec![code]);

let mut module = kclvm_parser::parse_file_force_errors(&k_path, val_opt.kcl_code)?;
let sess = ParseSessionRef::default();
let mut compile_res = kclvm_parser::load_program(
sess,
vec![k_path]
.iter()
.map(|s| s.as_str())
.collect::<Vec<&str>>()
.as_slice(),
Some(LoadProgramOptions {
k_code_list: k_code,
package_maps: Default::default(),
load_plugins: true,
..Default::default()
}),
None,
)?;

let schemas = filter_schema_stmt(&module);
let schemas = filter_schema_stmt_from_prog(&compile_res.program);
let schema_name = match val_opt.schema_name {
Some(name) => Some(name),
None => schemas.get(0).map(|schema| schema.name.node.clone()),
Expand All @@ -192,9 +206,26 @@ pub fn validate(val_opt: ValidateOption) -> Result<bool> {

let assign_stmt = build_assign(&val_opt.attribute_name, validated_expr);

module.body.insert(0, assign_stmt);
match compile_res.program.pkgs.get_mut(kclvm_ast::MAIN_PKG) {
Some(pkg) => {
if let Some(module) = pkg.first_mut() {
module.body.insert(0, assign_stmt);
} else {
return Err(anyhow::anyhow!("No main module found"));
}
}
None => {
return Err(anyhow::anyhow!("No main package found"));
}
}

execute_module(module).map_err_to_result().map(|_| true)
execute(
ParseSessionRef::default(),
compile_res.program,
&ExecProgramArgs::default(),
)
.map_err_to_result()
.map(|_| true)
}

fn build_assign(attr_name: &str, node: NodeRef<Expr>) -> NodeRef<Stmt> {
Expand All @@ -209,13 +240,21 @@ fn build_assign(attr_name: &str, node: NodeRef<Expr>) -> NodeRef<Stmt> {
}))
}

fn filter_schema_stmt(module: &Module) -> Vec<&SchemaStmt> {
fn filter_schema_stmt_from_prog(prog: &Program) -> Vec<&SchemaStmt> {
let mut result = vec![];
for stmt in &module.body {
if let Stmt::Schema(s) = &stmt.node {
result.push(s);
for (pkg_name, modules) in &prog.pkgs {
if pkg_name != kclvm_ast::MAIN_PKG {
continue;
}
for module in modules {
for stmt in &module.body {
if let Stmt::Schema(s) = &stmt.node {
result.push(s);
}
}
}
}

result
}

Expand Down

0 comments on commit 5578591

Please sign in to comment.