Files
modeling-app/src/wasm-lib/derive-docs/tests/doc_comment_with_code.gen
Jonathan Tran 0577b6a984 internal: KCL modules, part 1 (#4149)
Addresses #4080. (Not ready to close it yet.)

# Important

Requires a fix for #4147 before it can work in ZMA.

# Overview

```kcl
// numbers.kcl
export fn inc = (x) => {
  return x + 1
}
```

```kcl
import inc from "numbers.kcl"

answer = inc(41)
```

This also implements multiple imports with optional renaming.

```kcl
import inc, dec from "numbers.kcl"
import identity as id, length as len from "utils.kcl"
```

Note: Imported files _must_ be in the same directory.

Things for a follow-up PR:

- #4147. Currently, we cannot read files in WebAssembly, i.e. ZMA.
- Docs
- Should be an error to `import` anywhere besides the top level. Needs parser restructuring to track the context of a "function body".
- Should be an error to have `export` anywhere besides the top level. It has no effect, but we should tell people it's not valid instead of silently ignoring it.
- Error message for cycle detection is funky because the Rust side doesn't actually know the name of the first file. Message will say "b -> a -> b" instead of "a -> b -> a" when "a" is the top-level file.
- Cache imported files so that they don't need to be re-parsed and re-executed.
2024-10-16 21:48:33 -07:00

190 lines
6.4 KiB
Plaintext

#[cfg(test)]
mod test_examples_my_func {
#[tokio::test(flavor = "multi_thread")]
async fn test_mock_example_my_func0() {
let tokens =
crate::token::lexer("This is another code block.\nyes sirrr.\nmyFunc").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let id_generator = crate::executor::IdGenerator::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn_mock::EngineConnection::new()
.await
.unwrap(),
)),
fs: std::sync::Arc::new(crate::fs::FileManager::new()),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
settings: Default::default(),
context_type: crate::executor::ContextType::Mock,
};
ctx.run(&program, None, id_generator, None).await.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_my_func0() {
let code = "This is another code block.\nyes sirrr.\nmyFunc";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_my_func0"),
&result,
0.99,
);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_mock_example_my_func1() {
let tokens = crate::token::lexer("This is code.\nIt does other shit.\nmyFunc").unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let id_generator = crate::executor::IdGenerator::default();
let ctx = crate::executor::ExecutorContext {
engine: std::sync::Arc::new(Box::new(
crate::engine::conn_mock::EngineConnection::new()
.await
.unwrap(),
)),
fs: std::sync::Arc::new(crate::fs::FileManager::new()),
stdlib: std::sync::Arc::new(crate::std::StdLib::new()),
settings: Default::default(),
context_type: crate::executor::ContextType::Mock,
};
ctx.run(&program, None, id_generator, None).await.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn kcl_test_example_my_func1() {
let code = "This is code.\nIt does other shit.\nmyFunc";
let result =
crate::test_server::execute_and_snapshot(code, crate::settings::types::UnitLength::Mm)
.await
.unwrap();
twenty_twenty::assert_image(
&format!("tests/outputs/{}.png", "serial_test_example_my_func1"),
&result,
0.99,
);
}
}
#[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: myFunc\nThis is some function.\nIt does shit."]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)]
pub(crate) struct MyFunc {}
#[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: myFunc\nThis is some function.\nIt does shit."]
pub(crate) const MyFunc: MyFunc = MyFunc {};
fn boxed_my_func(
exec_state: &mut crate::executor::ExecState,
args: crate::std::Args,
) -> std::pin::Pin<
Box<
dyn std::future::Future<
Output = anyhow::Result<crate::executor::KclValue, crate::errors::KclError>,
> + Send
+ '_,
>,
> {
Box::pin(my_func(exec_state, args))
}
impl crate::docs::StdLibFn for MyFunc {
fn name(&self) -> String {
"myFunc".to_string()
}
fn summary(&self) -> String {
"This is some function.".to_string()
}
fn description(&self) -> String {
"It does shit.".to_string()
}
fn tags(&self) -> Vec<String> {
vec![]
}
fn args(&self, inline_subschemas: bool) -> Vec<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "kittycad::types::InputFormat".to_string(),
schema: generator.root_schema_for::<Option<kittycad::types::InputFormat>>(),
required: false,
}]
}
fn return_value(&self, inline_subschemas: bool) -> Option<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = inline_subschemas;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
let schema = generator.root_schema_for::<Vec<Sketch>>();
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "[Sketch]".to_string(),
schema,
required: true,
})
}
fn unpublished(&self) -> bool {
false
}
fn deprecated(&self) -> bool {
false
}
fn examples(&self) -> Vec<String> {
let code_blocks = vec![
"This is another code block.\nyes sirrr.\nmyFunc",
"This is code.\nIt does other shit.\nmyFunc",
];
code_blocks
.iter()
.map(|cb| {
let tokens = crate::token::lexer(cb).unwrap();
let parser = crate::parser::Parser::new(tokens);
let program = parser.ast().unwrap();
let mut options: crate::ast::types::FormatOptions = Default::default();
options.insert_final_newline = false;
program.recast(&options, 0)
})
.collect::<Vec<String>>()
}
fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_my_func
}
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {
Box::new(self.clone())
}
}
#[doc = r" This is some function."]
#[doc = r" It does shit."]
#[doc = r""]
#[doc = r" This is code."]
#[doc = r" It does other shit."]
#[doc = r" myFunc"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" This is another code block."]
#[doc = r" yes sirrr."]
#[doc = r" myFunc"]
#[doc = r" ```"]
fn inner_my_func(
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
) -> Result<Vec<Box<Sketch>>> {
args
}