Skip to main content

Monorepo Setup

fhir-dsl is a pnpm workspace monorepo. This page covers the project structure, build system, and how to work with it locally.

Project Structure

fhir-dsl/
├── packages/
│ ├── core/ # @fhir-dsl/core - Query builder DSL
│ ├── runtime/ # @fhir-dsl/runtime - HTTP executor
│ ├── types/ # @fhir-dsl/types - Base type definitions
│ ├── fhirpath/ # @fhir-dsl/fhirpath - Typed FHIRPath builder + evaluator
│ ├── terminology/ # @fhir-dsl/terminology - ValueSet/CodeSystem expansion + validate-code
│ ├── smart/ # @fhir-dsl/smart - SMART-on-FHIR auth (PKCE, backend-services)
│ ├── mcp/ # @fhir-dsl/mcp - Model Context Protocol server
│ ├── generator/ # @fhir-dsl/generator - Code generation engine
│ ├── cli/ # @fhir-dsl/cli - Command-line interface
│ ├── utils/ # @fhir-dsl/utils - Shared error/Result toolkit + helpers
│ └── example/ # Example project with generated types
├── package.json # Workspace root
├── pnpm-workspace.yaml # Workspace config
├── tsconfig.base.json # Shared TypeScript config
├── vitest.config.ts # Test config
└── biome.json # Linter config

Prerequisites

  • Node.js >= 20
  • pnpm >= 10

Getting Started

# Clone the repo
git clone https://github.com/awbx/fhir-dsl.git
cd fhir-dsl

# Install dependencies
pnpm install

# Build all packages
pnpm build

Workspace Scripts

Run from the repository root:

CommandDescription
pnpm buildBuild all packages with tsup
pnpm typecheckType-check all packages
pnpm testRun all tests with Vitest
pnpm lintLint with Biome
pnpm lint:fixAuto-fix lint issues
pnpm formatFormat with Biome
pnpm devRun dev mode across packages
pnpm version:bumpBump version across all packages

Build System

Each package uses tsup for bundling:

  • Generates both ESM and CommonJS outputs
  • Produces .d.ts declaration files
  • Fast incremental builds

Packages declare their entry points in package.json:

{
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
}
}
}

Inter-Package Dependencies

Packages reference each other using workspace:*:

{
"dependencies": {
"@fhir-dsl/types": "workspace:*"
}
}

pnpm resolves these to the local packages during development and replaces them with actual version numbers at publish time.

TypeScript Configuration

All packages extend a shared tsconfig.base.json:

// packages/core/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": ["src"]
}

Testing

Tests use Vitest with a root-level configuration:

# Run all tests
pnpm test

# Run tests in watch mode
pnpm vitest

# Run tests for a specific package
pnpm vitest packages/core

Test files follow the *.test.ts naming convention and are colocated with source files or in __tests__ directories.

Linting

Biome handles both linting and formatting:

# Check for issues
pnpm lint

# Auto-fix issues
pnpm lint:fix

# Format only
pnpm format

Version Management

All packages share the same version number. Use the bump script to update:

pnpm version:bump

This updates the version in all package.json files across the monorepo.

Adding a New Package

  1. Create a new directory under packages/:
mkdir packages/my-package
  1. Add a package.json:
{
"name": "@fhir-dsl/my-package",
"version": "0.0.0",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts"
}

The version field gets rewritten to match the rest of the monorepo the next time you run pnpm version:bump, so any placeholder works here.

  1. Add a tsconfig.json extending the base config.

  2. Add a tsup.config.ts for building.

  3. Run pnpm install to link the package.