ADR-0010: Monorepo Package Structure
ADR-0010: Monorepo Package Structure
Status
Accepted
Context
python2ts started as a single package combining the transpiler and runtime. As the project grew, several concerns emerged:
- Bundle size: Users who only need the runtime (pythonlib) were forced to include the entire transpiler with its parser dependencies
- Versioning: The transpiler and runtime have different release cycles - runtime is more stable while the transpiler evolves rapidly
- Use cases: Some users want pythonlib standalone for Python-style utilities in TypeScript, without any transpilation
- Dependencies: The transpiler needs
@lezer/pythonfor parsing, but the runtime has zero dependencies
Options considered:
-
Single package: Keep everything in one package
- Pro: Simpler publishing, single version
- Con: Bloated bundles, coupled releases
-
Separate repositories: Split into independent repos
- Pro: Complete independence
- Con: Coordination overhead, harder to test together
-
Monorepo with workspaces: Single repo, multiple packages
- Pro: Unified development, atomic changes, shared tooling
- Con: More complex setup, workspace protocol in dependencies
Decision
We adopt a pnpm monorepo structure with two independent packages:
python2ts/├── packages/│ ├── python2ts/ # Transpiler (depends on pythonlib)│ └── pythonlib/ # Runtime (zero dependencies)├── tests/ # Shared test suite├── docs/ # Documentation└── package.json # Workspace rootPackage: python2ts
The transpiler package:
{ "name": "python2ts", "dependencies": { "@lezer/python": "^1.1.0", "pythonlib": "workspace:*" }}- Purpose: Parse Python, transform AST, generate TypeScript
- Entry point:
python2ts(main export + CLI) - Dependencies: Lezer parser, pythonlib runtime
- Users: Developers transpiling Python to TypeScript
Package: pythonlib
The runtime library:
{ "name": "pythonlib", "dependencies": {}}- Purpose: Python standard library implementations in TypeScript
- Entry points: Main export + subpath exports (see ADR-0009)
- Dependencies: None (zero-dependency)
- Users: Anyone wanting Python-style utilities in TypeScript
Workspace Configuration
Root package.json:
{ "name": "python2ts-monorepo", "private": true, "packageManager": "pnpm@9.15.4", "scripts": { "build": "pnpm -r build", "test": "vitest --run", "lint": "eslint packages/*/src tests" }}pnpm-workspace.yaml:
packages: - "packages/*"Dependency Flow
┌─────────────────────┐│ python2ts ││ (transpiler) │├─────────────────────┤│ @lezer/python ││ pythonlib ──────────┼──────┐└─────────────────────┘ │ ▼ ┌─────────────────────┐ │ pythonlib │ │ (runtime) │ ├─────────────────────┤ │ (zero dependencies) │ └─────────────────────┘Shared Test Suite
Tests live at the monorepo root to:
- Test integration between packages
- Verify generated code works with runtime
- Share test utilities and fixtures
tests/├── e2e/ # End-to-end transpilation tests├── runtime.test.ts # Runtime unit tests├── transformer.test.ts├── parser.test.ts└── generator.test.tsConsequences
Positive
- Independent installation:
npm install pythonlibworks standalone - Smaller bundles: pythonlib has zero dependencies, tree-shakeable
- Flexible versioning: Packages can be versioned independently
- Atomic changes: Cross-package changes are single commits
- Shared tooling: One ESLint, Prettier, TypeScript, Vitest config
- Unified CI: Single workflow tests everything together
Negative
- Workspace protocol:
workspace:*requires pnpm or special handling for npm/yarn - Publishing complexity: Need to publish multiple packages
- Version coordination: Major changes may need coordinated releases
Publishing Strategy
- pythonlib: Publish first as it has no internal dependencies
- python2ts: Publish second, referencing published pythonlib version
For npm compatibility, workspace:* is replaced with actual version during publish:
pnpm publish --filter pythonlibpnpm publish --filter python2tsInstallation Scenarios
# Full transpiler (includes pythonlib)npm install python2ts
# Runtime only (zero dependencies)npm install pythonlib
# Specific module onlynpm install pythonlib # then import from "pythonlib/itertools"Directory Structure
python2ts/├── packages/│ ├── python2ts/│ │ ├── src/│ │ │ ├── parser/ # Lezer-based Python parser│ │ │ ├── transformer/ # AST transformation│ │ │ ├── generator/ # TypeScript code generation│ │ │ └── cli/ # Command-line interface│ │ ├── package.json│ │ └── tsup.config.ts│ ││ └── pythonlib/│ ├── src/│ │ ├── index.ts # Main export (builtins)│ │ ├── itertools.ts # pythonlib/itertools│ │ ├── functools.ts # pythonlib/functools│ │ ├── collections.ts│ │ ├── math.ts│ │ ├── random.ts│ │ ├── datetime.ts│ │ ├── json.ts│ │ ├── re.ts│ │ ├── os.ts│ │ └── string.ts│ ├── package.json│ └── tsup.config.ts│├── tests/ # Shared test suite├── docs/ # Documentation & ADRs├── package.json # Workspace root├── pnpm-workspace.yaml├── tsconfig.json # Shared TS config├── eslint.config.js # Shared lint config└── vitest.config.ts # Test configuration