Merge remote-tracking branch 'origin/main' into paultag/import
This commit is contained in:
@ -10,6 +10,7 @@ use convert_case::Casing;
|
||||
use handlebars::Renderable;
|
||||
use indexmap::IndexMap;
|
||||
use itertools::Itertools;
|
||||
use schemars::schema::SingleOrVec;
|
||||
use serde_json::json;
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
@ -673,6 +674,7 @@ fn cleanup_type_links<'a>(output: &str, types: impl Iterator<Item = &'a String>)
|
||||
// TODO: This is a hack for the handlebars template being too complex.
|
||||
cleaned_output = cleaned_output.replace("`[, `number`, `number`]`", "`[number, number]`");
|
||||
cleaned_output = cleaned_output.replace("`[, `number`, `number`, `number`]`", "`[number, number, number]`");
|
||||
cleaned_output = cleaned_output.replace("`[, `integer`, `integer`, `integer`]`", "`[integer, integer, integer]`");
|
||||
|
||||
// Fix the links to the types.
|
||||
for type_name in types.map(|s| &**s).chain(DECLARED_TYPES) {
|
||||
@ -691,7 +693,7 @@ fn cleanup_type_links<'a>(output: &str, types: impl Iterator<Item = &'a String>)
|
||||
// TODO handle union types generically rather than special casing them.
|
||||
cleaned_output = cleaned_output.replace(
|
||||
"`Sketch | Plane | Face`",
|
||||
"[`Sketch`](/docs/kcl/types/Sketch) `|` [`Plane`](/docs/kcl/types/Face) `|` [`Plane`](/docs/kcl/types/Face)",
|
||||
"[`Sketch`](/docs/kcl/types/Sketch) OR [`Plane`](/docs/kcl/types/Plane) OR [`Face`](/docs/kcl/types/Face)",
|
||||
);
|
||||
|
||||
cleanup_static_links(&cleaned_output)
|
||||
@ -720,6 +722,11 @@ fn add_to_types(
|
||||
));
|
||||
};
|
||||
|
||||
if name == "SourceRange" {
|
||||
types.insert(name.to_string(), schema.clone());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// If we have an array we want to generate the type markdown files for each item in the
|
||||
// array.
|
||||
if let Some(array) = &o.array {
|
||||
@ -727,7 +734,7 @@ fn add_to_types(
|
||||
if let Some(items) = &array.items {
|
||||
match items {
|
||||
schemars::schema::SingleOrVec::Single(item) => {
|
||||
if is_primitive(item)?.is_some() && name != "SourceRange" {
|
||||
if is_primitive(item)?.is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
return add_to_types(name.trim_start_matches('[').trim_end_matches(']'), item, types);
|
||||
@ -816,9 +823,8 @@ fn generate_type(
|
||||
}
|
||||
|
||||
let cleaned_schema = recurse_and_create_references(name, schema, types)?;
|
||||
let new_schema = super::cleanup_number_tuples(&cleaned_schema);
|
||||
|
||||
let schemars::schema::Schema::Object(o) = new_schema else {
|
||||
let schemars::schema::Schema::Object(o) = cleaned_schema else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Failed to get object schema, should have not been a primitive"
|
||||
));
|
||||
@ -950,6 +956,13 @@ fn recurse_and_create_references(
|
||||
"Failed to get object schema, should have not been a primitive"
|
||||
));
|
||||
};
|
||||
|
||||
// If this is a primitive just use the primitive.
|
||||
if to.subschemas.is_none() && to.object.is_none() && to.reference.is_none() {
|
||||
return Ok(t.clone());
|
||||
}
|
||||
|
||||
// Otherwise append the metadata to our reference.
|
||||
if let Some(metadata) = obj.metadata.as_mut() {
|
||||
if metadata.description.is_none() {
|
||||
metadata.description = to.metadata.as_ref().and_then(|m| m.description.clone());
|
||||
@ -1052,6 +1065,13 @@ fn recurse_and_create_references(
|
||||
*item = new_item;
|
||||
}
|
||||
}
|
||||
|
||||
if subschema.one_of.is_none() && subschema.all_of.is_none() && subschema.any_of.is_none() && obj.array.is_none()
|
||||
{
|
||||
if let Some(SingleOrVec::Single(_)) = &o.instance_type {
|
||||
return Ok(schema.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let obj = cleanup_type_description(&obj)
|
||||
|
@ -660,69 +660,6 @@ pub fn get_description_string_from_schema(schema: &schemars::schema::RootSchema)
|
||||
None
|
||||
}
|
||||
|
||||
pub fn cleanup_number_tuples_root(mut schema: schemars::schema::RootSchema) -> schemars::schema::RootSchema {
|
||||
cleanup_number_tuples_object(&mut schema.schema);
|
||||
schema
|
||||
}
|
||||
|
||||
fn cleanup_number_tuples_object(o: &mut schemars::schema::SchemaObject) {
|
||||
if let Some(object) = &mut o.object {
|
||||
for (_, value) in object.properties.iter_mut() {
|
||||
*value = cleanup_number_tuples(value);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(array) = &mut o.array {
|
||||
if let Some(items) = &mut array.items {
|
||||
match items {
|
||||
schemars::schema::SingleOrVec::Single(_) => {
|
||||
// Do nothing since its only a single item.
|
||||
}
|
||||
schemars::schema::SingleOrVec::Vec(items) => {
|
||||
if items.len() == 2 {
|
||||
// Get the second item and see if its a NumericType.
|
||||
|
||||
if let Some(schemars::schema::Schema::Object(obj)) = items.get(1) {
|
||||
if let Some(reference) = &obj.reference {
|
||||
if reference == "#/components/schemas/NumericType" {
|
||||
// Get the first item.
|
||||
if let Some(schemars::schema::Schema::Object(obj2)) = items.first() {
|
||||
let mut obj2 = obj2.clone();
|
||||
obj2.metadata = o.metadata.clone();
|
||||
// Replace the array with the first item.
|
||||
*o = obj2;
|
||||
}
|
||||
}
|
||||
} else if NUMERIC_TYPE_SCHEMA.object == obj.object {
|
||||
if let Some(schemars::schema::Schema::Object(obj2)) = items.first() {
|
||||
let mut obj2 = obj2.clone();
|
||||
obj2.metadata = o.metadata.clone();
|
||||
// Replace the array with the first item.
|
||||
*o = obj2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Some numbers will be tuples of 2 where the second type is always "NumericType". We want to
|
||||
/// replace these with the first item in the array and not have an array as it messes
|
||||
/// with the docs generation which assumes if there is a tuple that you give 2 values not one
|
||||
/// in the form of an array.
|
||||
fn cleanup_number_tuples(schema: &schemars::schema::Schema) -> schemars::schema::Schema {
|
||||
let mut schema = schema.clone();
|
||||
|
||||
if let schemars::schema::Schema::Object(o) = &mut schema {
|
||||
cleanup_number_tuples_object(o);
|
||||
}
|
||||
|
||||
schema
|
||||
}
|
||||
|
||||
pub fn is_primitive(schema: &schemars::schema::Schema) -> Result<Option<Primitive>> {
|
||||
match schema {
|
||||
schemars::schema::Schema::Object(o) => {
|
||||
|
@ -1258,6 +1258,48 @@ mod linear_pattern3d_a_pattern {
|
||||
super::execute(TEST_NAME, true).await
|
||||
}
|
||||
}
|
||||
mod pattern_circular_in_module {
|
||||
const TEST_NAME: &str = "pattern_circular_in_module";
|
||||
|
||||
/// Test parsing KCL.
|
||||
#[test]
|
||||
fn parse() {
|
||||
super::parse(TEST_NAME)
|
||||
}
|
||||
|
||||
/// Test that parsing and unparsing KCL produces the original KCL input.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn unparse() {
|
||||
super::unparse(TEST_NAME).await
|
||||
}
|
||||
|
||||
/// Test that KCL is executed correctly.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_execute() {
|
||||
super::execute(TEST_NAME, true).await
|
||||
}
|
||||
}
|
||||
mod pattern_linear_in_module {
|
||||
const TEST_NAME: &str = "pattern_linear_in_module";
|
||||
|
||||
/// Test parsing KCL.
|
||||
#[test]
|
||||
fn parse() {
|
||||
super::parse(TEST_NAME)
|
||||
}
|
||||
|
||||
/// Test that parsing and unparsing KCL produces the original KCL input.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn unparse() {
|
||||
super::unparse(TEST_NAME).await
|
||||
}
|
||||
|
||||
/// Test that KCL is executed correctly.
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn kcl_test_execute() {
|
||||
super::execute(TEST_NAME, true).await
|
||||
}
|
||||
}
|
||||
mod tangential_arc {
|
||||
const TEST_NAME: &str = "tangential_arc";
|
||||
|
||||
|
@ -72,7 +72,7 @@ impl KwArgs {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TyF64 {
|
||||
@ -98,6 +98,16 @@ impl TyF64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl JsonSchema for TyF64 {
|
||||
fn schema_name() -> String {
|
||||
"TyF64".to_string()
|
||||
}
|
||||
|
||||
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||
gen.subschema_for::<f64>()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Args {
|
||||
/// Positional args.
|
||||
|
@ -381,6 +381,7 @@ async fn send_pattern_transform<T: GeometryTrait>(
|
||||
args: &Args,
|
||||
) -> Result<Vec<T>, KclError> {
|
||||
let id = exec_state.next_uuid();
|
||||
let extra_instances = transforms.len();
|
||||
|
||||
let resp = args
|
||||
.send_modeling_cmd(
|
||||
@ -393,10 +394,19 @@ async fn send_pattern_transform<T: GeometryTrait>(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let OkWebSocketResponseData::Modeling {
|
||||
let mut mock_ids = Vec::new();
|
||||
let entity_ids = if let OkWebSocketResponseData::Modeling {
|
||||
modeling_response: OkModelingCmdResponse::EntityLinearPatternTransform(pattern_info),
|
||||
} = &resp
|
||||
else {
|
||||
{
|
||||
&pattern_info.entity_ids
|
||||
} else if args.ctx.no_engine_commands().await {
|
||||
mock_ids.reserve(extra_instances);
|
||||
for _ in 0..extra_instances {
|
||||
mock_ids.push(exec_state.next_uuid());
|
||||
}
|
||||
&mock_ids
|
||||
} else {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("EntityLinearPattern response was not as expected: {:?}", resp),
|
||||
source_ranges: vec![args.source_range],
|
||||
@ -404,7 +414,7 @@ async fn send_pattern_transform<T: GeometryTrait>(
|
||||
};
|
||||
|
||||
let mut geometries = vec![solid.clone()];
|
||||
for id in pattern_info.entity_ids.iter().copied() {
|
||||
for id in entity_ids.iter().copied() {
|
||||
let mut new_solid = solid.clone();
|
||||
new_solid.set_id(id);
|
||||
geometries.push(new_solid);
|
||||
@ -1280,10 +1290,21 @@ async fn pattern_circular(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let OkWebSocketResponseData::Modeling {
|
||||
// The common case is borrowing from the response. Instead of cloning,
|
||||
// create a Vec to borrow from in mock mode.
|
||||
let mut mock_ids = Vec::new();
|
||||
let entity_ids = if let OkWebSocketResponseData::Modeling {
|
||||
modeling_response: OkModelingCmdResponse::EntityCircularPattern(pattern_info),
|
||||
} = &resp
|
||||
else {
|
||||
{
|
||||
&pattern_info.entity_ids
|
||||
} else if args.ctx.no_engine_commands().await {
|
||||
mock_ids.reserve(num_repetitions as usize);
|
||||
for _ in 0..num_repetitions {
|
||||
mock_ids.push(exec_state.next_uuid());
|
||||
}
|
||||
&mock_ids
|
||||
} else {
|
||||
return Err(KclError::Engine(KclErrorDetails {
|
||||
message: format!("EntityCircularPattern response was not as expected: {:?}", resp),
|
||||
source_ranges: vec![args.source_range],
|
||||
@ -1293,18 +1314,18 @@ async fn pattern_circular(
|
||||
let geometries = match geometry {
|
||||
Geometry::Sketch(sketch) => {
|
||||
let mut geometries = vec![sketch.clone()];
|
||||
for id in pattern_info.entity_ids.iter() {
|
||||
for id in entity_ids.iter().copied() {
|
||||
let mut new_sketch = sketch.clone();
|
||||
new_sketch.id = *id;
|
||||
new_sketch.id = id;
|
||||
geometries.push(new_sketch);
|
||||
}
|
||||
Geometries::Sketches(geometries)
|
||||
}
|
||||
Geometry::Solid(solid) => {
|
||||
let mut geometries = vec![solid.clone()];
|
||||
for id in pattern_info.entity_ids.iter() {
|
||||
for id in entity_ids.iter().copied() {
|
||||
let mut new_solid = solid.clone();
|
||||
new_solid.id = *id;
|
||||
new_solid.id = id;
|
||||
geometries.push(new_solid);
|
||||
}
|
||||
Geometries::Solids(geometries)
|
||||
|
Reference in New Issue
Block a user