Skip to main content

dingo-developer

Generates and reviews Dingo meta-language code with Go boundary handling. Use when the user mentions Dingo, .dingo files, or Dingo-to-Go transpilation.

Informations de source

Dépôt
MadAppGang/magus
Dernière activité de la source
26 septembre 2026 à 14:36
Langue détectée de SKILL.md
anglais
Étoiles
11
Forks
4

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
2 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
dingo-developer
description
Generates and reviews Dingo meta-language code with Go boundary handling. Use when the user mentions Dingo, .dingo files, or Dingo-to-Go transpilation.
# Dingo Developer ## Overview Dingo is a meta-language for Go that transpiles `.dingo` files to idiomatic `.go` files. It provides modern language features — Result/Option types, sum types (enums), pattern matching, error propagation, safe navigation, null coalescing, lambdas, generics, and tuples — while maintaining 100% Go ecosystem compatibility. **Repository:** https://github.com/MadAppGang/dingo **Key philosophy:** Dingo is syntax sugar over Go, not a new type system. The transpiled Go code is clean and idiomatic. All Go syntax remains valid in `.dingo` files. **When to use Dingo:** - You want concise error handling with the `?` operator - You need sum types (enums) and pattern matching - You prefer functional patterns with lambdas - You want `Option[T]` and `Result[T, E]` types - You need safe navigation (`?.`) and null coalescing (`??`) **CLI commands:** ```bash dingo build ./cmd/app # Transpile + compile; explicit packages only, not ./... dingo run main.dingo # Transpile + run directly dingo go ./... # Generate .go files only, into build/ (no go.mod there) ``` Build directory, checking a project, CI, editor setup and transpile errors: `references/build-and-tooling.md` (relative to this file). --- ## Error Handling ### The `?` Operator — Three Variants **Decision tree — pick the first that applies:** 1. Just propagate the error unchanged → plain `?` 2. Add lightweight string context → `? "message"` 3. Build a custom error type or capture variables → `? |e| expr` 4. Need side effects or multi-statement logic → `guard` (see below) 5. Absence is expected, not an error → use `Option[T]` + `guard` --- #### Variant 1: Plain Propagation ```go // BEFORE (Go) user, err := getUser(id) if err != nil { return nil, err } ``` ```dingo // AFTER (Dingo) user := getUser(id)? ``` --- #### Variant 2: String Context Generates `fmt.Errorf("message: %w", err)`. ```go // BEFORE (Go) config, err := loadConfig(path) if err != nil { return nil, fmt.Errorf("load config: %w", err) } ``` ```dingo // AFTER (Dingo) config := loadConfig(path) ? "load config" ``` --- #### Variant 3: Lambda Transform Captures local variables and builds custom error types. Both Rust-style (`|e|`) and TypeScript-style (`e =>`) are valid. ```go // BEFORE (Go) resp, err := httpClient.Get(url) if err != nil { return nil, &NetworkError{URL: url, Err: err} } ``` ```dingo // AFTER — Rust-style resp := httpClient.Get(url) ? |e| &NetworkError{URL: url, Err: e} // AFTER — TypeScript-style (identical semantics) resp := httpClient.Get(url) ? e => &NetworkError{URL: url, Err: e} ``` --- ### Function Signature Compatibility | Return type | `?` works? | Notes | |---|---|---| | `(T, error)` | YES | Most common | | `(T1, T2, error)` | YES | Extracts last value | | `Result[T, E]` | YES | Unwraps to T | | `error` only (void success) | YES | Propagates error directly | | `(T, bool)` | NO | Use `Option[T]` + guard | | `T` only (no error) | NO | Nothing to propagate | **`?` in void functions is a compile error.** If you need to propagate from a void-returning call, acknowledge explicitly: ```dingo // WRONG — compile error when function returns void validateInput(data)? // CORRECT _ = validateInput(data)? ``` --- ### `guard` Statement `guard` provides early-return logic for `Result[T, E]` and `Option[T]` values. It is the idiomatic way to flatten a "pyramid of doom" into a sequential happy path. **CRITICAL CONSTRAINT:** `guard` ONLY works with `Result[T, E]` or `Option[T]` return types. It does NOT work on plain booleans, integers, or other types. ```dingo // WRONG — guard on boolean generates invalid Go (compile error) guard user.Active else { return "inactive" } // CORRECT — guard on Option[T] guard profile := getProfile(userID) else { return "no profile" } // CORRECT — guard on Result[T, E] guard user := findUser(id) else |err| { return fmt.Errorf("find user: %w", err) } ``` #### Guard Syntax Reference ```dingo // Result: bind error value with |err| guard user := findUser(id) else |err| { return Err(fmt.Errorf("find user: %w", err)) } // Option: no |err| binding (None has no error value) guard theme := getTheme(id) else { return "default" } // Reassignment: use = not := when variable already declared guard user = refreshUser(ctx, user.ID) else |err| { return Err(err) } // Tuple destructuring guard (lat, lng) := getCoords(address) else |err| { return Err(fmt.Errorf("coords: %w", err)) } ``` #### Pyramid of Doom → Flat Guard Chain ```go // BEFORE (Go) — nested error ladder user, err := findUser(id) if err != nil { return "", fmt.Errorf("find user: %w", err) } profile, err := loadProfile(user.ID) if err != nil { return "", fmt.Errorf("load profile: %w", err) } settings, err := loadSettings(profile.ID) if err != nil { return "", fmt.Errorf("load settings: %w", err) } ``` ```dingo // AFTER (Dingo) — flat guard chain guard user := findUser(id) else |e| { return "", fmt.Errorf("find user: %w", e) } guard profile := loadProfile(user.ID) else |e| { return "", fmt.Errorf("load profile: %w", e) } guard settings := loadSettings(profile.ID) else |e| { return "", fmt.Errorf("load settings: %w", e) } ``` --- ### `?` in Goroutines The `?` operator cannot propagate errors from inside goroutines (there is no enclosing function to return to). Use channels or `sync.WaitGroup` + error collection instead. ```dingo // WRONG — ? inside goroutine has no propagation target go func() { result := fetch()? // compile error or logic error }() // CORRECT — explicit error handling inside goroutines errCh := make(chan error, 1) go func() { result, err := fetch() if err != nil { errCh <- err return } process(result) errCh <- nil }() if err := <-errCh; err != nil { return nil, err } ``` --- ## Result & Option Types ### Result[T, E] Use for operations that can fail when callers need to act on the error type. **Constructors:** `Ok[T, E](value)` and `Err[T, E](err)` **Methods (complete list):** | Method | Description | |---|---| | `.IsOk()` | Returns true if Ok variant | | `.IsErr()` | Returns true if Err variant | | `.MustOk()` | Returns value; panics if Err | | `.MustErr()` | Returns error; panics if Ok | | `.OkOr(default)` | Returns value or default if Err | **NOT available:** `.Unwrap()`, `.Map()`, `.FlatMap()`, `.UnwrapErr()` — these do not exist in the dgo package. Do not use them. ```dingo func divide(a, b int) Result[int, string] { if b == 0 { return Err[int, string]("division by zero") } return Ok[int, string](a / b) } result := divide(10, 2) if result.IsOk() { fmt.Println(result.MustOk()) // 5 } // Safe extraction with default value := divide(10, 0).OkOr(0) // 0 ``` #### Result in Service Layer ```dingo func (s *UserService) FindByID(ctx context.Context, id string) Result[User, error] { guard user := s.repo.FindByID(ctx, id) else |err| { if errors.Is(err, sql.ErrNoRows) { return Err[User, error](NotFoundError("user")) } return Err[User, error](InternalError(err)) } return Ok[User, error](user) } ``` --- ### Option[T] Use when absence is expected and normal — not an error condition. **Constructors:** `Some(value)` and `None[T]()` **Methods (complete list):** | Method | Description | |---|---| | `.IsSome()` | Returns true if Some variant | | `.IsNone()` | Returns true if None variant | | `.MustSome()` | Returns value; panics if None | | `.SomeOr(default)` | Returns value or default | | `.SomeOrElse(fn)` | Returns value or calls fn() for default | **NOT available:** `.Unwrap()`, `.Map()`, `.FlatMap()` — these do not exist in the dgo package. Do not use them. ```dingo func findUser(id string) Option[User] { user, err := db.FindByID(id) if err != nil { return None[User]() } return Some(user) } user := findUser("123") if user.IsSome() { fmt.Println(user.MustSome().Name) } // Safe extraction with default name := findUser("123").SomeOr(User{Name: "Anonymous"}).Name // Lazy default (only computed when None) name := findUser("123").SomeOrElse(func() User { return buildDefaultUser() }).Name ``` --- ### Result vs Option — When to Use Which | Situation | Use | |---|---| | Absence is expected and normal ("not found") | `Option[T]` | | Absence needs explanation to the caller | `Result[T, E]` | | Infrastructure/stdlib calls | `(T, error)` + `?` | | Domain API with typed errors | `Result[T, DomainError]` | | "Find" queries on collections | `Option[T]` | | "Create/Update" domain operations | `Result[T, error]` | **Rule:** If absence is the expected outcome (e.g., cache miss, optional config), use `Option[T]`. If absence would surprise the caller and they need to know why, use `Result[T, E]`. Do NOT mix: a function should return either `Result[T, E]` or `(T, error)` — not both. `func f() (Result[User, string], error)` is always wrong. --- ## Enums & Sum Types ### Enum Declaration ```dingo // Simple variants (no data) enum Status { Pending Active Done } // Variants with data enum Event { UserCreated { userID: int, email: string } UserDeleted { userID: int } EmailChanged { userID: int, oldEmail: string, newEmail: string } } // Mixed enum APIResponse { Success { transactionID: string, amount: float64 } NotFound Error { code: int, reason: string } } ``` ### Constructor Naming Constructors are auto-generated as `New{EnumName}{VariantName}(fieldValues...)`. ```dingo // Simple variants (no constructor call needed — use as value) status := Status.Pending // Variants with data — use generated constructor event := NewEventUserCreated(42, "user@example.com") deleted := NewEventUserDeleted(42) resp := NewAPIResponseSuccess("TXN-123", 99.99) notFound := NewAPIResponseNotFound() ``` ### What Enums Generate Each enum declaration generates: - A Go interface with a marker method - One struct per variant containing the variant's fields - Constructor functions `New{Enum}{Variant}(...)` ```go
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub