Skip to content

Port Python SDK route generation from nextlove to Metalsmith#581

Merged
razor-x merged 9 commits into
mainfrom
claude/python-sdk-codegen-migration-imhyb8
Jul 21, 2026
Merged

Port Python SDK route generation from nextlove to Metalsmith#581
razor-x merged 9 commits into
mainfrom
claude/python-sdk-codegen-migration-imhyb8

Conversation

@razor-x

@razor-x razor-x commented Jul 21, 2026

Copy link
Copy Markdown
Member

Summary

This PR replaces the direct dependency on @seamapi/nextlove-sdk-generator with a Metalsmith-based code generation pipeline for Python SDK route files. The generation logic has been ported and restructured to align with the existing javascript-http codegen plugin architecture.

Key Changes

  • Replaced generation script: Removed generate-routes.js which called @seamapi/nextlove-sdk-generator directly. Replaced with codegen/smith.ts that uses Metalsmith as the build orchestrator.

  • Ported core generation logic: Migrated route generation from @seamapi/nextlove-sdk-generator to codegen/lib/routes.ts, which:

    • Iterates through blueprint routes and endpoints
    • Builds class models with methods and parameters
    • Generates route namespace hierarchy
    • Filters endpoints based on OpenAPI extensions and endpoint rules
  • Extracted OpenAPI utilities: Created modular OpenAPI processing functions:

    • get-filtered-routes.ts: Filters documented routes
    • get-parameter-and-response-schema.ts: Extracts request/response schemas
    • deep-flatten-one-of-and-all-of-schema.ts: Flattens complex schema compositions
    • flatten-obj-schema.ts: Normalizes object schemas
    • map-parent-to-children-resource.ts: Maps resource hierarchies
    • types.ts: Minimal OpenAPI type definitions
  • Introduced data models: Created class-model.ts to represent route classes, methods, and parameters independently of serialization.

  • Built layout context builders: Created context builders for Handlebars templates:

    • layouts/route.ts: Builds context for individual route class files
    • layouts/models.ts: Builds context for the models file
    • layouts/routes-index.ts: Builds context for the routes index file
  • Added Handlebars templates: Created template files for code generation:

    • route.hbs: Route class template
    • models.hbs: Models file template
    • routes-index.hbs: Routes index template
    • partials/route-method.hbs: Route method template
    • partials/abstract-route-class.hbs: Abstract class template
    • partials/model-dataclass.hbs: Dataclass template
    • partials/abstract-routes.hbs: Abstract routes template
  • Added utility modules:

    • map-python-type.ts: Maps OpenAPI types to Python types
    • custom-resource-name-conversions.ts: Handles special resource name mappings
    • endpoint-rules.ts: Defines endpoint filtering rules
    • handlebars-helpers.ts: Custom Handlebars helpers
  • Updated build configuration: Modified package.json to use tsx codegen/smith.ts instead of node generate-routes.js, and added dependencies on @metalsmith/layouts, @seamapi/blueprint, and @seamapi/smith.

  • Added configuration files: Created .prettierignore to exclude Handlebars templates from formatting.

Notable Implementation Details

  • The generation logic preserves exact output compatibility with the previous nextlove generator through careful porting, including quirks like the operator precedence bug in parameter sorting.
  • Multiple TODO comments mark locations where the code could migrate to use @seamapi/blueprint data once generated output changes are allowed.
  • The raw OpenAPI spec is consulted alongside the blueprint where they normalize data differently (e.g., integer vs. number types, union flattening).
  • The Metalsmith pipeline follows the same plugin architecture as the existing javascript-http codegen, making it maintainable and extensible.

https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s

claude added 3 commits July 20, 2026 23:11
Replace the @seamapi/nextlove-sdk-generator based route generation with
the metalsmith + handlebars + @seamapi/blueprint architecture used by
seamapi/javascript-http. The generated output under seam/routes/ is
byte-identical.

The blueprint drives the route, endpoint, and namespace structure. The
raw OpenAPI spec is still consulted wherever the nextlove generator
derived output from data the blueprint normalizes differently (integer
vs number types, resource schema set and order, parameter flattening);
each of those spots carries a TODO to migrate to the blueprint once
output is allowed to change.

- Add codegen/ with the Metalsmith pipeline, plugin, context builders,
  and Handlebars layouts and partials
- Remove generate-routes.js
- Pin @seamapi/types at 1.910.0 for output parity and use
  @seamapi/blueprint 0.55.0
- Bump del to ^8 to satisfy the @seamapi/smith peer range
- Ignore *.hbs and CODEGEN.md in a new .prettierignore since the
  glimmer parser mangles Python-flavored templates
- Re-include codegen/lib/ in .gitignore (the Python template ignores
  lib/) and ignore the generated CODEGEN.md seed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
Every comment describing behavior to address later now leads with TODO
so the deferred work is greppable: the parameter comparator precedence
quirk and the unwired deeply nested namespaces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
- Trim devDependencies to direct imports only: metalsmith,
  @metalsmith/layouts, jstransformer-handlebars, del, tsx, typescript,
  eslint, jiti, and mkdirp are @seamapi/smith peers that npm installs
  automatically, matching how seamapi/docs consumes smith
- Add tsconfig.json extending @seamapi/smith/tsconfig.base.json with a
  typecheck script and codegen/index.ts stub, mirroring seamapi/docs
  and seamapi/javascript-http
- Widen response type properties for exactOptionalPropertyTypes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
Comment thread .gitignore
Comment thread .gitignore Outdated
claude added 4 commits July 21, 2026 15:40
- Add lint, postlint, and preformat scripts using
  @seamapi/smith/eslint-config via a one-line eslint.config.ts,
  matching seamapi/docs
- Replace relative parent imports with lib/* path imports (tsconfig
  baseUrl and paths), satisfying import/no-relative-parent-imports and
  matching the smith import sort convention
- Mark every file and function that exists only for output parity with
  a TEMPORARY banner and a TODO to delete it once generated output is
  allowed to change, so temp code is skippable in review

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
Match how seamapi/docs consumes @seamapi/smith: extend the base
tsconfig with no compiler option overrides and use plain relative
imports in codegen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
CODEGEN.md moves to the top of the file. The codegen/lib/ negation
moves next to the lib/ pattern it negates, since a gitignore negation
only takes effect after the pattern it overrides.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
The CODEGEN.md gitignore rule matches any depth, so the Metalsmith
source seed codegen/content/CODEGEN.md was never committed and CI
failed to generate with ENOENT on the missing directory. Force-add the
seed exactly as seamapi/javascript-http does; the ignore rule still
covers the generated CODEGEN.md at the repository root.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
Comment thread .gitignore Outdated
eggs/
.eggs/
lib/
# Negations must follow the pattern they negate, so this cannot move to the top

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Negations must follow the pattern they negate, so this cannot move to the top

claude and others added 2 commits July 21, 2026 16:05
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019iX1vWXfXKzUyRJTVm8D7s
Add exception for codegen/lib in .gitignore
@razor-x
razor-x marked this pull request as ready for review July 21, 2026 16:08
@razor-x
razor-x requested a review from a team as a code owner July 21, 2026 16:08
@razor-x
razor-x merged commit b768d1d into main Jul 21, 2026
18 checks passed
@razor-x
razor-x deleted the claude/python-sdk-codegen-migration-imhyb8 branch July 21, 2026 16:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants