@k8ts/metadata 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +3 -0
  3. package/dist/error.d.ts +5 -0
  4. package/dist/error.d.ts.map +1 -0
  5. package/dist/error.js +12 -0
  6. package/dist/error.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +6 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/input/dict-input.d.ts +12 -0
  12. package/dist/input/dict-input.d.ts.map +1 -0
  13. package/dist/input/dict-input.js +3 -0
  14. package/dist/input/dict-input.js.map +1 -0
  15. package/dist/input/parse-dict.d.ts +5 -0
  16. package/dist/input/parse-dict.d.ts.map +1 -0
  17. package/dist/input/parse-dict.js +48 -0
  18. package/dist/input/parse-dict.js.map +1 -0
  19. package/dist/key/convert.d.ts +6 -0
  20. package/dist/key/convert.d.ts.map +1 -0
  21. package/dist/key/convert.js +7 -0
  22. package/dist/key/convert.js.map +1 -0
  23. package/dist/key/index.d.ts +4 -0
  24. package/dist/key/index.d.ts.map +1 -0
  25. package/dist/key/index.js +11 -0
  26. package/dist/key/index.js.map +1 -0
  27. package/dist/key/parse-key.d.ts +5 -0
  28. package/dist/key/parse-key.d.ts.map +1 -0
  29. package/dist/key/parse-key.js +45 -0
  30. package/dist/key/parse-key.js.map +1 -0
  31. package/dist/key/repr.d.ts +30 -0
  32. package/dist/key/repr.d.ts.map +1 -0
  33. package/dist/key/repr.js +64 -0
  34. package/dist/key/repr.js.map +1 -0
  35. package/dist/key/types.d.ts +23 -0
  36. package/dist/key/types.d.ts.map +1 -0
  37. package/dist/key/types.js +8 -0
  38. package/dist/key/types.js.map +1 -0
  39. package/dist/meta.d.ts +101 -0
  40. package/dist/meta.d.ts.map +1 -0
  41. package/dist/meta.js +230 -0
  42. package/dist/meta.js.map +1 -0
  43. package/dist/mutable-meta.d.ts +1 -0
  44. package/dist/mutable-meta.d.ts.map +1 -0
  45. package/dist/mutable-meta.js +2 -0
  46. package/dist/mutable-meta.js.map +1 -0
  47. package/dist/src.tsbuildinfo +1 -0
  48. package/dist/test.tsbuildinfo +1 -0
  49. package/package.json +88 -0
  50. package/src/error.ts +7 -0
  51. package/src/index.ts +2 -0
  52. package/src/input/dict-input.ts +12 -0
  53. package/src/input/parse-dict.ts +45 -0
  54. package/src/key/convert.ts +6 -0
  55. package/src/key/index.ts +4 -0
  56. package/src/key/parse-key.ts +58 -0
  57. package/src/key/repr.ts +72 -0
  58. package/src/key/types.ts +27 -0
  59. package/src/meta.ts +275 -0
  60. package/src/mutable-meta.ts +0 -0
  61. package/src/tsconfig.json +10 -0
  62. package/tsconfig.json +15 -0
@@ -0,0 +1,72 @@
1
+ import { hash } from "immutable"
2
+ interface ImmObject {
3
+ equals(other: ImmObject): boolean
4
+ hashCode(): number
5
+ }
6
+ abstract class KeyType implements ImmObject {
7
+ abstract get str(): string
8
+ equals(other: ImmObject): boolean {
9
+ return this.constructor === other.constructor && this.toString() === other.toString()
10
+ }
11
+ hashCode(): number {
12
+ return hash(this.toString())
13
+ }
14
+ toString() {
15
+ return this.str
16
+ }
17
+ }
18
+
19
+ export class ValueKey extends KeyType {
20
+ type = "full" as const
21
+ constructor(
22
+ readonly _prefix: string,
23
+ readonly _section: string | undefined,
24
+ readonly _name: string
25
+ ) {
26
+ super()
27
+ }
28
+
29
+ get suffix() {
30
+ const parts = []
31
+ if (this._section) {
32
+ parts.push(this._section)
33
+ if (!this._section.endsWith("/")) {
34
+ parts.push("/")
35
+ }
36
+ }
37
+ parts.push(this._name)
38
+ return parts.join("")
39
+ }
40
+
41
+ get str() {
42
+ return [this._prefix, this.suffix].join("")
43
+ }
44
+
45
+ get parent() {
46
+ if (this._section == null) {
47
+ return null
48
+ }
49
+ return new SectionKey(this._section)
50
+ }
51
+
52
+ section(section: string | SectionKey) {
53
+ section = section instanceof SectionKey ? section.str : section
54
+ if (this._section) {
55
+ throw new Error("Already has a section")
56
+ }
57
+ return new ValueKey(this._prefix, section, this._name)
58
+ }
59
+ }
60
+
61
+ export class SectionKey extends KeyType {
62
+ type = "heading" as const
63
+ constructor(readonly _section: string) {
64
+ super()
65
+ }
66
+
67
+ get str() {
68
+ return [this._section].join("")
69
+ }
70
+ }
71
+
72
+ export type SomeKey = ValueKey | SectionKey
@@ -0,0 +1,27 @@
1
+ export namespace Char {
2
+ export namespace Prefix {
3
+ export type Label = "%"
4
+ export type Annotation = "^"
5
+ export type Comment = "#"
6
+ export type Custom = `${Label | Annotation | Comment}`
7
+ }
8
+
9
+ export type Section = "/"
10
+ export const Section = "/"
11
+
12
+ export type Lower =
13
+ `${"a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"}`
14
+ export type Upper = Uppercase<Lower>
15
+ export type Digit = `${"0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"}`
16
+ export type Extra = "-" | "_" | "."
17
+ export type Normal = `${Lower | Digit | Extra | Upper}`
18
+ }
19
+
20
+ export namespace Key {
21
+ export type Section = `${Char.Normal}${string}${Char.Section}`
22
+ export type Special = "name" | "namespace"
23
+ export type Value = `${Char.Prefix.Custom}${string}${Char.Normal}` | Special
24
+
25
+ export type Key = Section | Value
26
+ }
27
+ export type Key = Key.Key
package/src/meta.ts ADDED
@@ -0,0 +1,275 @@
1
+ import { Map, Set } from "immutable"
2
+ import { MetadataError } from "./error"
3
+ import type { InputMeta, MetaInputParts } from "./input/dict-input"
4
+ import { parseKey, parseMetaInput } from "./key"
5
+ import { ValueKey, type SectionKey } from "./key/repr"
6
+ import { Key as Key_ } from "./key/types"
7
+ export type Meta = Meta.Meta
8
+ export type MutableMeta = Meta.MutableMeta
9
+ export namespace Meta {
10
+ export type Input = InputMeta
11
+ export import Key = Key_
12
+ export class Meta implements Iterable<[ValueKey, string]> {
13
+ constructor(private readonly _dict: Map<ValueKey, string>) {
14
+ const a = _dict
15
+ const aaa = 1
16
+ }
17
+
18
+ [Symbol.iterator]() {
19
+ return this._dict.entries()[Symbol.iterator]()
20
+ }
21
+ protected _create(raw: Map<ValueKey, string>) {
22
+ return new Meta(raw)
23
+ }
24
+ private _createWith(f: (raw: Map<ValueKey, string>) => Map<ValueKey, string>) {
25
+ return this._create(f(this._dict))
26
+ }
27
+ add(key: Key.Value, value: string): Meta
28
+ add(key: Key.Section, value: MetaInputParts.Nested): Meta
29
+ add(input: InputMeta): Meta
30
+ add(a: any, b?: any) {
31
+ return this._createWith(raw => {
32
+ const parsed = _pairToMap([a, b])
33
+ const newMap = raw.mergeWith((prev, cur, key) => {
34
+ throw new MetadataError(`Duplicate entry for ${key}, was ${prev} now ${cur}`, {
35
+ key: key.str
36
+ })
37
+ }, parsed)
38
+ return newMap
39
+ })
40
+ }
41
+
42
+ equals(other: Meta.Input) {
43
+ return this._dict.equals(make(other)._dict)
44
+ }
45
+
46
+ section(key: string) {
47
+ return this._createWith(raw => {
48
+ return raw.mapKeys(k => k.section(key))
49
+ })
50
+ }
51
+
52
+ overwrite(key: Key.Value, value: string): Meta
53
+ overwrite(key: Key.Section, value: MetaInputParts.Nested): Meta
54
+ overwrite(input?: InputMeta): Meta
55
+ overwrite(a?: any, b?: any) {
56
+ if (a === undefined) {
57
+ return this
58
+ }
59
+ return this._createWith(raw => {
60
+ const fromPair = _pairToMap([a, b])
61
+ return raw.merge(fromPair)
62
+ })
63
+ }
64
+
65
+ has<X extends Key.Value>(key: X) {
66
+ const parsed = parseKey(key)
67
+ if (parsed instanceof ValueKey) {
68
+ return this._dict.has(parsed)
69
+ } else {
70
+ return this._matchSectionKeys(parsed).size > 0
71
+ }
72
+ }
73
+
74
+ get(key: Key.Value) {
75
+ const parsed = parseKey(key)
76
+ const v = this._dict.get(parsed as ValueKey)
77
+ if (v === undefined) {
78
+ throw new MetadataError(`Key ${key} not found!`, { key })
79
+ }
80
+ return v
81
+ }
82
+
83
+ tryGet(key: Key.Value, fallback?: string) {
84
+ const parsed = parseKey(key)
85
+ if (!(parsed instanceof ValueKey)) {
86
+ throw new MetadataError("Unexpected section key!", { key })
87
+ }
88
+ return this._dict.get(parsed) ?? fallback
89
+ }
90
+
91
+ private _matchSectionKeys(key: SectionKey) {
92
+ return this._dict.filter((_, k) => k.parent?.equals(key))
93
+ }
94
+
95
+ pick(...keySpecs: Key.Key[]) {
96
+ return this._createWith(raw => {
97
+ const parsed = keySpecs.map(parseKey)
98
+ let keySet = Set()
99
+ for (const key of parsed) {
100
+ if (key instanceof ValueKey) {
101
+ keySet = keySet.add(key)
102
+ } else {
103
+ const sectionKeys = this._matchSectionKeys(key)
104
+ keySet = keySet.union(sectionKeys.keySeq())
105
+ }
106
+ }
107
+ return raw.filter((_, k) => keySet.has(k))
108
+ })
109
+ }
110
+
111
+ private _prefixed(prefix: string) {
112
+ return this._dict
113
+ .filter((_, k) => k._prefix === prefix)
114
+ .mapKeys(k => k.suffix)
115
+ .toObject()
116
+ }
117
+
118
+ get labels() {
119
+ return this._prefixed("%")
120
+ }
121
+
122
+ get annotations() {
123
+ return this._prefixed("^")
124
+ }
125
+
126
+ get comments() {
127
+ return this._prefixed("#")
128
+ }
129
+
130
+ get values() {
131
+ return this._dict.toJS()
132
+ }
133
+
134
+ get core() {
135
+ return this._prefixed("") as {
136
+ [key in Key.Special]?: string
137
+ }
138
+ }
139
+ remove(key: Key.Value): this
140
+ remove(ns: Key.Section, key: string): this
141
+ remove(ns: Key.Section): this
142
+ remove(a: any, b?: any) {
143
+ return this._createWith(raw => {
144
+ const parsed = parseKey(a)
145
+ if (parsed instanceof ValueKey) {
146
+ return raw.delete(parsed)
147
+ } else {
148
+ return raw.filter((_, k) => !k.parent?.equals(parsed))
149
+ }
150
+ })
151
+ }
152
+
153
+ expand() {
154
+ const labels = this.labels
155
+ const annotations = this.annotations
156
+ const core = this.core
157
+ return {
158
+ ...core,
159
+ labels,
160
+ annotations
161
+ }
162
+ }
163
+
164
+ toMutable() {
165
+ return new MutableMeta(this)
166
+ }
167
+ }
168
+
169
+ export function make(key: Key.Value, value: string): Meta
170
+ export function make(key: Key.Section, value: MetaInputParts.Nested): Meta
171
+ export function make(input?: InputMeta): Meta
172
+ export function make(a?: any, b?: any) {
173
+ return new Meta(_pairToMap([a, b]))
174
+ }
175
+ function _pairToObject(pair: [string, string | object] | [object]) {
176
+ const [key, value] = pair
177
+ if (key instanceof Meta) {
178
+ return Map(key)
179
+ }
180
+ if (typeof key === "string") {
181
+ return {
182
+ [key]: value as string
183
+ }
184
+ }
185
+ return key
186
+ }
187
+ function _pairToMap(pair: [string, string | object] | [object]) {
188
+ return parseMetaInput(_pairToObject(pair))
189
+ }
190
+ export function makeMutable(input: InputMeta = {}) {
191
+ return make(input).toMutable()
192
+ }
193
+
194
+ export function splat(...input: InputMeta[]) {
195
+ return input.map(make).reduce((acc, meta) => acc.add(meta), make())
196
+ }
197
+
198
+ export function is(value: any): value is Meta {
199
+ return value instanceof Meta
200
+ }
201
+
202
+ export class MutableMeta {
203
+ constructor(private _meta: Meta) {}
204
+
205
+ add(key: Key.Value, value: string): this
206
+ add(key: Key.Section, value: MetaInputParts.Nested): this
207
+ add(input: InputMeta): this
208
+ add(a: any, b?: any) {
209
+ this._meta = this._meta.add(a, b)
210
+ return this
211
+ }
212
+
213
+ remove(key: Key.Value): this
214
+ remove(ns: Key.Section, key: string): this
215
+ remove(ns: Key.Section): this
216
+ remove(a: any, b?: any) {
217
+ this._meta = this._meta.remove(a, b)
218
+ return this
219
+ }
220
+
221
+ overwrite(key: Key.Value, value: string): this
222
+ overwrite(key: Key.Section, value: MetaInputParts.Nested): this
223
+ overwrite(input?: InputMeta): this
224
+ overwrite(a?: any, b?: any) {
225
+ this._meta = this._meta.overwrite(a, b)
226
+ return this
227
+ }
228
+ equals(other: Meta.Input) {
229
+ return this._meta.equals(other)
230
+ }
231
+ get(key: Key.Value) {
232
+ return this._meta.get(key)
233
+ }
234
+
235
+ tryGet(key: Key.Value, fallback?: string) {
236
+ return this._meta.tryGet(key, fallback)
237
+ }
238
+
239
+ has(key: Key.Value) {
240
+ return this._meta.has(key)
241
+ }
242
+
243
+ pick(...keySpecs: Key.Key[]) {
244
+ const newMeta = this._meta.pick(...keySpecs)
245
+ return new MutableMeta(newMeta)
246
+ }
247
+
248
+ toMutable() {
249
+ return new MutableMeta(this._meta)
250
+ }
251
+
252
+ section(key: string) {
253
+ return new MutableMeta(this._meta.section(key))
254
+ }
255
+ get labels() {
256
+ return this._meta.labels
257
+ }
258
+
259
+ get annotations() {
260
+ return this._meta.annotations
261
+ }
262
+
263
+ get comments() {
264
+ return this._meta.comments
265
+ }
266
+
267
+ get core() {
268
+ return this._meta.core
269
+ }
270
+
271
+ toImmutable() {
272
+ return this._meta
273
+ }
274
+ }
275
+ }
File without changes
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "rootDir": ".",
5
+ "noEmit": false,
6
+ "outDir": "../dist",
7
+ "tsBuildInfoFile": "../dist/src.tsbuildinfo"
8
+ },
9
+ "include": ["**/*.ts"]
10
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "references": [
3
+ {
4
+ "path": "./src/tsconfig.json"
5
+ },
6
+ {
7
+ "path": "./test/tsconfig.json"
8
+ }
9
+ ],
10
+ "compilerOptions": {
11
+ "composite": true,
12
+ "noEmit": true
13
+ },
14
+ "files": []
15
+ }