embed.go raw
1 package kind
2
3 import (
4 _ "embed"
5 "encoding/json"
6 )
7
8 //go:embed kinds.json
9 var KindsJSON []byte
10
11 // KindData represents the full structure of the kinds.json file
12 type KindData struct {
13 Version string `json:"version"`
14 Source string `json:"source"`
15 Ranges Ranges `json:"ranges"`
16 Kinds map[string]KindInfo `json:"kinds"`
17 Privileged []int `json:"privileged"`
18 Directory []int `json:"directory"`
19 Aliases map[string]int `json:"aliases"`
20 }
21
22 // Ranges defines the kind number ranges for each event classification
23 type Ranges struct {
24 Regular Range `json:"regular"`
25 Replaceable Range `json:"replaceable"`
26 Ephemeral Range `json:"ephemeral"`
27 Parameterized Range `json:"parameterized"`
28 }
29
30 // Range defines a start and end for a kind range
31 type Range struct {
32 Start int `json:"start"`
33 End int `json:"end"`
34 Description string `json:"description"`
35 }
36
37 // KindInfo contains metadata about a specific event kind
38 type KindInfo struct {
39 Name string `json:"name"`
40 NIP *string `json:"nip,omitempty"`
41 Description string `json:"description"`
42 Classification string `json:"classification,omitempty"`
43 Deprecated bool `json:"deprecated,omitempty"`
44 DeprecatedBy string `json:"deprecatedBy,omitempty"`
45 Spec string `json:"spec,omitempty"`
46 RangeEnd int `json:"rangeEnd,omitempty"`
47 }
48
49 var kindData *KindData
50
51 func init() {
52 kindData = &KindData{}
53 if err := json.Unmarshal(KindsJSON, kindData); err != nil {
54 panic("failed to parse kinds.json: " + err.Error())
55 }
56
57 // Populate the Map from JSON data for backward compatibility
58 MapMx.Lock()
59 defer MapMx.Unlock()
60 for kStr, info := range kindData.Kinds {
61 var k int
62 if err := json.Unmarshal([]byte(kStr), &k); err == nil {
63 Map[uint16(k)] = info.Name
64 }
65 }
66 }
67
68 // GetKindData returns the parsed kind data from the embedded JSON
69 func GetKindData() *KindData {
70 return kindData
71 }
72
73 // GetKindInfo returns the KindInfo for a specific kind number
74 func GetKindInfo(k uint16) (KindInfo, bool) {
75 kStr := json.Number(string(rune('0' + k))).String()
76 // Manual conversion since json.Number doesn't work like that
77 kStr = itoa(int(k))
78 info, ok := kindData.Kinds[kStr]
79 return info, ok
80 }
81
82 func itoa(n int) string {
83 if n == 0 {
84 return "0"
85 }
86
87 var digits []byte
88 negative := n < 0
89 if negative {
90 n = -n
91 }
92
93 for n > 0 {
94 digits = append([]byte{byte('0' + n%10)}, digits...)
95 n /= 10
96 }
97
98 if negative {
99 digits = append([]byte{'-'}, digits...)
100 }
101
102 return string(digits)
103 }
104
105 // GetDescription returns the description for a kind number
106 func GetDescription(k uint16) string {
107 if info, ok := GetKindInfo(k); ok {
108 return info.Description
109 }
110 return ""
111 }
112
113 // GetNIP returns the NIP reference for a kind number
114 func GetNIP(k uint16) string {
115 if info, ok := GetKindInfo(k); ok && info.NIP != nil {
116 return *info.NIP
117 }
118 return ""
119 }
120
121 // IsDeprecated returns whether a kind is deprecated
122 func IsDeprecated(k uint16) bool {
123 if info, ok := GetKindInfo(k); ok {
124 return info.Deprecated
125 }
126 return false
127 }
128
129 // GetClassification returns the classification (regular, replaceable, ephemeral, parameterized) for a kind
130 func GetClassification(k uint16) string {
131 // First check explicit classification in JSON
132 if info, ok := GetKindInfo(k); ok && info.Classification != "" {
133 return info.Classification
134 }
135
136 // Fall back to range-based classification
137 if k >= uint16(kindData.Ranges.Parameterized.Start) && k <= uint16(kindData.Ranges.Parameterized.End) {
138 return "parameterized"
139 }
140 if k >= uint16(kindData.Ranges.Ephemeral.Start) && k < uint16(kindData.Ranges.Ephemeral.End) {
141 return "ephemeral"
142 }
143 if k >= uint16(kindData.Ranges.Replaceable.Start) && k < uint16(kindData.Ranges.Replaceable.End) {
144 return "replaceable"
145 }
146 if k >= uint16(kindData.Ranges.Regular.Start) && k <= uint16(kindData.Ranges.Regular.End) {
147 return "regular"
148 }
149
150 // Core kinds 0 and 3 are replaceable
151 if k == 0 || k == 3 {
152 return "replaceable"
153 }
154
155 return "regular"
156 }
157