From 42c1fb551704dbc27be8631b7fd01a52ee620db4 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Wed, 26 Aug 2026 16:24:26 -0700 Subject: [PATCH 1/7] feat: generate System Nexus interceptor points --- .../_system_nexus_interceptor.py | 97 ++++++++++++ src/generator/mod.rs | 4 +- src/generator/python.rs | 141 +++++++++++++++++- src/lib.rs | 12 ++ src/main.rs | 31 +++- tests/generate_python.rs | 3 + xtask/src/build_examples.rs | 10 +- xtask/src/validate.rs | 2 +- 8 files changed, 281 insertions(+), 19 deletions(-) create mode 100644 advanced/samples/python/wit/workflow_service/_system_nexus_interceptor.py diff --git a/advanced/samples/python/wit/workflow_service/_system_nexus_interceptor.py b/advanced/samples/python/wit/workflow_service/_system_nexus_interceptor.py new file mode 100644 index 00000000..a554465c --- /dev/null +++ b/advanced/samples/python/wit/workflow_service/_system_nexus_interceptor.py @@ -0,0 +1,97 @@ +# Generated by nexgen v0.2.2. DO NOT EDIT! + +from __future__ import annotations + + +import abc +import typing + +from temporalio.nexus.system import TEMPORAL_SYSTEM_ENDPOINT + +from . import models + +if typing.TYPE_CHECKING: + import temporalio.workflow + from temporalio.worker._interceptor import StartNexusOperationInput + + +__all__ = [ + "_start_system_nexus_operation", + "_SystemNexusWorkflowOutboundInterceptorBase", + "_SystemNexusWorkflowOutboundInterceptorTerminal", +] + + +_InputT = typing.TypeVar("_InputT") +_OutputT = typing.TypeVar("_OutputT") + + +async def _start_system_nexus_operation( + interceptor: _SystemNexusWorkflowOutboundInterceptorBase, + input: StartNexusOperationInput[_InputT, _OutputT], +) -> temporalio.workflow.NexusOperationHandle[_OutputT]: + if ( + input.service == "temporal.api.workflowservice.v1.WorkflowService" + and input.operation_name == "SignalWithStartWorkflowExecution" + ): + typed_input = typing.cast( + "StartNexusOperationInput[models.SignalWithStartWorkflowRequest, models.SignalWithStartWorkflowResponse]", + input, + ) + # The dispatch check above establishes that this operation's response type is _OutputT. + return typing.cast( + "temporalio.workflow.NexusOperationHandle[_OutputT]", + await interceptor.start_signal_with_start_workflow(typed_input.input), + ) + raise ValueError( + f"unsupported System Nexus operation: {input.service}/{input.operation_name}" + ) + + +class _SystemNexusWorkflowOutboundInterceptorBase(abc.ABC): + @abc.abstractmethod + def _next_system_nexus_interceptor( + self, + ) -> _SystemNexusWorkflowOutboundInterceptorBase: ... + + async def start_signal_with_start_workflow( + self, request: models.SignalWithStartWorkflowRequest + ) -> temporalio.workflow.NexusOperationHandle[ + models.SignalWithStartWorkflowResponse + ]: + """Intercept the System Nexus temporal.api.workflowservice.v1.WorkflowService/SignalWithStartWorkflowExecution operation.""" + return await self._next_system_nexus_interceptor().start_signal_with_start_workflow( + request + ) + + +class _SystemNexusWorkflowOutboundInterceptorTerminal(abc.ABC): + @abc.abstractmethod + async def _outbound_start_nexus_operation( + self, + input: StartNexusOperationInput[_InputT, _OutputT], + ) -> temporalio.workflow.NexusOperationHandle[_OutputT]: ... + + async def start_signal_with_start_workflow( + self, request: models.SignalWithStartWorkflowRequest + ) -> temporalio.workflow.NexusOperationHandle[ + models.SignalWithStartWorkflowResponse + ]: + from temporalio.worker._interceptor import StartNexusOperationInput + from temporalio.workflow import NexusOperationCancellationType + + return await self._outbound_start_nexus_operation( + StartNexusOperationInput( + endpoint=TEMPORAL_SYSTEM_ENDPOINT, + service="temporal.api.workflowservice.v1.WorkflowService", + operation="SignalWithStartWorkflowExecution", + input=request, + output_type=models.SignalWithStartWorkflowResponse, + schedule_to_close_timeout=None, + schedule_to_start_timeout=None, + start_to_close_timeout=None, + cancellation_type=NexusOperationCancellationType.WAIT_COMPLETED, + headers=None, + summary=None, + ) + ) diff --git a/src/generator/mod.rs b/src/generator/mod.rs index 8753ecd7..18587185 100644 --- a/src/generator/mod.rs +++ b/src/generator/mod.rs @@ -123,6 +123,8 @@ pub(crate) struct GenerateFilesOptions { /// The TypeScript temporal representation (`--date-time-types`); ignored by /// the non-TypeScript backends. pub(crate) ts_date_time_types: TsDateTimeTypes, + /// Enables Python-only output needed by Temporal System Nexus bindings. + pub(crate) system_nexus: bool, } pub(crate) fn generate_files_for_tree_with_mode_and_options( @@ -147,7 +149,7 @@ pub(crate) fn generate_files_from_planned_tree( Language::Dotnet => dotnet::generate(tree, support, mode), Language::Go => generate_go_tree(tree, support, mode, options), Language::Java => java::generate(tree, support, mode, options.java_package_root.as_deref()), - Language::Python => python::generate(tree, support, mode), + Language::Python => python::generate(tree, support, mode, options.system_nexus), Language::TypeScript => { typescript::generate(tree, support, mode, options.ts_date_time_types) } diff --git a/src/generator/python.rs b/src/generator/python.rs index 72924793..aafa5283 100644 --- a/src/generator/python.rs +++ b/src/generator/python.rs @@ -46,13 +46,14 @@ pub(crate) fn generate( tree: &crate::spec::ApiSpecTree, support: &crate::SupportFiles, mode: GenerationMode, + system_nexus: bool, ) -> Result { match &tree.root { ApiSpecNode::Leaf(leaf) => { let support_fragments = support_fragments_for_plan(&leaf.spec, support); - generate_leaf(&leaf.spec, &support_fragments, mode) + generate_leaf(&leaf.spec, &support_fragments, mode, system_nexus) } - ApiSpecNode::Branch(branch) => generate_tree(branch, support, mode), + ApiSpecNode::Branch(branch) => generate_tree(branch, support, mode, system_nexus), } } @@ -60,6 +61,7 @@ fn generate_leaf( api_plan: &PlannedSpec, support_fragments: &[SupportFragmentSpec], mode: GenerationMode, + system_nexus: bool, ) -> Result { reject_support_namespaces(Language::Python, support_fragments)?; let inline_model_rebuilds = api_plan @@ -67,8 +69,11 @@ fn generate_leaf( .module_imports .values() .all(BTreeSet::is_empty); - let generated = - ApiPlanner::new(api_plan, inline_model_rebuilds, None)?.build(support_fragments, mode)?; + let generated = ApiPlanner::new(api_plan, inline_model_rebuilds, None)?.build( + support_fragments, + mode, + system_nexus, + )?; Ok(generated.generated_files) } @@ -77,15 +82,21 @@ fn generate_leaf_with_model_hoists( support_fragments: &[SupportFragmentSpec], mode: GenerationMode, model_hoists: &PythonModelHoists, + system_nexus: bool, ) -> Result { reject_support_namespaces(Language::Python, support_fragments)?; - ApiPlanner::new(api_plan, true, Some(model_hoists))?.build(support_fragments, mode) + ApiPlanner::new(api_plan, true, Some(model_hoists))?.build( + support_fragments, + mode, + system_nexus, + ) } fn generate_tree( branch: &ApiSpecBranch, support: &crate::SupportFiles, mode: GenerationMode, + system_nexus: bool, ) -> Result { let model_hoists = tree_model_hoists(branch)?; let mut files = BTreeMap::new(); @@ -102,6 +113,7 @@ fn generate_tree( support, mode, &model_hoists, + system_nexus, &mut files, &mut warnings, &mut root_package_imports, @@ -127,6 +139,7 @@ fn generate_tree_node( support: &crate::SupportFiles, mode: GenerationMode, model_hoists: &PythonModelHoists, + system_nexus: bool, files: &mut BTreeMap, warnings: &mut Vec, root_package_imports: &mut RootPackageImports, @@ -139,6 +152,7 @@ fn generate_tree_node( &support_fragments, mode, model_hoists, + system_nexus, )?; extend_root_package_imports(root_package_imports, generated.root_package_imports); warnings.extend(generated.generated_files.warnings); @@ -156,6 +170,7 @@ fn generate_tree_node( support, mode, model_hoists, + system_nexus, files, warnings, root_package_imports, @@ -510,6 +525,7 @@ impl<'a> ApiPlanner<'a> { mut self, support_fragments: &[SupportFragmentSpec], mode: GenerationMode, + system_nexus: bool, ) -> Result { let api_plan = self.api_plan; let services = api_plan @@ -564,8 +580,13 @@ impl<'a> ApiPlanner<'a> { self.render_model_fragments(model_refs.as_slice(), variant_refs.as_slice())?; validate_python_generated_names(self.api_plan, &model_fragments.generated_names)?; - let (generated_files, exported_names) = - self.render_package(&model_fragments, &services, support_fragments, mode)?; + let (generated_files, exported_names) = self.render_package( + &model_fragments, + &services, + support_fragments, + mode, + system_nexus, + )?; Ok(PythonGenerationResult { generated_files, root_package_imports: model_fragments.root_package_imports, @@ -588,6 +609,7 @@ impl<'a> ApiPlanner<'a> { services: &[RenderedService<'_>], support_fragments: &[SupportFragmentSpec], mode: GenerationMode, + system_nexus: bool, ) -> Result<(GeneratedFiles, BTreeSet)> { let mut files = BTreeMap::new(); render_support_package(&mut files, support_fragments)?; @@ -733,6 +755,13 @@ impl<'a> ApiPlanner<'a> { render_operations_package_init(), )?; } + if system_nexus && mode == GenerationMode::NativeApi { + insert_generated_file( + &mut files, + "_system_nexus_interceptor.py", + render_system_nexus_interceptor(services), + )?; + } for service in services { for resource in &service.resources { @@ -4630,6 +4659,99 @@ fn render_operations_package_init() -> String { output } +/// Renders the mixins that turn System Nexus operations into operation-specific +/// workflow-outbound interception points. +fn render_system_nexus_interceptor(services: &[RenderedService<'_>]) -> String { + let operations = services + .iter() + .flat_map(|service| { + service + .operations + .iter() + .map(move |operation| (service, operation)) + }) + .collect::>(); + let mut output = String::new(); + render_generated_file_header(&mut output); + output.push_str("\n\nimport abc\nimport typing\n\nfrom temporalio.nexus.system import TEMPORAL_SYSTEM_ENDPOINT\n\nfrom . import models\n\nif typing.TYPE_CHECKING:\n import temporalio.workflow\n from temporalio.worker._interceptor import StartNexusOperationInput\n\n\n__all__ = [\n \"_start_system_nexus_operation\",\n \"_SystemNexusWorkflowOutboundInterceptorBase\",\n \"_SystemNexusWorkflowOutboundInterceptorTerminal\",\n]\n\n\n_InputT = typing.TypeVar(\"_InputT\")\n_OutputT = typing.TypeVar(\"_OutputT\")\n\n\n"); + output.push_str( + "async def _start_system_nexus_operation(\n interceptor: _SystemNexusWorkflowOutboundInterceptorBase,\n input: StartNexusOperationInput[_InputT, _OutputT],\n) -> temporalio.workflow.NexusOperationHandle[_OutputT]:\n", + ); + for (service, operation) in &operations { + let output_type = system_nexus_type_expr(&operation.output_type_expr); + output.push_str(" if input.service == "); + output.push_str(&python_string_literal(service.wire_name)); + output.push_str(" and input.operation_name == "); + output.push_str(&python_string_literal(operation.wire_name)); + output.push_str( + ":\n typed_input = typing.cast(\n \"StartNexusOperationInput[", + ); + output.push_str(operation_input_type_ref(operation)); + output.push_str(", "); + output.push_str(&output_type); + output.push_str("]\",\n input,\n )\n # The dispatch check above establishes that this operation's response type is _OutputT.\n return typing.cast(\n \"temporalio.workflow.NexusOperationHandle[_OutputT]\",\n await interceptor.start_"); + output.push_str(&operation.attr_name); + output.push_str("(typed_input.input),\n )\n"); + } + output.push_str(" raise ValueError(f\"unsupported System Nexus operation: {input.service}/{input.operation_name}\")\n"); + + output.push_str("\n\nclass _SystemNexusWorkflowOutboundInterceptorBase(abc.ABC):\n"); + output.push_str(" @abc.abstractmethod\n def _next_system_nexus_interceptor(\n self,\n ) -> _SystemNexusWorkflowOutboundInterceptorBase:\n ...\n"); + for (service, operation) in &operations { + let output_type = system_nexus_type_expr(&operation.output_type_expr); + output.push_str("\n async def start_"); + output.push_str(&operation.attr_name); + output.push_str("(\n self, request: "); + output.push_str(operation_input_type_ref(operation)); + output.push_str("\n ) -> temporalio.workflow.NexusOperationHandle["); + output.push_str(&output_type); + output.push_str("]:\n"); + output.push_str(" \"\"\"Intercept the System Nexus "); + output.push_str(service.wire_name); + output.push('/'); + output.push_str(operation.wire_name); + output.push_str(" operation.\"\"\"\n"); + output.push_str(" return await self._next_system_nexus_interceptor().start_"); + output.push_str(&operation.attr_name); + output.push_str("(request)\n"); + } + + output.push_str("\n\nclass _SystemNexusWorkflowOutboundInterceptorTerminal(abc.ABC):\n"); + output.push_str(" @abc.abstractmethod\n async def _outbound_start_nexus_operation(\n self,\n input: StartNexusOperationInput[_InputT, _OutputT],\n ) -> temporalio.workflow.NexusOperationHandle[_OutputT]:\n ...\n"); + for (service, operation) in operations { + let output_type = system_nexus_type_expr(&operation.output_type_expr); + output.push_str("\n async def start_"); + output.push_str(&operation.attr_name); + output.push_str("(\n self, request: "); + output.push_str(operation_input_type_ref(operation)); + output.push_str("\n ) -> temporalio.workflow.NexusOperationHandle["); + output.push_str(&output_type); + output.push_str("]:\n"); + output.push_str( + " from temporalio.worker._interceptor import StartNexusOperationInput\n", + ); + output + .push_str(" from temporalio.workflow import NexusOperationCancellationType\n\n"); + output.push_str(" return await self._outbound_start_nexus_operation(\n"); + output.push_str(" StartNexusOperationInput(\n endpoint=TEMPORAL_SYSTEM_ENDPOINT,\n service="); + output.push_str(&python_string_literal(service.wire_name)); + output.push_str(",\n operation="); + output.push_str(&python_string_literal(operation.wire_name)); + output.push_str(",\n input=request,\n output_type="); + output.push_str(&output_type); + output.push_str(",\n schedule_to_close_timeout=None,\n schedule_to_start_timeout=None,\n start_to_close_timeout=None,\n cancellation_type=NexusOperationCancellationType.WAIT_COMPLETED,\n headers=None,\n summary=None,\n )\n )\n"); + } + output +} + +fn system_nexus_type_expr(type_expr: &str) -> String { + if type_expr == "None" || type_expr.contains('.') || type_expr.contains('[') { + type_expr.to_string() + } else { + format!("models.{type_expr}") + } +} + fn function_type_parameters( functions: &[RenderedFunctionField], output_type_parameters: &BTreeSet, @@ -7921,7 +8043,10 @@ class Example(enum.Enum): &descriptors, &crate::SupportFiles::default(), GenerationMode::NativeApi, - GenerateFilesOptions::default(), + GenerateFilesOptions { + system_nexus: true, + ..GenerateFilesOptions::default() + }, ) .unwrap(); assert_eq!(generated.layout, GeneratedOutputLayout::Directory); diff --git a/src/lib.rs b/src/lib.rs index 473ee959..285842a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,6 +48,17 @@ pub struct GenerateRequest { } pub fn generate_to_file(request: &GenerateRequest) -> Result<()> { + generate_to_file_with_system_nexus(request, false) +} + +/// Generates bindings with optional Temporal System Nexus-specific output. +/// +/// This is used by the advanced CLI surface; ordinary library generation keeps +/// the option disabled. +pub fn generate_to_file_with_system_nexus( + request: &GenerateRequest, + system_nexus: bool, +) -> Result<()> { // A resolved output path with no name at all (the filesystem root, or // `..` past it) is never a real output directory: Go and Java derive // package names from its basename, and for every language it means the @@ -79,6 +90,7 @@ pub fn generate_to_file(request: &GenerateRequest) -> Result<()> { None }, ts_date_time_types: request.ts_date_time_types, + system_nexus, }; let generated = compile_tree_to_files( request.language, diff --git a/src/main.rs b/src/main.rs index e6025e3d..22968e4f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ use std::path::PathBuf; use std::process::ExitCode; use clap::{Args, Parser, Subcommand, ValueEnum}; +#[cfg(feature = "advanced")] +use nexgen::generate_to_file_with_system_nexus; use nexgen::generator::TsDateTimeTypes; use nexgen::language::Language; #[cfg(feature = "advanced")] @@ -65,6 +67,10 @@ struct GenerateArgs { #[cfg(feature = "advanced")] #[arg(long = "native-api")] generate_native_api: bool, + /// Generate Temporal System Nexus-specific bindings. + #[cfg(feature = "advanced")] + #[arg(long = "system-nexus")] + system_nexus: bool, } #[derive(Args)] @@ -162,12 +168,25 @@ fn main() -> ExitCode { Default::default(), Some(args.package_name), )), - Commands::Python(args) => generate_to_file(&generate_request( - Language::Python, - args, - Default::default(), - None, - )), + Commands::Python(args) => { + #[cfg(feature = "advanced")] + { + let system_nexus = args.system_nexus; + generate_to_file_with_system_nexus( + &generate_request(Language::Python, args, Default::default(), None), + system_nexus, + ) + } + #[cfg(not(feature = "advanced"))] + { + generate_to_file(&generate_request( + Language::Python, + args, + Default::default(), + None, + )) + } + } Commands::Typescript(args) => generate_to_file(&generate_request( Language::TypeScript, args.common, diff --git a/tests/generate_python.rs b/tests/generate_python.rs index 12c16f11..471a8c5e 100644 --- a/tests/generate_python.rs +++ b/tests/generate_python.rs @@ -816,6 +816,9 @@ fn generate_formatted_python_output(root: &Path, example_id: &str, output_path: output_path.to_str().unwrap(), "--native-api", ]); + if example_id == PRIMARY_EXAMPLE_ID { + command.arg("--system-nexus"); + } let status = command.status().unwrap(); assert!(status.success()); diff --git a/xtask/src/build_examples.rs b/xtask/src/build_examples.rs index f6a4596a..4c7e92d0 100644 --- a/xtask/src/build_examples.rs +++ b/xtask/src/build_examples.rs @@ -6,7 +6,7 @@ use heck::ToSnakeCase; use nexgen::error::{Error, Result}; use nexgen::generator::{GenerationMode, TsDateTimeTypes}; use nexgen::language::Language; -use nexgen::{GenerateRequest, generate_to_file}; +use nexgen::{GenerateRequest, generate_to_file, generate_to_file_with_system_nexus}; #[derive(Clone)] pub struct BuildExamplesRequest { @@ -381,7 +381,7 @@ fn build_example(repo_root: &Path, language: Language, example_id: &str) -> Resu let output_path = example_output_path(repo_root, language, example_id); let language_root = advanced_language_root(repo_root, language); reset_example_output_directory(&language_root, &output_path)?; - generate_to_file(&GenerateRequest { + let generate_request = GenerateRequest { language, input_paths, support_paths: Vec::new(), @@ -392,7 +392,11 @@ fn build_example(repo_root: &Path, language: Language, example_id: &str) -> Resu java_package_name: (language == Language::Java) .then(|| example_directory_name(language, example_id)), ts_date_time_types: Default::default(), - })?; + }; + generate_to_file_with_system_nexus( + &generate_request, + language == Language::Python && example_id == "workflow-service", + )?; format_example_output(&language_root, language, &output_path)?; println!("Built {} with nexgen", output_path.display()); Ok(()) diff --git a/xtask/src/validate.rs b/xtask/src/validate.rs index 31a42831..c4a6dec9 100644 --- a/xtask/src/validate.rs +++ b/xtask/src/validate.rs @@ -68,7 +68,7 @@ fn validate_python(repo_root: &Path) -> Result<()> { run(&root, "uv", &["sync", "--locked"])?; run(&root, "uv", &["run", "ruff", "check", "."])?; run(&root, "uv", &["run", "ruff", "format", "--check", "."])?; - run(&root, "uv", &["run", "basedpyright"])?; + run(&root, "uv", &["run", "basedpyright", "--warnings"])?; run(&root, "uv", &["run", "pytest"])?; } Ok(()) From 7463144c07679efeffd68b50f7df74527bfb00aa Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Fri, 28 Aug 2026 10:07:33 -0700 Subject: [PATCH 2/7] refactor: scope generation configuration --- .../_system_nexus_interceptor.py | 2 +- src/generator/mod.rs | 12 ++- src/generator/python.rs | 68 ++++++---------- src/lib.rs | 36 +++------ src/main.rs | 18 +++-- src/nexgen_config.rs | 79 +++++++++++++++++++ xtask/src/build_examples.rs | 12 +-- 7 files changed, 146 insertions(+), 81 deletions(-) create mode 100644 src/nexgen_config.rs diff --git a/advanced/samples/python/wit/workflow_service/_system_nexus_interceptor.py b/advanced/samples/python/wit/workflow_service/_system_nexus_interceptor.py index a554465c..f3e8f84d 100644 --- a/advanced/samples/python/wit/workflow_service/_system_nexus_interceptor.py +++ b/advanced/samples/python/wit/workflow_service/_system_nexus_interceptor.py @@ -59,7 +59,7 @@ async def start_signal_with_start_workflow( ) -> temporalio.workflow.NexusOperationHandle[ models.SignalWithStartWorkflowResponse ]: - """Intercept the System Nexus temporal.api.workflowservice.v1.WorkflowService/SignalWithStartWorkflowExecution operation.""" + """Intercept the SignalWithStartWorkflow operation.""" return await self._next_system_nexus_interceptor().start_signal_with_start_workflow( request ) diff --git a/src/generator/mod.rs b/src/generator/mod.rs index 18587185..b0bc5000 100644 --- a/src/generator/mod.rs +++ b/src/generator/mod.rs @@ -123,8 +123,6 @@ pub(crate) struct GenerateFilesOptions { /// The TypeScript temporal representation (`--date-time-types`); ignored by /// the non-TypeScript backends. pub(crate) ts_date_time_types: TsDateTimeTypes, - /// Enables Python-only output needed by Temporal System Nexus bindings. - pub(crate) system_nexus: bool, } pub(crate) fn generate_files_for_tree_with_mode_and_options( @@ -135,7 +133,13 @@ pub(crate) fn generate_files_for_tree_with_mode_and_options( mode: GenerationMode, options: GenerateFilesOptions, ) -> Result { - crate::compile_tree_to_files(language, tree, descriptors, support, mode, options) + let config = crate::nexgen_config::NexgenConfig { + mode, + ..crate::nexgen_config::current() + }; + crate::nexgen_config::with_nexgen_config(config, || { + crate::compile_tree_to_files(language, tree, descriptors, support, options) + }) } pub(crate) fn generate_files_from_planned_tree( @@ -149,7 +153,7 @@ pub(crate) fn generate_files_from_planned_tree( Language::Dotnet => dotnet::generate(tree, support, mode), Language::Go => generate_go_tree(tree, support, mode, options), Language::Java => java::generate(tree, support, mode, options.java_package_root.as_deref()), - Language::Python => python::generate(tree, support, mode, options.system_nexus), + Language::Python => python::generate(tree, support, mode), Language::TypeScript => { typescript::generate(tree, support, mode, options.ts_date_time_types) } diff --git a/src/generator/python.rs b/src/generator/python.rs index aafa5283..bafbacd8 100644 --- a/src/generator/python.rs +++ b/src/generator/python.rs @@ -46,14 +46,13 @@ pub(crate) fn generate( tree: &crate::spec::ApiSpecTree, support: &crate::SupportFiles, mode: GenerationMode, - system_nexus: bool, ) -> Result { match &tree.root { ApiSpecNode::Leaf(leaf) => { let support_fragments = support_fragments_for_plan(&leaf.spec, support); - generate_leaf(&leaf.spec, &support_fragments, mode, system_nexus) + generate_leaf(&leaf.spec, &support_fragments, mode) } - ApiSpecNode::Branch(branch) => generate_tree(branch, support, mode, system_nexus), + ApiSpecNode::Branch(branch) => generate_tree(branch, support, mode), } } @@ -61,7 +60,6 @@ fn generate_leaf( api_plan: &PlannedSpec, support_fragments: &[SupportFragmentSpec], mode: GenerationMode, - system_nexus: bool, ) -> Result { reject_support_namespaces(Language::Python, support_fragments)?; let inline_model_rebuilds = api_plan @@ -69,11 +67,8 @@ fn generate_leaf( .module_imports .values() .all(BTreeSet::is_empty); - let generated = ApiPlanner::new(api_plan, inline_model_rebuilds, None)?.build( - support_fragments, - mode, - system_nexus, - )?; + let generated = + ApiPlanner::new(api_plan, inline_model_rebuilds, None)?.build(support_fragments, mode)?; Ok(generated.generated_files) } @@ -82,21 +77,15 @@ fn generate_leaf_with_model_hoists( support_fragments: &[SupportFragmentSpec], mode: GenerationMode, model_hoists: &PythonModelHoists, - system_nexus: bool, ) -> Result { reject_support_namespaces(Language::Python, support_fragments)?; - ApiPlanner::new(api_plan, true, Some(model_hoists))?.build( - support_fragments, - mode, - system_nexus, - ) + ApiPlanner::new(api_plan, true, Some(model_hoists))?.build(support_fragments, mode) } fn generate_tree( branch: &ApiSpecBranch, support: &crate::SupportFiles, mode: GenerationMode, - system_nexus: bool, ) -> Result { let model_hoists = tree_model_hoists(branch)?; let mut files = BTreeMap::new(); @@ -113,7 +102,6 @@ fn generate_tree( support, mode, &model_hoists, - system_nexus, &mut files, &mut warnings, &mut root_package_imports, @@ -139,7 +127,6 @@ fn generate_tree_node( support: &crate::SupportFiles, mode: GenerationMode, model_hoists: &PythonModelHoists, - system_nexus: bool, files: &mut BTreeMap, warnings: &mut Vec, root_package_imports: &mut RootPackageImports, @@ -152,7 +139,6 @@ fn generate_tree_node( &support_fragments, mode, model_hoists, - system_nexus, )?; extend_root_package_imports(root_package_imports, generated.root_package_imports); warnings.extend(generated.generated_files.warnings); @@ -170,7 +156,6 @@ fn generate_tree_node( support, mode, model_hoists, - system_nexus, files, warnings, root_package_imports, @@ -525,7 +510,6 @@ impl<'a> ApiPlanner<'a> { mut self, support_fragments: &[SupportFragmentSpec], mode: GenerationMode, - system_nexus: bool, ) -> Result { let api_plan = self.api_plan; let services = api_plan @@ -580,13 +564,8 @@ impl<'a> ApiPlanner<'a> { self.render_model_fragments(model_refs.as_slice(), variant_refs.as_slice())?; validate_python_generated_names(self.api_plan, &model_fragments.generated_names)?; - let (generated_files, exported_names) = self.render_package( - &model_fragments, - &services, - support_fragments, - mode, - system_nexus, - )?; + let (generated_files, exported_names) = + self.render_package(&model_fragments, &services, support_fragments, mode)?; Ok(PythonGenerationResult { generated_files, root_package_imports: model_fragments.root_package_imports, @@ -609,7 +588,6 @@ impl<'a> ApiPlanner<'a> { services: &[RenderedService<'_>], support_fragments: &[SupportFragmentSpec], mode: GenerationMode, - system_nexus: bool, ) -> Result<(GeneratedFiles, BTreeSet)> { let mut files = BTreeMap::new(); render_support_package(&mut files, support_fragments)?; @@ -755,7 +733,7 @@ impl<'a> ApiPlanner<'a> { render_operations_package_init(), )?; } - if system_nexus && mode == GenerationMode::NativeApi { + if crate::nexgen_config::current().system_nexus && mode == GenerationMode::NativeApi { insert_generated_file( &mut files, "_system_nexus_interceptor.py", @@ -4697,7 +4675,7 @@ fn render_system_nexus_interceptor(services: &[RenderedService<'_>]) -> String { output.push_str("\n\nclass _SystemNexusWorkflowOutboundInterceptorBase(abc.ABC):\n"); output.push_str(" @abc.abstractmethod\n def _next_system_nexus_interceptor(\n self,\n ) -> _SystemNexusWorkflowOutboundInterceptorBase:\n ...\n"); - for (service, operation) in &operations { + for (_service, operation) in &operations { let output_type = system_nexus_type_expr(&operation.output_type_expr); output.push_str("\n async def start_"); output.push_str(&operation.attr_name); @@ -4706,10 +4684,8 @@ fn render_system_nexus_interceptor(services: &[RenderedService<'_>]) -> String { output.push_str("\n ) -> temporalio.workflow.NexusOperationHandle["); output.push_str(&output_type); output.push_str("]:\n"); - output.push_str(" \"\"\"Intercept the System Nexus "); - output.push_str(service.wire_name); - output.push('/'); - output.push_str(operation.wire_name); + output.push_str(" \"\"\"Intercept the "); + output.push_str(operation.name); output.push_str(" operation.\"\"\"\n"); output.push_str(" return await self._next_system_nexus_interceptor().start_"); output.push_str(&operation.attr_name); @@ -7800,6 +7776,7 @@ mod tests { generate_files_for_tree_with_mode_and_options, generate_source, }; use crate::language::Language; + use crate::nexgen_config::{NexgenConfig, current, with_nexgen_config}; use crate::spec::ApiSpecTree; use crate::spec::{LanguageImportSpec, LanguageImportStyle}; @@ -8037,15 +8014,20 @@ class Example(enum.Enum): let descriptors = DescriptorIndex::load(&root.join("advanced/samples/descriptors/temporal_api.bin")) .unwrap(); - let generated = generate_files_for_tree_with_mode_and_options( - Language::Python, - ApiSpecTree::single(spec.clone()), - &descriptors, - &crate::SupportFiles::default(), - GenerationMode::NativeApi, - GenerateFilesOptions { + let generated = with_nexgen_config( + NexgenConfig { system_nexus: true, - ..GenerateFilesOptions::default() + ..current() + }, + || { + generate_files_for_tree_with_mode_and_options( + Language::Python, + ApiSpecTree::single(spec.clone()), + &descriptors, + &crate::SupportFiles::default(), + GenerationMode::NativeApi, + GenerateFilesOptions::default(), + ) }, ) .unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 285842a4..cdfb432d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ pub mod error; pub mod generator; pub mod json_schema; pub mod language; +pub mod nexgen_config; pub mod parser; pub mod spec; @@ -48,17 +49,18 @@ pub struct GenerateRequest { } pub fn generate_to_file(request: &GenerateRequest) -> Result<()> { - generate_to_file_with_system_nexus(request, false) + let config = nexgen_config::NexgenConfig { + mode: if request.generate_native_api { + GenerationMode::NativeApi + } else { + GenerationMode::DefinitionsOnly + }, + ..nexgen_config::current() + }; + nexgen_config::with_nexgen_config(config, || generate_to_file_inner(request)) } -/// Generates bindings with optional Temporal System Nexus-specific output. -/// -/// This is used by the advanced CLI surface; ordinary library generation keeps -/// the option disabled. -pub fn generate_to_file_with_system_nexus( - request: &GenerateRequest, - system_nexus: bool, -) -> Result<()> { +fn generate_to_file_inner(request: &GenerateRequest) -> Result<()> { // A resolved output path with no name at all (the filesystem root, or // `..` past it) is never a real output directory: Go and Java derive // package names from its basename, and for every language it means the @@ -90,20 +92,8 @@ pub fn generate_to_file_with_system_nexus( None }, ts_date_time_types: request.ts_date_time_types, - system_nexus, }; - let generated = compile_tree_to_files( - request.language, - tree, - &descriptors, - &support, - if request.generate_native_api { - GenerationMode::NativeApi - } else { - GenerationMode::DefinitionsOnly - }, - options, - )?; + let generated = compile_tree_to_files(request.language, tree, &descriptors, &support, options)?; print_warnings(&generated); write_generated_files(&request.output_path, &generated)?; @@ -123,9 +113,9 @@ pub(crate) fn compile_tree_to_files( authored_tree: ApiSpecTree, descriptors: &DescriptorIndex, support: &SupportFiles, - mode: GenerationMode, options: GenerateFilesOptions, ) -> Result { + let mode = nexgen_config::current().mode; // parse (frontend) -> validate authored intent -> select target metadata let authored_tree = planning::AuthoredValidationPass::new(descriptors, language).apply(authored_tree)?; diff --git a/src/main.rs b/src/main.rs index 22968e4f..d9a64a03 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,11 +2,11 @@ use std::path::PathBuf; use std::process::ExitCode; use clap::{Args, Parser, Subcommand, ValueEnum}; -#[cfg(feature = "advanced")] -use nexgen::generate_to_file_with_system_nexus; use nexgen::generator::TsDateTimeTypes; use nexgen::language::Language; #[cfg(feature = "advanced")] +use nexgen::nexgen_config::{NexgenConfig, current, with_nexgen_config}; +#[cfg(feature = "advanced")] use nexgen::parser::write_prepared_wit_directory; #[cfg(feature = "advanced")] use nexgen::{AddMessageRequest, AddRpcRequest, add_message_to_file, add_rpc_to_file}; @@ -172,10 +172,18 @@ fn main() -> ExitCode { #[cfg(feature = "advanced")] { let system_nexus = args.system_nexus; - generate_to_file_with_system_nexus( - &generate_request(Language::Python, args, Default::default(), None), + let config = NexgenConfig { system_nexus, - ) + ..current() + }; + with_nexgen_config(config, || { + generate_to_file(&generate_request( + Language::Python, + args, + Default::default(), + None, + )) + }) } #[cfg(not(feature = "advanced"))] { diff --git a/src/nexgen_config.rs b/src/nexgen_config.rs new file mode 100644 index 00000000..970cd389 --- /dev/null +++ b/src/nexgen_config.rs @@ -0,0 +1,79 @@ +//! Scoped generation settings shared across the compiler. +//! +//! Configuration is thread-local so concurrent in-process callers cannot affect +//! one another. Scopes nest and restore the prior configuration during unwinding. + +use std::cell::RefCell; + +use crate::generator::GenerationMode; + +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] +pub struct NexgenConfig { + pub mode: GenerationMode, + pub system_nexus: bool, +} + +thread_local! { + static CONFIGS: RefCell> = RefCell::new(Vec::new()); +} + +pub fn current() -> NexgenConfig { + CONFIGS.with(|configs| configs.borrow().last().copied().unwrap_or_default()) +} + +pub fn with_nexgen_config(config: NexgenConfig, f: impl FnOnce() -> T) -> T { + CONFIGS.with(|configs| configs.borrow_mut().push(config)); + let _scope = Scope; + f() +} + +struct Scope; + +impl Drop for Scope { + fn drop(&mut self) { + CONFIGS.with(|configs| { + configs + .borrow_mut() + .pop() + .expect("NexGen configuration scope must be present"); + }); + } +} + +#[cfg(test)] +mod tests { + use super::{NexgenConfig, current, with_nexgen_config}; + use crate::generator::GenerationMode; + + #[test] + fn restores_nested_configuration_after_unwinding() { + let outer = NexgenConfig { + mode: GenerationMode::DefinitionsOnly, + system_nexus: true, + }; + with_nexgen_config(outer, || { + assert_eq!(current(), outer); + let result = std::panic::catch_unwind(|| { + with_nexgen_config(NexgenConfig::default(), || panic!("test unwind")); + }); + assert!(result.is_err()); + assert_eq!(current(), outer); + }); + assert_eq!(current(), NexgenConfig::default()); + } + + #[test] + fn is_isolated_per_thread() { + let config = NexgenConfig { + mode: GenerationMode::DefinitionsOnly, + system_nexus: true, + }; + with_nexgen_config(config, || { + assert_eq!(current(), config); + assert_eq!( + std::thread::spawn(current).join().unwrap(), + NexgenConfig::default() + ); + }); + } +} diff --git a/xtask/src/build_examples.rs b/xtask/src/build_examples.rs index 4c7e92d0..86148223 100644 --- a/xtask/src/build_examples.rs +++ b/xtask/src/build_examples.rs @@ -6,7 +6,8 @@ use heck::ToSnakeCase; use nexgen::error::{Error, Result}; use nexgen::generator::{GenerationMode, TsDateTimeTypes}; use nexgen::language::Language; -use nexgen::{GenerateRequest, generate_to_file, generate_to_file_with_system_nexus}; +use nexgen::nexgen_config::{NexgenConfig, current, with_nexgen_config}; +use nexgen::{GenerateRequest, generate_to_file}; #[derive(Clone)] pub struct BuildExamplesRequest { @@ -393,10 +394,11 @@ fn build_example(repo_root: &Path, language: Language, example_id: &str) -> Resu .then(|| example_directory_name(language, example_id)), ts_date_time_types: Default::default(), }; - generate_to_file_with_system_nexus( - &generate_request, - language == Language::Python && example_id == "workflow-service", - )?; + let config = NexgenConfig { + system_nexus: language == Language::Python && example_id == "workflow-service", + ..current() + }; + with_nexgen_config(config, || generate_to_file(&generate_request))?; format_example_output(&language_root, language, &output_path)?; println!("Built {} with nexgen", output_path.display()); Ok(()) From 21c49956ca4f9637d9d273dad632332fe6923ce9 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Fri, 28 Aug 2026 10:10:01 -0700 Subject: [PATCH 3/7] refactor: read generation mode from config --- src/generator/dotnet.rs | 15 ++++++--------- src/generator/go.rs | 30 ++++++++++++------------------ src/generator/java.rs | 3 +-- src/generator/mod.rs | 16 ++++++---------- src/generator/python.rs | 32 +++++++++----------------------- src/generator/typescript.rs | 29 ++++++++--------------------- src/lib.rs | 8 +------- 7 files changed, 43 insertions(+), 90 deletions(-) diff --git a/src/generator/dotnet.rs b/src/generator/dotnet.rs index 2ee8e7c1..8685d50d 100644 --- a/src/generator/dotnet.rs +++ b/src/generator/dotnet.rs @@ -2257,22 +2257,21 @@ impl ExternalModelBackend for DotNetExternalModels { pub(crate) fn generate( tree: &crate::spec::ApiSpecTree, support: &crate::SupportFiles, - mode: GenerationMode, ) -> Result { match &tree.root { ApiSpecNode::Leaf(leaf) => { let support_fragments = support_fragments_for_plan(&leaf.spec, support); - generate_leaf(&leaf.spec, &support_fragments, mode) + generate_leaf(&leaf.spec, &support_fragments) } - ApiSpecNode::Branch(branch) => generate_tree(branch, support, mode), + ApiSpecNode::Branch(branch) => generate_tree(branch, support), } } fn generate_leaf( api_plan: &PlannedSpec, support_fragments: &[SupportFragmentSpec], - mode: GenerationMode, ) -> Result { + let mode = crate::nexgen_config::current().mode; let support_namespace = dotnet_support_namespace(support_fragments)?; let generator = ApiPlanner::new(api_plan, support_namespace.as_deref())?; validate_dotnet_support_references( @@ -2322,12 +2321,11 @@ fn generate_leaf( fn generate_tree( branch: &ApiSpecBranch, support: &crate::SupportFiles, - mode: GenerationMode, ) -> Result { let mut files = BTreeMap::new(); let mut warnings = Vec::new(); for node in branch.children.values() { - generate_tree_node(node, support, mode, &mut files, &mut warnings)?; + generate_tree_node(node, support, &mut files, &mut warnings)?; } Ok(GeneratedFiles { layout: crate::generator::GeneratedOutputLayout::Directory, @@ -2339,14 +2337,13 @@ fn generate_tree( fn generate_tree_node( node: &ApiSpecNode, support: &crate::SupportFiles, - mode: GenerationMode, files: &mut BTreeMap, warnings: &mut Vec, ) -> Result<()> { match node { ApiSpecNode::Leaf(leaf) => { let support_fragments = support_fragments_for_plan(&leaf.spec, support); - let generated = generate_leaf(&leaf.spec, &support_fragments, mode)?; + let generated = generate_leaf(&leaf.spec, &support_fragments)?; warnings.extend(generated.warnings); let prefix = leaf.module_path.to_path_buf(); for (path, contents) in generated.files { @@ -2356,7 +2353,7 @@ fn generate_tree_node( } ApiSpecNode::Branch(branch) => { for node in branch.children.values() { - generate_tree_node(node, support, mode, files, warnings)?; + generate_tree_node(node, support, files, warnings)?; } Ok(()) } diff --git a/src/generator/go.rs b/src/generator/go.rs index 0f39bc57..54dce334 100644 --- a/src/generator/go.rs +++ b/src/generator/go.rs @@ -625,9 +625,8 @@ pub(crate) fn generate( api_plan: &PlannedSpec, support_fragments: &[SupportFragmentSpec], options: &GoOptions, - mode: GenerationMode, ) -> Result { - generate_in_tree(api_plan, support_fragments, options, mode, &[]) + generate_in_tree(api_plan, support_fragments, options, &[]) } /// Generates one input file, given every JSON model the whole generate closure @@ -643,10 +642,9 @@ fn generate_in_tree( api_plan: &PlannedSpec, support_fragments: &[SupportFragmentSpec], options: &GoOptions, - mode: GenerationMode, tree_models: &[PlannedJsonType], ) -> Result { - ApiPlanner::new(api_plan, options, mode, tree_models)?.generate(support_fragments) + ApiPlanner::new(api_plan, options, tree_models)?.generate(support_fragments) } /// Every JSON model declared anywhere in the generate closure. @@ -662,11 +660,10 @@ pub(crate) fn generate_tree( tree: &ApiSpecTree, support: &SupportFiles, options: &GoOptions, - mode: GenerationMode, ) -> Result { match &tree.root { - ApiSpecNode::Leaf(leaf) => generate_single_leaf(leaf, support, options, mode), - ApiSpecNode::Branch(branch) => generate_branch_tree(branch, support, options, mode), + ApiSpecNode::Leaf(leaf) => generate_single_leaf(leaf, support, options), + ApiSpecNode::Branch(branch) => generate_branch_tree(branch, support, options), } } @@ -678,9 +675,8 @@ fn generate_single_leaf( leaf: &ApiSpecLeaf, support: &SupportFiles, options: &GoOptions, - mode: GenerationMode, ) -> Result { - let mut generated = generate(&leaf.spec, &support.fragments, options, mode)?; + let mut generated = generate(&leaf.spec, &support.fragments, options)?; if go_tree_has_json_models(&[leaf]) { let package_name = GoPackageContext::new(&leaf.spec, options)?.package_name; insert_generated_file( @@ -696,7 +692,6 @@ fn generate_branch_tree( branch: &ApiSpecBranch, support: &SupportFiles, options: &GoOptions, - mode: GenerationMode, ) -> Result { let mut leaves = Vec::new(); collect_leaf_specs(branch, &mut leaves); @@ -729,7 +724,7 @@ fn generate_branch_tree( // references to sibling files are unqualified within the one package. let mut leaf_spec = leaf.spec.clone(); leaf_spec.module_path = root.clone(); - let generated = generate_in_tree(&leaf_spec, &[], options, mode, &tree_models)?; + let generated = generate_in_tree(&leaf_spec, &[], options, &tree_models)?; warnings.extend(generated.warnings); // `generate` names the single JSON member file `.go`; re-key it @@ -885,9 +880,11 @@ fn plan_uses_json_models(api_plan: &PlannedSpec) -> bool { } impl GoExternalModels { - fn new(api_plan: &PlannedSpec, package: GoPackageContext, mode: GenerationMode) -> Self { + fn new(api_plan: &PlannedSpec, package: GoPackageContext) -> Self { if plan_uses_json_models(api_plan) { - Self::Json(json::ModelBackend::new(mode == GenerationMode::NativeApi)) + Self::Json(json::ModelBackend::new( + crate::nexgen_config::current().mode == GenerationMode::NativeApi, + )) } else { Self::Proto(proto::ModelBackend::new(package)) } @@ -1006,7 +1003,6 @@ impl GoExternalModels { struct ApiPlanner<'a> { api_plan: &'a PlannedSpec, - mode: GenerationMode, package: GoPackageContext, imports: BTreeSet, external_models: GoExternalModels, @@ -1020,7 +1016,6 @@ impl<'a> ApiPlanner<'a> { fn new( api_plan: &'a PlannedSpec, options: &GoOptions, - mode: GenerationMode, tree_models: &[PlannedJsonType], ) -> Result { let package = GoPackageContext::new(api_plan, options)?; @@ -1034,13 +1029,12 @@ impl<'a> ApiPlanner<'a> { collect_imports_from_plan(api_plan, &mut imports); imports.retain(|import_path| !package.is_self_import(import_path)); - let mut external_models = GoExternalModels::new(api_plan, package.clone(), mode); + let mut external_models = GoExternalModels::new(api_plan, package.clone()); external_models.adopt_tree_models(tree_models); external_models.prepare(api_plan)?; Ok(Self { api_plan, - mode, package, imports, external_models, @@ -1156,7 +1150,7 @@ impl<'a> ApiPlanner<'a> { self.imports .insert("github.com/nexus-rpc/sdk-go/nexus".to_string()); } - if self.mode == GenerationMode::NativeApi + if crate::nexgen_config::current().mode == GenerationMode::NativeApi && self.external_models.renders_operation_references() && !self.api_plan.services.is_empty() && !self.package.is_self_import("go.temporal.io/sdk/workflow") diff --git a/src/generator/java.rs b/src/generator/java.rs index df624fd9..c0f08dbf 100644 --- a/src/generator/java.rs +++ b/src/generator/java.rs @@ -6,7 +6,7 @@ use heck::ToLowerCamelCase; use crate::error::{Error, Result}; use crate::generator::json_schema::java as java_json; use crate::generator::json_schema::java::JavaContext; -use crate::generator::{GeneratedFiles, GeneratedOutputLayout, GenerationMode}; +use crate::generator::{GeneratedFiles, GeneratedOutputLayout}; use crate::planning::{PlannedFamily, PlannedJsonType}; use crate::spec::{ApiSpecLeaf, ApiSpecNode}; use crate::spec::{ExternalTypeSpec, ModulePath, ServiceSpec, TypeSpec}; @@ -17,7 +17,6 @@ const JAVA_FORMAT_LINE_LENGTH: usize = 88; pub(crate) fn generate( tree: &crate::spec::ApiSpecTree, _support: &crate::SupportFiles, - _mode: GenerationMode, base_package: Option<&str>, ) -> Result { let base_package = base_package.unwrap_or(DEFAULT_PACKAGE); diff --git a/src/generator/mod.rs b/src/generator/mod.rs index b0bc5000..b5d7a91c 100644 --- a/src/generator/mod.rs +++ b/src/generator/mod.rs @@ -146,17 +146,15 @@ pub(crate) fn generate_files_from_planned_tree( language: Language, tree: &ApiSpecTree, support: &SupportFiles, - mode: GenerationMode, options: GenerateFilesOptions, ) -> Result { + let mode = crate::nexgen_config::current().mode; let mut generated = match language { - Language::Dotnet => dotnet::generate(tree, support, mode), - Language::Go => generate_go_tree(tree, support, mode, options), - Language::Java => java::generate(tree, support, mode, options.java_package_root.as_deref()), - Language::Python => python::generate(tree, support, mode), - Language::TypeScript => { - typescript::generate(tree, support, mode, options.ts_date_time_types) - } + Language::Dotnet => dotnet::generate(tree, support), + Language::Go => generate_go_tree(tree, support, options), + Language::Java => java::generate(tree, support, options.java_package_root.as_deref()), + Language::Python => python::generate(tree, support), + Language::TypeScript => typescript::generate(tree, support, options.ts_date_time_types), language => Err(Error::UnsupportedLanguage { language }), }?; generated.warnings = if mode == GenerationMode::NativeApi { @@ -170,7 +168,6 @@ pub(crate) fn generate_files_from_planned_tree( fn generate_go_tree( tree: &ApiSpecTree, support: &SupportFiles, - mode: GenerationMode, options: GenerateFilesOptions, ) -> Result { go::generate_tree( @@ -180,7 +177,6 @@ fn generate_go_tree( output_dir_name: options.go_output_dir_name, ..go::GoOptions::default() }, - mode, ) } diff --git a/src/generator/python.rs b/src/generator/python.rs index bafbacd8..5f1c06cc 100644 --- a/src/generator/python.rs +++ b/src/generator/python.rs @@ -45,21 +45,19 @@ struct PythonGenerationResult { pub(crate) fn generate( tree: &crate::spec::ApiSpecTree, support: &crate::SupportFiles, - mode: GenerationMode, ) -> Result { match &tree.root { ApiSpecNode::Leaf(leaf) => { let support_fragments = support_fragments_for_plan(&leaf.spec, support); - generate_leaf(&leaf.spec, &support_fragments, mode) + generate_leaf(&leaf.spec, &support_fragments) } - ApiSpecNode::Branch(branch) => generate_tree(branch, support, mode), + ApiSpecNode::Branch(branch) => generate_tree(branch, support), } } fn generate_leaf( api_plan: &PlannedSpec, support_fragments: &[SupportFragmentSpec], - mode: GenerationMode, ) -> Result { reject_support_namespaces(Language::Python, support_fragments)?; let inline_model_rebuilds = api_plan @@ -68,24 +66,22 @@ fn generate_leaf( .values() .all(BTreeSet::is_empty); let generated = - ApiPlanner::new(api_plan, inline_model_rebuilds, None)?.build(support_fragments, mode)?; + ApiPlanner::new(api_plan, inline_model_rebuilds, None)?.build(support_fragments)?; Ok(generated.generated_files) } fn generate_leaf_with_model_hoists( api_plan: &PlannedSpec, support_fragments: &[SupportFragmentSpec], - mode: GenerationMode, model_hoists: &PythonModelHoists, ) -> Result { reject_support_namespaces(Language::Python, support_fragments)?; - ApiPlanner::new(api_plan, true, Some(model_hoists))?.build(support_fragments, mode) + ApiPlanner::new(api_plan, true, Some(model_hoists))?.build(support_fragments) } fn generate_tree( branch: &ApiSpecBranch, support: &crate::SupportFiles, - mode: GenerationMode, ) -> Result { let model_hoists = tree_model_hoists(branch)?; let mut files = BTreeMap::new(); @@ -100,7 +96,6 @@ fn generate_tree( let exported_names = generate_tree_node( node, support, - mode, &model_hoists, &mut files, &mut warnings, @@ -125,7 +120,6 @@ fn generate_tree( fn generate_tree_node( node: &ApiSpecNode, support: &crate::SupportFiles, - mode: GenerationMode, model_hoists: &PythonModelHoists, files: &mut BTreeMap, warnings: &mut Vec, @@ -134,12 +128,8 @@ fn generate_tree_node( match node { ApiSpecNode::Leaf(leaf) => { let support_fragments = support_fragments_for_plan(&leaf.spec, support); - let generated = generate_leaf_with_model_hoists( - &leaf.spec, - &support_fragments, - mode, - model_hoists, - )?; + let generated = + generate_leaf_with_model_hoists(&leaf.spec, &support_fragments, model_hoists)?; extend_root_package_imports(root_package_imports, generated.root_package_imports); warnings.extend(generated.generated_files.warnings); let prefix = leaf.module_path.to_path_buf(); @@ -154,7 +144,6 @@ fn generate_tree_node( let exported_names = generate_tree_node( node, support, - mode, model_hoists, files, warnings, @@ -509,7 +498,6 @@ impl<'a> ApiPlanner<'a> { fn build( mut self, support_fragments: &[SupportFragmentSpec], - mode: GenerationMode, ) -> Result { let api_plan = self.api_plan; let services = api_plan @@ -565,7 +553,7 @@ impl<'a> ApiPlanner<'a> { validate_python_generated_names(self.api_plan, &model_fragments.generated_names)?; let (generated_files, exported_names) = - self.render_package(&model_fragments, &services, support_fragments, mode)?; + self.render_package(&model_fragments, &services, support_fragments)?; Ok(PythonGenerationResult { generated_files, root_package_imports: model_fragments.root_package_imports, @@ -587,8 +575,8 @@ impl<'a> ApiPlanner<'a> { model_fragments: &RenderedModelFragments, services: &[RenderedService<'_>], support_fragments: &[SupportFragmentSpec], - mode: GenerationMode, ) -> Result<(GeneratedFiles, BTreeSet)> { + let mode = crate::nexgen_config::current().mode; let mut files = BTreeMap::new(); render_support_package(&mut files, support_fragments)?; for (path, contents) in self.external_models.render_support_files()? { @@ -682,7 +670,6 @@ impl<'a> ApiPlanner<'a> { &empty_root_package_imports }; let exported_names = package_export_names( - mode, services, if mode == GenerationMode::NativeApi { &package_model_names @@ -3334,14 +3321,13 @@ fn render_definitions_only_package_init( } fn package_export_names( - mode: GenerationMode, services: &[RenderedService<'_>], model_names: &[String], root_package_imports: &RootPackageImports, ) -> BTreeSet { let mut names = root_package_export_names(root_package_imports); names.extend(model_names.iter().cloned()); - match mode { + match crate::nexgen_config::current().mode { GenerationMode::DefinitionsOnly => { names.extend(services.iter().map(|service| service.name.to_string())); } diff --git a/src/generator/typescript.rs b/src/generator/typescript.rs index b8072def..6a869193 100644 --- a/src/generator/typescript.rs +++ b/src/generator/typescript.rs @@ -86,9 +86,9 @@ pub(crate) fn render_tree_support_files( fn generate_tree( branch: &ApiSpecBranch, support: &crate::SupportFiles, - mode: GenerationMode, ts_date_time_types: TsDateTimeTypes, ) -> Result { + let mode = crate::nexgen_config::current().mode; let mut files = BTreeMap::new(); let mut warnings = Vec::new(); let tree_support_files = render_tree_support_files(branch); @@ -97,14 +97,7 @@ fn generate_tree( insert_branch_index_file(&mut files, branch, has_json_runtime_module)?; insert_files(&mut files, tree_support_files)?; for node in branch.children.values() { - generate_tree_node( - node, - support, - mode, - ts_date_time_types, - &mut files, - &mut warnings, - )?; + generate_tree_node(node, support, ts_date_time_types, &mut files, &mut warnings)?; } Ok(GeneratedFiles { layout: crate::generator::GeneratedOutputLayout::Directory, @@ -116,7 +109,6 @@ fn generate_tree( fn generate_tree_node( node: &ApiSpecNode, support: &crate::SupportFiles, - mode: GenerationMode, ts_date_time_types: TsDateTimeTypes, files: &mut BTreeMap, warnings: &mut Vec, @@ -124,8 +116,7 @@ fn generate_tree_node( match node { ApiSpecNode::Leaf(leaf) => { let support_fragments = support_fragments_for_plan(&leaf.spec, support); - let generated = - generate_leaf(&leaf.spec, &support_fragments, mode, ts_date_time_types)?; + let generated = generate_leaf(&leaf.spec, &support_fragments, ts_date_time_types)?; warnings.extend(generated.warnings); let prefix = leaf.module_path.to_path_buf(); for (path, mut contents) in generated.files { @@ -141,7 +132,7 @@ fn generate_tree_node( ApiSpecNode::Branch(branch) => { insert_branch_index_file(files, branch, false)?; for node in branch.children.values() { - generate_tree_node(node, support, mode, ts_date_time_types, files, warnings)?; + generate_tree_node(node, support, ts_date_time_types, files, warnings)?; } Ok(()) } @@ -1889,7 +1880,6 @@ impl PlannedOperationExt for PlannedOperation { pub(crate) fn generate( tree: &crate::spec::ApiSpecTree, support: &crate::SupportFiles, - mode: GenerationMode, ts_date_time_types: TsDateTimeTypes, ) -> Result { // A `$ref` resolves against the whole input closure ([[ref]] @@ -1900,9 +1890,9 @@ pub(crate) fn generate( match &tree.root { ApiSpecNode::Leaf(leaf) => { let support_fragments = support_fragments_for_plan(&leaf.spec, support); - generate_leaf(&leaf.spec, &support_fragments, mode, ts_date_time_types) + generate_leaf(&leaf.spec, &support_fragments, ts_date_time_types) } - ApiSpecNode::Branch(branch) => generate_tree(branch, support, mode, ts_date_time_types), + ApiSpecNode::Branch(branch) => generate_tree(branch, support, ts_date_time_types), } } @@ -1938,7 +1928,6 @@ fn collect_tree_json_models_into( fn generate_leaf( api_plan: &PlannedSpec, support_fragments: &[SupportFragmentSpec], - mode: GenerationMode, ts_date_time_types: TsDateTimeTypes, ) -> Result { reject_support_namespaces(Language::TypeScript, support_fragments)?; @@ -2013,7 +2002,6 @@ fn generate_leaf( &language_imports, support_source.as_deref(), api_plan, - mode, ) } @@ -3087,8 +3075,8 @@ fn render_module_files( language_imports: &[LanguageImportSpec], support_source: Option<&str>, api_plan: &PlannedSpec, - mode: GenerationMode, ) -> Result { + let mode = crate::nexgen_config::current().mode; let support_source = support_source.filter(|source| !source.trim().is_empty()); let support_exports = support_source.map(support_exports); let module_model_names = model_fragments @@ -3109,7 +3097,6 @@ fn render_module_files( language_imports, support_exports.as_ref(), api_plan, - mode, ); // A module whose every operation type is `$ref`d from another file declares // nothing of its own. Emitting the empty `models.ts` anyway would leave the @@ -3729,8 +3716,8 @@ fn render_models_module( language_imports: &[LanguageImportSpec], support_exports: Option<&SupportExports>, api_plan: &PlannedSpec, - mode: GenerationMode, ) -> String { + let mode = crate::nexgen_config::current().mode; let mut body = String::new(); if mode == GenerationMode::NativeApi { diff --git a/src/lib.rs b/src/lib.rs index cdfb432d..f68d859a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,13 +144,7 @@ pub(crate) fn compile_tree_to_files( // planned IR -> emitted JSON names -> render target-language files let name_resolution = planning::EmittedNameResolutionPass::new(language, &planned_tree)?; let generator_ready_tree = name_resolution.apply(planned_tree)?; - generator::generate_files_from_planned_tree( - language, - &generator_ready_tree, - support, - mode, - options, - ) + generator::generate_files_from_planned_tree(language, &generator_ready_tree, support, options) } /// The output directory's basename, used as the Go package name — matching From 37ecf30af03c87e36ff5cd816f9070268b957e6b Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Fri, 28 Aug 2026 10:12:46 -0700 Subject: [PATCH 4/7] refactor: configure generation at entry points --- src/lib.rs | 3 +++ src/main.rs | 5 +++++ src/nexgen_config.rs | 4 ++++ xtask/src/build_examples.rs | 1 + 4 files changed, 13 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index f68d859a..1c71212b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,6 +49,9 @@ pub struct GenerateRequest { } pub fn generate_to_file(request: &GenerateRequest) -> Result<()> { + if nexgen_config::is_scoped() { + return generate_to_file_inner(request); + } let config = nexgen_config::NexgenConfig { mode: if request.generate_native_api { GenerationMode::NativeApi diff --git a/src/main.rs b/src/main.rs index d9a64a03..88320883 100644 --- a/src/main.rs +++ b/src/main.rs @@ -173,6 +173,11 @@ fn main() -> ExitCode { { let system_nexus = args.system_nexus; let config = NexgenConfig { + mode: if args.generate_native_api { + nexgen::generator::GenerationMode::NativeApi + } else { + nexgen::generator::GenerationMode::DefinitionsOnly + }, system_nexus, ..current() }; diff --git a/src/nexgen_config.rs b/src/nexgen_config.rs index 970cd389..b0e9b78f 100644 --- a/src/nexgen_config.rs +++ b/src/nexgen_config.rs @@ -21,6 +21,10 @@ pub fn current() -> NexgenConfig { CONFIGS.with(|configs| configs.borrow().last().copied().unwrap_or_default()) } +pub fn is_scoped() -> bool { + CONFIGS.with(|configs| !configs.borrow().is_empty()) +} + pub fn with_nexgen_config(config: NexgenConfig, f: impl FnOnce() -> T) -> T { CONFIGS.with(|configs| configs.borrow_mut().push(config)); let _scope = Scope; diff --git a/xtask/src/build_examples.rs b/xtask/src/build_examples.rs index 86148223..5b2f48e2 100644 --- a/xtask/src/build_examples.rs +++ b/xtask/src/build_examples.rs @@ -395,6 +395,7 @@ fn build_example(repo_root: &Path, language: Language, example_id: &str) -> Resu ts_date_time_types: Default::default(), }; let config = NexgenConfig { + mode: GenerationMode::NativeApi, system_nexus: language == Language::Python && example_id == "workflow-service", ..current() }; From aa21c86a7663d79240126f16972ec98fded9fbfc Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Fri, 28 Aug 2026 10:38:44 -0700 Subject: [PATCH 5/7] refactor: configure generation requests --- src/generator/mod.rs | 5 ++- src/generator/python.rs | 28 +++++++--------- src/lib.rs | 20 ++--------- src/main.rs | 20 ++++------- src/nexgen_config.rs | 39 +++++++++++++--------- tests/doc_rendering.rs | 2 +- tests/generate_dotnet.rs | 2 +- tests/generate_go.rs | 64 ++++++++++++++++++------------------ tests/generate_java.rs | 62 ++++++++++++++++++---------------- tests/generate_python.rs | 46 +++++++++++++------------- tests/generate_typescript.rs | 50 ++++++++++++++-------------- tests/toolchain/mod.rs | 2 +- xtask/src/build_examples.rs | 15 ++++----- 13 files changed, 169 insertions(+), 186 deletions(-) diff --git a/src/generator/mod.rs b/src/generator/mod.rs index b5d7a91c..70f96dfb 100644 --- a/src/generator/mod.rs +++ b/src/generator/mod.rs @@ -137,9 +137,8 @@ pub(crate) fn generate_files_for_tree_with_mode_and_options( mode, ..crate::nexgen_config::current() }; - crate::nexgen_config::with_nexgen_config(config, || { - crate::compile_tree_to_files(language, tree, descriptors, support, options) - }) + let _scope = crate::nexgen_config::scope(config); + crate::compile_tree_to_files(language, tree, descriptors, support, options) } pub(crate) fn generate_files_from_planned_tree( diff --git a/src/generator/python.rs b/src/generator/python.rs index 5f1c06cc..357b333a 100644 --- a/src/generator/python.rs +++ b/src/generator/python.rs @@ -7762,7 +7762,7 @@ mod tests { generate_files_for_tree_with_mode_and_options, generate_source, }; use crate::language::Language; - use crate::nexgen_config::{NexgenConfig, current, with_nexgen_config}; + use crate::nexgen_config::{NexgenConfig, current, scope}; use crate::spec::ApiSpecTree; use crate::spec::{LanguageImportSpec, LanguageImportStyle}; @@ -8000,21 +8000,17 @@ class Example(enum.Enum): let descriptors = DescriptorIndex::load(&root.join("advanced/samples/descriptors/temporal_api.bin")) .unwrap(); - let generated = with_nexgen_config( - NexgenConfig { - system_nexus: true, - ..current() - }, - || { - generate_files_for_tree_with_mode_and_options( - Language::Python, - ApiSpecTree::single(spec.clone()), - &descriptors, - &crate::SupportFiles::default(), - GenerationMode::NativeApi, - GenerateFilesOptions::default(), - ) - }, + let _scope = scope(NexgenConfig { + system_nexus: true, + ..current() + }); + let generated = generate_files_for_tree_with_mode_and_options( + Language::Python, + ApiSpecTree::single(spec.clone()), + &descriptors, + &crate::SupportFiles::default(), + GenerationMode::NativeApi, + GenerateFilesOptions::default(), ) .unwrap(); assert_eq!(generated.layout, GeneratedOutputLayout::Directory); diff --git a/src/lib.rs b/src/lib.rs index 1c71212b..4e5beebe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,13 +32,13 @@ pub struct SupportFiles { } pub struct GenerateRequest { + pub config: nexgen_config::NexgenConfig, pub language: Language, pub input_paths: Vec, pub support_paths: Vec, pub descriptor_paths: Vec, pub output_path: PathBuf, pub format: bool, - pub generate_native_api: bool, /// Java-only: the base package for generated types. Its last /// dot-separated segment must match the output directory's name. Ignored /// for other languages. @@ -49,21 +49,7 @@ pub struct GenerateRequest { } pub fn generate_to_file(request: &GenerateRequest) -> Result<()> { - if nexgen_config::is_scoped() { - return generate_to_file_inner(request); - } - let config = nexgen_config::NexgenConfig { - mode: if request.generate_native_api { - GenerationMode::NativeApi - } else { - GenerationMode::DefinitionsOnly - }, - ..nexgen_config::current() - }; - nexgen_config::with_nexgen_config(config, || generate_to_file_inner(request)) -} - -fn generate_to_file_inner(request: &GenerateRequest) -> Result<()> { + let _config_scope = nexgen_config::scope(request.config); // A resolved output path with no name at all (the filesystem root, or // `..` past it) is never a real output directory: Go and Java derive // package names from its basename, and for every language it means the @@ -449,13 +435,13 @@ mod tests { fn java_request(output_path: &str, java_package_name: Option<&str>) -> GenerateRequest { GenerateRequest { + config: Default::default(), language: Language::Java, input_paths: Vec::new(), support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: PathBuf::from(output_path), format: false, - generate_native_api: false, java_package_name: java_package_name.map(str::to_string), ts_date_time_types: Default::default(), } diff --git a/src/main.rs b/src/main.rs index 88320883..17adc2f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use clap::{Args, Parser, Subcommand, ValueEnum}; use nexgen::generator::TsDateTimeTypes; use nexgen::language::Language; #[cfg(feature = "advanced")] -use nexgen::nexgen_config::{NexgenConfig, current, with_nexgen_config}; +use nexgen::nexgen_config::NexgenConfig; #[cfg(feature = "advanced")] use nexgen::parser::write_prepared_wit_directory; #[cfg(feature = "advanced")] @@ -179,16 +179,11 @@ fn main() -> ExitCode { nexgen::generator::GenerationMode::DefinitionsOnly }, system_nexus, - ..current() }; - with_nexgen_config(config, || { - generate_to_file(&generate_request( - Language::Python, - args, - Default::default(), - None, - )) - }) + let mut request = + generate_request(Language::Python, args, Default::default(), None); + request.config = config; + generate_to_file(&request) } #[cfg(not(feature = "advanced"))] { @@ -240,6 +235,7 @@ fn generate_request( java_package_name: Option, ) -> GenerateRequest { GenerateRequest { + config: Default::default(), language, input_paths: args.inputs, #[cfg(feature = "advanced")] @@ -255,10 +251,6 @@ fn generate_request( format: args.format, #[cfg(not(feature = "advanced"))] format: false, - #[cfg(feature = "advanced")] - generate_native_api: args.generate_native_api, - #[cfg(not(feature = "advanced"))] - generate_native_api: false, java_package_name, ts_date_time_types, } diff --git a/src/nexgen_config.rs b/src/nexgen_config.rs index b0e9b78f..28038e06 100644 --- a/src/nexgen_config.rs +++ b/src/nexgen_config.rs @@ -7,12 +7,21 @@ use std::cell::RefCell; use crate::generator::GenerationMode; -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct NexgenConfig { pub mode: GenerationMode, pub system_nexus: bool, } +impl Default for NexgenConfig { + fn default() -> Self { + Self { + mode: GenerationMode::DefinitionsOnly, + system_nexus: false, + } + } +} + thread_local! { static CONFIGS: RefCell> = RefCell::new(Vec::new()); } @@ -21,19 +30,14 @@ pub fn current() -> NexgenConfig { CONFIGS.with(|configs| configs.borrow().last().copied().unwrap_or_default()) } -pub fn is_scoped() -> bool { - CONFIGS.with(|configs| !configs.borrow().is_empty()) -} - -pub fn with_nexgen_config(config: NexgenConfig, f: impl FnOnce() -> T) -> T { +pub fn scope(config: NexgenConfig) -> NexgenConfigScope { CONFIGS.with(|configs| configs.borrow_mut().push(config)); - let _scope = Scope; - f() + NexgenConfigScope } -struct Scope; +pub struct NexgenConfigScope; -impl Drop for Scope { +impl Drop for NexgenConfigScope { fn drop(&mut self) { CONFIGS.with(|configs| { configs @@ -46,7 +50,7 @@ impl Drop for Scope { #[cfg(test)] mod tests { - use super::{NexgenConfig, current, with_nexgen_config}; + use super::{NexgenConfig, current, scope}; use crate::generator::GenerationMode; #[test] @@ -55,14 +59,16 @@ mod tests { mode: GenerationMode::DefinitionsOnly, system_nexus: true, }; - with_nexgen_config(outer, || { + { + let _outer_scope = scope(outer); assert_eq!(current(), outer); let result = std::panic::catch_unwind(|| { - with_nexgen_config(NexgenConfig::default(), || panic!("test unwind")); + let _inner_scope = scope(NexgenConfig::default()); + panic!("test unwind"); }); assert!(result.is_err()); assert_eq!(current(), outer); - }); + } assert_eq!(current(), NexgenConfig::default()); } @@ -72,12 +78,13 @@ mod tests { mode: GenerationMode::DefinitionsOnly, system_nexus: true, }; - with_nexgen_config(config, || { + { + let _scope = scope(config); assert_eq!(current(), config); assert_eq!( std::thread::spawn(current).join().unwrap(), NexgenConfig::default() ); - }); + } } } diff --git a/tests/doc_rendering.rs b/tests/doc_rendering.rs index b106312f..a0c7764c 100644 --- a/tests/doc_rendering.rs +++ b/tests/doc_rendering.rs @@ -72,13 +72,13 @@ fn generate(language: nexgen::language::Language, java_package_name: Option<&str let output_path = temp_dir.join(output_dir_name); fs::write(&input_path, HOSTILE_DOCUMENTATION_SCHEMA).unwrap(); generate_to_file(&GenerateRequest { + config: Default::default(), language, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: true, java_package_name: java_package_name.map(str::to_string), ts_date_time_types: Default::default(), }) diff --git a/tests/generate_dotnet.rs b/tests/generate_dotnet.rs index 5e7636e9..ea92e5e2 100644 --- a/tests/generate_dotnet.rs +++ b/tests/generate_dotnet.rs @@ -139,13 +139,13 @@ fn generate_dotnet_files( let temp_dir = unique_output_path("dotnet-rendered"); let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Dotnet, input_paths: input_paths.to_vec(), support_paths: Vec::new(), descriptor_paths: descriptor_paths.to_vec(), output_path: output_path.clone(), format: false, - generate_native_api: true, java_package_name: None, ts_date_time_types: Default::default(), }) diff --git a/tests/generate_go.rs b/tests/generate_go.rs index 38fc432d..59db1bb3 100644 --- a/tests/generate_go.rs +++ b/tests/generate_go.rs @@ -214,13 +214,13 @@ fn generate_to_string_with_inputs( let temp_dir = unique_output_path("go-rendered"); let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { + config: Default::default(), language, input_paths: input_paths.to_vec(), support_paths: Vec::new(), descriptor_paths: descriptor_paths.to_vec(), output_path: output_path.clone(), format: false, - generate_native_api: true, java_package_name: None, ts_date_time_types: Default::default(), })?; @@ -1025,13 +1025,13 @@ fn go_json_package_name_derives_from_output_directory_name() { let temp_dir = unique_output_path("go-json-package-name-fallback"); let output_path = temp_dir.join("widgets"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![json_input_path(&root, "chat")], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: true, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1723,13 +1723,13 @@ fn go_rejects_inputs_flattening_to_the_same_module_file() { let output_path = temp_dir.join("output"); let result = generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![temp_dir.clone()], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path, format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }); @@ -1761,13 +1761,13 @@ fn go_rejects_reserved_generated_name_collision() { let output_path = temp_dir.join("output"); let result = generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![temp_dir.clone()], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path, format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }); @@ -1832,13 +1832,13 @@ fn go_json_names_inline_object_union_branch() { let output_path = temp_dir.join("detail"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1870,13 +1870,13 @@ fn go_json_decodes_element_position_unions() { let output_path = temp_dir.join("bag"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1969,13 +1969,13 @@ fn go_json_recursively_converts_and_validates_element_positions() { let output_path = temp_dir.join("recursive"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2101,13 +2101,13 @@ fn go_json_validates_non_object_union_branch_constraints() { let output_path = temp_dir.join("bc"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2155,13 +2155,13 @@ properties: let output_path = temp_dir.join("note"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2200,13 +2200,13 @@ properties: let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2273,13 +2273,13 @@ $defs: let output_path = temp_dir.join("mixed"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2377,13 +2377,13 @@ properties: .unwrap(); let output_path = temp_dir.join("matcher"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2486,13 +2486,13 @@ services: .unwrap(); let output_path = temp_dir.join("service"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2531,13 +2531,13 @@ $defs: .unwrap(); let output_path = temp_dir.join("temporal_wire"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2624,13 +2624,13 @@ properties: .unwrap(); let output_path = temp_dir.join("native"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2690,13 +2690,13 @@ fn go_json_wave3_pairwise_runtime_matrix() { fs::write(&input_path, GO_WAVE3_MATRIX_SCHEMA).unwrap(); let output_path = temp_dir.join("audit"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2971,13 +2971,13 @@ fn go_json_cross_module_go_name_override_moves_every_reference() { let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3036,13 +3036,13 @@ fn go_json_override_moves_member_derived_names_only() { let output_path = temp_dir.join("probe"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3101,13 +3101,13 @@ services: .unwrap(); let error = generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_dir.clone()], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: temp_dir.join("out"), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3123,13 +3123,13 @@ services: // Java gives each module its own sub-package (`…pkg.a.page`, `…pkg.b.page`) // and emits no aggregating barrel, so the two `Page` classes stay distinct. generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: temp_dir.join("pkg"), format: false, - generate_native_api: false, java_package_name: Some("com.example.pkg".to_string()), ts_date_time_types: Default::default(), }) @@ -3178,13 +3178,13 @@ $defs: .unwrap(); let error = generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: temp_dir.join("out"), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3229,13 +3229,13 @@ services: let output_path = temp_dir.join("out"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3288,13 +3288,13 @@ properties: .unwrap(); let output_path = temp_dir.join("fmod"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3400,13 +3400,13 @@ properties: .unwrap(); let output_path = temp_dir.join("nullable"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3550,13 +3550,13 @@ $defs: let output_path = temp_dir.join("out"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3625,13 +3625,13 @@ properties: .unwrap(); let output_path = temp_dir.join("mat"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3764,13 +3764,13 @@ properties: .unwrap(); let output_path = temp_dir.join("bag"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3854,13 +3854,13 @@ $defs: .unwrap(); let output_path = temp_dir.join("shapes"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -3980,13 +3980,13 @@ $defs: .unwrap(); let output_path = temp_dir.join("shapes"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -4039,13 +4039,13 @@ properties: .unwrap(); let output_path = temp_dir.join("nums"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -4131,13 +4131,13 @@ properties: .unwrap(); let output_path = temp_dir.join("elements"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -4251,13 +4251,13 @@ properties: .unwrap(); let output_path = temp_dir.join("names"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Go, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) diff --git a/tests/generate_java.rs b/tests/generate_java.rs index e79c1871..33ed9e3b 100644 --- a/tests/generate_java.rs +++ b/tests/generate_java.rs @@ -318,7 +318,7 @@ fn read_java_files(dir: &Path) -> BTreeMap { /// Regenerates one example into a temp Gradle-shaped tree so the derived Java /// package matches the checked-in output, then compares the emitted files. -fn assert_regeneration_matches(mode: &str, generate_native_api: bool) { +fn assert_regeneration_matches(mode: &str, generation_mode: nexgen::generator::GenerationMode) { let root = project_root(); for example_id in ["chat", "kb", "showcase", "temporal"] { let temp_dir = unique_output_path(&format!("java-json-{mode}-{example_id}")); @@ -327,13 +327,16 @@ fn assert_regeneration_matches(mode: &str, generate_native_api: bool) { let output_path = temp_dir.join(example_id); generate_to_file(&GenerateRequest { + config: nexgen::nexgen_config::NexgenConfig { + mode: generation_mode, + ..Default::default() + }, language: nexgen::language::Language::Java, input_paths: vec![json_input_path(&root, example_id)], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api, java_package_name: Some(format!("json_schema.{mode}.{example_id}")), ts_date_time_types: Default::default(), }) @@ -392,12 +395,15 @@ fn assert_regeneration_matches(mode: &str, generate_native_api: bool) { #[test] fn java_json_example_generation_matches_checked_in_output() { - assert_regeneration_matches("definitions", false); + assert_regeneration_matches( + "definitions", + nexgen::generator::GenerationMode::DefinitionsOnly, + ); } #[test] fn java_json_api_example_generation_matches_checked_in_output() { - assert_regeneration_matches("api", true); + assert_regeneration_matches("api", nexgen::generator::GenerationMode::NativeApi); } /// A structured inline object branch of a property-level union is named @@ -414,13 +420,13 @@ fn java_json_names_inline_object_union_branch() { let output_path = temp_dir.join("detail"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("detail".to_string()), ts_date_time_types: Default::default(), }) @@ -466,13 +472,13 @@ fn java_json_validates_non_object_union_branch_constraints() { let output_path = temp_dir.join("bc"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("bc".to_string()), ts_date_time_types: Default::default(), }) @@ -515,13 +521,13 @@ fn java_json_rejects_non_finite_numbers_in_every_serialize_position() { let output_path = temp_dir.join("finite"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("finite".to_string()), ts_date_time_types: Default::default(), }) @@ -580,13 +586,13 @@ fn java_json_emits_runtime_support_for_nested_materialized_values() { let output_path = temp_dir.join("nested"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("nested".to_string()), ts_date_time_types: Default::default(), }) @@ -649,13 +655,13 @@ fn java_json_emits_wave2_object_and_matcher_contracts() { let output_path = temp_dir.join("java_conformance"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("java_conformance".to_string()), ts_date_time_types: Default::default(), }) @@ -743,13 +749,13 @@ fn java_json_emits_deprecated_services_and_operations() { let output_path = temp_dir.join("legacy"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: true, java_package_name: Some("legacy".to_string()), ts_date_time_types: Default::default(), }) @@ -785,13 +791,13 @@ fn java_json_rejects_empty_service_descriptions() { let input_path = temp_dir.join("empty.nexusrpc.yaml"); fs::write(&input_path, JAVA_EMPTY_SERVICE_DESCRIPTION_SCHEMA).unwrap(); let error = generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: temp_dir.join("empty"), format: false, - generate_native_api: true, java_package_name: Some("empty".to_string()), ts_date_time_types: Default::default(), }) @@ -819,13 +825,13 @@ fn java_json_decodes_element_position_unions() { let output_path = temp_dir.join("bag"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("bag".to_string()), ts_date_time_types: Default::default(), }) @@ -928,13 +934,13 @@ fn java_json_cross_module_java_name_override_moves_every_reference() { let output_path = temp_dir.join("pages"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("example.pages".to_string()), ts_date_time_types: Default::default(), }) @@ -1007,13 +1013,13 @@ services: let output_path = temp_dir.join("pkg"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("com.example.pkg".to_string()), ts_date_time_types: Default::default(), }) @@ -1075,13 +1081,13 @@ fn java_json_nullable_property_keeps_the_branch_constraints() { let output_path = temp_dir.join("nullable_shape"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("nullable_shape".to_string()), ts_date_time_types: Default::default(), }) @@ -1151,13 +1157,13 @@ fn java_json_serialize_side_guards_match_the_parse_side() { let output_path = temp_dir.join("guards"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("guards".to_string()), ts_date_time_types: Default::default(), }) @@ -1235,13 +1241,13 @@ fn java_json_dispatches_a_non_string_discriminant_by_value() { let output_path = temp_dir.join("tagged"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("tagged".to_string()), ts_date_time_types: Default::default(), }) @@ -1294,13 +1300,13 @@ fn java_json_repaths_nested_violations_on_serialize() { let output_path = temp_dir.join("nested_path"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("nested_path".to_string()), ts_date_time_types: Default::default(), }) @@ -1353,13 +1359,13 @@ fn java_json_compiles_contains_matcher_regexes_once() { let output_path = temp_dir.join("contains_regex"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("contains_regex".to_string()), ts_date_time_types: Default::default(), }) @@ -1416,13 +1422,13 @@ fn java_json_member_javadoc_lands_on_the_getter() { let output_path = temp_dir.join("member_doc"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("member_doc".to_string()), ts_date_time_types: Default::default(), }) @@ -1478,13 +1484,13 @@ fn java_json_typed_map_union_branch_implements_the_interface() { let output_path = temp_dir.join("union_map"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("union_map".to_string()), ts_date_time_types: Default::default(), }) @@ -1554,13 +1560,13 @@ fn java_json_nullable_element_keeps_the_branch_constraints() { let output_path = temp_dir.join("nullable_element"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("nullable_element".to_string()), ts_date_time_types: Default::default(), }) @@ -1633,13 +1639,13 @@ fn java_json_writes_materialized_collection_elements_itself() { let output_path = temp_dir.join("materialized"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("materialized".to_string()), ts_date_time_types: Default::default(), }) @@ -1714,13 +1720,13 @@ fn java_json_enum_name_override_reaches_non_string_members() { let output_path = temp_dir.join("enum_names"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("enum_names".to_string()), ts_date_time_types: Default::default(), }) @@ -1794,13 +1800,13 @@ properties: let output_path = temp_dir.join("naming"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("naming".to_string()), ts_date_time_types: Default::default(), }) @@ -1863,13 +1869,13 @@ properties: .unwrap(); let output_path = temp_dir.join("spelling"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("spelling".to_string()), ts_date_time_types: Default::default(), }) @@ -1910,13 +1916,13 @@ properties: .unwrap(); let error = generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: temp_dir.join("collide"), format: false, - generate_native_api: false, java_package_name: Some("collide".to_string()), ts_date_time_types: Default::default(), }) @@ -1951,13 +1957,13 @@ properties: let output_path = temp_dir.join("fracsec"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Java, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: Some("fracsec".to_string()), ts_date_time_types: Default::default(), }) diff --git a/tests/generate_python.rs b/tests/generate_python.rs index 471a8c5e..be2b0bb5 100644 --- a/tests/generate_python.rs +++ b/tests/generate_python.rs @@ -761,13 +761,13 @@ fn generate_python_to_string(input_paths: &[PathBuf], descriptor_paths: &[PathBu let temp_dir = unique_output_path("python-rendered"); let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: input_paths.to_vec(), support_paths: Vec::new(), descriptor_paths: descriptor_paths.to_vec(), output_path: output_path.clone(), format: false, - generate_native_api: true, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -788,13 +788,13 @@ fn generate_python_package_files( let temp_dir = unique_output_path("python-package"); let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: input_paths.to_vec(), support_paths: Vec::new(), descriptor_paths: descriptor_paths.to_vec(), output_path: output_path.clone(), format: false, - generate_native_api: true, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1609,13 +1609,13 @@ fn python_json_names_inline_object_union_branch() { let output_path = temp_dir.join("detail"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1646,13 +1646,13 @@ fn python_json_validates_non_object_union_branch_constraints() { let output_path = temp_dir.join("bc"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1694,13 +1694,13 @@ fn python_json_enforces_remaining_scalar_and_typed_extra_contracts() { let output_path = temp_dir.join("contract_package"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1750,13 +1750,13 @@ $defs: let output_path = temp_dir.join("contract_package"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: true, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1803,13 +1803,13 @@ fn python_json_union_serializer_validates_before_dispatching() { let output_path = temp_dir.join("bag_package"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1869,13 +1869,13 @@ fn python_json_annotates_element_position_unions() { let output_path = temp_dir.join("bag"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1959,13 +1959,13 @@ fn python_json_cross_module_py_name_override_moves_every_reference() { let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2021,13 +2021,13 @@ fn python_json_rejects_same_type_name_in_two_modules() { .unwrap(); let request = |output: &str| GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_dir.clone()], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: temp_dir.join(output), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }; @@ -2094,13 +2094,13 @@ services: let output_path = temp_dir.join("out"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2146,13 +2146,13 @@ fn python_json_property_names_never_shadow_converter_locals() { let output_path = temp_dir.join("shadow_package"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2229,13 +2229,13 @@ fn python_json_model_properties_use_union_none_and_defaults_preserve_presence() let output_path = temp_dir.join("default_package"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2275,20 +2275,20 @@ fn python_json_model_properties_use_union_none_and_defaults_preserve_presence() fn generate_unformatted_python_package( temp_dir: &Path, schema_source: &str, - generate_native_api: bool, + config: nexgen::nexgen_config::NexgenConfig, ) -> PathBuf { fs::create_dir_all(temp_dir).unwrap(); let input_path = temp_dir.join("probe.nexusrpc.yaml"); fs::write(&input_path, schema_source).unwrap(); let output_path = temp_dir.join("probe_package"); generate_to_file(&GenerateRequest { + config, language: nexgen::language::Language::Python, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2328,7 +2328,7 @@ $defs: description: 'Trailing quote "' type: string "##, - false, + nexgen::nexgen_config::NexgenConfig::default(), ); let models = fs::read_to_string(output_path.join("models.py")).unwrap(); @@ -2383,7 +2383,7 @@ $defs: properties: a: { type: string } "##, - false, + nexgen::nexgen_config::NexgenConfig::default(), ); let services = fs::read_to_string(output_path.join("services.py")).unwrap(); @@ -2424,7 +2424,7 @@ $defs: uniqueItems: true items: { type: string } "##, - false, + nexgen::nexgen_config::NexgenConfig::default(), ); let models = fs::read_to_string(output_path.join("models.py")).unwrap(); @@ -2458,7 +2458,7 @@ $defs: dd: { type: string, format: date } tt: { type: string, format: time } "##, - false, + nexgen::nexgen_config::NexgenConfig::default(), ); let definitions = fs::read_to_string(output_path.join("_definitions.py")).unwrap(); @@ -2520,7 +2520,7 @@ $defs: maximum: 9007199254740992 i: { type: integer } "##, - false, + nexgen::nexgen_config::NexgenConfig::default(), ); let models = fs::read_to_string(output_path.join("models.py")).unwrap(); @@ -2592,7 +2592,7 @@ $defs: items: { type: number } contains: { enum: [1.5, 2] } "##, - false, + nexgen::nexgen_config::NexgenConfig::default(), ); let models = fs::read_to_string(output_path.join("models.py")).unwrap(); @@ -2646,13 +2646,13 @@ $defs: ) .unwrap(); let error = generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::Python, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: temp_dir.join("out"), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2683,7 +2683,7 @@ $defs: - { type: string } - { type: integer } "##, - false, + nexgen::nexgen_config::NexgenConfig::default(), ); let models = fs::read_to_string(output_path.join("models.py")).unwrap(); diff --git a/tests/generate_typescript.rs b/tests/generate_typescript.rs index c06232ad..c33a7be9 100644 --- a/tests/generate_typescript.rs +++ b/tests/generate_typescript.rs @@ -615,13 +615,13 @@ fn generate_typescript_to_string(input_paths: &[PathBuf], descriptor_paths: &[Pa let temp_dir = unique_output_path("typescript-rendered"); let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: input_paths.to_vec(), support_paths: Vec::new(), descriptor_paths: descriptor_paths.to_vec(), output_path: output_path.clone(), format: false, - generate_native_api: true, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1157,13 +1157,13 @@ fn typescript_json_names_inline_object_union_branch() { let output_path = temp_dir.join("detail"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1200,13 +1200,13 @@ fn typescript_json_validates_non_object_union_branch_constraints() { let output_path = temp_dir.join("bc"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1247,13 +1247,13 @@ fn typescript_json_recursively_converts_union_array_branches() { let output_path = temp_dir.join("probe"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: nexgen::generator::TsDateTimeTypes::Date, }) @@ -1306,13 +1306,13 @@ fn typescript_json_rejects_non_finite_numbers_at_every_position() { let output_path = temp_dir.join("probe"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1341,13 +1341,13 @@ fn typescript_json_detects_nested_runtime_support() { let output_path = temp_dir.join("probe"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1375,13 +1375,13 @@ fn typescript_json_validates_native_temporals_before_serializing() { let output_path = temp_dir.join("probe"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: repr, }) @@ -1435,13 +1435,13 @@ fn typescript_json_guards_nullable_array_elements_during_serialize_validation() let output_path = temp_dir.join("probe"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1477,13 +1477,13 @@ fn typescript_json_maps_element_position_unions() { let output_path = temp_dir.join("bag"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1516,13 +1516,13 @@ fn typescript_json_one_sided_operation_type_info() { let output_path = temp_dir.join("jobs"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1553,13 +1553,13 @@ fn typescript_json_operation_type_info_follows_ts_name_override() { let output_path = temp_dir.join("pages"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1592,13 +1592,13 @@ fn typescript_json_cross_module_ts_name_override_moves_every_reference() { let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1650,13 +1650,13 @@ fn typescript_json_override_moves_member_derived_names_only() { let output_path = temp_dir.join("probe"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1692,13 +1692,13 @@ fn typescript_json_rejects_same_type_name_in_two_modules() { fs::write(input_dir.join("b/page.json"), page).unwrap(); let request = |output: &str| GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_dir.clone()], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: temp_dir.join(output), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }; @@ -1777,13 +1777,13 @@ fn typescript_json_service_module_without_own_types_imports_instead_of_reemittin let input_dir = write_service_only_module_closure(&temp_dir); let output_path = temp_dir.join("out"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_dir], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -1836,13 +1836,13 @@ fn typescript_json_emits_complete_matchers_and_typed_mixed_extras() { let output_path = temp_dir.join("probe"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: nexgen::generator::TsDateTimeTypes::Temporal, }) @@ -1993,13 +1993,13 @@ fn typescript_json_emits_complete_property_name_matcher() { fs::write(&input_path, TYPESCRIPT_PROPERTY_NAMES_SCHEMA).unwrap(); let output_path = temp_dir.join("names"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2025,13 +2025,13 @@ fn typescript_json_materializes_closed_values_and_nullable_defaults() { fs::write(&input_path, TYPESCRIPT_MATERIALIZED_CLOSED_SCHEMA).unwrap(); let output_path = temp_dir.join("closed"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: nexgen::generator::TsDateTimeTypes::Temporal, }) @@ -2061,13 +2061,13 @@ fn typescript_json_deprecates_types_fields_services_and_operations() { fs::write(&input_path, TYPESCRIPT_DEPRECATION_SCHEMA).unwrap(); let output_path = temp_dir.join("jobs"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2089,13 +2089,13 @@ fn typescript_json_wave3_pairwise_runtime_matrix() { fs::write(&input_path, TYPESCRIPT_WAVE3_MATRIX_SCHEMA).unwrap(); let output_path = temp_dir.join("audit"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: nexgen::generator::TsDateTimeTypes::Temporal, }) @@ -2409,13 +2409,13 @@ fn typescript_json_wave7_discrete_defects_typecheck_and_run() { fs::write(&input_path, TYPESCRIPT_WAVE7_SCHEMA).unwrap(); let output_path = temp_dir.join("probe"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2597,13 +2597,13 @@ fn typescript_json_dispatches_cross_module_ref_union_branches() { fs::write(&main_path, TYPESCRIPT_CROSS_MODULE_MAIN).unwrap(); let output_path = temp_dir.join("closure"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![main_path, shapes_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2683,13 +2683,13 @@ fn typescript_json_guards_nullable_elements_in_array_keywords() { fs::write(&input_path, TYPESCRIPT_NULLABLE_ELEMENT_SCHEMA).unwrap(); let output_path = temp_dir.join("bag"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2792,13 +2792,13 @@ properties: .unwrap(); let output_path = temp_dir.join("pin"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: Default::default(), }) @@ -2881,13 +2881,13 @@ fn typescript_json_truncates_over_capacity_fractional_seconds() { fs::write(&input_path, TYPESCRIPT_FRACTIONAL_SECOND_SCHEMA).unwrap(); let output_path = temp_dir.join("clock"); generate_to_file(&GenerateRequest { + config: Default::default(), language: nexgen::language::Language::TypeScript, input_paths: vec![input_path], support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: None, ts_date_time_types: *repr, }) diff --git a/tests/toolchain/mod.rs b/tests/toolchain/mod.rs index 4c8e9a1e..1df0561c 100644 --- a/tests/toolchain/mod.rs +++ b/tests/toolchain/mod.rs @@ -150,13 +150,13 @@ impl Workspace { fs::create_dir_all(parent).map_err(|error| error.to_string())?; } generate_to_file(&GenerateRequest { + config: Default::default(), language: target.language(), input_paths: schemas.to_vec(), support_paths: Vec::new(), descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: false, java_package_name: (target == Target::Java).then(|| format!("conformance.{dir}")), ts_date_time_types, }) diff --git a/xtask/src/build_examples.rs b/xtask/src/build_examples.rs index 5b2f48e2..37c70513 100644 --- a/xtask/src/build_examples.rs +++ b/xtask/src/build_examples.rs @@ -6,7 +6,7 @@ use heck::ToSnakeCase; use nexgen::error::{Error, Result}; use nexgen::generator::{GenerationMode, TsDateTimeTypes}; use nexgen::language::Language; -use nexgen::nexgen_config::{NexgenConfig, current, with_nexgen_config}; +use nexgen::nexgen_config::NexgenConfig; use nexgen::{GenerateRequest, generate_to_file}; #[derive(Clone)] @@ -383,23 +383,21 @@ fn build_example(repo_root: &Path, language: Language, example_id: &str) -> Resu let language_root = advanced_language_root(repo_root, language); reset_example_output_directory(&language_root, &output_path)?; let generate_request = GenerateRequest { + config: NexgenConfig { + mode: GenerationMode::NativeApi, + system_nexus: language == Language::Python && example_id == "workflow-service", + }, language, input_paths, support_paths: Vec::new(), descriptor_paths: vec![repo_root.join("advanced/samples/descriptors/temporal_api.bin")], output_path: output_path.clone(), format: false, - generate_native_api: true, java_package_name: (language == Language::Java) .then(|| example_directory_name(language, example_id)), ts_date_time_types: Default::default(), }; - let config = NexgenConfig { - mode: GenerationMode::NativeApi, - system_nexus: language == Language::Python && example_id == "workflow-service", - ..current() - }; - with_nexgen_config(config, || generate_to_file(&generate_request))?; + generate_to_file(&generate_request)?; format_example_output(&language_root, language, &output_path)?; println!("Built {} with nexgen", output_path.display()); Ok(()) @@ -454,7 +452,6 @@ fn build_json_example_variant( descriptor_paths: Vec::new(), output_path: output_path.clone(), format: false, - generate_native_api: mode == GenerationMode::NativeApi, java_package_name: (language == Language::Java) .then(|| json_example_java_package(&dir_name, mode)), ts_date_time_types, From 7ebb6984deb61fabdec97804d4cc6c4de8440803 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Fri, 28 Aug 2026 10:46:14 -0700 Subject: [PATCH 6/7] refactor: configure generation requests --- src/main.rs | 10 ++++++++++ tests/generate_dotnet.rs | 5 ++++- tests/generate_go.rs | 5 ++++- tests/generate_python.rs | 5 ++++- xtask/src/build_examples.rs | 4 ++++ 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 17adc2f3..598d9408 100644 --- a/src/main.rs +++ b/src/main.rs @@ -235,6 +235,16 @@ fn generate_request( java_package_name: Option, ) -> GenerateRequest { GenerateRequest { + #[cfg(feature = "advanced")] + config: NexgenConfig { + mode: if args.generate_native_api { + nexgen::generator::GenerationMode::NativeApi + } else { + nexgen::generator::GenerationMode::DefinitionsOnly + }, + ..Default::default() + }, + #[cfg(not(feature = "advanced"))] config: Default::default(), language, input_paths: args.inputs, diff --git a/tests/generate_dotnet.rs b/tests/generate_dotnet.rs index ea92e5e2..633736c7 100644 --- a/tests/generate_dotnet.rs +++ b/tests/generate_dotnet.rs @@ -139,7 +139,10 @@ fn generate_dotnet_files( let temp_dir = unique_output_path("dotnet-rendered"); let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { - config: Default::default(), + config: nexgen::nexgen_config::NexgenConfig { + mode: nexgen::generator::GenerationMode::NativeApi, + ..Default::default() + }, language: nexgen::language::Language::Dotnet, input_paths: input_paths.to_vec(), support_paths: Vec::new(), diff --git a/tests/generate_go.rs b/tests/generate_go.rs index 59db1bb3..11ddc41a 100644 --- a/tests/generate_go.rs +++ b/tests/generate_go.rs @@ -214,7 +214,10 @@ fn generate_to_string_with_inputs( let temp_dir = unique_output_path("go-rendered"); let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { - config: Default::default(), + config: nexgen::nexgen_config::NexgenConfig { + mode: nexgen::generator::GenerationMode::NativeApi, + ..Default::default() + }, language, input_paths: input_paths.to_vec(), support_paths: Vec::new(), diff --git a/tests/generate_python.rs b/tests/generate_python.rs index be2b0bb5..e73e3a3a 100644 --- a/tests/generate_python.rs +++ b/tests/generate_python.rs @@ -761,7 +761,10 @@ fn generate_python_to_string(input_paths: &[PathBuf], descriptor_paths: &[PathBu let temp_dir = unique_output_path("python-rendered"); let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { - config: Default::default(), + config: nexgen::nexgen_config::NexgenConfig { + mode: nexgen::generator::GenerationMode::NativeApi, + ..Default::default() + }, language: nexgen::language::Language::Python, input_paths: input_paths.to_vec(), support_paths: Vec::new(), diff --git a/xtask/src/build_examples.rs b/xtask/src/build_examples.rs index 37c70513..32009a79 100644 --- a/xtask/src/build_examples.rs +++ b/xtask/src/build_examples.rs @@ -446,6 +446,10 @@ fn build_json_example_variant( let output_path = json_example_output_path(repo_root, language, output_id, mode); reset_example_output_directory(&root, &output_path)?; generate_to_file(&GenerateRequest { + config: NexgenConfig { + mode, + ..Default::default() + }, language, input_paths: vec![input_path.clone()], support_paths: Vec::new(), From eeef5c5419be2de342382e5ce647ba2909e4ac79 Mon Sep 17 00:00:00 2001 From: Tim Conley Date: Fri, 28 Aug 2026 10:54:32 -0700 Subject: [PATCH 7/7] test: configure generation modes explicitly --- tests/generate_typescript.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/generate_typescript.rs b/tests/generate_typescript.rs index c33a7be9..a32a40bf 100644 --- a/tests/generate_typescript.rs +++ b/tests/generate_typescript.rs @@ -615,7 +615,10 @@ fn generate_typescript_to_string(input_paths: &[PathBuf], descriptor_paths: &[Pa let temp_dir = unique_output_path("typescript-rendered"); let output_path = temp_dir.join("output"); generate_to_file(&GenerateRequest { - config: Default::default(), + config: nexgen::nexgen_config::NexgenConfig { + mode: nexgen::generator::GenerationMode::NativeApi, + ..Default::default() + }, language: nexgen::language::Language::TypeScript, input_paths: input_paths.to_vec(), support_paths: Vec::new(),