Skip to content

refactor(generator): split CliParserGenerator.cs into partial files and decompose oversized methods - #69

Merged
Mpdreamz merged 5 commits into
mainfrom
fix/large-file
Aug 19, 2026
Merged

Mpdreamz merged 5 commits into
mainfrom
fix/large-file

Conversation

@Mpdreamz

Copy link
Copy Markdown
Contributor

Summary

CliParserGenerator.cs was 11,717 lines — the largest file in the repo by a factor of 20. This PR eliminates the outlier without any behaviour change.

  • Delete ~650 lines of dead code: The legacy SourceProductionContext-based registration path (ExpandTypeRegistration and everything it reached transitively) was superseded by the DiagnosticAccumulator incremental path but never removed. Its non-Acc validator twins were an active sync hazard; they're gone.
  • Split into 14 partial class files under the existing CliParserGenerator.<Area>.cs convention (.Schema.cs and .Completion.cs were already there). CliParserGenerator.cs itself is now ~280 lines of pipeline wiring.
  • Decompose two oversized dispatch methods: EmitValidationChecks (330 → 59 lines, 14 extracted Emit*ConstraintCheck helpers) and EmitParseFromString (326 → ~30 lines, 6 extracted per-scalar-kind helpers). Both follow the shape of helpers that already existed in the file (EmitCollectionFilesystemValidation, EmitNullableNumericParseFromString, etc.).

Verification

All phases were verified bit-identical against a baseline ArghGenerated.g.cs captured before any changes (zero diff except the version hash line). Full test suite (302 tests) passes at each commit.

File layout after this PR

File Role
CliParserGenerator.cs Pipeline wiring only (~280 lines)
.Diagnostics.cs AGH0001–33 descriptors + DiagnosticAccumulator
.Models.cs All symbol-free model records and enums
.Analysis.cs AnalyzeInvocation, TryBuildAppEmitModel
.SymbolReaders.cs Attribute/type interrogation helpers
.Validation.cs ValidationConstraint hierarchy + validators
.Emit.Dispatch.cs Dispatch tree emission
.Emit.Dto.cs DTO binding emission
.Emit.Help.cs Help printer emission
.Emit.Parsing.cs Option/flag parsing emission
.Emit.Runner.cs Command runner emission
.Documentation.cs Doc-comment extraction
.Naming.cs Naming static class + escape helpers
.CommandModel.cs CommandModel record
.ParameterModel.cs ParameterModel record + factories

Test plan

  • dotnet build -c Release — 0 errors at each commit
  • dotnet test -c Release --logger:pretty — 302 tests pass at each commit
  • Generated ArghGenerated.g.cs diff vs baseline — empty at each commit
  • ./build.sh release — build + test + pack all pass (validatepackages fails on a pre-existing System.Reactive env issue unrelated to this PR)

🤖 Generated with Claude Code

Mpdreamz and others added 5 commits August 19, 2026 17:23
…nContext expansion path

The SourceProductionContext-based registration path (ExpandTypeRegistration,
ExpandMapStringDelegate, ExpandMapRootCommand, AddMethodsFromType) was superseded
when analysis moved into the incremental Select step (DiagnosticAccumulator path)
but was never deleted. Removes it along with its byte-for-byte validator twins
(ReportDuplicateCliNames, ReportBoolNegationSwitchConflicts,
ValidateExpandedParameterLayout, ValidateVariadicPositionalIsLast) and the three
FlattenAsParametersType(context) overloads. Also removes the SourceProductionContext
overloads of CommandModel.FromMethod/FromRootMethod and BuildParameterModels.

Follow-on simplification: drops SourceProductionContext? reportCtx from all
ParameterModel.From* factory signatures and simplifies ReportFilesystemPathAttributeIssues
to a single DiagnosticAccumulator? acc path, removing the nested ReportFilesystemDiag/
ReportFilesystemDiagTwo helpers. Generated output is bit-identical; all 202 tests pass.

Also enables EmitCompilerGeneratedFiles in Tests.CliHost temporarily for baseline diffing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CliParserGenerator.cs drops from 11 105 lines to 279 — the incremental
pipeline wiring only. Content moves wholesale into focused partial files
under src/Nullean.Argh.Generator/:

  .Diagnostics.cs    — AGH0001-33 descriptors, DiagnosticAccumulator
  .Models.cs         — RegistryNode, AppEmitModel, AI* records, enums
  .Analysis.cs       — AnalyzeInvocation, TryBuildAppEmitModel, expansion helpers
  .SymbolReaders.cs  — attribute/type interrogation, options-model builders
  .Validation.cs     — ReportBool*, ReportDuplicate*, ReadValidationConstraints
  .Emit.Dispatch.cs  — EmitEmpty, EmitApp, EmitHierarchical, dispatch/route emitters
  .Emit.Dto.cs       — DtoBindingTarget, EmitDtoBindingMethods, EmitDtoTypeExtensions
  .Emit.Parsing.cs   — EmitOptionsTryParse, EmitValidationChecks, EmitCommandRunner
  .Emit.Runner.cs    — EmitCommandRunner through EmitLambdaInvocation, flag helpers
  .Emit.Help.cs      — EmitCommandHelpPrinter, EmitHelpOptionRows*, UsageSynopsis
  .Documentation.cs  — TryExtract* doc helpers, TransformRemarksInnerXml
  .CommandModel.cs   — CommandModel record and ParseOptionsFlagDocumentation
  .ParameterModel.cs — ParameterModel record and factories
  .Naming.cs         — Escape*, OptionsStaticFieldName*, Naming static class

Pure mechanical split — generated output is bit-identical (verified by
diffing ArghGenerated.g.cs against the Phase 1 baseline). All 294 tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t-check helpers

The 330-line flat switch over ValidationConstraint subtypes becomes a
14-line dispatch table. Each arm is extracted into an Emit<X>ConstraintCheck
private static method following the EmitCollectionFilesystemValidation signature
pattern (sb, [constraint,] p, cliName, varName, failureExit, flagHelpStdErr,
runHint). The outer loop removes the isNullable/isNullableValueType locals;
each helper derives them from p instead.

Generated output is bit-identical. All 302 tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nd helpers

The 326-line method becomes a flat if-chain dispatch of 8 guards. Each
scalar-kind branch is extracted to a private static helper matching the
existing EmitNullableNumericParseFromString / EmitNullableTemporalParseFromString
signature convention (sb, p, rawExpr, targetVar, ind, outVarKeyword, failureExit,
helpMethodName, flagHelpStdErrMethodName, parseFailureRunHint):

  EmitEnumParseFromString          — enum switch-case block (~27 lines)
  EmitFileInfoParseFromString       — optional/required FileInfo (~42 lines)
  EmitDirectoryInfoParseFromString  — optional/required DirectoryInfo (~42 lines)
  EmitUriParseFromString            — optional/required Uri (~38 lines)
  EmitCustomParserFromString        — IArgumentParser<T> adapter (~15 lines)
  EmitPrimitiveScalarParseFromString — non-nullable scalar switch (~136 lines)

Generated output is bit-identical. All 302 tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Temporary property added for baseline diff capture during Phase 2 split
is no longer needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Mpdreamz Mpdreamz added the enhancement New feature or request label Aug 19, 2026
@Mpdreamz
Mpdreamz merged commit 67c29a5 into main Aug 19, 2026
5 checks passed
@Mpdreamz
Mpdreamz deleted the fix/large-file branch August 19, 2026 16:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant