idents

package
v1.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 4, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package idents holds the Go-identifier conversion helpers used by both the semantic analyser and the codegen pass. Keeping it here - instead of inside codegen - lets semantic detect "user_id and userId map to the same Go field name" collisions during analysis without pulling in the rest of codegen.

Index

Constants

This section is empty.

Variables

View Source
var BuiltinTypes = map[string]bool{
	"string": true, "bool": true,
	"int": true, "int8": true, "int16": true, "int32": true, "int64": true,
	"uint": true, "uint8": true, "uint16": true, "uint32": true, "uint64": true,
	"float32": true, "float64": true,
	"bytes":  true,
	"any":    true,
	"object": true,
	"file":   true,
}

BuiltinTypes is the closed set of primitive type spellings the DSL recognises out of the box. The semantic resolver, codegen, and the parser's disambiguation rules all consult it, so the table lives here in a transport-neutral package - adding a new primitive happens once, every consumer picks it up. `object` is the permissive bag-of-fields used inside `@example({...})`; `file` is the upload-only marker that codegen maps to `*multipart.FileHeader`.

Prefer the IsBuiltin / IsWireParseable helpers over reading this map directly so the predicates stay consistent across every call site.

Functions

func GoFieldName

func GoFieldName(name string) string

GoFieldName converts a DSL field name (which is allowed to be lowercase, snake_case, or camelCase) into an exported Go identifier applying the common-initialism rule.

Hot path (called per field across codegen + collision detection): Builder keeps the per-part append allocation-free.

func IsBuiltin

func IsBuiltin(name string) bool

IsBuiltin reports whether name is one of the DSL's built-in type spellings (every entry in BuiltinTypes). Use this in code that has to differentiate "user-declared type" from "builtin" - codegen import resolution and semantic ref classification both reach for it.

func IsWireParseable

func IsWireParseable(name string) bool

IsWireParseable reports whether name is a primitive the wire-string binders (`@query`, `@header`, `@cookie`, `@form`) can parse from a single string. Excludes `bytes` / `any` / `object` / `file` - those need their own wire format. Mirrors the codegen's `queryPrims` table so semantic-time and gen-time rejections stay in sync without two hardcoded lists.

func KebabCase added in v1.2.0

func KebabCase(s string) string

KebabCase lowercases each word SplitFieldName yields and joins them with `-`. It is the one word-splitting rule for kebab output (route segments, generated file names) so the analyser's pathless-method route and the route codegen registers cannot disagree: `ListV2Items` → `list-v2items`, `GetUser` → `get-user`. A digit→letter boundary is NOT a word break, so `V2Items` stays one word — unlike a hand-rolled camel walker that splits before any uppercase whose next rune is lowercase.

func SplitFieldName

func SplitFieldName(s string) []string

SplitFieldName breaks a name into word components on `_`, `-`, and camelCase boundaries. Consecutive uppercase letters are kept together as a single acronym word (so `DBError` → `["DB", "Error"]` and `HTTPRequest` → `["HTTP", "Request"]`); a new word starts whenever an uppercase letter follows a lowercase letter, OR when an uppercase letter sits between two other uppercase letters and is followed by a lowercase letter (the "acronym ends here" boundary).

Exported so callers outside this package (codegen path / error helpers) can derive their own kebab / snake forms without duplicating the boundary logic.

Types

type Collision

type Collision struct {
	// DSLNames are the DSL spellings, in source order, that all
	// converted to the same canonical Go identifier.
	DSLNames []string
	// CanonicalGoName is the Go identifier the first DSL name maps
	// to - the "winner" that keeps its bare spelling.
	CanonicalGoName string
	// ResolvedGoNames pairs each DSLName index with the Go
	// identifier emitted in the generated struct: index 0 is the
	// canonical name; indices ≥ 1 carry the `_N` disambiguator.
	ResolvedGoNames []string
}

Collision records one DSL → Go-identifier mapping inside a group of names that produced the same Go identifier under GoFieldName. The first occurrence keeps the bare Go name; subsequent ones are suffixed `_2`, `_3`, ... so the resulting struct compiles. Both the original and the resolved Go names are returned so callers (semantic warnings + codegen) stay consistent on what spelling each DSL name maps to in the emitted struct.

func DedupGoFieldNames

func DedupGoFieldNames(dslNames []string) (resolved []string, collisions []Collision)

DedupGoFieldNames takes the DSL field names of a single struct in source order and returns:

  • resolved: the Go identifiers to emit in the struct, with `_N` suffixes appended to any duplicate beyond the first occurrence.
  • collisions: one Collision per group whose size is > 1, in source-order of the first occurrence. Empty when the struct is collision-free, which is the overwhelming common case.

The dedup keeps the first DSL spelling at its bare Go name so a project that adds a colliding alias later doesn't retroactively rename the original field — generated code stays stable for already-published struct shapes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL