Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .claude/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
commands/
hooks/
plans/
skills/
93 changes: 93 additions & 0 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Go library that gives first-class Go types to the `format` keyword from
[JSON Schema](https://json-schema.org/understanding-json-schema/reference/string#format) and
[OpenAPI](https://spec.openapis.org/oas/v3.1.1.html#data-types).

In those specs, `format` is a string annotation that hints at richer semantics —
`"date-time"`, `"uuid"`, `"email"`, `"uri"`, `"duration"`, etc. This package turns each
format into a concrete Go type (`DateTime`, `UUID`, `Email`, …) that knows how to validate,
parse, and round-trip through JSON, SQL (`driver.Valuer`/`sql.Scanner`), text, and BSON
encodings.

A pluggable `Registry` lets consumers (code generators, validators, runtime
libraries) discover and work with formats generically.

The package is a foundational building block of the
[go-swagger](https://github.com/go-swagger/go-swagger) ecosystem, but is useful anywhere
OpenAPI/JSON Schema formats need to travel across serialization boundaries.

See [docs/MAINTAINERS.md](../docs/MAINTAINERS.md) for CI/CD, release process, and repo structure details.

### Package layout

This is a mono-repo with multiple Go modules tied together by `go.work`.

#### Root module (`github.com/go-openapi/strfmt`)

| File | Contents |
|------|----------|
| `doc.go` | Package-level godoc |
| `ifaces.go` | Core interfaces: `Format` (string + text marshaling) and `Registry` (format registration, validation, parsing) |
| `format.go` | `Default` registry, `NewFormats()`, `NewSeededFormats()`, `NameNormalizer`, registry implementation |
| `default.go` | Simple string-wrapper types: `Base64`, `URI`, `Email`, `Hostname`, `IPv4`, `IPv6`, `CIDR`, `MAC`, `UUID`/`UUID3`/`UUID4`/`UUID5`/`UUID7`, `ISBN`/`ISBN10`/`ISBN13`, `CreditCard`, `SSN`, `HexColor`, `RGBColor`, `Password`; validators (`IsEmail`, `IsURI`, …) |
| `date.go` | `Date` type (wraps `time.Time`, RFC3339 full-date format) |
| `time.go` | `DateTime` type (wraps `time.Time`, RFC3339 date-time with flexible parsing) |
| `duration.go` | `Duration` type (wraps `time.Duration`, ISO 8601 duration parsing) |
| `ulid.go` | `ULID` type (wraps `oklog/ulid`) |
| `bson.go` | `ObjectId` type (`[12]byte`), hex encoding, no mongo-driver dependency |
| `mongo.go` | `MarshalBSON`/`UnmarshalBSON` implementations for all types, uses `internal/bsonlite` codec |
| `errors.go` | `ErrFormat` sentinel error |
| `conv/` | Pointer-helper sub-package: `conv.Date(v)` → `*Date`, `conv.DateValue(p)` → `Date`, etc. for every type |

#### Internal packages (`internal/`)

| Package | Contents |
|---------|----------|
| `internal/bsonlite` | Minimal BSON codec (wire-compatible with mongo-driver v2.5.0), handles single-key documents with string/DateTime/ObjectID values |

#### Sub-modules

| Module | Contents |
|--------|----------|
| `enable/mongodb` | Blank-import package that swaps the built-in `bsonlite` codec with the real MongoDB driver codec |
| `internal/testintegration` | Integration tests against real databases (MongoDB, MariaDB, PostgreSQL) |

### Key API

- `Format` interface — `String()` + `encoding.TextMarshaler` / `encoding.TextUnmarshaler`
- `Registry` interface — `Add()`, `DelByName()`, `GetType()`, `ContainsName()`, `Validates()`, `Parse()`, `MapStructureHookFunc()`
- `Default` — the global `Registry` instance, pre-seeded with all built-in formats
- `NewFormats()` — creates a new registry seeded from `Default`
- `NewSeededFormats(seeds, normalizer)` — creates a registry with custom seeds and name normalizer
- Format types — `Date`, `DateTime`, `Duration`, `ULID`, `ObjectId`, `UUID`, `Email`, `URI`, `Hostname`, `Base64`, etc.
- Validators — `IsDate()`, `IsDateTime()`, `IsDuration()`, `IsUUID()`, `IsEmail()`, `IsHostname()`, etc.

### Dependencies

- `github.com/go-openapi/errors` — error types for validation failures
- `github.com/go-viper/mapstructure/v2` — decode hook for format-aware struct mapping
- `github.com/google/uuid` — UUID parsing and validation
- `github.com/oklog/ulid/v2` — ULID implementation
- `golang.org/x/net` — IDNA hostname validation
- `github.com/go-openapi/testify/v2` — test-only assertions (zero-dep testify fork)

### Notable design decisions

- **Self-registering types via `init()`** — each format type file has an `init()` function that
registers itself in the `Default` registry. This means importing the package automatically
makes all formats available.
- **BSON without mongo-driver** — the `internal/bsonlite` package provides a minimal BSON codec
so the root module has no dependency on the MongoDB driver. Users who need the full driver
import `enable/mongodb` as a blank import to swap in the real codec.
- **`ObjectId` is `[12]byte`, not a string** — unlike many Go BSON libraries, `ObjectId` is a
fixed-size byte array for zero-allocation hex encoding and efficient comparison.
- **`DateTime` accepts flexible input** — the parser tries multiple RFC3339 variations (with/without
fractional seconds, Z vs offset) to handle real-world JSON from various sources.
- **`Duration` parses ISO 8601** — supports both Go-style (`1h30m`) and ISO 8601 (`P1DT12H`)
duration strings.

27 changes: 27 additions & 0 deletions .claude/rules/comments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
paths:
- "**/*.go"
---

# Comments for strfmt types

Formatted types (all types exported by this library, e.g. `DateTime`, `UUID`, ...) come
with a special annotation `swagger:strfmt [format]`.

These comments are significant and consumed by the `go-swagger`
to generate OpenAPI specifications from go source.

The comment must reside exactly on a single line, preferably as the last block of comment lines for this type.

The `swagger:strfmt` string must remain as-is.

The `[format]` string must be the name of the registered format (e.g. `date`, `date-time`, `uuid` etc.).

The comment line _may_ be terminated with a `.` to mark the end of the comment sentence (common comment linting rule).

```go
// [MyFormattedType] ...
//
// swagger:strfmt [format].
type [MyFormattedType] ...
```
52 changes: 52 additions & 0 deletions .claude/rules/contributions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
paths:
- "**/*"
---

# Contribution rules (go-openapi)

Read `.github/CONTRIBUTING.md` before opening a pull request.

## Commit hygiene

- Every commit **must** be DCO signed-off (`git commit -s`) with a real email address.
PGP-signed commits are appreciated but not required.
- Agents may be listed as co-authors (`Co-Authored-By:`) but the commit **author must be the human sponsor**.
We do not accept commits solely authored by bots or agents.
- Squash commits into logical units of work before requesting review (`git rebase -i`).

## Linting

Before pushing, verify your changes pass linting against the base branch:

```sh
golangci-lint run --new-from-rev master
```

Install the latest version if you don't have it:

```sh
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
```

## Problem statement

- Clearly describe the problem the PR solves, or reference an existing issue.
- PR descriptions must not be vague ("fix bug", "improve code") — explain *what* was wrong and *why* the change is correct.

## Tests are mandatory

- Every bug fix or feature **must** include tests that demonstrate the problem and verify the fix.
- The only exceptions are documentation changes and typo fixes.
- Aim for at least 80% coverage of your patch.
- Run the full test suite before submitting:

For mono-repos:
```sh
go test work ./...
```

For single module repos:
```sh
go test ./...
```
11 changes: 11 additions & 0 deletions .claude/rules/go-conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
paths:
- "**/*.go"
---

# Code conventions (go-openapi)

- All files must have SPDX license headers (Apache-2.0).
- Go version policy: support the 2 latest stable Go minor versions.
- Commits require DCO sign-off (`git commit -s`).
- use `golangci-lint fmt` to format code (not `gofmt` or `gofumpt`)
17 changes: 17 additions & 0 deletions .claude/rules/linting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
paths:
- "**/*.go"
---

# Linting conventions (go-openapi)

```sh
golangci-lint run
```

Config: `.golangci.yml` — posture is `default: all` with explicit disables.
See `docs/STYLE.md` for the rationale behind each disabled linter.

Key rules:
- Every `//nolint` directive **must** have an inline comment explaining why.
- Prefer disabling a linter over scattering `//nolint` across the codebase.
47 changes: 47 additions & 0 deletions .claude/rules/testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
paths:
- "**/*_test.go"
---

# Testing conventions (go-openapi)

## Running tests

**Single module repos:**

```sh
go test ./...
```

**Mono-repos (with `go.work`):**

```sh
# All modules
go test work ./...

# Single module
go test ./conv/...
```

Note: in mono-repos, plain `go test ./...` only tests the root module.
The `work` pattern expands to all modules listed in `go.work`.

CI runs tests on `{ubuntu, macos, windows} x {stable, oldstable}` with `-race` via `gotestsum`.

## Fuzz tests

```sh
# List all fuzz targets
go test -list Fuzz ./...

# Run a specific target (go test -fuzz cannot span multiple packages)
go test -fuzz=Fuzz -run='FuzzTargetName$' -fuzztime=1m30s ./package
```

Fuzz corpus lives in `testdata/fuzz/` within each package. CI runs each fuzz target for 1m30s
with a 5m minimize timeout.

## Test framework

`github.com/go-openapi/testify/v2` — a zero-dep fork of `stretchr/testify`.
Because it's a fork, `testifylint` does not work.
1 change: 1 addition & 0 deletions .github/copilot
73 changes: 73 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Copilot Instructions

## Project Overview

Go library that gives first-class Go types to the `format` keyword from
[JSON Schema](https://json-schema.org/understanding-json-schema/reference/string#format) and
[OpenAPI](https://spec.openapis.org/oas/v3.1.1.html#data-types).

In those specs, `format` is a string annotation that hints at richer semantics —
`"date-time"`, `"uuid"`, `"email"`, `"uri"`, `"duration"`, etc. This package turns each
format into a concrete Go type (`DateTime`, `UUID`, `Email`, …) that knows how to validate,
parse, and round-trip through JSON, SQL (`driver.Valuer`/`sql.Scanner`), text, and BSON
encodings. A pluggable `Registry` lets consumers (code generators, validators, runtime
libraries) discover and work with formats generically.

The package is a foundational building block of the
[go-swagger](https://github.com/go-swagger/go-swagger) ecosystem, but is useful anywhere
OpenAPI/JSON Schema formats need to travel across serialization boundaries.

This is a mono-repo (`go.work`) with three modules: root, `enable/mongodb`, `internal/testintegration`.

## Package Layout

| File | Contents |
|------|----------|
| `ifaces.go` | Core interfaces: `Format` (string + text marshaling) and `Registry` (format registration, validation, parsing) |
| `format.go` | `Default` registry, `NewFormats()`, `NewSeededFormats()`, `NameNormalizer` |
| `default.go` | Simple string-wrapper types: `URI`, `Email`, `Hostname`, `IPv4`, `IPv6`, `CIDR`, `MAC`, `UUID`/`UUID3-7`, `ISBN`, `CreditCard`, `SSN`, `HexColor`, `RGBColor`, `Password`, `Base64`; validators |
| `date.go` | `Date` type (wraps `time.Time`, RFC3339 full-date) |
| `time.go` | `DateTime` type (wraps `time.Time`, RFC3339 date-time with flexible parsing) |
| `duration.go` | `Duration` type (wraps `time.Duration`, ISO 8601 duration parsing) |
| `ulid.go` | `ULID` type (wraps `oklog/ulid`) |
| `bson.go` | `ObjectId` type (`[12]byte`), hex encoding, no mongo-driver dependency |
| `mongo.go` | `MarshalBSON`/`UnmarshalBSON` for all types via `internal/bsonlite` codec |
| `errors.go` | `ErrFormat` sentinel error |
| `conv/` | Pointer helpers: `conv.Date(v)` → `*Date`, `conv.DateValue(p)` → `Date`, etc. |

## Key API

- `Format` interface — `String()` + `encoding.TextMarshaler` / `encoding.TextUnmarshaler`
- `Registry` interface — `Add()`, `DelByName()`, `GetType()`, `ContainsName()`, `Validates()`, `Parse()`
- `Default` — global `Registry`, pre-seeded with all built-in formats
- Format types — `Date`, `DateTime`, `Duration`, `ULID`, `ObjectId`, `UUID`, `Email`, `URI`, `Hostname`, `Base64`, …
- Validators — `IsDate()`, `IsDateTime()`, `IsDuration()`, `IsUUID()`, `IsEmail()`, …

## Design Decisions

- Types self-register via `init()` — importing the package makes all formats available.
- BSON without mongo-driver — `internal/bsonlite` provides a minimal codec; `enable/mongodb` swaps in the real driver.
- `ObjectId` is `[12]byte`, not a string — zero-allocation hex encoding, efficient comparison.
- `DateTime` accepts flexible RFC3339 input (with/without fractional seconds, Z vs offset).
- `Duration` parses both Go-style (`1h30m`) and ISO 8601 (`P1DT12H`) strings.
- Formatted types carry a `swagger:strfmt [format]` annotation consumed by go-swagger (see rules).

## Dependencies

- `github.com/go-openapi/errors` — validation error types
- `github.com/go-viper/mapstructure/v2` — decode hook for format-aware struct mapping
- `github.com/google/uuid` — UUID parsing and validation
- `github.com/oklog/ulid/v2` — ULID implementation
- `golang.org/x/net` — IDNA hostname validation
- `github.com/go-openapi/testify/v2` — test-only assertions (zero-dep fork of `stretchr/testify`)

## Conventions

- All `.go` files must have SPDX license headers (Apache-2.0).
- Commits require DCO sign-off (`git commit -s`).
- Linting: `golangci-lint run` — config in `.golangci.yml` (posture: `default: all` with explicit disables).
- Every `//nolint` directive **must** have an inline comment explaining why.
- Tests: `go test work ./...` (mono-repo). CI runs on `{ubuntu, macos, windows} x {stable, oldstable}` with `-race`.
- Test framework: `github.com/go-openapi/testify/v2` (not `stretchr/testify`; `testifylint` does not work).

See `.github/copilot/` (symlinked to `.claude/rules/`) for detailed rules on Go conventions, linting, testing, and swagger comments.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@
.idea
.env
.mcp.json
.claude/
1 change: 1 addition & 0 deletions AGENTS.md
Loading