Skip to content

Commit

Permalink
NextJS Codegen (#1346)
Browse files Browse the repository at this point in the history
This adds native integration for next.js code generation.
  • Loading branch information
seawatts authored Feb 15, 2025
1 parent fca8b91 commit 0b792de
Show file tree
Hide file tree
Showing 178 changed files with 48,769 additions and 4,492 deletions.
143 changes: 143 additions & 0 deletions .cursor/rules/diataxis-docs.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
description: Write docs using Diátaxis: tutorials for learning, how-to guides for tasks, reference for facts, explanation for understanding
globs: *.mdx
---
# Diátaxis Documentation Framework

## Core Concept

The fundamental idea behind Diátaxis is that documentation needs fall into four distinct categories. Each category serves a different purpose and requires a different approach to writing. The framework is not just a list of types, but a systematic way to think about documentation.

## The Four Documentation Types

### 1. Tutorials
- **Definition**: A tutorial is a lesson that guides a learner through a practical experience
- **Core Purpose**: Skills acquisition through doing
- **Key Attributes**:
- Always practical - the user must do something
- Designed around a specific learning experience
- Instructor takes responsibility for learner's success
- Learning happens through action, not through being taught
- **Special Challenge**: The instructor must be "present" through written instruction alone
- **What to Avoid**:
- Don't explain concepts in depth - link to explanations instead
- Don't assume prior knowledge
- Don't focus on options or alternatives
- Don't include reference material
- Don't show all possible ways to do something
- **Example**: Like a driving lesson - the goal is developing skills and confidence, not reaching a destination

### 2. How-to Guides
- **Definition**: Step-by-step guidance to achieve a specific goal
- **Core Purpose**: Practical problem solving
- **Key Attributes**:
- Addresses a specific real-world task or problem
- Written for users who know what they need to do
- Focused on completing work rather than learning
- Assumes necessary competence
- **What to Avoid**:
- Don't teach basic concepts
- Don't explain why things work
- Don't cover every possible variation
- Don't include detailed technical specifications
- Don't focus on learning objectives
- **Examples**:
- "How to store cellulose nitrate film"
- "How to configure frame profiling"
- "Troubleshooting deployment problems"

### 3. Reference
- **Definition**: Technical descriptions of the machinery
- **Core Purpose**: Information
- **Key Attributes**:
- Contains pure technical facts
- Must be accurate and complete
- Structure mirrors the code/system architecture
- Neutral and objective - like a map
- Serves users who know what they're looking for
- **What to Avoid**:
- Don't include tutorials or guides
- Don't explain concepts
- Don't include opinions or recommendations
- Don't provide step-by-step instructions
- Don't teach or guide the reader
- Don't include best practices
- **Distinction**: Like a map that could be used by both a navigator plotting a course or a magistrate in a legal case

### 4. Explanation
- **Definition**: Discussion that clarifies and illuminates a particular topic
- **Core Purpose**: Understanding
- **Key Attributes**:
- Provides background and context
- Can take different approaches to a topic
- May include opinions and alternative views
- Connects different concepts
- Answers "why" questions
- **What to Avoid**:
- Don't include practical steps
- Don't mix with tutorials
- Don't focus on specific tasks
- Don't include detailed technical specifications
- Don't try to be completely objective
- Don't include best practices
- **Important Note**: Should be separated from tutorials to avoid overloading learners

## The Diátaxis Map

The documentation types are arranged along two axes:

| Axis | Practical | Theoretical |
|-----------|-------------------------|-------------------------|
| Learning | Tutorials | Explanation |
| Work | How-to Guides | Reference |

This creates natural tensions and relationships:
- Tutorials ↔ How-to guides (practical knowledge)
- Reference ↔ Explanation (theoretical knowledge)
- Tutorials ↔ Explanation (learning-oriented)
- How-to guides ↔ Reference (work-oriented)

## The Diátaxis Compass

Use this tool to identify documentation types:

| If content... | ...and serves the user's... | Then it belongs in... |
|-----------------|---------------------------|---------------------|
| Guides action | Learning | Tutorials |
| Guides action | Work | How-to guides |
| Explains theory | Work | Reference |
| Explains theory | Learning | Explanation |

## Pntionally simple:

1. Look at your current documentation
2. Ask: "How could this be better?"
3. Choose ONE small improvement
4. Make that improvement
5. Repeat

## Key Principles

1. **Separation of Concerns**
- Keep the four types distinct
- Don't mix tutorials with explanation
- Link between types instead of combining them

2. **Minimal Approach**
- Start with small improvements
- You don't need to read or understand everything
- Each improvement suggests the next

3. **Pragmatic Usage**
- Use what works for you
- No need to commit to the entire framework
- Even small improvements are valuable

## Important Notes

- The framework is a practical tool, not a theoretical construct
- You don't need to understand all of Diátaxis to start using it
- The documentation will naturally evolve as you make improvements
- Let real documentation problems guide your use of the framework

[Source: [Diátaxis Documentation Framework](mdc:https:/diataxis.fr/start-here)]
2 changes: 1 addition & 1 deletion .github/workflows/build-typescript-release.reusable.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
# NOTE: we can't use mise here because it doesn't support Windows
- uses: pnpm/action-setup@v4
with:
version: 9.0.6
version: 9.12.0
run_install: false
- uses: actions/setup-node@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/primary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9.0.6
version: 9.12.0
run_install: false
- uses: actions/setup-node@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
- name: setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.0.6
version: 9.12.0
package_json_file: engine/language_client_typescript/package.json
run_install: false

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,4 @@ web_modules/
yarn-debug.log*
yarn-error.log*
yarn.lock
artifacts
6 changes: 5 additions & 1 deletion engine/baml-lib/baml-types/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ pub enum GeneratorOutputType {
#[strum(serialize = "typescript")]
Typescript,

#[strum(serialize = "typescript/react")]
TypescriptReact,

#[strum(serialize = "ruby/sorbet")]
RubySorbet,
}
Expand All @@ -38,6 +41,7 @@ impl GeneratorOutputType {
// DO NOT CHANGE THIS DEFAULT EVER OR YOU WILL BREAK EXISTING USERS
Self::PythonPydantic => GeneratorDefaultClientMode::Async,
Self::Typescript => GeneratorDefaultClientMode::Async,
Self::TypescriptReact => GeneratorDefaultClientMode::Async,
Self::RubySorbet => GeneratorDefaultClientMode::Sync,
}
}
Expand All @@ -48,6 +52,7 @@ impl GeneratorOutputType {
Self::OpenApi => GeneratorDefaultClientMode::Sync,
Self::PythonPydantic => GeneratorDefaultClientMode::Sync,
Self::Typescript => GeneratorDefaultClientMode::Async,
Self::TypescriptReact => GeneratorDefaultClientMode::Async,
Self::RubySorbet => GeneratorDefaultClientMode::Sync,
}
}
Expand All @@ -56,7 +61,6 @@ impl GeneratorOutputType {
impl clap::ValueEnum for GeneratorOutputType {
fn value_variants<'a>() -> &'a [Self] {
use strum::VariantArray;

Self::VARIANTS
}

Expand Down
4 changes: 4 additions & 0 deletions engine/baml-runtime/src/cli/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ impl GenerateArgs {
// this has no meaning
GeneratorDefaultClientMode::Sync
}
internal_baml_core::configuration::GeneratorOutputType::TypescriptReact => {
GeneratorDefaultClientMode::Async
}
};
// Normally `baml_client` is added via the generator, but since we're not running the generator, we need to add it manually.
let output_dir_relative_to_baml_src = PathBuf::from("..");
Expand All @@ -77,6 +80,7 @@ impl GenerateArgs {
default_client_mode,
// TODO: this should be set if user is asking for openapi
vec![],
None,
)
.context("Failed while resolving .baml paths in baml_src/")?,
)
Expand Down
4 changes: 3 additions & 1 deletion engine/baml-runtime/src/cli/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ impl InitArgs {
Some(s) => format!("{} clients via OpenAPI", s),
None => "REST clients".to_string(),
},
GeneratorOutputType::TypescriptReact => "TypeScript React clients".to_string(),
}
);
log::info!(
Expand All @@ -100,6 +101,7 @@ impl InitArgs {
GeneratorOutputType::Typescript => "typescript",
GeneratorOutputType::RubySorbet => "ruby",
GeneratorOutputType::OpenApi => "openapi",
GeneratorOutputType::TypescriptReact => "typescript-react",
}
);

Expand All @@ -114,7 +116,7 @@ fn generate_main_baml_content(
) -> String {
let default_client_mode = match output_type {
GeneratorOutputType::OpenApi | GeneratorOutputType::RubySorbet => "".to_string(),
GeneratorOutputType::PythonPydantic | GeneratorOutputType::Typescript => format!(
GeneratorOutputType::PythonPydantic | GeneratorOutputType::Typescript | GeneratorOutputType::TypescriptReact => format!(
r#"
// Valid values: "sync", "async"
// This controls what `b.FunctionName()` will be (sync or async).
Expand Down
5 changes: 3 additions & 2 deletions engine/baml-runtime/src/cli/serve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use axum_extra::{
headers::{self, authorization::Basic, Authorization, Header},
TypedHeader,
};
use baml_types::{BamlValue, GeneratorDefaultClientMode};
use baml_types::{BamlValue, GeneratorDefaultClientMode, GeneratorOutputType};
use core::pin::Pin;
use futures::Stream;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -67,7 +67,7 @@ impl ServeArgs {
if !self.preview {
log::warn!(
r#"BAML-over-HTTP API is a preview feature.
Please run with --preview, like so:
{} serve --preview
Expand Down Expand Up @@ -623,6 +623,7 @@ Tip: test that the server is up using `curl http://localhost:{}/_debug/ping`
true,
GeneratorDefaultClientMode::Sync,
Vec::new(),
None,
)
.map_err(|_| BamlError::InternalError {
message: "Failed to make placeholder generator".to_string(),
Expand Down
1 change: 1 addition & 0 deletions engine/baml-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ impl BamlRuntime {
no_version_check,
generator.default_client_mode(),
generator.on_generate.clone(),
Some(generator.output_type),
)?,
))
})
Expand Down
1 change: 1 addition & 0 deletions engine/baml-schema-wasm/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0",
"description": "The WASM package for baml-fmt",
"main": "./dist/src/baml_schema_build.js",
"packageManager": "[email protected]",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
Expand Down
6 changes: 6 additions & 0 deletions engine/language_client_codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub struct GeneratorArgs {
// Default call mode for functions
default_client_mode: GeneratorDefaultClientMode,
on_generate: Vec<String>,

// The type of client to generate
client_type: Option<GeneratorOutputType>,
}

fn relative_path_to_baml_src(path: &Path, baml_src: &Path) -> Result<PathBuf> {
Expand All @@ -54,6 +57,7 @@ impl GeneratorArgs {
no_version_check: bool,
default_client_mode: GeneratorDefaultClientMode,
on_generate: Vec<String>,
client_type: Option<GeneratorOutputType>,
) -> Result<Self> {
let baml_src = baml_src_dir.into();
let input_file_map: BTreeMap<PathBuf, String> = input_files
Expand All @@ -70,6 +74,7 @@ impl GeneratorArgs {
no_version_check,
default_client_mode,
on_generate,
client_type,
})
}

Expand Down Expand Up @@ -185,6 +190,7 @@ impl GenerateClient for GeneratorOutputType {
GeneratorOutputType::PythonPydantic => python::generate(ir, gen),
GeneratorOutputType::RubySorbet => ruby::generate(ir, gen),
GeneratorOutputType::Typescript => typescript::generate(ir, gen),
GeneratorOutputType::TypescriptReact => typescript::generate(ir, gen),
}?;

#[cfg(not(target_arch = "wasm32"))]
Expand Down
Loading

0 comments on commit 0b792de

Please sign in to comment.