Sylin.Koan.Tagging
0.17.0
dotnet add package Sylin.Koan.Tagging --version 0.17.0
NuGet\Install-Package Sylin.Koan.Tagging -Version 0.17.0
<PackageReference Include="Sylin.Koan.Tagging" Version="0.17.0" />
<PackageVersion Include="Sylin.Koan.Tagging" Version="0.17.0" />
<PackageReference Include="Sylin.Koan.Tagging" />
paket add Sylin.Koan.Tagging --version 0.17.0
#r "nuget: Sylin.Koan.Tagging, 0.17.0"
#:package Sylin.Koan.Tagging@0.17.0
#addin nuget:?package=Sylin.Koan.Tagging&version=0.17.0
#tool nuget:?package=Sylin.Koan.Tagging&version=0.17.0
Koan.Tagging
Tag system primitives for Koan-built applications.
Overview
Two layers, deliberately separated:
TagSet— a model-facet value type that lives on entities. Holds tags in two visibility scopes (Public/Private) each grouped into open-ended named categories. ThePublic/Privatecut is a serialisation boundary, not just a naming convention.Tag— a domain-entity that manages the roster of canonical tag identities themselves.Tag.ParentOfis a synonym graph: aliases listed there resolve to the Tag's canonicalIdat write time. No taxonomic hierarchy, no parent-walking — just rename-on-write canonicalisation.
Quick start
using Koan.Tagging;
var tags = new TagSet();
tags.Public["game"].Set(["ffxiv", "expedition-33"]);
tags.Public["technique"].Set("dof").Set("clarity").Set("magicbloom");
tags.Public["aesthetic"].Set("cinematic");
tags.Private["moderation"].Set("review-pending");
tags.Has("ffxiv"); // true (defaults to Public)
tags.Has("review-pending"); // false (Public default)
tags.Has("review-pending", TagSet.EScope.Private); // true
tags.Find("ffxiv"); // TagLocation(Public, "game")
tags.PublicTags;
// ["ffxiv", "expedition-33", "dof", "clarity", "magicbloom", "cinematic"]
A typical entity:
public sealed class Package : Entity<Package>
{
public string? Name { get; set; }
public TagSet Tags { get; set; } = new();
// ...
}
A typical public-surface projection:
public sealed class PublicPackage
{
public required string Id { get; init; }
public string? Name { get; init; }
public IReadOnlyList<string> Tags { get; init; } = [];
public static implicit operator PublicPackage(Package p) => new()
{
Id = p.Id,
Name = p.Name,
Tags = p.Tags.PublicTags, // <-- the Public/Private boundary
};
}
Synonym registry (Tag entity)
Use the Tag entity to declare canonical names and their aliases:
await new Tag
{
Id = "ffxiv",
DisplayName = "Final Fantasy XIV",
ParentOf = ["ff14", "final-fantasy-xiv", "final-fantasy-14"]
}.Upsert();
// At write time, normalise input:
string canonical = await ResolveCanonical("ff14"); // → "ffxiv"
tags.Public["game"].Set(canonical);
async Task<string> ResolveCanonical(string raw)
{
var match = await Tag.Query(t => t.ParentOf.Contains(raw));
return match.FirstOrDefault()?.Id ?? raw;
}
The Tag entity is opt-in: tag strings that don't have a corresponding Tag entity are their own canonical form. Add a Tag entity only when canonicalisation, admin-managed metadata, or a synonym story matters for that tag.
JSON shape
TagSet serialises as a nested object:
{
"public": {
"game": ["ffxiv"],
"technique": ["dof", "clarity"]
},
"private": {
"moderation": ["review-pending"]
}
}
Empty categories are stripped. The flat PublicTags projection is what public
surfaces typically emit instead.
Design notes
- Category names are open-ended. Consuming projects document their own
conventions (
game,source,technique,aesthetic, etc.). Add new categories without code changes. - No hierarchy on
Tag.ParentOfis intentionally a synonym graph, not a taxonomy. If a downstream needs hierarchy, build it separately. - Tag entities are optional. TagSets work on flat strings; the Tag registry adds canonicalisation only where it's earned.
Public/Privateis a serialisation boundary. Public surfaces consumeTagSet.PublicTags; admin surfaces consume the full TagSet. The compiler enforces the boundary when projections are typed (e.g.PublicPackagevs.Package).
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Sylin.Koan.Data.Core (>= 0.17.0 && < 0.18.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
See release notes: https://github.com/sylin-labs/Koan-framework/releases