feat(sieve): add sieve module with Map

This commit is contained in:
2026-10-11 14:22:56 +02:00
parent b906bdd48b
commit 6933004b87
4 changed files with 103 additions and 0 deletions

View File

@@ -108,6 +108,7 @@ The `migrate`, `migrate:status`, `migrate:rollback`, `serve` and admin commands
| [party](modules/party/README.md) | Compiled plugin registry that orders plugins by their dependencies and runs their Register and Boot lifecycle. | The guest list and the order people arrive in; it registers plugins and boots them in dependency order. |
| [phrasebook](modules/phrasebook/README.md) | Namespaced translation catalogs loaded from plugin YAML, with locale fallback, placeholder interpolation and CLDR pluralization. | What you pack to speak the local language on holiday; it holds the translations. |
| [postcard](modules/postcard/README.md) | Transactional mail from plugin-owned Markdown templates and layouts, delivered through a memory, log or SMTP driver. | What you send home in summer; it delivers the application's mail. |
| [sieve](modules/sieve/README.md) | Generic, dependency-free collection helpers that the standard library slices and maps packages lack: mapping, filtering, reducing, keying, grouping, deduplicating, partitioning and finding, plus a small set type. | A sand sieve: you shake a collection through it and keep what you need; map, filter and reduce for slices and maps. |
| [sunrise](modules/sunrise/README.md) | Bootstrap script that installs the summer CLI and creates a new SummerCMS application, or updates an existing one, in one command, embedded so it is versioned with the framework. | The start of a summer day; it starts a new application, or updates one, in one command. |
| [sunscreen](modules/sunscreen/README.md) | Credential-redacting slog handler that keeps API keys, tokens and passwords out of application logs. | Protects you from exposure; it keeps secrets out of the logs. |
| [surf](modules/surf/README.md) | HTTP routing for SummerCMS: collects plugin routes and named middleware into a `net/http` ServeMux with constraints, rate limiting, body limits, CORS and panic recovery, and provides the `serve` and `route:list` commands. | Catching the incoming waves; it routes incoming HTTP requests to their handlers. |

56
modules/sieve/README.md Normal file
View File

@@ -0,0 +1,56 @@
# sieve
Generic, dependency-free collection helpers that the standard library slices and maps packages lack: mapping, filtering, reducing, keying, grouping, deduplicating, partitioning and finding, plus a small set type.
`import "git.golem15.com/golem15/summercms/modules/sieve"`
**Name:** A sand sieve: you shake a collection through it and keep what you need; map, filter and reduce for slices and maps.
## Overview
`sieve` gives plain Go slices the collection operations that WinterCMS code reaches for on Laravel collections. Every function is eager and never modifies its input, results never share a backing array with the input, callbacks run once per element in input order, and nil or empty input yields a non-nil empty result, so `encoding/json` writes `[]` rather than `null`.
## Role in the framework
A dependency-free leaf with no imports, so any module, plugin or application can use it without import cycles.
## Features
- `sieve.Map` applies a function to every element and returns the results in order; with a field accessor it is the pluck operation.
## Usage
```go
package blog
import "git.golem15.com/golem15/summercms/modules/sieve"
type Post struct {
ID int
Title string
}
func titles(posts []Post) []string {
return sieve.Map(posts, func(p Post) string { return p.Title })
}
```
## API reference
| Identifier | Description |
|------------|-------------|
| `sieve.Map` | Returns f applied to each element, in input order. Nil input gives a non-nil empty slice. |
## Dependencies
- SummerCMS modules: none.
- Third-party: none.
- Standard library: none (the package has no imports).
## Testing
```sh
go test ./modules/sieve/...
```
The tests are in-memory and need no external services.

View File

@@ -0,0 +1,24 @@
package sieve_test
import (
"fmt"
"git.golem15.com/golem15/summercms/modules/sieve"
)
type post struct {
ID int
Title string
}
func ExampleMap() {
posts := []post{
{ID: 1, Title: "Hello"},
{ID: 2, Title: "Summer"},
{ID: 3, Title: "Goodbye"},
}
// Pluck the titles with a field accessor.
titles := sieve.Map(posts, func(p post) string { return p.Title })
fmt.Println(titles)
// Output: [Hello Summer Goodbye]
}

22
modules/sieve/sieve.go Normal file
View File

@@ -0,0 +1,22 @@
// Package sieve provides generic, dependency-free collection helpers that the
// standard library slices and maps packages lack.
//
// Every function is eager and never modifies its input. Results never share a
// backing array with the input, so changing or appending to a result leaves the
// caller's slice unchanged. Callbacks run once per element, in input order.
// Nil or empty input yields a non-nil empty slice or map, so encoding/json
// writes [] or {} rather than null.
package sieve
// Map returns a new slice holding f applied to each element of s, in order.
// f is called once per element. A nil or empty s yields a non-nil empty slice.
//
// Map is also the pluck operation: pass an accessor func to extract one field
// from every element, for example the titles of a slice of posts.
func Map[S ~[]T, T, U any](s S, f func(T) U) []U {
out := make([]U, 0, len(s))
for _, v := range s {
out = append(out, f(v))
}
return out
}