Validate makes sure the root expression is valid for code generation.
()
| 176 | |
| 177 | // Validate makes sure the root expression is valid for code generation. |
| 178 | func (r *RootExpr) Validate() error { |
| 179 | var verr eval.ValidationErrors |
| 180 | if r.API == nil { |
| 181 | verr.Add(r, "Missing API declaration") |
| 182 | } |
| 183 | // Ensure user type Go type names are unique across the design. Duplicate |
| 184 | // user type names (e.g., via TypeName) can lead to conflicting generated |
| 185 | // code. The Type DSL checks for duplicate declared names; this check |
| 186 | // covers collisions introduced by renaming. |
| 187 | useen := make(map[string]struct{}) |
| 188 | for _, ut := range r.Types { |
| 189 | name := ut.Name() |
| 190 | if _, ok := useen[name]; ok { |
| 191 | verr.Add(r, "type %#v defined twice", name) |
| 192 | } else { |
| 193 | useen[name] = struct{}{} |
| 194 | } |
| 195 | } |
| 196 | // Ensure result type Go type names are unique across declared result types |
| 197 | // (exclude generated collection/result types). Generated types (e.g., |
| 198 | // CollectionOf) do not set the openapi:typename meta, whereas declared |
| 199 | // result types do (set when calling dsl.ResultType). This prevents |
| 200 | // collisions like two declared ResultType blocks both using TypeName("A"), |
| 201 | // while allowing declared types to coexist with generated collection types |
| 202 | // that may share a name like "XCollection". |
| 203 | seen := make(map[string]struct{}) |
| 204 | for _, rt := range r.ResultTypes { |
| 205 | if _, declared := rt.Meta["openapi:typename"]; !declared { |
| 206 | continue // skip generated result types |
| 207 | } |
| 208 | name := rt.Name() |
| 209 | if _, ok := seen[name]; ok { |
| 210 | verr.Add(r, "result type %#v defined twice", name) |
| 211 | } else { |
| 212 | seen[name] = struct{}{} |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | verr.Merge(r.validateRelocatedUserTypes()) |
| 217 | |
| 218 | return &verr |
| 219 | } |
| 220 | |
| 221 | // validateRelocatedUserTypes enforces that relocated user types (those with |
| 222 | // `struct:pkg:path`) only depend on other declared user types with an explicit |