Skip to content

TypeSpec implementation#5

Draft
kyleamazza wants to merge 20 commits intomainfrom
new-implementation
Draft

TypeSpec implementation#5
kyleamazza wants to merge 20 commits intomainfrom
new-implementation

Conversation

@kyleamazza
Copy link
Collaborator

@kyleamazza kyleamazza commented Mar 14, 2026

TODO: still needs massive cleanup 🤖, but it works at least on a small multi-file setup for happy-path. Will update the description more thoroughly.

TL;DR: it does the thing. (loc mapping across different files from a single entrypoint, handles multi-file via offsets, tracks violations)

Clanker summary:

Complete rewrite of the @basketry/typespec parser — replaces the incomplete alpha implementation with a fully functional TypeSpec-to-Basketry IR parser with HTTP
protocol support.

Core Parser

  • Compile TypeSpec files via @typespec/compiler, extract HTTP services, and map the full type graph to Basketry IR
  • HTTP protocol info: verbs, paths, path/query/header/body parameters, status codes
  • Multi-file support with correct source location tracking across .tsp files
  • @extension("x-*", value) decorator extraction via @typespec/openapi, mapped to method/type meta (enables existing rules like require-auth-module)
  • Doc comment mapping (@doc / /** */) to IR description fields on all node types
  • Precise source locations narrowed to name identifiers rather than full node spans

Type System

  • Scalar type mapping: TypeSpec built-in scalars (string, int32, float64, utcDateTime, etc.) to Basketry IR primitives with validation rules (e.g., integer
    format, int32/int64 range)
  • Model/enum/union support: inheritance, named unions, nullable and array properties
  • Anonymous union detection with violations warning about data loss

Error Handling

  • TypeSpec compiler diagnostics surfaced as Basketry violations
  • Early return on compiler errors to prevent generating invalid IR
  • Violation factory functions for consistent diagnostic formatting

Testing

  • Unit tests for parser, location encoding, type mapping, and violations
  • Snapshot tests with two multi-file TypeSpec fixtures (example + petstore)
  • Migrated from Jest to Vitest for native ESM support

Packaging

  • ESM output for @typespec/compiler compatibility
  • CJS entry point (index.cjs) with conditional exports so Basketry's NodeEngine can require() the parser
  • JSON-RPC entry point for plugin communication

kyleamazza and others added 20 commits March 12, 2026 22:03
Initial project structure with TypeScript, ESLint, Prettier, Jest, and
stub parser/RPC entry points.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- location.ts: source index building and loc encoding helpers
- violations.ts: violation factory functions for parser diagnostics
- type-mapping.ts: TypeSpec scalar to Basketry IR primitive mapping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements the TypeSpecParser class that compiles TypeSpec files, extracts
HTTP services, maps the type graph to Basketry IR, and produces HTTP
protocol info. Updates jest config for ESM compatibility with @typespec
packages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a multi-file TypeSpec fixture (main.tsp, models.tsp, operations.tsp)
exercising inheritance, enums, named unions, nullable/array properties, and
all HTTP verbs. Fixes encodeLoc to walk the AST parent chain to find the
source file, enabling correct sourceIndex values in multi-file scenarios.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rors

- Add unsupportedFeature violation when anonymous unions drop variants
  beyond the first one, warning about data loss
- Early return from parse() when compiler has error-severity diagnostics
  to prevent generating garbage IR from invalid input

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ScalarShowcase model to example fixture exercising coerced scalars
- Add Scalars interface endpoint to expose ScalarShowcase in operations
- Fix ValidationRule id field to be plain string (not wrapped object)
- Remove float16 (not a TypeSpec built-in scalar type)
- Update type-mapping.test.ts to match corrected rule structure
- Add scalar mapping describe block in parser.test.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Basketry resolves sourcePaths relative to its project root via
path.resolve(cwd, sourcePaths[0]). When .tsp files lived in a
subdirectory, the relative paths caused ENOENT errors. Absolute
paths let Basketry handle relativization on its end.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire getDoc() from @typespec/compiler into all IR node types: Interface,
Method, Parameter, Type, Property, Enum, EnumMember, and Union.
Multi-paragraph doc comments are split by double newlines into separate
StringLiteral array entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace Jest with Vitest for native ESM support — eliminates the need for
--experimental-vm-modules and ts-jest workarounds. Add CJS entry point
(index.cjs) with conditional exports so Basketry's NodeEngine can load
the parser via require() despite being an ESM package.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use TypeSpec AST node.id for precise name locations instead of
full node spans that include doc comments and body declarations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ReturnValue was missing a loc, causing the response-envelope rule
to default to main.tsp:1:1. Now points to the response model definition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Read TypeSpec @extension("x-*", value) decorators via @typespec/openapi
and map them to MetaValue[] on methods, parameters, types, properties,
enums, and unions. Strips the x- prefix to match OpenAPI parser behavior,
enabling existing Basketry rules like require-auth-module to work unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ions

Use nameLoc (AST node.id span) for the node-level loc field, falling
back to the full span only when no id is available. This ensures rules
like require-auth-module and response-envelope highlight the specific
name rather than the entire block including doc comments and body.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

1 participant